diff --git a/Kernel/Arch/riscv64/Interrupts.cpp b/Kernel/Arch/riscv64/Interrupts.cpp index 34bf141d02..00f4344e0a 100644 --- a/Kernel/Arch/riscv64/Interrupts.cpp +++ b/Kernel/Arch/riscv64/Interrupts.cpp @@ -7,9 +7,12 @@ #include #include +#include #include #include +#include #include +#include #include #include #include @@ -32,6 +35,90 @@ void dump_registers(RegisterState const& regs) dbgln("s1={:p} s2={:p} s3={:p} s4={:p} s5={:p} s6={:p} s7={:p} s8={:p} s9={:p} s10={:p} s11={:p}", regs.x[8], regs.x[17], regs.x[18], regs.x[19], regs.x[20], regs.x[21], regs.x[22], regs.x[23], regs.x[24], regs.x[25], regs.x[26]); } +extern "C" void trap_handler(TrapFrame& trap_frame); +extern "C" void trap_handler(TrapFrame& trap_frame) +{ + auto scause = trap_frame.regs->scause; + + if ((to_underlying(scause) & RISCV64::CSR::SCAUSE_INTERRUPT_MASK) != 0) { + // Interrupt + + Processor::current().enter_trap(trap_frame, true); + + auto interrupt_number = to_underlying(scause) & ~RISCV64::CSR::SCAUSE_INTERRUPT_MASK; + + auto* handler = s_interrupt_handlers[interrupt_number]; + VERIFY(handler); + handler->increment_call_count(); + handler->handle_interrupt(*trap_frame.regs); + handler->eoi(); + + Processor::current().exit_trap(trap_frame); + } else { + // Exception + + Processor::current().enter_trap(trap_frame, false); + Processor::enable_interrupts(); + + using enum RISCV64::CSR::SCAUSE; + switch (scause) { + case InstructionAddressMisaligned: + case LoadAddressMisaligned: + case StoreOrAMOAddressMisaligned: + handle_crash(*trap_frame.regs, "Unaligned memory access", SIGBUS, false); + break; + + case InstructionAccessFault: + case LoadAccessFault: + case StoreOrAMOAccessFault: + handle_crash(*trap_frame.regs, "Memory access fault", SIGBUS, false); + break; + + case IllegalInstrction: + handle_crash(*trap_frame.regs, "Illegal instruction", SIGILL, false); + break; + + case InstructionPageFault: + case LoadPageFault: + case StoreOrAMOPageFault: { + // The privileged ISA theoretically allows stval to always be zero (in which case we would report a page fault in the zero page). + // But all implementations capable of running general purpose operating systems should probably set this CSR, + // as otherwise you can't handle page faults. + // We simply require that Sstvala (see RISC-V Profiles) is supported, which means stval is always set to the faulting address on a page fault. + PageFault fault { VirtualAddress(trap_frame.regs->stval) }; + + if (scause == InstructionPageFault) + fault.set_instruction_fetch(true); + else if (scause == LoadPageFault) + fault.set_access(PageFault::Access::Read); + else if (scause == StoreOrAMOPageFault) + fault.set_access(PageFault::Access::Write); + + // FIXME: RISC-V doesn't tell you *why* a memory access failed, only the original access type (r/w/x). + // So either detect the correct type by walking the page table or rewrite MM to not depend on the processor-provided reason. + fault.set_type(PageFault::Type::ProtectionViolation); + + fault.handle(*trap_frame.regs); + break; + } + + case EnvironmentCallFromUMode: + TODO_RISCV64(); + break; + + case Breakpoint: + TODO_RISCV64(); + break; + + default: + VERIFY_NOT_REACHED(); + }; + + Processor::disable_interrupts(); + Processor::current().exit_trap(trap_frame); + } +} + // FIXME: Share the code below with Arch/x86_64/Interrupts.cpp // While refactoring, the interrupt handlers can also be moved into the InterruptManagement class. GenericInterruptHandler& get_interrupt_handler(u8)