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
|
.global _start
.extern long_mode_start
.section .text
.code32
// Entry point. It puts the machine into a consistent state and starts long mode.
_start:
mov $0x80000, %esp // Setup the stack.
push %ebx // Pass multiboot info structure.
push %eax // Pass multiboot magic code.
call check_multiboot
call check_cpuid
call check_long_mode
call setup_page_tables
call enable_paging
lgdt (gdtdesc)
jmpl $0x8, $long_mode_start
//jmp gdt64.code_segment:long_mode_start
call halt
halt:
hlt
check_multiboot:
cmp $0x36d76289, %eax
jne .no_multiboot
ret
.no_multiboot:
mov $'M', %al
jmp error
check_cpuid:
pushfd
pop %eax
mov %eax, %ecx
xor $(1 << 21), %eax
push %eax
popfd
pushfd
pop %eax
push %ecx
popfd
cmp %eax, %ecx
je .no_cpuid
ret
.no_cpuid:
mov $'C', %al
jmp error
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
.no_long_mode:
mov $'L', %al
jmp error
setup_page_tables:
mov $page_table_l3, %eax
or $0b11 , %eax // present, writable
mov %eax, (page_table_l4)
mov $page_table_l2, %eax
or $0b11, %eax // present, writable
mov %eax, (page_table_l3)
mov $0, %ecx // counter
.loop:
mov $0x200000, %eax // 2MiB
mul %ecx
or $0b10000011, %eax // present, writable, huge page
mov %eax, +page_table_l2(,%ecx,8)
inc %ecx // increment counter
cmp $512, %ecx // checks if the whole table is mapped
jne .loop // if not, continue
ret
enable_paging:
// pass page table location to cpu
mov $page_table_l4, %eax
mov %eax, %cr3
// enable PAE
mov %cr4, %eax
or $(1 << 5), %eax
mov %eax, %cr4
// enable long mode
mov $0xC0000080, %ecx
rdmsr
or $(1 << 8), %eax
wrmsr
// enable paging
mov %cr0, %eax
or $(1 << 31), %eax
mov %eax, %cr0
ret
error:
// // print "ERR: X" where X is the error code
movl $0x4f524f45, 0xb8000
movl $0x4f3a4f52, 0xb8004
movl $0x4f204f20, 0xb8008
movb %al, 0xb800a
hlt
.section .bss
.align 4096
page_table_l4:
.skip 4096
page_table_l3:
.skip 4096
page_table_l2:
.skip 4096
stack_bottom:
.skip 4096 * 4
stack_top:
.section .rodata
.p2align 2 # force 4 byte alignment
gdt64:
.quad 0 // zero entry
.code_segment:
.quad (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) # code segment
gdtdesc:
.word (gdtdesc - gdt64 - 1) # sizeof(gdt) - 1
.long gdt64 # address gdt
//# Bootstrap GDT
//gdt:
// SEG_NULLASM # null seg
// SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg
// SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg
//
//gdtdesc:
// .word (gdtdesc - gdt - 1) # sizeof(gdt) - 1
// .long gdt # address gdt
//
//section .rodata
//gdt64:
// dq 0 ; zero entry
//.code_segment: equ $ - gdt64
// dq (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) ; code segment
//.pointer:
// dw $ - gdt64 - 1 ; length
// dq gdt64 ; address
//
|