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
This commit is contained in:
Bananymous 2023-01-30 18:52:38 +02:00
parent bfe3426f6d
commit 6dc22b7251
8 changed files with 77 additions and 66 deletions

View File

@ -111,23 +111,16 @@ namespace IDT
extern "C" void handle_irq() extern "C" void handle_irq()
{ {
uint32_t isr[8];
InterruptController::Get().GetISR(isr);
uint8_t irq = 0; 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 = i;
{ break;
irq = 32 * i + j;
goto found;
}
} }
} }
found:
if (irq == 0) if (irq == 0)
{ {
dprintln("Spurious irq"); dprintln("Spurious irq");
@ -137,19 +130,7 @@ namespace IDT
if (s_irq_handlers[irq]) if (s_irq_handlers[irq])
s_irq_handlers[irq](); s_irq_handlers[irq]();
else 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); dprintln("no handler for irq 0x{2H}\n", irq);
}
InterruptController::Get().EOI(irq); InterruptController::Get().EOI(irq);
} }

View File

@ -10,6 +10,33 @@
namespace IDT 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 struct GateDescriptor
{ {
uint16_t offset1; uint16_t offset1;
@ -68,25 +95,20 @@ namespace IDT
"Unkown Exception 0x1F", "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( Kernel::Panic(
"{} (error code: 0x{16H})\r\n" "{} (error code: 0x{16H})\r\n"
"Register dump\r\n" "Register dump\r\n"
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n" "rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
"rsp=0x{16H}, rbp=0x{16H}\r\n" "rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
"CR0=0x{16H}, CR2=0x{16H}, CR3=0x{16H}, CR4=0x{16H}\r\n", "rip=0x{16H}, rflags=0x{16H}\r\n"
isr_exceptions[isr], error, rax, rbx, rcx, rdx, rsp, rbp, cr0, cr2, cr3, cr4 "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](); s_irq_handlers[irq]();
else else
{ {
uint32_t isr_byte = irq / 32; if (!InterruptController::Get().IsInService(irq))
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); dprintln("spurious irq 0x{2H}", irq);
return; return;
@ -117,21 +134,21 @@ namespace IDT
asm volatile("lidt %0"::"m"(s_idtr)); 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]; GateDescriptor& descriptor = s_idt[index];
descriptor.offset1 = (uint16_t)((uint64_t)f >> 0); descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0);
descriptor.offset2 = (uint16_t)((uint64_t)f >> 16); descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16);
descriptor.offset3 = (uint32_t)((uint64_t)f >> 32); descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32);
descriptor.selector = 0x08; descriptor.selector = 0x08;
descriptor.IST = 0; descriptor.IST = 0;
descriptor.flags = 0x8E; 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(); extern "C" void isr0();

View File

@ -36,16 +36,28 @@
isr_stub: isr_stub:
pushaq 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 call cpp_isr_handler
addq $56, %rsp
popaq popaq
addq $16, %rsp addq $16, %rsp
iretq iretq
irq_stub: irq_stub:
pushaq pushaq
movq 120(%rsp), %rdi movq 0x78(%rsp), %rdi # irq number
call cpp_irq_handler call cpp_irq_handler
popaq popaq
addq $16, %rsp addq $16, %rsp

View File

@ -8,7 +8,7 @@ class APIC final : public InterruptController
public: public:
virtual void EOI(uint8_t) override; virtual void EOI(uint8_t) override;
virtual void EnableIrq(uint8_t) override; virtual void EnableIrq(uint8_t) override;
virtual void GetISR(uint32_t[8]) override; virtual bool IsInService(uint8_t) override;
private: private:
uint32_t ReadFromLocalAPIC(ptrdiff_t); uint32_t ReadFromLocalAPIC(ptrdiff_t);

View File

@ -9,7 +9,7 @@ public:
virtual void EOI(uint8_t) = 0; virtual void EOI(uint8_t) = 0;
virtual void EnableIrq(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 void Initialize(bool force_pic);
static InterruptController& Get(); static InterruptController& Get();

View File

@ -7,7 +7,7 @@ class PIC final : public InterruptController
public: public:
virtual void EOI(uint8_t) override; virtual void EOI(uint8_t) override;
virtual void EnableIrq(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 Remap();
static void MaskAll(); static void MaskAll();

View File

@ -358,8 +358,11 @@ void APIC::EnableIrq(uint8_t irq)
ioapic->Write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword); 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++) uint32_t dword = (irq + IRQ_VECTOR_BASE) / 32;
out[i] = ReadFromLocalAPIC(LAPIC_IS_REG + i * 0x10); uint32_t bit = (irq + IRQ_VECTOR_BASE) % 32;
uint32_t isr = ReadFromLocalAPIC(LAPIC_IS_REG + dword * 0x10);
return isr & (1 << bit);
} }

View File

@ -98,14 +98,12 @@ void PIC::EnableIrq(uint8_t irq)
IO::outb(port, value); IO::outb(port, value);
} }
void PIC::GetISR(uint32_t out[8]) bool PIC::IsInService(uint8_t irq)
{ {
memset(out, 0, 8 * sizeof(uint32_t)); uint16_t port = irq < 8 ? PIC1_COMMAND : PIC2_COMMAND;
IO::outb(PIC1_COMMAND, PIC_READ_ISR); uint8_t bit = irq < 8 ? irq : irq - 8;
IO::outb(PIC2_COMMAND, PIC_READ_ISR);
uint16_t isr0 = IO::inb(PIC1_COMMAND);
uint16_t isr1 = IO::inb(PIC2_COMMAND);
uintptr_t addr = (uintptr_t)out + IRQ_VECTOR_BASE / 8; IO::outb(port, PIC_READ_ISR);
*(uint16_t*)addr = (isr1 << 8) | isr0; uint16_t isr = IO::inb(port);
return isr & (1 << bit);
} }