From 6dc22b72516f7b4d115bbe645dccc556e050b97a Mon Sep 17 00:00:00 2001 From: Bananymous Date: Mon, 30 Jan 2023 18:52:38 +0200 Subject: [PATCH] Kernel: Add actual register values to x86_64 kernel panic Very hackish implementation, but we now get actual registers at the time of the interrupt happening --- kernel/arch/i386/IDT.cpp | 27 ++------ kernel/arch/x86_64/IDT.cpp | 69 +++++++++++++-------- kernel/arch/x86_64/interrupts.S | 18 +++++- kernel/include/kernel/APIC.h | 2 +- kernel/include/kernel/InterruptController.h | 2 +- kernel/include/kernel/PIC.h | 2 +- kernel/kernel/APIC.cpp | 9 ++- kernel/kernel/PIC.cpp | 14 ++--- 8 files changed, 77 insertions(+), 66 deletions(-) diff --git a/kernel/arch/i386/IDT.cpp b/kernel/arch/i386/IDT.cpp index d9460b98cf..2b62f2d5fb 100644 --- a/kernel/arch/i386/IDT.cpp +++ b/kernel/arch/i386/IDT.cpp @@ -111,23 +111,16 @@ namespace IDT extern "C" void handle_irq() { - uint32_t isr[8]; - InterruptController::Get().GetISR(isr); - uint8_t irq = 0; - for (uint8_t i = 0; i < 8; i++) + for (uint32_t i = 0; i <= 0xFF; i++) { - for (uint8_t j = 0; j < 32; j++) + if (InterruptController::Get().IsInService(i)) { - if (isr[i] & ((uint32_t)1 << j)) - { - irq = 32 * i + j; - goto found; - } + irq = i; + break; } } - found: if (irq == 0) { dprintln("Spurious irq"); @@ -137,19 +130,7 @@ namespace IDT if (s_irq_handlers[irq]) s_irq_handlers[irq](); else - { - uint32_t isr_byte = irq / 32; - uint32_t isr_bit = irq % 32; - - uint32_t isr[8]; - InterruptController::Get().GetISR(isr); - if (!(isr[isr_byte] & (1 << isr_bit))) - { - dprintln("spurious irq 0x{2H}", irq); - return; - } dprintln("no handler for irq 0x{2H}\n", irq); - } InterruptController::Get().EOI(irq); } diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/arch/x86_64/IDT.cpp index d74dd9ccbc..796a5d7582 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/arch/x86_64/IDT.cpp @@ -10,6 +10,33 @@ namespace IDT { + struct Registers + { + uint64_t rsp; + uint64_t rip; + uint64_t rflags; + uint64_t cr4; + uint64_t cr3; + uint64_t cr2; + uint64_t cr0; + + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rsi; + uint64_t rdi; + uint64_t rbp; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + }; + struct GateDescriptor { uint16_t offset1; @@ -68,25 +95,20 @@ namespace IDT "Unkown Exception 0x1F", }; - extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error) + extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, const Registers* regs) { - uint64_t rax, rbx, rcx, rdx, rsp, rbp; - uint64_t cr0, cr2, cr3, cr4; - asm volatile("" : "=a"(rax), "=b"(rbx), "=c"(rcx), "=d"(rdx)); - asm volatile("movq %%rsp, %0" : "=r"(rsp)); - asm volatile("movq %%rbp, %0" : "=r"(rbp)); - asm volatile("movq %%cr0, %0" : "=r"(cr0)); - asm volatile("movq %%cr2, %0" : "=r"(cr2)); - asm volatile("movq %%cr3, %0" : "=r"(cr3)); - asm volatile("movq %%cr4, %0" : "=r"(cr4)); - Kernel::Panic( "{} (error code: 0x{16H})\r\n" "Register dump\r\n" "rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n" - "rsp=0x{16H}, rbp=0x{16H}\r\n" - "CR0=0x{16H}, CR2=0x{16H}, CR3=0x{16H}, CR4=0x{16H}\r\n", - isr_exceptions[isr], error, rax, rbx, rcx, rdx, rsp, rbp, cr0, cr2, cr3, cr4 + "rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n" + "rip=0x{16H}, rflags=0x{16H}\r\n" + "cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}\r\n", + isr_exceptions[isr], error, + regs->rax, regs->rbx, regs->rcx, regs->rdx, + regs->rsp, regs->rbp, regs->rdi, regs->rsi, + regs->rip, regs->rflags, + regs->cr0, regs->cr2, regs->cr3, regs->cr4 ); } @@ -96,12 +118,7 @@ namespace IDT s_irq_handlers[irq](); else { - uint32_t isr_byte = irq / 32; - uint32_t isr_bit = irq % 32; - - uint32_t isr[8]; - InterruptController::Get().GetISR(isr); - if (!(isr[isr_byte] & (1 << isr_bit))) + if (!InterruptController::Get().IsInService(irq)) { dprintln("spurious irq 0x{2H}", irq); return; @@ -117,21 +134,21 @@ namespace IDT asm volatile("lidt %0"::"m"(s_idtr)); } - static void register_interrupt_handler(uint8_t index, void(*f)()) + static void register_interrupt_handler(uint8_t index, void(*handler)()) { GateDescriptor& descriptor = s_idt[index]; - descriptor.offset1 = (uint16_t)((uint64_t)f >> 0); - descriptor.offset2 = (uint16_t)((uint64_t)f >> 16); - descriptor.offset3 = (uint32_t)((uint64_t)f >> 32); + descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0); + descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16); + descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32); descriptor.selector = 0x08; descriptor.IST = 0; descriptor.flags = 0x8E; } - void register_irq_handler(uint8_t irq, void(*f)()) + void register_irq_handler(uint8_t irq, void(*handler)()) { - s_irq_handlers[irq] = f; + s_irq_handlers[irq] = handler; } extern "C" void isr0(); diff --git a/kernel/arch/x86_64/interrupts.S b/kernel/arch/x86_64/interrupts.S index 84bd375899..c650991ef4 100644 --- a/kernel/arch/x86_64/interrupts.S +++ b/kernel/arch/x86_64/interrupts.S @@ -36,16 +36,28 @@ isr_stub: pushaq - movq 120(%rsp), %rdi - movq 128(%rsp), %rsi + + movq %cr0, %rax; pushq %rax + movq %cr2, %rax; pushq %rax + movq %cr3, %rax; pushq %rax + movq %cr4, %rax; pushq %rax + movq 184(%rsp), %rax; pushq %rax + movq 176(%rsp), %rax; pushq %rax + movq 208(%rsp), %rax; pushq %rax + + movq 176(%rsp), %rdi + movq 184(%rsp), %rsi + movq %rsp, %rdx + call cpp_isr_handler + addq $56, %rsp popaq addq $16, %rsp iretq irq_stub: pushaq - movq 120(%rsp), %rdi + movq 0x78(%rsp), %rdi # irq number call cpp_irq_handler popaq addq $16, %rsp diff --git a/kernel/include/kernel/APIC.h b/kernel/include/kernel/APIC.h index 17b65c0787..215b43a2e7 100644 --- a/kernel/include/kernel/APIC.h +++ b/kernel/include/kernel/APIC.h @@ -8,7 +8,7 @@ class APIC final : public InterruptController public: virtual void EOI(uint8_t) override; virtual void EnableIrq(uint8_t) override; - virtual void GetISR(uint32_t[8]) override; + virtual bool IsInService(uint8_t) override; private: uint32_t ReadFromLocalAPIC(ptrdiff_t); diff --git a/kernel/include/kernel/InterruptController.h b/kernel/include/kernel/InterruptController.h index 328482a335..31080c29fe 100644 --- a/kernel/include/kernel/InterruptController.h +++ b/kernel/include/kernel/InterruptController.h @@ -9,7 +9,7 @@ public: virtual void EOI(uint8_t) = 0; virtual void EnableIrq(uint8_t) = 0; - virtual void GetISR(uint32_t[8]) = 0; + virtual bool IsInService(uint8_t) = 0; static void Initialize(bool force_pic); static InterruptController& Get(); diff --git a/kernel/include/kernel/PIC.h b/kernel/include/kernel/PIC.h index 92574ca147..054e358e4a 100644 --- a/kernel/include/kernel/PIC.h +++ b/kernel/include/kernel/PIC.h @@ -7,7 +7,7 @@ class PIC final : public InterruptController public: virtual void EOI(uint8_t) override; virtual void EnableIrq(uint8_t) override; - virtual void GetISR(uint32_t[8]) override; + virtual bool IsInService(uint8_t) override; static void Remap(); static void MaskAll(); diff --git a/kernel/kernel/APIC.cpp b/kernel/kernel/APIC.cpp index 83cadaf304..05df6e13fe 100644 --- a/kernel/kernel/APIC.cpp +++ b/kernel/kernel/APIC.cpp @@ -358,8 +358,11 @@ void APIC::EnableIrq(uint8_t irq) ioapic->Write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword); } -void APIC::GetISR(uint32_t out[8]) +bool APIC::IsInService(uint8_t irq) { - for (uint32_t i = 0; i < 8; i++) - out[i] = ReadFromLocalAPIC(LAPIC_IS_REG + i * 0x10); + uint32_t dword = (irq + IRQ_VECTOR_BASE) / 32; + uint32_t bit = (irq + IRQ_VECTOR_BASE) % 32; + + uint32_t isr = ReadFromLocalAPIC(LAPIC_IS_REG + dword * 0x10); + return isr & (1 << bit); } \ No newline at end of file diff --git a/kernel/kernel/PIC.cpp b/kernel/kernel/PIC.cpp index cc98eb65b0..43b0bdfe3b 100644 --- a/kernel/kernel/PIC.cpp +++ b/kernel/kernel/PIC.cpp @@ -98,14 +98,12 @@ void PIC::EnableIrq(uint8_t irq) IO::outb(port, value); } -void PIC::GetISR(uint32_t out[8]) +bool PIC::IsInService(uint8_t irq) { - memset(out, 0, 8 * sizeof(uint32_t)); - IO::outb(PIC1_COMMAND, PIC_READ_ISR); - IO::outb(PIC2_COMMAND, PIC_READ_ISR); - uint16_t isr0 = IO::inb(PIC1_COMMAND); - uint16_t isr1 = IO::inb(PIC2_COMMAND); + uint16_t port = irq < 8 ? PIC1_COMMAND : PIC2_COMMAND; + uint8_t bit = irq < 8 ? irq : irq - 8; - uintptr_t addr = (uintptr_t)out + IRQ_VECTOR_BASE / 8; - *(uint16_t*)addr = (isr1 << 8) | isr0; + IO::outb(port, PIC_READ_ISR); + uint16_t isr = IO::inb(port); + return isr & (1 << bit); } \ No newline at end of file