Files
mop3/kernel/amd64/intr.c
kamkow1 fbf067d418
All checks were successful
Build ISO image / build-and-deploy (push) Successful in 2m6s
Build documentation / build-and-deploy (push) Successful in 1m18s
Parse commandline strings, move away from old env vars
2026-04-28 22:45:31 +02:00

252 lines
6.7 KiB
C

#include <amd64/apic.h>
#include <amd64/fx.h>
#include <amd64/gdt.h>
#include <amd64/intr.h>
#include <amd64/intr_defs.h>
#include <amd64/io.h>
#include <aux/compiler.h>
#include <irq/irq.h>
#include <libk/lengthof.h>
#include <libk/std.h>
#include <libk/string.h>
#include <proc/reschedule.h>
#include <sync/biglock.h>
#include <sys/debug.h>
#include <sys/intr.h>
#include <sys/smp.h>
#include <sys/spin.h>
#include <syscall/syscall.h>
#include <syscall_defs.h>
/* 8259 PIC defs. */
#define PIC1 0x20
#define PIC2 0xA0
#define PIC1_CMD PIC1
#define PIC1_DATA (PIC1 + 1)
#define PIC2_CMD PIC2
#define PIC2_DATA (PIC2 + 1)
#define PIC_EOI 0x20
#define ICW1_ICW4 0x01
#define ICW1_SINGLE 0x02
#define ICW1_INTVL4 0x04
#define ICW1_LEVEL 0x08
#define ICW1_INIT 0x10
#define ICW4_8086 0x01
#define ICW4_AUTO 0x02
#define ICW4_BUFSLAVE 0x08
#define ICW4_BUFMASER 0x0C
#define ICW4_SFNM 0x10
#define CASCADE_IRQ 2
/* IDT defs. */
#define IDT_ENTRIES_MAX 256
/* 64-bit <IDT entry structure: https://wiki.osdev.org/Interrupt_Descriptor_Table */
struct idt_entry {
uint16_t intrlow;
uint16_t kernel_cs;
uint8_t ist;
uint8_t attrs;
uint16_t intrmid;
uint32_t intrhigh;
uint32_t resv;
} PACKED;
struct idt {
uint16_t limit;
uint64_t base;
} PACKED;
ALIGNED(16) static volatile struct idt_entry idt_entries[IDT_ENTRIES_MAX];
static volatile struct idt idt;
/* Remaps and disables old 8259 PIC, since we'll be using APIC. */
static void pic_init(void) {
outb(PIC1_CMD, (ICW1_INIT | ICW1_ICW4));
io_wait();
outb(PIC2_CMD, (ICW1_INIT | ICW1_ICW4));
io_wait();
outb(PIC1_DATA, 0x20);
io_wait();
outb(PIC2_DATA, 0x28);
io_wait();
outb(PIC1_DATA, (1 << CASCADE_IRQ));
io_wait();
outb(PIC2_DATA, 2);
io_wait();
outb(PIC1_DATA, ICW4_8086);
io_wait();
outb(PIC2_DATA, ICW4_8086);
io_wait();
/* Disable */
outb(PIC1_DATA, 0xFF);
io_wait();
outb(PIC2_DATA, 0xFF);
io_wait();
}
/* Set IDT entry */
static void idt_set(volatile struct idt_entry* ent, uint64_t handler, uint8_t flags, uint8_t ist) {
ent->intrlow = (handler & 0xFFFF);
ent->kernel_cs = GDT_KCODE;
ent->ist = ist;
ent->attrs = flags;
ent->intrmid = ((handler >> 16) & 0xFFFF);
ent->intrhigh = ((handler >> 32) & 0xFFFFFFFF);
ent->resv = 0;
}
/* Load the IDT */
void idt_load(void) { __asm__ volatile("lidt %0" ::"m"(idt)); }
/* Initialize IDT entries */
static void idt_init(void) {
memset((void*)idt_entries, 0, sizeof(idt_entries));
#define IDT_ENTRY(n, ist) \
extern void intr##n(void); \
idt_set(&idt_entries[(n)], (uint64_t)&intr##n, 0x8E, (ist))
/* clang-format off */
IDT_ENTRY (0, 1); IDT_ENTRY (1, 1); IDT_ENTRY (2, 1); IDT_ENTRY (3, 1);
IDT_ENTRY (4, 1); IDT_ENTRY (5, 1); IDT_ENTRY (6, 1); IDT_ENTRY (7, 1);
IDT_ENTRY (8, 1); IDT_ENTRY (9, 1); IDT_ENTRY (10, 1); IDT_ENTRY (11, 1);
IDT_ENTRY (12, 1); IDT_ENTRY (13, 1); IDT_ENTRY (14, 1); IDT_ENTRY (15, 1);
IDT_ENTRY (16, 1); IDT_ENTRY (17, 1); IDT_ENTRY (18, 1); IDT_ENTRY (19, 1);
IDT_ENTRY (20, 1); IDT_ENTRY (21, 1); IDT_ENTRY (22, 1); IDT_ENTRY (23, 1);
IDT_ENTRY (24, 1); IDT_ENTRY (25, 1); IDT_ENTRY (26, 1); IDT_ENTRY (27, 1);
IDT_ENTRY (28, 1); IDT_ENTRY (29, 1); IDT_ENTRY (30, 1); IDT_ENTRY (31, 1);
IDT_ENTRY (32, 2); IDT_ENTRY (33, 2); IDT_ENTRY (34, 2); IDT_ENTRY (35, 2);
IDT_ENTRY (36, 2); IDT_ENTRY (37, 2); IDT_ENTRY (38, 2); IDT_ENTRY (39, 2);
IDT_ENTRY (40, 2); IDT_ENTRY (41, 2); IDT_ENTRY (42, 2); IDT_ENTRY (43, 2);
IDT_ENTRY (44, 2); IDT_ENTRY (45, 2); IDT_ENTRY (46, 2); IDT_ENTRY (47, 2);
IDT_ENTRY (INTR_SYSTICK, 2);
IDT_ENTRY (INTR_CPU_REQUEST_SCHED, 2);
IDT_ENTRY (INTR_CPU_SPURIOUS, 2);
/* clang-format on */
#undef IDT_ENTRY
idt.limit = sizeof(idt_entries) - 1;
idt.base = (uint64_t)idt_entries;
idt_load();
}
/* Handle CPU exception and dump registers. If incoming CS has CPL3, kill the process. */
static void intr_exception(struct saved_regs* regs) {
DEBUG("cpu exception %lu (%lu)\n", regs->trap, regs->error);
uint64_t cr2;
__asm__ volatile("movq %%cr2, %0" : "=r"(cr2));
uint64_t cr3;
__asm__ volatile("movq %%cr3, %0" : "=r"(cr3));
debugprintf("r15=%016lx r14=%016lx r13=%016lx\n"
"r12=%016lx r11=%016lx r10=%016lx\n"
"r9 =%016lx r8 =%016lx rbp=%016lx\n"
"rdi=%016lx rsi=%016lx rdx=%016lx\n"
"rcx=%016lx rax=%016lx trp=%016lx\n"
"err=%016lx rip=%016lx cs =%016lx\n"
"rfl=%016lx rsp=%016lx ss =%016lx\n"
"cr2=%016lx cr3=%016lx rbx=%016lx\n",
regs->r15, regs->r14, regs->r13, regs->r12, regs->r11, regs->r10, regs->r9, regs->r8,
regs->rbp, regs->rdi, regs->rsi, regs->rdx, regs->rcx, regs->rax, regs->trap,
regs->error, regs->rip, regs->cs, regs->rflags, regs->rsp, regs->ss, cr2, cr3,
regs->rbx);
if (regs->cs == (GDT_UCODE | 0x03)) {
biglock_lock();
struct reschedule_ctx rctx;
memset(&rctx, 0, sizeof(rctx));
proc_kill(thiscpu->proc_current, &rctx);
bool do_thiscpu = false;
for (size_t i = 0; i < lengthof(rctx.cpus); i++) {
if (rctx.cpus[i] != NULL && rctx.cpus[i] != thiscpu)
cpu_request_sched(rctx.cpus[i], true);
else
do_thiscpu = true;
}
if (do_thiscpu)
cpu_request_sched(thiscpu, true);
biglock_unlock();
} else {
spin();
}
}
/* Handle incoming interrupt, dispatch IRQ handlers. */
void intr_handler(void* stack_ptr) {
load_kernel_cr3();
struct saved_regs* regs = stack_ptr;
if (regs->trap <= 31) {
intr_exception(regs);
} else {
bool user = false;
if (regs->cs == (GDT_UCODE | 0x3)) {
biglock_lock();
user = true;
struct proc* proc_current = thiscpu->proc_current;
memcpy(&proc_current->pdata.regs, regs, sizeof(struct saved_regs));
fx_save(proc_current->pdata.fx_env);
}
lapic_eoi();
struct irq* irq = irq_find(regs->trap);
if (irq == NULL) {
if (user)
biglock_unlock();
return;
}
struct reschedule_ctx rctx;
memset(&rctx, 0, sizeof(rctx));
irq->func(irq->arg, stack_ptr, user, &rctx);
if (user) {
bool do_thiscpu = false;
for (size_t i = 0; i < lengthof(rctx.cpus); i++) {
if (rctx.cpus[i] != NULL && rctx.cpus[i] != thiscpu)
cpu_request_sched(rctx.cpus[i], user);
else
do_thiscpu = true;
}
if (do_thiscpu)
cpu_request_sched(thiscpu, user);
biglock_unlock();
}
}
}
void intr_disable(void) { __asm__ volatile("cli" ::: "memory"); }
void intr_enable(void) { __asm__ volatile("sti" ::: "memory"); }
/* Initialize interrupts */
void intr_init(void) {
pic_init();
idt_init();
}