diff --git a/Kernel/Arch/riscv64/MMU.cpp b/Kernel/Arch/riscv64/MMU.cpp index ba14d80f2c..8139f753e2 100644 --- a/Kernel/Arch/riscv64/MMU.cpp +++ b/Kernel/Arch/riscv64/MMU.cpp @@ -206,7 +206,8 @@ static UNMAP_AFTER_INIT void setup_kernel_page_directory(u64* root_table) " sd zero, (t0) \n" " sfence.vma \n" - // TODO: Set `stvec` to a trap handling function + " la t0, asm_trap_handler \n" + " csrw stvec, t0 \n" " li ra, 0 \n" " li fp, 0 \n" diff --git a/Kernel/Arch/riscv64/trap_handler.S b/Kernel/Arch/riscv64/trap_handler.S new file mode 100644 index 0000000000..edee17fb51 --- /dev/null +++ b/Kernel/Arch/riscv64/trap_handler.S @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +.section .text.asm_trap_handler + +#define REGISTER_STATE_SIZE (36 * 8) +#if REGISTER_STATE_SIZE % 16 != 0 +# error "REGISTER_STATE_SIZE is not a multiple of 16 bytes!" +#endif + +#define SSTATUS_SLOT (31 * 8) +#define SEPC_SLOT (32 * 8) +#define SCAUSE_SLOT (33 * 8) +#define STVAL_SLOT (34 * 8) +#define USERSPACE_SP_SLOT (35 * 8) + +.extern trap_handler + +.p2align 2 +.global asm_trap_handler +asm_trap_handler: + // FIXME: Handle traps from userspace + + // Save the current register state to the current stack + // and enter the C++ trap handler + + // Allocate stack space for trap frame + addi sp, sp, -REGISTER_STATE_SIZE + + sd x1, 0*8(sp) + sd x2, 1*8(sp) + sd x3, 2*8(sp) + sd x4, 3*8(sp) + sd x5, 4*8(sp) + sd x6, 5*8(sp) + sd x7, 6*8(sp) + sd x8, 7*8(sp) + sd x9, 8*8(sp) + sd x10, 9*8(sp) + sd x11, 10*8(sp) + sd x12, 11*8(sp) + sd x13, 12*8(sp) + sd x14, 13*8(sp) + sd x15, 14*8(sp) + sd x16, 15*8(sp) + sd x17, 16*8(sp) + sd x18, 17*8(sp) + sd x19, 18*8(sp) + sd x20, 19*8(sp) + sd x21, 20*8(sp) + sd x22, 21*8(sp) + sd x23, 22*8(sp) + sd x24, 23*8(sp) + sd x25, 24*8(sp) + sd x26, 25*8(sp) + sd x27, 26*8(sp) + sd x28, 27*8(sp) + sd x29, 28*8(sp) + sd x30, 29*8(sp) + sd x31, 30*8(sp) + + // Let's save some special registers + csrr t0, sstatus + sd t0, SSTATUS_SLOT(sp) + csrr t0, sepc + sd t0, SEPC_SLOT(sp) + + // We also have to save those registers as interrupts are enabled during the page fault handling code. + // A page fault exception may be reported as an interrupt in the register dump, if we wouldn't do that. + csrr t0, scause + sd t0, SCAUSE_SLOT(sp) + csrr t0, stval + sd t0, STVAL_SLOT(sp) + + // TODO + sd zero, USERSPACE_SP_SLOT(sp) + + // Set up TrapFrame struct on the stack + mv t0, sp + addi sp, sp, -16 + sd t0, 1*8(sp) + sd zero, 0*8(sp) + + // Move stack pointer into first argument register + // and jump to the C++ trap handler + mv a0, sp + + call trap_handler + + // Remove TrapFrame from the stack + addi sp, sp, 16 + + // Restore special registers first + ld t0, SSTATUS_SLOT(sp) + csrw sstatus, t0 + ld t0, SEPC_SLOT(sp) + csrw sepc, t0 + + ld x1, 0*8(sp) + // sp + ld x3, 2*8(sp) + ld x4, 3*8(sp) + ld x5, 4*8(sp) + ld x6, 5*8(sp) + ld x7, 6*8(sp) + ld x8, 7*8(sp) + ld x9, 8*8(sp) + ld x10, 9*8(sp) + ld x11, 10*8(sp) + ld x12, 11*8(sp) + ld x13, 12*8(sp) + ld x14, 13*8(sp) + ld x15, 14*8(sp) + ld x16, 15*8(sp) + ld x17, 16*8(sp) + ld x18, 17*8(sp) + ld x19, 18*8(sp) + ld x20, 19*8(sp) + ld x21, 20*8(sp) + ld x22, 21*8(sp) + ld x23, 22*8(sp) + ld x24, 23*8(sp) + ld x25, 24*8(sp) + ld x26, 25*8(sp) + ld x27, 26*8(sp) + ld x28, 27*8(sp) + ld x29, 28*8(sp) + ld x30, 29*8(sp) + ld x31, 30*8(sp) + + ld x2, 1*8(sp) + + addi sp, sp, REGISTER_STATE_SIZE + sret diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index bfc2c7660f..c90d9ede16 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -545,6 +545,7 @@ elseif("${SERENITY_ARCH}" STREQUAL "riscv64") Arch/riscv64/SBI.cpp Arch/riscv64/SmapDisabler.cpp Arch/riscv64/Timer.cpp + Arch/riscv64/trap_handler.S ) # NOTE: These files cannot use a stack protector and sanitizers, as these will cause accesses to global variables to be inserted