Kernel: Rework interrupt mechanism

All interruptrable classes now inherit from Interruptable which
has methdo handle_irq which is called on a interrupt.
This commit is contained in:
2023-10-05 18:53:45 +03:00
parent 68a913c838
commit 27eb5af6f0
23 changed files with 716 additions and 706 deletions

View File

@@ -13,7 +13,7 @@
#define REGISTER_ISR_HANDLER(i) register_interrupt_handler(i, isr ## i)
#define REGISTER_IRQ_HANDLER(i) register_interrupt_handler(IRQ_VECTOR_BASE + i, irq ## i)
namespace IDT
namespace Kernel::IDT
{
struct Registers
@@ -63,7 +63,7 @@ namespace IDT
static IDTR s_idtr;
static GateDescriptor* s_idt = nullptr;
static void(*s_irq_handlers[0x10])() { nullptr };
static Interruptable* s_interruptables[0x10] {};
enum ISR
{
@@ -160,53 +160,62 @@ namespace IDT
"Unkown Exception 0x1F",
};
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, Kernel::InterruptStack& interrupt_stack, const Registers* regs)
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs)
{
#if __enable_sse
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
if (from_userspace)
Kernel::Thread::current().save_sse();
Thread::current().save_sse();
#endif
pid_t tid = Kernel::Scheduler::current_tid();
pid_t pid = tid ? Kernel::Process::current().pid() : 0;
pid_t tid = Scheduler::current_tid();
pid_t pid = tid ? Process::current().pid() : 0;
if (pid && isr == ISR::PageFault)
if (tid)
{
PageFaultError page_fault_error;
page_fault_error.raw = error;
Thread::current().set_return_rsp(interrupt_stack.rsp);
Thread::current().set_return_rip(interrupt_stack.rip);
// Try demand paging on non present pages
if (!page_fault_error.present)
if (isr == ISR::PageFault)
{
asm volatile("sti");
auto result = Kernel::Process::current().allocate_page_for_demand_paging(regs->cr2);
asm volatile("cli");
if (!result.is_error() && result.value())
return;
if (result.is_error())
// Check if stack is OOB
auto& stack = Thread::current().stack();
if (interrupt_stack.rsp < stack.vaddr())
{
dwarnln("Demand paging: {}", result.error());
Kernel::Thread::current().handle_signal(SIGTERM);
derrorln("Stack overflow");
goto done;
}
if (interrupt_stack.rsp >= stack.vaddr() + stack.size())
{
derrorln("Stack underflow");
goto done;
}
// Try demand paging on non present pages
PageFaultError page_fault_error;
page_fault_error.raw = error;
if (!page_fault_error.present)
{
asm volatile("sti");
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2);
asm volatile("cli");
if (!result.is_error() && result.value())
goto done;
if (result.is_error())
{
dwarnln("Demand paging: {}", result.error());
Thread::current().handle_signal(SIGTERM);
goto done;
}
}
}
}
if (tid)
if (PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
{
auto start = Kernel::Thread::current().stack_base();
auto end = start + Kernel::Thread::current().stack_size();
if (interrupt_stack.rsp < start)
derrorln("Stack overflow");
if (interrupt_stack.rsp >= end)
derrorln("Stack underflow");
}
if (Kernel::PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & Kernel::PageTable::Flags::Present)
{
uint8_t* machine_code = (uint8_t*)interrupt_stack.rip;
auto* machine_code = (const uint8_t*)interrupt_stack.rip;
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
machine_code[0],
machine_code[1],
@@ -233,16 +242,10 @@ namespace IDT
regs->cr0, regs->cr2, regs->cr3, regs->cr4
);
if (isr == ISR::PageFault)
Kernel::PageTable::current().debug_dump();
PageTable::current().debug_dump();
Debug::dump_stack_trace();
if (tid)
{
Kernel::Thread::current().set_return_rsp(interrupt_stack.rsp);
Kernel::Thread::current().set_return_rip(interrupt_stack.rip);
}
if (tid && Kernel::Thread::current().is_userspace())
if (tid && Thread::current().is_userspace())
{
// TODO: Confirm and fix the exception to signal mappings
@@ -270,36 +273,38 @@ namespace IDT
break;
}
Kernel::Thread::current().handle_signal(signal);
Thread::current().handle_signal(signal);
}
else
{
Kernel::panic("Unhandled exception");
panic("Unhandled exception");
}
ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminated);
ASSERT(Thread::current().state() != Thread::State::Terminated);
done:
#if __enable_sse
if (from_userspace)
{
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
Kernel::Thread::current().load_sse();
ASSERT(Thread::current().state() == Thread::State::Executing);
Thread::current().load_sse();
}
#endif
return;
}
extern "C" void cpp_irq_handler(uint64_t irq, Kernel::InterruptStack& interrupt_stack)
extern "C" void cpp_irq_handler(uint64_t irq, InterruptStack& interrupt_stack)
{
#if __enable_sse
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
if (from_userspace)
Kernel::Thread::current().save_sse();
Thread::current().save_sse();
#endif
if (Kernel::Scheduler::current_tid())
if (Scheduler::current_tid())
{
Kernel::Thread::current().set_return_rsp(interrupt_stack.rsp);
Kernel::Thread::current().set_return_rip(interrupt_stack.rip);
Thread::current().set_return_rsp(interrupt_stack.rsp);
Thread::current().set_return_rip(interrupt_stack.rip);
}
if (!InterruptController::get().is_in_service(irq))
@@ -307,21 +312,21 @@ namespace IDT
else
{
InterruptController::get().eoi(irq);
if (s_irq_handlers[irq])
s_irq_handlers[irq]();
if (s_interruptables[irq])
s_interruptables[irq]->handle_irq();
else
dprintln("no handler for irq 0x{2H}\n", irq);
}
Kernel::Scheduler::get().reschedule_if_idling();
Scheduler::get().reschedule_if_idling();
ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminated);
ASSERT(Thread::current().state() != Thread::State::Terminated);
#if __enable_sse
if (from_userspace)
{
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
Kernel::Thread::current().load_sse();
ASSERT(Thread::current().state() == Thread::State::Executing);
Thread::current().load_sse();
}
#endif
}
@@ -349,9 +354,9 @@ namespace IDT
s_idt[index].flags = 0xEE;
}
void register_irq_handler(uint8_t irq, void(*handler)())
void register_irq_handler(uint8_t irq, Interruptable* interruptable)
{
s_irq_handlers[irq] = handler;
s_interruptables[irq] = interruptable;
}
extern "C" void isr0();
@@ -480,4 +485,4 @@ namespace IDT
ASSERT_NOT_REACHED();
}
}
}