-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootstrap.S
257 lines (210 loc) · 4.46 KB
/
bootstrap.S
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#include "kernel_config.h"
#include "memory.h"
#define MB_HEADER_MAGIC 0x1BADB002
#define MB_HEADER_FLAGS ((1 << 16) | (1 << 1))
#define MB_HEADER_CKSUM -(MB_HEADER_MAGIC + MB_HEADER_FLAGS)
.section .bootstrap, "ax"
.code32
.global start32
.extern main
.align 16
start32:
jmp 1f
.align 16
mboot_header:
.long MB_HEADER_MAGIC
.long MB_HEADER_FLAGS
.long MB_HEADER_CKSUM
.long mboot_header
.long text_phys_begin
.long data_phys_end
.long bss_phys_end
.long start32
.align 4
gdt:
.quad 0x0000000000000000
.quad 0x00cf9a000000ffff
.quad 0x00cf92000000ffff
.quad 0x00a09a0000000000
.quad 0x00a0920000000000
.quad 0x00a0fa0000000000
.quad 0x00a0f20000000000
.quad 0x0000000000000000 // reserve for TSS
.quad 0x0000000000000000
gdt_ptr:
.word (gdt_ptr - gdt - 1)
.quad gdt
gdt_ptr64:
.word (gdt_ptr - gdt - 1)
.quad KERNEL_VIRT(gdt)
.global mboot_info
mboot_info:
.long 0x13131313
.space 0x100
bootstrap_stack_top:
1:
movl $bootstrap_stack_top, %esp
pushl %eax
call videomem_clrscr
popl %eax
cmpl $0x2badb002, %eax
je 1f
pushl $not_multiboot
jmp fail
1:
movl %ebx, mboot_info
call check_long_mode
call setup_identity_mapping
pushl $enter_long_mode
call videomem_puts
addl $4, %esp
movl $0xC0000080, %ecx
rdmsr
orl $(1 << 8), %eax
wrmsr
pushl $enable_paging
call videomem_puts
addl $4, %esp
movl %cr0, %eax
orl $(1 << 31), %eax
movl %eax, %cr0
pushl $enable_64bit_gdt
call videomem_puts
addl $4, %esp
lgdt gdt_ptr
ljmp $0x18, $start64
/**
* Utlities:
* - fail function - prints messages and halts
* - check_long_mode function - checks weather long mode available or not
* and fails if it's not available
* - setup_identity_mapping - setup identity mapping for lower 1G of physical
* memory, it loads cr3 with pml4 adddress and
* sets PAE bit in cr4, but doesn't enable paging.
*/
.code32
#define PTE_PRESENT (1 << 0)
#define PTE_WRITE (1 << 1)
#define PTE_LARGE (1 << 7)
#define CR4_PAE (1 << 5)
setup_identity_mapping:
pushl $setup_mapping
call videomem_puts
addl $4, %esp
movl $bss_phys_begin, %edx
movl $(bss_phys_begin + PAGE_SIZE), %eax
orl $(PTE_PRESENT | PTE_WRITE), %eax
movl %eax, (%edx)
movl %eax, 2048(%edx)
movl %eax, 4088(%edx)
addl $PAGE_SIZE, %edx
addl $PAGE_SIZE, %eax
movl %eax, (%edx)
movl %eax, 4080(%edx)
addl $PAGE_SIZE, %eax
movl %eax, 8(%edx)
movl %eax, 4088(%edx)
addl $PAGE_SIZE, %eax
movl %eax, 16(%edx);
addl $PAGE_SIZE, %eax
movl %eax, 24(%edx);
addl $PAGE_SIZE, %edx
movl $(PTE_LARGE | PTE_PRESENT | PTE_WRITE), %eax
movl $2048, %ecx
1:
movl %eax, (%edx)
addl $0x200000, %eax
addl $8, %edx
loop 1b
movl %cr4, %eax
orl $CR4_PAE, %eax
movl %eax, %cr4
movl $bss_phys_begin, %eax
movl %eax, %cr3
ret
check_long_mode:
subl $4, %esp
movl $checking_cpuid, (%esp)
call videomem_puts
pushf
pushf
xorl $(1 << 21), (%esp)
popf
pushf
popl %eax
xor (%esp), %eax
popf
test $(1 << 21), %eax
jne 1f
movl $cpuid_not_available, (%esp)
jmp fail
1:
movl $checking_x86_64, (%esp)
call videomem_puts
movl $0x80000000, %eax
cpuid
cmpl $0x80000001, %eax
jnb 1f
movl $no_extended_cpuid, (%esp)
jmp fail
1:
movl $0x80000001, %eax
cpuid
test $(1 << 29), %edx
jnz 1f
movl $x86_64_not_available, (%esp)
jmp fail
1:
addl $4, %esp
ret
fail:
call videomem_puts
halt: jmp halt
not_multiboot:
.asciz "Not a multiboot compatible bootloader!\n";
no_memory_map:
.asciz "No memory map provided!\n";
enable_64bit_gdt:
.asciz "Enable bootstrap 64 bit GDT...\n"
checking_cpuid:
.asciz "Checking CPUID instruction...\n"
cpuid_not_available:
.asciz "CPUID instruction is not available!\n"
checking_x86_64:
.asciz "Checking long mode...\n"
no_extended_cpuid:
.asciz "There is no extended CPUID function available!\n"
x86_64_not_available:
.asciz "Long mode is not available!\n"
setup_mapping:
.asciz "Setup identity mapping for lower 1G physical addresses...\n"
enter_long_mode:
.asciz "Enter long mode...\n"
enable_paging:
.asciz "Enable paging...\n"
.code64
start64:
lgdt gdt_ptr64
movw $0x20, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
movabsq $init_stack_top, %rax
movq %rax, %rsp
cld
movabsq $main, %rax
#ifdef CONFIG_QEMU_GDB_HANG
1: jmp 1b
#endif /* CONFIG_QEMU_GDB_HANG */
call *%rax
cli
1:
hlt
jmp 1b
.bss
.global init_stack_top
.align 0x1000
.space 0x2000
init_stack_top: