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);
}
#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");

View file

@ -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

View file

@ -17,17 +17,31 @@
#include <arch/gdt.h>
#include <arch/idt.h>
#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();
}

View file

@ -5,7 +5,7 @@
#include <stdint.h>
#include <stdbool.h>
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);

View file

@ -4,6 +4,7 @@
#include <sys/apic/lapic.h>
#include <sys/apic/ioapic.h>
#include <util/log.h>
#include <arch/smp.h>
#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);
}

View file

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

View file

@ -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);
}

View file

@ -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

View file

@ -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");
}
}
}

View file

@ -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

View file

@ -6,6 +6,8 @@
#include <lib/string.h>
#include <arch/cpu.h>
#include <arch/smp.h>
#include <sys/apic/lapic.h>
#include <arch/idt.h>
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)