From 2dfa12365d7bda07398697c2eee2bbc56a24e1e5 Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 09:00:54 +0200 Subject: [PATCH 1/6] Tracks: Linux parity is the floor; the T14's own features, for security and for speed The owner reset the security bar: parity with the pinned Ubuntu kernel is the floor, and the T14 also gets every security feature its CPU and platform support. The ruling that deleted kernel IBT ("every hardening default the config sets, and no more") is reversed. issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md: - The parity sentence is replaced by the floor. Table rows: user shadow stacks go to S11; X86_KERNEL_IBT (config line 496, unset) to S12; X86_INTEL_MEMORY_PROTECTION_KEYS (497), which the config sets and the table missed, to S14. - S11 user shadow stacks (promoted from the defect, which is deleted: only the table cited it), S12 kernel IBT, S13 kernel shadow stack, S14 user protection keys, S15 Key Locker, S16 TME read back, S17 split-lock disable. Each names its first step (the CPUID bit in S0's capture, since Intel documents these for the Tiger Lake family and not for the i5-1135G7), its mutation and its oracle. - S0 captures the leaves and MSRs the new stages read: CPUID 5, (7,1), (0xD,0), (0xD,1), 0x19, 0x80000001, MSRs 0x982 and 0xCF, and Linux's TME and split-lock lines. The Ubuntu wipe also waits on the speed track's P0. - LASS and LAM are not Tiger Lake's: SDM 325462-093US Vol. 1 Table 5-2 introduces both with Sierra Forest, Atom P6900 and Core Ultra 200H; PKS with Alder Lake. They are in the new hardware file. issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md (new): P0 Linux baseline from one Rust program; P1 XSAVE and AVX/AVX2/AVX-512 in user programs (CR4.OSXSAVE is clear today, so cpufeatures never selects an AVX path); P2 kernel copies with rep movsb (compiler-builtins uses it only under +ermsb); P3 1 GiB direct-map leaves; P4 shootdowns only to CPUs that ran the space; P5 FSGSBASE measured against the swapgs cost, taken or rejected; P6 deep idle (Linux takes the T14's MWAIT hints from _CST); P7 NVMe APST and HMB. HWP, PGE, interrupt spreading, placement, 4 KiB pages, userland NVMe and the stick's link speed are cited to the issues that own them. issues/hardware/newer-hardware-offers-what-the-t14-lacks.md (new): FRED/LKGS, LASS, LAM, PKS, UINTR, WAITPKG, fast short string ops, AMX, AVX10, APX, Thread Director, TDX, TSE, AMD INVLPGB, SEV-SNP and shadow stack, Arm MTE, PAC, BTI, GCS, POE and SME, each with the hardware and why it matters. Intel parts from SDM Table 5-2 or ISE 319433-062 Table 1-2; AMD and Arm from Linux v7.2, with the AMD parts and Arm cores marked unverified. Sources read: SDM 325462-093US, ISE 319433-062, datasheet 631121-012 rev 012, Key Locker spec 343965-001US, Linux Ubuntu-6.8.0-142.142 (53e5d07a) and v7.2, QEMU v11.1.1 target/i386/cpu.c, and the config from linux-modules-6.8.0-142-generic (sha256 3b8533dd...5890, re-measured). Co-Authored-By: Claude Opus 5.5 --- ...ewer-hardware-offers-what-the-t14-lacks.md | 45 +++++ ...tigates-what-linux-mitigates-on-the-t14.md | 171 ++++++++++++++++-- ...what-the-t14s-hardware-offers-for-speed.md | 155 ++++++++++++++++ ...ser-programs-run-without-a-shadow-stack.md | 18 -- 4 files changed, 357 insertions(+), 32 deletions(-) create mode 100644 issues/hardware/newer-hardware-offers-what-the-t14-lacks.md create mode 100644 issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md delete mode 100644 issues/kernel/user-programs-run-without-a-shadow-stack.md diff --git a/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md b/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md new file mode 100644 index 00000000000..88e03f1d532 --- /dev/null +++ b/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md @@ -0,0 +1,45 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# Newer hardware offers what the T14 lacks + +Owner ruling: the T14 gets every security and speed feature its hardware has +(`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`, +`issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`), and +what only other modern systems have is written down here. A feature becomes +work when ToyOS gains a machine that has it. Intel's parts are named by the +SDM 325462-093US, Vol. 1 Table 5-2 ("SDM"), or by the ISE reference +319433-062, Table 1-2 ("ISE"), neither of which places any of these in Tiger +Lake. AMD's and Arm's are read in Linux at tag `v7.2`; the AMD parts that +carry each were not verified against AMD's documents, and the Arm cores were +not verified against Arm's. The Arm rows belong to +`issues/kernel/toyos-runs-on-arm64.md`'s CPU-state declaration, which names +none of them yet. + +| Feature | Hardware | Why it matters to ToyOS | +|---|---|---| +| FRED and LKGS | Panther Lake, Clearwater Forest, Diamond Rapids (ISE) | Replaces the IDT and SYSCALL entry; `SWAPGS`, `SETSSBSY` and `CLRSSBSY` are `#UD` under it (SDM Vol. 3A §8.5.1), so FSGSBASE (speed track P5) costs no `swapgs` and a kernel shadow stack (security S13) needs no tokens | +| LASS | Sierra Forest, Atom P6900, Core Ultra 200H (SDM) | Refuses a user access to the kernel half before any page walk whose timing would map the kernel's layout (SDM Vol. 3A §4.3), which security S10's KASLR rests on; Linux v7.2 sets it on every CPU (`arch/x86/kernel/cpu/common.c:413-431`) | +| LAM | the parts LASS names (SDM) | Metadata in a user pointer's unused bits, for sanitizers and JITs; Linux v7.2 holds it back until LASS (`arch/x86/Kconfig:2150-2153`) | +| PKS | Alder Lake, Sapphire Rapids, Sierra Forest (SDM) | Protection keys for kernel pages (SDM Vol. 3A §5.6.2): page tables and other kernel state writable only inside the code that owns them | +| User interrupts (UINTR) | Sapphire Rapids, Sierra Forest, Atom P6900, Core Ultra 200H (SDM) | `SENDUIPI` interrupts another thread at CPL 3 (SDM Vol. 3A §9.1): userland servers wake each other without a syscall | +| UMONITOR, UMWAIT, TPAUSE | Tremont, Alder Lake, Sapphire Rapids (SDM) | A userland driver or lock waits at low power without a syscall | +| Fast zero-length `rep movsb`, fast short `rep stosb` | Alder Lake, Sapphire Rapids (SDM) | Speed track P2's copies, and `memset`, cheaper at small sizes | +| AMX | Sapphire Rapids (SDM) | Matrix tiles for user programs; 8192 bytes of XSAVE state per thread (SDM Vol. 1 §13.1), so the kernel grants it per process | +| AVX10.1, AVX10.2 | AVX10.1: Granite Rapids, Nova Lake; AVX10.2: Diamond Rapids, Nova Lake (ISE) | AVX-512-class vectors on client parts again: Alder Lake has none (SDM Table 5-2, note 3) | +| APX | Diamond Rapids, Nova Lake (ISE) | Extended general-purpose registers, a new XSAVE component (ISE revision history, EGPR) the kernel saves, and a target feature for the toolchain | +| Thread Director, HRESET | Alder Lake (SDM) | The core-class hints `issues/kernel/all-cores-are-assumed-equal-and-arm64-breaks-that.md` needs on a hybrid part | +| TDX | Emerald Rapids (ISE) | ToyOS as a confidential guest; ToyOS runs no guest today | +| Total Storage Encryption | Panther Lake (ISE) | A platform engine encrypts storage under a key `PBNDKB` wraps to the platform (SDM Vol. 2B, PBNDKB), so disk encryption's key reaches memory only wrapped | +| INVLPGB, TLBSYNC | AMD, CPUID 0x80000008:EBX bit 3 (`arch/x86/include/asm/cpufeatures.h:331,335`) | Broadcast TLB invalidation without IPIs, which Linux v7.2 uses (`arch/x86/mm/tlb.c:276-285,407-448`); it would replace speed track P4's shootdown IPIs, as `TLBI IS` does on Arm | +| SEV-SNP | AMD, CPUID 0x8000001F:EAX bit 4 (`cpufeatures.h:448,453`) | ToyOS as a confidential guest; ToyOS runs no guest today | +| Shadow stack on AMD | AMD; unverified: that AMD enumerates it through the bit Linux reads for Intel, CPUID.(7,0):ECX bit 7 (`cpufeatures.h:390,397`), and which parts set it | Security S11 and S13 would run there unchanged | +| MTE | Armv8.5 (`arch/arm64/Kconfig:2150-2170`) | Always-on detection of memory errors at runtime, in C programs and unsafe Rust | +| Pointer authentication | Armv8.3 (`arch/arm64/Kconfig:1967-1974`) | Signed return addresses and pointers: Arm's answer to ROP | +| BTI | Armv8.5 (`arch/arm64/Kconfig:2087-2093`) | Arm's IBT: security S12 on the arm64 port | +| GCS | Armv9.4 (`arch/arm64/Kconfig:2236-2254`) | Arm's shadow stack: security S11 and S13 on the arm64 port | +| POE | Armv8.9 (`arch/arm64/Kconfig:2198-2213`) | Arm's protection keys: security S14 on the arm64 port | +| SME | Arm (`arch/arm64/Kconfig:2311-2319`) | Matrix state for user programs, granted per process as AMX is | diff --git a/issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md b/issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md index 4b7b655bae2..51e152bdd2b 100644 --- a/issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md +++ b/issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md @@ -22,15 +22,16 @@ on the T14, and the hardening table below. ## Hardening defaults -The track matches every hardening default the pinned Ubuntu config sets, and -no more. A hardening default is an option the config sets that, under the -default command line, makes an attack on the kernel or a process harder and -that no vulnerabilities line reports; access policy (the LSMs, lockdown, +Parity with the pinned Ubuntu kernel is the floor, and the T14 also gets every +security feature its CPU and platform support. A hardening default is an +option the config sets that, under the default command line, makes an attack +on the kernel or a process harder and that no vulnerabilities line reports; access policy (the LSMs, lockdown, `*_RESTRICT`, `STRICT_DEVMEM`) is the capability model's. `CONFIG_SLS` is the one entry of the `CPU_MITIGATIONS` menu (`arch/x86/Kconfig:2475-2664`) that no line reports. Numbers are the config's lines; each row is closed by its stage, its -defect, the ToyOS mechanism named, or the reason it does not apply. +defect, the ToyOS mechanism named, or the reason it does not apply. A row the +config leaves unset names the stage that goes past it. | Option | Disposition | |---|---| @@ -39,7 +40,9 @@ defect, the ToyOS mechanism named, or the reason it does not apply. | `ARCH_MMAP_RND_BITS=32` (909) | S8 | | `STACKPROTECTOR_STRONG` (882) | S9 | | `SLS` (564) | S5 | -| `X86_USER_SHADOW_STACK` (502) | `issues/kernel/user-programs-run-without-a-shadow-stack.md` | +| `X86_USER_SHADOW_STACK` (502) | S11 | +| `X86_KERNEL_IBT` (496), unset | S12 | +| `X86_INTEL_MEMORY_PROTECTION_KEYS` (497) | S14 | | `RESET_ATTACK_MITIGATION` (2457) | `issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md` | | `RANDOMIZE_KSTACK_OFFSET_DEFAULT` (933) | `issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md` | | `ZERO_CALL_USED_REGS` (11477) | `issues/kernel/kernel-functions-return-with-their-used-registers-intact.md` | @@ -84,7 +87,10 @@ direct map sits at the fixed `PHYS_OFFSET` (`kernel/src/mm/mod.rs`) and the kernel image at `PHYS_OFFSET` plus wherever firmware allocated it (`bootloader/src/main.rs`): nothing draws either. The kernel target is `x86_64-unknown-none` with no stack-protector or `cf-protection` flag -(`kernel/.cargo/config.toml`). +(`kernel/.cargo/config.toml`). `CR4.CET`, `CR4.PKE`, `CR4.KL` and +`CR4.OSXSAVE` are in no declaration (`control_regs.rs`), nothing writes +`IA32_S_CET`, `IA32_U_CET` or `MSR_MEMORY_CTRL`, and a thread's saved user +state is `FXSAVE64`'s 512 bytes (`kernel/src/arch/x86_64/fpu.rs`). ## Stages @@ -96,7 +102,10 @@ nightly's `guest` and `audio` shards run KVM with `-cpu host` branches gated on those bits run on whatever CPU the runner has. A QEMU test therefore asserts wiring only: what the guest applied equals S1 applied to the facts the guest itself reports on a `boot-actuators` line. Independence -comes from S1's T14 fixture and the T14 run, never from KVM. +comes from S1's T14 fixture and the T14 run, never from KVM. TCG enumerates +PKU and none of the bits S11–S13 and S15–S17 read (`TCG_7_0_ECX_FEATURES`, +`target/i386/cpu.c:992-995`; `TCG_7_0_EDX_FEATURES`, `:1003`), so those run +on the T14 alone. - **S0 — Evidence.** On the T14 under its stock Ubuntu boot, as root: @@ -109,6 +118,9 @@ comes from S1's T14 fixture and the T14 run, never from KVM. grep microcode /proc/cpuinfo cpuid -r -l 1; cpuid -r -l 7 -s 0; cpuid -r -l 7 -s 2 cpuid -r -l 0x80000000; cpuid -r -l 0x80000008; cpuid -r -l 0x80000021 + cpuid -r -l 5; cpuid -r -l 7 -s 1; cpuid -r -l 0xd -s 0; cpuid -r -l 0xd -s 1 + cpuid -r -l 0x19; cpuid -r -l 0x80000001 + dmesg | grep -e 'x86/tme' -e 'x86/split lock detection' rdmsr -a 0x10a; rdmsr -a 0x48; rdmsr -a 0x123 mkdir -p rd/bin rd/sys rd/proc && cp /usr/bin/busybox rd/bin/ printf '#!/bin/busybox sh\n/bin/busybox mount -t sysfs s /sys\n/bin/busybox mount -t proc p /proc\n/bin/busybox cat /proc/version\n/bin/busybox grep . /sys/devices/system/cpu/vulnerabilities/*\n/bin/busybox poweroff -f\n' > rd/init && chmod +x rd/init @@ -117,9 +129,11 @@ comes from S1's T14 fixture and the T14 run, never from KVM. and `rdmsr -a 0x122` where 0x10A bit 7 (TSX_CTRL_MSR) is set, and `rdmsr -a 0x10f` where CPUID.(7,0):EDX bits 11 and 13 (RTM_ALWAYS_ABORT, - TSX_FORCE_ABORT, `arch/x86/include/asm/cpufeatures.h:422-423`) are. - `/proc/cpuinfo`'s `microcode` is the revision as Linux reads it - (`arch/x86/include/asm/microcode.h:62-75`). On the development host, whose + TSX_FORCE_ABORT, `arch/x86/include/asm/cpufeatures.h:422-423`) are, + `rdmsr -a 0x982` where CPUID.(7,0):ECX bit 13 (TME, `cpufeatures.h:399`) is, + and `rdmsr -a 0xcf` where CPUID.(7,0):EDX bit 30 (CORE_CAPABILITIES, + `cpufeatures.h:438`) is. `/proc/cpuinfo`'s `microcode` is the revision as + Linux reads it (`arch/x86/include/asm/microcode.h:62-75`). On the development host, whose QEMU is the one `.github/qemu-version` pins, `qemu-system-x86_64 --version` and then `qemu-system-x86_64 -nodefaults -machine q35 -cpu qemu64,+rdrand,+smap,+fsgsbase,+x2apic,+smep -smp 2 -m 4G -kernel @@ -132,7 +146,8 @@ comes from S1's T14 fixture and the T14 run, never from KVM. the one above. The capture is one-time: the kernel image, `s0.cpio` and busybox are never committed and no build or test boots them. **Exit**: the captured text outputs committed as S1's fixtures. Ubuntu - is wiped from the T14 only after that commit. + is wiped from the T14 only after that commit and P0's of + `issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`. - **S1 — The decision, a host-tested function.** A pure function, in a crate the kernel and a host test both build, maps (vendor, family, model, stepping, microcode revision, CPUID.1, CPUID.(7,0), CPUID.(7,2), @@ -393,6 +408,133 @@ comes from S1's T14 fixture and the T14 run, never from KVM. them (per-bit false-red probability 1.0e-7, exact binomial tail); a fixed base reds it. +S11–S17 go past the config where it stops. Intel places CET and Key Locker in +Tiger Lake as a family (SDM 325462-093US, Vol. 1 Table 5-2), and TME, CET and +Key Locker in the 11th-generation family (datasheet 631121-012, +§2.3.13-2.3.15), never in the i5-1135G7 by name, and names no Tiger Lake part +for PKU or split-lock disable. So each stage's first step confirms its bit in +S0's capture, and a bit S0 finds clear closes the stage. + +- **S11 — User shadow stacks.** First, CPUID.(7,0):ECX bit 7 (SHSTK, + `cpufeatures.h:393`); the datasheet enables either ring's shadow stack on its + own (§2.3.14.1). As `CONFIG_X86_USER_SHADOW_STACK` does: `CR4.CET` joins the + declaration (it needs `CR0.WP`, SDM Vol. 3A §5.1.3), the kernel maps each + thread a shadow stack as it creates the thread (`shstk_alloc_thread_stack`, + `arch/x86/kernel/shstk.c:195`) in shadow-stack pages, read-only and dirty in + the leaf and writable above it (SDM Vol. 3A §5.6.1), and a thread's + `IA32_U_CET` (0x6A0, `SH_STK_EN` bit 0) and `IA32_PL3_SSP` (0x6A7) + (`arch/x86/include/asm/msr-index.h:478-480,493`) switch with it as XSAVES's + CET_U component (`arch/x86/include/asm/fpu/types.h:120`), so it waits on P1 + of `issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`. + Where Linux lets each process choose (`shstk_prctl`, `shstk.c:548`), every + ToyOS program is built with `-Zcf-protection=return` + (`rust/compiler/rustc_session/src/options.rs:2377` at the `rust/` commit, + 1b236638), and on a CPU with shadow stacks the loader refuses an object whose + `.note.gnu.property` lacks `GNU_PROPERTY_X86_FEATURE_1_SHSTK`. Two paths + leave a frame other than by `RET` and must pop it: std's unwinder, + `unwinding` 0.2.10 (`rust/library/Cargo.lock`), whose source has no + `incssp`, and libc's `longjmp` (`userland/libc/src/misc.rs`). A shadow stack + costs its thread a 2 MiB page until + `issues/kernel/process-memory-is-2-mib-pages-and-that-caps-the-process-count.md` + lands. **Exit**, T14: a `test-actuators` program writes a planted + function's address over its return address and returns, in its first thread + and in a second, and is ended naming `#CP` NEAR-RET (error code 1, SDM Vol. + 3A §7.15, Event 21); a caught panic in it returns normally. `SH_STK_EN` + left clear lets the forged return reach the planted function, which says so + and reds it; the second thread handed the first's shadow stack reds its + first return; the unwinder without its `incssp` reds the panic. The oracle + is the T14's CPU. +- **S12 — Kernel IBT**, which the config leaves unset (496) and upstream's + Kconfig defaults on (`arch/x86/Kconfig:1840-1842`). First, CPUID.(7,0):EDX + bit 20 (IBT, `cpufeatures.h:429`). `-Zcf-protection=branch` for the kernel + and the `core` and `alloc` `src/toolchain.rs` builds. SYSCALL and every + event leave the ring-0 tracker waiting for an `endbr64` (SDM Vol. 1 + §18.3.3.1), so `syscall_entry` and every IDT stub begin with one, as + `entry_SYSCALL_64` does (`arch/x86/entry/entry_64.S:89`). `IA32_S_CET` + (0x6A2) holds `ENDBR_EN` (bit 2), declared with `CR4.CET` and asserted on + every CPU, as `setup_cet` writes it (`common.c:587-592`); `NOTRACK_EN` + stays clear, so the kernel has no jump table (`arch/x86/Makefile:73-83`). + **Exit**: a gate over `kernel.elf` finds `endbr64` at every symbol the IDT + and `IA32_LSTAR` name and no `notrack`-prefixed branch; deleting the + `endbr64` from `syscall_entry` reds it. On the T14 a `boot-actuators` + indirect call to a function with no `endbr64`, as `ibt_selftest` makes + (`arch/x86/kernel/ibt_selftest.S:6-17`), panics naming `#CP` ENDBRANCH + (error code 3), the boot's last event; `IA32_S_CET` declared without + `ENDBR_EN` lets the call return and reds it. The oracle is the T14's CPU. +- **S13 — Kernel shadow stack**, which Linux does not build: its supervisor + CET state is `XFEATURE_CET_KERNEL_UNUSED` (`fpu/types.h:121`). S11's bit + enumerates it. `SH_STK_EN` joins S12's `IA32_S_CET`. Each thread's kernel + stack gets a shadow stack topped by a supervisor shadow-stack token (SDM + Vol. 1 §18.2.3). SYSCALL sets SSP to 0 at ring 0 (SDM Vol. 2B, SYSCALL), so + `syscall_entry` takes the thread's from `IA32_PL0_SSP` (0x6A4) with + `SETSSBSY` and frees it with `CLRSSBSY` before `sysretq`; IST entries take + theirs through `IA32_INT_SSP_TAB` (0x6A8, `msr-index.h:490-494`); + `context_switch` moves SSP with `SAVEPREVSSP` and `RSTORSSP` (SDM Vol. 1 + §18.2.5). A shadow-stack page is protected only through its own mapping + (SDM Vol. 3A §5.6.1), so its frame leaves the direct map's writable 2 MiB + leaves, the split `issues/kernel/a-threads-kernel-stack-has-no-guard-page.md` + needs too. **Exit**, T14: a `boot-actuators` frame writes a planted + function's address over its return address and returns, and the kernel + panics naming `#CP` NEAR-RET; `IA32_S_CET` without `SH_STK_EN` reaches the + planted function, which reds it. S9's `kernel_stack_canary` boot runs with + kernel shadow stacks, and a `context_switch` that leaves SSP where it was + `#CP`s at the first return after a switch and reds it. The oracle is the + T14's CPU. +- **S14 — User protection keys.** First, CPUID.(7,0):ECX bit 3 (PKU, + `cpufeatures.h:389`): Table 5-2 introduces PKU with Comet Lake and names no + Tiger Lake part. `CR4.PKE` joins the declaration, as `setup_pku` sets it + (`common.c:506-515`); PKRU is per thread and an XSAVE component, so it + waits on P1. A process allocates a key and puts a mapping under it, as + `pkey_alloc` and `pkey_mprotect` do (`mm/mprotect.c:836-872`); that is an + ABI change, discussed with the owner before the stage starts. The key is + the leaf's bits 62:59 (SDM Vol. 3A §5.6.2). **Exit**, under TCG with `+pku` + and on the T14: a thread that denies itself writes to a key with `WRPKRU` + and writes a page under it is ended naming a page fault with PK set (bit 5, + SDM Vol. 3A §5.7), and another thread of the process writes the same page. + No key written into the entry lets the first write through and reds it; a + PKRU not switched per thread faults the second and reds it. TCG and the T14 + are two implementations of §5.6.2. +- **S15 — Key Locker**, which no `arch/x86` file at the pinned tag names. + First, CPUID.(7,0):ECX bit 23 (KL, Intel Key Locker Specification + 343965-001US §1.3). `CPUID.19H:EBX[0]` (AESKLE) reads 1 only once `CR4.KL` + is set and firmware has enabled Key Locker (§1.3), so ToyOS's first boot + with `CR4.KL` declared prints it; a 0 there closes the stage unless the + T14's setup enables it, which is the owner's. As §5.1 has it, the BSP loads + a random IWKey with `LOADIWKEY`, copies it out with + `IA32_COPY_LOCAL_TO_PLATFORM` and every AP copies it in with + `IA32_COPY_PLATFORM_TO_LOCAL` (§4.2-4.3), so a handle works on every CPU, + and no process runs with `CR4.KL` unless that succeeded. No ToyOS program + holds a long-lived AES key yet, so the test is the only user until one + does. **Exit**, T14: a program wraps FIPS-197 Appendix C.1's key with + `ENCODEKEY128` on one CPU and encrypts that appendix's plaintext with + `AESENC128KL` on another, getting its ciphertext; each CPU loading its own + random IWKey fails the handle on the second CPU (ZF set) and reds it. + FIPS-197 is the oracle. +- **S16 — TME, read back.** Firmware enables and locks it (datasheet + §2.3.13), and its availability varies by processor line (§1.3); Linux only + reports it and disables MKTME when CPUs disagree (`detect_tme_early`, + `arch/x86/kernel/cpu/intel.c:204-234`). First, CPUID.(7,0):ECX bit 13 and + 0x982 from S0; TME present but not enabled is the owner's to turn on in the + T14's setup. ToyOS reads `IA32_TME_ACTIVATE` (0x982) on every CPU, prints + it, and refuses the boot by name when two CPUs disagree. **Exit**, T14: + every CPU reads enabled and locked (bits 1 and 0, `intel.c:187-188`), + matching S0's `x86/tme:` line; a `boot-actuators` arm reporting cpu1's value + with bit 1 flipped is refused, and deleting the comparison boots it and reds + it. +- **S17 — Split-lock disable**, Linux's default with no config option: + `sld_state_setup` takes `sld_warn` (`intel.c:1081-1101`) where + `IA32_CORE_CAPABILITIES` (0xCF) bit 5 is set, and TIGERLAKE_L is not in its + model list (`intel.c:1308-1313`). A split-locked access locks the bus for + every core (SDM Vol. 3A §11.1.2.3). First, 0xCF bit 5 from S0. + `MSR_MEMORY_CTRL` (0x33) bit 29 joins the declaration (SDM Vol. 4, MSR 33H); + a split lock then raises `#AC(0)` whatever `CR0.AM` holds (§11.1.2.3, note + 1), so the kernel gains an `#AC` handler: in ring 3 it ends the process + naming the split lock, where Linux warns and slows it (`split_lock_warn`, + `intel.c:1191-1230`), and in ring 0 it panics. **Exit**, T14: a + `test-actuators` program's `lock add` across a cache-line boundary is ended + naming the split lock; bit 29 left clear lets it exit 0 and reds it. S0's + `x86/split lock detection:` line is the oracle for the T14's support. + ## Decisions - **IBPB is conditional**, Linux's default: `spectre_v2_user_select_mitigation` @@ -419,5 +561,6 @@ it is not worse: Reading ARCH_CAPABILITIES as 0 instead of from 0x10A turns `spectre_v2` into "Mitigation: Retpolines; …" and `gather_data_sampling` into "Vulnerable: No -microcode", and reds it. S1–S6 and S8–S10 are green, S7 is closed by S0's -finding or by the owner, and every defect the hardening table cites is closed. +microcode", and reds it. S1–S6 and S8–S17 are green or closed by S0's +finding, S7 is closed by S0's finding or by the owner, and every defect the +hardening table cites is closed. diff --git a/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md b/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md new file mode 100644 index 00000000000..dc227e6b8a0 --- /dev/null +++ b/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md @@ -0,0 +1,155 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# ToyOS uses what the T14's hardware offers for speed + +Owner ruling: ToyOS takes the newest hardware features that make it faster, at +least on the T14, an i5-1135G7, Tiger Lake, family 6 model 0x8C +(`issues/hardware/the-t14-touchpad-is-i2c-hid-and-unbuilt.md`). Features the +T14 lacks are `issues/hardware/newer-hardware-offers-what-the-t14-lacks.md`. +Intel documents most of these for the Tiger Lake family, not for the +i5-1135G7, so a stage's first step confirms its bit in S0's CPUID capture +(`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`), and +a bit S0 finds clear closes the stage. Linux `path:line`s are read at that +track's tag, `Ubuntu-6.8.0-142.142`; Intel's documents are the SDM +325462-093US and the 11th-generation datasheet 631121-012. + +**How a stage is judged.** Each figure is the median of 11 runs on the T14, +with its spread, taken by P0's program. A stage is done when ToyOS's figure is +at or past P0's Linux figure, or when the gap is filed as a defect with both +numbers. A stage Linux has no counterpart for is measured against ToyOS +without it and lands only if it wins. + +**Owned elsewhere, not repeated here.** HWP, RAPL and turbo: PR #590's +`issues/kernel/the-kernel-owns-cpu-performance-state.md`. Global kernel pages: +`issues/kernel/page-global-is-a-decision-nobody-has-made.md`. A vector per CPU +or per queue: `issues/kernel/every-interrupt-lands-on-the-boot-cpu.md`. +Placement that weighs caches and idle depth: +`issues/kernel/placement-is-blind-to-caches-and-topology.md` and +`issues/kernel/the-scheduler-and-the-clocks-never-talk.md`. 4 KiB process +pages: `issues/kernel/process-memory-is-2-mib-pages-and-that-caps-the-process-count.md`. +NVMe with commands in flight: step 3 of +`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`. The +stick at SuperSpeed: +`issues/hardware/the-t14s-superspeed-stick-enumerates-at-high-speed-under-toyos.md`. +PCID is in use, and a switch keeps the incoming space's translations +(`CR3_NOFLUSH`, `kernel/src/arch/x86_64/paging.rs`). + +## Stages + +- **P0 — The Linux baseline.** One Rust program, built from one source for + `x86_64-unknown-linux-gnu` under Ubuntu on the T14 and for ToyOS, measures: + memcpy at 64 B, 4 KiB, 256 KiB and 64 MiB; AES-128-GCM, ChaCha20-Poly1305 + and SHA-256 through the RustCrypto versions sshd links + (`userland/Cargo.lock`); a pipe round trip between two threads and between + two processes, and pipe throughput at 64 B, 4 KiB and 64 KiB writes; munmaps + per second of a page a sibling thread on another CPU has touched; a + sleeping thread's lateness past a 1 ms timer; 4 KiB random reads at 1 and 32 + in flight and 1 MiB sequential reads of the raw NVMe namespace, read-only; + and an idle minute's package energy, from + `/sys/class/powercap/intel-rapl:0/energy_uj` under Linux. It runs in S0's + session with `lspci -vvv -nn`, `lsusb -tv`, `nvme id-ctrl -H /dev/nvme0`, + `nvme get-feature -f 0x0c -H /dev/nvme0` (APST) and `-f 0x06` (volatile + write cache), and `grep . + /sys/devices/system/cpu/cpu0/cpuidle/state*/{name,desc,latency,residency}`. + **Exit**: the outputs committed as fixtures; S0's wipe waits on that commit. +- **P1 — XSAVE, and with it AVX, AVX2 and AVX-512 in user programs.** + `CR4.OSXSAVE` is clear and a thread's saved state is `FXSAVE64`'s + (`kernel/src/arch/x86_64/fpu.rs`), so no user program may run a VEX or EVEX + instruction. RustCrypto's `cpufeatures` 0.2.17 gates every AVX feature on + `OSXSAVE` and `XCR0` (`src/x86.rs:67-83,97-101`), so `chacha20` 0.9.1's AVX2 + backend (`src/lib.rs:173`) and `sha2` 0.10.9's AVX2 SHA-512 + (`src/sha512/x86.rs:14`) never run; AES-NI, PCLMULQDQ and SHA-NI need no + `XCR0` and run today (`cpufeatures` `src/x86.rs:116,122,142`). First, + AVX-512 from S0's capture: the datasheet warns it may be absent on some + SKUs (§2.4.10). `CR4.OSXSAVE` and `XCR0` (x87, SSE and AVX, and opmask, + ZMM_Hi256 and Hi16_ZMM where CPUID offers them, SDM Vol. 1 §13.1, §13.3) + join the one declaration and are asserted on every CPU. A switch saves with + XSAVES where CPUID.(0xD,1) offers it, which the security track's S11 needs + for CET_U, and with XSAVEOPT where not: TCG offers neither XSAVEC nor XSAVES + (`target/i386/cpu.c:1012-1014` at QEMU v11.1.1) and no AVX-512 + (`:977-985`). A thread's state grows from 512 bytes to CPUID.(0xD,0):EBX. + `aes` 0.8.4 and `polyval` 0.6.2 carry no VAES or VPCLMULQDQ path, so those + wait on a crate version that has one. **Exit**, T14: P0's + ChaCha20-Poly1305 figure; two threads that fill their vector registers with + different patterns and switch each find their own, and a save mask short of + Hi16_ZMM reds it. +- **P2 — Kernel copies with `rep movsb`.** compiler-builtins copies with + `rep movsb` only under `target_feature = "ermsb"` + (`rust/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs:23-54` + at the `rust/` commit, 1b236638), which the kernel's `x86_64-unknown-none` + build lacks, so every kernel copy is `rep movsq` and a byte tail. First, + CPUID.(7,0):EBX bit 9 (ERMS) and EDX bit 4 (FSRM) from S0 + (`arch/x86/include/asm/cpufeatures.h:251,418`); SDM Vol. 1 Table 5-2 + introduces fast short `rep movsb` with Ice Lake and names no Tiger Lake + part. `+ermsb` for the kernel and the `core`, `alloc` and + `compiler_builtins` it builds makes ERMS a boot requirement, refused by name, + as the security track's S4 makes SMAP one. **Exit**, T14: P0's pipe figures + before and after. +- **P3 — 1 GiB leaves in the direct map.** Every direct-map leaf is 2 MiB + (`toyos-bootmap/src/lib.rs`, `PAGE_2M`), with a page directory per GiB + (`issues/kernel/the-direct-maps-page-directories-come-from-a-512-kib-heap.md`). + First, CPUID.80000001H:EDX bit 26 (`cpufeatures.h:67`); TCG offers it + (`target/i386/cpu.c:945`). A GiB of one memory type takes one 1 GiB leaf, + and a GiB of mixed types keeps 2 MiB leaves (SDM Vol. 3A §14.11.9). + **Exit**, T14: P0's 64 KiB pipe throughput before and after, and the boot's + count of 1 GiB and 2 MiB direct-map leaves. +- **P4 — Shootdowns only where the space ran.** Every shootdown interrupts + every other CPU, and each flushes every PCID (`kernel/src/arch/x86_64/tlb.rs` + header, `flush_tlb_all` in `paging.rs`). Linux interrupts only the CPUs in + the space's `mm_cpumask`, which a switch keeps (`arch/x86/mm/tlb.c:575-628`), + and flushes by page up to 33 pages (`tlb.c:1003,1048-1076`). A shootdown + goes to the CPUs that ran the space since its last flush and flushes that + space's PCID, or its pages. This is memory management: a guest test's + sibling thread on another CPU touches a page, the initiator unmaps it, and + the sibling's next touch faults; a target set that omits a CPU the space + ran on lets the read through and reds it, and + `kernel-loom/tests/tlb_shootdown.rs` models the ordering. **Exit**, T14: + P0's munmap figure and the `tlb:` census line's shootdowns and wait. +- **P5 — FSGSBASE, measured, then taken or rejected.** Every switch reads and + writes `IA32_FS_BASE` with `rdmsr` and `wrmsr` + (`kernel/src/arch/x86_64/hw.rs:423,445`). One `CR4` bit enables all four + base instructions (SDM Vol. 3A §2.5) in ring 3 as in ring 0, and `GS.base` + is the kernel's per-CPU pointer with no `swapgs` on entry, which is why + `control_regs.rs` forbids it. Taking it means a `swapgs` entry, and then the + security track's S4 owes Linux's swapgs barriers + (`arch/x86/kernel/cpu/bugs.c:943-944`). It buys `rdfsbase`/`wrfsbase` on + the switch and a user thread that sets its own FS base. **Exit**, T14: P0's + round trips with the `wrfsbase` switch, the `swapgs` entry and the + barriers, against without; a loss becomes a `rejected` issue carrying both + figures. +- **P6 — Deep idle.** An idle CPU runs `sti; hlt` + (`kernel/src/arch/x86_64/hw.rs:52-53`), which reaches C1 or C1E (datasheet + §3.2.3); Tiger Lake cores and the package go to C10 through MWAIT hints + (§3.2.4-3.2.5). TIGERLAKE_L has no table in `intel_idle` + (`drivers/idle/intel_idle.c:1603-1657`), so Linux takes its hints from ACPI + `_CST` (`:2347-2349`), which ToyOS cannot evaluate without an AML + interpreter (`issues/kernel/the-scheduler-and-the-clocks-never-talk.md`). + P0's cpuidle capture becomes a TIGERLAKE_L table, as `intel_idle` carries + one per model, and an idle CPU picks the deepest state whose target + residency fits before its next deadline. Package C9 and C10 need every PCIe + link in L1.2 (datasheet §3.7, Table 3-8), which is P7's. **Exit**, T14: the + idle desktop minute's package energy, read by the sampler of stage 4 of PR + #590's track, against P0's; P0's timer lateness no worse than `hlt`'s by + more than the chosen state's exit latency. +- **P7 — The T14's NVMe drive, idle and busy.** blockd runs several I/O queue + pairs on the claim's one MSI-X vector (`userland/blockd/src/nvme.rs`). The + drive's model is unrecorded; P0's `id-ctrl` says whether it offers APST + (`apsta`), a host memory buffer (`hmpre`) and a volatile write cache. What + it offers is taken, as Linux takes it: APST through feature 0x0C + (`drivers/nvme/host/core.c:2495-2592`, `include/linux/nvme.h:1222`), a host + memory buffer through 0x0D (`drivers/nvme/host/pci.c:2108`). Blocked on + blockd driving the T14's NVMe, which step 3 of the small-kernel track meets + on the T14 only with its step 10. **Exit**, T14: P0's block figures against + Linux's on the same drive, and P6's idle minute with the drive idle. + +The whole-system figure is PR #568's T14 LLVM build bar once it lands; each +stage names a narrower one. + +**Not taken.** Vector registers in the kernel: its target is soft-float, as +Linux builds its kernel's C and Rust without SSE or AVX +(`arch/x86/Makefile:70-71`), and the kernel has no bulk data to encrypt or +hash. diff --git a/issues/kernel/user-programs-run-without-a-shadow-stack.md b/issues/kernel/user-programs-run-without-a-shadow-stack.md deleted file mode 100644 index ba44987e0c4..00000000000 --- a/issues/kernel/user-programs-run-without-a-shadow-stack.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -status: open -kind: defect -opened: 2026-09-29 ---- - -# User programs run without a shadow stack - -At `Ubuntu-6.8.0-142.142`, `CONFIG_X86_USER_SHADOW_STACK=y` (config line 502) -lets a process opt into CET shadow stacks: a return address a `RET` pops is -checked against a hardware-maintained copy that ordinary writes cannot reach, -so a corrupted return address on the data stack is refused rather than taken. -ToyOS builds no user shadow stack: no program can enable one, and nothing in -`kernel/src` maps a shadow-stack page or sets `CR4.CET`/`MSR_IA32_U_CET`. - -**Exit**: a process can have a shadow stack of its own, the kernel maps and -enables one for it, and a `RET` to a return address forged on the data stack -is refused rather than taken. From 8a75a4203b8ea03c6363d322dd16027a0a2a677a Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 09:49:59 +0200 Subject: [PATCH 2/6] PR #603 round 2: both tracks cut to issues/README.md's shape, TME leaves the T14, and every high-risk stage names its mutation The review of 2dfa1236 found the security track grown from 423 to 566 lines and the speed track a 155-line design, against issues/README.md's rule that a track carries no design and no stage table and is cut back past a screen. - Both tracks keep their intent in a sentence or two, and each stage is one entry: its name, its exit, the mutation that must go red, and its oracle. Mechanism, register-level design, the "What is true today" section, the S0 command block and every Linux and SDM line citation no exit needs are deleted; they land with each stage's own PR. The security track goes from 566 lines to 114, the speed track from 155 to 71. - The security track is renamed the-kernel-is-at-least-as-secure-as-linux-on-the-t14, because S13 goes past Linux parity. Every citation moves; the seven defects that called themselves "a row of the hardening table" lose that sentence, since the table is gone and the track's Exit names each of them. - S16 (TME) moves to newer-hardware-offers-what-the-t14-lacks as a row: the T14's CPUID.(7,0):ECX is 0x18c05fde, bit 13 clear. Split-lock disable becomes S16. - S11: the loader refuses an unmarked program or library on every CPU (the orchestrator's ruling), so `unmarked_object_refused` runs under TCG; the sysroot link reds on one unmarked input; a store to the shadow stack is #PF and user_ptr refuses a read into it. The libc longjmp clause goes: it is a panicking stub. - S13 is gated on CET_SSS and tests that a DirectMap store to a kernel shadow stack faults. S14's window refuses a user copy under a key the thread denied; its ABI is approved in principle. - S15, P0 and P4 need two distinct CPUs, and no boot-actuators arm or ABI call places a thread. The speed track gains the Pin stage, a test-actuators SYS_DEBUG action whose test reads the CPU's own APIC ID. - P1 has one save path, XSAVEOPT: QEMU v11.1.1's TCG implements neither XSAVEC nor XSAVES (target/i386/cpu.c:1012-1014), and S11's CET state switches by wrmsr. P3 names a toyos-bootmap host test, P4 a loom case for a CPU joining the space during a shootdown, P5 an NMI under a user GS base; P6 takes C-states from _CST after the AML interpreter; P7 names Linux's APST bound and quirks. The #568 and #590 citations go. - The newer-hardware file states what it is blocked on and its exit. Co-Authored-By: Claude Opus 5.5 --- ...ewer-hardware-offers-what-the-t14-lacks.md | 11 +- ...-a-domain-of-its-own-reaches-all-memory.md | 4 +- ...-threads-kernel-stack-has-no-guard-page.md | 3 +- ...syscall-runs-at-one-kernel-stack-offset.md | 3 +- ...return-with-their-used-registers-intact.md | 3 +- ...itable-and-every-kernel-page-executable.md | 3 +- ...kernel-heap-has-none-of-slubs-hardening.md | 3 +- ...-at-least-as-secure-as-linux-on-the-t14.md | 114 ++++ ...tigates-what-linux-mitigates-on-the-t14.md | 566 ------------------ ...what-the-t14s-hardware-offers-for-speed.md | 208 ++----- .../kernel/tsx-stays-as-firmware-left-it.md | 12 +- 11 files changed, 194 insertions(+), 736 deletions(-) create mode 100644 issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md delete mode 100644 issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md diff --git a/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md b/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md index 88e03f1d532..ab002469db1 100644 --- a/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md +++ b/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md @@ -7,17 +7,17 @@ opened: 2026-09-29 # Newer hardware offers what the T14 lacks Owner ruling: the T14 gets every security and speed feature its hardware has -(`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`, +(`issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md`, `issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`), and -what only other modern systems have is written down here. A feature becomes -work when ToyOS gains a machine that has it. Intel's parts are named by the +what only other modern systems have is written down here. It is blocked on a +machine that has the feature; its exit is every row a stage on that +machine's track or a `rejected` issue. Intel's parts are named by the SDM 325462-093US, Vol. 1 Table 5-2 ("SDM"), or by the ISE reference 319433-062, Table 1-2 ("ISE"), neither of which places any of these in Tiger Lake. AMD's and Arm's are read in Linux at tag `v7.2`; the AMD parts that carry each were not verified against AMD's documents, and the Arm cores were not verified against Arm's. The Arm rows belong to -`issues/kernel/toyos-runs-on-arm64.md`'s CPU-state declaration, which names -none of them yet. +`issues/kernel/toyos-runs-on-arm64.md`'s CPU-state declaration. | Feature | Hardware | Why it matters to ToyOS | |---|---|---| @@ -34,6 +34,7 @@ none of them yet. | Thread Director, HRESET | Alder Lake (SDM) | The core-class hints `issues/kernel/all-cores-are-assumed-equal-and-arm64-breaks-that.md` needs on a hybrid part | | TDX | Emerald Rapids (ISE) | ToyOS as a confidential guest; ToyOS runs no guest today | | Total Storage Encryption | Panther Lake (ISE) | A platform engine encrypts storage under a key `PBNDKB` wraps to the platform (SDM Vol. 2B, PBNDKB), so disk encryption's key reaches memory only wrapped | +| TME | 11th-generation Core lines that set CPUID.(7,0):ECX bit 13, which varies by line (datasheet 631121-012 §1.3); the T14 reads ECX 0x18c05fde, bit 13 clear | Memory encrypted under a key firmware activates and locks; the kernel reads `IA32_TME_ACTIVATE` on every CPU and refuses a boot where two disagree, where Linux only reports it (`detect_tme_early`) | | INVLPGB, TLBSYNC | AMD, CPUID 0x80000008:EBX bit 3 (`arch/x86/include/asm/cpufeatures.h:331,335`) | Broadcast TLB invalidation without IPIs, which Linux v7.2 uses (`arch/x86/mm/tlb.c:276-285,407-448`); it would replace speed track P4's shootdown IPIs, as `TLBI IS` does on Arm | | SEV-SNP | AMD, CPUID 0x8000001F:EAX bit 4 (`cpufeatures.h:448,453`) | ToyOS as a confidential guest; ToyOS runs no guest today | | Shadow stack on AMD | AMD; unverified: that AMD enumerates it through the bit Linux reads for Intel, CPUID.(7,0):ECX bit 7 (`cpufeatures.h:390,397`), and which parts set it | Security S11 and S13 would run there unchanged | diff --git a/issues/kernel/a-device-without-a-domain-of-its-own-reaches-all-memory.md b/issues/kernel/a-device-without-a-domain-of-its-own-reaches-all-memory.md index 5458bcb8ae9..2faa9d1d82d 100644 --- a/issues/kernel/a-device-without-a-domain-of-its-own-reaches-all-memory.md +++ b/issues/kernel/a-device-without-a-domain-of-its-own-reaches-all-memory.md @@ -15,9 +15,7 @@ under the T14's `CONFIG_INTEL_IOMMU_DEFAULT_ON=y` and `CONFIG_IOMMU_DEFAULT_DMA_LAZY=y`, turns DMA remapping on (`drivers/iommu/intel/iommu.c:227`) and gives every device a translated default domain (`drivers/iommu/iommu.c:197-210`), which maps only what its -driver maps. A row of the -hardening table in -`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`. +driver maps. **Exit**: a function's DMA reaches only what its driver mapped and the reserved ranges firmware names for it; a `boot-actuators` arm that points an unclaimed diff --git a/issues/kernel/a-threads-kernel-stack-has-no-guard-page.md b/issues/kernel/a-threads-kernel-stack-has-no-guard-page.md index 1394b4b573b..53a04684dfc 100644 --- a/issues/kernel/a-threads-kernel-stack-has-no-guard-page.md +++ b/issues/kernel/a-threads-kernel-stack-has-no-guard-page.md @@ -15,8 +15,7 @@ write. The per-CPU idle stacks already have an unmapped page below them (`kernel/src/arch/x86_64/percpu.rs:482`). Linux at `Ubuntu-6.8.0-142.142`, under the T14's `CONFIG_VMAP_STACK=y`, maps every task stack in vmalloc space between guard pages (`kernel/fork.c:314-318`, `arch/Kconfig:1327-1336`), so -the first write past the end faults. A row of the hardening table in -`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`. +the first write past the end faults. **Exit**: every thread's kernel stack has an unmapped page below it; a `boot-actuators` arm that recurses a thread past its stack gets a double fault diff --git a/issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md b/issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md index bba5fe80b30..e6d86f01af0 100644 --- a/issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md +++ b/issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md @@ -15,8 +15,7 @@ Linux at `Ubuntu-6.8.0-142.142`, under the T14's offset at every syscall entry (`arch/x86/entry/common.c:73`, `include/linux/randomize_kstack.h:40,50`), drawn on the exit before it (`arch/x86/include/asm/entry-common.h:85`), 7 bits after alignment on x86-64 -(`entry-common.h:76-83`). A row of the hardening table in -`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`. +(`entry-common.h:76-83`). **Exit**: every syscall's handler runs below an offset drawn per syscall, of at least 7 bits; a `boot-actuators` probe records one handler frame's address diff --git a/issues/kernel/kernel-functions-return-with-their-used-registers-intact.md b/issues/kernel/kernel-functions-return-with-their-used-registers-intact.md index 6ea64923aad..26761964990 100644 --- a/issues/kernel/kernel-functions-return-with-their-used-registers-intact.md +++ b/issues/kernel/kernel-functions-return-with-their-used-registers-intact.md @@ -14,8 +14,7 @@ builds with `-fzero-call-used-regs=used-gpr` (`Makefile:891-894`). LLVM acts on the function attribute `zero-call-used-regs` (`llvm/lib/CodeGen/PrologEpilogInserter.cpp:1212`), and the rustc fork at 1b236638 has no option that sets it -(`compiler/rustc_session/src/options.rs`). A row of the hardening table in -`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`. +(`compiler/rustc_session/src/options.rs`). **Exit**: the kernel, `core` and `alloc` build under a rustc option that sets `zero-call-used-regs=used-gpr` on every function, carried in the fork to diff --git a/issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md b/issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md index 42b790c801d..fe1548068ef 100644 --- a/issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md +++ b/issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md @@ -14,8 +14,7 @@ executed at CPL 0. Linux at `Ubuntu-6.8.0-142.142`, under the T14's `CONFIG_STRICT_KERNEL_RWX=y`, makes text and rodata read-only and everything else non-executable (`arch/x86/mm/init_64.c:1402-1447`), and under `CONFIG_DEBUG_WX=y` walks the tables for a writable and executable mapping at -boot (`arch/x86/mm/dump_pagetables.c:434`). Two rows of the hardening table in -`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`. +boot (`arch/x86/mm/dump_pagetables.c:434`). **Exit**: kernel text is mapped read-only and executable, rodata read-only and `NX`, and every other kernel mapping `NX`; each boot walks the kernel tables diff --git a/issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md b/issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md index 83a69b84690..8a03007abb6 100644 --- a/issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md +++ b/issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md @@ -17,8 +17,7 @@ pointer XORed with a per-cache secret and its own address (`mm/slub.c:479-490`), `CONFIG_SLAB_FREELIST_RANDOM` shuffles each slab's free list (`mm/slub.c:2228,2290`), and `CONFIG_RANDOM_KMALLOC_CACHES` spreads each size over 16 caches chosen by call site and a per-boot seed -(`include/linux/slab.h:340-341,398-401`). Three rows of the hardening table in -`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`. +(`include/linux/slab.h:340-341,398-401`). **Exit**: a free-list link is stored encoded with a per-boot secret and checked on every unlink, a size class's allocation order is drawn per boot, diff --git a/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md b/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md new file mode 100644 index 00000000000..ec7a9c7d8d7 --- /dev/null +++ b/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md @@ -0,0 +1,114 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# The kernel is at least as secure as Linux on the T14 + +Owner ruling: parity with the Linux the T14 +(`issues/hardware/the-t14-boots-toyos-unattended.md`) runs is the floor, and +the T14 also gets every security feature its CPU and platform support. That +Linux is tag `Ubuntu-6.8.0-142.142` (53e5d07aac028a1523ab0b115f079d6d1bc831ef) +of `https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/noble`, +config sha256 3b8533dd9d235ca634ac58f82c5ce1ee35f12ef620693e17033184d2c9ca5890. +A hardening default its config sets and no vulnerabilities line reports is +closed by the stage naming it or by a defect the Exit names; ToyOS already +meets `INIT_ON_ALLOC_DEFAULT_ON`, `SCHED_STACK_END_CHECK`, `HARDENED_USERCOPY` +and `X86_UMIP`, Rust meets `INIT_STACK_ALL_ZERO`, `FORTIFY_SOURCE` and +`UBSAN_*`, ToyOS has no modules, kexec, BPF or vsyscall page, and +`SHUFFLE_PAGE_ALLOCATOR` is off by default. A QEMU test asserts wiring, S1 +over the facts the guest reports. A probe is a `boot-actuators` arm or a +`test-actuators` `SYS_DEBUG` action, never a syscall. A stage's oracle is the +T14's CPU unless it names another. + +- **S0 — Evidence.** Exit: the T14's and the TCG model's captures under that + Linux, committed as S1's fixtures, and no Linux image; before the wipe it + adds CPUID 5, 0x19 and 0x80000001, MSR 0xCF, the split-lock line and the + config's IBT and PKU options. Mutation: a config hash off by one byte is + refused. Oracle: that Linux. Ubuntu leaves the T14 only after this and P0 of + `issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`. +- **S1 — The decision**, host-tested, from a CPU's facts to each + vulnerabilities line and mitigation. Exit: S0's facts give S0's lines. + Mutation: `GDS` deleted from `cpu_vuln_blacklist`'s TIGERLAKE_L row. + Oracle: S0's lines. +- **S2 — SPEC_CTRL and GDS.** Exit, T14: every CPU's 0x48 is S0's read less + SSBD, and a probe sets `GDS_MITG_DIS` and reads it clear after the kernel's + write. Mutation: the clear deleted. Oracle: S0's reads. +- **S3 — BHB clear, RSB fill, IBPB conditional on S6's flag.** Exit: a gate + matches `kernel.elf` against `clear_bhb_loop` and `__FILL_RETURN_BUFFER`; + probes count a clear per syscall and two IBPBs over B, C, idle, B, A, idle, + A, B on the T14, and a fill per switch under TCG. Mutation: either sequence + edited, the clear's condition inverted, no fill, IBPB decided by the + previous root. Oracle: Linux's sequences. +- **S4 — Spectre v1**: SMAP required, `lfence` and mask at `user_ptr`'s range + checks. Exit: a boot without SMAP is refused by name; on the T14 a gadget + through each site leaks a planted byte in at most 16 of 1000 trials. + Mutation: SMAP optional; a site's fence or mask gone must exceed 16. +- **S5 — Thunks for every indirect branch and return, and `SLS`.** Exit: a + gate finds no raw indirect branch or `ret` outside thunks and entry, `int3` + after each there, each ITS thunk's branch at `addr & 63 >= 32`; boots + compare live thunks with S1's. Mutation: a branch at a line start, an `int3` + gone, the ITS thunk everywhere. Oracle: `indirect-target-selection.rst`. +- **S6 — SSBD per program flagged in `system.toml`**, inherited at spawn. + Exit, T14: it reads clear, set, and set in a flagged process's child. + Mutation: no inheritance. +- **S7 — Microcode loading, the owner's**: it is firmware run on the CPU, + which root `CLAUDE.md` does not carve out. Exit: S0 shows the BIOS at + Linux's fixing revision, or the owner rules. +- **S8 — User ASLR, `ARCH_MMAP_RND_BITS`.** Exit: over 256 spawns each claimed + bit of the three bases is set 88 to 168 times. Mutation: `BASE + n * 2 + MiB`, a constant seed. Oracle: Linux's 32 bits for image and mmap and 22 + for the stack; a shortfall is a defect. +- **S9 — `STACKPROTECTOR_STRONG`** at `%gs:N`, by LLVM and rustc changes the + orchestrator admitted as upstream-quality cross-platform options. Exit: + `stack-protector-3.ll` and a rustc assembly test see `%gs:` and no + `__stack_chk_guard`; `kernel_stack_canary` panics on B's guard in A's + frame. Mutation: the old lowering, the flags dropped, `context_switch`'s + write gone, a constant guard. Oracle: FileCheck, and the CPU's compare. +- **S10 — `RANDOMIZE_BASE`, `RANDOMIZE_MEMORY`, `Tier::Weekly`.** Exit: 64 + boots set each claimed bit 12 to 52 times, S9's guard and S8's first spawn + included. Mutation: a fixed base. Oracle: Linux's at most 9 bits of text + slot and a PUD-granular direct map. +- **S11 — `X86_USER_SHADOW_STACK`.** Owner ruling: the loader refuses every + program and library without `GNU_PROPERTY_X86_FEATURE_1_SHSTK`, on every + CPU. Exit: `unmarked_object_refused` under TCG; a sysroot link with an + unmarked input reds; on the T14 a forged return is `#CP` in two threads, a + caught panic unwinds, a store to the shadow stack is `#PF`, and `user_ptr` + refuses a `read` into it with `BadAddress`. Mutation: the check gone, + `SH_STK_EN` clear, one shadow stack for two threads, no `incssp`, the stack + mapped writable or faulted in as CoW. +- **S12 — `X86_KERNEL_IBT`**, unset in the config. Exit: a gate finds + `endbr64` at every IDT and `IA32_LSTAR` target and no `notrack`; on the T14 + a call to a function without one is `#CP`. Mutation: `syscall_entry`'s + `endbr64` gone, `ENDBR_EN` clear. +- **S13 — Kernel shadow stack**, which Linux lacks; CET_SSS, CPUID.(7,1):EDX + bit 18. Exit, T14: a forged kernel return is `#CP`, `kernel_stack_canary` + runs under it, a `DirectMap` store to a shadow stack faults. Mutation: + `SH_STK_EN` clear, SSP not switched, the frame in the writable direct map. +- **S14 — `X86_INTEL_MEMORY_PROTECTION_KEYS`**, after P1; owner ruling: its + ABI is approved in principle. Exit, TCG `+pku` and T14: a write under a key + the thread denied is `#PF` with PK, a sibling's is not, and `window` refuses a + `read` into it. Mutation: no key in the entry, one PKRU for all threads, no + key check in `window`. Oracle: TCG and the T14 on SDM Vol. 3A §5.6.2. +- **S15 — Key Locker**, after the speed track's Pin; CPUID.19H:EBX bits 0 and + 4, ECX bit 1. Exit, T14: a handle wrapped on one pinned CPU gives FIPS-197 + C.1's ciphertext on another. Mutation: an IWKey per CPU. Oracle: FIPS-197. +- **S16 — Split-lock disable**, Linux's default without a config option; a + split lock ends a ToyOS process where Linux warns. Exit, T14: a `lock add` + across a line is ended by name. Mutation: `MSR_MEMORY_CTRL` bit 29 clear. + +**Exit.** The T14's ToyOS boot prints S0's Linux line for each +vulnerabilities file, less `spectre_v1`'s swapgs barriers while ToyOS runs +no `swapgs` and `spectre_v2`'s VM-exit clauses, since it runs no guest; +`spec_store_bypass` reads "Mitigation: Speculative Store Bypass disabled per +program". Mutation: ARCH_CAPABILITIES read as 0. Every stage is green or +closed, and so is every defect the hardening defaults name: +`issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md`, +`issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md`, +`issues/kernel/kernel-functions-return-with-their-used-registers-intact.md`, +`issues/kernel/a-threads-kernel-stack-has-no-guard-page.md`, +`issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md`, +`issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md`, +`issues/kernel/tsx-stays-as-firmware-left-it.md`, +`issues/kernel/a-device-without-a-domain-of-its-own-reaches-all-memory.md`. diff --git a/issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md b/issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md deleted file mode 100644 index 51e152bdd2b..00000000000 --- a/issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md +++ /dev/null @@ -1,566 +0,0 @@ ---- -status: open -kind: track -opened: 2026-09-29 ---- - -# The kernel mitigates what Linux mitigates on the T14 - -Owner ruling: ToyOS also needs to be at least as secure as Linux on the same -hardware. The hardware is the T14 (`issues/hardware/the-t14-boots-toyos-unattended.md`), -an i5-1135G7, Tiger Lake, family 6 model 0x8C -(`issues/hardware/the-t14-touchpad-is-i2c-hid-and-unbuilt.md`). The Linux is -the kernel the T14 runs, Ubuntu's 6.8.0-142-generic. Its source is tag -`Ubuntu-6.8.0-142.142` (commit 53e5d07aac028a1523ab0b115f079d6d1bc831ef) of -`https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/noble`, -where every Linux `path:line` here is read; `bugs.c` and `common.c` are in -`arch/x86/kernel/cpu/`. Its config is `/boot/config-6.8.0-142-generic` from -`linux-modules-6.8.0-142-generic_6.8.0-142.142_amd64.deb`, sha256 -3b8533dd9d235ca634ac58f82c5ce1ee35f12ef620693e17033184d2c9ca5890. The -scoreboard is that kernel's `/sys/devices/system/cpu/vulnerabilities/*` lines -on the T14, and the hardening table below. - -## Hardening defaults - -Parity with the pinned Ubuntu kernel is the floor, and the T14 also gets every -security feature its CPU and platform support. A hardening default is an -option the config sets that, under the default command line, makes an attack -on the kernel or a process harder and that no vulnerabilities line reports; access policy (the LSMs, lockdown, -`*_RESTRICT`, `STRICT_DEVMEM`) is the capability model's. `CONFIG_SLS` is the -one entry of -the `CPU_MITIGATIONS` menu (`arch/x86/Kconfig:2475-2664`) that no line -reports. Numbers are the config's lines; each row is closed by its stage, its -defect, the ToyOS mechanism named, or the reason it does not apply. A row the -config leaves unset names the stage that goes past it. - -| Option | Disposition | -|---|---| -| `RANDOMIZE_BASE` (528) | S10 | -| `RANDOMIZE_MEMORY` (532) | S10 | -| `ARCH_MMAP_RND_BITS=32` (909) | S8 | -| `STACKPROTECTOR_STRONG` (882) | S9 | -| `SLS` (564) | S5 | -| `X86_USER_SHADOW_STACK` (502) | S11 | -| `X86_KERNEL_IBT` (496), unset | S12 | -| `X86_INTEL_MEMORY_PROTECTION_KEYS` (497) | S14 | -| `RESET_ATTACK_MITIGATION` (2457) | `issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md` | -| `RANDOMIZE_KSTACK_OFFSET_DEFAULT` (933) | `issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md` | -| `ZERO_CALL_USED_REGS` (11477) | `issues/kernel/kernel-functions-return-with-their-used-registers-intact.md` | -| `VMAP_STACK` (930) | `issues/kernel/a-threads-kernel-stack-has-no-guard-page.md` | -| `STRICT_KERNEL_RWX` (935) | `issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md` | -| `DEBUG_WX` (12074) | `issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md` | -| `SLAB_FREELIST_RANDOM` (1132) | `issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md` | -| `SLAB_FREELIST_HARDENED` (1133) | `issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md` | -| `RANDOM_KMALLOC_CACHES` (1136) | `issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md` | -| `X86_INTEL_TSX_MODE_OFF` (498) | `issues/kernel/tsx-stays-as-firmware-left-it.md` | -| `INTEL_IOMMU_DEFAULT_ON` (9892) | `issues/kernel/a-device-without-a-domain-of-its-own-reaches-all-memory.md` | -| `INIT_ON_ALLOC_DEFAULT_ON` (11474), pages | `pmm::alloc_page` and `alloc_contiguous` zero every page they hand out (`kernel/src/mm/pmm.rs:280-282,318-320`) | -| `SCHED_STACK_END_CHECK` (12084) | every scheduler pass panics on a running thread whose stack-end word changed (`kernel/src/sched/driver.rs:521,592,925-935`), as `schedule_debug` does (`kernel/sched/core.c:5957-5958`) | -| `HARDENED_USERCOPY` (11376) | the kernel side of every user copy is a slice, a `T` or a ring run, whose extent its type carries, never a bare pointer and length (`kernel/src/user_ptr.rs:146-161,187-214,247-275`) | -| `X86_UMIP` (493) | `CR4_OPTIONAL` sets UMIP wherever CPUID offers it (`kernel/src/arch/x86_64/control_regs.rs:60,212`), as `setup_umip` does (`common.c:360-370`) | -| `INIT_ON_ALLOC_DEFAULT_ON` (11474), slab | not applicable: Rust reads no allocation before writing it | -| `INIT_STACK_ALL_ZERO` (11473) | not applicable: Rust reads no local before writing it, and `copy_out` copies only a `UserSafe` type, which has no padding (`kernel/src/user_ptr.rs:25-28`) | -| `FORTIFY_SOURCE` (11377) | not applicable: every Rust slice copy checks both lengths | -| `UBSAN_BOUNDS`, `_SHIFT`, `_BOOL`, `_ENUM` (12040-12045) | not applicable: each reports C undefined behaviour that safe Rust defines or refuses | -| `STRICT_MODULE_RWX` (937) | not applicable: ToyOS loads no code into the kernel | -| `LEGACY_VSYSCALL_XONLY` (536) | not applicable: ToyOS maps no vsyscall page | -| `SHUFFLE_PAGE_ALLOCATOR` (1139) | not applicable: Linux shuffles only under `page_alloc.shuffle=1` (`mm/shuffle.c:12-30`) | -| `BPF_JIT_ALWAYS_ON` (124) | not applicable: ToyOS has no BPF | -| `MODULE_SIG` (982) | not applicable: ToyOS loads no modules | -| `KEXEC_SIG` (318) | not applicable: ToyOS has no kexec | - -## What is true today - -The kernel writes no CPU-vulnerability mitigation: no access to -`IA32_SPEC_CTRL` (0x48), `IA32_PRED_CMD` (0x49), `IA32_ARCH_CAPABILITIES` -(0x10A) or `IA32_FLUSH_CMD` (0x10B) anywhere in `kernel/src/`, no `lfence` -speculation barrier, no `verw` buffer clear, no retpoline or return-thunk -codegen flag. It executes no `swapgs`: GS holds kernel per-CPU data -permanently (`kernel/src/arch/x86_64/syscall.rs`, above `syscall_entry`) and -`FSGSBASE` is `CR4_FORBIDDEN` (`kernel/src/arch/x86_64/control_regs.rs`). -SMEP, SMAP and UMIP are taken only when offered (`CR4_OPTIONAL`, same file). -Every user process loads at `USER_VM_BASE` (`kernel/src/loader/mod.rs`) with -its stack directly under the image (`kernel/src/vma.rs`, `ALLOC_CEILING = -STACK_BASE`) and its mmap window at fixed bounds (`vma.rs`, `WINDOW`), and -`rebase_base` (`toyos-userbound/src/span.rs`) takes no random input. The -direct map sits at the fixed `PHYS_OFFSET` (`kernel/src/mm/mod.rs`) and the -kernel image at `PHYS_OFFSET` plus wherever firmware allocated it -(`bootloader/src/main.rs`): nothing draws either. The kernel target is -`x86_64-unknown-none` with no stack-protector or `cf-protection` flag -(`kernel/.cargo/config.toml`). `CR4.CET`, `CR4.PKE`, `CR4.KL` and -`CR4.OSXSAVE` are in no declaration (`control_regs.rs`), nothing writes -`IA32_S_CET`, `IA32_U_CET` or `MSR_MEMORY_CTRL`, and a thread's saved user -state is `FXSAVE64`'s 512 bytes (`kernel/src/arch/x86_64/fpu.rs`). - -## Stages - -System-mode TCG enumerates none of SPEC_CTRL, ARCH_CAPABILITIES and SSBD -(`target/i386/cpu.c` at QEMU v11.1.1: `CPUID_7_0_EDX_KERNEL_FEATURES` is 0 -outside `CONFIG_USER_ONLY`), nor BHI_CTRL (`TCG_7_2_EDX_FEATURES`). The -nightly's `guest` and `audio` shards run KVM with `-cpu host` -(`.github/workflows/nightly.yml`, `src/arch.rs` `Arch::cpu`), so there the -branches gated on those bits run on whatever CPU the runner has. A QEMU test -therefore asserts wiring only: what the guest applied equals S1 applied to -the facts the guest itself reports on a `boot-actuators` line. Independence -comes from S1's T14 fixture and the T14 run, never from KVM. TCG enumerates -PKU and none of the bits S11–S13 and S15–S17 read (`TCG_7_0_ECX_FEATURES`, -`target/i386/cpu.c:992-995`; `TCG_7_0_EDX_FEATURES`, `:1003`), so those run -on the T14 alone. - -- **S0 — Evidence.** On the T14 under its stock Ubuntu boot, as root: - - ``` - apt-get install -y msr-tools cpuid busybox-static cpio && modprobe msr - cat /proc/version /proc/cmdline /proc/sys/vm/mmap_rnd_bits - dpkg-query -W linux-image-6.8.0-142-generic linux-modules-6.8.0-142-generic - sha256sum /boot/config-6.8.0-142-generic - grep . /sys/devices/system/cpu/vulnerabilities/* - grep microcode /proc/cpuinfo - cpuid -r -l 1; cpuid -r -l 7 -s 0; cpuid -r -l 7 -s 2 - cpuid -r -l 0x80000000; cpuid -r -l 0x80000008; cpuid -r -l 0x80000021 - cpuid -r -l 5; cpuid -r -l 7 -s 1; cpuid -r -l 0xd -s 0; cpuid -r -l 0xd -s 1 - cpuid -r -l 0x19; cpuid -r -l 0x80000001 - dmesg | grep -e 'x86/tme' -e 'x86/split lock detection' - rdmsr -a 0x10a; rdmsr -a 0x48; rdmsr -a 0x123 - mkdir -p rd/bin rd/sys rd/proc && cp /usr/bin/busybox rd/bin/ - printf '#!/bin/busybox sh\n/bin/busybox mount -t sysfs s /sys\n/bin/busybox mount -t proc p /proc\n/bin/busybox cat /proc/version\n/bin/busybox grep . /sys/devices/system/cpu/vulnerabilities/*\n/bin/busybox poweroff -f\n' > rd/init && chmod +x rd/init - (cd rd && find . | cpio -o -H newc) > s0.cpio && cp /boot/vmlinuz-6.8.0-142-generic . - ``` - - and `rdmsr -a 0x122` where 0x10A bit 7 (TSX_CTRL_MSR) is set, and `rdmsr -a - 0x10f` where CPUID.(7,0):EDX bits 11 and 13 (RTM_ALWAYS_ABORT, - TSX_FORCE_ABORT, `arch/x86/include/asm/cpufeatures.h:422-423`) are, - `rdmsr -a 0x982` where CPUID.(7,0):ECX bit 13 (TME, `cpufeatures.h:399`) is, - and `rdmsr -a 0xcf` where CPUID.(7,0):EDX bit 30 (CORE_CAPABILITIES, - `cpufeatures.h:438`) is. `/proc/cpuinfo`'s `microcode` is the revision as - Linux reads it (`arch/x86/include/asm/microcode.h:62-75`). On the development host, whose - QEMU is the one `.github/qemu-version` pins, `qemu-system-x86_64 --version` - and then `qemu-system-x86_64 -nodefaults -machine q35 -cpu - qemu64,+rdrand,+smap,+fsgsbase,+x2apic,+smep -smp 2 -m 4G -kernel - vmlinuz-6.8.0-142-generic -initrd s0.cpio -append "console=ttyS0 panic=-1" - -serial stdio -display none -no-reboot` capture the TCG model's lines. S0 - builds ToyOS's `boot-actuators` facts line, printed on the T14 and on the TCG - model: the same CPUID leaves, 0x10A, and 0x48 and 0x123 as read before the - kernel's first write to either. The capture is refused unless `/proc/version` - names 6.8.0-142, both packages are 6.8.0-142.142 and the config's sha256 is - the one above. The capture is one-time: the kernel - image, `s0.cpio` and busybox are never committed and no build or test boots - them. **Exit**: the captured text outputs committed as S1's fixtures. Ubuntu - is wiped from the T14 only after that commit and P0's of - `issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`. -- **S1 — The decision, a host-tested function.** A pure function, in a crate - the kernel and a host test both build, maps (vendor, family, model, - stepping, microcode revision, CPUID.1, CPUID.(7,0), CPUID.(7,2), - CPUID.0x80000008:EBX, CPUID.0x80000021:EAX, ARCH_CAPABILITIES) to each - vulnerability's Linux line and the mitigation ToyOS applies. The two - extended leaves are read where CPUID.0x80000000:EAX reaches them, as - `get_cpu_cap` does (`common.c:1072-1084`), and carry the AMD bits - `init_speculation_control` folds into IBRS, IBPB, STIBP and SSBD - (`common.c:994-1011`); the TCG model is AuthenticAMD. It carries `cpu_vuln_whitelist` and `cpu_vuln_blacklist` - (`common.c:1182-1344`), `cpu_set_bug_bits` (`common.c:1414-1578`), - `spectre_bad_microcodes` (`arch/x86/kernel/cpu/intel.c:141-163`) and - `bugs.c`'s selections under the default command line and the pinned config. - CPUID.(7,0):EDX bit 26 is SPEC_CTRL (IBRS and IBPB), 27 STIBP, 29 - ARCH_CAPABILITIES and 31 SSBD (`arch/x86/include/asm/cpufeatures.h:434-439`), - and CPUID.(7,2):EDX bit 4 is BHI_CTRL (`arch/x86/kernel/cpu/scattered.c:31`); - the kernel reads 0x10A only when bit 29 is set, as `x86_read_arch_cap_msr` - does (`common.c:1353-1361`), since the read is `#GP` otherwise. **Exit**: - host tests feed S0's T14 facts and get S0's T14 lines, and feed the TCG - model's facts and get the TCG model's lines. Negative control: deleting - `GDS` from the TIGERLAKE_L blacklist row (`common.c:1312`) reds the T14 - case. That match is the only way `X86_BUG_GDS` is set (`common.c:1521-1523`), - and without the bug `cpu_show_common` answers "Not affected" - (`bugs.c:3308-3309`). -- **S2 — SPEC_CTRL and GDS.** The per-CPU base of `IA32_SPEC_CTRL` is declared - once with the control registers and asserted by `self_check` on every CPU. - It is S1's whole `x86_spec_ctrl_base`: every bit `bugs.c` ORs into it, under - S1's conditions for each (`RRSBA_DIS_S` at 1736, `BHI_DIS_S` at 1800, `IBRS` - at 1934, `SSBD` at 2224). S6's SSBD is the one bit a context switch - changes, so the assertion is `SPEC_CTRL & !SSBD == base`. Where S1 finds GDS - and ARCH_CAPABILITIES.GDS_CTRL, `IA32_MCU_OPT_CTRL.GDS_MITG_DIS` is cleared - and read back and `GDS_MITG_LOCKED` is never written, as `update_gds_msr` - does (`bugs.c:777-812`); a lock firmware set is reported as Linux reports it, - "Mitigation: Microcode (locked)" (`bugs.c:850-861`). **Exit**, T14: on every - CPU 0x48 reads the declared base, which equals S0's Linux read of 0x48 with - SSBD masked; a `boot-actuators` arm sets `GDS_MITG_DIS` on every CPU before - the kernel's GDS write and reads it clear after, so deleting the clear - leaves it set and reds it. If S0 finds `GDS_MITG_LOCKED` set, the arm cannot - set it and S0's fixture says so. On KVM the read-back equals S1's base over - the reported facts. -- **S3 — The boundaries.** The branch history is cleared in software on - syscall entry where S1 finds BHI and no BHI_CTRL (`bugs.c:1831-1858`, - `arch/x86/entry/entry_64.S:119`), and S2's BHI_DIS_S replaces the loop where - BHI_CTRL is present; Tiger Lake has eIBRS without BHI_CTRL, so the T14 takes - the loop. The RSB is filled on context switch where S1 selects retpoline, - LFENCE or IBRS mode and never under eIBRS (`bugs.c:1741-1789`, - `entry_64.S:205`). IBPB is conditional (Decisions). Each sequence is - Linux's: the clear is `clear_bhb_loop`, five outer passes of five inner - branches and then `lfence` (`entry_64.S:1534-1569`), and the fill is - `__FILL_RETURN_BUFFER` with `RSB_CLEAR_LOOPS`, 32 calls each followed by - `int3` and then `lfence` (`arch/x86/include/asm/nospec-branch.h:132,137-162`). - **Exit**: a gate over `kernel.elf` decodes both sequences at the symbols it - names and compares each decoded instruction — opcode, immediate and - normalised relative target — against `clear_bhb_loop` - (`entry_64.S:1534-1569`) and `__FILL_RETURN_BUFFER` under `RSB_CLEAR_LOOPS` - (`nospec-branch.h:132-162`), excluding `clear_bhb_loop`'s `.align 64, 0xcc` - (`entry_64.S:1540,1549`), whose bytes depend on where the linker places the - function, and `ASM_CREDIT_CALL_DEPTH` (`nospec-branch.h:161`), which exists - only under `CALL_DEPTH_TRACKING`, a mitigation ToyOS has no counterpart for: - deleting `3: jmp 4f`/`nop` from the inner loop - (`entry_64.S:1558-1560`), deleting the `int3` `__FILL_RETURN_SLOT` places - after each fill `call` (`nospec-branch.h:137-141`), or flattening the `call - 1f`/`call 2f`/`RET` nesting into direct `jmp`s each reds it. A - `boot-actuators` per-thread counter the clear sequence increments advances - by exactly 1000 over one thread's 1000 syscalls where S1 selects the loop, - the T14, and by 0 where it does not; inverting the runtime condition gives 0 - on the T14 and reds it. A `boot-actuators` count of RSB fills over a probe's - context switches equals the switch count where S1 over the reported facts - selects a filling mode and 0 otherwise; the TCG model is in retpoline mode - (`common.c:1231` lacks NO_SPECTRE_V2, and AUTO without eIBRS or RETBLEED - takes retpoline, `bugs.c:1878-1895`), so dropping the fill reds it there. - The IBPB decision is a pure function of the per-CPU last-user state and the - incoming process, host-tested on A→idle→B (IBPB when either is flagged) and - A→idle→A (none); deciding from the previous root instead, which on A→idle→B - is idle's kernel root (`kernel/src/arch/x86_64/hw.rs` activates one on every - switch), reds it. A `boot-actuators` arm drives B, C, idle, B, A, idle, A, B - through the switch path on one CPU with only A flagged and counts the writes - of `PRED_CMD_IBPB`, value 1, to `IA32_PRED_CMD` - (`arch/x86/include/asm/msr-index.h:61-62`): 2 (B→A, A→B) where S1 finds - IBPB, the T14, and 0 where it does not; dropping the write from the switch - path, or writing 0 in place of `PRED_CMD_IBPB`, gives 0 on the T14 and reds - it. -- **S4 — Spectre v1.** SMAP moves to the required set: the kernel refuses to - boot on an x86-64 CPU without it. With no `swapgs` executed and `FSGSBASE` - forbidden, Linux's own rule (`bugs.c:943-944`: `FSGSBASE || - !smap_works_speculatively()`) then owes no swapgs barrier. The usercopy - barrier and user-pointer sanitization go where the range is checked: an - `lfence` after `in_user_half` in `kernel/src/user_ptr.rs`'s `window` and - after `is_user_object` in its `object`, and the checked address masked to - the user half before `translate_user` walks it, as `barrier_nospec` in - `_copy_from_user` (`lib/usercopy.c:21`) and `mask_user_address` - (`arch/x86/include/asm/uaccess_64.h:64`) do. **Exit**: a standing guest test - boots without SMAP and asserts the refusal names SMAP; moving SMAP back to - `CR4_OPTIONAL` boots and reds it. The harness has one `-cpu` string per - accelerator (`src/arch.rs`, `Arch::cpu`), so the stage adds a per-test - override: that string without `+smap` under TCG, and `host,-smap` under KVM. On the T14 a - bounds-check-bypass gadget through each of the three sites recovers a byte - planted outside the user half in at most 16 of 1000 trials (chance is 1 in - 256; per-site false-red probability 7.6e-7, exact binomial tail). Each - site's mutation, its `lfence` or the mask deleted, must recover it in more - than 16, or that site is unmeasured and the stage is not done. -- **S5 — Indirect branches and returns.** Every indirect `call`/`jmp` goes - through `-Zretpoline-external-thunk` and every return through - `-Zfunction-return=thunk-extern` into the kernel's own thunks, whose body - is the one S1 selects: a retpoline, or for ITS an aligned thunk whose - branch's last byte lies in a cacheline's upper half - (`Documentation/admin-guide/hw-vuln/indirect-target-selection.rst:6-8,56-59`, - `arch/x86/lib/retpoline.S:371-403`), which the T14 takes - (`bugs.c:1222-1223,1313-1319`). The retpoline flag is a target modifier, so - the `x86_64-unknown-none` `core` and `alloc` that `src/toolchain.rs` builds - are built under it. Compiled code is then left with no raw `ret` or - indirect `jmp`, so SLS is owed in the kernel's own assembly, the thunks and - the entry code: every `ret` and indirect `jmp` there is followed by `int3`. - **Exit**: a gate over - `kernel.elf` finds no raw indirect `call`/`jmp` or `ret` outside the thunks - and the entry sequences it names by symbol, an `int3` after every `ret` and - indirect `jmp` there, and every aligned thunk's branch ending at `addr & 63 - >= 32`; placing a thunk's branch at a cacheline start, or deleting the `int3` - after one thunk's `ret`, reds it. Each boot reads its - live thunk bodies back and compares them with the body S1 selects over the - facts it reports: a `thunk_body` that answers the aligned thunk for every - input puts a bare `jmp *%reg` in the TCG model, whose selection is the - retpoline, and reds it. -- **S6 — Speculative Store Bypass.** `IA32_SPEC_CTRL.SSBD` is set while a - flagged process runs and clear otherwise, Linux's default (`bugs.c:2200-2202`: - the default command selects `SPEC_STORE_BYPASS_PRCTL`). The flag is one bit - in `SpawnArgs` on the existing `SYS_SPAWN` (`toyos-abi/src/syscall.rs`), set - by init from the program's `system.toml` entry and inherited by whatever a - flagged process spawns; it also marks the process for S3's IBPB. **Exit**, - T14: a `boot-actuators` probe logs `IA32_SPEC_CTRL.SSBD` as read on the first - switch into each process, and a guest test reads it clear for an unflagged - process, set for a flagged one, and set for a child a flagged process spawns - with the bit clear in its `SpawnArgs`; dropping the inheritance at spawn - clears the child's and reds it. On KVM the expected bits are S1's over the - reported facts. -- **S7 — Microcode loading. PARKED for the owner.** Gather Data Sampling and - some ITS variants are microcode-only fixes; Linux's coverage of them on the - T14 assumes the shipped BIOS carries microcode at or past the fixing - revision. Root `CLAUDE.md`'s dependency rule allows vendor firmware only - "loaded only by that device's own driver through its IOMMU domain; it never - executes on the CPU" — a CPU microcode update is firmware that *does* - execute on the CPU, the one case that rule does not carve out. This stage is - needed only if S0 finds the T14's shipped BIOS revision is below the - revision Linux's mitigation table requires; if S0 finds the BIOS already at - or past it, this stage is moot and is closed without being built. Either way - it is the owner's call, not this track's. -- **S8 — User-space ASLR.** The image base, the stack base and the mmap - window's base are each drawn per spawn from `arch::entropy::draw`; a draw - still `None` after `entropy::ATTEMPTS` refuses the spawn. Each base's entropy - is stated in bits against Linux's: `CONFIG_ARCH_MMAP_RND_BITS=32` for the - image and mmap bases (`fs/binfmt_elf.c:1127-1129`, `arch/x86/mm/mmap.c:77`), - 22 bits for the stack (`arch/x86/include/asm/elf.h:331`, `STACK_RND_MASK` - 0x3fffff pages). At 2 MiB alignment the 2^47-byte user half holds 2^26 - slots, so a base short of Linux's figure is filed as a defect with both - numbers. **Exit**: a guest test spawns one binary 256 times, each run - reporting its three bases from its own addresses; every claimed bit of every - base's slot index is set in between 88 and 168 runs (±5σ; per-bit false-red - probability 3.3e-7, exact binomial tail). `base = BASE + n * 2 MiB` leaves - every slot bit above bit 7 clear in all 256 runs and reds it. Each of S10's - 64 boots also prints its first spawn's three bases, bit-tested by S10's - rule; a constant-seeded generator repeats them every boot and reds it. -- **S9 — Kernel stack protector.** `-Zstack-protector=strong` for the kernel - and its `core` and `alloc` (`src/toolchain.rs`), every protected frame - loading and comparing a per-thread guard at `%gs:N`. Linux gets `%gs:40` - from a Linux triple under `-mcmodel=kernel` (`arch/x86/Makefile:169`, - `arch/x86/include/asm/stackprotector.h:9`). LLVM paths here are - `rust/src/llvm-project` at the commit `rust/` pins, a79bc52c1d5e. The - kernel's triple is `x86_64-unknown-none` (`kernel/.cargo/config.toml`), and - there X86 takes the segment slot only when `hasStackGuardSlotTLS` holds - (`llvm/lib/Target/X86/X86ISelLoweringCall.cpp:548-551,564`: glibc, musl, - Fuchsia, Android). Otherwise it falls through (`:604`, `:638-640`) to the - one global `__stack_chk_guard` - (`llvm/lib/CodeGen/TargetLoweringBase.cpp:2388-2411`), and the - `stack-protector-guard`, `-reg` and `-offset` module flags act only on - those four. No ToyOS-owned mechanism reaches the slot: X86's one - other lowering, `LOAD_STACK_GUARD`, is 64-bit Mach-O's alone - (`llvm/lib/Target/X86/X86ISelLowering.cpp:2770-2772`), and naming the - kernel a glibc or musl triple is a false claim about its environment. S9 is - four steps, each with its own test: - 1. **LLVM.** X86's `getIRStackGuard` takes the segment slot on any triple - whose module sets `stack-protector-guard` to `tls`, as RISC-V's does - (`llvm/lib/Target/RISCV/RISCVISelLowering.cpp:25703-25707`), and - `insertSSPDeclarations` then declares no global. Clang accepts - `-mstack-protector-guard=tls` and `-mstack-protector-guard-reg=gs` on - every x86 triple (`clang/lib/Driver/ToolChains/Clang.cpp:3479-3491, - 3561-3570`), and the backend lowers them to the global on a bare one, so - the change is an upstream fix. Test: RUN lines in - `llvm/test/CodeGen/X86/stack-protector-3.ll` for - `x86_64-unknown-none-elf` under `-code-model=kernel`, with `tls`, `gs` - and an offset, check `%gs:` and no `__stack_chk_guard`; the - unchanged lowering emits `__stack_chk_guard(%rip)` and reds them. - 2. **rustc**, which sets none of those flags today. - `-Zstack-protector-guard`, `-Zstack-protector-guard-reg` and - `-Zstack-protector-guard-offset` - (`compiler/rustc_session/src/options.rs`) set them in - `compiler/rustc_codegen_llvm/src/context.rs`, as Clang's - `clang/lib/CodeGen/CodeGenModule.cpp:1543-1553` does. Test: a - `tests/assembly-llvm/stack-protector/` test for `x86_64-unknown-none` - checks `%gs:` in prologue and epilogue and no - `__stack_chk_guard`; dropping the flags from `context.rs` reds it. - The orchestrator's ruling: root `CLAUDE.md`'s dependency rule governs — - "a fork carries a change written to upstream quality and goes when - upstream has it" — so a general cross-platform option written to - upstream quality is admitted when ToyOS needs it and upstream lacks it. - `src/forkcheck.rs` admits a cross-platform `rust/` file only for a - target arm at an existing dispatch site today; steps 1 and 2 each add a - cross-platform option instead, and the stage that lands them amends its - module header to admit exactly such an upstream-quality cross-platform - change. - 3. **The kernel.** `PerCpu` holds the guard at `N`, asserted at compile - time as `stackprotector.h:55` asserts 40. The kernel defines no - `__stack_chk_guard`, so a toolchain that falls back to the global fails - its link, and its `__stack_chk_fail` panics naming the stack protector. - A frame compares against the slot as it was on entry, so nothing changes - the slot under a live frame of the running thread - (`stackprotector.h:39-49`). `_start` (`kernel/src/arch/x86_64/boot.rs`) - writes the BSP's first `IA32_GS_BASE` and guard before - `call kernel_main`, where `percpu::init_bsp` writes the base from Rust - today, after the boot's first frames. A later write of the base carries - the slot's value over. An AP's `PerCpu` holds its first thread's guard - before the trampoline publishes it (`kernel/src/arch/x86_64/smp.rs`), as - `cpu_init_stack_canary` does (`stackprotector.h:66-69`, - `arch/x86/kernel/smpboot.c:969`). After that only `context_switch` - (`kernel/src/arch/x86_64/switch.rs`) writes the slot: the incoming - thread's own guard, after the stack switch, as `__switch_to_asm` does - (`arch/x86/entry/entry_64.S:193-196`). Each thread draws its guard from - `arch::entropy::draw` at creation; a draw still `None` after - `entropy::ATTEMPTS` refuses the thread, and `_start` halts on that bound. - 4. **Exit**: the guest test `kernel_stack_canary` is one boot with - `smp: 1`, so two threads share one slot. A `test-actuators` program's - threads A and B each call twice a `SYS_DEBUG` action whose frame holds a - local array, so it is protected, and which returns the `%gs:N` it reads - inside that frame; between its two calls each hands off to the other, - through a context switch. The test asserts each thread's two reads - agree and A's differ from B's. A then calls an action that writes a - given value over its own frame's guard through an out-of-bounds write - past that array. - Given A's read, it returns, so the frame compares against what `%gs:N` - held. Given B's read, the kernel panics naming the stack protector, the - boot's last event. Deleting `context_switch`'s write of the incoming - thread's guard leaves one value in the slot for both threads: A's and - B's reads agree and the overflow with B's guard returns, and both red. - Each of S10's 64 boots prints the guard `_start` drew, and S10's rule - holds for each of its 64 bits; a constant guard sets every bit in 0 or - 64 boots and reds it. -- **S10 — Kernel ASLR, `Tier::Weekly` (`src/tiers.rs`).** Its first step - times one `boot-actuators` boot of the TCG model and records 64 times that as - the weekly cost. The loader, which builds the mapping the kernel starts in, - draws the kernel image's virtual base and the direct map's base per boot - and refuses the boot when its draw fails; the kernel receives both in its - boot information, and `PHYS_OFFSET`'s two declarations - (`kernel/src/mm/mod.rs`, `bootloader/src/main.rs`) become that one - handed-over value. Each base's bits are stated against Linux's: - `CONFIG_RANDOMIZE_BASE` puts the text in a 2 MiB slot of `KERNEL_IMAGE_SIZE` - = 1 GiB (`arch/x86/include/asm/page_64_types.h:95-96`, at most 9 bits), and - `CONFIG_RANDOMIZE_MEMORY` draws `page_offset_base` at PUD granularity - (`arch/x86/mm/kaslr.c:146`). **Exit**: 64 QEMU boots each print both bases - on a `boot-actuators` line; every claimed bit is set in between 12 and 52 of - them (per-bit false-red probability 1.0e-7, exact binomial tail); a fixed - base reds it. - -S11–S17 go past the config where it stops. Intel places CET and Key Locker in -Tiger Lake as a family (SDM 325462-093US, Vol. 1 Table 5-2), and TME, CET and -Key Locker in the 11th-generation family (datasheet 631121-012, -§2.3.13-2.3.15), never in the i5-1135G7 by name, and names no Tiger Lake part -for PKU or split-lock disable. So each stage's first step confirms its bit in -S0's capture, and a bit S0 finds clear closes the stage. - -- **S11 — User shadow stacks.** First, CPUID.(7,0):ECX bit 7 (SHSTK, - `cpufeatures.h:393`); the datasheet enables either ring's shadow stack on its - own (§2.3.14.1). As `CONFIG_X86_USER_SHADOW_STACK` does: `CR4.CET` joins the - declaration (it needs `CR0.WP`, SDM Vol. 3A §5.1.3), the kernel maps each - thread a shadow stack as it creates the thread (`shstk_alloc_thread_stack`, - `arch/x86/kernel/shstk.c:195`) in shadow-stack pages, read-only and dirty in - the leaf and writable above it (SDM Vol. 3A §5.6.1), and a thread's - `IA32_U_CET` (0x6A0, `SH_STK_EN` bit 0) and `IA32_PL3_SSP` (0x6A7) - (`arch/x86/include/asm/msr-index.h:478-480,493`) switch with it as XSAVES's - CET_U component (`arch/x86/include/asm/fpu/types.h:120`), so it waits on P1 - of `issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`. - Where Linux lets each process choose (`shstk_prctl`, `shstk.c:548`), every - ToyOS program is built with `-Zcf-protection=return` - (`rust/compiler/rustc_session/src/options.rs:2377` at the `rust/` commit, - 1b236638), and on a CPU with shadow stacks the loader refuses an object whose - `.note.gnu.property` lacks `GNU_PROPERTY_X86_FEATURE_1_SHSTK`. Two paths - leave a frame other than by `RET` and must pop it: std's unwinder, - `unwinding` 0.2.10 (`rust/library/Cargo.lock`), whose source has no - `incssp`, and libc's `longjmp` (`userland/libc/src/misc.rs`). A shadow stack - costs its thread a 2 MiB page until - `issues/kernel/process-memory-is-2-mib-pages-and-that-caps-the-process-count.md` - lands. **Exit**, T14: a `test-actuators` program writes a planted - function's address over its return address and returns, in its first thread - and in a second, and is ended naming `#CP` NEAR-RET (error code 1, SDM Vol. - 3A §7.15, Event 21); a caught panic in it returns normally. `SH_STK_EN` - left clear lets the forged return reach the planted function, which says so - and reds it; the second thread handed the first's shadow stack reds its - first return; the unwinder without its `incssp` reds the panic. The oracle - is the T14's CPU. -- **S12 — Kernel IBT**, which the config leaves unset (496) and upstream's - Kconfig defaults on (`arch/x86/Kconfig:1840-1842`). First, CPUID.(7,0):EDX - bit 20 (IBT, `cpufeatures.h:429`). `-Zcf-protection=branch` for the kernel - and the `core` and `alloc` `src/toolchain.rs` builds. SYSCALL and every - event leave the ring-0 tracker waiting for an `endbr64` (SDM Vol. 1 - §18.3.3.1), so `syscall_entry` and every IDT stub begin with one, as - `entry_SYSCALL_64` does (`arch/x86/entry/entry_64.S:89`). `IA32_S_CET` - (0x6A2) holds `ENDBR_EN` (bit 2), declared with `CR4.CET` and asserted on - every CPU, as `setup_cet` writes it (`common.c:587-592`); `NOTRACK_EN` - stays clear, so the kernel has no jump table (`arch/x86/Makefile:73-83`). - **Exit**: a gate over `kernel.elf` finds `endbr64` at every symbol the IDT - and `IA32_LSTAR` name and no `notrack`-prefixed branch; deleting the - `endbr64` from `syscall_entry` reds it. On the T14 a `boot-actuators` - indirect call to a function with no `endbr64`, as `ibt_selftest` makes - (`arch/x86/kernel/ibt_selftest.S:6-17`), panics naming `#CP` ENDBRANCH - (error code 3), the boot's last event; `IA32_S_CET` declared without - `ENDBR_EN` lets the call return and reds it. The oracle is the T14's CPU. -- **S13 — Kernel shadow stack**, which Linux does not build: its supervisor - CET state is `XFEATURE_CET_KERNEL_UNUSED` (`fpu/types.h:121`). S11's bit - enumerates it. `SH_STK_EN` joins S12's `IA32_S_CET`. Each thread's kernel - stack gets a shadow stack topped by a supervisor shadow-stack token (SDM - Vol. 1 §18.2.3). SYSCALL sets SSP to 0 at ring 0 (SDM Vol. 2B, SYSCALL), so - `syscall_entry` takes the thread's from `IA32_PL0_SSP` (0x6A4) with - `SETSSBSY` and frees it with `CLRSSBSY` before `sysretq`; IST entries take - theirs through `IA32_INT_SSP_TAB` (0x6A8, `msr-index.h:490-494`); - `context_switch` moves SSP with `SAVEPREVSSP` and `RSTORSSP` (SDM Vol. 1 - §18.2.5). A shadow-stack page is protected only through its own mapping - (SDM Vol. 3A §5.6.1), so its frame leaves the direct map's writable 2 MiB - leaves, the split `issues/kernel/a-threads-kernel-stack-has-no-guard-page.md` - needs too. **Exit**, T14: a `boot-actuators` frame writes a planted - function's address over its return address and returns, and the kernel - panics naming `#CP` NEAR-RET; `IA32_S_CET` without `SH_STK_EN` reaches the - planted function, which reds it. S9's `kernel_stack_canary` boot runs with - kernel shadow stacks, and a `context_switch` that leaves SSP where it was - `#CP`s at the first return after a switch and reds it. The oracle is the - T14's CPU. -- **S14 — User protection keys.** First, CPUID.(7,0):ECX bit 3 (PKU, - `cpufeatures.h:389`): Table 5-2 introduces PKU with Comet Lake and names no - Tiger Lake part. `CR4.PKE` joins the declaration, as `setup_pku` sets it - (`common.c:506-515`); PKRU is per thread and an XSAVE component, so it - waits on P1. A process allocates a key and puts a mapping under it, as - `pkey_alloc` and `pkey_mprotect` do (`mm/mprotect.c:836-872`); that is an - ABI change, discussed with the owner before the stage starts. The key is - the leaf's bits 62:59 (SDM Vol. 3A §5.6.2). **Exit**, under TCG with `+pku` - and on the T14: a thread that denies itself writes to a key with `WRPKRU` - and writes a page under it is ended naming a page fault with PK set (bit 5, - SDM Vol. 3A §5.7), and another thread of the process writes the same page. - No key written into the entry lets the first write through and reds it; a - PKRU not switched per thread faults the second and reds it. TCG and the T14 - are two implementations of §5.6.2. -- **S15 — Key Locker**, which no `arch/x86` file at the pinned tag names. - First, CPUID.(7,0):ECX bit 23 (KL, Intel Key Locker Specification - 343965-001US §1.3). `CPUID.19H:EBX[0]` (AESKLE) reads 1 only once `CR4.KL` - is set and firmware has enabled Key Locker (§1.3), so ToyOS's first boot - with `CR4.KL` declared prints it; a 0 there closes the stage unless the - T14's setup enables it, which is the owner's. As §5.1 has it, the BSP loads - a random IWKey with `LOADIWKEY`, copies it out with - `IA32_COPY_LOCAL_TO_PLATFORM` and every AP copies it in with - `IA32_COPY_PLATFORM_TO_LOCAL` (§4.2-4.3), so a handle works on every CPU, - and no process runs with `CR4.KL` unless that succeeded. No ToyOS program - holds a long-lived AES key yet, so the test is the only user until one - does. **Exit**, T14: a program wraps FIPS-197 Appendix C.1's key with - `ENCODEKEY128` on one CPU and encrypts that appendix's plaintext with - `AESENC128KL` on another, getting its ciphertext; each CPU loading its own - random IWKey fails the handle on the second CPU (ZF set) and reds it. - FIPS-197 is the oracle. -- **S16 — TME, read back.** Firmware enables and locks it (datasheet - §2.3.13), and its availability varies by processor line (§1.3); Linux only - reports it and disables MKTME when CPUs disagree (`detect_tme_early`, - `arch/x86/kernel/cpu/intel.c:204-234`). First, CPUID.(7,0):ECX bit 13 and - 0x982 from S0; TME present but not enabled is the owner's to turn on in the - T14's setup. ToyOS reads `IA32_TME_ACTIVATE` (0x982) on every CPU, prints - it, and refuses the boot by name when two CPUs disagree. **Exit**, T14: - every CPU reads enabled and locked (bits 1 and 0, `intel.c:187-188`), - matching S0's `x86/tme:` line; a `boot-actuators` arm reporting cpu1's value - with bit 1 flipped is refused, and deleting the comparison boots it and reds - it. -- **S17 — Split-lock disable**, Linux's default with no config option: - `sld_state_setup` takes `sld_warn` (`intel.c:1081-1101`) where - `IA32_CORE_CAPABILITIES` (0xCF) bit 5 is set, and TIGERLAKE_L is not in its - model list (`intel.c:1308-1313`). A split-locked access locks the bus for - every core (SDM Vol. 3A §11.1.2.3). First, 0xCF bit 5 from S0. - `MSR_MEMORY_CTRL` (0x33) bit 29 joins the declaration (SDM Vol. 4, MSR 33H); - a split lock then raises `#AC(0)` whatever `CR0.AM` holds (§11.1.2.3, note - 1), so the kernel gains an `#AC` handler: in ring 3 it ends the process - naming the split lock, where Linux warns and slows it (`split_lock_warn`, - `intel.c:1191-1230`), and in ring 0 it panics. **Exit**, T14: a - `test-actuators` program's `lock add` across a cache-line boundary is ended - naming the split lock; bit 29 left clear lets it exit 0 and reds it. S0's - `x86/split lock detection:` line is the oracle for the T14's support. - -## Decisions - -- **IBPB is conditional**, Linux's default: `spectre_v2_user_select_mitigation` - maps the default command to PRCTL, which enables `switch_mm_cond_ibpb` - (`bugs.c:1512-1543`), and `arch/x86/mm/tlb.c:442-444` (`cond_mitigation`) - issues IBPB on a switch between two processes only when either is flagged, - printing "IBPB: conditional" (`bugs.c:3195-3205`). The flag is S6's. -- **Probes add no syscall.** A probe is compiled under `boot-actuators`, or - is a `SYS_DEBUG` action under `test-actuators`. - -## Exit - -The T14's ToyOS boot prints, for each vulnerabilities file S0 captured, -exactly S0's Linux line. Where ToyOS mitigates differently, the line and why -it is not worse: - -- `spectre_v1`: S0's line; ToyOS owes none of its swapgs barriers because it - executes no `swapgs` (S4). -- `spectre_v2`: S0's line without its VM-exit clauses (`PBRSB-eIBRS: …`, - `, KVM: …`); ToyOS runs no guest, so it has no VM exit to mitigate. -- `spec_store_bypass`: "Mitigation: Speculative Store Bypass disabled per - program"; any program can be flagged in `system.toml`, where Linux's - default mitigates only a process that asks by prctl. - -Reading ARCH_CAPABILITIES as 0 instead of from 0x10A turns `spectre_v2` into -"Mitigation: Retpolines; …" and `gather_data_sampling` into "Vulnerable: No -microcode", and reds it. S1–S6 and S8–S17 are green or closed by S0's -finding, S7 is closed by S0's finding or by the owner, and every defect the -hardening table cites is closed. diff --git a/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md b/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md index dc227e6b8a0..cfa7ca949b1 100644 --- a/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md +++ b/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md @@ -6,150 +6,66 @@ opened: 2026-09-29 # ToyOS uses what the T14's hardware offers for speed -Owner ruling: ToyOS takes the newest hardware features that make it faster, at -least on the T14, an i5-1135G7, Tiger Lake, family 6 model 0x8C -(`issues/hardware/the-t14-touchpad-is-i2c-hid-and-unbuilt.md`). Features the -T14 lacks are `issues/hardware/newer-hardware-offers-what-the-t14-lacks.md`. -Intel documents most of these for the Tiger Lake family, not for the -i5-1135G7, so a stage's first step confirms its bit in S0's CPUID capture -(`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`), and -a bit S0 finds clear closes the stage. Linux `path:line`s are read at that -track's tag, `Ubuntu-6.8.0-142.142`; Intel's documents are the SDM -325462-093US and the 11th-generation datasheet 631121-012. +Owner ruling: ToyOS takes the hardware features that make it faster, at least +on the T14; what the T14 lacks is +`issues/hardware/newer-hardware-offers-what-the-t14-lacks.md`. A figure is the +median of 11 T14 runs with its spread, taken by P0's program. A stage is done +at or past P0's Linux figure, or with the gap filed as a defect carrying both; +one Linux has no counterpart for lands only if it beats ToyOS without it. The +kernel uses no vector registers, as Linux's kernel does not. -**How a stage is judged.** Each figure is the median of 11 runs on the T14, -with its spread, taken by P0's program. A stage is done when ToyOS's figure is -at or past P0's Linux figure, or when the gap is filed as a defect with both -numbers. A stage Linux has no counterpart for is measured against ToyOS -without it and lands only if it wins. - -**Owned elsewhere, not repeated here.** HWP, RAPL and turbo: PR #590's -`issues/kernel/the-kernel-owns-cpu-performance-state.md`. Global kernel pages: -`issues/kernel/page-global-is-a-decision-nobody-has-made.md`. A vector per CPU -or per queue: `issues/kernel/every-interrupt-lands-on-the-boot-cpu.md`. -Placement that weighs caches and idle depth: -`issues/kernel/placement-is-blind-to-caches-and-topology.md` and -`issues/kernel/the-scheduler-and-the-clocks-never-talk.md`. 4 KiB process -pages: `issues/kernel/process-memory-is-2-mib-pages-and-that-caps-the-process-count.md`. -NVMe with commands in flight: step 3 of -`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`. The -stick at SuperSpeed: -`issues/hardware/the-t14s-superspeed-stick-enumerates-at-high-speed-under-toyos.md`. -PCID is in use, and a switch keeps the incoming space's translations -(`CR3_NOFLUSH`, `kernel/src/arch/x86_64/paging.rs`). - -## Stages - -- **P0 — The Linux baseline.** One Rust program, built from one source for - `x86_64-unknown-linux-gnu` under Ubuntu on the T14 and for ToyOS, measures: - memcpy at 64 B, 4 KiB, 256 KiB and 64 MiB; AES-128-GCM, ChaCha20-Poly1305 - and SHA-256 through the RustCrypto versions sshd links - (`userland/Cargo.lock`); a pipe round trip between two threads and between - two processes, and pipe throughput at 64 B, 4 KiB and 64 KiB writes; munmaps - per second of a page a sibling thread on another CPU has touched; a - sleeping thread's lateness past a 1 ms timer; 4 KiB random reads at 1 and 32 - in flight and 1 MiB sequential reads of the raw NVMe namespace, read-only; - and an idle minute's package energy, from - `/sys/class/powercap/intel-rapl:0/energy_uj` under Linux. It runs in S0's - session with `lspci -vvv -nn`, `lsusb -tv`, `nvme id-ctrl -H /dev/nvme0`, - `nvme get-feature -f 0x0c -H /dev/nvme0` (APST) and `-f 0x06` (volatile - write cache), and `grep . - /sys/devices/system/cpu/cpu0/cpuidle/state*/{name,desc,latency,residency}`. - **Exit**: the outputs committed as fixtures; S0's wipe waits on that commit. -- **P1 — XSAVE, and with it AVX, AVX2 and AVX-512 in user programs.** - `CR4.OSXSAVE` is clear and a thread's saved state is `FXSAVE64`'s - (`kernel/src/arch/x86_64/fpu.rs`), so no user program may run a VEX or EVEX - instruction. RustCrypto's `cpufeatures` 0.2.17 gates every AVX feature on - `OSXSAVE` and `XCR0` (`src/x86.rs:67-83,97-101`), so `chacha20` 0.9.1's AVX2 - backend (`src/lib.rs:173`) and `sha2` 0.10.9's AVX2 SHA-512 - (`src/sha512/x86.rs:14`) never run; AES-NI, PCLMULQDQ and SHA-NI need no - `XCR0` and run today (`cpufeatures` `src/x86.rs:116,122,142`). First, - AVX-512 from S0's capture: the datasheet warns it may be absent on some - SKUs (§2.4.10). `CR4.OSXSAVE` and `XCR0` (x87, SSE and AVX, and opmask, - ZMM_Hi256 and Hi16_ZMM where CPUID offers them, SDM Vol. 1 §13.1, §13.3) - join the one declaration and are asserted on every CPU. A switch saves with - XSAVES where CPUID.(0xD,1) offers it, which the security track's S11 needs - for CET_U, and with XSAVEOPT where not: TCG offers neither XSAVEC nor XSAVES - (`target/i386/cpu.c:1012-1014` at QEMU v11.1.1) and no AVX-512 - (`:977-985`). A thread's state grows from 512 bytes to CPUID.(0xD,0):EBX. - `aes` 0.8.4 and `polyval` 0.6.2 carry no VAES or VPCLMULQDQ path, so those - wait on a crate version that has one. **Exit**, T14: P0's - ChaCha20-Poly1305 figure; two threads that fill their vector registers with - different patterns and switch each find their own, and a save mask short of - Hi16_ZMM reds it. -- **P2 — Kernel copies with `rep movsb`.** compiler-builtins copies with - `rep movsb` only under `target_feature = "ermsb"` - (`rust/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs:23-54` - at the `rust/` commit, 1b236638), which the kernel's `x86_64-unknown-none` - build lacks, so every kernel copy is `rep movsq` and a byte tail. First, - CPUID.(7,0):EBX bit 9 (ERMS) and EDX bit 4 (FSRM) from S0 - (`arch/x86/include/asm/cpufeatures.h:251,418`); SDM Vol. 1 Table 5-2 - introduces fast short `rep movsb` with Ice Lake and names no Tiger Lake - part. `+ermsb` for the kernel and the `core`, `alloc` and - `compiler_builtins` it builds makes ERMS a boot requirement, refused by name, - as the security track's S4 makes SMAP one. **Exit**, T14: P0's pipe figures - before and after. -- **P3 — 1 GiB leaves in the direct map.** Every direct-map leaf is 2 MiB - (`toyos-bootmap/src/lib.rs`, `PAGE_2M`), with a page directory per GiB - (`issues/kernel/the-direct-maps-page-directories-come-from-a-512-kib-heap.md`). - First, CPUID.80000001H:EDX bit 26 (`cpufeatures.h:67`); TCG offers it - (`target/i386/cpu.c:945`). A GiB of one memory type takes one 1 GiB leaf, - and a GiB of mixed types keeps 2 MiB leaves (SDM Vol. 3A §14.11.9). - **Exit**, T14: P0's 64 KiB pipe throughput before and after, and the boot's - count of 1 GiB and 2 MiB direct-map leaves. -- **P4 — Shootdowns only where the space ran.** Every shootdown interrupts - every other CPU, and each flushes every PCID (`kernel/src/arch/x86_64/tlb.rs` - header, `flush_tlb_all` in `paging.rs`). Linux interrupts only the CPUs in - the space's `mm_cpumask`, which a switch keeps (`arch/x86/mm/tlb.c:575-628`), - and flushes by page up to 33 pages (`tlb.c:1003,1048-1076`). A shootdown - goes to the CPUs that ran the space since its last flush and flushes that - space's PCID, or its pages. This is memory management: a guest test's - sibling thread on another CPU touches a page, the initiator unmaps it, and - the sibling's next touch faults; a target set that omits a CPU the space - ran on lets the read through and reds it, and - `kernel-loom/tests/tlb_shootdown.rs` models the ordering. **Exit**, T14: - P0's munmap figure and the `tlb:` census line's shootdowns and wait. -- **P5 — FSGSBASE, measured, then taken or rejected.** Every switch reads and - writes `IA32_FS_BASE` with `rdmsr` and `wrmsr` - (`kernel/src/arch/x86_64/hw.rs:423,445`). One `CR4` bit enables all four - base instructions (SDM Vol. 3A §2.5) in ring 3 as in ring 0, and `GS.base` - is the kernel's per-CPU pointer with no `swapgs` on entry, which is why - `control_regs.rs` forbids it. Taking it means a `swapgs` entry, and then the - security track's S4 owes Linux's swapgs barriers - (`arch/x86/kernel/cpu/bugs.c:943-944`). It buys `rdfsbase`/`wrfsbase` on - the switch and a user thread that sets its own FS base. **Exit**, T14: P0's - round trips with the `wrfsbase` switch, the `swapgs` entry and the - barriers, against without; a loss becomes a `rejected` issue carrying both - figures. -- **P6 — Deep idle.** An idle CPU runs `sti; hlt` - (`kernel/src/arch/x86_64/hw.rs:52-53`), which reaches C1 or C1E (datasheet - §3.2.3); Tiger Lake cores and the package go to C10 through MWAIT hints - (§3.2.4-3.2.5). TIGERLAKE_L has no table in `intel_idle` - (`drivers/idle/intel_idle.c:1603-1657`), so Linux takes its hints from ACPI - `_CST` (`:2347-2349`), which ToyOS cannot evaluate without an AML - interpreter (`issues/kernel/the-scheduler-and-the-clocks-never-talk.md`). - P0's cpuidle capture becomes a TIGERLAKE_L table, as `intel_idle` carries - one per model, and an idle CPU picks the deepest state whose target - residency fits before its next deadline. Package C9 and C10 need every PCIe - link in L1.2 (datasheet §3.7, Table 3-8), which is P7's. **Exit**, T14: the - idle desktop minute's package energy, read by the sampler of stage 4 of PR - #590's track, against P0's; P0's timer lateness no worse than `hlt`'s by - more than the chosen state's exit latency. -- **P7 — The T14's NVMe drive, idle and busy.** blockd runs several I/O queue - pairs on the claim's one MSI-X vector (`userland/blockd/src/nvme.rs`). The - drive's model is unrecorded; P0's `id-ctrl` says whether it offers APST - (`apsta`), a host memory buffer (`hmpre`) and a volatile write cache. What - it offers is taken, as Linux takes it: APST through feature 0x0C - (`drivers/nvme/host/core.c:2495-2592`, `include/linux/nvme.h:1222`), a host - memory buffer through 0x0D (`drivers/nvme/host/pci.c:2108`). Blocked on - blockd driving the T14's NVMe, which step 3 of the small-kernel track meets - on the T14 only with its step 10. **Exit**, T14: P0's block figures against - Linux's on the same drive, and P6's idle minute with the drive idle. - -The whole-system figure is PR #568's T14 LLVM build bar once it lands; each -stage names a narrower one. - -**Not taken.** Vector registers in the kernel: its target is soft-float, as -Linux builds its kernel's C and Rust without SSE or AVX -(`arch/x86/Makefile:70-71`), and the kernel has no bulk data to encrypt or -hash. +- **Pin — a test holds a thread on a named CPU**, a `test-actuators` + `SYS_DEBUG` action. Exit: a guest test pins a thread to each CPU in turn and + reads CPUID.1:EBX[31:24] across 1000 yields at each: one APIC ID per pin, a + different one per CPU. Mutation: a pin the scheduler's placement ignores. + Oracle: the CPU's own APIC ID. +- **P0 — The Linux baseline.** One Rust program, built for + `x86_64-unknown-linux-gnu` and for ToyOS, measures memcpy from 64 B to 64 + MiB; AES-128-GCM, ChaCha20-Poly1305 and SHA-256 at sshd's RustCrypto + versions; pipe round trips, and throughput at 64 B to 64 KiB; munmaps per + second of a page a sibling on another CPU touched; lateness past a 1 ms + timer; NVMe reads, read-only; an idle minute's package energy; and the + T14's PCI, USB, NVMe and cpuidle identity. Exit: the outputs committed as + fixtures. Mutation: the munmap pair on one CPU, as `sched_getcpu` or Pin + reads it, is refused. Oracle: Linux. +- **P1 — XSAVE, and AVX to AVX-512 in user programs**, with one save path on + every CPU, XSAVEOPT: TCG implements neither XSAVEC nor XSAVES + (`target/i386/cpu.c:1012-1014` at QEMU v11.1.1), and the security track's + S11 switches its CET state by `wrmsr`, as `fs_base` is. Exit: threads that + fill their vector registers differently each find their own after a switch, + under TCG and on the T14; P0's ChaCha20-Poly1305 figure. Mutation: a save + mask short of Hi16_ZMM, and under TCG of YMM. Oracle: TCG and the T14 on SDM + Vol. 1 §13. +- **P2 — Kernel copies with `rep movsb`**, `+ermsb` for the kernel and the + `core`, `alloc` and `compiler_builtins` it builds; a CPU without ERMS is + refused by name. Exit: a gate finds `rep movsb` in `kernel.elf`'s `memcpy`; + P0's pipe figures. Mutation: no `+ermsb`. Oracle: P0's Linux figures. +- **P3 — 1 GiB direct-map leaves** where a GiB holds one memory type. Exit: a + `toyos-bootmap` host test gives a GiB holding one UC range 2 MiB leaves and + a uniform GiB one leaf; P0's 64 KiB pipe figure and the boot's leaf counts. + Mutation: a 1 GiB leaf for every GiB. Oracle: SDM Vol. 3A §14.11.9. +- **P4 — Shootdowns only to the CPUs that ran the space**, after Pin. Exit: a + sibling pinned on another CPU touches a page the initiator unmaps and then + faults; a case in `kernel-loom/tests/tlb_shootdown.rs` switches a CPU into + the space while the initiator reads the target set; P0's munmap figure. + Mutation: a target set that omits a CPU the space ran on, and a CPU that + joins the set after loading CR3. Oracle: loom. +- **P5 — FSGSBASE, measured, then taken or rejected**; it costs a `swapgs` + entry and the security track's S4 barriers. Exit: P0's round trips with and + without, a loss becoming a `rejected` issue with both figures; taken, an NMI + that arrives while a user GS base is set finds the kernel's. Mutation: an + IST entry that decides `swapgs` from the saved CS alone. Oracle: Linux's + `paranoid_entry`. +- **P6 — Deep idle** from `_CST`, as Linux takes the T14's states, after the + AML interpreter `issues/kernel/the-scheduler-and-the-clocks-never-talk.md` + waits on. Exit: P0's idle minute's energy, and P0's timer lateness no worse + than `hlt`'s by more than the chosen state's exit latency. Mutation: always + the deepest state. Oracle: P0's Linux figures. +- **P7 — NVMe APST and host memory buffer**, after blockd drives the T14's + drive (step 3 of + `issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`); as + Linux, APST stays within `default_ps_max_latency_us` and honours + `NVME_QUIRK_NO_APST` and `NVME_QUIRK_NO_DEEPEST_PS`. Exit: P0's block + figures, and P6's idle minute with the drive idle. Mutation: a host test's + table that admits a state past the bound. Oracle: Linux's + `nvme_configure_apst` over P0's `id-ctrl`. diff --git a/issues/kernel/tsx-stays-as-firmware-left-it.md b/issues/kernel/tsx-stays-as-firmware-left-it.md index 27078c01f56..6b8984acae2 100644 --- a/issues/kernel/tsx-stays-as-firmware-left-it.md +++ b/issues/kernel/tsx-stays-as-firmware-left-it.md @@ -15,10 +15,10 @@ T14's `CONFIG_X86_INTEL_TSX_MODE_OFF=y`, runs `tsx_init` (`tsx.c:139-156`), clears enumeration where RTM_ALWAYS_ABORT (`tsx.c:108-137,170-176`), and otherwise, where `ARCH_CAPABILITIES.TSX_CTRL_MSR`, sets `RTM_DISABLE | TSX_CPUID_CLEAR` -(`tsx.c:23-41,189-226`). A row of the hardening table in -`issues/kernel/the-kernel-mitigates-what-linux-mitigates-on-the-t14.md`. +(`tsx.c:23-41,189-226`). -**Exit**: S1 of that track carries `tsx_init`'s decision and every CPU applies -it; on the T14, ToyOS's reads of 0x122, 0x10F and 0x123 equal S0's Linux reads -where each exists, and dropping the write leaves 0x122 or 0x10F at firmware's -value and reds it. +**Exit**: S1 of +`issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md` +carries `tsx_init`'s decision and every CPU applies it; on the T14, ToyOS's +reads of 0x122, 0x10F and 0x123 equal S0's Linux reads where each exists, +and dropping the write leaves 0x122 or 0x10F at firmware's value and reds it. From 00fc315ff95588fb5c4b00cfbf808abfa24319e8 Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 11:44:28 +0200 Subject: [PATCH 3/6] PR #603 round 3: general tracks, one issue per stage The owner's direction: ToyOS is a general-purpose OS for modern hardware, and the T14 is a proving machine, not the design centre. - The security track becomes the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports, the speed track toyos-uses-what-modern-hardware-offers-for-speed, and the newer-hardware list features-no-proving-machine-is-known-to-offer. The proving machines are the T14 and the nightly's EPYC KVM guests; a stage that only one machine can prove says so. - Each track now holds only its intent and the ordered list of its stage issues. Every stage is its own file carrying its exit, mutation and oracle, as the eight hardening defects already were: 18 security stage files, the restored user-programs-run-without-a-shadow-stack among them, and 9 speed stage files. - The ERMS stage selects rep movsb where CPUID.(7,0):EBX[9] is set and keeps the plain copy elsewhere, and it refuses no CPU. Zen 2 has no ERMS: InstLatx64 ddff8a92's Matisse dump reads EBX 0x219C91A9, and QEMU v11.1.1's EPYC-Rome model omits ERMS where EPYC-Milan carries it. - The thunk stage asserts retbleed's and SRSO's return-thunk placement alongside ITS's, as vmlinux.lds.S:510-539 does at the pin. Each placement has a mutation. - Microcode is a kind: question for the owner, with no exit tied to firmware. - Protection keys: a write(2) from an access-denied buffer is refused. A key check made only on Access::Write reds it. - FSGSBASE: an NMI entered at CPL 0 with the user GS base live must find the kernel's per-CPU data. A swapgs decision from CS alone reds it. CR4_FORBIDDEN, user-writable-gsbase and gsbase_locked go when it is taken. - The TCG model gains +xsave,+xsaveopt,+avx,+avx2 and +pdpe1gb, and it keeps no ERMS so that the plain copy stays exercised. - The split-lock MSR is MSR_TEST_CTRL (0x33) at the pin, not MSR_MEMORY_CTRL. The APST names are read at the pin, not upstream v6.8. Co-Authored-By: Claude Opus 5.5 --- ...es-nvme-apst-and-the-host-memory-buffer.md | 18 +++ ...es-no-proving-machine-is-known-to-offer.md | 46 +++++++ ...t14-and-the-tcg-model-are-not-committed.md | 24 ++++ ...ewer-hardware-offers-what-the-t14-lacks.md | 46 ------- ...ures-toyos-against-linux-on-one-machine.md | 19 +++ ...s-speculation-mitigations-as-linux-does.md | 21 ++++ issues/kernel/a-split-lock-goes-unnoticed.md | 17 +++ ...eaches-only-the-cpus-that-ran-the-space.md | 18 +++ ...-the-vulnerabilities-lines-linux-prints.md | 18 +++ ...base-is-measured-then-taken-or-rejected.md | 21 ++++ .../idle-cpus-enter-the-c-states-cst-names.md | 16 +++ ...branches-and-returns-run-without-thunks.md | 29 +++++ ...es-use-rep-movsb-where-the-cpu-has-erms.md | 21 ++++ ...the-bhb-fills-the-rsb-or-issues-an-ibpb.md | 25 ++++ .../no-kernel-address-is-drawn-per-boot.md | 20 +++ ...-with-speculative-store-bypass-disabled.md | 18 +++ ...o-test-can-hold-a-thread-on-a-named-cpu.md | 16 +++ .../no-user-address-is-drawn-per-spawn.md | 19 +++ ...ams-hold-aes-keys-as-key-locker-handles.md | 19 +++ ...ctrl-and-gds-stay-as-firmware-left-them.md | 21 ++++ ...ses-1-gib-leaves-where-the-cpu-has-them.md | 20 +++ .../the-kernel-has-no-stack-protector.md | 21 ++++ ...s-linux-on-every-machine-toyos-supports.md | 43 +++++++ ...-at-least-as-secure-as-linux-on-the-t14.md | 114 ------------------ .../the-kernel-runs-without-a-shadow-stack.md | 19 +++ ...l-runs-without-indirect-branch-tracking.md | 18 +++ ...s-what-modern-hardware-offers-for-speed.md | 31 +++++ ...what-the-t14s-hardware-offers-for-speed.md | 71 ----------- .../kernel/tsx-stays-as-firmware-left-it.md | 10 +- ...o-spectre-v1-fence-and-smap-is-optional.md | 21 ++++ .../user-programs-have-no-protection-keys.md | 24 ++++ ...ser-programs-run-without-a-shadow-stack.md | 26 ++++ .../user-programs-use-avx-under-xsave.md | 22 ++++ ...ernel-loads-cpu-microcode-is-the-owners.md | 14 +++ 34 files changed, 671 insertions(+), 235 deletions(-) create mode 100644 issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md create mode 100644 issues/hardware/features-no-proving-machine-is-known-to-offer.md create mode 100644 issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-are-not-committed.md delete mode 100644 issues/hardware/newer-hardware-offers-what-the-t14-lacks.md create mode 100644 issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md create mode 100644 issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md create mode 100644 issues/kernel/a-split-lock-goes-unnoticed.md create mode 100644 issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md create mode 100644 issues/kernel/each-boot-prints-the-vulnerabilities-lines-linux-prints.md create mode 100644 issues/kernel/fsgsbase-is-measured-then-taken-or-rejected.md create mode 100644 issues/kernel/idle-cpus-enter-the-c-states-cst-names.md create mode 100644 issues/kernel/indirect-branches-and-returns-run-without-thunks.md create mode 100644 issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md create mode 100644 issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md create mode 100644 issues/kernel/no-kernel-address-is-drawn-per-boot.md create mode 100644 issues/kernel/no-program-runs-with-speculative-store-bypass-disabled.md create mode 100644 issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md create mode 100644 issues/kernel/no-user-address-is-drawn-per-spawn.md create mode 100644 issues/kernel/programs-hold-aes-keys-as-key-locker-handles.md create mode 100644 issues/kernel/spec-ctrl-and-gds-stay-as-firmware-left-them.md create mode 100644 issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md create mode 100644 issues/kernel/the-kernel-has-no-stack-protector.md create mode 100644 issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md delete mode 100644 issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md create mode 100644 issues/kernel/the-kernel-runs-without-a-shadow-stack.md create mode 100644 issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md create mode 100644 issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md delete mode 100644 issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md create mode 100644 issues/kernel/user-pointer-checks-have-no-spectre-v1-fence-and-smap-is-optional.md create mode 100644 issues/kernel/user-programs-have-no-protection-keys.md create mode 100644 issues/kernel/user-programs-run-without-a-shadow-stack.md create mode 100644 issues/kernel/user-programs-use-avx-under-xsave.md create mode 100644 issues/kernel/whether-the-kernel-loads-cpu-microcode-is-the-owners.md diff --git a/issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md b/issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md new file mode 100644 index 00000000000..35c401c0109 --- /dev/null +++ b/issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md @@ -0,0 +1,18 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# blockd drives NVMe APST and the host memory buffer + +After blockd drives the T14's drive, the blockd step of +`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`. As +Linux at `Ubuntu-6.8.0-142.142`, APST stays within +`default_ps_max_latency_us` and honours `NVME_QUIRK_NO_APST` and +`NVME_QUIRK_NO_DEEPEST_PS` (`drivers/nvme/host/core.c:63,2495-2598`). + +**Exit**: on the T14, the one proving machine with a physical NVMe drive, the +block figures, and the idle minute with the drive idle. **Mutation**: a host +test's table that admits a state past the bound. **Oracle**: Linux's +`nvme_configure_apst` over the T14's `id-ctrl`. diff --git a/issues/hardware/features-no-proving-machine-is-known-to-offer.md b/issues/hardware/features-no-proving-machine-is-known-to-offer.md new file mode 100644 index 00000000000..1c40541e44b --- /dev/null +++ b/issues/hardware/features-no-proving-machine-is-known-to-offer.md @@ -0,0 +1,46 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# Features no proving machine is known to offer + +No stage of +`issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md` +or `issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md` takes +these, since neither the T14 nor a nightly EPYC KVM guest is known to +enumerate one. It is blocked on a proving machine that does; its exit is every +row a stage issue under the track it serves, or a `rejected` issue. Intel's +parts are named by the SDM 325462-093US, Vol. 1 Table 5-2 ("SDM"), or by the +ISE reference 319433-062, Table 1-2 ("ISE"), neither of which places any of +these in Tiger Lake. AMD's and Arm's are read in Linux at tag `v7.2`; the AMD +parts that carry each were not verified against AMD's documents, and the Arm +cores were not verified against Arm's. The Arm rows belong to +`issues/kernel/toyos-runs-on-arm64.md`'s CPU-state declaration. + +| Feature | Hardware | +|---|---| +| FRED and LKGS | Panther Lake, Clearwater Forest, Diamond Rapids (ISE) | +| LASS | Sierra Forest, Atom P6900, Core Ultra 200H (SDM) | +| LAM | the parts LASS names (SDM) | +| PKS | Alder Lake, Sapphire Rapids, Sierra Forest (SDM) | +| User interrupts (UINTR) | Sapphire Rapids, Sierra Forest, Atom P6900, Core Ultra 200H (SDM) | +| UMONITOR, UMWAIT, TPAUSE | Tremont, Alder Lake, Sapphire Rapids (SDM) | +| Fast zero-length `rep movsb`, fast short `rep stosb` | Alder Lake, Sapphire Rapids (SDM) | +| AMX | Sapphire Rapids (SDM) | +| AVX10.1, AVX10.2 | AVX10.1: Granite Rapids, Nova Lake; AVX10.2: Diamond Rapids, Nova Lake (ISE) | +| APX | Diamond Rapids, Nova Lake (ISE) | +| Thread Director, HRESET | Alder Lake (SDM) | +| TDX | Emerald Rapids (ISE) | +| Total Storage Encryption | Panther Lake (ISE) | +| TME | 11th-generation Core lines that set CPUID.(7,0):ECX bit 13, which varies by line (datasheet 631121-012 §1.3); the T14 reads ECX 0x18c05fde, bit 13 clear | +| INVLPGB, TLBSYNC | AMD, CPUID 0x80000008:EBX bit 3 (`arch/x86/include/asm/cpufeatures.h:331,335`); whether a nightly EPYC guest sees it waits on its runner's CPUID capture | +| SEV-SNP | AMD, CPUID 0x8000001F:EAX bit 4 (`cpufeatures.h:448,453`) | +| Shadow stack on AMD | AMD; unverified: that AMD enumerates it through the bit Linux reads for Intel, CPUID.(7,0):ECX bit 7 (`cpufeatures.h:390,397`), and which parts set it; whether a nightly EPYC guest sees it waits on its runner's CPUID capture | +| MTE | Armv8.5 (`arch/arm64/Kconfig:2150-2170`) | +| Pointer authentication | Armv8.3 (`arch/arm64/Kconfig:1967-1974`) | +| BTI | Armv8.5 (`arch/arm64/Kconfig:2087-2093`) | +| GCS | Armv9.4 (`arch/arm64/Kconfig:2236-2254`) | +| POE | Armv8.9 (`arch/arm64/Kconfig:2198-2213`) | +| SME | Arm (`arch/arm64/Kconfig:2311-2319`) | diff --git a/issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-are-not-committed.md b/issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-are-not-committed.md new file mode 100644 index 00000000000..67f1be92423 --- /dev/null +++ b/issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-are-not-committed.md @@ -0,0 +1,24 @@ +--- +status: assigned +kind: tooling +opened: 2026-09-29 +--- + +# Linux's readings of the T14 and the TCG model are not committed + +The floor of +`issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md` +is tag `Ubuntu-6.8.0-142.142` (53e5d07aac028a1523ab0b115f079d6d1bc831ef) of +`https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/noble`, +config sha256 3b8533dd9d235ca634ac58f82c5ce1ee35f12ef620693e17033184d2c9ca5890, +and what it reads on the T14 and on the PR gate's TCG model are the fixtures +of `issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md`. +Pull request #601 holds it. Ubuntu leaves the T14 only after this issue and +`issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md` +close. + +**Exit**: both captures committed, and no Linux image; before the wipe the +T14's adds CPUID 5, 0x19 and 0x80000001, MSR 0xCF, the split-lock line, and +the config's `X86_KERNEL_IBT` and `X86_INTEL_MEMORY_PROTECTION_KEYS`. +**Mutation**: a config hash off by one byte is refused. **Oracle**: that +Linux. diff --git a/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md b/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md deleted file mode 100644 index ab002469db1..00000000000 --- a/issues/hardware/newer-hardware-offers-what-the-t14-lacks.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -status: open -kind: track -opened: 2026-09-29 ---- - -# Newer hardware offers what the T14 lacks - -Owner ruling: the T14 gets every security and speed feature its hardware has -(`issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md`, -`issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`), and -what only other modern systems have is written down here. It is blocked on a -machine that has the feature; its exit is every row a stage on that -machine's track or a `rejected` issue. Intel's parts are named by the -SDM 325462-093US, Vol. 1 Table 5-2 ("SDM"), or by the ISE reference -319433-062, Table 1-2 ("ISE"), neither of which places any of these in Tiger -Lake. AMD's and Arm's are read in Linux at tag `v7.2`; the AMD parts that -carry each were not verified against AMD's documents, and the Arm cores were -not verified against Arm's. The Arm rows belong to -`issues/kernel/toyos-runs-on-arm64.md`'s CPU-state declaration. - -| Feature | Hardware | Why it matters to ToyOS | -|---|---|---| -| FRED and LKGS | Panther Lake, Clearwater Forest, Diamond Rapids (ISE) | Replaces the IDT and SYSCALL entry; `SWAPGS`, `SETSSBSY` and `CLRSSBSY` are `#UD` under it (SDM Vol. 3A §8.5.1), so FSGSBASE (speed track P5) costs no `swapgs` and a kernel shadow stack (security S13) needs no tokens | -| LASS | Sierra Forest, Atom P6900, Core Ultra 200H (SDM) | Refuses a user access to the kernel half before any page walk whose timing would map the kernel's layout (SDM Vol. 3A §4.3), which security S10's KASLR rests on; Linux v7.2 sets it on every CPU (`arch/x86/kernel/cpu/common.c:413-431`) | -| LAM | the parts LASS names (SDM) | Metadata in a user pointer's unused bits, for sanitizers and JITs; Linux v7.2 holds it back until LASS (`arch/x86/Kconfig:2150-2153`) | -| PKS | Alder Lake, Sapphire Rapids, Sierra Forest (SDM) | Protection keys for kernel pages (SDM Vol. 3A §5.6.2): page tables and other kernel state writable only inside the code that owns them | -| User interrupts (UINTR) | Sapphire Rapids, Sierra Forest, Atom P6900, Core Ultra 200H (SDM) | `SENDUIPI` interrupts another thread at CPL 3 (SDM Vol. 3A §9.1): userland servers wake each other without a syscall | -| UMONITOR, UMWAIT, TPAUSE | Tremont, Alder Lake, Sapphire Rapids (SDM) | A userland driver or lock waits at low power without a syscall | -| Fast zero-length `rep movsb`, fast short `rep stosb` | Alder Lake, Sapphire Rapids (SDM) | Speed track P2's copies, and `memset`, cheaper at small sizes | -| AMX | Sapphire Rapids (SDM) | Matrix tiles for user programs; 8192 bytes of XSAVE state per thread (SDM Vol. 1 §13.1), so the kernel grants it per process | -| AVX10.1, AVX10.2 | AVX10.1: Granite Rapids, Nova Lake; AVX10.2: Diamond Rapids, Nova Lake (ISE) | AVX-512-class vectors on client parts again: Alder Lake has none (SDM Table 5-2, note 3) | -| APX | Diamond Rapids, Nova Lake (ISE) | Extended general-purpose registers, a new XSAVE component (ISE revision history, EGPR) the kernel saves, and a target feature for the toolchain | -| Thread Director, HRESET | Alder Lake (SDM) | The core-class hints `issues/kernel/all-cores-are-assumed-equal-and-arm64-breaks-that.md` needs on a hybrid part | -| TDX | Emerald Rapids (ISE) | ToyOS as a confidential guest; ToyOS runs no guest today | -| Total Storage Encryption | Panther Lake (ISE) | A platform engine encrypts storage under a key `PBNDKB` wraps to the platform (SDM Vol. 2B, PBNDKB), so disk encryption's key reaches memory only wrapped | -| TME | 11th-generation Core lines that set CPUID.(7,0):ECX bit 13, which varies by line (datasheet 631121-012 §1.3); the T14 reads ECX 0x18c05fde, bit 13 clear | Memory encrypted under a key firmware activates and locks; the kernel reads `IA32_TME_ACTIVATE` on every CPU and refuses a boot where two disagree, where Linux only reports it (`detect_tme_early`) | -| INVLPGB, TLBSYNC | AMD, CPUID 0x80000008:EBX bit 3 (`arch/x86/include/asm/cpufeatures.h:331,335`) | Broadcast TLB invalidation without IPIs, which Linux v7.2 uses (`arch/x86/mm/tlb.c:276-285,407-448`); it would replace speed track P4's shootdown IPIs, as `TLBI IS` does on Arm | -| SEV-SNP | AMD, CPUID 0x8000001F:EAX bit 4 (`cpufeatures.h:448,453`) | ToyOS as a confidential guest; ToyOS runs no guest today | -| Shadow stack on AMD | AMD; unverified: that AMD enumerates it through the bit Linux reads for Intel, CPUID.(7,0):ECX bit 7 (`cpufeatures.h:390,397`), and which parts set it | Security S11 and S13 would run there unchanged | -| MTE | Armv8.5 (`arch/arm64/Kconfig:2150-2170`) | Always-on detection of memory errors at runtime, in C programs and unsafe Rust | -| Pointer authentication | Armv8.3 (`arch/arm64/Kconfig:1967-1974`) | Signed return addresses and pointers: Arm's answer to ROP | -| BTI | Armv8.5 (`arch/arm64/Kconfig:2087-2093`) | Arm's IBT: security S12 on the arm64 port | -| GCS | Armv9.4 (`arch/arm64/Kconfig:2236-2254`) | Arm's shadow stack: security S11 and S13 on the arm64 port | -| POE | Armv8.9 (`arch/arm64/Kconfig:2198-2213`) | Arm's protection keys: security S14 on the arm64 port | -| SME | Arm (`arch/arm64/Kconfig:2311-2319`) | Matrix state for user programs, granted per process as AMX is | diff --git a/issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md b/issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md new file mode 100644 index 00000000000..9892273a19a --- /dev/null +++ b/issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md @@ -0,0 +1,19 @@ +--- +status: open +kind: tooling +opened: 2026-09-29 +--- + +# No program measures ToyOS against Linux on one machine + +One Rust program, built for `x86_64-unknown-linux-gnu` and for ToyOS, is to +measure memcpy from 64 B to 64 MiB; AES-128-GCM, ChaCha20-Poly1305 and SHA-256 +at sshd's RustCrypto versions; pipe round trips, and throughput at 64 B to 64 +KiB; munmaps per second of a page a sibling on another CPU touched; lateness +past a 1 ms timer; NVMe reads, read-only; an idle minute's package energy; and +the T14's PCI, USB, NVMe and cpuidle identity. It runs on the T14 under its +Ubuntu before the wipe and under the shipped ToyOS kernel. + +**Exit**: the outputs committed as fixtures. **Mutation**: a munmap pair on +one CPU, as each side reads its x2APIC ID from CPUID.0BH:EDX, is refused. +**Oracle**: Linux. diff --git a/issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md b/issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md new file mode 100644 index 00000000000..532e0f201ed --- /dev/null +++ b/issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md @@ -0,0 +1,21 @@ +--- +status: assigned +kind: track +opened: 2026-09-29 +--- + +# A pure function decides a CPU's speculation mitigations as Linux does + +From a CPU's facts to the line Linux at `Ubuntu-6.8.0-142.142` prints in each +`/sys/devices/system/cpu/vulnerabilities/*` file and the mitigation it +selects, built by the kernel and by a host test. Pull request #602 holds it. + +**Exit**: each committed fixture's facts give its lines: the T14's and the TCG +model's from +`issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-are-not-committed.md`, +and each nightly EPYC guest's once its runner is captured. **Mutation**: `GDS` +deleted from `cpu_vuln_blacklist`'s TIGERLAKE_L row reds the T14's fixture, +and `SRSO` deleted from its family 0x19 row reds a family-0x19 EPYC guest's. +**Oracle**: those lines, and Linux's `cpu_vuln_whitelist` and +`cpu_vuln_blacklist` row for row +(`arch/x86/kernel/cpu/common.c:1182-1244,1284-1344`). diff --git a/issues/kernel/a-split-lock-goes-unnoticed.md b/issues/kernel/a-split-lock-goes-unnoticed.md new file mode 100644 index 00000000000..8af3a7dabf0 --- /dev/null +++ b/issues/kernel/a-split-lock-goes-unnoticed.md @@ -0,0 +1,17 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# A split lock goes unnoticed + +The kernel never sets `MSR_TEST_CTRL` (0x33) bit 29, so a user `lock` +instruction across a cache line locks the bus for every CPU and nothing +reports it. Linux at `Ubuntu-6.8.0-142.142` detects it by default and warns +(`sld_warn`, `arch/x86/kernel/cpu/intel.c:1083`); ToyOS ends the process by +name instead. + +**Exit**: on the T14, the one proving machine known to enumerate split-lock +detection, a `lock add` across a line is ended by name. **Mutation**: bit 29 +clear. **Oracle**: the T14's CPU. diff --git a/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md b/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md new file mode 100644 index 00000000000..8c6054f2c9f --- /dev/null +++ b/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md @@ -0,0 +1,18 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# A TLB shootdown reaches only the CPUs that ran the space + +A shootdown blocks on every other CPU (`kernel/src/mm/unmapped.rs:5`), +whether or not it ever ran the address space. It waits on +`issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md`. + +**Exit**: on every proving machine and under TCG, a sibling pinned on another +CPU touches a page the initiator unmaps and then faults; a case in +`kernel-loom/tests/tlb_shootdown.rs` switches a CPU into the space while the +initiator reads the target set; the T14's munmap figure. **Mutation**: a +target set that omits a CPU the space ran on; a CPU that joins the set after +loading CR3. **Oracle**: loom. diff --git a/issues/kernel/each-boot-prints-the-vulnerabilities-lines-linux-prints.md b/issues/kernel/each-boot-prints-the-vulnerabilities-lines-linux-prints.md new file mode 100644 index 00000000000..8c04912bfe1 --- /dev/null +++ b/issues/kernel/each-boot-prints-the-vulnerabilities-lines-linux-prints.md @@ -0,0 +1,18 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# Each boot prints the vulnerabilities lines Linux prints + +**Exit**: each proving machine's ToyOS boot prints, for each vulnerabilities +file, the line Linux at `Ubuntu-6.8.0-142.142` printed on that machine: the +T14's from +`issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-are-not-committed.md`, +each EPYC guest's from its runner's capture. It omits only clauses about what +ToyOS does not run: `spectre_v1`'s swapgs barriers while it runs no `swapgs`, +the KVM and VM-exit clauses since it runs no guest, and `IBRS_FW` since the +kernel calls no firmware; `spec_store_bypass` reads "Mitigation: Speculative +Store Bypass disabled per program". **Mutation**: `ARCH_CAPABILITIES` read as +0 reds the T14. **Oracle**: Linux's lines. diff --git a/issues/kernel/fsgsbase-is-measured-then-taken-or-rejected.md b/issues/kernel/fsgsbase-is-measured-then-taken-or-rejected.md new file mode 100644 index 00000000000..8715ca63e28 --- /dev/null +++ b/issues/kernel/fsgsbase-is-measured-then-taken-or-rejected.md @@ -0,0 +1,21 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# FSGSBASE is measured, then taken or rejected + +`CR4.FSGSBASE` is forbidden (`kernel/src/arch/x86_64/control_regs.rs:62-75`): +GS always holds the kernel's per-CPU base and the kernel runs no `swapgs`. +Taking it costs a `swapgs` entry and the swapgs barriers of +`issues/kernel/user-pointer-checks-have-no-spectre-v1-fence-and-smap-is-optional.md`. + +**Exit**: the T14's pipe round trips with and without it, a loss becoming a +`rejected` issue with both figures. Taken: on every proving machine and under +TCG, a `boot-actuators` arm enters vector 2 at CPL 0 while the user GS base is +live, between entry and its `swapgs` or after the exit path's, and the handler +finds the kernel's per-CPU data; `CR4_FORBIDDEN`, the `user-writable-gsbase` +kernel (`src/build.rs:1370`) and the test `gsbase_locked` are deleted. +**Mutation**: an IST entry that decides `swapgs` from the saved CS alone. +**Oracle**: Linux's `paranoid_entry`. diff --git a/issues/kernel/idle-cpus-enter-the-c-states-cst-names.md b/issues/kernel/idle-cpus-enter-the-c-states-cst-names.md new file mode 100644 index 00000000000..ea53ca33f83 --- /dev/null +++ b/issues/kernel/idle-cpus-enter-the-c-states-cst-names.md @@ -0,0 +1,16 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# Idle CPUs enter the C-states `_CST` names + +The kernel runs no `mwait` and reads no `_CST`. The states come from `_CST`, +as Linux takes the T14's, after the AML interpreter that +`issues/kernel/the-scheduler-and-the-clocks-never-talk.md` waits on. + +**Exit**: on the T14, since a KVM guest's idle is its host's: the idle +minute's package energy, and timer lateness no worse than `hlt`'s by more than +the chosen state's exit latency. **Mutation**: always the deepest state. +**Oracle**: Linux's figures. diff --git a/issues/kernel/indirect-branches-and-returns-run-without-thunks.md b/issues/kernel/indirect-branches-and-returns-run-without-thunks.md new file mode 100644 index 00000000000..46934f31ada --- /dev/null +++ b/issues/kernel/indirect-branches-and-returns-run-without-thunks.md @@ -0,0 +1,29 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# Indirect branches and returns run without thunks + +Nothing in the kernel's build asks for a retpoline, a return thunk or +straight-line-speculation padding. Linux at `Ubuntu-6.8.0-142.142` builds with +`MITIGATION_RETPOLINE`, `MITIGATION_RETHUNK`, `MITIGATION_ITS` and `SLS` +(`debian.master/config/annotations:8043-8045,12190`) and installs the return +thunk its decision selects: ITS's on the T14; on AMD, retbleed's untrained +return (`arch/x86/kernel/cpu/bugs.c:1125`) or SRSO's safe RET, in its alias +form on family 0x19 (`bugs.c:2726-2732`). + +**Exit**: a gate finds no raw indirect branch or `ret` in `kernel.elf` outside +the thunks and entry, an `int3` after each, and every placement Linux's linker +script asserts (`arch/x86/kernel/vmlinux.lds.S:510-539`): +`retbleed_return_thunk` and `srso_safe_ret` at a line start, the SRSO alias +pair's addresses differing in exactly bits 2, 8, 14 and 20, and each ITS +thunk's branch in its line's upper half. Each proving machine's boot installs +the thunks the decision selects for it: ITS's on the T14, SRSO's alias on a +family-0x19 EPYC guest. No proving machine is family 0x17, so the untrained +return is proven by the gate and the decision's host test alone. +**Mutation**, each red: an ITS thunk at a line start; `retbleed_return_thunk` +one byte past its line start; the SRSO alias one cache line off its pair; an +`int3` gone; ITS's thunk installed on every CPU. **Oracle**: that linker +script, and `Documentation/admin-guide/hw-vuln/indirect-target-selection.rst`. diff --git a/issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md b/issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md new file mode 100644 index 00000000000..420cba9afc7 --- /dev/null +++ b/issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md @@ -0,0 +1,21 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# Kernel copies use `rep movsb` where the CPU has ERMS + +The kernel's copies take `rep movsb` on a CPU that enumerates ERMS, +CPUID.(7,0):EBX bit 9, and the plain copy elsewhere; a CPU without ERMS is +never refused. Zen 2 has none: a Ryzen 9 PRO 3900 (CPUID.1:EAX 0x00870F10, +family 0x17) reads CPUID.(7,0):EBX 0x219C91A9, bit 9 clear (InstLatx64 +ddff8a92, `AuthenticAMD/AuthenticAMD0870F10_K17_Matisse_CPUID.txt:52`), and +QEMU v11.1.1's EPYC-Rome model omits ERMS where its EPYC-Milan model carries +it (`target/i386/cpu.c:6792-6796,6895-6899`). The TCG model has no ERMS and +keeps the plain copy. + +**Exit**: on every proving machine and under TCG the boot selects the copy +CPUID.(7,0):EBX bit 9 names; the T14's pipe figures. **Mutation**: a +selection that ignores the bit reds on one side. **Oracle**: the CPU's own +CPUID, and Linux's pipe figures. diff --git a/issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md b/issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md new file mode 100644 index 00000000000..2c0273be2e3 --- /dev/null +++ b/issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md @@ -0,0 +1,25 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# No entry or switch clears the BHB, fills the RSB or issues an IBPB + +Nothing in `kernel/src` clears branch history, fills the return stack buffer +or issues an indirect branch prediction barrier. Linux at +`Ubuntu-6.8.0-142.142` runs `clear_bhb_loop` on entry where its decision +selects the BHI loop (`arch/x86/entry/entry_64.S:1534`), +`__FILL_RETURN_BUFFER` on a switch where it selects RSB filling +(`arch/x86/include/asm/nospec-branch.h:151`), and an IBPB on a switch between +address spaces one of which asked for it (`arch/x86/mm/tlb.c:384`). In ToyOS +the ask is the flag of +`issues/kernel/no-program-runs-with-speculative-store-bypass-disabled.md`. + +**Exit**: a gate matches `kernel.elf` against both of Linux's sequences; on +every proving machine probes count what +`issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md` +selects for it: a clear per syscall where it selects the loop, a fill per +switch where it selects filling, and two IBPBs over B, C, idle, B, A, idle, A, +B. **Mutation**: either sequence edited, the clear's condition inverted, no +fill, the IBPB decided by the previous root. **Oracle**: Linux's sequences. diff --git a/issues/kernel/no-kernel-address-is-drawn-per-boot.md b/issues/kernel/no-kernel-address-is-drawn-per-boot.md new file mode 100644 index 00000000000..31d36981770 --- /dev/null +++ b/issues/kernel/no-kernel-address-is-drawn-per-boot.md @@ -0,0 +1,20 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# No kernel address is drawn per boot + +The direct map sits at the constant `PHYS_OFFSET` +(`kernel/src/mm/mod.rs:33`) and the kernel image in it at the physical +address firmware allocated (`bootloader/src/arch/x86_64.rs:90`), so nothing +but firmware moves the kernel's layout. Linux at `Ubuntu-6.8.0-142.142` builds +with `RANDOMIZE_BASE` and `RANDOMIZE_MEMORY` +(`debian.master/config/annotations:10674,10677`): at most 9 bits of text slot, +and a direct map placed at PUD granularity. + +**Exit**: on every proving machine, over 64 boots in a `Tier::Weekly` test, +each claimed bit is set 12 to 52 times, the guard of +`issues/kernel/the-kernel-has-no-stack-protector.md` and the first spawn's +bases included. **Mutation**: a fixed base. **Oracle**: Linux's bits. diff --git a/issues/kernel/no-program-runs-with-speculative-store-bypass-disabled.md b/issues/kernel/no-program-runs-with-speculative-store-bypass-disabled.md new file mode 100644 index 00000000000..75e8fe7a229 --- /dev/null +++ b/issues/kernel/no-program-runs-with-speculative-store-bypass-disabled.md @@ -0,0 +1,18 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# No program runs with speculative store bypass disabled + +The kernel never sets SSBD, so no process can have it. Linux at +`Ubuntu-6.8.0-142.142` defaults to `prctl`: a task that asks runs with it +(`arch/x86/kernel/cpu/bugs.c:2172,2278`). In ToyOS a program asks by a flag in +`system.toml`, and a flagged program's children inherit it at spawn. + +**Exit**: on every proving machine a flagged program runs with SSBD set, +through the control +`issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md` +names for its CPU, and so does its child, while an unflagged one runs with it +clear. **Mutation**: no inheritance. **Oracle**: the CPU's own register. diff --git a/issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md b/issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md new file mode 100644 index 00000000000..c4f9f89ac6b --- /dev/null +++ b/issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md @@ -0,0 +1,16 @@ +--- +status: open +kind: tooling +opened: 2026-09-29 +--- + +# No test can hold a thread on a named CPU + +No `boot-actuators` arm and no `SYS_DEBUG` action pins a thread, so no test +can put two threads on two CPUs it knows. The pin is a `test-actuators` +action, so the shipped kernel carries none. + +**Exit**: a guest test pins a thread to each CPU in turn and reads its x2APIC +ID from CPUID.0BH:EDX across 1000 yields at each, on every proving machine and +under TCG: one ID per pin, a different one per CPU. **Mutation**: a pin the +scheduler's placement ignores. **Oracle**: the CPU's own x2APIC ID. diff --git a/issues/kernel/no-user-address-is-drawn-per-spawn.md b/issues/kernel/no-user-address-is-drawn-per-spawn.md new file mode 100644 index 00000000000..62e3cb99486 --- /dev/null +++ b/issues/kernel/no-user-address-is-drawn-per-spawn.md @@ -0,0 +1,19 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# No user address is drawn per spawn + +Every spawn puts the image at `USER_VM_BASE` (`kernel/src/loader/mod.rs:48`) +and the stack at `STACK_BASE` (`kernel/src/vma.rs:12`), and allocates +mappings in one fixed window (`kernel/src/vma.rs:18`), so an address one +process leaks is the same address in the next. Linux at `Ubuntu-6.8.0-142.142` +draws 32 bits for the image and the mmap base (`CONFIG_ARCH_MMAP_RND_BITS`, +`debian.master/config/annotations:18`) and 22 for the stack. + +**Exit**: on every proving machine, over 256 spawns each claimed bit of the +three bases is set 88 to 168 times, and each base claims Linux's bits or its +shortfall is filed as a defect. **Mutation**: `BASE + n * 2 MiB`; a constant +seed. **Oracle**: Linux's bits. diff --git a/issues/kernel/programs-hold-aes-keys-as-key-locker-handles.md b/issues/kernel/programs-hold-aes-keys-as-key-locker-handles.md new file mode 100644 index 00000000000..391fe02e0f3 --- /dev/null +++ b/issues/kernel/programs-hold-aes-keys-as-key-locker-handles.md @@ -0,0 +1,19 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# Programs hold AES keys as Key Locker handles + +Under Key Locker a program wraps an AES key into a handle under a wrapping key +the kernel loads into every CPU, and encrypts with the handle, so the key +itself need not stay in memory. Linux at `Ubuntu-6.8.0-142.142` has none: +nothing under its `arch/x86` names Key Locker. It is blocked on its first +consumer, a program that keeps an AES key for a session's life, and lands with +it, after `issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md`. + +**Exit**: on each proving machine that enumerates CPUID.19H:EBX bits 0 and 4 +and ECX bit 1, a handle wrapped on one pinned CPU gives FIPS-197 C.1's +ciphertext on another. **Mutation**: a wrapping key per CPU. **Oracle**: +FIPS-197. diff --git a/issues/kernel/spec-ctrl-and-gds-stay-as-firmware-left-them.md b/issues/kernel/spec-ctrl-and-gds-stay-as-firmware-left-them.md new file mode 100644 index 00000000000..3ccd0e00466 --- /dev/null +++ b/issues/kernel/spec-ctrl-and-gds-stay-as-firmware-left-them.md @@ -0,0 +1,21 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# SPEC_CTRL and GDS stay as firmware left them + +Nothing in `kernel/src` reads or writes `IA32_SPEC_CTRL` (0x48) or +`IA32_MCU_OPT_CTRL` (0x123), so every CPU runs under the speculation controls +firmware left, and an Intel part affected by Gather Data Sampling runs +unmitigated if firmware left `GDS_MITG_DIS` set. Linux at +`Ubuntu-6.8.0-142.142` writes both as its decision selects +(`arch/x86/kernel/cpu/bugs.c:89,777`). + +**Exit**: on every proving machine each CPU's 0x48 holds what +`issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md` +selects for it, on the T14 Linux's read less SSBD; on the T14, the one proving +machine with GDS, a probe sets `GDS_MITG_DIS` and reads it clear after the +kernel's write. **Mutation**: the clear deleted. **Oracle**: Linux's reads on +each machine. diff --git a/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md b/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md new file mode 100644 index 00000000000..3e0f771beb7 --- /dev/null +++ b/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md @@ -0,0 +1,20 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# The direct map uses 1 GiB leaves where the CPU has them + +The direct map has no 1 GiB leaf: `toyos-bootmap` maps 2 MiB and 4 KiB +(`toyos-bootmap/src/x86_64.rs:33-54`). On a CPU that enumerates `pdpe1gb`, +CPUID.80000001H:EDX bit 26, a GiB that holds one memory type takes one 1 GiB +leaf; any other GiB, and every GiB on a CPU without it, keeps 2 MiB leaves. +The TCG model gains `+pdpe1gb`, which TCG implements (`target/i386/cpu.c:945` +at QEMU v11.1.1), so the PR gate maps 1 GiB leaves. + +**Exit**: a `toyos-bootmap` host test gives a GiB holding one UC range 2 MiB +leaves, a uniform GiB one leaf, and every GiB 2 MiB leaves without `pdpe1gb`; +each proving machine's boot reports its leaf counts; the T14's 64 KiB pipe +figure. **Mutation**: a 1 GiB leaf for every GiB. **Oracle**: SDM Vol. 3A +§14.11.9. diff --git a/issues/kernel/the-kernel-has-no-stack-protector.md b/issues/kernel/the-kernel-has-no-stack-protector.md new file mode 100644 index 00000000000..d006560db11 --- /dev/null +++ b/issues/kernel/the-kernel-has-no-stack-protector.md @@ -0,0 +1,21 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# The kernel has no stack protector + +Nothing in the build asks rustc for a stack protector, so an overflow of a +kernel stack buffer reaches the return address unchecked. Linux at +`Ubuntu-6.8.0-142.142` builds with `STACKPROTECTOR_STRONG` +(`debian.master/config/annotations:13402`), its guard at a fixed `%gs` offset +and switched per task. + +**Exit**: the kernel builds with a strong stack protector whose guard is at +`%gs:`, through LLVM and rustc changes the orchestrator admitted as +upstream-quality cross-platform options; `stack-protector-3.ll` and a rustc +assembly test see `%gs:` and no `__stack_chk_guard`; on every proving +machine the guest test `kernel_stack_canary` panics on thread B's guard in A's +frame. **Mutation**: the old lowering; the flags dropped; `context_switch`'s +write gone; a constant guard. **Oracle**: FileCheck, and the CPU's compare. diff --git a/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md b/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md new file mode 100644 index 00000000000..9370d510cda --- /dev/null +++ b/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md @@ -0,0 +1,43 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# The kernel is at least as secure as Linux on every machine ToyOS supports + +Parity with Linux at `Ubuntu-6.8.0-142.142`, pinned by the first issue below, +is the floor on every CPU ToyOS supports, and the kernel also takes every +security feature such a CPU offers. The proving machines are the T14 and the +nightly's AMD EPYC KVM guests; the PR gate's TCG model proves wiring only. A +probe is a `boot-actuators` arm or a `test-actuators` `SYS_DEBUG` action, +never a syscall. + +**Exit**: every issue below is closed, in the order listed. + +- `issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-are-not-committed.md` +- `issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md` +- `issues/kernel/spec-ctrl-and-gds-stay-as-firmware-left-them.md` +- `issues/kernel/no-program-runs-with-speculative-store-bypass-disabled.md` +- `issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md` +- `issues/kernel/user-pointer-checks-have-no-spectre-v1-fence-and-smap-is-optional.md` +- `issues/kernel/indirect-branches-and-returns-run-without-thunks.md` +- `issues/kernel/tsx-stays-as-firmware-left-it.md` +- `issues/kernel/whether-the-kernel-loads-cpu-microcode-is-the-owners.md` +- `issues/kernel/no-user-address-is-drawn-per-spawn.md` +- `issues/kernel/the-kernel-has-no-stack-protector.md` +- `issues/kernel/no-kernel-address-is-drawn-per-boot.md` +- `issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md` +- `issues/kernel/kernel-functions-return-with-their-used-registers-intact.md` +- `issues/kernel/a-threads-kernel-stack-has-no-guard-page.md` +- `issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md` +- `issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md` +- `issues/kernel/a-device-without-a-domain-of-its-own-reaches-all-memory.md` +- `issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md` +- `issues/kernel/user-programs-run-without-a-shadow-stack.md` +- `issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md` +- `issues/kernel/the-kernel-runs-without-a-shadow-stack.md` +- `issues/kernel/user-programs-have-no-protection-keys.md` +- `issues/kernel/programs-hold-aes-keys-as-key-locker-handles.md` +- `issues/kernel/a-split-lock-goes-unnoticed.md` +- `issues/kernel/each-boot-prints-the-vulnerabilities-lines-linux-prints.md` diff --git a/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md b/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md deleted file mode 100644 index ec7a9c7d8d7..00000000000 --- a/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -status: open -kind: track -opened: 2026-09-29 ---- - -# The kernel is at least as secure as Linux on the T14 - -Owner ruling: parity with the Linux the T14 -(`issues/hardware/the-t14-boots-toyos-unattended.md`) runs is the floor, and -the T14 also gets every security feature its CPU and platform support. That -Linux is tag `Ubuntu-6.8.0-142.142` (53e5d07aac028a1523ab0b115f079d6d1bc831ef) -of `https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/noble`, -config sha256 3b8533dd9d235ca634ac58f82c5ce1ee35f12ef620693e17033184d2c9ca5890. -A hardening default its config sets and no vulnerabilities line reports is -closed by the stage naming it or by a defect the Exit names; ToyOS already -meets `INIT_ON_ALLOC_DEFAULT_ON`, `SCHED_STACK_END_CHECK`, `HARDENED_USERCOPY` -and `X86_UMIP`, Rust meets `INIT_STACK_ALL_ZERO`, `FORTIFY_SOURCE` and -`UBSAN_*`, ToyOS has no modules, kexec, BPF or vsyscall page, and -`SHUFFLE_PAGE_ALLOCATOR` is off by default. A QEMU test asserts wiring, S1 -over the facts the guest reports. A probe is a `boot-actuators` arm or a -`test-actuators` `SYS_DEBUG` action, never a syscall. A stage's oracle is the -T14's CPU unless it names another. - -- **S0 — Evidence.** Exit: the T14's and the TCG model's captures under that - Linux, committed as S1's fixtures, and no Linux image; before the wipe it - adds CPUID 5, 0x19 and 0x80000001, MSR 0xCF, the split-lock line and the - config's IBT and PKU options. Mutation: a config hash off by one byte is - refused. Oracle: that Linux. Ubuntu leaves the T14 only after this and P0 of - `issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md`. -- **S1 — The decision**, host-tested, from a CPU's facts to each - vulnerabilities line and mitigation. Exit: S0's facts give S0's lines. - Mutation: `GDS` deleted from `cpu_vuln_blacklist`'s TIGERLAKE_L row. - Oracle: S0's lines. -- **S2 — SPEC_CTRL and GDS.** Exit, T14: every CPU's 0x48 is S0's read less - SSBD, and a probe sets `GDS_MITG_DIS` and reads it clear after the kernel's - write. Mutation: the clear deleted. Oracle: S0's reads. -- **S3 — BHB clear, RSB fill, IBPB conditional on S6's flag.** Exit: a gate - matches `kernel.elf` against `clear_bhb_loop` and `__FILL_RETURN_BUFFER`; - probes count a clear per syscall and two IBPBs over B, C, idle, B, A, idle, - A, B on the T14, and a fill per switch under TCG. Mutation: either sequence - edited, the clear's condition inverted, no fill, IBPB decided by the - previous root. Oracle: Linux's sequences. -- **S4 — Spectre v1**: SMAP required, `lfence` and mask at `user_ptr`'s range - checks. Exit: a boot without SMAP is refused by name; on the T14 a gadget - through each site leaks a planted byte in at most 16 of 1000 trials. - Mutation: SMAP optional; a site's fence or mask gone must exceed 16. -- **S5 — Thunks for every indirect branch and return, and `SLS`.** Exit: a - gate finds no raw indirect branch or `ret` outside thunks and entry, `int3` - after each there, each ITS thunk's branch at `addr & 63 >= 32`; boots - compare live thunks with S1's. Mutation: a branch at a line start, an `int3` - gone, the ITS thunk everywhere. Oracle: `indirect-target-selection.rst`. -- **S6 — SSBD per program flagged in `system.toml`**, inherited at spawn. - Exit, T14: it reads clear, set, and set in a flagged process's child. - Mutation: no inheritance. -- **S7 — Microcode loading, the owner's**: it is firmware run on the CPU, - which root `CLAUDE.md` does not carve out. Exit: S0 shows the BIOS at - Linux's fixing revision, or the owner rules. -- **S8 — User ASLR, `ARCH_MMAP_RND_BITS`.** Exit: over 256 spawns each claimed - bit of the three bases is set 88 to 168 times. Mutation: `BASE + n * 2 - MiB`, a constant seed. Oracle: Linux's 32 bits for image and mmap and 22 - for the stack; a shortfall is a defect. -- **S9 — `STACKPROTECTOR_STRONG`** at `%gs:N`, by LLVM and rustc changes the - orchestrator admitted as upstream-quality cross-platform options. Exit: - `stack-protector-3.ll` and a rustc assembly test see `%gs:` and no - `__stack_chk_guard`; `kernel_stack_canary` panics on B's guard in A's - frame. Mutation: the old lowering, the flags dropped, `context_switch`'s - write gone, a constant guard. Oracle: FileCheck, and the CPU's compare. -- **S10 — `RANDOMIZE_BASE`, `RANDOMIZE_MEMORY`, `Tier::Weekly`.** Exit: 64 - boots set each claimed bit 12 to 52 times, S9's guard and S8's first spawn - included. Mutation: a fixed base. Oracle: Linux's at most 9 bits of text - slot and a PUD-granular direct map. -- **S11 — `X86_USER_SHADOW_STACK`.** Owner ruling: the loader refuses every - program and library without `GNU_PROPERTY_X86_FEATURE_1_SHSTK`, on every - CPU. Exit: `unmarked_object_refused` under TCG; a sysroot link with an - unmarked input reds; on the T14 a forged return is `#CP` in two threads, a - caught panic unwinds, a store to the shadow stack is `#PF`, and `user_ptr` - refuses a `read` into it with `BadAddress`. Mutation: the check gone, - `SH_STK_EN` clear, one shadow stack for two threads, no `incssp`, the stack - mapped writable or faulted in as CoW. -- **S12 — `X86_KERNEL_IBT`**, unset in the config. Exit: a gate finds - `endbr64` at every IDT and `IA32_LSTAR` target and no `notrack`; on the T14 - a call to a function without one is `#CP`. Mutation: `syscall_entry`'s - `endbr64` gone, `ENDBR_EN` clear. -- **S13 — Kernel shadow stack**, which Linux lacks; CET_SSS, CPUID.(7,1):EDX - bit 18. Exit, T14: a forged kernel return is `#CP`, `kernel_stack_canary` - runs under it, a `DirectMap` store to a shadow stack faults. Mutation: - `SH_STK_EN` clear, SSP not switched, the frame in the writable direct map. -- **S14 — `X86_INTEL_MEMORY_PROTECTION_KEYS`**, after P1; owner ruling: its - ABI is approved in principle. Exit, TCG `+pku` and T14: a write under a key - the thread denied is `#PF` with PK, a sibling's is not, and `window` refuses a - `read` into it. Mutation: no key in the entry, one PKRU for all threads, no - key check in `window`. Oracle: TCG and the T14 on SDM Vol. 3A §5.6.2. -- **S15 — Key Locker**, after the speed track's Pin; CPUID.19H:EBX bits 0 and - 4, ECX bit 1. Exit, T14: a handle wrapped on one pinned CPU gives FIPS-197 - C.1's ciphertext on another. Mutation: an IWKey per CPU. Oracle: FIPS-197. -- **S16 — Split-lock disable**, Linux's default without a config option; a - split lock ends a ToyOS process where Linux warns. Exit, T14: a `lock add` - across a line is ended by name. Mutation: `MSR_MEMORY_CTRL` bit 29 clear. - -**Exit.** The T14's ToyOS boot prints S0's Linux line for each -vulnerabilities file, less `spectre_v1`'s swapgs barriers while ToyOS runs -no `swapgs` and `spectre_v2`'s VM-exit clauses, since it runs no guest; -`spec_store_bypass` reads "Mitigation: Speculative Store Bypass disabled per -program". Mutation: ARCH_CAPABILITIES read as 0. Every stage is green or -closed, and so is every defect the hardening defaults name: -`issues/boot-media/the-loader-never-sets-the-firmwares-memory-overwrite-request.md`, -`issues/kernel/every-syscall-runs-at-one-kernel-stack-offset.md`, -`issues/kernel/kernel-functions-return-with-their-used-registers-intact.md`, -`issues/kernel/a-threads-kernel-stack-has-no-guard-page.md`, -`issues/kernel/kernel-text-is-writable-and-every-kernel-page-executable.md`, -`issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md`, -`issues/kernel/tsx-stays-as-firmware-left-it.md`, -`issues/kernel/a-device-without-a-domain-of-its-own-reaches-all-memory.md`. diff --git a/issues/kernel/the-kernel-runs-without-a-shadow-stack.md b/issues/kernel/the-kernel-runs-without-a-shadow-stack.md new file mode 100644 index 00000000000..e0c80694d90 --- /dev/null +++ b/issues/kernel/the-kernel-runs-without-a-shadow-stack.md @@ -0,0 +1,19 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# The kernel runs without a shadow stack + +Nothing checks a kernel return, so an overwritten kernel return address is +taken. Linux at `Ubuntu-6.8.0-142.142` has no kernel shadow stack; the kernel +takes one where the CPU enumerates supervisor shadow stacks, CET_SSS, +CPUID.(7,1):EDX bit 18, which the T14 reads set (EDX 0x00040000). + +**Exit**: on the T14, the one proving machine known to enumerate CET_SSS, a +forged kernel return is `#CP`, the guest test `kernel_stack_canary` of +`issues/kernel/the-kernel-has-no-stack-protector.md` runs under it, and a +store through `DirectMap` to a shadow stack faults. **Mutation**: `SH_STK_EN` +clear; SSP not switched; the frame left in the writable direct map. +**Oracle**: the T14's CPU. diff --git a/issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md b/issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md new file mode 100644 index 00000000000..1b3be91b828 --- /dev/null +++ b/issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md @@ -0,0 +1,18 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# The kernel runs without indirect branch tracking + +Nothing in the build asks for `endbr64` and nothing sets `S_CET.ENDBR_EN`, so +an indirect call or jump in the kernel may land anywhere in its text. Linux at +`Ubuntu-6.8.0-142.142` leaves `X86_KERNEL_IBT` unset +(`debian.master/config/annotations:834`); the kernel takes it where the CPU +enumerates IBT. + +**Exit**: a gate finds `endbr64` at every IDT and `IA32_LSTAR` target and no +`notrack` in `kernel.elf`; on the T14, the one proving machine known to +enumerate IBT, a call to a function without one is `#CP`. **Mutation**: +`syscall_entry`'s `endbr64` gone; `ENDBR_EN` clear. **Oracle**: the T14's CPU. diff --git a/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md b/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md new file mode 100644 index 00000000000..dc0e3f07794 --- /dev/null +++ b/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md @@ -0,0 +1,31 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# ToyOS uses what modern hardware offers for speed + +ToyOS takes each hardware feature that makes it faster on every CPU that +enumerates it; a CPU without one runs the plain path, or is refused by name +where the stage says so. The proving machines are the T14 and the nightly's +AMD EPYC KVM guests, and a stage's correctness test runs on each that has its +feature. A figure is the T14's, since the EPYC guests are shared CI runners: +the median of 11 runs with its spread, taken by the program of +`issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md`. +A stage is done at or past that program's Linux figure, or with the gap filed +as a defect carrying both; a feature Linux has no counterpart for lands only +if it beats ToyOS without it. What no proving machine is known to offer is +`issues/hardware/features-no-proving-machine-is-known-to-offer.md`. + +**Exit**: every issue below is closed, in the order listed. + +- `issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md` +- `issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md` +- `issues/kernel/user-programs-use-avx-under-xsave.md` +- `issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md` +- `issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md` +- `issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md` +- `issues/kernel/fsgsbase-is-measured-then-taken-or-rejected.md` +- `issues/kernel/idle-cpus-enter-the-c-states-cst-names.md` +- `issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md` diff --git a/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md b/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md deleted file mode 100644 index cfa7ca949b1..00000000000 --- a/issues/kernel/toyos-uses-what-the-t14s-hardware-offers-for-speed.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -status: open -kind: track -opened: 2026-09-29 ---- - -# ToyOS uses what the T14's hardware offers for speed - -Owner ruling: ToyOS takes the hardware features that make it faster, at least -on the T14; what the T14 lacks is -`issues/hardware/newer-hardware-offers-what-the-t14-lacks.md`. A figure is the -median of 11 T14 runs with its spread, taken by P0's program. A stage is done -at or past P0's Linux figure, or with the gap filed as a defect carrying both; -one Linux has no counterpart for lands only if it beats ToyOS without it. The -kernel uses no vector registers, as Linux's kernel does not. - -- **Pin — a test holds a thread on a named CPU**, a `test-actuators` - `SYS_DEBUG` action. Exit: a guest test pins a thread to each CPU in turn and - reads CPUID.1:EBX[31:24] across 1000 yields at each: one APIC ID per pin, a - different one per CPU. Mutation: a pin the scheduler's placement ignores. - Oracle: the CPU's own APIC ID. -- **P0 — The Linux baseline.** One Rust program, built for - `x86_64-unknown-linux-gnu` and for ToyOS, measures memcpy from 64 B to 64 - MiB; AES-128-GCM, ChaCha20-Poly1305 and SHA-256 at sshd's RustCrypto - versions; pipe round trips, and throughput at 64 B to 64 KiB; munmaps per - second of a page a sibling on another CPU touched; lateness past a 1 ms - timer; NVMe reads, read-only; an idle minute's package energy; and the - T14's PCI, USB, NVMe and cpuidle identity. Exit: the outputs committed as - fixtures. Mutation: the munmap pair on one CPU, as `sched_getcpu` or Pin - reads it, is refused. Oracle: Linux. -- **P1 — XSAVE, and AVX to AVX-512 in user programs**, with one save path on - every CPU, XSAVEOPT: TCG implements neither XSAVEC nor XSAVES - (`target/i386/cpu.c:1012-1014` at QEMU v11.1.1), and the security track's - S11 switches its CET state by `wrmsr`, as `fs_base` is. Exit: threads that - fill their vector registers differently each find their own after a switch, - under TCG and on the T14; P0's ChaCha20-Poly1305 figure. Mutation: a save - mask short of Hi16_ZMM, and under TCG of YMM. Oracle: TCG and the T14 on SDM - Vol. 1 §13. -- **P2 — Kernel copies with `rep movsb`**, `+ermsb` for the kernel and the - `core`, `alloc` and `compiler_builtins` it builds; a CPU without ERMS is - refused by name. Exit: a gate finds `rep movsb` in `kernel.elf`'s `memcpy`; - P0's pipe figures. Mutation: no `+ermsb`. Oracle: P0's Linux figures. -- **P3 — 1 GiB direct-map leaves** where a GiB holds one memory type. Exit: a - `toyos-bootmap` host test gives a GiB holding one UC range 2 MiB leaves and - a uniform GiB one leaf; P0's 64 KiB pipe figure and the boot's leaf counts. - Mutation: a 1 GiB leaf for every GiB. Oracle: SDM Vol. 3A §14.11.9. -- **P4 — Shootdowns only to the CPUs that ran the space**, after Pin. Exit: a - sibling pinned on another CPU touches a page the initiator unmaps and then - faults; a case in `kernel-loom/tests/tlb_shootdown.rs` switches a CPU into - the space while the initiator reads the target set; P0's munmap figure. - Mutation: a target set that omits a CPU the space ran on, and a CPU that - joins the set after loading CR3. Oracle: loom. -- **P5 — FSGSBASE, measured, then taken or rejected**; it costs a `swapgs` - entry and the security track's S4 barriers. Exit: P0's round trips with and - without, a loss becoming a `rejected` issue with both figures; taken, an NMI - that arrives while a user GS base is set finds the kernel's. Mutation: an - IST entry that decides `swapgs` from the saved CS alone. Oracle: Linux's - `paranoid_entry`. -- **P6 — Deep idle** from `_CST`, as Linux takes the T14's states, after the - AML interpreter `issues/kernel/the-scheduler-and-the-clocks-never-talk.md` - waits on. Exit: P0's idle minute's energy, and P0's timer lateness no worse - than `hlt`'s by more than the chosen state's exit latency. Mutation: always - the deepest state. Oracle: P0's Linux figures. -- **P7 — NVMe APST and host memory buffer**, after blockd drives the T14's - drive (step 3 of - `issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`); as - Linux, APST stays within `default_ps_max_latency_us` and honours - `NVME_QUIRK_NO_APST` and `NVME_QUIRK_NO_DEEPEST_PS`. Exit: P0's block - figures, and P6's idle minute with the drive idle. Mutation: a host test's - table that admits a state past the bound. Oracle: Linux's - `nvme_configure_apst` over P0's `id-ctrl`. diff --git a/issues/kernel/tsx-stays-as-firmware-left-it.md b/issues/kernel/tsx-stays-as-firmware-left-it.md index 6b8984acae2..a2bd73517cd 100644 --- a/issues/kernel/tsx-stays-as-firmware-left-it.md +++ b/issues/kernel/tsx-stays-as-firmware-left-it.md @@ -17,8 +17,10 @@ T14's `CONFIG_X86_INTEL_TSX_MODE_OFF=y`, runs `tsx_init` `ARCH_CAPABILITIES.TSX_CTRL_MSR`, sets `RTM_DISABLE | TSX_CPUID_CLEAR` (`tsx.c:23-41,189-226`). -**Exit**: S1 of -`issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-the-t14.md` +**Exit**: +`issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md` carries `tsx_init`'s decision and every CPU applies it; on the T14, ToyOS's -reads of 0x122, 0x10F and 0x123 equal S0's Linux reads where each exists, -and dropping the write leaves 0x122 or 0x10F at firmware's value and reds it. +reads of 0x122, 0x10F and 0x123 equal the Linux reads of +`issues/hardware/linuxs-readings-of-the-t14-and-the-tcg-model-are-not-committed.md` +where each exists, and dropping the write leaves 0x122 or 0x10F at firmware's +value and reds it. diff --git a/issues/kernel/user-pointer-checks-have-no-spectre-v1-fence-and-smap-is-optional.md b/issues/kernel/user-pointer-checks-have-no-spectre-v1-fence-and-smap-is-optional.md new file mode 100644 index 00000000000..b0e4ac6ecc8 --- /dev/null +++ b/issues/kernel/user-pointer-checks-have-no-spectre-v1-fence-and-smap-is-optional.md @@ -0,0 +1,21 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# User-pointer checks have no Spectre v1 fence, and SMAP is optional + +`user_ptr`'s range checks carry no `lfence` and no index mask, and SMAP is an +optional bit of the CR4 declaration +(`kernel/src/arch/x86_64/control_regs.rs:60`), so a CPU without it boots, and +a mispredicted check can load through a user pointer. Linux at +`Ubuntu-6.8.0-142.142` reports `usercopy/swapgs barriers and __user pointer +sanitization`. + +**Exit**: SMAP is required and a boot without it is refused by name; on every +proving machine a gadget through each `user_ptr` site recovers a planted byte +no more often than chance, 1 in 256, by a bound the stage derives over 1000 +trials from the same gadget's unfenced rate on that machine. **Mutation**: +SMAP optional again; a site's fence or mask removed exceeds the bound. +**Oracle**: the CPU's own speculation. diff --git a/issues/kernel/user-programs-have-no-protection-keys.md b/issues/kernel/user-programs-have-no-protection-keys.md new file mode 100644 index 00000000000..06a756d2652 --- /dev/null +++ b/issues/kernel/user-programs-have-no-protection-keys.md @@ -0,0 +1,24 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# User programs have no protection keys + +`CR4.PKE` is never set and no mapping carries a key, so a thread cannot fence +part of its own memory off from itself. Linux at `Ubuntu-6.8.0-142.142` builds +with `X86_INTEL_MEMORY_PROTECTION_KEYS` +(`debian.master/config/annotations:15334`). Its ABI is approved in principle +and shaped in this issue's pull request, which lands after +`issues/kernel/user-programs-use-avx-under-xsave.md`, since PKRU is XSAVE +state. + +**Exit**: under TCG with `+pku` (`target/i386/cpu.c:992` at QEMU v11.1.1), on +the T14, and on each EPYC guest that enumerates PKU: a write under a key the +thread denied is `#PF` with PK set, and a sibling thread's is not; `window` +refuses a `read(2)` into a page under a key the thread write-denied, and a +`write(2)` from a buffer under a key it access-denied. **Mutation**: no key in +the entry; one PKRU for all threads; `window` without the key check; `window` +checking the key only on `Access::Write`, which the `write(2)` reds. +**Oracle**: TCG and the T14 on SDM Vol. 3A §5.6.2. diff --git a/issues/kernel/user-programs-run-without-a-shadow-stack.md b/issues/kernel/user-programs-run-without-a-shadow-stack.md new file mode 100644 index 00000000000..8900397773f --- /dev/null +++ b/issues/kernel/user-programs-run-without-a-shadow-stack.md @@ -0,0 +1,26 @@ +--- +status: open +kind: defect +opened: 2026-09-29 +--- + +# User programs run without a shadow stack + +At `Ubuntu-6.8.0-142.142`, `CONFIG_X86_USER_SHADOW_STACK=y` (config line 502) +lets a process opt into CET shadow stacks: a return address a `RET` pops is +checked against a hardware-maintained copy that ordinary writes cannot reach, +so a corrupted return address on the data stack is refused rather than taken. +ToyOS builds no user shadow stack: no program can enable one, and nothing in +`kernel/src` maps a shadow-stack page or sets `CR4.CET`/`MSR_IA32_U_CET`. +ToyOS does not make it opt-in: the loader refuses every program and library +without `GNU_PROPERTY_X86_FEATURE_1_SHSTK`, on every CPU, with or without +shadow-stack hardware. + +**Exit**: the guest test `unmarked_object_refused` passes on every proving +machine and under TCG; a sysroot link with one unmarked input reds, since lld +ANDs the property; on the T14, the one proving machine known to enumerate +shadow stacks, a forged return is `#CP` in two threads, a caught panic +unwinds, a store to the shadow stack is `#PF`, and `user_ptr` refuses a `read` +into it with `BadAddress`. **Mutation**: the property check gone; `SH_STK_EN` +clear; one shadow stack for two threads; no `incssp`; the stack mapped +writable or faulted in as CoW. **Oracle**: the T14's CPU. diff --git a/issues/kernel/user-programs-use-avx-under-xsave.md b/issues/kernel/user-programs-use-avx-under-xsave.md new file mode 100644 index 00000000000..cbaeab370b4 --- /dev/null +++ b/issues/kernel/user-programs-use-avx-under-xsave.md @@ -0,0 +1,22 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# User programs use AVX to AVX-512 under XSAVE + +`CR4.OSXSAVE` stays clear and a thread's state is its `FXSAVE64` image +(`kernel/src/arch/x86_64/fpu.rs:6-7`), so AVX is `#UD` in every user program. +The kernel enables every vector component the CPU enumerates and saves them +by one path on every CPU, XSAVEOPT, refusing by name a CPU without it: TCG +implements neither XSAVEC nor XSAVES (`target/i386/cpu.c:1012-1014` at QEMU +v11.1.1), and the CET state of +`issues/kernel/user-programs-run-without-a-shadow-stack.md` is switched by +`wrmsr`, as `fs_base` is. The TCG model gains `+xsave,+xsaveopt,+avx,+avx2`, +which TCG implements (`cpu.c:905,907,981,1012`). + +**Exit**: on every proving machine and under TCG, threads that fill their +vector registers differently each find their own after a switch; the T14's +ChaCha20-Poly1305 figure. **Mutation**: a save mask short of Hi16_ZMM, and +under TCG of YMM. **Oracle**: TCG and the T14 on SDM Vol. 1 §13. diff --git a/issues/kernel/whether-the-kernel-loads-cpu-microcode-is-the-owners.md b/issues/kernel/whether-the-kernel-loads-cpu-microcode-is-the-owners.md new file mode 100644 index 00000000000..1e6b8e4fef2 --- /dev/null +++ b/issues/kernel/whether-the-kernel-loads-cpu-microcode-is-the-owners.md @@ -0,0 +1,14 @@ +--- +status: owner +kind: question +opened: 2026-09-29 +--- + +# Whether the kernel loads CPU microcode is the owner's + +Microcode is firmware that runs on the CPU, which root `CLAUDE.md` does not +carve out: it admits only device firmware that never executes on the CPU. Until +the kernel loads it, a CPU whose BIOS ships stale microcode stays below Linux +at `Ubuntu-6.8.0-142.142` on every line that rests on microcode. + +**Exit**: the owner rules. From 0e24b5c0d49320a7100e070976ff6c8724df6ddc Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 12:54:17 +0200 Subject: [PATCH 4/6] PR #603 round 3: kernel copies are one rep movsb on every CPU The round-2 review's fix for the ERMS stage: one rep movsb path on every CPU and no refusal. The previous round-3 commit selected rep movsb by CPUID at boot and kept the plain copy elsewhere, which is two paths. The kernel's memcpy, memmove and memset are compiler_builtins', which choose at compile time: the ermsb target feature gives one rep movsb or rep stosb, and without it rep movsq or rep stosq sits between two byte strings (compiler-builtins/src/mem/x86_64.rs:15-17,23-58,88-126). So the stage builds them with ermsb, and no runtime selection exists to test. A gate over kernel.elf finds no rep movsq or rep stosq in a forward copy or fill, and a build without ermsb reds it. Zen 2 runs the same path without ERMS. No proving machine is family 0x17, so its cost there is recorded as unmeasured. The stage is renamed kernel-copies-are-one-rep-movsb-on-every-cpu, and the speed track's list moves with it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01U6SVYFkdvV2t38KzNrESxs --- ...l-copies-are-one-rep-movsb-on-every-cpu.md | 22 +++++++++++++++++++ ...es-use-rep-movsb-where-the-cpu-has-erms.md | 21 ------------------ ...s-what-modern-hardware-offers-for-speed.md | 2 +- 3 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md delete mode 100644 issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md diff --git a/issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md b/issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md new file mode 100644 index 00000000000..2652336dda4 --- /dev/null +++ b/issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md @@ -0,0 +1,22 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# Kernel copies are one `rep movsb` on every CPU + +The kernel's `memcpy`, `memmove` and `memset` are `compiler_builtins`', which +frame `rep movsq` or `rep stosq` with two byte strings, and take one `rep movsb` +or `rep stosb` only when built with the `ermsb` target feature +(`rust/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs:15-17,23-58,88-126`). +The kernel builds them with it, one path on every CPU: `rep movsb` is correct +without ERMS, CPUID.(7,0):EBX bit 9, and no CPU is refused. Zen 2 lacks ERMS +(a Ryzen 9 PRO 3900, family 0x17, reads EBX 0x219C91A9: InstLatx64 ddff8a92, +`AuthenticAMD/AuthenticAMD0870F10_K17_Matisse_CPUID.txt:52`), and no proving +machine is family 0x17, so the cost there is unmeasured. + +**Exit**: a gate finds each forward copy and fill in `kernel.elf` one `rep +movsb` or `rep stosb`, with no `rep movsq` or `rep stosq`; the T14's pipe +figures. **Mutation**: the build without `ermsb` reds the gate. **Oracle**: +Linux's pipe figures. diff --git a/issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md b/issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md deleted file mode 100644 index 420cba9afc7..00000000000 --- a/issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -status: open -kind: track -opened: 2026-09-29 ---- - -# Kernel copies use `rep movsb` where the CPU has ERMS - -The kernel's copies take `rep movsb` on a CPU that enumerates ERMS, -CPUID.(7,0):EBX bit 9, and the plain copy elsewhere; a CPU without ERMS is -never refused. Zen 2 has none: a Ryzen 9 PRO 3900 (CPUID.1:EAX 0x00870F10, -family 0x17) reads CPUID.(7,0):EBX 0x219C91A9, bit 9 clear (InstLatx64 -ddff8a92, `AuthenticAMD/AuthenticAMD0870F10_K17_Matisse_CPUID.txt:52`), and -QEMU v11.1.1's EPYC-Rome model omits ERMS where its EPYC-Milan model carries -it (`target/i386/cpu.c:6792-6796,6895-6899`). The TCG model has no ERMS and -keeps the plain copy. - -**Exit**: on every proving machine and under TCG the boot selects the copy -CPUID.(7,0):EBX bit 9 names; the T14's pipe figures. **Mutation**: a -selection that ignores the bit reds on one side. **Oracle**: the CPU's own -CPUID, and Linux's pipe figures. diff --git a/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md b/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md index dc0e3f07794..58fdc70a0cb 100644 --- a/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md +++ b/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md @@ -23,7 +23,7 @@ if it beats ToyOS without it. What no proving machine is known to offer is - `issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md` - `issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md` - `issues/kernel/user-programs-use-avx-under-xsave.md` -- `issues/kernel/kernel-copies-use-rep-movsb-where-the-cpu-has-erms.md` +- `issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md` - `issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md` - `issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md` - `issues/kernel/fsgsbase-is-measured-then-taken-or-rejected.md` From 7ef57418b65f6e2fec29ac7d7c29652658209e34 Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 13:36:31 +0200 Subject: [PATCH 5/6] PR #603 round 4: the direct map is the kernel's, the shootdown test sees PCID, and kernel.elf's gates share one decoder The round-3 review's two BLOCKERs, five NOTEs and REMOVEs. - 1 GiB leaves: the direct map is paging::init's, which maps it 2 MiB at a time (paging.rs:953-956); toyos-bootmap's map is the loader's. The leaf decision is a pure function paging::init calls, beside direct_map_end. policy_at, guard_4k and ensure_table under map_2m each read a PDPT entry as a table, so each splits a 1 GiB leaf. A TCG +pdpe1gb boot-actuators arm guards a page and maps MMIO inside a 1 GiB leaf; guard_4k without the split must go red. - TLB shootdown: every CR3 load sets NOFLUSH under PCID (paging.rs:295-306), so a switched-out CPU keeps the space's entries. The sibling blocks off its pinned CPU before the unmap and touches the page after it wakes there, on each proving machine with PCID; the TCG model has none (src/arch.rs:169). A loom case switches out. Clearing a CPU from the set when it switches away must go red. - Copies: the kernel links the sysroot's compiler_builtins, built by src/sysroot.rs's build_std from std_config (sysroot.rs:522), whose place_std replaces each guest target's libraries from the stage-2 toolchain. So the feature is std_config's [target.x86_64-unknown-none] rustflags, which moves the sysroot key (RECIPE, sysroot.rs:65), not write_config's; bootstrap applies a target's rustflags to every crate built for it (core/builder/cargo.rs:1488-1494). The gate is scoped to memcpy, memset and memmove's forward branch, because copy_backward keeps rep movsq under ermsb, and the slug says so. The exit records Zen 2's cost as a figure or a tooling issue. - issues/build/no-gate-decodes-kernel-elfs-instructions.md: the five kernel.elf gates' one Rust decoder, listed before them in both tracks. - The benchmark reads both x2APIC IDs before and after the timed window. - NVMe: the host memory buffer is sized as Linux v6.8 sizes it (pci.c:55,2019-2037, max_host_mem_size_mb 128) and confined to blockd's domain; the slug says so. - Removed ", never a syscall" from the security track. Gate: cargo run -- --ci host exit 0 (54 steps, all green). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01U6SVYFkdvV2t38KzNrESxs --- ...o-gate-decodes-kernel-elfs-instructions.md | 28 +++++++++++++++++ ...st-memory-buffer-confined-to-its-domain.md | 26 ++++++++++++++++ ...es-nvme-apst-and-the-host-memory-buffer.md | 18 ----------- ...ures-toyos-against-linux-on-one-machine.md | 12 ++++--- ...eaches-only-the-cpus-that-ran-the-space.md | 21 +++++++++---- ...branches-and-returns-run-without-thunks.md | 5 +-- ...l-copies-are-one-rep-movsb-on-every-cpu.md | 22 ------------- ...are-one-rep-movsb-or-stosb-on-every-cpu.md | 31 +++++++++++++++++++ ...return-with-their-used-registers-intact.md | 3 +- ...the-bhb-fills-the-rsb-or-issues-an-ibpb.md | 4 ++- ...ses-1-gib-leaves-where-the-cpu-has-them.md | 27 ++++++++++------ ...s-linux-on-every-machine-toyos-supports.md | 4 +-- ...l-runs-without-indirect-branch-tracking.md | 5 +-- ...s-what-modern-hardware-offers-for-speed.md | 5 +-- 14 files changed, 142 insertions(+), 69 deletions(-) create mode 100644 issues/build/no-gate-decodes-kernel-elfs-instructions.md create mode 100644 issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md delete mode 100644 issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md delete mode 100644 issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md create mode 100644 issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md diff --git a/issues/build/no-gate-decodes-kernel-elfs-instructions.md b/issues/build/no-gate-decodes-kernel-elfs-instructions.md new file mode 100644 index 00000000000..96080bb2ca6 --- /dev/null +++ b/issues/build/no-gate-decodes-kernel-elfs-instructions.md @@ -0,0 +1,28 @@ +--- +status: open +kind: tooling +opened: 2026-09-29 +--- + +# No gate decodes `kernel.elf`'s instructions + +Five stages each owe a gate over `kernel.elf`'s instructions: + +- `issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md` +- `issues/kernel/indirect-branches-and-returns-run-without-thunks.md` +- `issues/kernel/kernel-functions-return-with-their-used-registers-intact.md` +- `issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md` +- `issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md` + +The one gate that reads `kernel.elf` today matches bytes at a symbol +(`judge_entry_window`, `src/build.rs:1641`), which cannot tell an opcode from a +displacement or an immediate. The five share one x86-64 decoder, in Rust in the +tree and run by the host gate, with no external disassembler: it lands before +any of them, and each adds its own check over it rather than a decoder of its +own. + +**Exit**: the decoder walks every function `kernel.elf`'s `.symtab` names, from +its address to its size, and a walk that decodes a byte it does not know or +ends anywhere but the function's end is refused. **Mutation**: an instruction +length misread by one, a SIB byte dropped after a ModRM r/m of 100b, reds the +walk over the shipped kernel. **Oracle**: SDM Vol. 2's opcode maps, Appendix A. diff --git a/issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md b/issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md new file mode 100644 index 00000000000..6ea76933695 --- /dev/null +++ b/issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md @@ -0,0 +1,26 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# blockd drives NVMe APST, and a host memory buffer confined to its domain + +After blockd drives the T14's drive, the blockd step of +`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`. As +Linux at `Ubuntu-6.8.0-142.142`, APST stays within +`default_ps_max_latency_us` and honours `NVME_QUIRK_NO_APST` and +`NVME_QUIRK_NO_DEEPEST_PS` (`drivers/nvme/host/core.c:63,2495-2598`). A drive +whose HMPRE is non-zero gets a host memory buffer sized as Linux at v6.8 sizes +it: HMPRE capped at `max_host_mem_size_mb`, 128 MiB, and none when HMMIN is +past that cap (`drivers/nvme/host/pci.c:55,2019-2037`). The buffer is mapped in +blockd's IOMMU domain and in no other, since the controller writes it at will. + +**Exit**: host tests of the APST table and of the buffer's size over HMPRE and +HMMIN; on the T14, the one proving machine with a physical NVMe drive, the +block figures, the idle minute with the drive idle, and, where its `id-ctrl` +reads HMPRE non-zero, the IOMMU's tables read back holding the buffer in +blockd's domain alone; where it reads zero, the host tests alone prove the +buffer. **Mutation**, each red: a table that admits a state past the bound; a +buffer past the cap; the buffer mapped in a second domain. **Oracle**: Linux's +`nvme_configure_apst` and `nvme_setup_host_mem` over the T14's `id-ctrl`. diff --git a/issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md b/issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md deleted file mode 100644 index 35c401c0109..00000000000 --- a/issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -status: open -kind: track -opened: 2026-09-29 ---- - -# blockd drives NVMe APST and the host memory buffer - -After blockd drives the T14's drive, the blockd step of -`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`. As -Linux at `Ubuntu-6.8.0-142.142`, APST stays within -`default_ps_max_latency_us` and honours `NVME_QUIRK_NO_APST` and -`NVME_QUIRK_NO_DEEPEST_PS` (`drivers/nvme/host/core.c:63,2495-2598`). - -**Exit**: on the T14, the one proving machine with a physical NVMe drive, the -block figures, and the idle minute with the drive idle. **Mutation**: a host -test's table that admits a state past the bound. **Oracle**: Linux's -`nvme_configure_apst` over the T14's `id-ctrl`. diff --git a/issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md b/issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md index 9892273a19a..9e57c354f45 100644 --- a/issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md +++ b/issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md @@ -12,8 +12,12 @@ at sshd's RustCrypto versions; pipe round trips, and throughput at 64 B to 64 KiB; munmaps per second of a page a sibling on another CPU touched; lateness past a 1 ms timer; NVMe reads, read-only; an idle minute's package energy; and the T14's PCI, USB, NVMe and cpuidle identity. It runs on the T14 under its -Ubuntu before the wipe and under the shipped ToyOS kernel. +Ubuntu before the wipe and under the shipped ToyOS kernel. A munmap pair's two +sides each read their x2APIC ID from CPUID.0BH:EDX before and after the timed +window, and a pure function over the four readings refuses the figure when the +two sides' IDs match or either side's changed across the window. -**Exit**: the outputs committed as fixtures. **Mutation**: a munmap pair on -one CPU, as each side reads its x2APIC ID from CPUID.0BH:EDX, is refused. -**Oracle**: Linux. +**Exit**: the outputs committed as fixtures, and that function host-tested. +**Mutation**, each red: a pair on one CPU passes; only the readings before the +window compared, so a sibling that moved onto the initiator's CPU inside it +passes. **Oracle**: Linux. diff --git a/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md b/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md index 8c6054f2c9f..ab588e8a8dc 100644 --- a/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md +++ b/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md @@ -8,11 +8,20 @@ opened: 2026-09-29 A shootdown blocks on every other CPU (`kernel/src/mm/unmapped.rs:5`), whether or not it ever ran the address space. It waits on -`issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md`. +`issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md`. A CPU that +switches away keeps the space's entries: under PCID every CR3 load sets +NOFLUSH (`kernel/src/arch/x86_64/paging.rs:295-306`), so a CPU leaves the +target set only when those entries are gone, not when it stops running the +space. The TCG model has no PCID (`src/arch.rs:169`), so only a machine with +PCID can show a switched-out CPU still holding them. **Exit**: on every proving machine and under TCG, a sibling pinned on another -CPU touches a page the initiator unmaps and then faults; a case in -`kernel-loom/tests/tlb_shootdown.rs` switches a CPU into the space while the -initiator reads the target set; the T14's munmap figure. **Mutation**: a -target set that omits a CPU the space ran on; a CPU that joins the set after -loading CR3. **Oracle**: loom. +CPU touches a page the initiator unmaps and then faults; on each proving +machine with PCID, the sibling touches the page, blocks off its pinned CPU +while a thread of another space runs there, and faults on touching it again +after it wakes there; cases in `kernel-loom/tests/tlb_shootdown.rs` switch a +CPU into the space, and out of it, while the initiator reads the target set; +the T14's munmap figure. **Mutation**, each red: a target set that omits a CPU +the space ran on; a CPU that joins the set after loading CR3; a CPU cleared +from the set when it switches away from the space. **Oracle**: loom, and each +proving machine's TLB. diff --git a/issues/kernel/indirect-branches-and-returns-run-without-thunks.md b/issues/kernel/indirect-branches-and-returns-run-without-thunks.md index 46934f31ada..45b3f614171 100644 --- a/issues/kernel/indirect-branches-and-returns-run-without-thunks.md +++ b/issues/kernel/indirect-branches-and-returns-run-without-thunks.md @@ -14,8 +14,9 @@ thunk its decision selects: ITS's on the T14; on AMD, retbleed's untrained return (`arch/x86/kernel/cpu/bugs.c:1125`) or SRSO's safe RET, in its alias form on family 0x19 (`bugs.c:2726-2732`). -**Exit**: a gate finds no raw indirect branch or `ret` in `kernel.elf` outside -the thunks and entry, an `int3` after each, and every placement Linux's linker +**Exit**: a gate over `kernel.elf`, on the decoder of +`issues/build/no-gate-decodes-kernel-elfs-instructions.md`, finds no raw +indirect branch or `ret` outside the thunks and entry, an `int3` after each, and every placement Linux's linker script asserts (`arch/x86/kernel/vmlinux.lds.S:510-539`): `retbleed_return_thunk` and `srso_safe_ret` at a line start, the SRSO alias pair's addresses differing in exactly bits 2, 8, 14 and 20, and each ITS diff --git a/issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md b/issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md deleted file mode 100644 index 2652336dda4..00000000000 --- a/issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -status: open -kind: track -opened: 2026-09-29 ---- - -# Kernel copies are one `rep movsb` on every CPU - -The kernel's `memcpy`, `memmove` and `memset` are `compiler_builtins`', which -frame `rep movsq` or `rep stosq` with two byte strings, and take one `rep movsb` -or `rep stosb` only when built with the `ermsb` target feature -(`rust/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs:15-17,23-58,88-126`). -The kernel builds them with it, one path on every CPU: `rep movsb` is correct -without ERMS, CPUID.(7,0):EBX bit 9, and no CPU is refused. Zen 2 lacks ERMS -(a Ryzen 9 PRO 3900, family 0x17, reads EBX 0x219C91A9: InstLatx64 ddff8a92, -`AuthenticAMD/AuthenticAMD0870F10_K17_Matisse_CPUID.txt:52`), and no proving -machine is family 0x17, so the cost there is unmeasured. - -**Exit**: a gate finds each forward copy and fill in `kernel.elf` one `rep -movsb` or `rep stosb`, with no `rep movsq` or `rep stosq`; the T14's pipe -figures. **Mutation**: the build without `ermsb` reds the gate. **Oracle**: -Linux's pipe figures. diff --git a/issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md b/issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md new file mode 100644 index 00000000000..0fc1863ff7b --- /dev/null +++ b/issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md @@ -0,0 +1,31 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# Kernel forward copies and fills are one `rep movsb` or `rep stosb` on every CPU + +The kernel's `memcpy`, `memset` and `memmove` are `compiler_builtins`', which +frame `rep movsq` or `rep stosq` with two byte strings, and take one `rep movsb` +or `rep stosb` only when built with the `ermsb` target feature +(`rust/library/compiler-builtins/compiler-builtins/src/mem/x86_64.rs:15-17,23-58,88-126`); +`memmove`'s backward branch, `copy_backward` (`:62-85`), keeps `rep movsq` +either way. The kernel links the sysroot's `compiler_builtins`, which no kernel +build flag recompiles: the feature is `rustflags = ["-Ctarget-feature=+ermsb"]` +under `[target.x86_64-unknown-none]` in the std build's `bootstrap.toml` +(`std_config`, `src/sysroot.rs:522`; bootstrap's `core/config/toml/target.rs:41`), +and it moves the sysroot key (`RECIPE`, `src/sysroot.rs:65`). One path on every +CPU: `rep movsb` is correct without ERMS, CPUID.(7,0):EBX bit 9, and no CPU is +refused. Zen 2 lacks ERMS (a Ryzen 9 PRO 3900, family 0x17, reads EBX +0x219C91A9: InstLatx64 ddff8a92, +`AuthenticAMD/AuthenticAMD0870F10_K17_Matisse_CPUID.txt:52`), and no proving +machine is family 0x17. + +**Exit**: a gate over `kernel.elf`, on the decoder of +`issues/build/no-gate-decodes-kernel-elfs-instructions.md`, finds `memcpy`, +`memset` and `memmove`'s forward branch each one `rep movsb` or `rep stosb`, +with no `rep movsq` or `rep stosq`; the T14's pipe figures; and Zen 2's cost +recorded, as a family-0x17 figure against the build without `ermsb` or as a +`tooling` issue that owes it. **Mutation**: the build without `ermsb` reds the +gate. **Oracle**: Linux's pipe figures. diff --git a/issues/kernel/kernel-functions-return-with-their-used-registers-intact.md b/issues/kernel/kernel-functions-return-with-their-used-registers-intact.md index 26761964990..ad26a54bff8 100644 --- a/issues/kernel/kernel-functions-return-with-their-used-registers-intact.md +++ b/issues/kernel/kernel-functions-return-with-their-used-registers-intact.md @@ -18,6 +18,7 @@ on the function attribute `zero-call-used-regs` **Exit**: the kernel, `core` and `alloc` build under a rustc option that sets `zero-call-used-regs=used-gpr` on every function, carried in the fork to -upstream quality; a gate over `kernel.elf` finds each function's used +upstream quality; a gate over `kernel.elf`, on the decoder of +`issues/build/no-gate-decodes-kernel-elfs-instructions.md`, finds each function's used call-clobbered general registers zeroed before its return thunk, and a build without the option reds it. diff --git a/issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md b/issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md index 2c0273be2e3..8e716f8e4b5 100644 --- a/issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md +++ b/issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md @@ -16,7 +16,9 @@ address spaces one of which asked for it (`arch/x86/mm/tlb.c:384`). In ToyOS the ask is the flag of `issues/kernel/no-program-runs-with-speculative-store-bypass-disabled.md`. -**Exit**: a gate matches `kernel.elf` against both of Linux's sequences; on +**Exit**: a gate over `kernel.elf`, on the decoder of +`issues/build/no-gate-decodes-kernel-elfs-instructions.md`, matches it against +both of Linux's sequences; on every proving machine probes count what `issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md` selects for it: a clear per syscall where it selects the loop, a fill per diff --git a/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md b/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md index 3e0f771beb7..3466feb4c51 100644 --- a/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md +++ b/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md @@ -6,15 +6,24 @@ opened: 2026-09-29 # The direct map uses 1 GiB leaves where the CPU has them -The direct map has no 1 GiB leaf: `toyos-bootmap` maps 2 MiB and 4 KiB -(`toyos-bootmap/src/x86_64.rs:33-54`). On a CPU that enumerates `pdpe1gb`, -CPUID.80000001H:EDX bit 26, a GiB that holds one memory type takes one 1 GiB -leaf; any other GiB, and every GiB on a CPU without it, keeps 2 MiB leaves. -The TCG model gains `+pdpe1gb`, which TCG implements (`target/i386/cpu.c:945` -at QEMU v11.1.1), so the PR gate maps 1 GiB leaves. +The kernel's direct map has no 1 GiB leaf: `paging::init` maps it 2 MiB at a +time (`kernel/src/arch/x86_64/paging.rs:953-956`). On a CPU that enumerates +`pdpe1gb`, CPUID.80000001H:EDX bit 26, a GiB that holds one memory type takes +one 1 GiB leaf; any other GiB, and every GiB on a CPU without it, keeps 2 MiB +leaves. Which leaf a GiB takes is a pure function that `paging::init` calls, +living beside `direct_map_end` in `toyos-bootmap/src/x86_64.rs` and host-tested +there. Every walker of the direct map reads a PDPT entry as a table pointer — +`policy_at` (`paging.rs:718`), `guard_4k` (`:749`), `ensure_table` (`:820`) +under `map_2m` — so each splits a 1 GiB leaf into 2 MiB leaves of its type +before it descends; unsplit, `guard_kernel_page` writes a page table into the +GiB's first page. The TCG model gains `+pdpe1gb`, which TCG implements +(`target/i386/cpu.c:945` at QEMU v11.1.1), so the PR gate maps 1 GiB leaves. -**Exit**: a `toyos-bootmap` host test gives a GiB holding one UC range 2 MiB +**Exit**: the decision's host test gives a GiB holding one UC range 2 MiB leaves, a uniform GiB one leaf, and every GiB 2 MiB leaves without `pdpe1gb`; -each proving machine's boot reports its leaf counts; the T14's 64 KiB pipe -figure. **Mutation**: a 1 GiB leaf for every GiB. **Oracle**: SDM Vol. 3A +under TCG with `+pdpe1gb`, a `boot-actuators` arm guards a 4 KiB page and maps +an MMIO range inside a 1 GiB leaf, and finds the GiB's other pages mapped with +their type; each proving machine's boot reports its leaf counts; the T14's 64 +KiB pipe figure. **Mutation**, each red: a 1 GiB leaf for every GiB; `guard_4k` +without the split, reading the PS=1 PDPT entry as a PD. **Oracle**: SDM Vol. 3A §14.11.9. diff --git a/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md b/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md index 9370d510cda..6d7aa2f67a0 100644 --- a/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md +++ b/issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md @@ -10,8 +10,7 @@ Parity with Linux at `Ubuntu-6.8.0-142.142`, pinned by the first issue below, is the floor on every CPU ToyOS supports, and the kernel also takes every security feature such a CPU offers. The proving machines are the T14 and the nightly's AMD EPYC KVM guests; the PR gate's TCG model proves wiring only. A -probe is a `boot-actuators` arm or a `test-actuators` `SYS_DEBUG` action, -never a syscall. +probe is a `boot-actuators` arm or a `test-actuators` `SYS_DEBUG` action. **Exit**: every issue below is closed, in the order listed. @@ -19,6 +18,7 @@ never a syscall. - `issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md` - `issues/kernel/spec-ctrl-and-gds-stay-as-firmware-left-them.md` - `issues/kernel/no-program-runs-with-speculative-store-bypass-disabled.md` +- `issues/build/no-gate-decodes-kernel-elfs-instructions.md` - `issues/kernel/no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb.md` - `issues/kernel/user-pointer-checks-have-no-spectre-v1-fence-and-smap-is-optional.md` - `issues/kernel/indirect-branches-and-returns-run-without-thunks.md` diff --git a/issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md b/issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md index 1b3be91b828..e9b6dd64060 100644 --- a/issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md +++ b/issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md @@ -12,7 +12,8 @@ an indirect call or jump in the kernel may land anywhere in its text. Linux at (`debian.master/config/annotations:834`); the kernel takes it where the CPU enumerates IBT. -**Exit**: a gate finds `endbr64` at every IDT and `IA32_LSTAR` target and no -`notrack` in `kernel.elf`; on the T14, the one proving machine known to +**Exit**: a gate over `kernel.elf`, on the decoder of +`issues/build/no-gate-decodes-kernel-elfs-instructions.md`, finds `endbr64` at +every IDT and `IA32_LSTAR` target and no `notrack`; on the T14, the one proving machine known to enumerate IBT, a call to a function without one is `#CP`. **Mutation**: `syscall_entry`'s `endbr64` gone; `ENDBR_EN` clear. **Oracle**: the T14's CPU. diff --git a/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md b/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md index 58fdc70a0cb..cc153c4441f 100644 --- a/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md +++ b/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md @@ -23,9 +23,10 @@ if it beats ToyOS without it. What no proving machine is known to offer is - `issues/kernel/no-test-can-hold-a-thread-on-a-named-cpu.md` - `issues/hardware/no-program-measures-toyos-against-linux-on-one-machine.md` - `issues/kernel/user-programs-use-avx-under-xsave.md` -- `issues/kernel/kernel-copies-are-one-rep-movsb-on-every-cpu.md` +- `issues/build/no-gate-decodes-kernel-elfs-instructions.md` +- `issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md` - `issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md` - `issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md` - `issues/kernel/fsgsbase-is-measured-then-taken-or-rejected.md` - `issues/kernel/idle-cpus-enter-the-c-states-cst-names.md` -- `issues/hardware/blockd-drives-nvme-apst-and-the-host-memory-buffer.md` +- `issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md` From 5ce48d3ad5a2f1413b423370991ecdc1acf76fd1 Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 13:55:46 +0200 Subject: [PATCH 6/6] PR #603 round 5: walkers that cannot split read a 1 GiB leaf, the decoder covers every executable byte, and HMB waits on a machine - 1 GiB leaves: the GiB `direct_map_end` cuts keeps 2 MiB leaves (Linux's `split_mem_range` as oracle); `policy_at` and `debug_page_walk`, which cannot split, read a PS=1 PDPT entry as a leaf, each with an arm and a mutation. - Decoder: refuses any executable byte no walked function covers, apart from named regions decoded in their own mode (the AP trampoline); `global_asm!("1: jmp rax")` is a mutation that must red; functions come from `toyos_symbols::locate`; the false "one gate" sentence is deleted. - NVMe: the host memory buffer is a row of the features file until a proving machine reads HMPRE non-zero; the slug drops it. - TLB exit: the unmap happens while the sibling is blocked, and the switch-out mutation's red is recorded over repeated runs. - ermsb: the RECIPE bump reaches CI only once the release tag's `trees()` hashes `src/sysroot.rs`, pointing at the issue that owes it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01U6SVYFkdvV2t38KzNrESxs --- ...o-gate-decodes-kernel-elfs-instructions.md | 23 ++++++---- ...st-memory-buffer-confined-to-its-domain.md | 26 ------------ issues/hardware/blockd-drives-nvme-apst.md | 18 ++++++++ ...es-no-proving-machine-is-known-to-offer.md | 1 + ...eaches-only-the-cpus-that-ran-the-space.md | 18 ++++---- ...are-one-rep-movsb-or-stosb-on-every-cpu.md | 6 ++- ...ses-1-gib-leaves-where-the-cpu-has-them.md | 42 ++++++++++++------- ...s-what-modern-hardware-offers-for-speed.md | 2 +- 8 files changed, 75 insertions(+), 61 deletions(-) delete mode 100644 issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md create mode 100644 issues/hardware/blockd-drives-nvme-apst.md diff --git a/issues/build/no-gate-decodes-kernel-elfs-instructions.md b/issues/build/no-gate-decodes-kernel-elfs-instructions.md index 96080bb2ca6..80f3d6547e2 100644 --- a/issues/build/no-gate-decodes-kernel-elfs-instructions.md +++ b/issues/build/no-gate-decodes-kernel-elfs-instructions.md @@ -14,15 +14,20 @@ Five stages each owe a gate over `kernel.elf`'s instructions: - `issues/kernel/the-kernel-runs-without-indirect-branch-tracking.md` - `issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md` -The one gate that reads `kernel.elf` today matches bytes at a symbol -(`judge_entry_window`, `src/build.rs:1641`), which cannot tell an opcode from a -displacement or an immediate. The five share one x86-64 decoder, in Rust in the -tree and run by the host gate, with no external disassembler: it lands before -any of them, and each adds its own check over it rather than a decoder of its -own. +The five share one x86-64 decoder, in Rust in the tree and run by the host +gate, with no external disassembler: it lands before any of them, and each adds +its own check over it rather than a decoder of its own. It takes its functions +from `toyos_symbols::locate` over `toyos_elf` (`src/build.rs:1575-1598`), not +from a second ELF reader. `global_asm!` emits no `.type` or `.size`, so code +such as the AP trampoline (`kernel/src/arch/x86_64/smp.rs:396`), in `.text` +with a `jmp far [mem]` and a `retf`, is covered by no sized function. **Exit**: the decoder walks every function `kernel.elf`'s `.symtab` names, from its address to its size, and a walk that decodes a byte it does not know or -ends anywhere but the function's end is refused. **Mutation**: an instruction -length misread by one, a SIB byte dropped after a ModRM r/m of 100b, reds the -walk over the shipped kernel. **Oracle**: SDM Vol. 2's opcode maps, Appendix A. +ends anywhere but the function's end is refused; so is any byte of an +executable section that no walked function covers, apart from a region named by +symbol and decoded in its own mode, as the trampoline's 16-, 32- and 64-bit +code is. **Mutation**, each red over the shipped kernel: an instruction length +misread by one, a SIB byte dropped after a ModRM r/m of 100b; +`global_asm!("1: jmp rax")` in `.text`. **Oracle**: SDM Vol. 2's opcode maps, +Appendix A. diff --git a/issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md b/issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md deleted file mode 100644 index 6ea76933695..00000000000 --- a/issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -status: open -kind: track -opened: 2026-09-29 ---- - -# blockd drives NVMe APST, and a host memory buffer confined to its domain - -After blockd drives the T14's drive, the blockd step of -`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`. As -Linux at `Ubuntu-6.8.0-142.142`, APST stays within -`default_ps_max_latency_us` and honours `NVME_QUIRK_NO_APST` and -`NVME_QUIRK_NO_DEEPEST_PS` (`drivers/nvme/host/core.c:63,2495-2598`). A drive -whose HMPRE is non-zero gets a host memory buffer sized as Linux at v6.8 sizes -it: HMPRE capped at `max_host_mem_size_mb`, 128 MiB, and none when HMMIN is -past that cap (`drivers/nvme/host/pci.c:55,2019-2037`). The buffer is mapped in -blockd's IOMMU domain and in no other, since the controller writes it at will. - -**Exit**: host tests of the APST table and of the buffer's size over HMPRE and -HMMIN; on the T14, the one proving machine with a physical NVMe drive, the -block figures, the idle minute with the drive idle, and, where its `id-ctrl` -reads HMPRE non-zero, the IOMMU's tables read back holding the buffer in -blockd's domain alone; where it reads zero, the host tests alone prove the -buffer. **Mutation**, each red: a table that admits a state past the bound; a -buffer past the cap; the buffer mapped in a second domain. **Oracle**: Linux's -`nvme_configure_apst` and `nvme_setup_host_mem` over the T14's `id-ctrl`. diff --git a/issues/hardware/blockd-drives-nvme-apst.md b/issues/hardware/blockd-drives-nvme-apst.md new file mode 100644 index 00000000000..ab3ef5d75dd --- /dev/null +++ b/issues/hardware/blockd-drives-nvme-apst.md @@ -0,0 +1,18 @@ +--- +status: open +kind: track +opened: 2026-09-29 +--- + +# blockd drives NVMe APST + +After blockd drives the T14's drive, the blockd step of +`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`. As +Linux at `Ubuntu-6.8.0-142.142`, APST stays within +`default_ps_max_latency_us` and honours `NVME_QUIRK_NO_APST` and +`NVME_QUIRK_NO_DEEPEST_PS` (`drivers/nvme/host/core.c:63,2495-2598`). + +**Exit**: host tests of the APST table; on the T14, the one proving machine +with a physical NVMe drive, the block figures and the idle minute with the +drive idle. **Mutation**: a table that admits a state past the bound. +**Oracle**: Linux's `nvme_configure_apst` over the T14's `id-ctrl`. diff --git a/issues/hardware/features-no-proving-machine-is-known-to-offer.md b/issues/hardware/features-no-proving-machine-is-known-to-offer.md index 1c40541e44b..c771b54bc67 100644 --- a/issues/hardware/features-no-proving-machine-is-known-to-offer.md +++ b/issues/hardware/features-no-proving-machine-is-known-to-offer.md @@ -44,3 +44,4 @@ cores were not verified against Arm's. The Arm rows belong to | GCS | Armv9.4 (`arch/arm64/Kconfig:2236-2254`) | | POE | Armv8.9 (`arch/arm64/Kconfig:2198-2213`) | | SME | Arm (`arch/arm64/Kconfig:2311-2319`) | +| NVMe host memory buffer | an NVMe drive whose `id-ctrl` reads HMPRE non-zero; the T14's has not been read, and blockd builds the buffer only once a proving machine's does | diff --git a/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md b/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md index ab588e8a8dc..8c19c4414d9 100644 --- a/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md +++ b/issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md @@ -17,11 +17,13 @@ PCID can show a switched-out CPU still holding them. **Exit**: on every proving machine and under TCG, a sibling pinned on another CPU touches a page the initiator unmaps and then faults; on each proving -machine with PCID, the sibling touches the page, blocks off its pinned CPU -while a thread of another space runs there, and faults on touching it again -after it wakes there; cases in `kernel-loom/tests/tlb_shootdown.rs` switch a -CPU into the space, and out of it, while the initiator reads the target set; -the T14's munmap figure. **Mutation**, each red: a target set that omits a CPU -the space ran on; a CPU that joins the set after loading CR3; a CPU cleared -from the set when it switches away from the space. **Oracle**: loom, and each -proving machine's TLB. +machine with PCID, the sibling touches the page and blocks off its pinned CPU, +the initiator unmaps it while the sibling is blocked and a thread of another +space runs there, and the sibling faults on touching it again after it wakes +there; cases in `kernel-loom/tests/tlb_shootdown.rs` switch a CPU into the +space, and out of it, while the initiator reads the target set; the T14's +munmap figure. **Mutation**, each red: a target set that omits a CPU the space +ran on; a CPU that joins the set after loading CR3; a CPU cleared from the set +when it switches away from the space, its red recorded over repeated runs, +since it rests on the TLB keeping the entry across the block. **Oracle**: loom, +and each proving machine's TLB. diff --git a/issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md b/issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md index 0fc1863ff7b..ae7e1d78368 100644 --- a/issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md +++ b/issues/kernel/kernel-forward-copies-and-fills-are-one-rep-movsb-or-stosb-on-every-cpu.md @@ -15,7 +15,11 @@ either way. The kernel links the sysroot's `compiler_builtins`, which no kernel build flag recompiles: the feature is `rustflags = ["-Ctarget-feature=+ermsb"]` under `[target.x86_64-unknown-none]` in the std build's `bootstrap.toml` (`std_config`, `src/sysroot.rs:522`; bootstrap's `core/config/toml/target.rs:41`), -and it moves the sysroot key (`RECIPE`, `src/sysroot.rs:65`). One path on every +and it moves the sysroot key (`RECIPE`, `src/sysroot.rs:65`), which reaches +CI's installed toolchain only once the release tag's `trees()` +(`src/release.rs:25-31`) hashes `src/sysroot.rs`, the work of +`issues/build/the-release-tag-hashes-none-of-the-build-system-that-builds-the-toolchain.md`, +which lands first. One path on every CPU: `rep movsb` is correct without ERMS, CPUID.(7,0):EBX bit 9, and no CPU is refused. Zen 2 lacks ERMS (a Ryzen 9 PRO 3900, family 0x17, reads EBX 0x219C91A9: InstLatx64 ddff8a92, diff --git a/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md b/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md index 3466feb4c51..57924b70cdf 100644 --- a/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md +++ b/issues/kernel/the-direct-map-uses-1-gib-leaves-where-the-cpu-has-them.md @@ -8,22 +8,32 @@ opened: 2026-09-29 The kernel's direct map has no 1 GiB leaf: `paging::init` maps it 2 MiB at a time (`kernel/src/arch/x86_64/paging.rs:953-956`). On a CPU that enumerates -`pdpe1gb`, CPUID.80000001H:EDX bit 26, a GiB that holds one memory type takes -one 1 GiB leaf; any other GiB, and every GiB on a CPU without it, keeps 2 MiB -leaves. Which leaf a GiB takes is a pure function that `paging::init` calls, -living beside `direct_map_end` in `toyos-bootmap/src/x86_64.rs` and host-tested -there. Every walker of the direct map reads a PDPT entry as a table pointer — -`policy_at` (`paging.rs:718`), `guard_4k` (`:749`), `ensure_table` (`:820`) -under `map_2m` — so each splits a 1 GiB leaf into 2 MiB leaves of its type -before it descends; unsplit, `guard_kernel_page` writes a page table into the -GiB's first page. The TCG model gains `+pdpe1gb`, which TCG implements +`pdpe1gb`, CPUID.80000001H:EDX bit 26, a GiB the direct map covers whole and +that holds one memory type takes one 1 GiB leaf; the GiB that `direct_map_end` +cuts (it rounds only to 2 MiB, `toyos-bootmap/src/x86_64.rs:22`), any other +GiB, and every GiB on a CPU without it keep 2 MiB leaves. Which leaf a GiB +takes is a pure function that `paging::init` calls, living beside +`direct_map_end` in `toyos-bootmap/src/x86_64.rs` and host-tested there. The +walkers that write, `guard_4k` (`paging.rs:749`) and `ensure_table` (`:820`) +under `map_2m`, split a 1 GiB leaf into 2 MiB leaves of its type before they +descend; unsplit, `guard_kernel_page` writes a page table into the GiB's first +page. The walkers that cannot split, `policy_at` (`:718`, `&self`) and the +lock-free `debug_page_walk` (`:1098`, called by the `#PF` handler, +`idt/exceptions.rs:206,332`), read a PS=1 PDPT entry as a 1 GiB leaf and stop +there. The TCG model gains `+pdpe1gb`, which TCG implements (`target/i386/cpu.c:945` at QEMU v11.1.1), so the PR gate maps 1 GiB leaves. **Exit**: the decision's host test gives a GiB holding one UC range 2 MiB -leaves, a uniform GiB one leaf, and every GiB 2 MiB leaves without `pdpe1gb`; -under TCG with `+pdpe1gb`, a `boot-actuators` arm guards a 4 KiB page and maps -an MMIO range inside a 1 GiB leaf, and finds the GiB's other pages mapped with -their type; each proving machine's boot reports its leaf counts; the T14's 64 -KiB pipe figure. **Mutation**, each red: a 1 GiB leaf for every GiB; `guard_4k` -without the split, reading the PS=1 PDPT entry as a PD. **Oracle**: SDM Vol. 3A -§14.11.9. +leaves, the GiB a non-GiB-aligned `end` cuts 2 MiB leaves, a uniform GiB one +leaf, and every GiB 2 MiB leaves without `pdpe1gb`; under TCG with `+pdpe1gb`, +a `boot-actuators` arm reads `direct_map_policy` of a page in an unsplit 1 GiB +leaf and gets its type, finds `debug_page_walk` of that page reporting the +1 GiB leaf without descending, then guards a 4 KiB page and maps an MMIO range +inside a 1 GiB leaf, and finds the GiB's other pages mapped with their type; +each proving machine's boot reports its leaf counts; the T14's 64 KiB pipe +figure. **Mutation**, each red: a 1 GiB leaf for every GiB; a 1 GiB leaf for +the last GiB when `end` is not GiB-aligned; `guard_4k` without the split, +reading the PS=1 PDPT entry as a PD; `policy_at` without the PDPT PS check; +`debug_page_walk` without it. **Oracle**: SDM Vol. 3A §14.11.9; Linux's +`split_mem_range` (`arch/x86/mm/init.c`), which gives 1 GiB pages only to a +range's GiB-aligned interior. diff --git a/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md b/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md index cc153c4441f..f6b97784fe0 100644 --- a/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md +++ b/issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md @@ -29,4 +29,4 @@ if it beats ToyOS without it. What no proving machine is known to offer is - `issues/kernel/a-tlb-shootdown-reaches-only-the-cpus-that-ran-the-space.md` - `issues/kernel/fsgsbase-is-measured-then-taken-or-rejected.md` - `issues/kernel/idle-cpus-enter-the-c-states-cst-names.md` -- `issues/hardware/blockd-drives-nvme-apst-and-a-host-memory-buffer-confined-to-its-domain.md` +- `issues/hardware/blockd-drives-nvme-apst.md`