feat/kernel: Die trap
This commit is contained in:
parent
d306dcb199
commit
2b29a1afa1
11 changed files with 152 additions and 42 deletions
|
@ -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");
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -211,7 +211,7 @@ void emk_entry(void)
|
|||
ioapic_init();
|
||||
|
||||
/* Setup timer */
|
||||
pit_init(NULL);
|
||||
pit_init(tick);
|
||||
|
||||
/* Finished */
|
||||
log_early("%s", LOG_SEPARATOR);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue