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
@@ -2019,7 +2019,7 @@ on until there is a tick on all three architectures (§16.1, §16.5).*
|
||||
Artemis in the banner, and the three logs exist under `logs/`.
|
||||
*Refs:* the surviving blocks are 2057, 2049, 2050. `mkcapsule --lint` before building.
|
||||
|
||||
- [ ] **0.2 — riscv64: real trap entry.**
|
||||
- [x] **0.2 — riscv64: real trap entry.**
|
||||
Replace the one-way `riscv64_trap_entry` in `arch/riscv64/isr.S` with save / dispatch /
|
||||
restore / `sret`. Route `scause` bit 63 + cause 5 to the timer path; everything else keeps
|
||||
falling through to the existing fatal handler.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-03T16:45:12Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-03T16:51:19Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_executions_delta,hot_word_count,avg_word_heat_q48,window_width,actual_window_size,predicted_label_hits,jitter_bits,apic_ticks,time_trust_q48,variance_q48,vm_call_depth_max,hera_heat_q48,hermes_heat_q48,artemis_heat_q48
|
||||
1,10000,10000,0,0,183,4,45,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
2,20000,10000,0,0,173,5,44,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
3,30000,10000,0,0,184,6,60,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
4,40000,10000,0,0,174,8,71,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
5,50000,10000,0,0,150,9,78,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
6,60000,10000,0,0,159,11,73,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
7,70000,10000,0,0,188,15,71,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
8,80000,10000,0,0,214,16,83,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
9,90000,10000,0,0,216,19,82,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
10,100000,10000,0,0,222,21,84,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
11,110000,10000,0,0,207,23,86,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
12,120000,10000,0,0,189,26,83,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
13,130000,10000,0,0,221,28,80,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
14,140000,10000,0,0,204,29,83,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
15,150000,10000,0,0,203,30,82,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
16,160000,10000,0,0,201,32,83,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
17,170000,10000,0,0,190,34,86,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
18,180000,10000,0,0,170,35,73,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
19,190000,10000,0,0,154,28,44,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
20,200000,10000,0,0,154,28,41,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
21,210000,10000,0,0,153,32,39,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
22,220000,10000,0,0,167,35,42,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
23,230000,10000,0,0,176,37,41,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
24,240000,10000,0,0,175,37,39,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
25,250000,10000,0,0,196,38,37,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
26,260000,10000,0,0,192,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
27,270000,10000,0,0,158,40,38,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
28,280000,10000,0,0,158,40,35,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
29,290000,10000,0,0,164,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
30,300000,10000,0,0,154,43,39,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
31,310000,10000,0,0,172,46,35,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
32,320000,10000,0,0,180,49,34,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
33,330000,10000,0,0,145,51,35,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
34,340000,10000,0,0,203,53,37,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
35,350000,10000,0,0,154,55,39,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
36,360000,10000,0,0,144,57,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
37,370000,10000,0,0,144,57,35,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
38,380000,10000,0,0,132,57,34,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
39,390000,10000,0,0,180,57,32,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
40,400000,10000,0,0,220,63,29,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
41,410000,10000,0,0,215,64,28,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||
42,420000,10000,0,0,208,68,29,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||
43,430000,10000,0,0,177,72,27,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||
44,440000,10000,0,0,199,77,28,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||
45,450000,10000,0,0,223,82,26,4096,30,0,0,0,65536,0,0,65536,0,0
|
||||
46,460000,10000,0,0,202,85,24,4096,67,0,0,0,65536,0,0,65536,0,0
|
||||
47,470000,10000,0,0,218,91,25,4096,198,0,0,0,65536,0,0,65536,0,0
|
||||
48,480000,10000,0,0,221,92,26,4096,350,0,0,0,65536,0,0,65536,0,0
|
||||
49,490000,10000,0,0,225,97,26,4096,528,0,0,0,65536,0,0,65536,0,0
|
||||
50,500000,10000,0,0,214,100,27,4096,694,0,0,0,65536,0,0,65536,0,0
|
||||
51,510000,10000,0,0,227,102,28,4096,883,0,0,0,65536,0,0,65536,0,0
|
||||
52,520000,10000,0,0,208,102,29,4096,1043,0,0,0,65536,0,0,65536,0,0
|
||||
53,530000,10000,0,0,207,102,30,4096,1202,0,0,0,65536,0,0,65536,0,0
|
||||
54,540000,10000,0,0,200,102,31,4096,1319,0,0,0,65536,0,0,65536,0,0
|
||||
55,550000,10000,0,0,205,103,32,4096,1464,0,0,0,65536,0,0,65536,0,0
|
||||
56,560000,10000,0,0,211,103,32,4096,1620,0,0,0,65536,0,0,65536,0,0
|
||||
57,570000,10000,0,0,193,110,33,4096,1712,0,0,0,65536,0,0,65536,0,0
|
||||
58,580000,10000,0,0,190,5,67,4096,1775,0,0,0,65536,0,0,65536,0,0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
*
|
||||
|
||||
@@ -15,13 +15,176 @@
|
||||
.hidden riscv64_trap_entry
|
||||
.hidden riscv64_install_vectors
|
||||
|
||||
/* Direct-mode trap entry: stvec[1:0] = 0 means all traps branch here */
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Trap frame layout (offsets from sp), 320 bytes, 16-byte aligned.
|
||||
*
|
||||
* Only the LP64D psABI's *caller-saved* registers are saved: a C handler
|
||||
* preserves callee-saved registers itself, and the interrupted code already
|
||||
* expects caller-saved registers to be clobbered across a call.
|
||||
*
|
||||
* integer caller-saved (16): ra, t0-t6, a0-a7
|
||||
* FP caller-saved (20): ft0-ft11, fa0-fa7 + fcsr
|
||||
* supervisor CSRs (2): sepc, sstatus
|
||||
*
|
||||
* The FP half is saved only when sstatus.FS != Off. Nothing in boot.S or
|
||||
* kernel_entry.S programs FS, so its state is whatever firmware left; touching
|
||||
* an f-register while FS == Off raises an illegal-instruction trap, which
|
||||
* inside the trap handler would be unrecoverable. The kernel image does
|
||||
* contain real FP code (fld/fmul.d/fcvt on the Q48.16 and statistics paths),
|
||||
* so the save cannot simply be omitted -- it has to be conditional.
|
||||
* ------------------------------------------------------------------------- */
|
||||
.equ TF_RA, 0
|
||||
.equ TF_T0, 8
|
||||
.equ TF_T1, 16
|
||||
.equ TF_T2, 24
|
||||
.equ TF_T3, 32
|
||||
.equ TF_T4, 40
|
||||
.equ TF_T5, 48
|
||||
.equ TF_T6, 56
|
||||
.equ TF_A0, 64
|
||||
.equ TF_A1, 72
|
||||
.equ TF_A2, 80
|
||||
.equ TF_A3, 88
|
||||
.equ TF_A4, 96
|
||||
.equ TF_A5, 104
|
||||
.equ TF_A6, 112
|
||||
.equ TF_A7, 120
|
||||
.equ TF_SEPC, 128
|
||||
.equ TF_SSTATUS,136
|
||||
.equ TF_FCSR, 144
|
||||
.equ TF_F0, 152 /* ft0-ft7 : 152 .. 208 */
|
||||
.equ TF_FA0, 216 /* fa0-fa7 : 216 .. 272 */
|
||||
.equ TF_FT8, 280 /* ft8-ft11 : 280 .. 304 */
|
||||
.equ TF_SIZE, 320
|
||||
|
||||
/* sstatus.FS occupies bits [14:13]; 0 = Off */
|
||||
.equ SSTATUS_FS_SHIFT, 13
|
||||
.equ SSTATUS_FS_MASK, 3
|
||||
|
||||
/* Direct-mode trap entry: stvec[1:0] = 0 means all traps branch here.
|
||||
* stvec requires 4-byte alignment. */
|
||||
.balign 4
|
||||
.global riscv64_trap_entry
|
||||
riscv64_trap_entry:
|
||||
call riscv64_exception_handler
|
||||
/* Should not return; if it does, spin */
|
||||
1: wfi
|
||||
j 1b
|
||||
addi sp, sp, -TF_SIZE
|
||||
|
||||
sd ra, TF_RA(sp)
|
||||
sd t0, TF_T0(sp)
|
||||
sd t1, TF_T1(sp)
|
||||
sd t2, TF_T2(sp)
|
||||
sd t3, TF_T3(sp)
|
||||
sd t4, TF_T4(sp)
|
||||
sd t5, TF_T5(sp)
|
||||
sd t6, TF_T6(sp)
|
||||
sd a0, TF_A0(sp)
|
||||
sd a1, TF_A1(sp)
|
||||
sd a2, TF_A2(sp)
|
||||
sd a3, TF_A3(sp)
|
||||
sd a4, TF_A4(sp)
|
||||
sd a5, TF_A5(sp)
|
||||
sd a6, TF_A6(sp)
|
||||
sd a7, TF_A7(sp)
|
||||
|
||||
csrr t0, sepc
|
||||
sd t0, TF_SEPC(sp)
|
||||
csrr t0, sstatus
|
||||
sd t0, TF_SSTATUS(sp)
|
||||
|
||||
/* Save FP only if FS != Off */
|
||||
srli t1, t0, SSTATUS_FS_SHIFT
|
||||
andi t1, t1, SSTATUS_FS_MASK
|
||||
beqz t1, 1f
|
||||
|
||||
frcsr t2
|
||||
sd t2, TF_FCSR(sp)
|
||||
fsd ft0, TF_F0+0(sp)
|
||||
fsd ft1, TF_F0+8(sp)
|
||||
fsd ft2, TF_F0+16(sp)
|
||||
fsd ft3, TF_F0+24(sp)
|
||||
fsd ft4, TF_F0+32(sp)
|
||||
fsd ft5, TF_F0+40(sp)
|
||||
fsd ft6, TF_F0+48(sp)
|
||||
fsd ft7, TF_F0+56(sp)
|
||||
fsd fa0, TF_FA0+0(sp)
|
||||
fsd fa1, TF_FA0+8(sp)
|
||||
fsd fa2, TF_FA0+16(sp)
|
||||
fsd fa3, TF_FA0+24(sp)
|
||||
fsd fa4, TF_FA0+32(sp)
|
||||
fsd fa5, TF_FA0+40(sp)
|
||||
fsd fa6, TF_FA0+48(sp)
|
||||
fsd fa7, TF_FA0+56(sp)
|
||||
fsd ft8, TF_FT8+0(sp)
|
||||
fsd ft9, TF_FT8+8(sp)
|
||||
fsd ft10, TF_FT8+16(sp)
|
||||
fsd ft11, TF_FT8+24(sp)
|
||||
1:
|
||||
|
||||
/* scause bit 63 set => interrupt (negative when read as signed). */
|
||||
csrr a0, scause
|
||||
bltz a0, 2f
|
||||
|
||||
/* Synchronous exception: fatal, does not return. */
|
||||
call riscv64_exception_handler
|
||||
9: wfi
|
||||
j 9b
|
||||
|
||||
2: /* Interrupt: a0 already holds scause for the C dispatcher. */
|
||||
call riscv64_interrupt_handler
|
||||
|
||||
/* Restore. Reload the saved sstatus first -- it decides whether the FP
|
||||
* half was written, and it must be restored *after* the f-registers so
|
||||
* that FS is back to the interrupted context's value on exit. */
|
||||
ld t0, TF_SSTATUS(sp)
|
||||
srli t1, t0, SSTATUS_FS_SHIFT
|
||||
andi t1, t1, SSTATUS_FS_MASK
|
||||
beqz t1, 3f
|
||||
|
||||
ld t2, TF_FCSR(sp)
|
||||
fscsr t2
|
||||
fld ft0, TF_F0+0(sp)
|
||||
fld ft1, TF_F0+8(sp)
|
||||
fld ft2, TF_F0+16(sp)
|
||||
fld ft3, TF_F0+24(sp)
|
||||
fld ft4, TF_F0+32(sp)
|
||||
fld ft5, TF_F0+40(sp)
|
||||
fld ft6, TF_F0+48(sp)
|
||||
fld ft7, TF_F0+56(sp)
|
||||
fld fa0, TF_FA0+0(sp)
|
||||
fld fa1, TF_FA0+8(sp)
|
||||
fld fa2, TF_FA0+16(sp)
|
||||
fld fa3, TF_FA0+24(sp)
|
||||
fld fa4, TF_FA0+32(sp)
|
||||
fld fa5, TF_FA0+40(sp)
|
||||
fld fa6, TF_FA0+48(sp)
|
||||
fld fa7, TF_FA0+56(sp)
|
||||
fld ft8, TF_FT8+0(sp)
|
||||
fld ft9, TF_FT8+8(sp)
|
||||
fld ft10, TF_FT8+16(sp)
|
||||
fld ft11, TF_FT8+24(sp)
|
||||
3:
|
||||
csrw sstatus, t0
|
||||
ld t0, TF_SEPC(sp)
|
||||
csrw sepc, t0
|
||||
|
||||
ld ra, TF_RA(sp)
|
||||
ld t0, TF_T0(sp)
|
||||
ld t1, TF_T1(sp)
|
||||
ld t2, TF_T2(sp)
|
||||
ld t3, TF_T3(sp)
|
||||
ld t4, TF_T4(sp)
|
||||
ld t5, TF_T5(sp)
|
||||
ld t6, TF_T6(sp)
|
||||
ld a0, TF_A0(sp)
|
||||
ld a1, TF_A1(sp)
|
||||
ld a2, TF_A2(sp)
|
||||
ld a3, TF_A3(sp)
|
||||
ld a4, TF_A4(sp)
|
||||
ld a5, TF_A5(sp)
|
||||
ld a6, TF_A6(sp)
|
||||
ld a7, TF_A7(sp)
|
||||
|
||||
addi sp, sp, TF_SIZE
|
||||
sret
|
||||
|
||||
.global riscv64_install_vectors
|
||||
riscv64_install_vectors:
|
||||
|
||||
Reference in New Issue
Block a user