From 4bce609d2a0145e70f44227636a68348e9b23cf9 Mon Sep 17 00:00:00 2001 From: Tianhao Wang Date: Tue, 4 Jun 2024 17:50:10 +0200 Subject: mm: fully map the kernel to high memory --- boot/startup-x86_64.s | 68 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 24 deletions(-) (limited to 'boot/startup-x86_64.s') 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 -- cgit v1.2.3-70-g09d2