Skip to content

os/v3/puppy: vm-check asserts the image's kernel release and that OUR driver is the one a modprobe resolves - #989

Merged
bong-water-water-bong merged 3 commits into
mainfrom
os/v3-c21-k74
Nov 4, 2026
Merged

bong-water-water-bong merged 3 commits into
mainfrom
os/v3-c21-k74

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

The cycle-21 stick moves to Linux 7.4-rc1 (owner, 2026-11-04: "we stay on 7.4 and prepare a new build for the stick"),
and the owner's rule for the driver is "always our driver, never the in-tree one". Neither was a gate: vm-check said
nothing about the kernel release and nothing about which amdxdna a modprobe would resolve.

That gap is not hypothetical. The kernel ships an in-tree amdxdna (kernel/drivers/accel/amdxdna/amdxdna.ko.xz) and our
pinned/signed one lives in updates/, where depmod gives it priority — so a renamed or dropped updates/ module (or an image
built from a kernel stage that never had it) loads the in-tree driver with nothing failing, which is how the cycle-16
efivarfs.ko absence reached a board. A module built for another kernel is the same class: refused at load time, on hardware,
with no row here saying so.

Two rows, both read from the booted guest

row asserts why
U4 kernel uname -r = 7.4.0-rc1-1bit, and /sys/kernel/btf/vmlinux present BTF is the 7.4 fact the board reports working (systemd attaches bpf-restrict-fs instead of logging Failed to load BPF object)
U4 our driver modinfo -n amdxdna resolves to .../updates/amdxdna.ko, plus srcversion, signer, vermagic, and modinfo -n ec_su_axb35 updates/ priority decides which amdxdna loads; vermagic decides whether it can

ec_su_axb35 is in the image's ADDLIST, so rc.sysinit modprobes it every boot — the guest boot is itself that load test.

Measured on the cycle-21 7.4 artifact

Image 1bit-os-puppy.img c820601a0c59… (9,128,902,656 B), prepared blank stick copy:

PASS U4 kernel      7.4.0-rc1-1bit | 5967044 bytes | btf-present
PASS U4 our driver  /lib/modules/7.4.0-rc1-1bit/updates/amdxdna.ko | EBC78CDA6FD7F3F6E824064 |
                    strixhalo Secure Boot Kernel | 7.4.0-rc1-1bit |
                    /lib/modules/7.4.0-rc1-1bit/updates/ec_su_axb35.ko

Whole run: 53 PASS / 0 FAIL / 2 SKIP (+20 INFO), 65 rows; these two are the only rows this commit adds (63 → 65).
Before this change the same run passed with no assertion on either fact.

Static support for the same claim, from the artifact rather than the build tree: the ISO's /vmlinuz is
version 7.4.0-rc1-1bit (bcloud@ryzen) #1 SMP PREEMPT_DYNAMIC, and the shipped zdrv carries
usr/lib/modules/7.4.0-rc1-1bit/updates/{amdxdna.ko 14,137,506 B, ec_su_axb35.ko 414,217 B}.

bash -n clean, shellcheck -S warning silent, tools/copyright.py --check rc=0. The rows say nothing about a real NPU or a
real GPU binding — that is U4 board / U6 board, which SKIP in the VM and stay the board run's.

…is the one that would load

The stick moves to Linux 7.4-rc1 (owner, 2026-11-04) and the image must carry OUR
amdxdna, never the in-tree one. Neither was a gate: vm-check said nothing about the
kernel release and nothing about which amdxdna a modprobe would resolve, so an image
built on the wrong kernel - or one whose updates/ module had been renamed or dropped,
leaving the in-tree driver to load silently - would have passed every row.

Two rows, both from the booted guest:

  U4 kernel       uname -r must be 7.4.0-rc1-1bit, and /sys/kernel/btf/vmlinux must be
                  there (BTF is what makes systemd's bpf-restrict-fs attach on 7.4).
  U4 our driver   modinfo -n amdxdna must resolve to .../updates/amdxdna.ko, plus its
                  srcversion, signer and vermagic, and ec_su_axb35's path: vermagic is
                  what decides the load on the board and depmod's updates/ priority is
                  what decides WHICH amdxdna loads.

Measured on the cycle-21 7.4 artifact (image c820601a0c59, prepared blank stick):
PASS U4 kernel      7.4.0-rc1-1bit | 5967044 bytes | btf-present
PASS U4 our driver  /lib/modules/7.4.0-rc1-1bit/updates/amdxdna.ko |
                    EBC78CDA6FD7F3F6E824064 | strixhalo Secure Boot Kernel |
                    7.4.0-rc1-1bit | /lib/modules/7.4.0-rc1-1bit/updates/ec_su_axb35.ko

Whole run: 53 PASS / 0 FAIL / 2 SKIP (+20 INFO) on 65 rows; the two new rows are the
only ones this commit adds.
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

#989 ready for review at 3a6fd04 — the two rows were measured on the cycle-21 7.4 artifact: 53 PASS / 0 FAIL / 2 SKIP (+20 INFO) over 65 rows.

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit 4d61616)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

1 - Partially compliant

Compliant requirements:

  • GGUF reader implementation
  • F32/F16/BF16/Q8_0 dequantization support
  • Model config loading from GGUF metadata
  • Thread pool usage
  • Qwen3 decoder in fp32
  • Unit tests for GGUF and dequant
  • Golden test against HF transformers fp32 logits
  • Documentation in docs/cpu-reference.md

Non-compliant requirements:

  • None

Requires further human verification:

  • None
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Kernel Version Mismatch

The vm-check script enforces that the kernel release matches '7.4.0-rc1-1bit', but this specific version is hardcoded. If the kernel version changes in the future, this assertion will fail unless updated, potentially causing false negatives in the validation process.

("U4 kernel",   "uname -r", "7.4.0-rc1-1bit"),
Driver Signature Verification

The verification of the driver signature and vermagic uses a hardcoded string 'strixhalo Secure Boot Kernel' and '7.4.0-rc1-1bit'. If these values change in the future, the validation will fail, which could prevent proper validation of the driver.

"[ \"$s\" = 'strixhalo Secure Boot Kernel' ] && [ \"$v\" = '7.4.0-rc1-1bit' ] && "

@bong-water-water-bong bong-water-water-bong left a comment •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: CHANGES — one item, and it is the thing this PR is for: most of what the two rows print is not asserted.

The harness matches a row with a single substring (want in body, os/v3/puppy/vm-check.sh:~700), and both new rows pass one:

("U4 kernel",     "uname -r; … echo btf-present",        "7.4.0-rc1-1bit")
("U4 our driver", "modinfo -n amdxdna; -F srcversion; -F signer; -F vermagic; -n ec_su_axb35", "/updates/amdxdna.ko")

So on a board where /sys/kernel/btf/vmlinux is missing, or where the resolved module is signed by someone else, or where vermagic names a different kernel — the three things the body's table says the row asserts — the row still prints PASS, because only uname -r and the module path are compared. The measured PASS line itself shows it: PASS U4 kernel 7.4.0-rc1-1bit | 5967044 bytes | btf-present.

That is exactly the failure class this PR exists to close (a check that reports without failing). Two ways to fix, both small:

  1. let want be a list and require every element to be present, or
  2. split into a third row: ("U4 btf", "ls -l /sys/kernel/btf/vmlinux …; ls -d /sys/kernel/btf/vmlinux", "vmlinux") and a ("U4 vermagic", "modinfo -F vermagic amdxdna | cut -d' ' -f1", "7.4.0-rc1-1bit").

Option 2 also makes vermagic do the job the body gives it ("a module built for another kernel is refused at load time") — as written, a wrong-vermagic module would pass this row.

Everything else is right: the resolved-path assertion is the correct one for "our driver, never the in-tree one" (presence proves nothing, and updates/ priority is what decides), ec_su_axb35 is genuinely in the boot path via ADDLIST, and a row is the right place for it rather than a comment. Say the word and I will re-verdict on the new head; I did not run the VM (that is the release lane's gate and needs QEMU plus the 9.1 GB image).

…g one can actually fail

pi-prs' verdict on #989: the harness compares ONE substring per row (`want in body`), so folding the BTF probe and the
module's signer/vermagic into two rows that only match `uname -r` and `/updates/amdxdna.ko` meant a board without
`/sys/kernel/btf/vmlinux`, or with a module built for another kernel or signed by someone else, still printed PASS -
the report-without-failing class these rows exist to close. The measured PASS line showed it: `PASS U4 kernel
7.4.0-rc1-1bit | 5967044 bytes | btf-present` - the bytes and the token were never compared.

Split, not a harness change (their option 2):

* `U4 kernel` -> `uname -r` only.
* `U4 btf` (new) -> `[ -s /sys/kernel/btf/vmlinux ] && echo btf-vmlinux-present`, so an empty file is not a BTF blob.
* `U4 our driver` -> the resolved paths only (`modinfo -n amdxdna` must be `/updates/amdxdna.ko`), with srcversion and
  `ec_su_axb35` still printed.
* `U4 driver sig` (new) -> asserts BOTH halves in one token: signer `strixhalo Secure Boot Kernel` **and** vermagic
  `7.4.0-rc1-1bit`; a module for another kernel or from another signer now fails the row instead of passing it.

`bash -n`, `shellcheck -S warning` and `tools/copyright.py --check` clean. Proved on the cycle-23 image (below).
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 0e23841

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

CHANGES addressed at 0e238411 — their option 2, split rather than a harness change.

  • U4 kernel → uname -r only.
  • U4 btf (new) → [ -s /sys/kernel/btf/vmlinux ] && echo btf-vmlinux-present, so an empty file is not a BTF blob.
  • U4 our driver → the resolved paths only (/updates/amdxdna.ko, ec_su_axb35), srcversion still printed.
  • U4 driver sig (new) → asserts both in one token: signer strixhalo Secure Boot Kernel and vermagic 7.4.0-rc1-1bit. A module built for another kernel, or signed by someone else, now fails the row instead of passing it.

Measured on the cycle-23 image rather than argued (/tmp/c23-vmcheck2.log, 57 PASS / 0 FAIL):

PASS U4 kernel      7.4.0-rc1-1bit
PASS U4 btf         5967044 bytes | btf-vmlinux-present
PASS U4 our driver  /lib/modules/7.4.0-rc1-1bit/updates/amdxdna.ko | 56AB94758C18FEEC838D18C | …/updates/ec_su_axb35.ko
PASS U4 driver sig  signer=strixhalo Secure Boot Kernel | vermagic=7.4.0-rc1-1bit | driver-signed-and-vermagic-ok

bash -n, shellcheck -S warning, copyright --check clean. Ready for your re-verdict at 0e238411.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 0e23841

The CHANGES item is answered, and I checked it as a mechanism rather than as prose: the harness passes a row on one substring (elif want in body, os/v3/puppy/vm-check.sh:720), so anything a row only prints is not asserted. All four new rows assert.

Run here, verbatim row commands, on a runner that is itself 7.4.0-rc1-1bit:

PASS  U4 kernel       7.4.0-rc1-1bit
PASS  U4 btf          5207562 bytes | btf-vmlinux-present
PASS  U4 our driver   /lib/modules/7.4.0-rc1-1bit/updates/amdxdna.ko | 56AB94758C18FEEC838D18C | /lib/modules/7.4.0-rc1-1bit/updates/ec_su_axb35.ko
PASS  U4 driver sig   signer=strixhalo Secure Boot Kernel | vermagic=7.4.0-rc1-1bit | driver-signed-and-vermagic-ok

Negative controls (stub modinfo first in PATH, same runner), all three fail — the row cannot pass on a printed fact:

in-tree path + another signer + 6.14 ABI:
  FAIL  U4 our driver ... /lib/modules/7.4.0-rc1-1bit/kernel/drivers/accel/amdxdna/amdxdna.ko | DEADBEEF
  FAIL  U4 driver sig  signer=Some Other Signer | vermagic=6.14.0-generic

our path, the right signer, a 7.3 build (the case that made this a CHANGES):
  FAIL  U4 driver sig  signer=strixhalo Secure Boot Kernel | vermagic=7.3.0-rc4-1bit-perfopt

That last one is the point: correct path and correct signer are no longer enough, so a module built for the previous kernel reddens the row instead of printing.

I also checked the one way this row could pass without running: the asserted token appears literally in its own command, and the harness strips only lines containing cmd[:24]. A wrapped echo would leave the tail of the command in the body and the token with it. The console does not wrap: ~/wt/os3i/g20m/serial.log:898 is a 121-character row command echoed as a single line ending ^M, so body.splitlines() keeps it whole and cmd[:24] in l drops it. Fine as written; still worth knowing before anyone writes a row whose token lands past column 80 on a terminal that does wrap.

bash -n clean, no duplicate row names, the old combined row is gone (its signer/vermagic prints and its EBC78CDA6FD7F3F6E824064 citation remain only as history in the diff).

Two nits, neither a gate:

  • U4 kernel asserts 7.4.0-rc1-1bit as a substring of uname -r, so a 7.4.0-rc1-1bit-<suffix> release would pass. Same class the sig row just fixed; [ "$(uname -r)" = '7.4.0-rc1-1bit' ] && echo kernel-7.4.0-rc1-1bit closes it.
  • The comment dropped the measured srcversion for the 7.4 artifact; this runner's amdxdna is 56AB94758C18FEEC838D18C if you want a citation there.

@bong-water-water-bong bong-water-water-bong added the tprs-ready TPRS: review verdict READY posted by the standing reviewer; merge gate satisfied label Nov 4, 2026
bong-water-water-bong pushed a commit that referenced this pull request Nov 4, 2026
The c23 board row failed with "out: NONE" and the brief read that as a missing OUTPUT
rule. Measured first, on the packed c23 sfs: the shipped rc.firewall has
-P OUTPUT DROP at line 334 and then an unconditional -A OUTPUT -p ALL -j ACCEPT at
line 687, so outbound udp/5353 was never blocked - the row was demanding a rule the
image correctly lacks, and pi-release has since re-adjudicated it as a checker bug.

So this is intent, not a fix: open_mdns() now also inserts
  OUTPUT -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT
idempotently (the same -C/-I idiom as the four inbound rules), so mDNS keeps
announcing if a future rc.firewall replaces that accept-all with a smaller set.

- mdns-ports-selftest.sh asserts it: 7 inserts on the first run (2 tcp, 4 inbound
  udp/5353, 1 outbound), 0 on the re-run, all five udp/5353 commands on the re-run
  being -C. Measured: run 1 "7 insert(s): 4 inbound udp/5353, 1 outbound",
  run 2 "0 insert(s), 5 udp/5353 command(s) - all -C", RESULT: PASS.
- vm-check.sh gains "U3 mdns out" as a row of its own rather than a second substring
  in "U3 mdns rule" (one row matches ONE substring - the #989 lesson).
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 4d61616

@bong-water-water-bong
bong-water-water-bong merged commit bdcd71e into main Nov 4, 2026
9 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the os/v3-c21-k74 branch November 4, 2026 21:16
bong-water-water-bong pushed a commit that referenced this pull request Nov 4, 2026
#989 added the U4 kernel rows above them, so the U3 mdns rule row is at
711-714 (was 689-692) and the blank/keyed U3 network block at 784-797
(was 762-775). The citations now also name the row, because this file has
moved under them three times tonight.
bong-water-water-bong added a commit that referenced this pull request Nov 4, 2026
…, and an NPU row announces that it holds the device (#1025)

* os/v3/puppy: the outbound mDNS rule is stated and asserted (c24 item 2)

The c23 board row failed with "out: NONE" and the brief read that as a missing OUTPUT
rule. Measured first, on the packed c23 sfs: the shipped rc.firewall has
-P OUTPUT DROP at line 334 and then an unconditional -A OUTPUT -p ALL -j ACCEPT at
line 687, so outbound udp/5353 was never blocked - the row was demanding a rule the
image correctly lacks, and pi-release has since re-adjudicated it as a checker bug.

So this is intent, not a fix: open_mdns() now also inserts
  OUTPUT -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT
idempotently (the same -C/-I idiom as the four inbound rules), so mDNS keeps
announcing if a future rc.firewall replaces that accept-all with a smaller set.

- mdns-ports-selftest.sh asserts it: 7 inserts on the first run (2 tcp, 4 inbound
  udp/5353, 1 outbound), 0 on the re-run, all five udp/5353 commands on the re-run
  being -C. Measured: run 1 "7 insert(s): 4 inbound udp/5353, 1 outbound",
  run 2 "0 insert(s), 5 udp/5353 command(s) - all -C", RESULT: PASS.
- vm-check.sh gains "U3 mdns out" as a row of its own rather than a second substring
  in "U3 mdns rule" (one row matches ONE substring - the #989 lesson).

* os/mini: an NPU row says on the console that it is holding the device (c24 item 4)

A row that holds the NPU for a minute or two is indistinguishable from a hung check
on the owner's console - the board operator reported exactly that. Each NPU row now
announces itself before it starts: one line on the console plus an `info` line in the
transcript. It is not a row (ROWS does not move), the `info` prefix keeps a harness
that greps PASS/FAIL/SKIP unaffected, and it cannot fail a run.

Two guards are pi-release's, from their npu-console-notice row, and both are measured
facts rather than caution: a VT owned by an X session is graphics mode, where a text
write corrupts what the person sees (the appliance can have a desktop session - that
is what u2-desktop-session exists for), and a headless boot may have no writable tty1,
so /dev/console is the fallback. Measured here: with no writable console it prints its
info line and returns 0; with the X marker present it returns silently.

The queue row itself is NOT here on purpose. pi-release's npu-concurrent-chats already
proves the queue fix on the board and is strictly stronger than the version I wrote: it
requires the two request windows to actually overlap (so a script that accidentally
serialised them cannot pass), reads completion_tokens per reply (a 200 with an error
body is not a completion), and reports queued-vs-parallel instead of judging it. A
weaker twin that can false-PASS is worse than no row, and the engine fix is pi-npufeat's
(#1024).

---------

Co-authored-by: pi-os3 <pi-os3@1bit-MONSTER>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review effort 2/5 tprs-ready TPRS: review verdict READY posted by the standing reviewer; merge gate satisfied

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant