riscv64: real trap entry with save/restore and SRET return
Punch list §25 item 0.2 complete. Verified: riscv64 builds clean and boots to the ok> prompt with no regression; dict_hash 0x3d4e1daf289da94f, unchanged from item 0.1's baseline. Disassembly confirms the 320-byte frame, all 16 integer caller-saved registers, the FS check, and SRET on exit; riscv64_trap_entry lands at 0x414fa8, 4-byte aligned as stvec direct mode requires. Not verified, and the item says so: neither new path was exercised. No timer is armed until 0.3, so riscv64_interrupt_handler never ran, and no exception occurred during boot, so the fatal path was not observed -- it is preserved structurally, same branch to the same unchanged handler. This is why C2 rewrote the acceptance to no-regression rather than to having taken and returned from a trap. Register set is the LP64D psABI caller-saved list, not this document's summary: integer ra/t0-t6/a0-a7 (16), FP ft0-ft11/fa0-fa7 (20) plus fcsr, and sepc + sstatus. Callee-saved registers are the C handler's responsibility. The FP half is conditional on sstatus.FS != Off, which the item did not anticipate. Nothing in boot.S or kernel_entry.S programs FS, so its value is whatever firmware leaves; touching an f-register with FS == Off raises an illegal-instruction trap, and doing that inside the trap handler would be unrecoverable. Omitting the FP save is not an option either -- the built riscv64 image contains 530 FP instructions (fld, fmul.d, fcvt.lu.d among them), confirming B2's finding against the binary rather than the build flags alone. So the save is conditional, and sstatus is restored after the f-registers. Dispatch: scause bit 63 routes to riscv64_interrupt_handler with scause in a0; cause 5 (supervisor timer) calls heartbeat_tick(). Other causes are ignored rather than fatal -- none are enabled to arrive. Everything else still falls through to riscv64_exception_handler, unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c3e4fc282c
commit
f3821ed686
@@ -11,11 +11,46 @@
|
||||
#include <stdint.h>
|
||||
#include "arch.h"
|
||||
#include "console.h"
|
||||
#include "starkernel/timer.h"
|
||||
|
||||
volatile const char *g_sk_fault_word = (void *)0;
|
||||
|
||||
extern void riscv64_install_vectors(void);
|
||||
|
||||
/* scause cause codes for supervisor-mode interrupts (RISC-V Privileged Spec
|
||||
* §4.1.9, Table "Supervisor cause register values"). Only the timer is used;
|
||||
* software (1) and external (9) interrupts are not enabled. */
|
||||
#define SCAUSE_INTERRUPT_BIT (1ULL << 63)
|
||||
#define SCAUSE_S_TIMER 5ULL
|
||||
|
||||
/**
|
||||
* @brief Dispatch an asynchronous supervisor interrupt.
|
||||
*
|
||||
* Called from @c riscv64_trap_entry in @c isr.S when @c scause has bit 63 set.
|
||||
* Unlike @c riscv64_exception_handler() this **returns** — the trap entry
|
||||
* restores the caller-saved register set and issues @c SRET.
|
||||
*
|
||||
* Supervisor timer (cause 5) is routed to @c heartbeat_tick(). No timer is
|
||||
* armed yet: arming via the SBI TIME extension, enabling @c sie.STIE, and the
|
||||
* mandatory per-tick re-arm are punch-list item 0.3. Until then this path is
|
||||
* unreachable, which is why item 0.2 accepts on "boots with no regression"
|
||||
* rather than on having observed an interrupt.
|
||||
*
|
||||
* Any other cause is ignored rather than fatal: an unexpected-but-harmless
|
||||
* asynchronous interrupt should not take the kernel down, and none are
|
||||
* currently enabled to arrive.
|
||||
*
|
||||
* @param scause Raw @c scause value, interrupt bit still set.
|
||||
*/
|
||||
void riscv64_interrupt_handler(uint64_t scause)
|
||||
{
|
||||
uint64_t cause = scause & ~SCAUSE_INTERRUPT_BIT;
|
||||
|
||||
if (cause == SCAUSE_S_TIMER) {
|
||||
heartbeat_tick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print a 64-bit value as "0xNNNNNNNNNNNNNNNN" to the kernel console.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user