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:
parent
bfe3426f6d
commit
6dc22b7251
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue