* better
[mascara-docs.git] / amd64 / bareMetalOS-0.5.2 / pure64.boot0 / src / init_smp_ap.asm
blob634511b5a67da358949df1fd03081b8bd00a26b8
1 ; =============================================================================
2 ; Pure64 -- a 64-bit OS loader written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT
5 ; INIT SMP AP
6 ; =============================================================================
8 USE16
10 mp_ap_setup:
11 nop
12 jmp 0x0000:clearcs_ap
14 clearcs_ap:
16 ; Enable the A20 gate
17 set_A20_ap:
18 in al, 0x64
19 test al, 0x02
20 jnz set_A20_ap
21 mov al, 0xD1
22 out 0x64, al
23 check_A20_ap:
24 in al, 0x64
25 test al, 0x02
26 jnz check_A20_ap
27 mov al, 0xDF
28 out 0x60, al
30 ; At this point we are done with real mode and BIOS interrupts. Jump to 32-bit mode.
31 lgdt [cs:GDTR32] ; load GDT register
33 mov eax, cr0 ; switch to 32-bit protected mode
34 or al, 1
35 mov cr0, eax
37 jmp 8:startap32
39 align 16
42 ; =============================================================================
43 ; 32-bit mode
44 USE32
46 startap32:
47 mov eax, 16 ; load 4 GB data descriptor
48 mov ds, ax ; to all data segment registers
49 mov es, ax
50 mov fs, ax
51 mov gs, ax
52 mov ss, ax
53 xor eax, eax
54 xor ebx, ebx
55 xor ecx, ecx
56 xor edx, edx
57 xor esi, esi
58 xor edi, edi
59 xor ebp, ebp
60 mov esp, 0x8000 ; Set a known free location for the stack
62 ; Load the GDT
63 lgdt [GDTR64]
65 ; Enable physical-address extensions (set CR4.PAE=1)
66 mov eax, cr4
67 or eax, 0x000000020 ; PAE (Bit 5)
68 mov cr4, eax
70 ; Point cr3 at PML4
71 mov eax, 0x00002008 ; Write-thru (Bit 3)
72 mov cr3, eax
74 ; Enable long mode (set EFER.LME=1)
75 mov ecx, 0xC0000080 ; EFER MSR number
76 rdmsr ; Read EFER
77 or eax, 0x00000100 ; LME (Bit 8)
78 wrmsr ; Write EFER
80 ; Enable paging to activate long mode (set CR0.PG=1)
81 mov eax, cr0
82 or eax, 0x80000000 ; PG (Bit 31)
83 mov cr0, eax
85 ; Make the jump directly from 16-bit real mode to 64-bit long mode
86 jmp SYS64_CODE_SEL:startap64
88 align 16
91 ; =============================================================================
92 ; 64-bit mode
93 USE64
95 startap64:
96 xor rax, rax ; aka r0
97 xor rbx, rbx ; aka r3
98 xor rcx, rcx ; aka r1
99 xor rdx, rdx ; aka r2
100 xor rsi, rsi ; aka r6
101 xor rdi, rdi ; aka r7
102 xor rbp, rbp ; aka r5
103 xor rsp, rsp ; aka r4
104 xor r8, r8
105 xor r9, r9
106 xor r10, r10
107 xor r11, r11
108 xor r12, r12
109 xor r13, r13
110 xor r14, r14
111 xor r15, r15
113 mov ds, ax ; Clear the legacy segment registers
114 mov es, ax
115 mov ss, ax
116 mov fs, ax
117 mov gs, ax
119 mov rax, clearcs64_ap
120 jmp rax
122 clearcs64_ap:
123 xor rax, rax
125 ; Reset the stack. Each CPU gets a 1024-byte unique stack location
126 mov rsi, [os_LocalAPICAddress] ; We would call os_smp_get_id here but the stack is not ...
127 add rsi, 0x20 ; ... yet defined. It is safer to find the value directly.
128 lodsd ; Load a 32-bit value. We only want the high 8 bits
129 shr rax, 24 ; Shift to the right and AL now holds the CPU's APIC ID
130 shl rax, 10 ; shift left 10 bits for a 1024byte stack
131 add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in
132 mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that
134 lgdt [GDTR64] ; Load the GDT
135 lidt [IDTR64] ; load IDT register
137 ; Enable Local APIC on AP
138 mov rsi, [os_LocalAPICAddress]
139 add rsi, 0x00f0 ; Offset to Spurious Interrupt Register
140 mov rdi, rsi
141 lodsd
142 or eax, 0000000100000000b
143 stosd
145 call init_cpu ; Setup CPU
147 ; Make sure exceptions are working.
148 ; xor rax, rax
149 ; xor rbx, rbx
150 ; xor rcx, rcx
151 ; xor rdx, rdx
152 ; div rax
154 lock
155 inc word [cpu_activated]
156 xor eax, eax
157 mov rsi, [os_LocalAPICAddress]
158 add rsi, 0x20 ; Add the offset for the APIC ID location
159 lodsd ; APIC ID is stored in bits 31:24
160 shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255)
161 mov rdi, 0x00005700 ; The location where the cpu values are stored
162 add rdi, rax ; RDI points to infomap CPU area + APIC ID. ex F701 would be APIC ID 1
163 mov al, 1
164 stosb
165 sti ; Activate interrupts for SMP
166 jmp ap_sleep
168 align 16
169 .apmsg db 'THE_AP_SPIN_ZONE'
170 align 16
172 ap_sleep:
173 hlt ; Suspend CPU until an interrupt is received. opcode for hlt is 0xF4
174 jmp ap_sleep ; just-in-case of an NMI
177 ; =============================================================================
178 ; EOF