@@ -20,18 +20,29 @@ MAX_MEM: equ 512
2020; they would be no longer accessable after the kernel switch to a higher half
2121; mapping. This is especially true for the multiboot info data.
2222
23+ ; Also be careful with imm width in asm instructions
24+ ; many instructions does not take 64 bit imm value. e.g. cmp. If the operand is
25+ ; an extern symbol the linker may tell you xyz "truncate to fit". In which case
26+ ; you should load the addresses or values into an register before using them
2327
2428; exported symbols
2529[GLOBAL startup]
2630[GLOBAL mb_magic]
2731[GLOBAL mb_info_addr]
2832; functions from other parts of rustubs
29- [EXTERN _entry]
3033[EXTERN ___BSS_PM_START__]
3134[EXTERN ___BSS_PM_END__]
32-
33- [SECTION .text]
34-
35+ [EXTERN KERNEL_OFFSET]
36+ [EXTERN _entry]
37+ ; =====================================================================
38+ ; begin of the text secion: unlike the text* sections from the rust code
39+ ; the text here is not supposed to be relocated to an higher memory,
40+ ; as we can not use high memory until we completely set up longmode paging.
41+ ; Therefore we explicitly link the startup text section to low address.
42+ ; the same goes for the ".data32" section: they are not necessarily 32bit,
43+ ; the point is to confine all address within 4GB (32bit) range
44+ ; =====================================================================
45+ [SECTION .text32]
3546; symbols used in 32bit mode:
3647; mb_magic
3748; mab_info_addr
@@ -45,6 +56,7 @@ startup:
4556 ; EAX: magic value 0x2BADB002
4657 ; EBX: 32-bit physical address of the multiboot information struct
4758 ; we store them in global variables for future uses in rust code.
59+ ; TODO place them on the stack and pass as parameters to _entry
4860 mov dword [ mb_magic ], eax
4961 mov dword [ mb_info_addr ], ebx
5062 ; setup GDT by loading GDT descriptor
@@ -59,7 +71,7 @@ startup:
5971
6072 ; define stack
6173 mov ss , ax
62- mov esp , init_stack + STACKSIZE
74+ lea esp , init_stack + STACKSIZE
6375
6476init_longmode:
6577 ; activate address extension (PAE)
@@ -81,12 +93,13 @@ clear_pt:
8193 ; table levels needed. see docs/x86_paging.txt
8294
8395 ; PML4 (Page Map Level 4 / 1st level)
96+ ; PML4 entry flag: 0xf = PRESENG | R/W | USER | Write Through
8497 mov eax , pdp0
8598 or eax , 0xf
8699 mov dword [ pml4 + 0 ], eax
87100 mov dword [ pml4 + 4 ], 0
88- ; PDPE flags
89- mov eax , 0x0 | 0x87 ; start-address bytes bit [30:31] + flags
101+ ; PDPE flags 0x87 = PageSize=1G | USER | R/W | PRESENT
102+ mov eax , 0x0 | 0x83 ; start-address bytes bit [30:31] + flags
90103 mov ebx , 0 ; start-address bytes bit [32:38]
91104 mov ecx , 0
92105fill_tables2:
@@ -126,22 +139,20 @@ activate_long_mode:
126139; - symbols defined in 64 bit code below, if mapped to higher memory (VA)
127140; - all symbols exported from rust code or linker script
128141; =====================================================================
129-
130142[BITS 64]
131143longmode_start:
132144 ; now we set the pagetables for higher half memory
133145 ; since we have Provisional paging now, why not using 64bit code?
134- mov eax , pdp1
135- or eax , 0xf
136- mov dword [ pml4 + 256 ], eax
137- mov dword [ pml4 + 256 + 4 ], 0
138- ; PDPE flags, see above
139-
146+ ; the 256th entry of pml4 points to memory from 0xffff_8000_0000_0000
147+ mov rax , pdp1
148+ ; privileged, r/w, present
149+ or rax , 0x3
150+ mov qword [ pml4 + 256 * 8 ], rax
140151 ; entry 0~63 is an identical mapping with offset 0x8000_0000_0000
141- ; clear the BSS section before going to rust code
152+ ; 1G Page | Privileged | R/W | PRESENT
142153 ; TODO this should not be executable
143154 mov rax , 0x0
144- or rax , 0x87
155+ or rax , 0x83
145156 mov rdi , 0
146157fill_kvma1:
147158 mov qword [ pdp1 + 8 * rdi ], rax
@@ -153,7 +164,7 @@ fill_kvma1:
153164 ; entry 64~127 is a hole (also some sort of protection)
154165 ; entry 128~191 are mapping of the kernel image itself
155166 mov rax , 0x0
156- or rax , 0x87
167+ or rax , 0x83
157168 mov rdi , 128
158169fill_kvma2:
159170 mov qword [ pdp1 + 8 * rdi ], rax
@@ -162,33 +173,43 @@ fill_kvma2:
162173 cmp rdi , 192
163174 jne fill_kvma2
164175 ; done :-)
165-
166176 ; clear BSS section for the rust code.
167177 mov rdi , ___BSS_PM_START__
178+ mov rax , ___BSS_PM_END__
168179clear_bss:
180+ ; clear the BSS section before going to rust code
181+ ; TODO speed this up by clearing 8 bytes at once. Alignment should be taken
182+ ; care of..
169183 mov byte [ rdi ], 0
170184 inc rdi
171- cmp rdi , ___BSS_PM_END__
185+ cmp rdi , rax
172186 jne clear_bss
187+
173188 ; enable FPU
174189 fninit
175190
176191 ; NOTE: must NOT use sse target features for rust compiler, if sse not
177192 ; enabled here.
178193
194+ ; shift the rsp to high memory mapping:
195+ mov rax , KERNEL_OFFSET ,
196+ or rsp , rax
179197 ; finally go to the rust code!
180- call _entry
198+ mov rax , _entry
199+ jmp rax
200+
181201 ; should not reach below
182202 cli
183203 hlt
184204
185205; =====================================================================
186206; data sections they should all have VAs identical to their PAs
187207; so we map these symbols differently than those generated by rust code
208+ ; the "data" itself doesn't care about 64 or 32 bit width, but we need
209+ ; to make sure they are not relocated to an address bigger then 4G (32)
188210; =====================================================================
189211
190- [SECTION .data]
191-
212+ [SECTION .data32]
192213gdt:
193214 ; see docs/x86_gdt.txt
194215
@@ -232,8 +253,7 @@ mb_magic:
232253mb_info_addr:
233254 dd 0x00000000
234255
235- [SECTION .bss]
236-
256+ [SECTION .init_k_stack]
237257global init_stack:data (init_stack.end - init_stack)
238258init_stack:
239259 resb STACKSIZE
0 commit comments