diff options
40 files changed, 1198 insertions, 0 deletions
diff --git a/.bochsrc b/.bochsrc new file mode 100644 index 0000000..0524112 --- /dev/null +++ b/.bochsrc @@ -0,0 +1,9 @@ +ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +ata0-master: type=cdrom, path="kernel.iso", status=inserted +boot: cdrom +log: xbochs.log +megs: 128 +magic_break: enabled=1 +com1: enabled=1, mode=file, dev=serial.log +display_library: x, options="gui_debug" +cpu: count=4 diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..f5905ac --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[unstable] +build-std-features = ["compiler-builtins-mem"] +build-std = ["core", "compiler_builtins"] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7fba126 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/target +/isodir +*.o +*.d +*.bin +*.iso +*.log +bx_enh_dbg.ini diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..09605ba --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,57 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "myrustkernel" +version = "0.1.0" +dependencies = [ + "lazy_static", + "spin 0.9.8", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8c8cf11 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "myrustkernel" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["staticlib"] + +[dependencies] + +[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies] +lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] } +spin = "0.9.8" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d370666 --- /dev/null +++ b/Makefile @@ -0,0 +1,152 @@ +export +ARCH ?= x86_64 +DEBUG ?= 1 +RUST_LIB_PATH=debug +CARGO_FLAGS = +#QEMU_DEBUG=-d int -no-reboot -no-shutdown +TARGET=kernel.iso + +ifeq ($(DEBUG), 0) + RUST_LIB_PATH=release + CARGO_FLAGS=--release +endif + +ifeq ($(ARCH), x86) + QEMU = qemu-system-i386 + QEMU_OPTS = -serial file:serial.log + MACHINE = -machine q35 + BOOT = -cdrom kernel.iso + ARCH_PREFIX = i386-elf- + target = "./arch/x86.json" + RUST_OBJS = ../target/x86/$(RUST_LIB_PATH)/libmyrustkernel.a + ASM_PATHS = ./arch/x86/boot + ASM_PATHS += ./arch/x86/common/boot + CARGO_B = --target "./arch/x86.json" + LD_SCRIPT=../arch/x86.ld +endif + +ifeq ($(ARCH), x86_64) + QEMU = qemu-system-x86_64 + QEMU_OPTS = -serial file:serial.log + MACHINE = -machine q35 + BOOT = -cdrom kernel.iso + ARCH_PREFIX = x86_64-elf- + target = "./arch/x86_64.json" + RUST_OBJS = ../target/x86_64/$(RUST_LIB_PATH)/libmyrustkernel.a + ASM_PATHS = ./arch/x86_64/boot + ASM_PATHS += ./arch/x86/common/boot + CARGO_B = --target "./arch/x86_64.json" + LD_SCRIPT=../arch/x86_64.ld +endif + +ifeq ($(ARCH), riscv64) + QEMU = qemu-system-riscv64 + QEMU_OPTS = -nographic -serial mon:stdio + MACHINE = -machine virt -bios none + BOOT = -kernel ./src/kernel.bin + ARCH_PREFIX = riscv64-elf- + target = "./arch/riscv64.json" + RUST_OBJS = ../target/riscv64/$(RUST_LIB_PATH)/libmyrustkernel.a + ASM_PATHS = ./arch/riscv64/boot + CARGO_B = --target "./arch/riscv64.json" + LD_SCRIPT=../arch/riscv64.ld + TARGET=src/kernel.bin +endif + +ifndef ARCH_PREFIX +$(error ARCH available: "x86_64", "x86", "riscv64") +endif + +CC = $(ARCH_PREFIX)gcc +AS = $(ARCH_PREFIX)as +LD = $(ARCH_PREFIX)ld +OBJDUMP = $(ARCH_PREFIX)objcopy +OBJCOPY = $(ARCH_PREFIX)objdump + +W := -Wall -Werror -Wextra -Wshadow -Wcast-align +# W:= -Wpointer-arith -pedantic -Wmissing-prototypes -Wmissing-declarations +W += -Wwrite-strings -Wredundant-decls -Wnested-externs -Winline -Wno-long-long +W += -Wconversion -Wstrict-prototypes +WNO := -Wno-error=unused-parameter -Wno-error=unused-variable +WNO += -Wno-error=unused-but-set-variable -Wno-error=unused-but-set-parameter +WNO += -Wno-error=infinite-recursion + +CFLAGS = $(W) $(WNO) -fno-omit-frame-pointer +CFLAGS += -MD -O3 -ffreestanding -nostdlib -std=gnu89 +CFLAGS += -fno-common -fno-stack-protector +CFLAGS += -fno-pie -no-pie -fno-pic +CFLAGS += -g -fsanitize=undefined +#CFLAGS += -fstack-protector-all +LDFLAGS = -z max-page-size=4096 + +ifeq ($(ARCH), x86) + CFLAGS += -mgeneral-regs-only +endif + +ifeq ($(ARCH), x86_64) + CFLAGS += -mcmodel=large + CFLAGS += -mgeneral-regs-only +endif + +ifeq ($(ARCH), riscv64) + CFLAGS += -mcmodel=medany +endif + +MAKE:=$(MAKE) -s + +all: $(TARGET) + +FORCE: + +src/kernel.bin: FORCE + cargo b $(CARGO_B) $(CARGO_FLAGS) + @rm -f src/kernel.bin + @$(MAKE) -C $(@D) + +isodir: + $(info [all] $@) + @mkdir -p isodir/boot/grub + @cp src/grub.cfg isodir/boot/grub/grub.cfg + @mkdir -p isodir/modules + @dd if=/dev/zero of=isodir/modules/ext2.img bs=4M count=2 > /dev/null 2>&1 + @mkfs.ext2 isodir/modules/ext2.img > /dev/null 2>&1 + +kernel.iso: src/kernel.bin src/grub.cfg Makefile isodir FORCE + $(info [all] $@) + @cp src/kernel.bin isodir/boot/kernel.bin + @sudo cp src/kernel.bin /srv/tftp/boot/kernel.bin + @grub-mkrescue -o kernel.iso isodir > /dev/null 2>&1 + + +.PHONY: all build qemu bochs mount umount clean + +BOCHS = bochs -q + +qemu: kernel.iso + $(QEMU) $(MACHINE) $(BOOT) $(QEMU_OPTS) $(QEMU_DEBUG) + @cat serial.log + +bochs: kernel.iso + @$(BOCHS) -qf .bochsrc + @cat serial.log + +mount: isodir +ifeq ("$(wildcard /mnt/ext2/lost+found/)","") + $(info [all] $@) + @doas mount isodir/modules/ext2.img /mnt/ext2 -o loop + @doas chown -R aleksa:aleksa /mnt/ext2 +endif + +umount: +ifneq ("$(wildcard /mnt/ext2/lost+found/)","") + $(info [all] $@) + @doas umount /mnt/ext2 +endif + +clean: + @find ./src/ -name "*.o" -exec rm {} \; + @find ./src/ -name "*.d" -exec rm {} \; + @rm -f kernel.iso src/kernel.bin xbochs.log bx_enh_dbg.ini log serial.log + @rm -rf isodir + @cargo clean + @$(MAKE) umount diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/README.md diff --git a/arch/riscv64.json b/arch/riscv64.json new file mode 100644 index 0000000..ea84208 --- /dev/null +++ b/arch/riscv64.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "riscv64-unknown-none-elf", + "data-layout": "e-m:e-p:64:64-i64:64-n32:64-S128", + "arch": "riscv64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "+m,+a,+c,+f,+d" +} diff --git a/arch/riscv64.ld b/arch/riscv64.ld new file mode 100644 index 0000000..cad0f07 --- /dev/null +++ b/arch/riscv64.ld @@ -0,0 +1,25 @@ +ENTRY(start); + +. = 0x80200000; + +SECTIONS { + .text : ALIGN(4K) { + *(.init); + *(.text); + } + .bss : ALIGN(4K) { + PROVIDE(bss_start = .); + *(.bss); + . += 4096; + PROVIDE(stack_top = .); + . += 4096; + PROVIDE(global_pointer = .); + PROVIDE(bss_end = .); + } + .rodata : ALIGN(4K) { + *(.rodata); + } + .data : ALIGN(4K) { + *(.data); + } +} diff --git a/arch/x86.json b/arch/x86.json new file mode 100644 index 0000000..9b558de --- /dev/null +++ b/arch/x86.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "i686-unknown-none", + "data-layout": "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-S128", + "arch": "x86", + "target-endian": "little", + "target-pointer-width": "32", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" +} diff --git a/arch/x86.ld b/arch/x86.ld new file mode 100644 index 0000000..440e513 --- /dev/null +++ b/arch/x86.ld @@ -0,0 +1,74 @@ +ENTRY (_start) + +KERNEL_PMA = 0x00100000; +KERNEL_VMA = 0xC0000000; + +SECTIONS +{ + . = KERNEL_PMA; + + + .multiboot.data : { + *(.multiboot2.header) + *(.boot32.rodata) + } + + .multiboot.text : { + *(.multiboot.text) + } + + . += KERNEL_VMA; + + .text ALIGN (4K) : AT (ADDR (.text) - KERNEL_VMA) + { + *(.text) + } + + .got ALIGN (4K) : AT (ADDR (.got) - KERNEL_VMA) + { + *(.got) + } + + .got.plt ALIGN (4K) : AT (ADDR (.got.plt) - KERNEL_VMA) + { + *(.got.plt) + } + + .rodata ALIGN(4K) : AT (ADDR (.rodata) - KERNEL_VMA) + { + *(.rodata) + } + + .data ALIGN (4K) : AT (ADDR (.data) - KERNEL_VMA) + { + *(.data) + } + + .bss ALIGN (4K) : AT (ADDR (.bss) - KERNEL_VMA) + { + *(COMMON) + *(.bss) + *(.bootstrap_stack) + } + + /DISCARD/ : + { + *(.debug_abbrev) + *(.debug_aranges) + *(.debug_frame) + *(.debug_gdb_scripts) + *(.debug_info) + *(.debug_line) + *(.debug_line_str) + *(.debug_loc) + *(.debug_pubnames) + *(.debug_pubtypes) + *(.debug_ranges) + *(.debug_str) + + *(.comment) + *(.note.*) + } + + _kernel_end = .; +} diff --git a/arch/x86_64.json b/arch/x86_64.json new file mode 100644 index 0000000..23da62b --- /dev/null +++ b/arch/x86_64.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" +} diff --git a/arch/x86_64.ld b/arch/x86_64.ld new file mode 100644 index 0000000..da6663e --- /dev/null +++ b/arch/x86_64.ld @@ -0,0 +1,81 @@ +ENTRY(_start) + +KERNEL_AP_PMA = 0x0000000000008000; +KERNEL_PMA = 0x0000000000100000; +KERNEL_VMA = 0xffffffff80000000; + +SECTIONS +{ + /* + . = KERNEL_AP_PMA; + + .apinit BLOCK(4K) : ALIGN(4K) + { + *(.apinit) + } + */ + + . = KERNEL_PMA; + + .boot BLOCK(4K) : ALIGN(4K) + { + KEEP(*(.multiboot2.header)) + *(.boot32.text) + *(.boot32.rodata) + *(.boot32.bss) + *(.boot64.text) + } + + . += KERNEL_VMA; + + .text ALIGN(4K) : AT (ADDR (.text) - KERNEL_VMA) + { + *(.text) + } + + .rodata ALIGN(4K) : AT (ADDR (.rodata) - KERNEL_VMA) + { + *(.rodata) + } + + .rodata. ALIGN(4K) : AT (ADDR (.rodata.) - KERNEL_VMA) + { + *(.rodata.*) + } + + .data ALIGN(4K) : AT (ADDR (.data) - KERNEL_VMA) + { + *(.data) + } + + .bss ALIGN(4K) : AT (ADDR (.bss) - KERNEL_VMA) + { + *(.bss) + } + + .bss. ALIGN(4K) : AT (ADDR (.bss.) - KERNEL_VMA) + { + *(.bss.*) + } + + /DISCARD/ : + { + *(.debug_abbrev) + *(.debug_aranges) + *(.debug_frame) + *(.debug_gdb_scripts) + *(.debug_info) + *(.debug_line) + *(.debug_line_str) + *(.debug_loc) + *(.debug_pubnames) + *(.debug_pubtypes) + *(.debug_ranges) + *(.debug_str) + + *(.comment) + *(.note.*) + } + + _kernel_end = .; +} diff --git a/riscv64-uboot.sh b/riscv64-uboot.sh new file mode 100755 index 0000000..7055608 --- /dev/null +++ b/riscv64-uboot.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +qemu-system-riscv64 -machine virt -kernel /usr/share/qemu/u-boot-riscv64.bin -device loader,file=./src/kernel.bin,addr=0x80200000 -nographic -serial mon:stdio diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..d5c03fb --- /dev/null +++ b/src/Makefile @@ -0,0 +1,18 @@ +CFLAGS += -I include + +ASM_OBJS := $(foreach path, $(ASM_PATHS), $(patsubst %.S, %.o, $(wildcard $(path)/*.S))) + +OBJS = \ + $(ASM_OBJS) \ + $(RUST_OBJS) + +kernel.bin: $(OBJS) $(LD_SCRIPT) ../Makefile Makefile + $(info [kernel] $@) + @$(LD) $(LDFLAGS) -T $(LD_SCRIPT) $(OBJS) -o kernel.bin + +%.o: %.S + $(info [kernel] $@) + @$(CC) $(CFLAGS) -c $< -o $@ + + +.PHONY: all diff --git a/src/arch/mod.rs b/src/arch/mod.rs new file mode 100644 index 0000000..5735bed --- /dev/null +++ b/src/arch/mod.rs @@ -0,0 +1,14 @@ +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod x86; +#[cfg(target_arch = "x86")] +pub use x86::*; + +#[cfg(target_arch = "x86_64")] +mod x86_64; +#[cfg(target_arch = "x86_64")] +pub use x86_64::*; + +#[cfg(target_arch = "riscv64")] +mod riscv64; +#[cfg(target_arch = "riscv64")] +pub use riscv64::*; diff --git a/src/arch/riscv64/boot/entry.S b/src/arch/riscv64/boot/entry.S new file mode 100644 index 0000000..f5fa092 --- /dev/null +++ b/src/arch/riscv64/boot/entry.S @@ -0,0 +1,37 @@ +.section .init + +.option norvc + +.type start, @function +.global start +start: + .cfi_startproc + +.option push +.option norelax + la gp, global_pointer +.option pop + + /* Reset satp */ + csrw satp, zero + + /* Setup stack */ + la sp, stack_top + + /* Clear the BSS section */ + la t5, bss_start + la t6, bss_end +bss_clear: + sd zero, (t5) + addi t5, t5, 8 + bltu t5, t6, bss_clear + + la t0, kernel_main + csrw sepc, t0 + + /* Jump to kernel! */ + tail kernel_main + + .cfi_endproc + +.end diff --git a/src/arch/riscv64/io/mod.rs b/src/arch/riscv64/io/mod.rs new file mode 100644 index 0000000..6d91cab --- /dev/null +++ b/src/arch/riscv64/io/mod.rs @@ -0,0 +1,2 @@ +mod uart; +pub use uart::*; diff --git a/src/arch/riscv64/io/uart.rs b/src/arch/riscv64/io/uart.rs new file mode 100644 index 0000000..7aafeef --- /dev/null +++ b/src/arch/riscv64/io/uart.rs @@ -0,0 +1,27 @@ +use core::fmt; +use core::fmt::Write; + +pub fn _print(args: fmt::Arguments) { + // Not thread safe but no dependencies + let mut stdout = Stdout; + fmt::write(&mut stdout, args); +} + +struct Stdout; +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + print_string(s); + Ok(()) + } +} + +pub fn print_string(s: &str) { + let uart_base = 0x10000000 as *mut u8; + while unsafe { uart_base.add(5).read_volatile() } & 0x20 == 0 {} + + for c in s.chars() { + unsafe { + uart_base.write_volatile(c as u8); + } + } +} diff --git a/src/arch/riscv64/mod.rs b/src/arch/riscv64/mod.rs new file mode 100644 index 0000000..608d4e1 --- /dev/null +++ b/src/arch/riscv64/mod.rs @@ -0,0 +1,2 @@ +mod io; +pub use io::*; diff --git a/src/arch/x86/boot/boot.S b/src/arch/x86/boot/boot.S new file mode 100644 index 0000000..02f6e91 --- /dev/null +++ b/src/arch/x86/boot/boot.S @@ -0,0 +1,126 @@ +.section .bootstrap_stack, "aw", @nobits +stack_bottom: +.skip 16384 +stack_top: + +.section .bss, "aw", @nobits + .align 4096 +page_directory: + .skip 4096 +page_table1: + .skip 4096 +page_table2: + .skip 4096 + + +.set P, 1<<0 +.set RW, 1<<1 +.set FLAGS, P | RW +.set KERNEL_VM, 0xC0000000 + + +.section .multiboot.text, "a" +.global _start +.type _start, @function +_start: +_start: + cli + mov $stack_top - KERNEL_VM, %esp + pushl %eax + pushl %ebx + + movl $page_table1 - KERNEL_VM + FLAGS, page_directory - KERNEL_VM + 0 * 4 + movl $page_table2 - KERNEL_VM + FLAGS, page_directory - KERNEL_VM + 1 * 4 + movl $page_table1 - KERNEL_VM + FLAGS, page_directory - KERNEL_VM + 768 * 4 + movl $page_table2 - KERNEL_VM + FLAGS, page_directory - KERNEL_VM + 769 * 4 + + mov $0, %ecx +not_done: + mov $0x1000, %eax + mul %ecx + orl $FLAGS, %eax + mov %eax, %edi + + // page_table1[%ecx] = 0x1000 * %ecx | 0x3 + mov $4, %eax + mul %ecx + add $page_table1 - KERNEL_VM, %eax + movl %edi, (%eax) + + // page_table2[%ecx] = 0x1000 * %ecx | 0x3 + mov $4, %eax + mul %ecx + add $1024 * 0x1000, %edi + add $page_table2 - KERNEL_VM, %eax + movl %edi, (%eax) + + inc %ecx + cmp $1024, %ecx + je done + jmp not_done +done: + + movl $(page_directory - KERNEL_VM), %ecx + movl %ecx, %cr3 + + movl %cr0, %ecx + orl $0x80001000, %ecx + movl %ecx, %cr0 + + lea 7f, %ecx + jmp *%ecx + + +.section .boot32.rodata + +gdt: +gdt_null = . - gdt + .quad 0 +kernel_code = . - gdt + .long 0xFFFF + .byte 0 + .byte 0x9A + .byte 0xCF + .byte 0 +kernel_data = . - gdt + .long 0xFFFF + .byte 0 + .byte 0x92 + .byte 0xCF + .byte 0 +user_code = . - gdt + .long 0xFFFF + .byte 0 + .byte 0xFA + .byte 0xCF + .byte 0 +user_data = . - gdt + .long 0xFFFF + .byte 0 + .byte 0xF2 + .byte 0xCF + .byte 0 + +.global gdtp +gdtp: + .word . - gdt - 1 + .long gdt + + +.section .text + +7: + addl $KERNEL_VM, %esp + lgdtl gdtp + ljmp $0x08, $code + +code: + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + call kernel_main + hlt diff --git a/src/arch/x86/common/boot/mod.rs b/src/arch/x86/common/boot/mod.rs new file mode 100644 index 0000000..b6aebe5 --- /dev/null +++ b/src/arch/x86/common/boot/mod.rs @@ -0,0 +1,2 @@ +mod multiboot; +pub use multiboot::*; diff --git a/src/arch/x86/common/boot/multiboot.S b/src/arch/x86/common/boot/multiboot.S new file mode 100644 index 0000000..8773b1f --- /dev/null +++ b/src/arch/x86/common/boot/multiboot.S @@ -0,0 +1,11 @@ +.set ALIGN, 1<<0 +.set MEMINFO, 1<<1 +.set FLAGS, ALIGN | MEMINFO +.set MAGIC, 0x1BADB002 +.set CHECKSUM, -(MAGIC + FLAGS) + +.section .multiboot.header, "aw" +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM diff --git a/src/arch/x86/common/boot/multiboot.rs b/src/arch/x86/common/boot/multiboot.rs new file mode 100644 index 0000000..09789ce --- /dev/null +++ b/src/arch/x86/common/boot/multiboot.rs @@ -0,0 +1,79 @@ +pub const MULTIBOOT2_BOOTLOADER_MAGIC: u32 = 0x36d76289; +pub const MULTIBOOT_TAG_TYPE_END: u32 = 0; +pub const MULTIBOOT_TAG_TYPE_MMAP: u32 = 6; +pub const MULTIBOOT_TAG_TYPE_FB: u32 = 8; + +use crate::{print, println}; + +pub fn parse_fb_multiboot(mut mem: *mut u32) { + let framebuffer_addr: u64 = unsafe { *(mem as *mut u64) }; + let framebuffer_pitch: u32 = unsafe { *mem.wrapping_add(2) }; + let framebuffer_width: u32 = unsafe { *mem.wrapping_add(3) }; + let framebuffer_height: u32 = unsafe { *mem.wrapping_add(4) }; + let framebuffer_bpp: u8 = unsafe { *(mem.wrapping_add(5) as *mut u8) }; + let framebuffer_type: u8 = unsafe { *(mem.wrapping_add(5) as *mut u8).wrapping_add(1) }; + let reserved: u8 = unsafe { *(mem.wrapping_add(5) as *mut u8).wrapping_add(1) }; + + println!( + "0x{:x} {:x} {:x} {:x}", + framebuffer_addr, framebuffer_pitch, framebuffer_width, framebuffer_height + ); +} + +pub fn parse_mem_multiboot(mut mem: *mut u32, _size: u32) { + let mut curr_size: u32 = 16; + + while curr_size < _size { + let base_addr: u64 = unsafe { *(mem as *mut u64) }; + let length: u64 = unsafe { *(mem.wrapping_add(2) as *mut u64) }; + let _type: u32 = unsafe { *mem.wrapping_add(4) }; + let reserved: u32 = unsafe { *mem.wrapping_add(5) }; + assert_eq!(reserved, 0, "reserved not 0"); + + //println!("{:x} {:x} {:x}", base_addr, length, _type); + + mem = mem.wrapping_add(6); + curr_size += 24; + } +} + +pub fn parse_multiboot(mut multiboot_bootinfo: *mut u32, multiboot_magic: u32) { + assert_eq!( + multiboot_magic, MULTIBOOT2_BOOTLOADER_MAGIC, + "MULTIBOOT2_BOOTLOADER_MAGIC" + ); + + let total_size: u32 = unsafe { *multiboot_bootinfo }; + let mut size = 8; + multiboot_bootinfo = multiboot_bootinfo.wrapping_add(2); + + while size < total_size { + let _type: u32 = unsafe { *multiboot_bootinfo }; + let _size: u32 = unsafe { *(multiboot_bootinfo.wrapping_add(1)) }; + let mem: *mut u32 = multiboot_bootinfo.wrapping_add(4); + let mem2: *mut u32 = multiboot_bootinfo.wrapping_add(2); + + match _type { + MULTIBOOT_TAG_TYPE_FB => { + parse_fb_multiboot(mem2); + } + MULTIBOOT_TAG_TYPE_MMAP => { + parse_mem_multiboot(mem, _size); + } + _ => {} + } + + let inc_size = (_size / 8 + (_size % 8 != 0) as u32) * 8; + size += inc_size; + + println!("{} {} {}", _type, _size, inc_size); + multiboot_bootinfo = multiboot_bootinfo.wrapping_add((inc_size / 4).try_into().unwrap()); + + if _type == MULTIBOOT_TAG_TYPE_END { + assert_eq!(_size, 8, "MULTIBOOT_TAG_TYPE_END"); + break; + } + } + + assert_eq!(total_size, size, "Multiboot"); +} diff --git a/src/arch/x86/common/boot/multiboot2.S b/src/arch/x86/common/boot/multiboot2.S new file mode 100644 index 0000000..d767ca0 --- /dev/null +++ b/src/arch/x86/common/boot/multiboot2.S @@ -0,0 +1,42 @@ +/* multiboot tags */ +.set TAG_END, 0 +.set TAG_FRAMEBUFFER, 5 + +/* multiboot flags */ +.set TAG_REQUIRED, 0 +.set TAG_OPTIONAL, 1 + +/* multiboot2 header constants */ +.set MAGIC, 0xe85250d6 +.set ARCH, 0 +.set HEADER_LENGTH, (header_end - header_start) +.set CHECKSUM, 0x100000000 - (MAGIC + ARCH + HEADER_LENGTH) + +.section .multiboot2.header, "a" +.align 4 +header_start: + /* magic */ + .align 8 + .long MAGIC + .long ARCH + .long HEADER_LENGTH + .long CHECKSUM + +/* + // framebuffer + .align 8 + .word TAG_FRAMEBUFFER + .word TAG_REQUIRED + .long 20 + .long 1024 + .long 768 + .long 32 +*/ + + /* end tag */ + .align 8 + .word TAG_END + .word TAG_REQUIRED + .long 8 + +header_end: diff --git a/src/arch/x86/common/forall.rs b/src/arch/x86/common/forall.rs new file mode 100644 index 0000000..39988e6 --- /dev/null +++ b/src/arch/x86/common/forall.rs @@ -0,0 +1,5 @@ +use crate::{print, println}; + +pub fn forall() { + println!("forall"); +} diff --git a/src/arch/x86/common/io/mod.rs b/src/arch/x86/common/io/mod.rs new file mode 100644 index 0000000..604e84c --- /dev/null +++ b/src/arch/x86/common/io/mod.rs @@ -0,0 +1,2 @@ +mod writer; +pub use writer::*; diff --git a/src/arch/x86/common/io/writer.rs b/src/arch/x86/common/io/writer.rs new file mode 100644 index 0000000..7361693 --- /dev/null +++ b/src/arch/x86/common/io/writer.rs @@ -0,0 +1,72 @@ +use core::fmt; +use core::fmt::Write; +use lazy_static::lazy_static; +use spin::Mutex; + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + WRITER.lock().write_fmt(args).unwrap(); +} + +lazy_static! { + pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer::new()); +} + +#[derive(Default)] +pub struct Writer { + max_y: isize, + max_x: isize, + x: isize, + y: isize, + addr: u32, +} + +impl Writer { + pub fn new() -> Self { + Self { + x: 0, + y: 0, + max_y: 25, + max_x: 80, + addr: 0xb8000, + } + } + + pub fn write(&mut self, c: char, b: u8) { + let off: isize = self.y * self.max_x + self.x; + let vga_buffer = self.addr as *mut u8; + + if c != '\n' { + unsafe { + *vga_buffer.offset(2 * off) = c as u8; + *vga_buffer.offset(2 * off + 1) = b; + } + self.x += 1; + } else { + self.x = 0; + self.y += 1; + } + + if self.x >= self.max_x { + self.x = 0; + self.y += 1; + } + + if self.y >= self.max_y { + self.y = 0; + } + } + + pub fn print(&mut self, s: &str, b: u8) { + for i in s.chars() { + self.write(i, b); + } + } +} + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.print(s, 0xb); + Ok(()) + } +} diff --git a/src/arch/x86/common/mod.rs b/src/arch/x86/common/mod.rs new file mode 100644 index 0000000..d1d4d98 --- /dev/null +++ b/src/arch/x86/common/mod.rs @@ -0,0 +1,8 @@ +mod forall; +pub use forall::*; + +mod io; +pub use io::*; + +mod boot; +pub use boot::*; diff --git a/src/arch/x86/mod.rs b/src/arch/x86/mod.rs new file mode 100644 index 0000000..c47ad74 --- /dev/null +++ b/src/arch/x86/mod.rs @@ -0,0 +1,10 @@ +#[cfg(target_arch = "x86")] +mod common; +#[cfg(target_arch = "x86")] +pub use common::*; + +#[cfg(target_arch = "x86_64")] +pub mod common; + +mod once; +pub use once::*; diff --git a/src/arch/x86/once.rs b/src/arch/x86/once.rs new file mode 100644 index 0000000..9397afb --- /dev/null +++ b/src/arch/x86/once.rs @@ -0,0 +1,6 @@ +use crate::{print, println}; + +pub fn once() +{ + println!("x86"); +} diff --git a/src/arch/x86_64/boot/boot.S b/src/arch/x86_64/boot/boot.S new file mode 100644 index 0000000..1dc2320 --- /dev/null +++ b/src/arch/x86_64/boot/boot.S @@ -0,0 +1,128 @@ +.code32 +.extern begin_long_mode + +.section .boot32.text, "a" + +.set STACK_TOP, 0x03008000 + +.global _start +_start: + cli + mov $STACK_TOP, %esp + pushl $0 + pushl %eax + pushl $0 + pushl %ebx + + call setup_page_tables + call enable_paging + + lgdt gdtp + ljmp $0x08, $begin_long_mode + +setup_page_tables: +/* first 2mb */ + mov $pt_lvl3, %eax + or $0x3, %eax + mov %eax, pt_lvl4 + + mov $pt_lvl2, %eax + or $0x3, %eax + mov %eax, pt_lvl3 + + xor %ecx, %ecx +1: + movl $0x00200000, %eax + mul %ecx + or $0b10000011, %eax + movl $pt_lvl2, %edx + leal (%edx, %ecx, 8), %edx + movl %eax, (%edx) + inc %ecx + cmp $25, %ecx + jne 1b + +/* first 2mb in hh */ + mov $pt_lvl3_hh, %eax + or $0x3, %eax + mov %eax, pt_lvl4 + 4096 - 8 + + mov $pt_lvl2_hh, %eax + or $0x3, %eax + mov %eax, pt_lvl3_hh + 4096 - 16 + + xor %ecx, %ecx +2: + movl $0x00200000, %eax + mul %ecx + or $0b10000011, %eax + movl $pt_lvl2_hh, %edx + leal (%edx, %ecx, 8), %edx + movl %eax, (%edx) + inc %ecx + cmp $25, %ecx + jne 2b + + ret + +.global enable_paging +enable_paging: + /* enable PAE */ + mov %cr4, %edx + or $1<<5 ,%edx + mov %edx, %cr4 + + /* set LME (long mode enable) */ + mov $0xC0000080, %ecx + rdmsr + or $1<<8, %eax + wrmsr + + /* pt_lvl4 */ + mov $pt_lvl4, %eax + mov %eax, %cr3 + + /* enable paging (+ protected mode if not already enabled) */ + mov %cr0, %eax + or $1<<31 + 1<<0, %eax + mov %eax, %cr0 + + ret + + +.section .boot32.rodata + +gdt: +gdt_null = . - gdt + .quad 0 +gdt_code = . - gdt + .long 0xFFFF + .byte 0 + .byte 0x9A + .byte 0xAF + .byte 0 +gdt_data = . - gdt + .long 0xFFFF + .byte 0 + .byte 0x92 + .byte 0xAF + .byte 0 +.global gdtp +gdtp: + .word . - gdt - 1 + .quad gdt + + +.section .boot32.bss +.align 4096 + +pt_lvl4: + .skip 4096 +pt_lvl3: + .skip 4096 +pt_lvl3_hh: + .skip 4096 +pt_lvl2: + .skip 4096 +pt_lvl2_hh: + .skip 4096 diff --git a/src/arch/x86_64/boot/boot64.S b/src/arch/x86_64/boot/boot64.S new file mode 100644 index 0000000..848256f --- /dev/null +++ b/src/arch/x86_64/boot/boot64.S @@ -0,0 +1,26 @@ +.code64 + +.set KERNEL_VMA, 0xffffffff80000000 +.set GDT_KERNEL_CS, 0x10 + +.section .boot64.text, "a" + +.global begin_long_mode +begin_long_mode: + mov $GDT_KERNEL_CS, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %ss + mov %ax, %fs + mov %ax, %gs + + add $KERNEL_VMA, %rsp + movabs $jump_main, %rax + jmp *%rax + +.section .text +jump_main: + popq %rdi + popq %rsi + call kernel_main + hlt diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs new file mode 100644 index 0000000..a5f019b --- /dev/null +++ b/src/arch/x86_64/mod.rs @@ -0,0 +1,4 @@ +pub use crate::arch::x86::common::*; + +mod once; +pub use once::*; diff --git a/src/arch/x86_64/once.rs b/src/arch/x86_64/once.rs new file mode 100644 index 0000000..8aebbcb --- /dev/null +++ b/src/arch/x86_64/once.rs @@ -0,0 +1,6 @@ +use crate::{print, println}; + +pub fn once() +{ + println!("x86_64"); +} diff --git a/src/grub.cfg b/src/grub.cfg new file mode 100644 index 0000000..95df700 --- /dev/null +++ b/src/grub.cfg @@ -0,0 +1,7 @@ +set timeout=0 +set default=0 + +insmod efi_gop +menuentry "myrustkernel" { + multiboot2 /boot/kernel.bin +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..26dc19d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +pub mod arch; + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::arch::_print(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! println { + () => (print!("\n")); + ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + println!("{}", info); + loop {} +} + +#[no_mangle] +//pub extern "C" fn kernel_main(multiboot_bootinfo: *mut u32, multiboot_magic: u32) -> ! { +pub extern "C" fn kernel_main() -> ! { + //arch::parse_multiboot(multiboot_bootinfo, multiboot_magic); + //arch::forall(); + //arch::once(); + + let mut x = 10; + for i in 0..100 { + x += i; + } + + println!("Hello World! {}", x); + + loop {} +} diff --git a/tftp/dnsmasq.conf b/tftp/dnsmasq.conf new file mode 100644 index 0000000..01a1782 --- /dev/null +++ b/tftp/dnsmasq.conf @@ -0,0 +1,20 @@ +interface=enp7s0 +bind-interfaces +domain=example.org +dhcp-option=3,0.0.0.0 +dhcp-option=6,0.0.0.0 +dhcp-option=121,192.168.111.0/24,192.168.111.1 +dhcp-range=192.168.111.50,192.168.111.100,5m +dhcp-range=::f,::ff,constructor:enp7s0 +dhcp-host=30:85:a9:88:61:0e,192.168.111.69 + +enable-tftp +tftp-root=/srv/tftp + +dhcp-match=set:efi-x86_64,option:client-arch,7 +dhcp-match=set:efi-x86_64,option:client-arch,9 +dhcp-match=set:efi-x86,option:client-arch,6 +dhcp-match=set:bios,option:client-arch,0 +dhcp-boot=tag:efi-x86_64,boot/grub/x86_64-efi/core.efi +dhcp-boot=tag:efi-x86,boot/grub/i386-efi/core.efi +dhcp-boot=tag:bios,boot/grub/i386-pc/core.0 diff --git a/tftp/dnsmasq.service b/tftp/dnsmasq.service new file mode 100644 index 0000000..c30c334 --- /dev/null +++ b/tftp/dnsmasq.service @@ -0,0 +1,20 @@ +[Unit] +Description=dnsmasq - A lightweight DHCP and caching DNS server +Documentation=man:dnsmasq(8) +After=network.target +Before=network-online.target nss-lookup.target +Wants=nss-lookup.target + +[Service] +Type=dbus +BusName=uk.org.thekelleys.dnsmasq +ExecStartPre=/usr/bin/dnsmasq --test +ExecStartPre=/home/aleksa/mygit/myrustkernel/tftp/setup.sh +ExecStart=/usr/bin/dnsmasq -k --enable-dbus --user=dnsmasq --pid-file +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +PrivateDevices=true +ProtectSystem=full + +[Install] +WantedBy=multi-user.target diff --git a/tftp/setup.sh b/tftp/setup.sh new file mode 100755 index 0000000..7e1737c --- /dev/null +++ b/tftp/setup.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +INTERFACE="enp7s0" +IP_ADDRESS="192.168.111.1/24" + +if ! ip addr show dev $INTERFACE | grep -q "$IP_ADDRESS"; then + sudo nmcli dev set $INTERFACE managed no + sudo ip link set $INTERFACE up + sudo ip addr add $IP_ADDRESS dev $INTERFACE + sudo systemctl restart dnsmasq + echo "Configuration applied successfully." +else + echo "IP address $IP_ADDRESS is already assigned to $INTERFACE." + echo "No changes made." +fi |
