diff --git a/src/kernel/ap_startup.s b/src/kernel/ap_startup.s index c438867..e5bb985 100644 --- a/src/kernel/ap_startup.s +++ b/src/kernel/ap_startup.s @@ -20,6 +20,7 @@ CR4_OSFXSR equ (1 << 9) CR4_OSCMMEXCPT equ (1 << 10) CR4_FSGSBASE equ (1 << 16) CR4_PCIDE equ (1 << 17) +CR4_INIT equ CR4_PAE|CR4_PGE CR4_VAL equ CR4_DE|CR4_PAE|CR4_MCE|CR4_PGE|CR4_OSFXSR|CR4_OSCMMEXCPT|CR4_FSGSBASE|CR4_PCIDE EFER_MSR equ 0xC0000080 @@ -69,7 +70,8 @@ align 4 lidt [BASE + (.idtd - ap_startup)] ; Enter long mode - mov eax, CR4_VAL + mov eax, cr4 + or eax, CR4_INIT mov cr4, eax mov eax, [BASE + (.pml4 - ap_startup)] @@ -100,6 +102,8 @@ align 8 mov gs, ax mov ss, ax + mov eax, CR4_VAL + mov rdi, [BASE + (.cpu - ap_startup)] mov rax, [rdi + CPU_DATA.rsp0] mov rsp, rax diff --git a/src/kernel/apic.cpp b/src/kernel/apic.cpp index 186c820..bd7d8da 100644 --- a/src/kernel/apic.cpp +++ b/src/kernel/apic.cpp @@ -70,16 +70,32 @@ lapic::get_id() } void -lapic::send_ipi(ipi_mode mode, uint8_t vector, uint8_t dest) +lapic::send_ipi(ipi mode, uint8_t vector, uint8_t dest) { // Wait until the APIC is ready to send ipi_wait(); - apic_write(m_base, lapic_icr_high, static_cast(dest) << 24); uint32_t command = static_cast(vector) | - static_cast(mode) << 8; + static_cast(mode); + apic_write(m_base, lapic_icr_high, static_cast(dest) << 24); + apic_write(m_base, lapic_icr_low, command); +} + +void +lapic::send_ipi_broadcast(ipi mode, bool self, uint8_t vector) +{ + // Wait until the APIC is ready to send + ipi_wait(); + + uint32_t command = + static_cast(vector) | + static_cast(mode) | + (self ? 0 : (1 << 18)) | + (1 << 19); + + apic_write(m_base, lapic_icr_high, 0); apic_write(m_base, lapic_icr_low, command); } diff --git a/src/kernel/apic.h b/src/kernel/apic.h index 9b434ac..c81fe7c 100644 --- a/src/kernel/apic.h +++ b/src/kernel/apic.h @@ -3,6 +3,7 @@ /// Classes to control both local and I/O APICs. #include +#include "kutil/enum_bitfields.h" enum class isr : uint8_t; @@ -18,6 +19,22 @@ protected: uint32_t *m_base; }; +enum class ipi : uint32_t +{ + // Delivery modes + fixed = 0x0000, + smi = 0x0200, + nmi = 0x0400, + init = 0x0500, + startup = 0x0600, + + // Flags + deassert = 0x0000, + assert = 0x4000, + edge = 0x0000, ///< edge-triggered + level = 0x8000, ///< level-triggered +}; +IS_BITFIELD(ipi); /// Controller for processor-local APICs class lapic : @@ -32,19 +49,17 @@ public: /// Get the local APIC's ID uint8_t get_id(); - enum class ipi_mode : uint8_t { - fixed = 0, - smi = 2, - nmi = 4, - init = 5, - startup = 6, - }; - /// Send an inter-processor interrupt. /// \arg mode The sending mode /// \arg vector The interrupt vector /// \arg dest The APIC ID of the destination - void send_ipi(ipi_mode mode, uint8_t vector, uint8_t dest); + void send_ipi(ipi mode, uint8_t vector, uint8_t dest); + + /// Send an inter-processor broadcast interrupt to all other CPUs + /// \arg mode The sending mode + /// \arg self If true, include this CPU in the broadcast + /// \arg vector The interrupt vector + void send_ipi_broadcast(ipi mode, bool self, uint8_t vector); /// Wait for an IPI to finish sending. This is done automatically /// before sending another IPI with send_ipi(). diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index be5fe98..b82329c 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -254,6 +254,9 @@ start_aps(void *kpml4) size_t free_stack_count = 0; uintptr_t stack_area_start = 0; + ipi mode = ipi::init | ipi::level | ipi::assert; + apic.send_ipi_broadcast(mode, false, 0); + for (uint8_t id : ids) { if (id == apic.get_id()) continue; @@ -287,10 +290,10 @@ start_aps(void *kpml4) // Kick it off! size_t current_count = ap_startup_count; log::debug(logs::boot, "Starting AP %d: stack %llx", cpu->index, stack_end); - apic.send_ipi(lapic::ipi_mode::init, 0, id); - clk.spinwait(1000); - apic.send_ipi(lapic::ipi_mode::startup, vector, id); + ipi startup = ipi::startup | ipi::assert; + + apic.send_ipi(startup, vector, id); for (unsigned i = 0; i < 20; ++i) { if (ap_startup_count > current_count) break; clk.spinwait(20); @@ -301,7 +304,7 @@ start_aps(void *kpml4) continue; // Send the second SIPI (intel recommends this) - apic.send_ipi(lapic::ipi_mode::startup, vector, id); + apic.send_ipi(startup, vector, id); for (unsigned i = 0; i < 100; ++i) { if (ap_startup_count > current_count) break; clk.spinwait(100);