Files
LithosAnanke/kernel/src/arch/aarch64/switch.S
T
Claude 3bd81097e1 chore(license): an SPDX header on every source file that had none (LicenseRef-Starship-1.0) [skip ci]
The header scan (Captain Bob, 2026-11-10): 788 source files -- 351 with the
SL-1.0 header, 12 with the old name (docs/working/experiments, kept by
ruling), 31 under someone else's licence (tools/kconfig, Linux's, GPL-2.0:
kept), and 394 with none. Ruled: the SPDX form; capsules (.4th, .f18) and
proofs (.thy) left for a ruling of their own (mkcapsule's 64x16 block format,
content-addressed capsules).

253 files now begin
    SPDX-License-Identifier: LicenseRef-Starship-1.0
    Copyright (c) 2023-2026 Robert A. James
as a /* */ block (C, headers, assembly, linker scripts) or # lines (scripts,
Makefiles, Kconfig; below a shebang or a coding line); tools/mkcapsule.c,
which had the copyright line, gets the SPDX line only.

Not touched: docs/working/ (archive and old campaign material, as the
ruling kept the experiments); v4/system/post_cases.c (generated by
v4/tools/mkpost.py, "do not edit" -- the generator has the header).

Comments only: the kernel builds on amd64, aarch64, riscv64; make -C v4
test-32: 39 programs, 0 failures; every changed script parses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
2026-11-10 04:12:49 +00:00

109 lines
3.4 KiB
ArmAsm

/* SPDX-License-Identifier: LicenseRef-Starship-1.0
* Copyright (c) 2023-2026 Robert A. James
*/
/*
* switch.S (aarch64) - Cooperative VM context switch primitive.
*
* FABRIC-3.md §XXVIII (Stage 2, preemptive-context-switch save/restore
* primitive, 2026-09-13). Deliberately NOT isr.S's interrupt trap frame
* (Stage 0) -- that saves everything because an interrupt has no call
* site. sk_vm_switch_to() is an ordinary `bl`, so AAPCS64 already makes
* every caller-saved register (x0-x18, v0-v7, v16-v31) the caller's own
* problem across the call. Only the callee-saved set needs explicit
* handling: x19-x28, x29 (fp), x30 (lr), and d8-d15 (only the low 64
* bits of v8-v15 are callee-saved per AAPCS64).
*
* void sk_vm_switch_to(uint64_t *save_sp_out, uint64_t new_sp);
* x0 = save_sp_out, x1 = new_sp
*
* For a VM that has never run before, new_sp must point at a synthetic
* 160-byte frame built by the C glue (switch.c) to this exact layout,
* with x30 (lr) set to the trampoline entry address and everything else
* zeroed, so the final `ret` below (which branches to lr) jumps there.
*/
.section .text
.balign 4
.equ SW_X19, 0
.equ SW_X21, 16
.equ SW_X23, 32
.equ SW_X25, 48
.equ SW_X27, 64
.equ SW_X29, 80 /* x29 (fp), x30 (lr) */
.equ SW_D8, 96
.equ SW_D10, 112
.equ SW_D12, 128
.equ SW_D14, 144
.equ SW_SIZE, 160
/* .hidden is an ELF-only visibility directive with no COFF equivalent;
* this file is also assembled for the aarch64 loader, which clang targets
* at aarch64-pc-windows-msvc (PE/COFF) -- guard on _WIN32 (defined only by
* that target), matching isr.S's own precedent exactly. */
#ifndef _WIN32
.hidden sk_vm_switch_to
#endif
.global sk_vm_switch_to
sk_vm_switch_to:
sub sp, sp, #SW_SIZE
stp x19, x20, [sp, #SW_X19]
stp x21, x22, [sp, #SW_X21]
stp x23, x24, [sp, #SW_X23]
stp x25, x26, [sp, #SW_X25]
stp x27, x28, [sp, #SW_X27]
stp x29, x30, [sp, #SW_X29]
stp d8, d9, [sp, #SW_D8]
stp d10, d11, [sp, #SW_D10]
stp d12, d13, [sp, #SW_D12]
stp d14, d15, [sp, #SW_D14]
mov x2, sp
str x2, [x0] /* *save_sp_out = sp (this context's parked SP) */
mov sp, x1 /* sp = new_sp (switch stacks) */
ldp x19, x20, [sp, #SW_X19]
ldp x21, x22, [sp, #SW_X21]
ldp x23, x24, [sp, #SW_X23]
ldp x25, x26, [sp, #SW_X25]
ldp x27, x28, [sp, #SW_X27]
ldp x29, x30, [sp, #SW_X29]
ldp d8, d9, [sp, #SW_D8]
ldp d10, d11, [sp, #SW_D10]
ldp d12, d13, [sp, #SW_D12]
ldp d14, d15, [sp, #SW_D14]
add sp, sp, #SW_SIZE
ret
/*
* uint64_t sk_vm_switch_prime(uint64_t stack_top, void *entry);
*
* Builds the synthetic frame above at the top of a fresh native stack, so
* the first ever sk_vm_switch_to() into it lands at `entry` (x30/lr) via
* its final `ret`. Kept in this file (not C) so the layout can never
* drift from sk_vm_switch_to() above -- one set of offsets, not two.
*/
#ifndef _WIN32
.hidden sk_vm_switch_prime
#endif
.global sk_vm_switch_prime
sk_vm_switch_prime:
sub x2, x0, #SW_SIZE
stp xzr, xzr, [x2, #SW_X19]
stp xzr, xzr, [x2, #SW_X21]
stp xzr, xzr, [x2, #SW_X23]
stp xzr, xzr, [x2, #SW_X25]
stp xzr, xzr, [x2, #SW_X27]
stp xzr, x1, [x2, #SW_X29] /* x29=0, x30(lr)=entry */
stp xzr, xzr, [x2, #SW_D8]
stp xzr, xzr, [x2, #SW_D10]
stp xzr, xzr, [x2, #SW_D12]
stp xzr, xzr, [x2, #SW_D14]
mov x0, x2
ret