diff options
| author | Tianhao Wang <shrik3@mailbox.org> | 2024-06-04 17:50:10 +0200 |
|---|---|---|
| committer | Tianhao Wang <shrik3@mailbox.org> | 2024-06-11 15:17:12 +0200 |
| commit | 4bce609d2a0145e70f44227636a68348e9b23cf9 (patch) | |
| tree | 8c753a99644172f0fd3bb5d382ae1b7790b137e6 | |
| parent | f4b50dd826b81295dc9628b655fc5f360445230b (diff) | |
mm: fully map the kernel to high memory
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | boot/startup-x86_64.s | 68 | ||||
| -rw-r--r-- | defs/x86_64-hm-linker.ld | 119 | ||||
| -rw-r--r-- | src/arch/x86_64/asm/vectors.s | 3 |
4 files changed, 168 insertions, 27 deletions
@@ -19,9 +19,10 @@ ARCH = x86_64 ASM = nasm ASMOBJFORMAT = elf64 ASMFLAGS = -w-zeroing -LINKER_SCRIPT = ./defs/$(ARCH)-linker.ld +LINKER_SCRIPT = ./defs/$(ARCH)-hm-linker.ld CARGO_XBUILD_TARGET = ./defs/$(ARCH)-rustubs.json CARGO_XBUILD_FLAGS = +RUSTC_FLAGS := -C code-model=large # ---------- No need to edit below this line -------------- # ---------- If you have to, something is wrong ----------- LDFLAGS = -no-warn-rwx-segment -static -e startup @@ -65,7 +66,7 @@ $(BUILD)/_%.o : %.s | $(BUILD) # define this, the linker will have troubles, especially when we use a "no_std" build rust_kernel: check @echo "---BUILDING RUST KERNEL---" - @cargo xbuild --target $(CARGO_XBUILD_TARGET) $(CARGO_XBUILD_FLAGS) + @RUSTFLAGS="$(RUSTC_FLAGS)" cargo xbuild --target $(CARGO_XBUILD_TARGET) $(CARGO_XBUILD_FLAGS) # need nasm # TODO make this arch dependent diff --git a/boot/startup-x86_64.s b/boot/startup-x86_64.s index f08c752..c97db5e 100644 --- a/boot/startup-x86_64.s +++ b/boot/startup-x86_64.s @@ -20,18 +20,29 @@ MAX_MEM: equ 512 ; they would be no longer accessable after the kernel switch to a higher half ; mapping. This is especially true for the multiboot info data. +; Also be careful with imm width in asm instructions +; many instructions does not take 64 bit imm value. e.g. cmp. If the operand is +; an extern symbol the linker may tell you xyz "truncate to fit". In which case +; you should load the addresses or values into an register before using them ; exported symbols [GLOBAL startup] [GLOBAL mb_magic] [GLOBAL mb_info_addr] ; functions from other parts of rustubs -[EXTERN _entry] [EXTERN ___BSS_PM_START__] [EXTERN ___BSS_PM_END__] - -[SECTION .text] - +[EXTERN KERNEL_OFFSET] +[EXTERN _entry] +; ===================================================================== +; begin of the text secion: unlike the text* sections from the rust code +; the text here is not supposed to be relocated to an higher memory, +; as we can not use high memory until we completely set up longmode paging. +; Therefore we explicitly link the startup text section to low address. +; the same goes for the ".data32" section: they are not necessarily 32bit, +; the point is to confine all address within 4GB (32bit) range +; ===================================================================== +[SECTION .text32] ; symbols used in 32bit mode: ; mb_magic ; mab_info_addr @@ -45,6 +56,7 @@ startup: ; EAX: magic value 0x2BADB002 ; EBX: 32-bit physical address of the multiboot information struct ; we store them in global variables for future uses in rust code. + ; TODO place them on the stack and pass as parameters to _entry mov dword [mb_magic], eax mov dword [mb_info_addr], ebx ; setup GDT by loading GDT descriptor @@ -59,7 +71,7 @@ startup: ; define stack mov ss, ax - mov esp, init_stack+STACKSIZE + lea esp, init_stack+STACKSIZE init_longmode: ; activate address extension (PAE) @@ -81,12 +93,13 @@ clear_pt: ; table levels needed. see docs/x86_paging.txt ; PML4 (Page Map Level 4 / 1st level) + ; PML4 entry flag: 0xf = PRESENG | R/W | USER | Write Through mov eax, pdp0 or eax, 0xf mov dword [pml4+0], eax mov dword [pml4+4], 0 - ; PDPE flags - mov eax, 0x0 | 0x87 ; start-address bytes bit [30:31] + flags + ; PDPE flags 0x87 = PageSize=1G | USER | R/W | PRESENT + mov eax, 0x0 | 0x83 ; start-address bytes bit [30:31] + flags mov ebx, 0 ; start-address bytes bit [32:38] mov ecx, 0 fill_tables2: @@ -126,22 +139,20 @@ activate_long_mode: ; - symbols defined in 64 bit code below, if mapped to higher memory (VA) ; - all symbols exported from rust code or linker script ; ===================================================================== - [BITS 64] longmode_start: ; now we set the pagetables for higher half memory ; since we have Provisional paging now, why not using 64bit code? - mov eax, pdp1 - or eax, 0xf - mov dword [pml4+256], eax - mov dword [pml4+256+4], 0 - ; PDPE flags, see above - + ; the 256th entry of pml4 points to memory from 0xffff_8000_0000_0000 + mov rax, pdp1 + ; privileged, r/w, present + or rax, 0x3 + mov qword [pml4+256*8], rax ; entry 0~63 is an identical mapping with offset 0x8000_0000_0000 - ; clear the BSS section before going to rust code + ; 1G Page | Privileged | R/W | PRESENT ; TODO this should not be executable mov rax, 0x0 - or rax, 0x87 + or rax, 0x83 mov rdi, 0 fill_kvma1: mov qword [pdp1 + 8*rdi], rax @@ -153,7 +164,7 @@ fill_kvma1: ; entry 64~127 is a hole (also some sort of protection) ; entry 128~191 are mapping of the kernel image itself mov rax, 0x0 - or rax, 0x87 + or rax, 0x83 mov rdi, 128 fill_kvma2: mov qword [pdp1 + 8*rdi], rax @@ -162,22 +173,31 @@ fill_kvma2: cmp rdi, 192 jne fill_kvma2 ; done :-) - ; clear BSS section for the rust code. mov rdi, ___BSS_PM_START__ + mov rax, ___BSS_PM_END__ clear_bss: + ; clear the BSS section before going to rust code + ; TODO speed this up by clearing 8 bytes at once. Alignment should be taken + ; care of.. mov byte [rdi], 0 inc rdi - cmp rdi, ___BSS_PM_END__ + cmp rdi, rax jne clear_bss + ; enable FPU fninit ; NOTE: must NOT use sse target features for rust compiler, if sse not ; enabled here. + ; shift the rsp to high memory mapping: + mov rax, KERNEL_OFFSET, + or rsp, rax ; finally go to the rust code! - call _entry + mov rax, _entry + jmp rax + ; should not reach below cli hlt @@ -185,10 +205,11 @@ clear_bss: ; ===================================================================== ; data sections they should all have VAs identical to their PAs ; so we map these symbols differently than those generated by rust code +; the "data" itself doesn't care about 64 or 32 bit width, but we need +; to make sure they are not relocated to an address bigger then 4G (32) ; ===================================================================== -[SECTION .data] - +[SECTION .data32] gdt: ; see docs/x86_gdt.txt @@ -232,8 +253,7 @@ mb_magic: mb_info_addr: dd 0x00000000 -[SECTION .bss] - +[SECTION .init_k_stack] global init_stack:data (init_stack.end - init_stack) init_stack: resb STACKSIZE diff --git a/defs/x86_64-hm-linker.ld b/defs/x86_64-hm-linker.ld new file mode 100644 index 0000000..2b12539 --- /dev/null +++ b/defs/x86_64-hm-linker.ld @@ -0,0 +1,119 @@ + +/* defs for Multiboot headers */ +/* https://www.gnu.org/software/grub/manual/multiboot/multiboot.txt */ +MB_MAGIC = 0x1badb002; +/* bit 0 + * all boot modules loaded along with the operating system must be + * aligned on page (4KB) bit 1 must include mem_* structures + */ +MB_FLAGS = 0x3; +MB_CHKSUM = 0x100000000 - (MB_MAGIC + MB_FLAGS); + +PROVIDE(KERNEL_OFFSET = 0xffff800000000000); + +SECTIONS +{ + . = 0x100000; + PROVIDE (___KERNEL_PM_START__ = . ); + .boot : + { + header_start = .; + LONG(MB_MAGIC) + LONG(MB_FLAGS) + LONG(MB_CHKSUM) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + header_end = .; + } + + + .d32 : + { + *(".data32") + } + + .reserved : + { + *(".reserved") + *(".reserved.*") + *(".gdt") + } + + /* + * basically the same as BSS, but I want some flexibility and I don't care + * for zeroing because it's explicitly overwritten anyways. I KNOW WHAT I'M + * DOING! An example is the idt. + */ + .reserved_0 (NOLOAD) : + { + *(".init_k_stack") + *(".reserved_0") + *(".reserved_0.*") + *(".reserved_0.init_stack") + } + + + /* global page table for 64-bit long mode */ + .global_pagetable ALIGN(4096) (NOLOAD) : + { + *(".global_pagetable") + } + + . = ALIGN(4096); + /* reserve space for a premitive stack based physical frame allocator */ + /* each frame is 4KiB in size and has a 64bit (physical) address. e.g. */ + /* for every 1 GiB physical memory we need 2 MiB space reserved for the */ + /* free stack. For a easier bootstraping we are using a fix-sized stack */ + /* array. Currently using 4GiB, therefore reserve 8MiB. */ + PROVIDE (___FREE_PAGE_STACK__ = .); + .global_free_page_stack ALIGN(4096) (NOLOAD) : + { + *("..global_free_page_stack") + } + . = ALIGN(4096); + + .t32 : + { + *(".text32") + *(".text.interrupt_gate") + } + + . = . + KERNEL_OFFSET; + .text : AT(ADDR(.text) - KERNEL_OFFSET) + { + *(".text") + *(".text.*") + *(".text$") + } + + .data : AT(ADDR(.data) - KERNEL_OFFSET) + { + *(".data") + *(".data.*") + *(".data$") + } + + .bss : AT(ADDR(.bss) - KERNEL_OFFSET) + { + PROVIDE (___BSS_PM_START__ = .); + *(".bss") + *(".bss.*") + PROVIDE (___BSS_PM_END__ = .); + } + + .rodata : AT(ADDR(.rodata) - KERNEL_OFFSET) + { + *(".rodata") + *(".rodata$") + *(".rodata.*") + } + + PROVIDE (___KERNEL_PM_END__ = . - KERNEL_OFFSET); +} diff --git a/src/arch/x86_64/asm/vectors.s b/src/arch/x86_64/asm/vectors.s index d5a2357..56aabf4 100644 --- a/src/arch/x86_64/asm/vectors.s +++ b/src/arch/x86_64/asm/vectors.s @@ -1,5 +1,6 @@ +; vi: ft=nasm ; vectors.s - idt for x86_64 - +[BITS 64] [GLOBAL idt] [GLOBAL idt_descr] [GLOBAL vectors_start] |
