summaryrefslogtreecommitdiff
path: root/kernel/src/boot/boot.S
blob: a96be002ce75a36543ea62ddeeff76b9fbcb6029 (plain)
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
.code32
.extern begin_long_mode

.set KERNEL_VMA, 0xc0000000

.section .boot.text, "a"
.global _start
_start:
	cli
	mov $stack_top - KERNEL_VMA, %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

	addl $KERNEL_VMA, %esp
	mov $4f, %ecx
	jmp *%ecx

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 $pt_lvl3 - KERNEL_VMA, %eax
	or $0x3, %eax
	mov %eax, pt_lvl4 - KERNEL_VMA

	// 0x00000000 - 0x00200000 : 0x00000000 - 0x00200000
	mov $pt_lvl2 - KERNEL_VMA, %eax
	or $0x3, %eax
	mov %eax, pt_lvl3 - KERNEL_VMA

	// 0xc0000000 - 0xc0200000 : 0xc0000000 - 0xc0200000
	mov $pt_lvl2_hh - KERNEL_VMA, %eax
	or $0x3, %eax
	mov %eax, pt_lvl3 + 24 - KERNEL_VMA

// first 2mb
	xor %ecx, %ecx
1:
	movl $0x00200000, %eax
	mul %ecx
	or $0b10000011, %eax
	movl $pt_lvl2 - KERNEL_VMA, %edx
	leal (%edx, %ecx, 8), %edx
	movl %eax, (%edx)
	inc %ecx
	cmp $1, %ecx
	jne 1b

// first 2mb in higher_half
	xor %ecx, %ecx
2:
	movl $0x00200000, %eax
	mul %ecx
	or $0b10000011, %eax
	movl $pt_lvl2_hh - KERNEL_VMA, %edx
	leal (%edx, %ecx, 8), %edx
	movl %eax, (%edx)
	inc %ecx
	cmp $1, %ecx
	jne 2b

	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

	// pt_lvl4
	mov $pt_lvl4 - KERNEL_VMA, %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 .text
4:
	lgdt gdtp
	ljmp $0x08, $begin_long_mode


.section .bss
.align 4096

// stack
stack_bottom:
	.skip 4096*16
stack_top:


// page tables
pt_lvl4:
	.skip 4096
pt_lvl3:
	.skip 4096
pt_lvl2:
	.skip 4096
pt_lvl2_hh:
	.skip 4096


// Access bits
.section .rodata
.set PRESENT,		1 << 7
.set NOT_SYS,		1 << 4
.set EXEC,		1 << 3
.set DC,		1 << 2
.set RW,		1 << 1
.set ACCESSED,		1 << 0

// Flags bits
.set GRAN_4K,		1 << 7
.set SZ_32,		1 << 6
.set LONG_MODE,		1 << 5

gdt:
gdt_null = . - gdt
	.quad 0
gdt_code = . - gdt
	.long 0xFFFF				// Limit & Base (low, bits 0-15)
	.byte 0					// Base (mid, bits 16-23)
	.byte PRESENT | NOT_SYS | EXEC | RW	// Access
	.byte GRAN_4K | LONG_MODE | 0xF		// Flags & Limit (high, bits 16-19)
	.byte 0					// Base (high, bits 24-31)
gdt_data = . - gdt
	.long 0xFFFF
	.byte 0
	.byte PRESENT | NOT_SYS | RW
	.byte GRAN_4K | SZ_32 | 0xF
	.byte 0
gdtp:
	.word . - gdt - 1
	.quad gdt