aboutsummaryrefslogtreecommitdiff
path: root/src/boot/boot32.s
blob: 0c368198a971ca7f9544f452a73d1795cb80962e (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
.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 $stack_top, %esp  // Setup the stack.
	
	call boot_check_multiboot
	call boot_check_cpuid
	call boot_check_long_mode

	call boot_setup_page_tables
	call boot_enable_paging

	lgdt (boot_gdtdesc)
	jmpl $0x8, $boot_long_mode_start
	hlt

boot_check_multiboot:
	cmp $0x36d76289, %eax 
	jne .boot_no_multiboot
	ret
.boot_no_multiboot:
	mov $'M', %al
	jmp boot_error

boot_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 .boot_no_cpuid
	ret
.boot_no_cpuid:
	mov $'C', %al
	jmp boot_error

boot_check_long_mode:
	mov $0x80000000, %eax 
	cpuid
	cmp $0x80000001, %eax 
	jb .boot_no_long_mode

	mov $0x80000001, %eax 
	cpuid
	test $(1 << 29), %edx 
	jz .boot_no_long_mode
	
	ret
.boot_no_long_mode:
	mov $'L', %al
	jmp boot_error

boot_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 */
.boot_pages_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 .boot_pages_loop     /* if not, continue */

	ret

boot_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

boot_error:
	/* print in VGA "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 */
boot_gdt64:
	.quad 0                                             /* zero entry */
	.quad (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) /* code segment */
boot_gdtdesc:
	.word   (boot_gdtdesc - boot_gdt64 - 1)             /* sizeof(gdt) - 1 */
	.long   boot_gdt64                                  /* address gdt */