@@ -20,18 +20,29 @@ MAX_MEM: equ 512
20
20
; they would be no longer accessable after the kernel switch to a higher half
21
21
; mapping. This is especially true for the multiboot info data.
22
22
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
23
27
24
28
; exported symbols
25
29
[GLOBAL startup]
26
30
[GLOBAL mb_magic]
27
31
[GLOBAL mb_info_addr]
28
32
; functions from other parts of rustubs
29
- [EXTERN _entry]
30
33
[EXTERN ___BSS_PM_START__]
31
34
[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]
35
46
; symbols used in 32bit mode:
36
47
; mb_magic
37
48
; mab_info_addr
@@ -45,6 +56,7 @@ startup:
45
56
; EAX: magic value 0x2BADB002
46
57
; EBX: 32-bit physical address of the multiboot information struct
47
58
; 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
48
60
mov dword [ mb_magic ], eax
49
61
mov dword [ mb_info_addr ], ebx
50
62
; setup GDT by loading GDT descriptor
@@ -59,7 +71,7 @@ startup:
59
71
60
72
; define stack
61
73
mov ss , ax
62
- mov esp , init_stack + STACKSIZE
74
+ lea esp , init_stack + STACKSIZE
63
75
64
76
init_longmode:
65
77
; activate address extension (PAE)
@@ -81,12 +93,13 @@ clear_pt:
81
93
; table levels needed. see docs/x86_paging.txt
82
94
83
95
; PML4 (Page Map Level 4 / 1st level)
96
+ ; PML4 entry flag: 0xf = PRESENG | R/W | USER | Write Through
84
97
mov eax , pdp0
85
98
or eax , 0xf
86
99
mov dword [ pml4 + 0 ], eax
87
100
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
90
103
mov ebx , 0 ; start-address bytes bit [32:38]
91
104
mov ecx , 0
92
105
fill_tables2:
@@ -126,22 +139,20 @@ activate_long_mode:
126
139
; - symbols defined in 64 bit code below, if mapped to higher memory (VA)
127
140
; - all symbols exported from rust code or linker script
128
141
; =====================================================================
129
-
130
142
[BITS 64]
131
143
longmode_start:
132
144
; now we set the pagetables for higher half memory
133
145
; 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
140
151
; 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
142
153
; TODO this should not be executable
143
154
mov rax , 0x0
144
- or rax , 0x87
155
+ or rax , 0x83
145
156
mov rdi , 0
146
157
fill_kvma1:
147
158
mov qword [ pdp1 + 8 * rdi ], rax
@@ -153,7 +164,7 @@ fill_kvma1:
153
164
; entry 64~127 is a hole (also some sort of protection)
154
165
; entry 128~191 are mapping of the kernel image itself
155
166
mov rax , 0x0
156
- or rax , 0x87
167
+ or rax , 0x83
157
168
mov rdi , 128
158
169
fill_kvma2:
159
170
mov qword [ pdp1 + 8 * rdi ], rax
@@ -162,33 +173,43 @@ fill_kvma2:
162
173
cmp rdi , 192
163
174
jne fill_kvma2
164
175
; done :-)
165
-
166
176
; clear BSS section for the rust code.
167
177
mov rdi , ___BSS_PM_START__
178
+ mov rax , ___BSS_PM_END__
168
179
clear_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..
169
183
mov byte [ rdi ], 0
170
184
inc rdi
171
- cmp rdi , ___BSS_PM_END__
185
+ cmp rdi , rax
172
186
jne clear_bss
187
+
173
188
; enable FPU
174
189
fninit
175
190
176
191
; NOTE: must NOT use sse target features for rust compiler, if sse not
177
192
; enabled here.
178
193
194
+ ; shift the rsp to high memory mapping:
195
+ mov rax , KERNEL_OFFSET ,
196
+ or rsp , rax
179
197
; finally go to the rust code!
180
- call _entry
198
+ mov rax , _entry
199
+ jmp rax
200
+
181
201
; should not reach below
182
202
cli
183
203
hlt
184
204
185
205
; =====================================================================
186
206
; data sections they should all have VAs identical to their PAs
187
207
; 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)
188
210
; =====================================================================
189
211
190
- [SECTION .data]
191
-
212
+ [SECTION .data32]
192
213
gdt:
193
214
; see docs/x86_gdt.txt
194
215
@@ -232,8 +253,7 @@ mb_magic:
232
253
mb_info_addr:
233
254
dd 0x00000000
234
255
235
- [SECTION .bss]
236
-
256
+ [SECTION .init_k_stack]
237
257
global init_stack:data (init_stack.end - init_stack)
238
258
init_stack:
239
259
resb STACKSIZE
0 commit comments