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
6 ; =============================================================================
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
42 ; =============================================================================
47 mov eax, 16 ; load 4 GB data descriptor
48 mov ds, ax ; to all data segment registers
60 mov esp, 0x8000 ; Set a known free location for the stack
65 ; Enable physical-address extensions (set CR4.PAE=1)
67 or eax, 0x000000020 ; PAE (Bit 5)
71 mov eax, 0x00002008 ; Write-thru (Bit 3)
74 ; Enable long mode (set EFER.LME=1)
75 mov ecx, 0xC0000080 ; EFER MSR number
77 or eax, 0x00000100 ; LME (Bit 8)
80 ; Enable paging to activate long mode (set CR0.PG=1)
82 or eax, 0x80000000 ; PG (Bit 31)
85 ; Make the jump directly from 16-bit real mode to 64-bit long mode
86 jmp SYS64_CODE_SEL:startap64
91 ; =============================================================================
100 xor rsi
, rsi
; aka r6
101 xor rdi
, rdi
; aka r7
102 xor rbp
, rbp
; aka r5
103 xor rsp
, rsp
; aka r4
113 mov ds, ax ; Clear the legacy segment registers
119 mov rax
, clearcs64_ap
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
142 or eax, 0000000100000000b
145 call init_cpu
; Setup CPU
147 ; Make sure exceptions are working.
155 inc word [cpu_activated
]
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
165 sti ; Activate interrupts for SMP
169 .apmsg
db 'THE_AP_SPIN_ZONE'
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 ; =============================================================================