1
0
Fork 0

feat/kernel: Die trap

This commit is contained in:
Kevin Alavik 2025-06-01 21:08:04 +02:00
parent d306dcb199
commit 2b29a1afa1
No known key found for this signature in database
GPG key ID: 47AAEA397DB76AD0
11 changed files with 152 additions and 42 deletions

View file

@ -40,34 +40,45 @@ void idt_default_interrupt_handler(struct register_ctx *ctx)
kpanic(ctx, NULL); kpanic(ctx, NULL);
} }
#define SET_GATE(interrupt, base, flags) \ /* pesky little trap which just halts the current cpu and lets it die alone */
do \ void die(struct register_ctx *)
{ \ {
idt_descriptor[(interrupt)].off_low = (base) & 0xFFFF; \ /* If the CPU has caught this its game over */
idt_descriptor[(interrupt)].sel = 0x8; \ cpu_local_t *cpu = get_cpu_local();
idt_descriptor[(interrupt)].ist = 0; \ cpu->ready = false;
idt_descriptor[(interrupt)].attr = (flags); \ hcf();
idt_descriptor[(interrupt)].off_mid = ((base) >> 16) & 0xFFFF; \ }
idt_descriptor[(interrupt)].off_high = ((base) >> 32) & 0xFFFFFFFF; \
idt_descriptor[(interrupt)].zero = 0; \ void idt_set_gate(uint8_t interrupt, uint64_t base, uint8_t flags)
} while (0) {
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() void idt_init()
{ {
for (int i = 0; i < 32; i++) 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; real_handlers[i] = idt_default_interrupt_handler;
} }
for (int i = 32; i < 256; i++) 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; real_handlers[0x80] = syscall_handler;
idt_set_gate(0xFE, stubs[0xFE], IDT_TRAP_GATE);
real_handlers[0xFE] = die;
__asm__ volatile( __asm__ volatile(
"lidt %0" "lidt %0"
: : "m"(idt_ptr) : "memory"); : : "m"(idt_ptr) : "memory");

View file

@ -33,5 +33,6 @@ typedef void (*idt_intr_handler)(struct register_ctx *ctx);
void idt_init(); void idt_init();
int idt_register_handler(size_t vector, idt_intr_handler handler); int idt_register_handler(size_t vector, idt_intr_handler handler);
void idt_default_interrupt_handler(struct register_ctx *ctx); 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 #endif // IDT_H

View file

@ -17,17 +17,31 @@
#include <arch/gdt.h> #include <arch/gdt.h>
#include <arch/idt.h> #include <arch/idt.h>
#define MAX_CPUS 256
#define MSR_GS_BASE 0xC0000101 #define MSR_GS_BASE 0xC0000101
uint32_t cpu_count = 0; uint32_t cpu_count = 0;
uint32_t bootstrap_lapic_id = 0; uint32_t bootstrap_lapic_id = 0;
atomic_uint started_cpus = 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) 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) 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); log_early("CPU %d (LAPIC ID %u) is up", cpu->cpu_index, lapic_id);
cpu->ready = true; cpu->ready = true;
__asm__ volatile("sti");
hlt(); hlt();
} }

View file

@ -5,7 +5,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
extern uint32_t bootstrap_lapic_id; #define MAX_CPUS 256
typedef struct typedef struct
{ {
@ -14,6 +14,10 @@ typedef struct
bool ready; bool ready;
} cpu_local_t; } 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(); void smp_init();
cpu_local_t *get_cpu_local(void); cpu_local_t *get_cpu_local(void);

View file

@ -4,6 +4,7 @@
#include <sys/apic/lapic.h> #include <sys/apic/lapic.h>
#include <sys/apic/ioapic.h> #include <sys/apic/ioapic.h>
#include <util/log.h> #include <util/log.h>
#include <arch/smp.h>
#define PIT_VECTOR 32 #define PIT_VECTOR 32
@ -28,6 +29,6 @@ void pit_init(idt_intr_handler handler)
outb(0x40, (divisor >> 8) & 0xFF); outb(0x40, (divisor >> 8) & 0xFF);
idt_register_handler(PIT_VECTOR, pit_handler); 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); ioapic_unmask(0);
} }

View file

@ -211,7 +211,7 @@ void emk_entry(void)
ioapic_init(); ioapic_init();
/* Setup timer */ /* Setup timer */
pit_init(NULL); pit_init(tick);
/* Finished */ /* Finished */
log_early("%s", LOG_SEPARATOR); log_early("%s", LOG_SEPARATOR);

View file

@ -51,7 +51,7 @@ uint32_t ioapic_read(uint8_t index)
return ioapic[IOAPIC_OFF_IOWIN / 4]; 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 gsi = irq_to_gsi(irq);
uint32_t max_irqs = ((ioapic_read(IOAPIC_IDX_IOAPICVER) >> 16) & 0xFF) + 1; 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 (dest_mode << 11) | // 0: Physical, 1: Logical
(0 << 8) | // Fixed delivery (0 << 8) | // Fixed delivery
vec; 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, redtble_lo);
ioapic_write(0x10 + 2 * gsi + 1, redtble_hi); 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) void ioapic_unmask(int irq)
@ -89,7 +87,6 @@ void ioapic_unmask(int irq)
uint32_t redtble_lo = ioapic_read(0x10 + 2 * gsi); uint32_t redtble_lo = ioapic_read(0x10 + 2 * gsi);
redtble_lo &= ~(1 << 16); redtble_lo &= ~(1 << 16);
ioapic_write(0x10 + 2 * gsi, redtble_lo); ioapic_write(0x10 + 2 * gsi, redtble_lo);
log_early("Unmasked IRQ %d (GSI %u)", irq, gsi);
} }
void ioapic_init(void) 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("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);
} }

View file

@ -12,7 +12,7 @@
#define IOAPIC_IDX_RED_TBL 0x10 #define IOAPIC_IDX_RED_TBL 0x10
void ioapic_init(); 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); void ioapic_unmask(int irq);
#endif // IOAPIC_H #endif // IOAPIC_H

View file

@ -46,6 +46,23 @@ uint32_t lapic_read(uint32_t offset)
return base[offset / LAPIC_REG_SIZE]; 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) void lapic_init(void)
{ {
uint64_t msr = rdmsr(LAPIC_BASE_MSR); uint64_t msr = rdmsr(LAPIC_BASE_MSR);
@ -72,18 +89,7 @@ void lapic_init(void)
} }
atomic_store(&lapic_base, virt_addr); atomic_store(&lapic_base, virt_addr);
uint32_t id = lapic_read(LAPIC_ID) >> 24; uint32_t id = lapic_get_id(); // Use the new function
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)
{
lapic_write(LAPIC_EOI, 0); lapic_write(LAPIC_EOI, 0);
} }
@ -118,7 +124,55 @@ void lapic_enable(void)
lapic_write(LAPIC_LVT_LINT1, lvt1); lapic_write(LAPIC_LVT_LINT1, lvt1);
lapic_write(LAPIC_TPR, 0); lapic_write(LAPIC_TPR, 0);
}
uint32_t id = lapic_read(LAPIC_ID) >> 24; void lapic_eoi(void)
log_early("LAPIC enabled: CPU %u, spurious vector 0x%x", id, LAPIC_SPURIOUS_VECTOR); {
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");
}
}
} }

View file

@ -23,12 +23,19 @@
// ICR Fields // ICR Fields
#define ICR_FIXED 0x00000000 #define ICR_FIXED 0x00000000
#define ICR_OTHER 0x00000003
#define ICR_INIT 0x00000500 #define ICR_INIT 0x00000500
#define ICR_STARTUP 0x00000600 #define ICR_STARTUP 0x00000600
#define ICR_PHYSICAL 0x00000000 #define ICR_PHYSICAL 0x00000000
#define ICR_LOGICAL 0x00000800
#define ICR_ASSERT 0x00004000 #define ICR_ASSERT 0x00004000
#define ICR_DEASSERT 0x00000000
#define ICR_EDGE 0x00000000 #define ICR_EDGE 0x00000000
#define ICR_LEVEL 0x00008000
#define ICR_NO_SHORTHAND 0x00000000 #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_SEND_PENDING 0x00001000
#define ICR_DESTINATION_SHIFT 24 #define ICR_DESTINATION_SHIFT 24
@ -41,5 +48,7 @@ void lapic_write(uint32_t offset, uint32_t value);
void lapic_init(void); void lapic_init(void);
void lapic_enable(void); void lapic_enable(void);
void lapic_eoi(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 #endif // LAPIC_H

View file

@ -6,6 +6,8 @@
#include <lib/string.h> #include <lib/string.h>
#include <arch/cpu.h> #include <arch/cpu.h>
#include <arch/smp.h> #include <arch/smp.h>
#include <sys/apic/lapic.h>
#include <arch/idt.h>
static const char *strings[32] = { static const char *strings[32] = {
"Division by Zero", "Division by Zero",
@ -41,6 +43,7 @@ static const char *strings[32] = {
"Security Exception", "Security Exception",
"RESERVED VECTOR"}; "RESERVED VECTOR"};
/* TODO: Move to arch/ since its arch-specific */
static void capture_regs(struct register_ctx *context) static void capture_regs(struct register_ctx *context)
{ {
__asm__ volatile( __asm__ volatile(
@ -93,6 +96,22 @@ static void capture_regs(struct register_ctx *context)
void kpanic(struct register_ctx *ctx, const char *fmt, ...) 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; struct register_ctx regs;
if (ctx == NULL) if (ctx == NULL)