summaryrefslogtreecommitdiff
path: root/kernel/boot.S
blob: 4276c98b6171bc658831c2429fda5a10a4dedb9a (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
.global _start
.extern begin_long_mode

.section .text
.code32

_start:
	mov $stack_top, %esp

	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

	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, %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:
	movl $0x4f4d, 0xb8000
	hlt

no_cpuid:
	movl $0x4f43, 0xb8000
	hlt

no_long_mode:
	movl $0x4f4c, 0xb8000
	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
page_table_lvl2:
	.skip 4096

.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