-
Notifications
You must be signed in to change notification settings - Fork 40
/
ap_bootstrap.s.x86_64.arch_specific
152 lines (131 loc) · 4.15 KB
/
ap_bootstrap.s.x86_64.arch_specific
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
[bits 16]
; Defined in our memory map
; PT: This address *must* match the page defined in kernel/ap_bootstrap.h
[org 0x8000]
[global ap_entry]
ap_entry:
cli
; PT: OSDev wiki seems to suggest clearing DF, but I'm not sure why
; Another ref claiming this is the environment GCC expects: https://www.cheesecake.org/sac/smp.html
cld
; Load the GDT mapped at the base of the data page
mov eax, [$protected_mode_gdt_ptr]
lgdt [eax]
; Enable Protected Mode by setting the first bit in CR0
mov eax, cr0
or al, 1
mov cr0, eax
; Put the new GDT into effect by loading the segment registers
; First, reload CS, which can only be done indirectly via a far jump
jmp 0x08:.first_reload_cs
; After the far jump, immediately start assembling 32-bit code
[bits 32]
.first_reload_cs:
; Reload data segment registers
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; All done setting up Protected Mode
; Now that we're fully operating in Protected Mode, start the process of getting into Long Mode
; Enable the PAE bit
mov eax, cr4
or eax, 0b100000
mov cr4, eax
; Enable the long mode flag in the Extended Feature Enable Register MSR
; This address to select the EFER MSR is given by the AMD manual §3.1.7
mov ecx, 0xc0000080
rdmsr
; Low 32-bit word is stored in eax
; Long-mode enable is bit #8 (AMD manual §Figure 3-8)
or eax, 1 << 8
wrmsr
; Load the PML4 (and double-dereference the parameter that was passed in by the BSP)
mov eax, [$pml4_ptr]
mov eax, [eax]
mov cr3, eax
; Next, load the long-mode GDT
; Note that we must use the address in low memory because we haven't yet enabled paging
mov eax, [$long_mode_gdt_low_memory_ptr]
lgdt [eax]
; Enable the paging bit in cr0
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
; Put the long mode GDT into effect by loading the segment registers
; First, reload CS via a jump
jmp 0x08:.long_mode_low_mem_gdt
; And immediately start assembling 64bit code
[bits 64]
.long_mode_low_mem_gdt:
; We're now in Long Mode
; Reload the GDT using the high-memory RAM remap address
; This way we can later free the low-memory identity map
; (Double-dereference)
xor rax, rax
mov eax, [$long_mode_gdt_high_memory_ptr]
mov rax, [eax]
lgdt [eax]
; Again, load the CS from the new GDT via a jump
;jmp 0x08:.long_mode_high_mem_gdt
;.long_mode_high_mem_gdt:
; Reload data segment registers
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Load the IDT
mov eax, [$idt_ptr]
lidt [eax]
; Load the stack registers with the AP kernel stack allocated by the BSP
xor rax, rax
mov eax, [$stack_top_ptr]
mov rax, [eax]
mov rsp, rax
mov rbp, rax
; Load the TSS
; Index 5 in the GDT, and set the RPL to 3
mov ax, 0x2b
ltr ax
; Enable SSE
mov rax, cr0
; Disable FPU emulation by clearing the EM bit
and ax, 0xFFFB
; Enable coprocessor monitoring by setting the MP bit
; AMD SDM §3.1.1:
; > Software typically should set MP to 1 if the processor implementation supports x87 instructions.
or ax, 0x2
mov cr0, rax
; Inform the CPU that we can handle SIMD floating point exceptions by setting the OSXMMEXCPT enable bit
mov rax, cr4
or ax, 1 << 10
mov cr4, rax
; Finally, set the OSFXSR bit which will enable SSE
or ax, 1 << 9
mov cr4, rax
; Jump to the C entry point
; Load the entry point (and double-dereference the parameter that was passed in by the BSP)
xor rax, rax
mov eax, [$c_entry_point_ptr]
mov rax, [eax]
push .return_from_c_entry_point
push rax
ret
; Spinloop in Long Mode!
.return_from_c_entry_point:
.loop:
jmp $.loop
align 16
; Defined in our memory map
; PT: These parameter pointers *must* match the offsets defined in kernel/ap_bootstrap.h
protected_mode_gdt_ptr: dd 0x9000
long_mode_gdt_low_memory_ptr: dd 0x9100
long_mode_gdt_high_memory_ptr: dd 0x9200
pml4_ptr: dd 0x9300
idt_ptr: dd 0x9400
c_entry_point_ptr: dd 0x9500
stack_top_ptr: dd 0x9600