-
Notifications
You must be signed in to change notification settings - Fork 99
Expand file tree
/
Copy pathsmp_ap.asm
More file actions
162 lines (130 loc) · 3.68 KB
/
smp_ap.asm
File metadata and controls
162 lines (130 loc) · 3.68 KB
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
; =============================================================================
; Pure64 -- a 64-bit OS/software loader written in Assembly for x86-64 systems
; Copyright (C) 2008-2025 Return Infinity -- see LICENSE.TXT
;
; INIT SMP AP
; =============================================================================
BITS 16
init_smp_ap:
; Check boot method of BSP
cmp byte [p_BootMode], 'U'
je skip_a20_ap ; If UEFI, then skip A20 code
; Enable the A20 gate
set_A20_ap:
in al, 0x64
test al, 0x02
jnz set_A20_ap
mov al, 0xD1
out 0x64, al
check_A20_ap:
in al, 0x64
test al, 0x02
jnz check_A20_ap
mov al, 0xDF
out 0x60, al
skip_a20_ap:
; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode.
lgdt [cs:GDTR32] ; Load GDT register
mov eax, cr0 ; Switch to 32-bit protected mode
or al, 1
mov cr0, eax
jmp 8:startap32
align 16
; =============================================================================
; 32-bit mode
BITS 32
startap32:
mov eax, 16 ; Load 4 GB data descriptor
mov ds, ax ; to all data segment registers
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
xor esi, esi
xor edi, edi
xor ebp, ebp
mov esp, 0x7000 ; Set a known free location for the temporary stack (shared by all APs)
; Load the GDT
lgdt [GDTR64]
; Enable extended properties
mov eax, cr4
or eax, 0x0000000B0 ; PGE (Bit 7), PAE (Bit 5), and PSE (Bit 4)
mov cr4, eax
; Point cr3 at PML4
mov eax, 0x00002008 ; Write-thru (Bit 3)
mov cr3, eax
; Enable long mode and SYSCALL/SYSRET
mov ecx, 0xC0000080 ; EFER MSR number
rdmsr ; Read EFER
or eax, 0x00000101 ; LME (Bit 8)
wrmsr ; Write EFER
; Enable paging to activate long mode
mov eax, cr0
or eax, 0x80000000 ; PG (Bit 31)
mov cr0, eax
; Make the jump directly from 16-bit real mode to 64-bit long mode
jmp SYS64_CODE_SEL:startap64
align 16
; =============================================================================
; 64-bit mode
BITS 64
startap64:
xor eax, eax ; aka r0
xor ebx, ebx ; aka r3
xor ecx, ecx ; aka r1
xor edx, edx ; aka r2
xor esi, esi ; aka r6
xor edi, edi ; aka r7
xor ebp, ebp ; aka r5
xor esp, esp ; aka r4
xor r8, r8
xor r9, r9
xor r10, r10
xor r11, r11
xor r12, r12
xor r13, r13
xor r14, r14
xor r15, r15
mov ax, 0x10 ; TODO Is this needed?
mov ds, ax ; Clear the legacy segment registers
mov es, ax
mov ss, ax
mov fs, ax
mov gs, ax
; Gather the CPU APIC ID without using the stack
cmp byte [p_x2APIC], 1
je get_id_x2APIC
get_id_APIC:
mov rsi, [p_LocalAPICAddress] ; We would call p_smp_get_id here but the stack is not ...
add rsi, 0x20 ; ... yet defined. It is safer to find the value directly.
lodsd ; Load a 32-bit value. We only want the high 8 bits
shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID
jmp get_id_done
get_id_x2APIC:
mov ecx, IA32_APIC_BASE
rdmsr
bts eax, 11 ; APIC Global Enable
bts eax, 10 ; Enable x2APIC mode
wrmsr
mov ecx, 0x802
rdmsr ; APIC ID returned in EAX
get_id_done:
; Set the stack. Each CPU gets a 1024-byte unique stack location
shl rax, 10 ; shift left 10 bits for a 1024byte stack
add rax, 0x0000000000090000 ; stacks decrement when you "push", start at 1024 bytes in
mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that
lgdt [GDTR64] ; Load the GDT
lidt [IDTR64] ; Load the IDT
call init_cpu ; Setup CPU
sti ; Activate interrupts for SMP
jmp ap_sleep
align 16
ap_sleep:
hlt ; Suspend CPU until an interrupt is received. opcode for hlt is 0xF4
jmp ap_sleep ; just-in-case of an NMI
; =============================================================================
; EOF