2023-05-17 22:54:37 -07:00
|
|
|
#include "interrupt/interrupt.h"
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
2023-05-29 21:52:01 -07:00
|
|
|
#include "common/port.h"
|
2023-05-17 22:54:37 -07:00
|
|
|
#include "debug/debug.h"
|
2023-06-07 13:40:36 -07:00
|
|
|
#include "interrupt/apic.h"
|
2023-06-07 10:01:22 -07:00
|
|
|
#include "memory/kernel_heap.h"
|
2023-05-29 22:32:50 -07:00
|
|
|
#include "scheduler/scheduler.h"
|
2023-05-17 22:54:37 -07:00
|
|
|
|
|
|
|
#define IDT_INTERRUPT_GATE 0x8E
|
|
|
|
|
|
|
|
#define KERNEL_CS 0x8
|
|
|
|
|
|
|
|
struct InterruptDescriptorTablePointer {
|
|
|
|
uint16_t size;
|
|
|
|
uint64_t base;
|
|
|
|
} __attribute__((packed));
|
|
|
|
|
|
|
|
struct InterruptDescriptor {
|
|
|
|
uint16_t offset_low;
|
|
|
|
uint16_t selector;
|
|
|
|
uint8_t ist;
|
|
|
|
uint8_t flags;
|
|
|
|
uint16_t offset_medium;
|
|
|
|
uint32_t offset_high;
|
|
|
|
uint32_t zero;
|
|
|
|
} __attribute__((packed));
|
|
|
|
|
|
|
|
static InterruptDescriptor gIdt[256];
|
|
|
|
|
|
|
|
InterruptDescriptor CreateDescriptor(void isr(void)) {
|
|
|
|
uint64_t offset = reinterpret_cast<uint64_t>(isr);
|
|
|
|
return InterruptDescriptor{
|
|
|
|
.offset_low = static_cast<uint16_t>(offset),
|
|
|
|
.selector = KERNEL_CS,
|
|
|
|
.ist = 0,
|
|
|
|
.flags = IDT_INTERRUPT_GATE,
|
|
|
|
.offset_medium = static_cast<uint16_t>(offset >> 16),
|
|
|
|
.offset_high = static_cast<uint32_t>(offset >> 32),
|
|
|
|
.zero = 0x0,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-05-18 13:56:09 -07:00
|
|
|
struct InterruptFrame {
|
2023-06-07 22:24:50 -07:00
|
|
|
uint64_t cr2;
|
2023-05-18 13:56:09 -07:00
|
|
|
uint64_t rax;
|
|
|
|
uint64_t rbx;
|
|
|
|
uint64_t rcx;
|
|
|
|
uint64_t rdx;
|
|
|
|
uint64_t rsi;
|
|
|
|
uint64_t rdi;
|
|
|
|
uint64_t r8;
|
|
|
|
uint64_t r9;
|
|
|
|
uint64_t r10;
|
|
|
|
uint64_t r11;
|
|
|
|
uint64_t r12;
|
|
|
|
uint64_t r13;
|
|
|
|
uint64_t r14;
|
|
|
|
uint64_t r15;
|
|
|
|
uint64_t rbp;
|
|
|
|
uint64_t error_code;
|
|
|
|
uint64_t rip;
|
|
|
|
uint64_t cs;
|
|
|
|
uint64_t eflags;
|
|
|
|
uint64_t rsp;
|
|
|
|
uint64_t ss;
|
|
|
|
};
|
|
|
|
|
2023-05-17 22:54:37 -07:00
|
|
|
extern "C" void isr_divide_by_zero();
|
|
|
|
extern "C" void interrupt_divide_by_zero(void* frame) { panic("DIV0"); }
|
|
|
|
|
|
|
|
extern "C" void isr_protection_fault();
|
2023-05-29 22:01:06 -07:00
|
|
|
extern "C" void interrupt_protection_fault(InterruptFrame* frame) {
|
|
|
|
dbgln("General Protection Fault");
|
|
|
|
uint64_t err = frame->error_code;
|
|
|
|
if (err & 0x1) {
|
|
|
|
dbgln("External Source");
|
|
|
|
}
|
|
|
|
if (err & 0x2) {
|
|
|
|
dbgln("IDT");
|
|
|
|
} else {
|
|
|
|
dbgln("GDT");
|
|
|
|
}
|
|
|
|
dbgln("Index: %u", err >> 3);
|
2023-06-07 00:04:53 -07:00
|
|
|
dbgln("RIP: %m", frame->rip);
|
|
|
|
dbgln("RSP: %m", frame->rsp);
|
2023-05-29 22:01:06 -07:00
|
|
|
|
|
|
|
panic("GP");
|
|
|
|
}
|
2023-05-17 22:54:37 -07:00
|
|
|
|
2023-05-18 10:43:45 -07:00
|
|
|
extern "C" void isr_page_fault();
|
2023-05-18 13:56:09 -07:00
|
|
|
extern "C" void interrupt_page_fault(InterruptFrame* frame) {
|
2023-06-07 22:24:50 -07:00
|
|
|
uint64_t err = frame->error_code;
|
|
|
|
if ((err & 0x1) == 0) {
|
|
|
|
// Page not present error may be resolveable.
|
|
|
|
if (gScheduler->CurrentProcess().vmas()->HandlePageFault(frame->cr2)) {
|
|
|
|
return;
|
|
|
|
}
|
2023-06-06 21:44:10 -07:00
|
|
|
}
|
2023-06-07 13:51:13 -07:00
|
|
|
dbgln("Unhandled Page Fault:");
|
2023-05-18 13:56:09 -07:00
|
|
|
if (err & 0x1) {
|
|
|
|
dbgln("Page Protection");
|
|
|
|
} else {
|
|
|
|
dbgln("Page Not Present");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err & 0x2) {
|
|
|
|
dbgln("Write");
|
|
|
|
} else {
|
|
|
|
dbgln("Read");
|
|
|
|
}
|
|
|
|
|
2023-06-06 21:44:10 -07:00
|
|
|
if (err & 0x4) {
|
|
|
|
dbgln("User Space");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err & 0x10) {
|
2023-05-18 13:56:09 -07:00
|
|
|
dbgln("Instruction Fetch");
|
|
|
|
}
|
|
|
|
|
|
|
|
dbgln("rip: %m", frame->rip);
|
2023-06-07 22:24:50 -07:00
|
|
|
dbgln("addr: %m", frame->cr2);
|
2023-05-18 13:56:09 -07:00
|
|
|
panic("PF");
|
|
|
|
}
|
2023-05-18 10:43:45 -07:00
|
|
|
|
2023-05-29 21:52:01 -07:00
|
|
|
uint64_t cnt = 0;
|
|
|
|
extern "C" void isr_timer();
|
|
|
|
extern "C" void interrupt_timer(InterruptFrame*) {
|
|
|
|
cnt++;
|
2023-05-29 22:17:56 -07:00
|
|
|
if (cnt % 20 == 0) {
|
2023-06-07 10:01:22 -07:00
|
|
|
if (cnt == 20) {
|
|
|
|
KernelHeap::DumpDistribution();
|
|
|
|
}
|
2023-05-29 22:17:56 -07:00
|
|
|
dbgln("timer: %us", cnt * 50 / 1000);
|
2023-05-29 21:52:01 -07:00
|
|
|
}
|
2023-06-07 13:40:36 -07:00
|
|
|
SignalEOI();
|
2023-05-29 23:48:32 -07:00
|
|
|
gScheduler->Preempt();
|
2023-05-29 21:52:01 -07:00
|
|
|
}
|
|
|
|
|
2023-06-21 15:07:40 -07:00
|
|
|
glcr::RefPtr<Port> pci1_port;
|
2023-06-12 19:20:51 -07:00
|
|
|
extern "C" void isr_pci1();
|
|
|
|
extern "C" void interrupt_pci1(InterruptFrame*) {
|
|
|
|
dbgln("Interrupt PCI line 1");
|
2023-06-21 23:42:21 -07:00
|
|
|
pci1_port->Send(0, nullptr, 0, nullptr);
|
2023-06-12 19:20:51 -07:00
|
|
|
SignalEOI();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void isr_pci2();
|
|
|
|
extern "C" void interrupt_pci2(InterruptFrame*) {
|
|
|
|
dbgln("Interrupt PCI line 2");
|
|
|
|
SignalEOI();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void isr_pci3();
|
|
|
|
extern "C" void interrupt_pci3(InterruptFrame*) {
|
|
|
|
dbgln("Interrupt PCI line 3");
|
|
|
|
SignalEOI();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void isr_pci4();
|
|
|
|
extern "C" void interrupt_pci4(InterruptFrame*) {
|
|
|
|
dbgln("Interrupt PCI line 4");
|
|
|
|
SignalEOI();
|
|
|
|
}
|
|
|
|
|
2023-05-17 22:54:37 -07:00
|
|
|
void InitIdt() {
|
|
|
|
gIdt[0] = CreateDescriptor(isr_divide_by_zero);
|
|
|
|
gIdt[13] = CreateDescriptor(isr_protection_fault);
|
2023-05-18 10:43:45 -07:00
|
|
|
gIdt[14] = CreateDescriptor(isr_page_fault);
|
2023-06-12 19:20:51 -07:00
|
|
|
|
|
|
|
gIdt[0x20] = CreateDescriptor(isr_timer);
|
|
|
|
|
|
|
|
gIdt[0x30] = CreateDescriptor(isr_pci1);
|
|
|
|
gIdt[0x31] = CreateDescriptor(isr_pci2);
|
|
|
|
gIdt[0x32] = CreateDescriptor(isr_pci3);
|
|
|
|
gIdt[0x33] = CreateDescriptor(isr_pci4);
|
|
|
|
|
2023-05-17 22:54:37 -07:00
|
|
|
InterruptDescriptorTablePointer idtp{
|
|
|
|
.size = sizeof(gIdt),
|
|
|
|
.base = reinterpret_cast<uint64_t>(gIdt),
|
|
|
|
};
|
|
|
|
asm volatile("lidt %0" ::"m"(idtp));
|
2023-05-29 21:52:01 -07:00
|
|
|
|
2023-06-07 13:40:36 -07:00
|
|
|
EnableApic();
|
2023-05-17 22:54:37 -07:00
|
|
|
}
|
2023-06-12 19:20:51 -07:00
|
|
|
|
2023-06-21 15:07:40 -07:00
|
|
|
void RegisterPciPort(const glcr::RefPtr<Port>& port) { pci1_port = port; }
|