summaryrefslogtreecommitdiff
path: root/src/kernel/arch/amd64/interrupts/isr.c
diff options
context:
space:
mode:
authordzwdz2024-07-22 18:05:07 +0200
committerdzwdz2024-07-22 18:05:07 +0200
commit2a09d77902c5007fb30c40f9c89ecb46aedf4006 (patch)
tree35e3f3332982fc359941e8cbc4ed5e3c5bf73425 /src/kernel/arch/amd64/interrupts/isr.c
parent1fc2d9c88af77c3af81b6bd461e6b019b97d2dbb (diff)
kernel/isr: improve interrupt handling code
On the assembly side, ensure the stack frame looks always the same, by pushing a fake "error code" for the interrupts that don't generate one. On the C side, use a struct instead of magic indices into an "array", and make it consistent with the current style.
Diffstat (limited to 'src/kernel/arch/amd64/interrupts/isr.c')
-rw-r--r--src/kernel/arch/amd64/interrupts/isr.c61
1 files changed, 38 insertions, 23 deletions
diff --git a/src/kernel/arch/amd64/interrupts/isr.c b/src/kernel/arch/amd64/interrupts/isr.c
index dd97fd4..bf84c5c 100644
--- a/src/kernel/arch/amd64/interrupts/isr.c
+++ b/src/kernel/arch/amd64/interrupts/isr.c
@@ -8,29 +8,48 @@
#include <stdint.h>
enum {
- NMI = 0x02,
- GP_FAULT = 0x0d,
- PAGE_FAULT = 0x0e,
+ Nmi = 0x02,
+ GpFault = 0x0d,
+ PageFault = 0x0e,
};
+typedef struct {
+ uint64_t ip, cs, flags;
+ /* only valid if switching from/into user mode */
+ uint64_t sp, ss;
+} IretFrame;
+
void (*irq_fn[16])(void) = {0};
-static void log_interrupt(int interrupt, uint64_t *stackframe) {
+static uint64_t
+getcr2(void)
+{
+ uint64_t cr2;
+ asm("mov %%cr2, %0" : "=r"(cr2));
+ return cr2;
+}
+
+static void
+log_interrupt(uint8_t inr, void *stackframe)
+{
+ IretFrame *iret = stackframe;
+ uint64_t *errcode = ((uint64_t*)stackframe) - 1;
kprintf("interrupt %d, rip = k/%08x, cs 0x%x, code 0x%x\n",
- interrupt, stackframe[0], stackframe[1], stackframe[-1]);
- if ((stackframe[1] & 0x3) == 0) {
- uint64_t *stack = (void*)stackframe[3];
- kprintf("kernel rip = %p, *rip = %p\n", stack, *stack);
+ inr, iret->ip, iret->cs, *errcode);
+ if ((iret->cs & 0x3) == 0) { /* ring 0? */
+ uint64_t *stack = (void*)iret->sp;
+ kprintf("kernel rsp = %p, *rsp = %p\n", stack, *stack);
}
- if (interrupt == PAGE_FAULT) {
- uint64_t addr = 0x69;
- asm("mov %%cr2, %0" : "=r"(addr));
- kprintf("addr 0x%x\n", addr);
+ if (inr == PageFault) {
+ kprintf("addr 0x%x\n", getcr2());
}
}
-void isr_stage3(uint8_t interrupt, uint64_t *stackframe) {
- uint8_t irqn = interrupt - IRQ_IBASE;
+void
+isr_stage3(uint8_t inr, void *stackframe)
+{
+ IretFrame *iret = stackframe;
+ uint8_t irqn = inr - IRQ_IBASE;
if (irqn < 16) {
if (irq_fn[irqn]) {
irq_fn[irqn]();
@@ -39,21 +58,17 @@ void isr_stage3(uint8_t interrupt, uint64_t *stackframe) {
}
}
- if (interrupt == NMI) { /* print some debugging information */
- log_interrupt(interrupt, stackframe);
+ if (inr == Nmi) { /* print some debugging information */
+ log_interrupt(inr, stackframe);
mem_debugprint();
return;
}
- if (interrupt == PAGE_FAULT || interrupt == GP_FAULT) {
- stackframe++;
- }
-
- if ((stackframe[1] & 0x3) == 0) { /* in kernel */
- log_interrupt(interrupt, stackframe);
+ if ((iret->cs & 0x3) == 0) { /* ring 0? */
+ log_interrupt(inr, stackframe);
cpu_halt();
} else { /* in user */
- proc_kill(proc_cur, interrupt);
+ proc_kill(proc_cur, inr);
proc_switch_any();
}
}