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()
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
}
|
Loading…
Reference in New Issue