diff --git a/kernel/src/arch/idt.c b/kernel/src/arch/idt.c index 7f2f32c..7fe50fd 100644 --- a/kernel/src/arch/idt.c +++ b/kernel/src/arch/idt.c @@ -40,34 +40,45 @@ void idt_default_interrupt_handler(struct register_ctx *ctx) kpanic(ctx, NULL); } -#define SET_GATE(interrupt, base, flags) \ - do \ - { \ - idt_descriptor[(interrupt)].off_low = (base) & 0xFFFF; \ - idt_descriptor[(interrupt)].sel = 0x8; \ - idt_descriptor[(interrupt)].ist = 0; \ - idt_descriptor[(interrupt)].attr = (flags); \ - idt_descriptor[(interrupt)].off_mid = ((base) >> 16) & 0xFFFF; \ - idt_descriptor[(interrupt)].off_high = ((base) >> 32) & 0xFFFFFFFF; \ - idt_descriptor[(interrupt)].zero = 0; \ - } while (0) +/* pesky little trap which just halts the current cpu and lets it die alone */ +void die(struct register_ctx *) +{ + /* If the CPU has caught this its game over */ + cpu_local_t *cpu = get_cpu_local(); + cpu->ready = false; + hcf(); +} + +void idt_set_gate(uint8_t interrupt, uint64_t base, uint8_t flags) +{ + idt_descriptor[(interrupt)].off_low = (base) & 0xFFFF; + idt_descriptor[(interrupt)].sel = 0x8; + idt_descriptor[(interrupt)].ist = 0; + idt_descriptor[(interrupt)].attr = (flags); + idt_descriptor[(interrupt)].off_mid = ((base) >> 16) & 0xFFFF; + idt_descriptor[(interrupt)].off_high = ((base) >> 32) & 0xFFFFFFFF; + idt_descriptor[(interrupt)].zero = 0; +} void idt_init() { for (int i = 0; i < 32; i++) { - SET_GATE(i, stubs[i], IDT_TRAP_GATE); + idt_set_gate(i, stubs[i], IDT_TRAP_GATE); real_handlers[i] = idt_default_interrupt_handler; } for (int i = 32; i < 256; i++) { - SET_GATE(i, stubs[i], IDT_INTERRUPT_GATE); + idt_set_gate(i, stubs[i], IDT_INTERRUPT_GATE); } - SET_GATE(0x80, stubs[0x80], IDT_INTERRUPT_GATE | GDT_ACCESS_RING3); + idt_set_gate(0x80, stubs[0x80], IDT_INTERRUPT_GATE | GDT_ACCESS_RING3); real_handlers[0x80] = syscall_handler; + idt_set_gate(0xFE, stubs[0xFE], IDT_TRAP_GATE); + real_handlers[0xFE] = die; + __asm__ volatile( "lidt %0" : : "m"(idt_ptr) : "memory"); diff --git a/kernel/src/arch/idt.h b/kernel/src/arch/idt.h index a1758ab..a7add50 100644 --- a/kernel/src/arch/idt.h +++ b/kernel/src/arch/idt.h @@ -33,5 +33,6 @@ typedef void (*idt_intr_handler)(struct register_ctx *ctx); void idt_init(); int idt_register_handler(size_t vector, idt_intr_handler handler); void idt_default_interrupt_handler(struct register_ctx *ctx); +void idt_set_gate(uint8_t interrupt, uint64_t base, uint8_t flags); #endif // IDT_H \ No newline at end of file diff --git a/kernel/src/arch/smp.c b/kernel/src/arch/smp.c index f4487c0..f8c3c08 100644 --- a/kernel/src/arch/smp.c +++ b/kernel/src/arch/smp.c @@ -17,17 +17,31 @@ #include #include -#define MAX_CPUS 256 #define MSR_GS_BASE 0xC0000101 uint32_t cpu_count = 0; uint32_t bootstrap_lapic_id = 0; atomic_uint started_cpus = 0; -static cpu_local_t cpu_locals[MAX_CPUS]; +cpu_local_t cpu_locals[MAX_CPUS] = {0}; cpu_local_t *get_cpu_local(void) { - return (cpu_local_t *)rdmsr(MSR_GS_BASE); + + cpu_local_t *tmp = (cpu_local_t *)rdmsr(MSR_GS_BASE); + if (tmp != NULL) + return tmp; + + uint32_t current_lapic_id = lapic_get_id(); + for (uint32_t i = 0; i < cpu_count; i++) + { + if (cpu_locals[i].lapic_id == current_lapic_id) + { + return &cpu_locals[i]; + } + } + + log_early("warning: No CPU found with LAPIC ID %u", current_lapic_id); + return NULL; } static inline void set_cpu_local(cpu_local_t *cpu) @@ -65,6 +79,8 @@ void smp_entry(struct limine_mp_info *smp_info) log_early("CPU %d (LAPIC ID %u) is up", cpu->cpu_index, lapic_id); cpu->ready = true; + + __asm__ volatile("sti"); hlt(); } diff --git a/kernel/src/arch/smp.h b/kernel/src/arch/smp.h index 4bbdcd9..5d46af1 100644 --- a/kernel/src/arch/smp.h +++ b/kernel/src/arch/smp.h @@ -5,7 +5,7 @@ #include #include -extern uint32_t bootstrap_lapic_id; +#define MAX_CPUS 256 typedef struct { @@ -14,6 +14,10 @@ typedef struct bool ready; } cpu_local_t; +extern uint32_t bootstrap_lapic_id; +extern cpu_local_t cpu_locals[MAX_CPUS]; +extern uint32_t cpu_count; + void smp_init(); cpu_local_t *get_cpu_local(void); diff --git a/kernel/src/dev/pit.c b/kernel/src/dev/pit.c index 9d7c1dc..0002d2b 100644 --- a/kernel/src/dev/pit.c +++ b/kernel/src/dev/pit.c @@ -4,6 +4,7 @@ #include #include #include +#include #define PIT_VECTOR 32 @@ -28,6 +29,6 @@ void pit_init(idt_intr_handler handler) outb(0x40, (divisor >> 8) & 0xFF); idt_register_handler(PIT_VECTOR, pit_handler); - ioapic_map(0, PIT_VECTOR, 0); + ioapic_map(0, PIT_VECTOR, 0, get_cpu_local()->lapic_id); ioapic_unmask(0); } \ No newline at end of file diff --git a/kernel/src/emk.c b/kernel/src/emk.c index 3cfa24c..887b70d 100644 --- a/kernel/src/emk.c +++ b/kernel/src/emk.c @@ -211,7 +211,7 @@ void emk_entry(void) ioapic_init(); /* Setup timer */ - pit_init(NULL); + pit_init(tick); /* Finished */ log_early("%s", LOG_SEPARATOR); diff --git a/kernel/src/sys/apic/ioapic.c b/kernel/src/sys/apic/ioapic.c index 91d1d64..350a18e 100644 --- a/kernel/src/sys/apic/ioapic.c +++ b/kernel/src/sys/apic/ioapic.c @@ -51,7 +51,7 @@ uint32_t ioapic_read(uint8_t index) return ioapic[IOAPIC_OFF_IOWIN / 4]; } -void ioapic_map(int irq, int vec, uint8_t dest_mode) +void ioapic_map(int irq, int vec, uint8_t dest_mode, uint8_t lapic_id) { uint32_t gsi = irq_to_gsi(irq); uint32_t max_irqs = ((ioapic_read(IOAPIC_IDX_IOAPICVER) >> 16) & 0xFF) + 1; @@ -70,11 +70,9 @@ void ioapic_map(int irq, int vec, uint8_t dest_mode) (dest_mode << 11) | // 0: Physical, 1: Logical (0 << 8) | // Fixed delivery vec; - uint32_t redtble_hi = (get_cpu_local()->lapic_id << 24); + uint32_t redtble_hi = (lapic_id << 24); ioapic_write(0x10 + 2 * gsi, redtble_lo); ioapic_write(0x10 + 2 * gsi + 1, redtble_hi); - - log_early("Mapped IRQ %d (GSI %u) to vector 0x%x on CPU %u", irq, gsi, vec, get_cpu_local()->lapic_id); } void ioapic_unmask(int irq) @@ -89,7 +87,6 @@ void ioapic_unmask(int irq) uint32_t redtble_lo = ioapic_read(0x10 + 2 * gsi); redtble_lo &= ~(1 << 16); ioapic_write(0x10 + 2 * gsi, redtble_lo); - log_early("Unmasked IRQ %d (GSI %u)", irq, gsi); } void ioapic_init(void) @@ -154,6 +151,4 @@ void ioapic_init(void) log_early("Initialized GSI %u to vector 0x%x", gsi, vec); } } - - log_early("IOAPIC init at 0x%lx (virt 0x%lx) with %u IRQs", phys_addr, virt_addr, max_irqs); } \ No newline at end of file diff --git a/kernel/src/sys/apic/ioapic.h b/kernel/src/sys/apic/ioapic.h index d3fbfef..385c71a 100644 --- a/kernel/src/sys/apic/ioapic.h +++ b/kernel/src/sys/apic/ioapic.h @@ -12,7 +12,7 @@ #define IOAPIC_IDX_RED_TBL 0x10 void ioapic_init(); -void ioapic_map(int irq, int vec, uint8_t dest_mode); +void ioapic_map(int irq, int vec, uint8_t dest_mode, uint8_t lapic_id); void ioapic_unmask(int irq); #endif // IOAPIC_H \ No newline at end of file diff --git a/kernel/src/sys/apic/lapic.c b/kernel/src/sys/apic/lapic.c index d6da5cf..6ccc2d2 100644 --- a/kernel/src/sys/apic/lapic.c +++ b/kernel/src/sys/apic/lapic.c @@ -46,6 +46,23 @@ uint32_t lapic_read(uint32_t offset) return base[offset / LAPIC_REG_SIZE]; } +uint32_t lapic_get_id(void) +{ + volatile uint32_t *base = LAPIC_BASE; + if (!base) + { + log_early("error: LAPIC not initialized for ID read"); + kpanic(NULL, "LAPIC get_id before init"); + } + uint32_t id = lapic_read(LAPIC_ID) >> 24; + if (id > 255) + { + log_early("error: Invalid LAPIC ID %u", id); + kpanic(NULL, "Invalid LAPIC ID"); + } + return id; +} + void lapic_init(void) { uint64_t msr = rdmsr(LAPIC_BASE_MSR); @@ -72,18 +89,7 @@ void lapic_init(void) } atomic_store(&lapic_base, virt_addr); - uint32_t id = lapic_read(LAPIC_ID) >> 24; - if (id > 255) - { - log_early("error: Invalid LAPIC ID %u", id); - kpanic(NULL, "Invalid LAPIC ID"); - } - log_early("LAPIC init: CPU %u at 0x%lx (virt 0x%lx)", id, phys_addr, virt_addr); - lapic_write(LAPIC_EOI, 0); -} - -void lapic_eoi(void) -{ + uint32_t id = lapic_get_id(); // Use the new function lapic_write(LAPIC_EOI, 0); } @@ -118,7 +124,55 @@ void lapic_enable(void) lapic_write(LAPIC_LVT_LINT1, lvt1); lapic_write(LAPIC_TPR, 0); +} - uint32_t id = lapic_read(LAPIC_ID) >> 24; - log_early("LAPIC enabled: CPU %u, spurious vector 0x%x", id, LAPIC_SPURIOUS_VECTOR); +void lapic_eoi(void) +{ + lapic_write(LAPIC_EOI, 0); +} + +void lapic_send_ipi(uint32_t apic_id, uint32_t vector, uint32_t delivery_mode, uint32_t dest_mode, uint32_t shorthand) +{ + volatile uint32_t *base = LAPIC_BASE; + if (!base) + { + log_early("error: LAPIC not initialized for IPI"); + kpanic(NULL, "LAPIC IPI before init"); + } + + if (vector > 255 && delivery_mode != ICR_INIT && delivery_mode != ICR_STARTUP) + { + log_early("error: Invalid vector 0x%x for IPI", vector); + kpanic(NULL, "Invalid IPI vector"); + } + if (apic_id > 255 && shorthand == ICR_NO_SHORTHAND) + { + log_early("error: Invalid APIC ID %u for IPI", apic_id); + kpanic(NULL, "Invalid APIC ID"); + } + + while (lapic_read(LAPIC_ICRLO) & ICR_SEND_PENDING) + { + __asm__ volatile("pause"); + } + + if (shorthand == ICR_NO_SHORTHAND) + { + lapic_write(LAPIC_ICRHI, apic_id << ICR_DESTINATION_SHIFT); + } + else + { + lapic_write(LAPIC_ICRHI, 0); + } + + uint32_t icr_lo = vector | delivery_mode | dest_mode | ICR_ASSERT | ICR_EDGE | shorthand; + lapic_write(LAPIC_ICRLO, icr_lo); + + if (delivery_mode != ICR_INIT && delivery_mode != ICR_STARTUP) + { + while (lapic_read(LAPIC_ICRLO) & ICR_SEND_PENDING) + { + __asm__ volatile("pause"); + } + } } \ No newline at end of file diff --git a/kernel/src/sys/apic/lapic.h b/kernel/src/sys/apic/lapic.h index dc4b4a9..0d1e8f7 100644 --- a/kernel/src/sys/apic/lapic.h +++ b/kernel/src/sys/apic/lapic.h @@ -23,12 +23,19 @@ // ICR Fields #define ICR_FIXED 0x00000000 +#define ICR_OTHER 0x00000003 #define ICR_INIT 0x00000500 #define ICR_STARTUP 0x00000600 #define ICR_PHYSICAL 0x00000000 +#define ICR_LOGICAL 0x00000800 #define ICR_ASSERT 0x00004000 +#define ICR_DEASSERT 0x00000000 #define ICR_EDGE 0x00000000 +#define ICR_LEVEL 0x00008000 #define ICR_NO_SHORTHAND 0x00000000 +#define ICR_SELF 0x00040000 +#define ICR_ALL_INCLUDING_SELF 0x00080000 +#define ICR_ALL_EXCLUDING_SELF 0x000C0000 #define ICR_SEND_PENDING 0x00001000 #define ICR_DESTINATION_SHIFT 24 @@ -41,5 +48,7 @@ void lapic_write(uint32_t offset, uint32_t value); void lapic_init(void); void lapic_enable(void); void lapic_eoi(void); +void lapic_send_ipi(uint32_t apic_id, uint32_t vector, uint32_t delivery_mode, uint32_t dest_mode, uint32_t shorthand); +uint32_t lapic_get_id(void); #endif // LAPIC_H \ No newline at end of file diff --git a/kernel/src/sys/kpanic.c b/kernel/src/sys/kpanic.c index 0b57c34..5eb9cca 100644 --- a/kernel/src/sys/kpanic.c +++ b/kernel/src/sys/kpanic.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include static const char *strings[32] = { "Division by Zero", @@ -41,6 +43,7 @@ static const char *strings[32] = { "Security Exception", "RESERVED VECTOR"}; +/* TODO: Move to arch/ since its arch-specific */ static void capture_regs(struct register_ctx *context) { __asm__ volatile( @@ -93,6 +96,22 @@ static void capture_regs(struct register_ctx *context) void kpanic(struct register_ctx *ctx, const char *fmt, ...) { + /* Halt all other CPU's using our custom die trap at 0xFE/254 */ + lapic_send_ipi(0, 0xFE, ICR_FIXED, ICR_PHYSICAL, ICR_ALL_EXCLUDING_SELF); + + /* Wait until all CPU's except the one that panicked is halted */ + for (uint32_t i = 0; i < cpu_count; i++) + { + cpu_local_t *cur = &cpu_locals[i]; + if (cur->cpu_index != get_cpu_local()->cpu_index) + { + while (cur->ready) + { + __asm__ volatile("pause"); + } + } + } + struct register_ctx regs; if (ctx == NULL)