4
4
; stack for the main function (renamed to _entry())
5
5
STACKSIZE: equ 65536
6
6
7
- ; 512 GB maximum RAM size for page table
8
- ; DON'T MODIFY THIS UNLESS YOU UPDATE THE setup_paging accordingly.
7
+ ; 512 GB maximum RAM size for page table. Do not further increment this because
8
+ ; one PML4 table (and by extension, one pdp table) covers only 512 GB address.
9
+ ; And we only provision one such entry/table.
9
10
; IMPORTANT! regardless of the initial mapping size, we limit the phy memory to
10
11
; 64GB in the actual paging, so that all kernel VMAs could fit into one pml4
11
12
; entry and one pdp (level 3) table. See docs/mem_layout.txt
12
-
13
13
MAX_MEM: equ 512
14
14
15
15
; be careful with the extern and exported symbols when mapping a higher-half
16
16
; kernel: regardless where they are physically loaded
17
17
; 1) extern symbols may have 64 bit virtual addresses or values. Do not use them
18
- ; in the 32bit part of the startup code.
18
+ ; in the 32bit part of the startup code.
19
19
; 2) if the exported (global) symbols are mapped to low (virtual) addresses,
20
- ; they would be no longer accessable after the kernel switch to a higher half
21
- ; mapping. This is especially true for the multiboot info data.
20
+ ; they would be no longer accessable after the kernel switch to a higher half
21
+ ; mapping. This is especially true for the multiboot info data.
22
22
23
23
; Also be careful with imm width in asm instructions
24
24
; many instructions does not take 64 bit imm value. e.g. cmp. If the operand is
@@ -30,35 +30,31 @@ MAX_MEM: equ 512
30
30
[GLOBAL mb_magic]
31
31
[GLOBAL mb_info_addr]
32
32
; functions from other parts of rustubs
33
+ ; NOTE: this are all from 64bit code, so do not use them in 32bit assembly
33
34
[EXTERN ___BSS_PM_START__]
34
35
[EXTERN ___BSS_PM_END__]
35
36
[EXTERN KERNEL_OFFSET]
36
37
[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
- ; =====================================================================
38
+ ; =============================================================================
39
+ ; begin of the text secion: unlike the text* sections from the rust code the
40
+ ; text here is not supposed to be relocated to an higher memory, as we can not
41
+ ; use high memory until we completely set up longmode paging. Therefore we
42
+ ; explicitly link the startup text section to low address. the same goes for the
43
+ ; ".data32" section: they are not necessarily 32bit, the point is to confine all
44
+ ; address within 4GB (32bit) range
45
+ ; =============================================================================
45
46
[SECTION .text32]
46
- ; symbols used in 32bit mode:
47
- ; mb_magic
48
- ; mab_info_addr
49
- ; gdt_80
50
- ; init_stack
51
47
[BITS 32]
52
48
startup:
53
49
cld
54
50
cli
55
51
; with multiboot specs, grub initialzes the registers:
56
52
; EAX: magic value 0x2BADB002
57
- ; EBX: 32-bit physical address of the multiboot information struct
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
60
- mov dword [ mb_magic ], eax
61
- mov dword [ mb_info_addr ], ebx
53
+ ; EBX: 32-bit physical address of the multiboot information struct we store
54
+ ; them in global variables for future uses in rust code. TODO place them on
55
+ ; the stack and pass as parameters to _entry
56
+ mov dword [ mb_magic ], eax
57
+ mov dword [ mb_info_addr ], ebx
62
58
; setup GDT by loading GDT descriptor
63
59
; see docs/x86_gdt.txt
64
60
lgdt [ gdt_80 ]
@@ -76,12 +72,11 @@ startup:
76
72
init_longmode:
77
73
; activate address extension (PAE)
78
74
mov eax , cr4
79
- or eax , 1 << 5
75
+ or eax , 1 << 5
80
76
mov cr4 , eax
81
77
82
78
setup_paging:
83
-
84
- ; zero out the initial page tables (2 pages in total)
79
+ ; zero out the initial page tables (3 x 4K pages in total)
85
80
mov edi , pml4
86
81
clear_pt:
87
82
mov dword [ edi ], 0
@@ -90,29 +85,31 @@ clear_pt:
90
85
jl clear_pt
91
86
92
87
; Provisional identical page mapping, using 1G huge page, therefore only 2
93
- ; table levels needed. see docs/x86_paging.txt
88
+ ; table levels needed. see docs/x86_paging.txt We provide two additional
89
+ ; mappings later in the long mode for higher half memory
94
90
95
91
; PML4 (Page Map Level 4 / 1st level)
96
92
; PML4 entry flag: 0xf = PRESENG | R/W | USER | Write Through
97
93
mov eax , pdp0
98
- or eax , 0xf
94
+ or eax , 0xf
99
95
mov dword [ pml4 + 0 ], eax
100
96
mov dword [ pml4 + 4 ], 0
101
97
; PDPE flags 0x87 = PageSize=1G | USER | R/W | PRESENT
102
- mov eax , 0x0 | 0x83 ; start-address bytes bit [30:31] + flags
103
- mov ebx , 0 ; start-address bytes bit [32:38]
98
+ mov eax , 0x0 | 0x83 ; start-address bytes bit [30:31] + flags
99
+ mov ebx , 0 ; start-address bytes bit [32:38]
104
100
mov ecx , 0
105
- fill_tables2 :
101
+ fill_pdp0 :
106
102
; fill one single PDP table, with 1G pages, 512 PDPE maps to 512 GB
107
103
cmp ecx , MAX_MEM
108
- je fill_tables2_done
104
+ je fill_pdp0_done
109
105
mov dword [ pdp0 + 8 * ecx + 0 ], eax ; low bytes
110
106
mov dword [ pdp0 + 8 * ecx + 4 ], ebx ; high bytes
111
- add eax , 0x40000000 ; 1G per page
112
- adc ebx , 0 ; overflow? -> increment higher-order half of the address
107
+ add eax , 0x40000000
108
+ ; increment high half address on carry (overflow)
109
+ adc ebx , 0
113
110
inc ecx
114
- ja fill_tables2
115
- fill_tables2_done :
111
+ ja fill_pdp0
112
+ fill_pdp0_done :
116
113
; set base pointer to PML4
117
114
mov eax , pml4
118
115
mov cr3 , eax
@@ -121,11 +118,11 @@ activate_long_mode:
121
118
; select EFER (Extended Feature Enable Register)
122
119
mov ecx , 0x0C0000080
123
120
rdmsr
124
- or eax , 1 << 8 ; LME (Long Mode Enable)
121
+ or eax , 1 << 8 ; LME (Long Mode Enable)
125
122
wrmsr
126
123
; activate paging
127
124
mov eax , cr0
128
- or eax , 1 << 31
125
+ or eax , 1 << 31
129
126
mov cr0 , eax
130
127
131
128
; use the 2nd gdt entry (see definition below)
@@ -146,7 +143,7 @@ longmode_start:
146
143
; the 256th entry of pml4 points to memory from 0xffff_8000_0000_0000
147
144
mov rax , pdp1
148
145
; privileged, r/w, present
149
- or rax , 0x3
146
+ or rax , 0x3
150
147
mov qword [ pml4 + 256 * 8 ], rax
151
148
; entry 0~63 is an identical mapping with offset 0x8000_0000_0000
152
149
; 1G Page | Privileged | R/W | PRESENT
@@ -160,7 +157,6 @@ fill_kvma1:
160
157
add rax , 0x40000000
161
158
cmp rdi , 64
162
159
jne fill_kvma1
163
-
164
160
; entry 64~127 is a hole (also some sort of protection)
165
161
; entry 128~191 are mapping of the kernel image itself
166
162
mov rax , 0x0
@@ -184,10 +180,8 @@ clear_bss:
184
180
inc rdi
185
181
cmp rdi , rax
186
182
jne clear_bss
187
-
188
183
; enable FPU
189
184
fninit
190
-
191
185
; NOTE: must NOT use sse target features for rust compiler, if sse not
192
186
; enabled here.
193
187
@@ -202,70 +196,68 @@ clear_bss:
202
196
cli
203
197
hlt
204
198
205
- ; =====================================================================
206
- ; data sections they should all have VAs identical to their PAs
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)
210
- ; =====================================================================
199
+ ; =============================================================================
200
+ ; data sections they should all have VAs identical to their PAs so we map these
201
+ ; symbols differently than those generated by rust code the "data" itself
202
+ ; doesn't care about 64 or 32 bit width, but we need to make sure they are not
203
+ ; relocated to an address bigger then 4G (32)
204
+ ; =============================================================================
211
205
212
206
[SECTION .data32]
213
207
gdt:
214
208
; see docs/x86_gdt.txt
215
209
216
210
; GDT[0] should always be NULL descriptor
217
- dw 0 , 0 , 0 , 0
211
+ dw 0 , 0 , 0 , 0
218
212
219
213
; 32-bit code segment descriptor
220
214
; limit=0xFFFF, base=0
221
215
; Types: P|Ring0|Code/Data|Exec|NonConforming|Readable|NotAccessed
222
216
; Flags: 4K|32-bit|Not Long Mode
223
- dw 0xFFFF
224
- dw 0x0000
225
- dw 0x9A00
226
- dw 0x00CF
217
+ dw 0xFFFF
218
+ dw 0x0000
219
+ dw 0x9A00
220
+ dw 0x00CF
227
221
228
222
; 64-bit code segment descriptor
229
223
; limit=0xFFFF, base=0
230
224
; Types: P|Ring0|Code/Data|Exec|NonConforming|Readable|NotAccessed
231
225
; Flags: 4K|-|LongMode|-
232
- dw 0xFFFF
233
- dw 0x0000
234
- dw 0x9A00
235
- dw 0x00AF
226
+ dw 0xFFFF
227
+ dw 0x0000
228
+ dw 0x9A00
229
+ dw 0x00AF
236
230
237
231
; data segment descriptor
238
232
; limit=0xFFFF, base=0
239
233
; Types: Present|Ring0|Code/Data|NoExec|GrowUp|Writable|NotAccessed
240
234
; Flags: 4K|32-bit|Not Long Mode
241
- dw 0xFFFF
242
- dw 0x0000
243
- dw 0x9200
244
- dw 0x00CF
235
+ dw 0xFFFF
236
+ dw 0x0000
237
+ dw 0x9200
238
+ dw 0x00CF
245
239
246
240
gdt_80:
247
- dw 4 * 8 - 1 ; GDT limit=24, 4 GDT entries - 1
248
- dq gdt ; GDT address
241
+ dw 4 * 8 - 1 ; GDT limit=24, 4 GDT entries - 1
242
+ dq gdt ; GDT address
249
243
250
244
; multiboot info
251
245
mb_magic:
252
- dd 0x00000000
246
+ dd 0x00000000
253
247
mb_info_addr:
254
- dd 0x00000000
248
+ dd 0x00000000
255
249
256
- [SECTION .init_k_stack ]
250
+ [SECTION .reserved_0.init_stack ]
257
251
global init_stack:data (init_stack.end - init_stack)
258
252
init_stack:
259
253
resb STACKSIZE
260
254
.end:
261
255
262
256
[SECTION .global_pagetable]
263
257
264
- ; create initial page tables wrt. the memory layout
265
- ; we use entry 0 and 256 of the PML4 table
266
- ; the whole of the first first pdp table (512G)
267
- ; and entry 0, 2 of the second pdp table
268
- ; all pages here are 1 GiB huge pages
258
+ ; create initial page tables wrt. the memory layout we use entry 0 and 256 of
259
+ ; the PML4 table the whole of the first first pdp table (512G) and entry 0, 2 of
260
+ ; the second pdp table all pages here are 1 GiB huge pages
269
261
pml4:
270
262
resb 4096
271
263
alignb 4096
0 commit comments