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()
{
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);
}

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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);
}

View File

@ -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);
}