Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/init/acpi.asm
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ APICapic: ; Entry Type 0
jnc readAPICstructures ; Read the next structure if CPU not usable
inc word [p_cpu_detected]
xchg eax, edx ; Restore the APIC ID back to EAX
stosb ; Store the 8-bit APIC ID
stosd ; Store the 8-bit APIC ID as a 32-bit value
jmp readAPICstructures ; Read the next structure

; I/O APIC Structure - 5.2.12.3
Expand Down Expand Up @@ -285,6 +285,7 @@ APICinterruptsourceoverride: ; Entry Type 2
jmp readAPICstructures ; Read the next structure

; Processor Local x2APIC Structure - 5.2.12.12
; TODO - Check if the same ID was found via APICapic - if so, ignore
;APICx2apic: ; Entry Type 9
; xor eax, eax
; xor edx, edx
Expand Down
107 changes: 93 additions & 14 deletions src/init/cpu.asm
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,19 @@ avx512_supported:
xsetbv ; Save XCR0 register
avx512_not_supported:

; Enable and Configure Local APIC
; mov ecx, IA32_APIC_BASE
; rdmsr
; bts eax, 11 ; APIC Global Enable
; cmp byte [p_x2APIC], 1
; jne skip_x2APIC_enable
; bts eax, 10 ; Enable x2APIC mode
;skip_x2APIC_enable:
; wrmsr
; Enable APIC
mov ecx, IA32_APIC_BASE
rdmsr
bts eax, 11 ; EN - xAPIC global enable/disable
cmp byte [p_x2APIC], 1
jne skip_x2APIC_enable
bts eax, 10 ; EXTD - Enable x2APIC mode
skip_x2APIC_enable:
wrmsr

mov r8d, eax ; Save MSR value as bit 8 is checked later

; Configure APIC
mov ecx, APIC_TPR
mov eax, 0x00000020
call apic_write ; Disable softint delivery
Expand All @@ -153,12 +157,15 @@ avx512_not_supported:
mov ecx, APIC_LVT_PERF
mov eax, 0x00010000
call apic_write ; Disable performance counter interrupts
cmp byte [p_x2APIC], 1
je skip_APIC ; Next 2 registers are APIC only
mov ecx, APIC_LDR
xor eax, eax
call apic_write ; Set Logical Destination Register
mov ecx, APIC_DFR
not eax ; Set EAX to 0xFFFFFFFF; Bits 31-28 set for Flat Mode
call apic_write ; Set Destination Format Register
skip_APIC:
mov ecx, APIC_LVT_LINT0
mov eax, 0x00008700 ; Bit 15 (1 = Level), Bits 10:8 for Ext
call apic_write ; Enable normal external interrupts
Expand All @@ -174,10 +181,17 @@ avx512_not_supported:

lock inc word [p_cpu_activated]
mov ecx, APIC_ID
call apic_read ; APIC ID is stored in bits 31:24
call apic_read
cmp byte [p_x2APIC], 1
je skip_shift
shr eax, 24 ; AL now holds the CPU's APIC ID (0 - 255)
mov rdi, IM_ActivedCoreIDs ; The location where the activated cores set their record to 1
add rdi, rax ; RDI points to InfoMap CPU area + APIC ID. ex 0x5E01 would be APIC ID 1
skip_shift:
bt r8d, 8 ; Check for BSP bit
jnc skip_bsp
mov [p_BSP], eax
skip_bsp:
mov edi, IM_ActivedCoreIDs ; The location where the activated cores set their record to 1
add edi, eax ; RDI points to InfoMap CPU area + APIC ID. ex 0x5E01 would be APIC ID 1
mov al, 1
stosb ; Store a 1 as the core is activated

Expand All @@ -186,26 +200,58 @@ avx512_not_supported:
; -----------------------------------------------------------------------------
; apic_read -- Read from a register in the APIC
; IN: ECX = Register to read
; OUT: EAX = Register value
; OUT: RAX = Register value
; All other registers preserved
apic_read:
cmp byte [p_x2APIC], 1
je apic_read_x2

apic_read_x:
mov rax, [p_LocalAPICAddress]
mov eax, [rax + rcx]
ret

apic_read_x2:
push rdx
push rcx
shr ecx, 4 ; Convert xAPIC register to x2APIC
add ecx, 0x800 ; Add MSR base offset
rdmsr ; Read to EDX:EAX
shl rdx, 32 ; Shift to upper 32 bits
or rax, rdx ; Combine into RAX
pop rcx
pop rdx
ret
; -----------------------------------------------------------------------------


; -----------------------------------------------------------------------------
; apic_write -- Write to a register in the APIC
; IN: ECX = Register to write
; EAX = Value to write
; RAX = Value to write
; OUT: All registers preserved
apic_write:
cmp byte [p_x2APIC], 1
je apic_write_x2

apic_write_x:
push rcx
add rcx, [p_LocalAPICAddress]
mov [rcx], eax
pop rcx
ret

apic_write_x2:
push rdx
push rcx
shr ecx, 4 ; Convert xAPIC register to x2APIC
add ecx, 0x800 ; Add MSR base offset
mov rdx, rax ; Copy RAX to RDX
shr rdx, 32 ; Shift upper 32 bits to lower 32
wrmsr ; Write as EDX:EAX
pop rcx
pop rdx
ret
; -----------------------------------------------------------------------------


Expand All @@ -227,6 +273,7 @@ APIC_TMR equ 0x180 ; Trigger Mode Register (Starting Address)
APIC_IRR equ 0x200 ; Interrupt Request Register (Starting Address)
APIC_ESR equ 0x280 ; Error Status Register
; 0x290 - 0x2E0 are Reserved
APIC_ICR equ 0x300 ; Interrupt Command Register (64-bit - x2APIC only)
APIC_ICRL equ 0x300 ; Interrupt Command Register (low 32 bits)
APIC_ICRH equ 0x310 ; Interrupt Command Register (high 32 bits)
APIC_LVT_TMR equ 0x320 ; LVT Timer Register
Expand All @@ -253,6 +300,38 @@ IA32_MTRR_PHYSMASK1 equ 0x203
IA32_PAT equ 0x277
IA32_MTRR_DEF_TYPE equ 0x2FF

; x2APIC MSR List
x2APIC_BASE equ 0x800
; 0x000 - 0x001 are Reserved
x2APIC_ID equ 0x002 ; ID Register
x2APIC_VER equ 0x003 ; Version Register
; 0x004 - 0x007 are Reserved
x2APIC_TPR equ 0x008 ; Task Priority Register - Bits 31:8 are Reserved.
; 0x009 is Reserved
x2APIC_PPR equ 0x00A ; Processor Priority Register
x2APIC_EOI equ 0x00B ; End Of Interrupt - Write 0 Only
; 0x00C is Reserved
x2APIC_LDR equ 0x00D ; Logical Destination Register - Read Only
; 0x00E is Reserved
x2APIC_SPURIOUS equ 0x00F ; Spurious Interrupt Vector Register
x2APIC_ISR equ 0x010 ; In-Service Register (Starting Address) - Read Only
x2APIC_TMR equ 0x018 ; Trigger Mode Register (Starting Address) - Read Only
x2APIC_IRR equ 0x020 ; Interrupt Request Register (Starting Address) - Read Only
x2APIC_ESR equ 0x028 ; Error Status Register
; 0x029 - 0x02E are Reserved
x2APIC_ICR equ 0x030 ; Interrupt Command Register
x2APIC_LVT_TMR equ 0x032 ; LVT Timer Register
x2APIC_LVT_TSR equ 0x033 ; LVT Thermal Sensor Register
x2APIC_LVT_PERF equ 0x034 ; LVT Performance Monitoring Counters Register
x2APIC_LVT_LINT0 equ 0x035 ; LVT LINT0 Register
x2APIC_LVT_LINT1 equ 0x036 ; LVT LINT1 Register
x2APIC_LVT_ERR equ 0x037 ; LVT Error Register
x2APIC_TMRINITCNT equ 0x038 ; Initial Count Register (for Timer)
x2APIC_TMRCURRCNT equ 0x039 ; Current Count Register (for Timer) - Read Only
; 0x03A - 0x03D are Reserved
x2APIC_TMRDIV equ 0x03E ; Divide Configuration Register (for Timer)
x2APIC_SELF_IPI equ 0x03F ; Self IPI - Write Only
; 0x040 - 0x3FF are Reserved

; =============================================================================
; EOF
82 changes: 53 additions & 29 deletions src/init/smp.asm
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,48 @@ init_smp:
cmp byte [cfg_smpinit], 1 ; Check if SMP should be enabled
jne noMP ; If not then skip SMP init

; Start the AP's one by one
xor eax, eax
xor edx, edx
mov rsi, [p_LocalAPICAddress]
mov eax, [rsi+0x20] ; Add the offset for the APIC ID location
shr rax, 24 ; APIC ID is stored in bits 31:24
mov dl, al ; Store BSP APIC ID in DL

mov esi, IM_DetectedCoreIDs
mov edx, [p_BSP] ; Get the BSP APIC ID
mov esi, IM_DetectedCoreIDs ; List of 32-bit APIC IDs
xor eax, eax
xor ecx, ecx
mov cx, [p_cpu_detected]
smp_send_INIT:
cmp cx, 0
je smp_send_INIT_done
lodsb
lodsd

cmp al, dl ; Is it the BSP?
je smp_send_INIT_skipcore
cmp eax, edx ; Is it the BSP?
je smp_send_INIT_skipcore ; If so, skip

cmp byte [p_x2APIC], 1
je smp_send_INIT_x2APIC

smp_send_INIT_APIC:
; Send 'INIT' IPI to APIC ID in AL
mov rdi, [p_LocalAPICAddress]
push rcx ; Save counter
shl eax, 24
mov dword [rdi+0x310], eax ; Interrupt Command Register (ICR); bits 63-32
mov ecx, APIC_ICRH ; Interrupt Command Register (ICR); bits 63-32
call apic_write
mov eax, 0x00004500
mov dword [rdi+0x300], eax ; Interrupt Command Register (ICR); bits 31-0
mov ecx, APIC_ICRL ; Interrupt Command Register (ICR); bits 31-0
call apic_write
smp_send_INIT_verify:
mov eax, [rdi+0x300] ; Interrupt Command Register (ICR); bits 31-0
call apic_read
bt eax, 12 ; Verify that the command completed
jc smp_send_INIT_verify
pop rcx ; Restore counter
jmp smp_send_INIT_APIC_done

smp_send_INIT_x2APIC:
; Send 'INIT' IPI to APIC ID in AL
push rcx ; Save counter
mov ecx, APIC_ICR ; Interrupt Command Register (ICR); bits 63-0
shl rax, 32
mov ax, 0x4500
call apic_write
pop rcx ; Restore counter

smp_send_INIT_APIC_done:

smp_send_INIT_skipcore:
dec cl
Expand All @@ -58,21 +70,40 @@ smp_send_INIT_done:
smp_send_SIPI:
cmp cx, 0
je smp_send_SIPI_done
lodsb
lodsd

cmp al, dl ; Is it the BSP?
cmp eax, edx ; Is it the BSP?
je smp_send_SIPI_skipcore

cmp byte [p_x2APIC], 1
je smp_send_SIPI_x2APIC

smp_send_SIPI_APIC:
; Send 'Startup' IPI to destination using vector 0x08 to specify entry-point is at the memory-address 0x00008000
mov rdi, [p_LocalAPICAddress]
push rcx
shl eax, 24
mov dword [rdi+0x310], eax ; Interrupt Command Register (ICR); bits 63-32
mov ecx, APIC_ICRH ; Interrupt Command Register (ICR); bits 63-32
call apic_write
mov eax, 0x00004608 ; Vector 0x08
mov dword [rdi+0x300], eax ; Interrupt Command Register (ICR); bits 31-0
mov ecx, APIC_ICRL ; Interrupt Command Register (ICR); bits 31-0
call apic_write
smp_send_SIPI_verify:
mov eax, [rdi+0x300] ; Interrupt Command Register (ICR); bits 31-0
call apic_read
bt eax, 12 ; Verify that the command completed
jc smp_send_SIPI_verify
pop rcx
jmp smp_send_SIPI_APIC_done

smp_send_SIPI_x2APIC:
; Send 'Startup' IPI to destination using vector 0x08 to specify entry-point is at the memory-address 0x00008000
push rcx
mov ecx, APIC_ICR ; Interrupt Command Register (ICR); bits 63-0
shl rax, 32
mov ax, 0x4608 ; Vector 0x08
call apic_write
pop rcx

smp_send_SIPI_APIC_done:

smp_send_SIPI_skipcore:
dec cl
Expand All @@ -85,13 +116,6 @@ smp_send_SIPI_done:
call timer_delay

noMP:
; Gather and store the APIC ID of the BSP
xor eax, eax
mov rsi, [p_LocalAPICAddress]
add rsi, 0x20 ; Add the offset for the APIC ID location
lodsd ; APIC ID is stored in bits 31:24
shr rax, 24 ; AL now holds the CPU's APIC ID (0 - 255)
mov [p_BSP], eax ; Store the BSP APIC ID

; Calculate base speed of CPU
cpuid
Expand Down
17 changes: 16 additions & 1 deletion src/init/smp_ap.asm
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,26 @@ startap64:
mov fs, ax
mov gs, ax

; Reset the stack. Each CPU gets a 1024-byte unique stack location
; 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
Expand Down
15 changes: 3 additions & 12 deletions src/pure64.asm
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ pde_end:
; Read APIC Address from MSR and enable it (if not done so already)
mov ecx, IA32_APIC_BASE
rdmsr ; Returns APIC in EDX:EAX
bts eax, 11 ; APIC Global Enable
bts eax, 11 ; EN - xAPIC global enable
wrmsr
and eax, 0xFFFFF000 ; Clear lower 12 bits
shl rdx, 32 ; Shift lower 32 bits to upper 32 bits
Expand All @@ -729,10 +729,10 @@ pde_end:

; Check for x2APIC support
mov eax, 1
cpuid ; x2APIC is supported if bit 21 is set
cpuid ; x2APIC is supported if ECX[21] is set
shr ecx, 21
and cl, 1
mov byte [p_x2APIC], cl
mov byte [p_x2APIC], cl ; Set flag for x2APIC

%ifndef NOVIDEO
; Visual Debug (3/8)
Expand Down Expand Up @@ -799,15 +799,6 @@ pde_end:
call debug_msg
%endif

; Reset the stack to the proper location (was set to 0x8000 previously)
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
shl rax, 10 ; shift left 10 bits for a 1024byte stack
add rax, 0x0000000000050400 ; stacks decrement when you "push", start at 1024 bytes in
mov rsp, rax ; Pure64 leaves 0x50000-0x9FFFF free so we use that

; Build the InfoMap
xor edi, edi
mov di, 0x5000
Expand Down
Loading