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
|
.global _start
.extern begin_long_mode
.section .text
.code32
_start:
mov $stack_top, %esp
pushl $0
pushl %eax
pushl $0
pushl %ebx
call check_multiboot
call check_cpuid
call check_long_mode
call setup_page_tables
call enable_paging
lgdt gdt64_pointer
ljmp $gdt64_code_segment, $begin_long_mode
check_multiboot:
cmp $0x36d76289, %eax
jne no_multiboot
ret
check_cpuid:
pushfl
pop %eax
mov %eax, %ecx
xor $1<<21, %eax
push %eax
popfl
pushfl
pop %eax
push %ecx
popfl
cmp %eax, %ecx
je no_cpuid
ret
check_long_mode:
mov $0x80000000, %eax
cpuid
cmp $0x80000001, %eax
jb no_long_mode
mov $0x80000001, %eax
cpuid
test $1<<29, %edx
jz no_long_mode
ret
setup_page_tables:
mov $page_table_lvl3, %eax
or $0x3, %eax
mov %eax, page_table_lvl4
mov $page_table_lvl2, %eax
or $0x3, %eax
mov %eax, page_table_lvl3
mov $page_table_lvl2 + 4096, %eax
or $0x3, %eax
mov %eax, page_table_lvl3+8
mov $page_table_lvl2 + 8192, %eax
or $0x3, %eax
mov %eax, page_table_lvl3+16
mov $page_table_lvl2 + 12288, %eax
or $0x3, %eax
mov %eax, page_table_lvl3+24
movl $0, %ecx
1:
movl $0x200000, %eax
mul %ecx
or $0b10000011, %eax
movl $page_table_lvl2, %edx
leal (%edx, %ecx, 8), %edx
movl %eax, (%edx)
inc %ecx
cmp $512*4, %ecx
jne 1b
ret
enable_paging:
// enable PAE
mov %cr4, %edx
or $1<<5 ,%edx
mov %edx, %cr4
// set LME (long mode enable)
mov $0xC0000080, %ecx
rdmsr
or $1<<8, %eax
wrmsr
// page_table_lvl4
mov $page_table_lvl4, %eax
mov %eax, %cr3
// enable paging (+ protected mode if not already enabled)
mov %cr0, %eax
or $1<<31 + 1<<0, %eax
mov %eax, %cr0
ret
no_multiboot:
hlt
no_cpuid:
hlt
no_long_mode:
hlt
.section .bss
.align 4096
// stack
stack_bottom:
.skip 4096*4
stack_top:
// page tables
page_table_lvl4:
.skip 4096
page_table_lvl3:
.skip 4096
// map first 4GB
page_table_lvl2:
.skip 4096*4
.section .rodata
gdt64:
.quad 0
gdt64_code_segment = . - gdt64
.quad 1<<43 + 1<<44 + 1<<47 + 1<<53
gdt64_pointer:
.word . - gdt64 - 1
.quad gdt64
|