From 6cd130ec8e5b08225b9c190cf1f07ea4375321bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Wed, 17 Apr 2024 12:33:22 +0200 Subject: [PATCH] Kernel/riscv64: Increment sepc before re-enabling interrupts This otherwise caused a race condition between the signal dispatcher (which sets sepc to the signal trampoline) and sepc being updated in the trap handler. We obviously have to keep the sepc set by the signal dispatcher and not increment it afterwards. --- Kernel/Arch/riscv64/Interrupts.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Kernel/Arch/riscv64/Interrupts.cpp b/Kernel/Arch/riscv64/Interrupts.cpp index 96c25223034..eab69888f21 100644 --- a/Kernel/Arch/riscv64/Interrupts.cpp +++ b/Kernel/Arch/riscv64/Interrupts.cpp @@ -42,6 +42,11 @@ extern "C" void trap_handler(TrapFrame& trap_frame) { auto scause = trap_frame.regs->scause; + // sepc has to point to the instruction following the ecall when returning from a syscall, unless it is changed by the syscall handler. + // We have to increment sepc before interrupts are re-enabled, as code triggered by interrupts also can cause sepc to be updated. + if (scause == RISCV64::CSR::SCAUSE::EnvironmentCallFromUMode) + trap_frame.regs->sepc += 4; + if ((to_underlying(scause) & RISCV64::CSR::SCAUSE_INTERRUPT_MASK) != 0) { // Interrupt @@ -105,7 +110,6 @@ extern "C" void trap_handler(TrapFrame& trap_frame) } case EnvironmentCallFromUMode: - trap_frame.regs->sepc += 4; syscall_handler(&trap_frame); break;