mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 07:27:45 +00:00
Kernel: Add SMP IPI support
We can now properly initialize all processors without crashing by sending SMP IPI messages to synchronize memory between processors. We now initialize the APs once we have the scheduler running. This is so that we can process IPI messages from the other cores. Also rework interrupt handling a bit so that it's more of a 1:1 mapping. We need to allocate non-sharable interrupts for IPIs. This also fixes the occasional hang/crash because all CPUs now synchronize memory with each other.
This commit is contained in:
parent
dec27e5e6f
commit
bc107d0b33
27 changed files with 1236 additions and 627 deletions
|
@ -27,11 +27,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <AK/NonnullOwnPtrVector.h>
|
||||
#include <Kernel/VM/MemoryManager.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
struct LocalAPIC {
|
||||
u32 apic_id;
|
||||
};
|
||||
|
||||
class APIC {
|
||||
public:
|
||||
static APIC& the();
|
||||
|
@ -39,14 +42,20 @@ public:
|
|||
static bool initialized();
|
||||
|
||||
bool init_bsp();
|
||||
void enable_bsp();
|
||||
void eoi();
|
||||
void boot_aps();
|
||||
void enable(u32 cpu);
|
||||
void init_finished(u32 cpu);
|
||||
void broadcast_ipi();
|
||||
void send_ipi(u32 cpu);
|
||||
static u8 spurious_interrupt_vector();
|
||||
Thread* get_idle_thread(u32 cpu) const;
|
||||
u32 enabled_processor_count() const { return m_processor_enabled_cnt; }
|
||||
|
||||
private:
|
||||
class ICRReg {
|
||||
u32 m_reg { 0 };
|
||||
u32 m_low { 0 };
|
||||
u32 m_high { 0 };
|
||||
|
||||
public:
|
||||
enum DeliveryMode {
|
||||
|
@ -76,25 +85,34 @@ private:
|
|||
AllExcludingSelf = 0x3,
|
||||
};
|
||||
|
||||
ICRReg(u8 vector, DeliveryMode delivery_mode, DestinationMode destination_mode, Level level, TriggerMode trigger_mode, DestinationShorthand destination)
|
||||
: m_reg(vector | (delivery_mode << 8) | (destination_mode << 11) | (level << 14) | (static_cast<u32>(trigger_mode) << 15) | (destination << 18))
|
||||
ICRReg(u8 vector, DeliveryMode delivery_mode, DestinationMode destination_mode, Level level, TriggerMode trigger_mode, DestinationShorthand destinationShort, u8 destination = 0)
|
||||
: m_low(vector | (delivery_mode << 8) | (destination_mode << 11) | (level << 14) | (static_cast<u32>(trigger_mode) << 15) | (destinationShort << 18)),
|
||||
m_high((u32)destination << 24)
|
||||
{
|
||||
}
|
||||
|
||||
u32 low() const { return m_reg; }
|
||||
u32 high() const { return 0; }
|
||||
u32 low() const { return m_low; }
|
||||
u32 high() const { return m_high; }
|
||||
};
|
||||
|
||||
OwnPtr<Region> m_apic_base;
|
||||
NonnullOwnPtrVector<Region> m_apic_ap_stacks;
|
||||
Vector<Processor> m_ap_processor_info;
|
||||
AK::Atomic<u32> m_apic_ap_count{0};
|
||||
Vector<OwnPtr<Region>> m_apic_ap_stacks;
|
||||
Vector<OwnPtr<Processor>> m_ap_processor_info;
|
||||
Vector<Thread*> m_ap_idle_threads;
|
||||
AK::Atomic<u8> m_apic_ap_count{0};
|
||||
AK::Atomic<u8> m_apic_ap_continue{0};
|
||||
u32 m_processor_cnt{0};
|
||||
u32 m_processor_enabled_cnt{0};
|
||||
|
||||
static PhysicalAddress get_base();
|
||||
static void set_base(const PhysicalAddress& base);
|
||||
void write_register(u32 offset, u32 value);
|
||||
u32 read_register(u32 offset);
|
||||
void set_lvt(u32 offset, u8 interrupt);
|
||||
void set_siv(u32 offset, u8 interrupt);
|
||||
void wait_for_pending_icr();
|
||||
void write_icr(const ICRReg& icr);
|
||||
void do_boot_aps();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue