summaryrefslogtreecommitdiff
path: root/kernel/src/boot.asm
blob: 3d79096a08a6d1d6dc615bee63ecf19a11ad4585 (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
global start

section .text
bits 32
start:
	mov esp, stack_top

	call check_multiboot
	call check_cpuid
	call check_long_mode

	; print 'OK'
	mov dword [0xb8000], 0x2f4b2f4f
	hlt

check_multiboot:
	cmp eax, 0x36d76289
	jne .no_multiboot
	ret
.no_multiboot
	mov al, "0"
	jmp error

check_cpuid:
	; Check if CPUID is supported by attempting to flip the ID bit (bit 21)
    ; in the FLAGS register. If we can flip it, CPUID is available.

    ; Copy EFLAGS in to EAX via stack
	pushfd
	pop eax

	; Save the current flags
	mov ecx, eax

	; Flip the ID bit
	xor eax, 1 << 21

	; push eax to eflags
	push eax
	popfd

	; Copy EAX to FLAGS via the Stack
	pushfd
	pop eax

	; Restore FLAGS from the old version stored in ECX (i.e. flipping the
    ; ID bit back if it was ever flipped).
    push ecx
    popfd

	; Check if the ID was changed
	cmp eax, ecx
	je .no_cpuid
	ret
.no_cpuid:
	mov al, "1"
	jmp error

check_long_mode:
    ; test if extended processor info in available
    mov eax, 0x80000000    ; implicit argument for cpuid
    cpuid                  ; get highest supported argument
    cmp eax, 0x80000001    ; it needs to be at least 0x80000001
    jb .no_long_mode       ; if it's less, the CPU is too old for long mode
	
	; extended info about long mode
    mov eax, 0x80000001    ; argument for the cpuid function
    cpuid                  ; Cpu id
	test edx, 1 << 29  	   ; check long mode availablity
	jz .no_long_mode
	ret

.no_long_mode
	mov al, "2"
	jmp error

setup_page_tables:
	; map first P4 entry to P3 table
    mov eax, p3_table
    or eax, 0b11 ; present + writable
    mov [p4_table], eax

    ; map first P3 entry to P2 table
    mov eax, p2_table
    or eax, 0b11 ; present + writable
    mov [p3_table], eax
	
	; map each P2 entry to a huge 2MiB page
    mov ecx, 0         ; counter variable
    mov eax, 0b10000011 ; present + writable + huge

.map_p2_table:
    ; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx
    mov [p2_table + ecx     ], eax ; map ecx-th entry
    add eax, 0x200000  ; 2MiB
    mov [p2_table + ecx + 8 ], eax ; map ecx-th entry
    add eax, 0x200000  ; 2MiB
    mov [p2_table + ecx + 16], eax ; map ecx-th entry
    add eax, 0x200000  ; 2MiB
    mov [p2_table + ecx + 24], eax ; map ecx-th entry
    add eax, 0x200000  ; 2MiB

	add ecx, 32
    cmp ecx, 4096      ; if counter == 512, the whole P2 table is mapped
    jne .map_p2_table  ; else map the next entry

	ret
; Prints 'ERR: ' and the given error code to the screen and halts
; parameter: error code letter (ascii) in al
error:
	mov dword [0xb8000], 0x4f524f45
	mov dword [0xb8004], 0x4f3a4f52
	mov dword [0xb8008], 0x4f504f20
	mov byte  [0xb800a], al
	hlt

section .bss
align 4096
p4_table:
	resb 4096
p3_table:
	resb 4096
p2_table:
	resb 4096
stack_bottom:
	resb 64
stack_top: