Stage 0: trap-frame parity across all 3 arches (FABRIC-3.md §XXVIII)
Build / build-amd64-iso (push) Canceled after 0s
Build / build-aarch64-iso (push) Canceled after 0s
Build / build-riscv64-img (push) Canceled after 0s

First stage of the preemptive context-switching plan (see
~/.claude/plans/logical-snuggling-bear.md). Pure foundation work -- every
arch's ISR now saves the full register set on interrupt entry, so a trap
frame is in principle sufficient to resume execution anywhere it was
taken. No FORTH-visible behavior changes.

amd64: added FXSAVE/FXRSTOR, closing a genuine pre-existing correctness
gap (not just future-preemption prep) -- confirmed live double-precision
FP code reachable from ordinary interpreter dispatch (vm_runtime.c Loop
#5/#6), and the ISR previously saved zero FP/SSE state. rbp repurposed as
a fixed anchor so the 16-byte-aligned FXSAVE area can be carved out of an
unpredictably-aligned rsp without disturbing existing argument reads.

aarch64: extended the trap frame 672->800 bytes, adding v8-v15 (AAPCS64
callee-saved, previously excluded on call-site-only reasoning that
doesn't hold for an async trap).

riscv64: extended the trap frame 320->512 bytes, adding s0-s11 and
fs0-fs11 (the latter still correctly gated behind sstatus.FS != Off).

All 3 architectures re-verified clean boot to ok> under the new frames --
amd64 through hundreds of timer ticks with FXSAVE/FXRSTOR live on every
interrupt, aarch64 through 987 ticks, riscv64 clean on the now-larger
FS-conditional block.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016UNhH1mhi52i6Qihh7ZV5S
This commit is contained in:
Robert Allan James
2026-09-13 09:23:28 -04:00
co-authored by Claude Sonnet 5
parent 2a30212bd3
commit 15672ce17c
12 changed files with 27368 additions and 39 deletions
+35 -14
View File
@@ -148,7 +148,7 @@ aarch64_install_vectors:
/* ---------------------------------------------------------------------------
* irq_spx_trampoline — save / call C handler / restore / ERET.
*
* Frame layout (672 bytes, 16-byte aligned; SP is guaranteed 16-aligned at
* Frame layout (800 bytes, 16-byte aligned; SP is guaranteed 16-aligned at
* any point AAPCS64 code can be asynchronously interrupted, so no extra
* alignment handling is needed around the initial SUB):
*
@@ -160,11 +160,20 @@ aarch64_install_vectors:
* 272 FPCR
* 280 (8 bytes unused -- keeps the V-register block 16-aligned)
* 288..415 v0-v7 (4 STP Q-pairs) -- AAPCS64 caller-saved
* 416..671 v16-v31 (8 STP Q-pairs) -- AAPCS64 caller-saved
* 416..543 v8-v15 (4 STP Q-pairs) -- AAPCS64 callee-saved
* 544..799 v16-v31 (8 STP Q-pairs) -- AAPCS64 caller-saved
*
* v8-v15 are AAPCS64 callee-saved and are deliberately not here: the C
* handler below is ordinary compiled code and preserves those itself if it
* touches them, per the same ABI the save list is drawn from.
* FABRIC-3.md SXXVIII (Stage 0, preemptive-context-switch trap-frame parity,
* 2026-09-13): v8-v15 now saved too. They are AAPCS64 callee-saved, so
* ordinary compiled code (the C handler below, or anything else called
* through a normal ABI boundary) already preserves them across a *call* --
* but an interrupt is not a call the interrupted code's own compiled
* instructions know about. A value the interrupted function is genuinely
* live-using in v8-v15 at the moment of interrupt has no ABI guarantee of
* surviving an async trap at all; only a frame that saves everything makes
* "resume execution anywhere it was taken" actually true. This trap frame
* is not yet copied into any per-VM saved context (that's Stage 2) -- this
* stage only makes the frame itself complete.
* ------------------------------------------------------------------------- */
.equ TF_X0, 0
.equ TF_X2, 16
@@ -190,15 +199,19 @@ aarch64_install_vectors:
.equ TF_V2, 320
.equ TF_V4, 352
.equ TF_V6, 384
.equ TF_V16, 416
.equ TF_V18, 448
.equ TF_V20, 480
.equ TF_V22, 512
.equ TF_V24, 544
.equ TF_V26, 576
.equ TF_V28, 608
.equ TF_V30, 640
.equ TF_SIZE, 672
.equ TF_V8, 416
.equ TF_V10, 448
.equ TF_V12, 480
.equ TF_V14, 512
.equ TF_V16, 544
.equ TF_V18, 576
.equ TF_V20, 608
.equ TF_V22, 640
.equ TF_V24, 672
.equ TF_V26, 704
.equ TF_V28, 736
.equ TF_V30, 768
.equ TF_SIZE, 800
.balign 4
irq_spx_trampoline:
@@ -247,6 +260,10 @@ irq_spx_trampoline:
stp q2, q3, [sp, #TF_V2]
stp q4, q5, [sp, #TF_V4]
stp q6, q7, [sp, #TF_V6]
stp q8, q9, [sp, #TF_V8]
stp q10, q11, [sp, #TF_V10]
stp q12, q13, [sp, #TF_V12]
stp q14, q15, [sp, #TF_V14]
stp q16, q17, [sp, #TF_V16]
stp q18, q19, [sp, #TF_V18]
stp q20, q21, [sp, #TF_V20]
@@ -262,6 +279,10 @@ irq_spx_trampoline:
ldp q2, q3, [sp, #TF_V2]
ldp q4, q5, [sp, #TF_V4]
ldp q6, q7, [sp, #TF_V6]
ldp q8, q9, [sp, #TF_V8]
ldp q10, q11, [sp, #TF_V10]
ldp q12, q13, [sp, #TF_V12]
ldp q14, q15, [sp, #TF_V14]
ldp q16, q17, [sp, #TF_V16]
ldp q18, q19, [sp, #TF_V18]
ldp q20, q21, [sp, #TF_V20]