1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
; Contains code from from the OSC lab project OOStuBS @ TU Dresden
; stack for the main function (renamed to _entry())
STACKSIZE: equ 65536
; 512 GB maximum RAM size for page table
; DON'T MODIFY THIS UNLESS YOU UPDATE THE setup_paging accordingly
MAX_MEM: equ 512
; exported symbols
[GLOBAL startup]
[GLOBAL pml4]
[GLOBAL pdp]
; functions from the other parts
[EXTERN vectors_start]
[EXTERN idt]
[EXTERN idt_descr]
[EXTERN _entry]
; addresses provided by the linker
[EXTERN ___BSS_START__]
[EXTERN ___BSS_END__]
[SECTION .text]
[BITS 32]
startup:
cld
cli
lgdt [gdt_80] ; set new segment descriptors
; global data segment
mov eax, 3 * 0x8
; 0x8 is the length of each entry these registers point to 4th entry the GDT
; (see also the code there) in x86 long mode these are dummy pointers which
; are not actually used in addressing. (don't use segmentation at all) all
; the addresses are physical addresses from 0.
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; define stack
mov ss, ax
mov esp, init_stack+STACKSIZE
init_longmode:
; activate address extension (PAE)
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
setup_paging:
; Provisional identical page mapping, using 1G huge page (therefore only 2 table
; levels needed)
;
; PML4 (Page Map Level 4 / 1st level)
mov eax, pdp
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
mov ebx, 0 ; start-address bytes bit [32:38]
mov ecx, 0
fill_tables2:
; fill one single PDP table, with 1G pages, 512 PDPE maps to 512 GB
cmp ecx, MAX_MEM
je fill_tables2_done
mov dword [pdp + 8*ecx + 0], eax ; low bytes
mov dword [pdp + 8*ecx + 4], ebx ; high bytes
add eax, 0x40000000 ; 1G per page
adc ebx, 0 ; overflow? -> increment higher-order half of the address
inc ecx
ja fill_tables2
fill_tables2_done:
; set base pointer to PML4
mov eax, pml4
mov cr3, eax
activate_long_mode:
; activate Long Mode (for now in compatibility mode)
mov ecx, 0x0C0000080 ; select EFER (Extended Feature Enable Register)
rdmsr
or eax, 1 << 8 ; LME (Long Mode Enable)
wrmsr
; activate paging
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
; jump to 64-bit code segment -> full activation of Long Mode
jmp 2 * 0x8 : longmode_start
;
; system start, part 2 (in 64-bit Long Mode)
; 1. clear BSS
; 2. enable floating poitn unit
; 3. set up idt
; 4. (optional) enable SSE
; 5. jump to rust main code
;
longmode_start:
[BITS 64]
; clear BSS
mov rdi, ___BSS_START__
clear_bss:
mov byte [rdi], 0
inc rdi
cmp rdi, ___BSS_END__
jne clear_bss
fninit ; activate FPU
init_sse:
; init SSE
; NOTE: must NOT use sse target features for rust compiler, if sse not enabled here.
;mov rax, cr0
;and rax, ~(1 << 2) ;clear coprocessor emulation CR0.EM
;or rax, 1 << 1 ;set coprocessor monitoring CR0.MP
;mov cr0, rax
;mov rax, cr4
;or rax, 3 << 9 ;set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
;mov cr4, rax
call _entry ; call the OS kernel's rust part.
cli ; Usually we should not get here.
hlt
[SECTION .data]
;
; Segment descriptors
;
gdt:
dw 0,0,0,0 ; NULL descriptor
; 32-bit code segment descriptor
dw 0xFFFF ; 4Gb - (0x100000*0x1000 = 4Gb)
dw 0x0000 ; base address=0
dw 0x9A00 ; code read/exec
dw 0x00CF ; granularity=4096, 386 (+5th nibble of limit)
; 64-bit code segment descriptor
dw 0xFFFF ; 4Gb - (0x100000*0x1000 = 4Gb)
dw 0x0000 ; base address=0
dw 0x9A00 ; code read/exec
dw 0x00AF ; granularity=4096, 386 (+5th nibble of limit), Long-Mode
; data segment descriptor
dw 0xFFFF ; 4Gb - (0x100000*0x1000 = 4Gb)
dw 0x0000 ; base address=0
dw 0x9200 ; data read/write
dw 0x00CF ; granularity=4096, 386 (+5th nibble of limit)
gdt_80:
dw 4*8 - 1 ; GDT limit=24, 4 GDT entries - 1
dq gdt ; GDT address
[SECTION .bss]
global init_stack:data (init_stack.end - init_stack)
init_stack:
resb STACKSIZE
.end:
[SECTION .global_pagetable]
pml4:
resb 4096
alignb 4096
pdp:
resb 4096
alignb 4096
|