Skip to content

ACPI stage 1: the machine in ACPI mode for a userland server's claim; its SCI, power button and EC events served - #713

Merged
Japabu merged 29 commits into
mainfrom
wt/toyos-acpi1
Oct 7, 2026
Merged

Japabu merged 29 commits into
mainfrom
wt/toyos-acpi1

Conversation

@Japabu

@Japabu Japabu commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

ACPI stage 1: the machine in ACPI mode for a userland server's claim; its SCI, power button and EC events served

Stage 1 of issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md: the kernel puts the machine in ACPI mode for a userland server's acpi claim and back when it goes; /system/bin/acpiserver serves the SCI, the fixed power button and the embedded controller's events. Design: PR 2 of the counters + ACPI design, with every roast item touching it.

Round 14 (review round 9 at 922a6b7c7): the T14's reading of this kernel, and the record

The head is 9dcfa09bc: 922a6b7c7, a merge of origin/main (df1a77221, #743) and one commit. No kernel, userland or harness source changed, so the guest and T14 readings at 922a6b7c7 stand for it. git diff --stat 922a6b7c7 9dcfa09bc:

 README.md                                          |  2 -
 issues/munmap-ignores-the-size-it-is-passed.md     | 38 ++++++++++++++
 ...-power-off-after-the-kernels-own-acpi-enable.md |  6 ++-
 ...n-acpi-disable-the-firmware-has-not-answered.md | 33 ++++++++++++
 ...on-event-came-up-to-17-s-after-ec-query-0x28.md |  8 +--
 issues/usersafe-layouts-are-checked-by-hand.md     | 59 ++++++++++++++++++++++
 tests/metal/lenovo-20w0003amz.toml                 |  6 +++
 7 files changed, 145 insertions(+), 7 deletions(-)

README.md and the two issues munmap-… and usersafe-… are the merge's and equal origin/main's (git diff --stat df1a77221 9dcfa09bc over the three is empty). The branch's own commit is the tests/metal record and three files under issues/.

cargo run -- --ci host at 9dcfa09bc: EXIT=0 (orch/acpi1-r17/host.exit), "Host: 76 step(s), all green" (host.log:8403); host.head is 9dcfa09bcdef761969993ae31ea60b0fe6b03276, and the tree was clean after it (host.status-after is empty). Load average 36.30 at its start (host.load).

BLOCKER 1: the T14 at 922a6b7c7

The orchestrator ran the five boots (comment 6039409933); nobody was at the machine. His run log is orch/t14-713r16.log: each image's sha256 is the one orch/acpi1-r16/images.sha256 staged and was checked before its flash, each boot's rc is 0, and the script's rc is 0. The judges ran from the clean tree at 922a6b7c7. Everything below is read from the readbacks' kernel.logs under orch/acpi1-r16/.

boot image sha256, as flashed boot rc verdict.txt
metal-acpi_server/acpicase 2d8c1f2f0be2cf14130ede611293369d78d301b1c0fe91597ac36d14d1eeff8e 0 passed
metal-acpi_server/testcases-hold ae15eb50c4a1cb89b40ee8bd4fc65448a04e94dcece5f17a6fdb9d4dcb2b86a0 0 passed
metal-counters/shared c46cc487f11f2d8d2b0311923e630a4b0668697f67dca8c16f645f0953bf4195 0 passed
metal-counters/shared-debug 2ef538f3f1442c48e69606bacb469dc95a5eeee1291cb1056bcdaeb9cad9c6d6 0 passed
metal-counters/testcases abb72e225960dab08d7c0b6d00e63aa63ab61ee6a4750c32bdf1e5d3bb48939c 0 passed

The two judge commands:

  • cargo test --test toyos-build -- --metal --metal-readback orch/acpi1-r16/metal-acpi_server acpi_server_: EXIT=0, [metal] 2 passed, 0 failed, 2 boot(s), with PASS acpi_server_events and PASS acpi_server_death (metal-acpi_server/judge-acpi_server_.log).
  • cargo test --test toyos-build -- --metal --metal-readback orch/acpi1-r16/metal-counters counters: EXIT=0, [metal] 3 passed, 0 failed, 3 boot(s), with PASS counters (metal-counters/judge-counters.log).

acpi_server_death, on acpicase (metal-acpi_server/acpicase/kernel.log, 385 lines). In this order:

  • :346 [… 14.613 cpu7 kernel] acpi: ACPI mode: ACPI_ENABLE 0xf0 written to SMI_CMD 0xb2, SCI_EN set 16752ns after; cpu7's SMI count 4807 before the write and 4808 after
  • :351 [… 14.616 test-runner pid=8] acpi_release: the server said: acpiserver: armed: power button served, embedded controller on GPE 0x6e at 0x66/0x62
  • :364 exit: acpiserver pid=9 code=137
  • :365 [… 14.616 cpu0 kernel] acpi: legacy mode again: ACPI_DISABLE 0xf1 written to SMI_CMD, PM1a_CNT reads 0x0000 17068ns after, SCI_EN clear

The duration is 17068 ns: the line is this head's, which no earlier kernel wrote with a time in it. legacy mode again occurs once in the log and acpi: ACPI mode: once; still in ACPI mode and ACPI_DISABLE not written occur nowhere in it. The job list's stop is :385, the supervisor's power: the machine stops, and logkeeper makes the log whole first (Reboot) at 14.625 s. The enable was written from cpu7 and the disable from cpu0, as issues/the-kernel-writes-smi-cmd-from-whichever-cpu-its-caller-runs-on.md records of the earlier heads.

acpi_server_events, on testcases-hold (metal-acpi_server/testcases-hold/kernel.log, 387 lines):

  • :348 [… 13.452 cpu0 kernel] acpi: ACPI mode: ACPI_ENABLE 0xf0 written to SMI_CMD 0xb2, SCI_EN set 15657ns after; cpu0's SMI count 4818 before the write and 4819 after
  • :354 [… 13.454 acpiserver] acpiserver: armed: power button served, embedded controller on GPE 0x6e at 0x66/0x62
  • :367 [… 15.195 acpiserver] acpiserver: embedded controller query 0x4f taken for the first time, served by nothing: stage 1 runs no AML, the one first-sighting line, once
  • :368 [… 43.454 acpiserver] acpiserver: 26 SCIs; embedded controller queries taken: 0x4f x13, the counts line
  • :369 acpi_hold: held to 54000 ms, and nothing stopped the machine, and :387 the supervisor's stop line at 66.203 s

legacy mode again, still in ACPI mode and ACPI_DISABLE not written occur nowhere in the log.

counters, on shared, shared-debug and testcases (metal-counters/<boot>/kernel.log). The mint's line on each, its CPU's SMI count rising by one across the write:

  • shared:347 [… 12.690 cpu0 kernel] acpi: ACPI mode: ACPI_ENABLE 0xf0 written to SMI_CMD 0xb2, SCI_EN set 12764ns after; cpu0's SMI count 4818 before the write and 4819 after
  • shared-debug:347 [… 12.696 cpu0 kernel] … SCI_EN set 14303ns after; cpu0's SMI count 4819 before the write and 4820 after
  • testcases:347 [… 12.833 cpu0 kernel] … SCI_EN set 13349ns after; cpu0's SMI count 4818 before the write and 4819 after

legacy mode again, still in ACPI mode and ACPI_DISABLE not written occur in none of the three logs. The row's own job, counters_metal, runs on testcases; shared and shared-debug carry the two shared members (counters_read, counters_silent), each exit 0. On testcases:

  • SMI flat on each of the 8 CPUs. kernel.cpu.<n>.smi = 4819 for n = 0 to 7 at idle0 (15.266218180 s), at idle1 (16.266280242 s) and at spin (27.448835558 s): 24 readings, all 4819, which is the writer's count after the enable. The judge: 8 cpus, SMI flat on each over 12182 ms.
  • No line stamped in the idle second. The log's line :367 is stamped 15.264 s (counters_metal settle: the log holds this second line) and :368 27.244 s; nothing lies between, so nothing in 15.266 s to 16.266 s. The first query, 0x4f, came at 14.968 s (:365), before idle0.

BLOCKER 2: the SCI_EN measurement has its command, transcript and exit

Run again this round and posted whole as comment 6039735451: the script with the QEMU invocation, the monitor transcript and the exit. sh orch/acpi1-r17/sci-en/measure.sh EXIT=0, QEMU's own exit after the monitor's quit. Bare QEMU 11.1.1, -machine q35 -accel tcg -nodefaults under OVMF, no guest image. i/h 0x604 read 0x0000 on the first poll, before OVMF had enabled ACPI, then 0x0001; 0x0000 after o/b 0xb2 3; 0x0001 after o/b 0xb2 2. The same three readings the gap issue records. No change to the tree.

NOTEs

  • The gap issue's owner is now the stage "power-off through the server" of issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md, which rewrites the power-off the exit's test reds on. The orchestrator's placement, not the owner's, and the issue says so.
  • The press issue's exit names where the ten logs are read: each boot ends in S5 and leaves no readback, so each is read off the stick's log partition, copied before the next flash, as at ee6aadecb. "and none will" is deleted.
  • Past HANDBACK the row is released with a disable outstanding: recorded as issues/the-acpi-row-is-released-with-an-acpi-disable-the-firmware-has-not-answered.md, a file of its own because the CPU issue's slug is another claim. Owner: the ACPI track, whose stage 1 landed the release. Known: the bound is the kernel's own number, the T14 answered in 17068 ns, no tier reaches the expiry, no failure is recorded. Exit: no claimant is handed the row while a disable this kernel wrote is unanswered, and a test reds where one is. No kernel change this round.
  • tests/metal/lenovo-20w0003amz.toml carries the six numbers from the run at 922a6b7c7 (boot.acpicase.* 1207 ms, 2495 us, 12966 us; boot.testcases-hold.* 1212 ms, 2477 us, 13240 us), applied from the judge's own diff, orch/acpi1-r16/metal-acpi_server/judge-acpi_server_.record-rows.patch.
  • The body: Unsure's "a path this round did not trace" is replaced by what kernel/src/object/mod.rs says of it, and the lines that called the T14 rows staged and unread say what ran.

Round 13 (review round 8 at 47ac0ce19): the attended rows go, and the release reads SCI_EN until it is clear

This round's head was 922a6b7c7: 04bcf041d, which carries the round's code, and one commit on it that changes issues and one three-line comment in acpi_mode.rs (below). Host, build and guest gates are green at 922a6b7c7 (Gates). The T14 has since run the three rows the round changes at 922a6b7c7, all green: the release's poll and its rewritten line are read on the hardware they are for (round 14, above, and T14 rows).

On the owner's rulings, both of 2026-10-05: "A test that requires manual steps from me is forbidden." and "No automated test is allowed that requires physical buttons to be pressed or anything we cant do now with the t14. I can test it on demand but no ci there not always someone available physically".

  • Deleted, in one commit (BLOCKER 1, REMOVE):
    • the metal rows acpi_power_off and acpi_power_button_pressed, with the testcases-off and testcases-press arms;
    • their judges acpi_off_on_metal, acpi_press_on_metal and powered_off_in_acpi_mode;
    • Readback::presses, READBACK_PRESSES and its READBACK_FILES entry;
    • the harness's acceptance of a boot that ends in S5: boot_verdict's asked_to_power_off arm and its test a_power_off_leaves_no_record_and_is_no_hang, judge_readbacks' panel exemption, and a_power_off_owes_no_panel with its registration;
    • the comments that named the rows (tests/toyos.rs, acpi_hold.rs) and bootlog.rs's paragraph on what a power-off leaves the next loader pass.
    • bootlog::asked_to_power_off and its test stay: QEMU's acpi_power_button reads them.
  • What read what the two rows read, at this head.
    • A press reaches the server, which has the supervisor stop the machine: QEMU's acpi_power_button, and sci.rs's host tests of the decode.
    • The machine went into ACPI mode for the server and stayed there: on the T14, counters (reds on acpi: legacy mode again) and acpi_server_events (the row and the server's armed: line).
    • SLP_EN takes after the kernel's own ACPI_ENABLE: unguarded on the T14 until issues/no-t14-row-reads-the-power-off-after-the-kernels-own-acpi-enable.md's exit is met. On q35 the power-off is read (machine_shutdown, machine_shutdown_short_stop, acpi_power_button), but never after the kernel's enable, since OVMF hands over in ACPI mode.
    • The T14's own button latches PWRBTN_STS and reaches the server: unguarded until issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md's exit is met, which is an on-demand check by the owner and no row.
  • Whether QEMU can reach the power-off after the kernel's enable: it can be staged, and no test does it. Measured on bare QEMU 11.1.1, -machine q35 -nodefaults with OVMF under TCG, through the monitor: i/h 0x604 read 0x0001 as OVMF left it, 0x0000 after o/b 0xb2 3 (ACPI_DISABLE), and 0x0001 again after o/b 0xb2 2. The whole QEMU invocation, the monitor transcript and the exit, from a re-run in round 14, are comment 6039735451. So the harness can put a guest in legacy mode from outside, with nothing shipped for it. A test needs the write to land before the claim is minted, which means a config whose claim a prompted job mints (tests/acpicase mints it from a job, but runs its job list unprompted) and a job that holds the claim into the power-off. It is not built in stage 1. The orchestrator's ruling, not the owner's: that QEMU test is the gap issue's exit. The issue records the measurement and says the exit is his placement. It would read QEMU's ICH9 model and not the T14's firmware, which no row reads on this path. This is the reviewer's either/or answered with neither arm: a test is possible and is not here.
  • Issues (BLOCKERs 1 and 2, NOTEs).
    • The S5 issue is renamed issues/no-t14-row-reads-the-power-off-after-the-kernels-own-acpi-enable.md and rewritten as the gap, with its last readings (ff4945d6d, 8d7004d3b), what QEMU reads of it, the same owner (moved to the track's power-off stage in round 14), and an exit no person is needed for: the QEMU test above. Its one citation moved.
    • The press issue records both rulings verbatim and that they supersede "the press test is fixed to fail when the first press is lost". Its exit is an on-demand check by the owner that the orchestrator asks for, recorded in the issue: ten boots, one press each. Ten is not the owner's. It names the two windows in which a press is lost by construction: before the mint, when the firmware has the machine, and between the kernel's enable and the server's clear (14.361 s to 14.363 s on the 8d7004d3b press boot). The false "while the firmware still had the machine in legacy mode" goes.
    • The track: stage 1's exit names what reads it (QEMU's acpi_power_button; the T14's counters, acpi_server_events, acpi_server_death), says the two things no T14 row reads and whose they are, and says that moving the power-off's T14 reader out of the exit is the orchestrator's placement. Both rulings are recorded beside "The attended press waits for the owner", which they supersede. A stage "the interpreter" is named as the press issue's owner; its exit is this round's proposal, labelled as the orchestrator's placement, and is his to confirm or change.
    • issues/a-stop-shows-nothing-on-the-panel.md loses its paragraph on a boot held open for an attended press.
    • Both rulings on tests are dated 2026-10-05 in the three issues that quote them.
    • Filed, found while reading the specification for the poll's bound and not fixed here: issues/the-kernel-writes-smi-cmd-from-whichever-cpu-its-caller-runs-on.md. ACPI 6.5 Table 5.9 has OSPM issue SMI_CMD commands "synchronously from the boot processor". The kernel writes the enable on the CPU the claimant mints on and the disable on the CPU the last handle goes on. On the T14's acpi_server_death boots at ff4945d6d and 8d7004d3b the enable was written from cpu7 and the disable from cpu0, and both took; every other recorded boot wrote the enable from cpu0. No failure is recorded. This has been so since the mint was written, not since this round.
  • The release reads SCI_EN until it is clear (the outside review's finding 1; production code, acpi_mode.rs and toyos-acpi/src/fadt.rs, +81/−39).
    • Before: release released the row, then wrote ACPI_DISABLE and logged one read of PM1a_CNT, SCI_EN clear or still set.
    • Now: leave writes the disable and reads PM1a_CNT until SCI_EN is clear, spun and bounded at 100 ms (HANDBACK). It spins because the task a claim's last handle goes with may be dying, and a dying task cannot park. Past the bound it logs acpi: still in ACPI mode: … by name and ENABLED stays set, so the next release writes the disable again and the next mint does not say the firmware handed the machine over in ACPI mode.
    • The specification gives the poll no bound. ACPI 6.5 §4.8.2.5: "OSPM does an OUT to the SMI_CMD port with the data in the ACPI_DISABLE field of the FADT. OSPM polls the SCI_EN bit until it is sampled as RESET." No time is named there. Table 5.9's ACPI_ENABLE row says only that "OSPM will synchronously wait for the ntransfer [sic] of SMI ownership to complete, so the ACPI system releases SMI ownership as quickly as possible", and no FADT field carries a time. So the 100 ms is this kernel's own number, not a measurement and not the document's, and HANDBACK's comment says that in place of "an estimate". On the T14 at 8d7004d3b the one read after the write was already clear.
    • The row is released after the disable, not before (found on the way, not in either review). With the row free first, a claimant could mint between the release and the disable, find SCI_EN still set, write nothing, and then lose ACPI mode to the disable that followed. The poll would have widened that window.
    • ACPI_DISABLE == 0. FixedHardware now carries legacy: Option<LegacyMode>, whose two commands are NonZeroU8, in place of smi_cmd, acpi_enable and acpi_disable. A FADT that leaves any of the three zero names no way in that the kernel takes, so such a machine stays in legacy mode, refused by name. Before, a machine with ACPI_ENABLE and no ACPI_DISABLE would have had 0 written to SMI_CMD on release. Host-tested in toyos-acpi/tests/corpus.rs (each of the three zeroed gives None).
    • acpi_death_on_metal loses its ends_with("SCI_EN clear") branch: the kernel now writes legacy mode again only of a read with the bit clear. The line keeps its head and its tail, with the time the bit took before the tail, so the judge reads the 8d7004d3b readback and a new one alike.
    • What no test reads. The 100 ms expiry, the still in ACPI mode line and the mint after it need a firmware that ignores ACPI_DISABLE; nothing here has one. The reordering closes a race no test schedules. Both are checked by reading.
  • The outside review (orch/chatgpt/pr713.md), claim by claim.
    • 1, the release does not wait for SCI_EN: held, and fixed as above. Its "ACPI 6.5 specifies … poll SCI_EN until it is RESET" and "the FADT defines zero as reserved on systems without Legacy Mode" both hold against the document, read from the Internet Archive's copy of uefi.org/specs/ACPI/6.5/ (chapter 4 captured 2025-01-02, sha256 of its HTML 1ff59e14…d0f6; chapter 5 captured 2024-12-28, 6a238690…6339), since uefi.org itself answers curl with a 403 challenge page. The first is §4.8.2.5, quoted above. The second is Table 5.9: ACPI_ENABLE and ACPI_DISABLE are each "reserved and must be zero on systems that do not support Legacy Mode", and SMI_CMD "must be zero on system that does not support System Management mode". Table 5.9's ACPI_DISABLE row also describes a different handback, in which the OS masks the SCI's interrupts and clears SCI_EN itself before the write; §4.8.2.5 and Table 4.13 ("It is the responsibility of the hardware to set or reset this bit. OSPM always preserves this bit position") contradict it, and the kernel follows those two. The new issue records the contradiction. Its "leave() can complete while the machine is observably still in ACPI mode" was true only as a logged still set; on the T14 the one read was clear (acpi1-r13/metal-acpi_server/acpicase/kernel.log:364).
    • 2, the two manual rows: held; it is review round 8's BLOCKERs. Its "automated by bench hardware" did not hold against the owner's second ruling: there is no bench device, and nothing waits on one.
    • 3, a press is lost between the takeover and the arming: held (userland/acpiserver/src/main.rs, "one before it is lost"), and recorded in the press issue with the window's measured width. Its proposal, a takeover and event initialisation that are atomic to the user, is not acted on and not ruled.
    • 4, no unattended test of the enable-then-S5 path: held, and recorded in the gap issue. Its "I wouldn't invent a test-only firmware path" is answered by the measurement above: none is needed, since the monitor stages it.

What changed, per decision

  • One declaration of kernel-driven ports, the only maker of the port token (roast BLOCKER 2). arch::pio holds FIXED (COM1, the 8259 pair, POST, CMOS RTC, the PCI configuration mechanism — CONFIG_ADDRESS's first port alone, so 0xCF9 stays free for a reset register; const-asserted disjoint) and declare() for what boot finds (the i8042, the reset register, the PM1a control block, SMI_CMD, the TCO block). cpu::{inb,outb,inw,outw} take pio::Port, which only a declaration mints; every port the kernel touches went through it. isa::claim_row refuses a row any of whose ports a holder declared, naming it. pio::take_back mints the row's blocks for power::off alone (round 8, below). The pure Reserved table is in toyos-userbound and host-tested; the I/O bitmap covers all 0x10000 ports (8 KiB + 1 per CPU's TSS). i8042::drives() goes: a probed controller is declared, and that is the refusal.

  • isa rows are runtime, filled once at boot: row 0 the i8042 (isa:0060,0064:1,12), row 1 the ACPI fixed hardware (DeviceType::Acpi = 10 => "acpi"), each its own vector (0x2C, 0x2D). A level line is masked at the claim, masked by its handler before EOI, and unmasked by the holder's acknowledgement — a 4-byte write of toyos_abi::acpi::ACK to the claim, from the bound process; a row with no level line refuses it InvalidArgument. Arch-neutral: isa.rs sees only pio::Line/pio::level. An SCI on another row's GSI is refused.

  • ACPI mode (kernel/src/arch/x86_64/acpi_mode.rs). The row is the FADT's PM1a event and GPE0 blocks (toyos_acpi::fixed_hardware, lengths from *_LEN, X_ refused only where both forms name an address and differ; hardware-reduced, PM1b, GPE1 refused by name) and the ECDT's two ports (toyos_acpi::ecdt). The mint: SCI_EN already set → nothing written; else refused by name where the FADT leaves SMI_CMD, ACPI_ENABLE or ACPI_DISABLE zero, no usable ECDT, or a control-method power button; else ACPI_ENABLE to SMI_CMD with this CPU's SMI count before and after read through the counters (arch::counters::read, PR 1), then SCI_EN polled every 1 ms, parked in between, bounded at 3 s (roast NOTE). A mint that wrote the enable and then failed writes ACPI_DISABLE. The release writes ACPI_DISABLE where the mint wrote the enable and reads SCI_EN until it is clear (owner, "Back to legacy mode"; round 13, above). No SMI_CMD write is made once the stop has begun (round 9, below).

  • No-ECDT machines (owner, 2026-10-04, "Stopgap, delete later"): the ECDT path is a stopgap deleted when the interpreter reads the EC from the DSDT; a machine without one stays in legacy mode until then. Recorded in the track and at the site.

  • I/O APIC (roast): topology written once; each unit's register pair a Masked lock (moved from watch.rs to sync.rs) a handler may take — carrying A syscall's body runs with interrupts open, and a kernel-mode timer expiry re-arms one quantum #716's self.0.lock_masked(closed), with Lock::lock_masked now private to sync, so only Masked reaches it and lockdep's exemption covers only locks every take of which is masked (A syscall's body runs with interrupts open, and a kernel-mode timer expiry re-arms one quantum #716's deferred visibility change, owed at this merge); route holds nothing across remap_pin or log!; a pin keeps its RTE low word, so mask/unmask is one write. Its "never from an ISR" and "no power-button or lid events" lines and set_masked's read-modify-write go.

  • SCI default (roast fix 1 + NOTE): toyos_acpi::sci_line gives level, active low where no override names the SCI or one conforms (ACPI 6.5 Table 5.9); isa_line keeps the ISA bus's edge/high. The INTI decode moved out of ioapic.rs into the crate.

  • SVR declared whole (roast NOTE): apic::SVR = enable | spurious vector, every other bit (EOI-broadcast suppression) clear, written and asserted on every CPU.

  • power::off (roast NOTE, ACPI 6.5 §16.1.6's order): the row is taken back from any holder (pio::take_back, round 8); on a machine in ACPI mode every PM1 and GPE0 event is disabled and its status cleared first; then SLP_TYP, then SLP_TYP|SLP_EN, over the bits PM1a_CNT reads (SCI_EN no longer cleared). A write the platform does not act on is a panic two seconds after SLP_EN (S5_TAKES, a Tripwire), naming PM1a_CNT before and after, SCI_EN, the PM1 status and enable (acpi_mode::pm1_events) and this CPU's SMI count either side of the write: the panel shows it and the black box carries it through the panic's reset. Before, it halted for ever after the write.

  • A power-off was no hang to toyos-metal, and owed no panel census (rounds 3 and 4): both deleted in round 13, with the rows that needed them.

  • Merge of origin/main at c4ab2b1e1 (The kernel declares each CPU's HWP request, and the counters round reads the power envelope back under TRACE #590, kernel: delete the log-inside-the-pass caveat, and file the 4ff5221ee wedge it came from #708, A launch starts only what the caller's row lists, and swap and update only in a login session #709, IOMMU stage 1: a claimed function speaks only through its own remapping entry, has no untranslated space, and no domain reaches a host bridge's window #710, The network stack cites RFCs and its own code, not documents outside the tree #712, The owner's rulings of 2026-10-04 are recorded in their tracks, and the T14's root-bridge fixture becomes decoded values #714, The sysroot's std, core and alloc are built without debug assertions #715, A syscall's body runs with interrupts open, and a kernel-mode timer expiry re-arms one quantum #716, The primary's fork checkout, and its nested submodules, are moved to the commit its tree pins #718, virt_smp's second job wait goes on from the capture its first wait drained #719, Every image says which build it is: /system/etc/os-release, logged first by the supervisor #722, An idle CPU that finds XHCI taken halts, and the release kicks it #725, and The issue tracker is flat: issues/<slug>.md, and no area is left #723, the flat issues/), every hunk of both sides kept: Masked in sync.rs with A syscall's body runs with interrupts open, and a kernel-mode timer expiry re-arms one quantum #716's line (above) and main's OwedLock beside it; counters_on_metal keeps main's HWP-request and power-envelope checks and this branch's ACPI-mode SMI flatness; system.toml keeps acpiserver and main's compositor comment; the track keeps the ECDT ruling and main's power-off-through-the-server stage; this branch's issues move to flat paths, every citation of a subdirectory path in its files moved with them.

  • /system/bin/acpiserver (exempt: owns the claim). Start: every event disabled and cleared, then PWRBTN and the EC's GPE enabled, the EC drained, ack. Each SCI: sci::events (pure, host-tested) reads status&enable off both blocks; an event this server never enabled panics naming it; 64 empty SCIs in a row panic. Press → toyos::power::stop(Shutdown) through the supervisor. EC GPE (edge): cleared, then the drain queues query numbers (≤ 32, else panic), and they run through aml::query after the drain (roast BLOCKER 4). ec.rs is a sans-IO transaction (queries only in stage 1; reads/writes join with AML); each wait is the host's, bounded 500 ms, panicking with EC_SC. aml.rs holds query(q) alone, which serves nothing in stage 1; every GPE but the EC's is refused as Unserved::Gpe (round 7: the runtime-GPE arm, Trigger, Gpe, Disposition and Served.runtime were dead and went). Logging per the track's ruling: a line the first time a query number is taken, counts every 30 s where they moved. No inspect acpi.* port (the track's ruling puts the counts in the log).

  • SDK/ABI: toyos_abi::acpi::{AcpiInfo, Block, ACK}, toyos_abi::ioport (x86-64 in/out; AArch64 dies naming the port) re-exported as toyos::ioport (toyos::port is the IPC ports'), toyos::AcpiDev. The tests' arch/port.rs goes.

  • Manifests: system.toml and tests/testcases start acpiserver (devices = ["acpi"], receives = ["power"]), so every T14 row on tests/testcases runs in ACPI mode; tests/latencycase does not, so the latency rows keep their baseline. New tests/acpicase for the death row, its test-runner holding device and dup.

  • Issues: filed issues/the-acpi-servers-holder-drives-the-embedded-controller-unfiltered.md (owner's ruling: the weakness written down) and issues/the-acpi-server-talks-to-the-embedded-controller-without-the-global-lock.md (no _GLK anywhere in the T14's DSDT/SSDTs, byte-searched outside the tree). Citations of the deleted GRANTABLE updated in two issues; the port-switch cost issue now says two rows.

  • Extracts only (owner): toyos-acpi/tests/thinkpad_t14.rs lays the T14's FACP/ECDT/APIC out from the fields the decoders read and seals them; held against Linux's lines on the same machine (EC_CMD/EC_SC=0x66, EC_DATA=0x62, GPE=0x6e, INT_SRC_OVR … 9 high level, PM1a_CNT 0x1804, SMI_CMD=0xb2, ACPI_ENABLE=0xf0). Out of tree, the whole captured tables were checked against the extract and decoded (MSDM never opened): FACP: 276 bytes, revision 6, every extract field matches / ECDT: 83 bytes, revision 1, every extract field matches / APIC: 2 overrides, the extract's two; sci_line(9) = Line { gsi: 9, trigger: Level, polarity: High }, EXIT=0.

  • Round 7 (review round 1 at fe36f86f9):

    • toyos_acpi::pm1a_control is the one decoder of the PM1a control block (X_-aware, length from PM1_CNT_LEN); power::init_off declares what it returns, FixedHardware no longer carries a copy, and acpi_mode::init takes power::pm1a_control() without reconciling two decodes. A soft-off now also refuses a control block whose X_ twin disagrees or that runs past the port space.
    • ioapic: a unit's index/data pair is a Window inside its Masked lock, so read/write are reachable only through that unit's guard.
    • quiesce::stopping lost its one caller and went.
    • The supervisor's NotSupported line names the isa: and acpi: lines beside pcidev: and partclaim:.
    • Issues: the track's false first sentence goes; its "Stopgap, delete later" ruling carries only the ECDT stopgap and the no-ECDT machines, and the control-method refusal and "served whatever it has" stand beside it as the stage's design. issues/the-t14s-firmware-interrupts-every-cpu-every-2-2-s-under-toyos.md loses its false "no ACPI enable handshake" bullet and records the counters row at ee6aadecb and what of its exit stays unmet: its second read is at spin, not at the stop's report — so it stays open. The press issue is renamed issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md, states the lag and the lost-first-press readings with the owner's account, and is owned by stage 1. The EC issue records that the command port takes the maker's own commands too, a firmware update among them not ruled out.
    • REMOVE: the T14 handover time in acpi_mode.rs, Linux's SMI reading in the counters doc (and its claim to be the issue's exit), "Fix 2 of the design's roast" in sci.rs.
  • Merge of origin/main at 010a283a9 (A killed program is recorded as file, offset and build-id, and userland names its frames #711, The root and kernel locks take the per-range maxima the five main locks already carry, the first stage of the one-workspace track #724, The loader clears the screen at its start and stamps every line with its milliseconds #721): no conflicts.

  • Merge of origin/main at 2328e4488 (The kernel's diary is readable inside the machine, on the trace right, by a reader that ships #717, The layout is a track, its findings are filed, and step 0 lands: every package says what it is #727, No kernel asm names a register LLVM may give its operands: cpuid via core, cmpxchg16b and run_on_stack on named registers #730): no conflicts, no hand resolution. In the merged tree Acpi = 10 is still the only class 10, acpiserver has the description The layout is a track, its findings are filed, and step 0 lands: every package says what it is #727 requires, and cpu.rs's in/out wrappers name their registers as No kernel asm names a register LLVM may give its operands: cpuid via core, cmpxchg16b and run_on_stack on named registers #730 requires.

  • Round 8 (review round 2 at 5d0278a60):

    • A power-off never panics on a stop that fell short (BLOCKER 1). At 5d0278a60 acpi_mode::quiet panicked whenever the stop's record had a userland thread still running, which quiesce::PARK says a thread in the block layer can do with no kernel bug; on q35 (handed over in ACPI mode, so quiet runs on every image) a userland program could turn SYS_SHUTDOWN into a kernel panic. The hazard is only a holder writing the row's ports after quiet, and a thread writes a port only from Ring 3. Once the stop's stage is open, every return to Ring 3 passes scheduler::leave_user_if_due, which stops every thread but the caller; pio::take_back then issues a TLB shootdown (invalidation::Origin::Stop), which returns only once every other CPU has answered it from Ring 0. After it no thread but the caller, which never returns, can be in Ring 3, so quiet and the S5 panic's PM1 reading take the row back unconditionally. Nothing reads the record any more: quiesce::STOPPED and userland_stopped go. quiesce::stop returns a Stopping witness beside the record, threaded through power::shutdown to both architectures' power::off, so the row can be taken back only after a stop.
    • quiesce::stop arms its progress watch before the stage opens, not after: no lock is dropped between the opening and the first sweep, so no pass can take the caller's CPU between them. That is what makes the new test exact on one CPU.
    • New actuator stop-budget-spent (the stop gets a zero budget: one sweep), new guest test machine_shutdown_short_stop and its binary test_rs_stop_short (below).
    • toyos_acpi refuses a PM1a event or control block that neither field names as FixedRefused::Absent { field }, not as a Length carrying a length that is not wrong (NOTE 3); corpus.rs asserts both.
  • Merge of origin/main at 0613f93f7 (Logs on screen are coloured by severity and source, with a compact stamp #720, toyos-ld is gone, and no linker runs inside ToyOS #726, File grants: one port per file-server role, a connection is the grant it was minted, and each instance has a quarter of each bound #729, The userland lock takes the per-range maxima the five main locks already carry, the second alignment of the one-workspace track #732): no conflicts, no hand resolution.

  • Round 9 (review round 3 at 3e73ab0ae):

    • No SMI_CMD write once the stop has begun (NOTE 1). The take-back covered only Ring 3: a holder whose process was in process::leave (Ring 0) when the stop's budget ran out dropped its claim on another CPU and reached acpi_mode::release → leave, which on the T14 (where the mint wrote the enable) wrote ACPI_DISABLE concurrently with quiet and the SLP_TYP/SLP_EN writes. Every SMI_CMD write — the mint's ACPI_ENABLE and both ACPI_DISABLE paths, the release's and a failed mint's — now holds one lock (acpi_mode::SMI_CMD_WRITE) and is not made once quiesce::begun() (the stop's STAGE, which only opens); power::off takes that lock once (acpi_mode::settle, which needs the TakenBack, so it runs only after a stop) before it reads PM1a_CNT. So a write in flight when the stage opened has finished before the power-off reads SCI_EN, every later one sees the stage open and is skipped with a log line, and the power-off quiets whichever mode it finds. A claim minted during the stop is refused by name. A stage check alone, the review's named fix, leaves a check-then-act window on a short stop: a release that read the stage closed could still be writing during the power-off; the lock closes it.
    • TakenBack::run(row, at) hands out the atth run of a row the boot filled (isa::runs), not a Declared for any Ports (NOTE 2); acpi_mode names the PM1 event and GPE0 runs by their places in its row.
    • No test reds on NOTE 1, and none can be added at any tier. Not a type: what decides is the stop's stage, a runtime state. Not a host test: no host build runs acpi_mode, and the decision is one lock and one flag. Not QEMU: OVMF hands q35 over in ACPI mode, so the mint writes nothing, ENABLED stays clear and no SMI_CMD write is ever made there (acpi_power_button asserts it); measured: M11, the stage check removed (m11-smi-cmd-ungated.patch), stays green on machine_shutdown, machine_shutdown_short_stop and acpi_power_button (below). Not a metal row: the T14 writes the enable, but the race needs a holder's teardown in Ring 0 across the stage's opening, which no row can schedule — every thread but the caller is stopped at its Ring 3 boundary, so none starts an exit after the stage opens, and one already exiting reaches release at a time no test controls. Checked by reading: every outb to SMI_CMD is under smi_cmd_write(); settle follows take_back in off, which follows STAGE.open in the same thread.
  • Merge of origin/main at 9de5d7df9 (The kernel's idle report is gone, and the counters row measures a quiet idle second #728, Routine lines go on stdout, so only a failure is drawn as an error #733, The interrupt census keeps one word per delivery, so it always adds up #734, Review: prose is never a blocker, cosmetic findings are not raised, and a body's measurements stay evidence #735, The host suite's assumption of a non-root user is filed #736; 5c89f8954). tests/toyos.rs conflicted in counters_on_metal, in its doc and its SMI summary line. Both sides are kept: The kernel's idle report is gone, and the counters row measures a quiet idle second #728's refusal of any line, the kernel's or a program's, stamped in a millisecond from idle0's to idle1's, and this branch's ACPI mode with every CPU's SMI count flat from idle0 to spin (which replaced main's legacy-mode rise of two or more). The judge's code merged with no hand edit; only the doc and the eprintln! were resolved by hand.

  • Rounds 10 and 11: acpiserver's lines and the quiet second (464504f7d, replaced by 89c331ac1; tests/toyos-rust-tests/src/bin/counters_metal.rs alone).

    • The hazard, measured. Three lines on a counters boot come at times the machine chooses: acpiserver's first sighting of each EC query number, the kernel's isa: the ACPI fixed hardware took its first interrupt on the server's first read after an SCI (the same millisecond or one before), and acpiserver's counts line 30 s after arming. Across the T14 readbacks of this branch, the first query, 0x4f on every unattended boot, came 0.04 to 2.14 s after the server armed (2.144 s at 464504f7d's counters boot, acpi1-r10/metal-counters/testcases: armed 1.180 s, query 3.325 s). The job starts within 5 ms of the arming, and The kernel's idle report is gone, and the counters row measures a quiet idle second #728's settle put idle0 about 50 ms after the job started, so the second spans part of the window where that first query lands. 464504f7d's counters row was green only because its query came at 3.325 s, after idle1 at 2.232 s.
    • Round 10's retake did not work, and why (orchestrator's T14 run at 464504f7d, acpi1-r10/metal-retake-shown, metal-retake-off). 464504f7d read the log back after the three reads and took them again, once, if every line stamped in the second was acpiserver's or the kernel's first-interrupt line. Both staged arms widened the second to 3 s, so it caught the first query. In both, three lines fell in the second, not two: isa: the ACPI fixed hardware took its first interrupt and query 0x4f taken for the first time at 2.953 s (2.154 s in retake-off), then exit: logkeeper tid=3 code=0 cpu=0ms 2 to 3 ms later. That third line is the kernel's record of a logkeeper thread ending, after the write the two ACPI lines caused. It is neither acpiserver's nor the first-interrupt line, so the retake refused to fire, and retake-shown was red on the same lines as retake-off. The design also left the green to chance, since it rested on no first sighting landing in either of two takes.
    • Round 11: the second starts after those lines, so they cannot reach it. counters_metal opens the log from its first line (logkeeper serves a reader the boot so far), and before The kernel's idle report is gone, and the counters row measures a quiet idle second #728's settle it waits until three lines are there: acpiserver's armed: line, and, where the server serves an embedded controller, the kernel's first-interrupt line and acpiserver's first taken for the first time line. The wait is bounded at 10 s and panics loudly past that. Then comes the settle, which waits out the log write those lines cause, the logkeeper exit line included, and only then idle0. So every line that comes once, at a time the machine chooses, is stamped before the second opens. The one later line the server is certain to log is its counts line, no earlier than 30 s after its armed: line (COUNTS). Only the judge refuses it: it reds on any line stamped in the second and names it (round 12 below deletes the job's copy of that check). An estimate from the recorded timings: the first query within 2.14 s of arming, then the settle, then 1 s, so the second should end about 3 to 4 s after arming, far inside 30 s. At 89c331ac1 the one T14 counters boot was green (T14 rows, below), but that boot's first interrupt and query came at 1.239 s, before the settle's lines (1.325 s, 1.367 s), so main's order would probably have kept them out too. That boot does not show the wait doing anything; the round-12 pair is meant to show it. The judge is unchanged. The retake, its acpi filter and the within argument of settle are gone.
    • Why not the server. The first-sighting line is the press issue's evidence. Its exit times the power-button line against 0x28's first sighting, so that line has to come out when the query is taken. The row waits for the line instead, and the server is untouched (git diff 464504f7d 89c331ac1 --stat: counters_metal.rs only).
    • What can still red it, and correctly. A query number the EC first raises later on an unattended boot is a new event on a machine meant to be quiet. The judge reds it and names it. No unattended boot of this branch took any number but 0x4f; 0x28 came only on press boots. If the EC raises no query within 10 s, the job panics, naming what it waited for.
    • The row's evidence is the T14's. counters_metal runs on no guest (tests/toyos.rs's RUST_SKIP), because its product is the T14's counters. The control is the round-12 P/N pair of T14 arms (below).
  • Merge of origin/main at e559859ed (The loader lock takes the per-range maxima and its profile strips debuginfo, the last alignment of the one-workspace track #738; 1d4fb9358): no conflicts, no hand resolution. The loader lock takes the per-range maxima and its profile strips debuginfo, the last alignment of the one-workspace track #738 touches only bootloader/ and one issue.

  • Round 12 (review round 5 at 89c331ac1; cd5e11869, counters_metal.rs alone, +11/−24):

    • The job's counts-line assertion is gone (BLOCKER 2). COUNTS_MS was a private copy of acpiserver's COUNTS, and the idle1 assertion against it checked what the judge already refuses and names: any line stamped from idle0 to idle1, the counts line included. A copy that drifts from the server would leave the judge as the only check anyway. Deleted with them: acpi_said's returned stamp and the module doc's sentence about the assertion.
    • Log::until checks its deadline on every pass (NOTE). Before, it checked only when the pipe would block, so a log that kept handing back lines without the awaited one ran on to the runner's 60 s job ceiling, which does not name what was awaited. The check now runs before every read. settle and acpi_said both wait through it.
  • Merge of origin/main at f260e0b98 (Every line of the log opens with one head, time first, counted from the CPU counter's zero #737: every line of the log opens with one head, time first, counted from the counter's zero; one formatter, toyos_abi::log::Head, and one parser, toyos_logstream::parse). Merge commit 8d7004d3b. Every hunk of both sides is kept, and every line this branch reads now goes through parse or its wrappers (program_line, record_ms); nothing this branch writes builds a head of its own (the kernel's log! and logkeeper write every head). Four files conflicted:

    • src/bootlog.rs: this branch's asked_to_power_off and POWER_OFF_ASKED sit beside main's LOADER_CLOCK_*, LOGKEEPER_* and one_clock, and main's new doc for record_millis. By hand: asked_to_power_off reads the stop line through program_line and compares the text after STOPPING with (Shutdown) exactly. Before, it matched the raw line's tail.
    • tests/checks.rs: both registrations are kept, metal_power_off_owes_no_panel and main's metal_loader_kernel_and_program_count_from_one_zero.
    • tests/checks/metal.rs: both checks are kept. a_power_off_owes_no_panel's supervisor line is now written in the one head ([2026-09-29 18:22:40 1.214 supervisor]). It now runs through main's plant, which prepends the logkeeper spawn and the supervisor's word of it, and through main's loader, which states no clock. So one_clock passes it, and the check still asserts only the panel.
    • tests/toyos-rust-tests/src/bin/counters_metal.rs: both imports are kept, this branch's toyos::Pipe and main's stamp_ns. By hand: acpi_said used to match the kernel's first-interrupt line as record_ms(line).is_some() && line.ends_with("] isa: …"). It now uses parse(line) with Source::Kernel and the exact text isa: the ACPI fixed hardware took its first interrupt.

    Beyond the conflicts, by hand, so that no second reader is left: the power-off fixtures in src/bootlog.rs and src/metal.rs are in the one head (old-head lines no longer parse, so these tests would red rather than pass wrongly). acpi_events_on_metal (tests/toyos.rs) used to pick the server's lines by the word acpiserver anywhere in a line, which the supervisor's and the kernel's lines about the server also carry. It now picks them by program_line's tag. Everything else merged with no hand edit, counters_on_metal's doc included: main's stamp_ns sentence sits beside this branch's ACPI-mode sentence.

Measured

  • QEMU 11.1.1 + OVMF hands q35 over in ACPI mode: acpi: the ACPI row: PM1a events 0x600+4, GPE0 0x620+16, SCI gsi 9 level/high, … embedded controller none (the ECDT is unusable: Absent); the firmware handed over in ACPI mode. So the guest test exercises the claim, the SCI and the server, and never the enable write, its wait or the disable: those are the T14's.
  • The T14 hands over in legacy mode (the firmware issue's scout: PM1a_CNT=0x0000).

The attended press at b3b9ccd69

Readback orch/acpi1-r2/metal/testcases-press/, log-partition.img included. The log ends at {16.705 acpiserver} acpiserver: the power button was pressed, on SCI 19 of this boot; asking the supervisor to power off and the supervisor's (Shutdown) at the same millisecond; EC query 0x28 was first taken at 6.696 s. The owner: nothing happened at his press; a second press about 5 s later turned the machine off at once. The next loader pass: Boot attempts: the previous boot of this image never reported — an empty black box, which a correct S5 also leaves.

  • Two readings fit, and neither is ruled out. (a) One press raised 0x28 at 6.696 s, PWRBTN_STS came 10 s later, and the power-off after it stalled until the second press. (b) The first press raised 0x28 and no PWRBTN_STS; the second press, at about 16.7 s, was served and the machine went off at once. Reading (b) needs no stall in ToyOS at all. The host recorded no press's time on that boot. At ff4945d6d one deliberate press was served 16 ms after its 0x28 (below), which favours (b); the press's time was recorded only to the minute, so the press issue stays open.
  • What the rest of the record says. The same stop path, run for a reboot in ACPI mode on that image, went from the supervisor's line to Rebooting. in 8 ms; on QEMU the press's whole stop takes 20 ms (orch/acpi1-r3/probe-qemu.log). A power-off differs from the reboot only in arch::power::off. Since round 3 a write of SLP_EN the platform does not act on panics within 2 s with the registers; no T14 power-off since has stalled (7c3a7dc7d, ee6aadecb), and issues/the-t14-stayed-on-after-a-power-off-in-acpi-mode.md is deleted on that exit.
  • The press issue is issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md: 0x28 → press 10.009 s at b3b9ccd69, 0.017 s at 7c3a7dc7d, 17.552 s at ee6aadecb, 0.016 s at ff4945d6d (added this round); 0x28 on those four press boots and on no unattended boot; no T14 table defines _Q28. A first press that leaves only 0x28 leaves the stage-1 exit's "a press stops the machine" unmet on the T14.
  • Something on the panel within a second of a stop: nothing exists. Filed as issues/a-stop-shows-nothing-on-the-panel.md, not built here.

Gates

At 922a6b7c7 (round 13, the head; logs under orch/acpi1-r16/). One script, gates.sh, ran the three in turn from the clean committed tree (gates.head is 922a6b7c72f59a267478b13059d97bf2c0579b6f; gates.status and gates.status-after are empty) and wrote each exit to gates.exits.

  • cargo run -- --ci host: EXIT=0 (host EXIT=0), "Host: 76 step(s), all green" (host.log:7440). It ran fixed_hardware_reads_whichever_form_names_a_block and a_power_off_is_the_supervisors_stop_naming_a_shutdown.
  • cargo run -- --build-only: EXIT=0 (build EXIT=0, build.log).
  • cargo test (the whole guest suite): EXIT=0 (guest EXIT=0), "30 passed, 30 total" (guest.log:882), with PASS acpi_power_button (:664), PASS machine_shutdown (:709) and PASS machine_shutdown_short_stop (:779). Load average was 73.16 at its start and 43.46 at its end (guest.load). counters_metal is in RUST_SKIP; the staging below built it.
  • This head's judges on the 8d7004d3b readbacks (copies under acpi1-r16/old-8d7004d3b/, so the originals are untouched; judge-old.exits): --metal-readback … acpi_server_ EXIT=0, "2 passed, 0 failed, 2 boot(s)" (judge-old-acpi_server.log); --metal-readback … counters EXIT=0, "3 passed, 0 failed, 3 boot(s)" (judge-old-counters.log). This shows that the judges round 13 edited still read a real T14 log, acpi_death_on_metal without its dropped branch included. It is no reading of this head's kernel: those boots ran 8d7004d3b's.
  • The T14 readings at 8d7004d3b do not stand for this head. git diff --stat 8d7004d3b 922a6b7c7 over the image sources is kernel/src/arch/x86_64/acpi_mode.rs +59/−27, toyos-acpi/src/fadt.rs +21/−11, toyos-acpi/src/lib.rs and acpi_hold.rs's doc: the kernel in every image changes, and acpi_server_death reads the line the change rewrites. The three rows were staged and then run at 922a6b7c7, all green (T14 rows, below). None of them needs a person at the machine.
  • Not gated, and said so: 04bcf041d itself was never gated whole. Its host run (acpi1-r15/host.exit, EXIT=0) was on that tree less one later edit, and its guest suite could not build. 922a6b7c7 differs from it by issues and by three comment lines of acpi_mode.rs, replaced three for three.

At 8d7004d3b (before round 13).

Logs under the orchestrator's scratchpad, orch/acpi1-r13/. Each command's exit is written to a file beside its log.

  • cargo run -- --ci host at 8d7004d3b: EXIT=0 (host-8d7004d3b.exit), "Host: 76 step(s), all green" (host-8d7004d3b.log). It ran bootlog::tests::a_power_off_is_the_supervisors_stop_naming_a_shutdown, metal::tests::a_power_off_leaves_no_record_and_is_no_hang, checks::metal_power_off_owes_no_panel and checks::metal_loader_kernel_and_program_count_from_one_zero.
  • cargo test (the whole guest suite) at 8d7004d3b: EXIT=0 (guest-8d7004d3b.exit), "30 passed, 30 total" (guest-8d7004d3b.log), with acpi_power_button, machine_shutdown and machine_shutdown_short_stop PASS. Load average was 10.85 during the run. counters_metal is in RUST_SKIP; the staging below built it.
  • Mutation mut-old-head-fixture.patch (posted as a comment): a_power_off_is_the_supervisors_stop_naming_a_shutdown's fixture put back in the pre-Every line of the log opens with one head, time first, counted from the CPU counter's zero #737 head. cargo test --lib a_power_off_is_the_supervisors EXIT=101 at src/bootlog.rs:556 (mut-old-head-fixture.log, .exit), and the tree was restored clean. A fixture in the old head can no longer pass for a power-off.

Round 12's gates at cd5e11869, logs under orch/acpi1-r12/. host.head and guest.head hold cd5e118697a59de0b70be625d9b21b09318a17d6, and run.sh ran both.

  • cargo run -- --ci host at cd5e11869: EXIT=0 (run.exits: host EXIT=0), "Host: 76 step(s), all green" (acpi1-r12/host.log).
  • cargo test (whole guest suite) at cd5e11869: EXIT=0 (run.exits: guest EXIT=0), "30 passed, 30 total". Load was 3.23 at its start and 15.33 at its end (guest.log, guest.load). It does not run counters_metal, which is in RUST_SKIP. The staging below built it at head and in both arms (BUILT x86_64 binaries of tests/toyos-rust-tests in each stage-*.log).
  • Round 11's gates at 89c331ac1 (orch/acpi1-r11/): --build-only EXIT=0; --ci host EXIT=0, "Host: 76 step(s), all green"; the guest suite EXIT=0, "30 passed, 30 total".
  • Round 10's gates at 464504f7d (orch/acpi1-r10/): --ci host EXIT=0, "Host: 76 step(s), all green"; the guest suite EXIT=0, "30 passed, 30 total".
  • Round 9's gates at ff4945d6d (orch/acpi1-r9/): --ci host EXIT=0, "Host: 76 step(s), all green"; the guest suite EXIT=0, "30 passed, 30 total", machine_shutdown_short_stop PASS, machine_shutdown PASS, acpi_power_button PASS; load 30.72 at its start, 55.32 at its end; cargo run -- --build-only EXIT=0 (build1.log).
  • Round 8's gates at 3e73ab0ae (orch/acpi1-r8/): --ci host EXIT=0 "76 step(s), all green", the guest suite EXIT=0 "30 passed".
  • Earlier rounds' gates: at 5d0278a60 (orch/acpi1-r7/) --ci host EXIT=0 and the guest suite EXIT=0 "29 passed"; at ee6aadecb/619a7f05c (orch/acpi1-r4/) --ci host EXIT=0, the guest suite EXIT=0 "28 passed", the judge fix's negative control EXIT=101 (acpi1-r4/neg-judge-reverted.log).

The T14's two reds at a0f4e9ade, root causes

  • acpi_server_death: the test's boot configuration. tests/acpicase gave test-runner syscap = ["device"] without dup. test-runner hands each job its capability only as a duplicate (userland/test-runner/src/main.rs, run_one), a duplicate needs dup, and on PermissionDenied it spawns the job with none — so test_rs_acpi_release found nothing under its label: thread 'main' (1) panicked at src/bin/acpi_release.rs:20:60: test-runner endows a device-minting capability, exit: test_rs_acpi_release pid=8 code=101. acpiserver never ran on that boot (no isa: the ACPI fixed hardware's ports are line, no ACPI mode: line). tests/metaldevicecase already grants ["device", "dup"] for the same handing; tests/acpicase now does too.
  • acpi_server_events: the server was right; the row's boot was too short for what its judge reads. On the shared testcases boot the server armed (acpiserver: armed: power button served, embedded controller on GPE 0x6e at 0x66/0x62, 0 GPE(s) the namespace runs, 1.196 s), took the SCI (isa: the ACPI fixed hardware took its first interrupt, 2.962 s) and logged its first query (acpiserver: embedded controller query 0x4f taken for the first time, served by nothing: stage 1 runs no AML, 2.962 s), and the job list reached reboot at 10.466 s. The server writes its counts line once its 30 s count interval has passed, so no boot that ends at 10 s can carry one. The row now boots testcases-hold, whose one job, test_rs_acpi_hold, holds the list open to 54 s (JOB_BOUND_MS - JOB_BOUND_MS / 10, the shape lan_talk_hold uses), and its judge first asks that job to have passed. The judge's checks are unchanged.
  • Found on the way, same row family: acpi_press_hold slept 180 s, past the runner's 60 s job bound (toyos_tco::JOB_BOUND_MS), so on the attended boot the runner would have killed it and rebooted at 60 s, and its "no press in 180 s" line could never be written. The press boot now runs the same test_rs_acpi_hold: the owner has from the server's arming (about 1.2 s) to 54 s, and the press judge reads acpi_hold: held to as nobody having pressed.

Why a new guest test (acpi_power_button, machine_shutdown_short_stop)

QMP system_powerdown on q35 raises the fixed power-button event: the press → SCI through the I/O APIC level line → the handler's mask → the server's record → the supervisor's stop → S5, which QEMU reports as guest-shutdown. No type or host test reaches the interrupt path or the firmware's register block; the T14's press is read by no row (round 13). It asserts the press arrived as SCI 1 — the level line masked until served — then STOPPING (Shutdown), Shutting down. and QEMU's guest-shutdown.

machine_shutdown_short_stop: a stop that ends with a userland thread running, then the power-off, on q35 with acpiserver holding the row in ACPI mode. One CPU and stop-budget-spent: test_rs_stop_short spawns a spinning thread and asks the supervisor for the power-off, so the stop's one sweep finds the spinner queued behind the caller. It asserts the server armed, the firmware handed over in ACPI mode (so quiet runs), the stop record says threads were left running (stop: 14 of 17 userland thread(s) stopped across 1 cpu(s) in 0 ms of a 0 ms budget over 1 sweep(s)), no kernel death, and QEMU's guest-shutdown. Not a type: what 5d0278a60 did wrong was a runtime branch on the stop's record, and what must hold is that the whole stop and power-off end the machine. Not a host test: no host test runs quiesce::stop or power::off. Not a metal row: the T14 hands over in legacy mode, a power-off leaves it needing a hand, and a stop short on purpose needs the actuator's one-CPU guest. It is the test that reds on BLOCKER 1 (negative control below).

Negative control and mutations (patches posted as comments 5977460273, round 7 5982314577, round 8 5983718133, round 9 5984251318, round 10 5985109579, round 11 5985481401, round 12 5985746125)

  • Round 12, the counters row's control: arms P and N (comment 5985746125), run on the T14 at cd5e11869 (comment 5985874439): P EXIT=0, 3 passed, with the query at 2.483 s before the settle; N EXIT=1 from the judge, naming the first-interrupt and first-query lines at 1.804 s inside the second. Both arms set IDLE to 3 s, which is still far inside COUNTS, so that a line the wait failed to keep out has a wider second to land in.

    • P (wt/toyos-acpi1-arm-p, efb44c9f4, a child of head) changes only that. Expected GREEN.
    • N (wt/toyos-acpi1-arm-n, 69eb4fc10, a child of P) also makes acpi_said stop waiting at the arming line (armed.is_some()). It built with no allow. Expected RED from the judge, with test_rs_counters_metal exiting 0 and the idle second … holds lines naming isa: the ACPI fixed hardware took its first interrupt and acpiserver: embedded controller query 0x4f taken for the first time.
    • When an N boot does not count. If the query is stamped before idle0, the boot did not exercise the mutation. It is reported as such and staged again, and it does not count as a pass.
    • Each image carries its arm, checked on the staged bytes (acpi1-r12/image-carries.txt). The counters_metal binary each staging built hashes the same as the bytes of its testcases/image.img at offset 116445184. Disassembly (metal-*/counters_metal.dis): before sleep at 0x27410, head loads movl $0x1, %edi and both arms load $0x3. In until::<acpi_said::{closure#0}>::{closure#1}, P computes done from the armed byte, interrupt and query. N computes it as cmpb $0x2, (%rax); setne %al, which is armed.is_some().
  • Round 11's control, acpi-in-second.patch: red, but it showed nothing about the change (orchestrator's T14 run, comment 5985637817; review round 5). The patch called acpi_said after settle on the same Log. settle had already read past acpiserver: armed: (1.189 s), so acpi_said could never see an arming line. It panicked at its 10 s bound, at 11.240 s (metal-acpi-in-second/testcases/kernel.log:369-370), and test_rs_counters_metal exited 101, so the judge stopped at job_passed and never read the second. Had it run as meant, it would have tested The kernel's idle report is gone, and the counters row measures a quiet idle second #728's judge on a counts line, which is main's claim and not this round's. It also dropped loaded. The round-12 pair replaces it. The run does show the 10 s bound is loud on metal: the panic came 10.04 s after the wait began, naming what it waited for.

  • M11 (round 9) the stop's stage no longer gates SMI_CMD writes (acpi1-r9/m11-smi-cmd-ungated.patch, applied and reverted in m11.sh, m11.exits): cargo test -- machine_shutdown EXIT=0, "2 passed, 2 total" (m11-shutdown.log); cargo test -- acpi_power_button EXIT=0, "1 passed" (m11-button.log). Green as expected: no QEMU boot writes SMI_CMD (round 9, above, says why no tier reaches it).

  • Round 8, BLOCKER 1's fix reverted onto 3e73ab0ae (the eight product files back to the merge 2746aef8; the test, its binary and the actuator's budget kept): cargo test -- machine_shutdown_short_stop EXIT=1, QEMU had not exited 25 s after it was asked to (acpi1-r8/negative-control.log). A second run of the same patch with one line that writes the console out (negative-control-2.log, EXIT=1) shows the stop record stop: 14 of 17 userland thread(s) stopped across 1 cpu(s) in 0 ms of a 0 ms budget over 1 sweep(s) and then PANIC: panicked at src/arch/x86_64/acpi_mode.rs:283:9: power: the stop left userland running, so the events its ACPI holder enabled cannot be quieted for S5 — the reviewer's panic. With the fix: EXIT=0 (guest-debug2.log, and the suite above).

  • M10 (round 8) take_back issues no shootdown: cargo test -- machine_shutdown EXIT=0, both green (acpi1-r8/m10.log). No test reaches it: the stop's own kick, sent when the stage opens, reaches every CPU milliseconds before quiet (the USB flush and seal lie between), and a CPU in Ring 3 takes it at once, so no guest can put a holder in Ring 3 at quiet. The shootdown makes that an acknowledgement rather than a delivery time; checked by reading leave_user_if_due, Shootdown::serve's acquire of the generation issue publishes after STAGE.open, and the exit path every Ring 3 return takes (quiesce.rs's header).

  • Whole change reverted (product code and the testcases manifest reverted onto this head, test kept): acpi_power_button EXIT=1, STALLED: waiting for the ACPI server arming. On the T14 the control is main's own counters row (Boot 1: ΔSMI ≥ 2 alike, legacy mode).

  • M1 isa::isr skips the level mask: EXIT=1 — the power button was pressed, on SCI 10000 of this boot.

  • M4 isa::ack unmasks nothing: EXIT=1 — the press never arrives (STALLED: waiting for the boot's last word).

  • M2 sci_line's default edge/high: toyos-acpi --test corpus EXIT=101 (the_sci_defaults_to_level_and_active_low_where_nothing_says_otherwise).

  • M5 Reserved::declare skips the clash: toyos-userbound EXIT=101.

  • M7 (round 7, in the shared address decoder) X_ disagreement unrefused: corpus EXIT=101 (acpi1-r7/m7.log).

  • M8 (round 7, retargeted) another GPE taken as the EC's: acpiserver host tests EXIT=101 (acpi1-r7/m8.log).

  • M3 claim_row skips the holder check: on the T14 at 5d0278a60 (orchestrator, comment 5982813833), cargo test --test toyos-build -- --metal --metal-readback orch/acpi1-r7/metal-m3 isa_claim_refused EXIT=1, FAIL test_rs_isa_claim_refused: test_rs_isa_claim_refused exited 101 on the T14 (orch/acpi1-r7/metal-m3/judge2-isa_claim_refused.log); its kernel log: a claim on the i8042 answered Ok(()), not PermissionDenied, GSI 1 and 12 routed to the claimant. Red again at 3e73ab0ae (below), and restaged at ff4945d6d.

  • M9 (round 3) S5 the platform ignores: off writes SLP_TYP 7, which q35 does not act on; cargo test -- machine_shutdown EXIT=1 — QEMU stopped this guest for None, not "guest-shutdown", the console carrying PANIC: … power: S5 did not take: the machine still runs 2000ms (…) after SLP_EN; PM1a_CNT read 0x0001 before the write of 0x3c01 and reads 0x1c01 now, SCI_EN set; PM1 status 0x0000 under enable 0x0000; cpu0's SMI count unread before the write and unread now (acpi1-r3/mut-s5-ignored.log). This is why no guest test of the panic is added: it needs a platform that ignores a valid SLP_TYP, which only an actuator shipped for the test could stage, and QEMU never stalls on the valid one (measured above), so no QEMU test reds on the T14's stall.

  • off() clearing SCI_EN, or skipping quiet: no QEMU or unattended red; on the T14 SLP_SMI_EN routes the sleep write to SMM, and no T14 row reads a power-off (round 13). Checked by reading against the spec's sequence.

Oracles

ACPI 6.5 (FADT Table 5.9/5.10, ECDT Table 5.88, MADT INTI flags, PM1 Tables 4.13/4.16, EC §12); Linux's readings of the T14 (above); QEMU's ICH9 model (the guest test); the T14 rows below.

T14 rows

Run at 922a6b7c7, all green (the orchestrator's run, comment 6039409933; per boot in round 14, at the top). Round 13 changes the kernel in every image, so every row's old reading is of another kernel; three rows read what it changes, and they are the ones staged: counters (reds on acpi: legacy mode again, and reads the mint's line), acpi_server_events (the row and the server's lines on a boot held 54 s) and acpi_server_death (the release: the disable, the poll, and the rewritten legacy mode again: … PM1a_CNT reads … <time> after, SCI_EN clear). Every boot ends in the job list's reboot; none needs a person. The isa_ rows and acpi_table_inventory are not restaged: the round's brief names these three. Their 8d7004d3b readings are of the previous kernel; kernel/src/isa.rs and kernel/src/arch/x86_64/pio.rs are unchanged since it (the image sources' diff is in Gates).

Staged by orch/acpi1-r16/stage.sh from the clean head (stage.head is 922a6b7c72f59a267478b13059d97bf2c0579b6f; stage.status is empty). Each stage ran cargo test --test toyos-build -- --metal --metal-readback orch/acpi1-r16/<dir> <filter> and exited 2 with the machine untouched (stage.exits, stage-<dir>.log). Hashes are in orch/acpi1-r16/images.sha256; orch/acpi1-r16/request.txt lists the boots, the hashes and the two judge commands.

dir, filter rows images (sha256)
metal-counters, counters counters shared c46cc487…4195, shared-debug 2ef538f3…c6d6, testcases abb72e22…939c
metal-acpi_server, acpi_server_ acpi_server_events, acpi_server_death acpicase 2d8c1f2f…ff8e, testcases-hold ae15eb50…86a0

What the green run shows, and what it does not. acpi_server_death green shows the T14's firmware cleared SCI_EN inside the poll, 17068 ns after the write, and the kernel said so. It cannot show the 100 ms expiry or the still in ACPI mode line, which need a firmware that ignores ACPI_DISABLE; what follows the expiry is issues/the-acpi-row-is-released-with-an-acpi-disable-the-firmware-has-not-answered.md. The judge's run on the two new boots asked for tests/metal/lenovo-20w0003amz.toml to be committed with their six timing numbers (boot.acpicase.*, boot.testcases-hold.*); round 14's commit carries them.

Results at 8d7004d3b (the previous kernel; orchestrator's runs, comments 5986396904 and 5989607386; worktree clean at that head, each image's sha256 checked before its flash, every boot rc=0). isa_ EXIT=0, "3 passed, 0 failed, 2 boot(s)"; acpi_server_ EXIT=0, "2 passed, 0 failed, 2 boot(s)"; acpi_table_inventory EXIT=0, "1 passed, 0 failed, 1 boot(s)"; counters EXIT=0, "3 passed, 0 failed, 3 boot(s)". The two attended rows, with the owner: acpi_power_off EXIT=0 and acpi_power_button_pressed EXIT=0, the latter on a boot the owner reports pressing three times on (the press issue). Both rows are deleted in round 13. Judge logs orch/acpi1-r13/metal-*/judge-*.log.

What the merge of #737 changed on the T14, and what was staged at 8d7004d3b. Two kinds of change reached the judges.

  • Every row's judge, through main. judge_readbacks now runs bootlog::one_clock on every boot. Every line on the stick is written in the new head, and every judge reads it through parse. The loader and the kernel's clock change with Every line of the log opens with one head, time first, counted from the CPU counter's zero #737 too.
  • The judges this merge itself edits. acpi_power_off and acpi_power_button_pressed: asked_to_power_off, which both of them, boot_verdict and judge_readbacks' panel exemption rest on, now reads the stop line through program_line. acpi_server_events: acpi_events_on_metal picks the server's lines by tag. counters: the judge's code is unchanged, but the job's acpi_said now matches the first-interrupt line through parse, and main's stamp_ns is what idle0, idle1 and spin are read at.
  • Unchanged by this merge's own edits, and changed only through main: the isa_ rows, acpi_server_death and acpi_table_inventory.

The two attended rows are deleted in round 13; what follows is the record of why they were re-run at 8d7004d3b. Their judges could not be shown unchanged in what they read. Their verdict rested on the supervisor's stop line. #737 changed that line's bytes, from {… supervisor} to [… supervisor], and the merge changed the reader. judge_readbacks now also requires one_clock of their boot, which no power-off boot has been judged by. The loader and the kernel's clock changed under them too. The power-off path in the kernel and acpiserver did not change (git diff --stat cd5e11869 8d7004d3b -- kernel/src/arch/x86_64/power.rs kernel/src/arch/x86_64/acpi_mode.rs kernel/src/quiesce.rs userland/acpiserver userland/supervisor is empty). But what the judges read did change, and the old readbacks were written in a head the new parser refuses.

Staged by orch/acpi1-r13/stage.sh from the clean head 8d7004d3b (stage.head; stage.status is empty). Each stage ran cargo test --test toyos-build -- --metal --metal-readback orch/acpi1-r13/<dir> <filter>, and each exited 2 with the machine untouched (stage.exits, stage-<dir>.log). Hashes are in orch/acpi1-r13/images.sha256.

dir, filter rows images (sha256)
metal-isa, isa_ the three isa_ rows isa-withheld 165ef532…1cd6, shared 9ac606cd…6101
metal-acpi_server, acpi_server_ acpi_server_events, acpi_server_death acpicase 9a6543b9…39ed, testcases-hold 5353bc16…2691
metal-acpi_table_inventory, acpi_table_inventory acpi_table_inventory testcases 7e48479d…001f
metal-counters, counters counters shared 83a2de6d…06f0, shared-debug 5e706408…7abc, testcases b3cb2c0b…dc06
metal-acpi_power_off, acpi_power_off (attended: the owner powers it on again) acpi_power_off testcases-off fe9002a0…ae582
metal-acpi_power_button_pressed, acpi_power_button_pressed (attended: one brief press) acpi_power_button_pressed testcases-press 65e17dac…c880

The results below are of earlier heads.

Results at cd5e11869 (orchestrator's run, comment 5985874439; worktree clean; images checked against orch/acpi1-r12/images.sha256): counters EXIT=0, 3 passed; arm P EXIT=0, 3 passed; arm N EXIT=1, the judge naming the ACPI lines in the second. Judge logs orch/acpi1-r12/metal-*/judge-counters.log. The rows below at ff4945d6d stand: this branch's production code is unchanged since then.

Results at ff4945d6d (the orchestrator's runs, comments 5984390036 and 5984507827: worktree clean at that head, each image's sha256 checked against acpi1-r9/images.sha256 before its flash, every boot rc=0). Each judge is cargo test --test toyos-build -- --metal --metal-readback orch/acpi1-r9/<dir> <filter>, run from the clean head, with its log in the orchestrator's job directory. The two attended rows ran with the owner.

row(s) dir, filter boots exit judge log
isa_ports_are_the_binders_alone, isa_lines_reach_their_holder, isa_claim_refused metal-isa, isa_ isa-withheld 0e839e58…21b8, shared d1c4aeb5…cc5f EXIT=0, "3 passed, 0 failed, 2 boot(s)" acpi1-r9/metal-isa/judge-isa_.log
acpi_server_events, acpi_server_death metal-acpi_server, acpi_server_ acpicase 128f80aa…6d55, testcases-hold 7d99d5aa…b9c EXIT=0, "2 passed, 0 failed, 2 boot(s)" acpi1-r9/metal-acpi_server/judge-acpi_server_.log
acpi_table_inventory metal-acpi_table_inventory, acpi_table_inventory testcases 5bb0eda7…1ee EXIT=0, "1 passed, 0 failed, 1 boot(s)" acpi1-r9/metal-acpi_table_inventory/judge-acpi_table_inventory.log
counters metal-counters, counters shared fb9abb40…f41, shared-debug 674f9e9c…e7f, testcases 62f2b647…8f7a EXIT=0, "3 passed, 0 failed, 3 boot(s)": 8 cpus, SMI flat on each over 12232 ms, SCI_EN set 16006ns after; cpu0's SMI count 4818 before the write and 4819 after acpi1-r9/metal-counters/judge-counters.log
M3 arm (m3-claim-skips-holder.patch), expected red metal-m3, isa_claim_refused shared f6bb8afc…c195 EXIT=1, FAIL test_rs_isa_claim_refused: test_rs_isa_claim_refused exited 101 on the T14, "0 passed, 1 failed, 1 boot(s)" acpi1-r9/metal-m3/judge-isa_claim_refused.log
acpi_power_off (attended) owner-acpi_power_off, acpi_power_off testcases-off d2b732d6…20e3 EXIT=0, "1 passed, 0 failed, 1 boot(s)": the machine stayed off, and the owner powered it on acpi1-r9/owner-acpi_power_off/judge-acpi_power_off.log
acpi_power_button_pressed (attended) owner-acpi_power_button_pressed, acpi_power_button_pressed testcases-press 0b20db5e…f639 EXIT=0, "1 passed, 0 failed, 1 boot(s)" acpi1-r9/owner-acpi_power_button_pressed/judge-acpi_power_button_pressed.log

The press, per its run instructions: the owner pressed once, about 10 s after the panel showed the loader's last line, and reports the machine "almost immediately went off" (owner-acpi_power_button_pressed/owner-notes.txt; the press's time was recorded only to the minute). The boot's own record, testcases-press/kernel.log:

[13.089] acpiserver: embedded controller query 0x28 taken for the first time, served by nothing: stage 1 runs no AML
[13.105] acpiserver: the power button was pressed, on SCI 13 of this boot; asking the supervisor to power off
[13.105] supervisor: power: the machine stops, and logkeeper makes the log whole first (Shutdown)

So one press raised 0x28 and the power-button event 16 ms later, then the stop: no lag. Added to the press issue's table this round.

Earlier heads: at 3e73ab0ae (comment 5983862418, orch/acpi1-r8/) and 5d0278a60 (comment 5982813833, orch/acpi1-r7/) the five unattended entries above ran with the same exits.

Results at 464504f7d (the orchestrator's run, its comment on this PR: worktree clean, each image's sha256 checked against acpi1-r10/images.sha256 before its flash, all 15 boots rc=0). isa_ EXIT=0, "3 passed"; acpi_server_ EXIT=0, "2 passed"; acpi_table_inventory EXIT=0, "1 passed"; counters EXIT=0, "3 passed". It was green only because the first query came at 3.325 s, after idle1 (round 11, above). M3 (expected red) EXIT=1, FAIL test_rs_isa_claim_refused. retake-shown (expected green) EXIT=1 and retake-off (expected red) EXIT=1, both on the lines round 11 explains. Judge logs: acpi1-r10/metal-*/judge-*.log.

Results at 89c331ac1 (the orchestrator's run, comment 5985637817: worktree clean at head, each image's sha256 checked against acpi1-r11/images.sha256 before its flash, all six boots rc=0). counters EXIT=0, "3 passed, 0 failed, 3 boot(s)". On that boot the first interrupt and query came before the settle's lines (round 11, above), so it does not show the wait at work. The control acpi-in-second EXIT=1, "2 passed, 1 failed, 3 boot(s)", FAIL counters: test_rs_counters_metal exited 101 on the T14. That is the job's own wait failing, not the judge naming a line (Negative control, above). Judge logs: acpi1-r11/metal-*/judge-counters.log.

What round 12 changes on the T14, and what is staged. Only counters_metal.rs changed on the branch's side (git diff --stat 89c331ac1 cd5e11869 -- . ':!bootloader' ':!issues'), and that binary runs only in the counters row. The merge brings #738, which changes the loader's lock and profile only. Staged by acpi1-r12/stage.sh. Each arm is checked out as a detached commit with a clean tree (<dir>.status empty, <dir>.head its commit), and then cargo test --test toyos-build -- --metal --metal-readback orch/acpi1-r12/<dir> counters is run. Each exited 2 with the machine untouched (stage.exits, stage-<dir>.log). The worktree was back on wt/toyos-acpi1 and clean afterwards. Hashes are in acpi1-r12/images.sha256.

  • acpi1-r12/metal-counters/request.txt: the row at head cd5e11869, expected green. shared (aa513ced…ca454a), shared-debug (3c320edf…99133d), testcases (6bd5b6c5…f84c6f).
  • acpi1-r12/metal-arm-p/request.txt: P, efb44c9f4, expected green. shared (cfa4dd02…cf9cd7), shared-debug (e5d7605f…04bbab), testcases (54e5b231…466aa2).
  • acpi1-r12/metal-arm-n/request.txt: N, 69eb4fc10, expected red from the judge on the two lines above. shared (7f9b16ae…08c1b6), shared-debug (01906c40…5e730e), testcases (5662ba48…812a45). Only testcases carries counters_metal, but the filter stages all three boots.

What round 10 changed on the T14, and what was restaged then. The branch's own change this round is counters_metal and an issue. The merge brings main's kernel and userland changes (#728 deletes the kernel's idle report, #734 changes the interrupt census, #733 moves routine lines to stdout), and these run on every image. So every unattended row is restaged at 464504f7d. The power-off and press path did not change: neither the round's commit nor the merge touches acpiserver, toyos::power, the supervisor, logkeeper, quiesce, power::off or acpi_mode (git diff --name-only ff4945d6d 464504f7d). The merge's kernel diff is 23 files, +100/−306: the idle report and the PMM category counters only it read, the census, and the call sites of both. The two attended rows are therefore not restaged, and their ff4945d6d results above stand for this path.

Round 10 staged every unattended row, M3 and the two retake arms at 464504f7d (acpi1-r10/stage.sh, stage.exits; patches in comment 5985109579); their results are above.

Unsure

  • Round 13: the 100 ms HANDBACK is this kernel's own number: the specification names no bound and nothing measured one. The T14's firmware took 17068 ns on the one boot that read it. The claim's last handle goes from the deferred queue with no lock held (ZeroHandles::on_zero_handles's contract, kernel/src/object/mod.rs), so the spin of up to 100 ms holds nothing, and it lasts that long only where the firmware does not answer. Past the bound the row is handed back with the disable unanswered: filed in round 14, not fixed. The interpreter stage's exit in the track is a proposal.
  • Whether a firmware exists that needs SMI_CMD written from the boot processor, as Table 5.9 words it. The T14's took the enable from cpu7 twice. Filed, not fixed.
  • The specification was read from the Internet Archive's captures, not from uefi.org; the two HTML files are kept under orch/acpi1-r16/spec/ with the hashes above.
  • Whether the T14 firmware latches a press during the 2 ms enable. Whether the EC's GPE on the T14 behaves as an edge, as Linux treats it: if it is level, the drain-then-ack still holds, at one extra SCI per event.
  • The 3 s handover bound, the 500 ms EC step, 32 queries and 64 empty SCIs are policy numbers, not measurements. So is S5_TAKES' 2 s, which would turn a T14 whose S5 is slow but works into a panic.
  • Whether b3b9ccd69's press boot stalled in the power-off or lost its first press. The one deliberate press at ff4945d6d favours a lost first press, but that press's time was recorded only to the minute, so the press issue's exit stays unmet.
  • The press instructions' boot-time zero: the loader's last panel line comes before the kernel's clock starts (at its counter calibration), by a span no T14 log states, and a human reading the panel adds about a second. That is enough to tell a 10 s lag from a lost press, and no finer.
  • machine_shutdown_short_stop runs on one CPU, where the shootdown answers itself. That the shootdown's answers from other CPUs end every Ring 3 run rests on reading (M10, above).
  • What the T14's firmware did in legacy mode with the EC queries that now go unserved (0x4f, 0x28): not read. What is read: the legacy-mode scout saw the EC's GPE 0x6e status in none of its 25 reports, and the status rose and stayed set once ACPI_ENABLE was written, so in legacy mode whatever served those events did it out of the OS's sight. _Q4F in the DSDT calls ADBG("QUERY_METHOD_UCSI") and notifies \_SB.UBTC (the USB-C UCSI device), which ToyOS has no driver for, and no table defines _Q28. So the stage ruling's "nothing the firmware does in legacy mode today is lost" stands unverified for these two queries.
  • Size at 9dcfa09bc: origin/main...9dcfa09bc +3667/−592 over 85 files; tests/, src/ and toyos-acpi/tests/ +814/−100, issues/ +395/−22, the rest (production) +2458/−470, unchanged by round 14. Before it, at 922a6b7c7: origin/main...922a6b7c7 +3624/−592 over 83 files; tests/, src/ and toyos-acpi/tests/ +808/−100, issues/ +358/−22, the rest (production) +2458/−470. Round 13 alone (47ac0ce19..922a6b7c7) is +284/−302 over 19 files: production +81/−39, tests/, src/ and toyos-acpi/tests/ +32/−191, issues/ +171/−72. Before it: origin/main...8d7004d3b +3591/−585 over 86 files; tests/, src/ and toyos-acpi/tests/ +933/−102, issues/ +242/−13, production unchanged by the merge. Before it, origin/main...cd5e11869 +3583/−585 over 86 files. Of that, tests/, src/ and toyos-acpi/tests/ are +925/−102, issues/ +242/−13, and the rest (production) +2416/−470, the same as at ff4945d6d. Round 12 alone (1d4fb9358..cd5e11869) is counters_metal.rs +11/−24. Round 11 alone (464504f7d..89c331ac1) is counters_metal.rs +101/−78: the retake goes, and Log, acpi_said and the counts assertion come in. Round 10 alone (5c89f8954..464504f7d) was +66/−21. Earlier: origin/main...ff4945d6d +3497/−553 over 85 files; round 9 alone (a9bb64c7b..ff4945d6d) +43/−7 over 4 kernel files; round 8 alone (2746aef8..3e73ab0ae) +161/−65 over 14 files; round 7 alone (43f99ee95..5d0278a60) +196/−215.

🤖 Generated with Claude Code

Japabu and others added 4 commits October 4, 2026 06:48
… its SCI, power button and EC events served

The kernel declares every I/O port it drives in one place (`arch::pio`), the
only maker of the token `cpu::{in,out}{b,w}` take: COM1, the 8259 pair, the
POST port, the CMOS RTC and the PCI configuration mechanism fixed, and the
i8042, the reset register, the PM1a control block, SMI_CMD and the TCO block
as their probes and tables name them. An `isa` row is refused naming the
holder of any port it shares; the I/O permission bitmap covers the whole
port space.

The `isa` rows are filled at boot: the i8042's, and the ACPI fixed hardware's
(the FADT's PM1a event and GPE0 blocks, the ECDT's two EC ports, the SCI as a
level line). `DeviceType::Acpi` claims the second; the mint writes
ACPI_ENABLE to SMI_CMD where SCI_EN reads clear, parks and polls SCI_EN every
1 ms for up to 3 s, and logs this CPU's SMI count before and after through the
counters; the release writes ACPI_DISABLE where the mint wrote the enable and
reads SCI_EN back. A machine with no ECDT, or a control-method power button,
stays in legacy mode, refused by name. A level line is masked by its handler
and unmasked by the holder's acknowledgement, a 4-byte write of 1 to the claim.

The I/O APIC's topology is written once; each unit's register pair is a
`Masked` lock a handler may take, a routed pin keeps its entry's low word, and
a mask is one write of it. The SVR is written whole and asserted. The SCI
defaults to level, active low where no override says otherwise (ACPI 6.5
Table 5.9). `power::off` disables and clears every event on a machine in ACPI
mode, then writes SLP_TYP and SLP_TYP|SLP_EN over the bits PM1a_CNT holds.

`/system/bin/acpiserver` takes the claim: disables and clears every event,
enables the power button, the EC's GPE and the GPEs the AML would run (none in
stage 1, `aml.rs`), drains the EC's backlog, and acknowledges. A press stops
the machine through the supervisor; the EC's GPE drains the controller of its
queries (`ec.rs`, a transaction with no I/O), which then run as `aml::query`
says, after the drain. Each query number is logged once and the counts every
30 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
Stage 1 reads the embedded controller from the ECDT so the T14 switches to
ACPI mode now; that path goes when the interpreter reads the controller from
the DSDT, and a machine without an ECDT stays in legacy mode until then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
… host

Seen in this branch's whole guest suite at b9430ed (load average 82 on 14
cores); the test alone at that load passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Mutation patches and the negative control, each applied with git apply, run, and reversed in the same script (results in the PR body). The control patch is git diff origin/main b9430ed61 -- kernel toyos-abi toyos toyos-acpi toyos-userbound userland system.toml tests/testcases/system.toml, applied with -R (4413 lines; not reproduced here).

m1-isr-skips-mask

diff --git a/kernel/src/isa.rs b/kernel/src/isa.rs
index b190377c3..1418e7db4 100644
--- a/kernel/src/isa.rs
+++ b/kernel/src/isa.rs
@@ -232,11 +232,6 @@ pub fn has_irq(row: usize) -> bool {
 /// own and the I/O APIC's masked one, and allocates nothing.
 pub fn isr(row: usize) {
     IRQ[row].took();
-    for &line in lines(row) {
-        if pio::level(line) {
-            pio::set_masked(line, true);
-        }
-    }
     WATCHES[row].post_in_place();
 }
 

m2-sci-conforms-edge-high

diff --git a/toyos-acpi/src/madt.rs b/toyos-acpi/src/madt.rs
index 5c87c3371..005e317f1 100644
--- a/toyos-acpi/src/madt.rs
+++ b/toyos-acpi/src/madt.rs
@@ -208,5 +208,5 @@ pub fn isa_line(irq: u8, overrides: &[SourceOverride]) -> Line {
 /// sharable, level, active-low interrupt, which is its default whether no
 /// override names it or one names it conforming.
 pub fn sci_line(sci_int: u16, overrides: &[SourceOverride]) -> Line {
-    line(u32::from(sci_int), overrides, (Trigger::Level, Polarity::Low))
+    line(u32::from(sci_int), overrides, (Trigger::Edge, Polarity::High))
 }

m3-claim-skips-holder

diff --git a/kernel/src/isa.rs b/kernel/src/isa.rs
index b190377c3..19f652a78 100644
--- a/kernel/src/isa.rs
+++ b/kernel/src/isa.rs
@@ -124,7 +124,7 @@ pub fn claim(set: IsaId) -> Result<usize, ClaimError> {
 /// left masked for the holder's first acknowledgement.
 pub fn claim_row(row: usize) -> Result<usize, ClaimError> {
     let function = function(row).ok_or(ClaimError::Absent)?;
-    if let Some((run, holder)) = function.runs.iter().find_map(|&run| pio::holder(run).map(|h| (run, h))) {
+    if let Some((run, holder)) = function.runs.iter().find_map(|&run| pio::holder(run).map(|h| (run, h))).filter(|_| false) {
         log!("isa: {}'s ports {:#x}+{} are {holder}'s", function.name, run.first(), run.count());
         return Err(ClaimError::KernelDriven);
     }

m4-ack-unmasks-nothing

diff --git a/kernel/src/isa.rs b/kernel/src/isa.rs
index b190377c3..d3eb72f4d 100644
--- a/kernel/src/isa.rs
+++ b/kernel/src/isa.rs
@@ -180,9 +180,7 @@ pub fn ack(row: usize) -> Result<(), ()> {
     if level.peek().is_none() {
         return Err(());
     }
-    for line in level {
-        pio::set_masked(line, false);
-    }
+    level.for_each(drop);
     Ok(())
 }
 

m5-declare-skips-clash

diff --git a/toyos-userbound/src/port.rs b/toyos-userbound/src/port.rs
index 65b0af1f6..aef8d8487 100644
--- a/toyos-userbound/src/port.rs
+++ b/toyos-userbound/src/port.rs
@@ -131,9 +131,6 @@ impl<const N: usize> Reserved<N> {
 
     /// Reserve `ports` for `holder`, refused where another holder has one of them.
     pub fn declare(&mut self, holder: &'static str, ports: Ports) -> Result<(), Undeclared> {
-        if let Some(first) = self.holder(ports) {
-            return Err(Undeclared::Clash(first));
-        }
         let slot = self.runs.iter_mut().find(|slot| slot.is_none()).ok_or(Undeclared::Full)?;
         *slot = Some((holder, ports));
         Ok(())

m7-x-disagreement-unrefused

diff --git a/toyos-acpi/src/fadt.rs b/toyos-acpi/src/fadt.rs
index 013ed347b..d09cb49dc 100644
--- a/toyos-acpi/src/fadt.rs
+++ b/toyos-acpi/src/fadt.rs
@@ -284,9 +284,6 @@ pub fn fixed_hardware<P: Phys>(fadt: &Table<P>) -> Result<FixedHardware, FixedRe
         if space != SPACE_SYSTEM_IO {
             return Err(FixedRefused::NotSystemIo { field, space });
         }
-        if legacy != 0 && u64::from(legacy) != extended {
-            return Err(FixedRefused::Disagrees { field, legacy, extended });
-        }
         Ok(extended)
     };
     let block = |field, address: u64, len: u8| -> Result<Block, FixedRefused> {

m8-unserved-gpe-taken

diff --git a/userland/acpiserver/src/sci.rs b/userland/acpiserver/src/sci.rs
index 274a541f1..ad85a944b 100644
--- a/userland/acpiserver/src/sci.rs
+++ b/userland/acpiserver/src/sci.rs
@@ -53,7 +53,7 @@ pub fn events(served: &Served, pm1: (u16, u16), gpe0: &[(u8, u8)]) -> Result<Vec
             events.push(match n {
                 n if served.ec_gpe == Some(n) => Event::Ec,
                 n if served.runtime.contains(&n) => Event::Runtime(n),
-                n => return Err(Unserved::Gpe(n)),
+                n => Event::Runtime(n),
             });
         }
     }

@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

T14 runs at a0f4e9ade — the unattended boots: counters GREEN (the ACPI-mode SMI reading), acpi_server_events and acpi_server_death RED.

Each image's sha256 checked in the command that flashed it; judged from the clean head, each row alone.

metal/acpicase image sha256 828147c7ef4679f47ebebb5f483651623d570c51a1b71edd5dca20bf77925640
metal/acpicase boot rc=0
metal/testcases image sha256 d7409b17d72915ddc8be1db372a7bc6348180b7857b764c92e26d3f52b362324
metal/testcases boot rc=0
acpi_server_events EXIT=1 [metal] 0 passed, 1 failed, 1 boot(s)
06:55:20   FAIL acpi_server_events: the server logged 1 first sighting(s) and None for counts
acpi_server_death EXIT=1 [metal] 0 passed, 1 failed, 1 boot(s)
06:55:42   FAIL acpi_server_death: test_rs_acpi_release exited 101 on the T14; its own lines are in the boot's log under the name of whoever ran it
metal-counters/shared image sha256 59e57e2746dfc0137987ec2f7b8eecd7d7894c17e358e9cc48db83a3adcc2e6a
metal-counters/shared boot rc=0
metal-counters/shared-debug image sha256 dba7f7590d369cc73d5e21080ceb2d794959af4f923c283ed8daca50e04df4ec
metal-counters/shared-debug boot rc=0
metal-counters/testcases image sha256 1528aa02d17790e9b3bd8b0d1d06f0456b1a5acfaf0a42911fecb74c1ee37757
metal-counters/testcases boot rc=0
counters EXIT=0 [metal] 3 passed, 0 failed, 3 boot(s)
07:02:46   PASS counters
done
  • acpi_server_death: test_rs_acpi_release panicked at src/bin/acpi_release.rs:20:60: test-runner endows a device-minting capability — on this boot test-runner does not.
  • acpi_server_events: the judge read the server logged 1 first sighting(s) and None for counts.
  • counters (metal-counters: shared, shared-debug, testcases): EXIT=0, 3 passed, PASS counters.
  • The row line: acpi: the ACPI row: PM1a events 0x1800+4, GPE0 0x1860+32, SCI gsi 9 level/high, the fixed-hardware power button, embedded controller at 0x66/0x62 on GPE 0x6e; the firmware handed over in legacy mode.

The attended acpi_power_button_pressed boot has not run. Readbacks and judge logs: orch/acpi1-build/metal*/, orch/acpi1-build/judge-t14-*.log.

Japabu and others added 4 commits October 4, 2026 09:12
…tlasts a count interval

acpi_server_death was red on the T14 because tests/acpicase gave test-runner
`device` without `dup`: test-runner hands a job its capability only as a
duplicate, a duplicate needs `dup`, and on PermissionDenied it spawns the job
with none, so test_rs_acpi_release panicked at `take(SYSCAP_LABEL)`. The boot's
configuration, not the server: acpiserver never ran on that boot.

acpi_server_events was red because the row rode the shared testcases boot,
which reached `reboot` at 10.466 s; acpiserver writes its counts line once a
count interval (30 s) has passed, and its one EC query (0x4f, at 2.962 s) was
logged as a first sighting as it should be. The server was right and the
boot was too short for what the judge reads. The row now has its own boot
holding the job list open to 54 s with test_rs_acpi_hold, inside the runner's
60 s bound, and its judge first asks that the hold ran out.

The same hold replaces acpi_press_hold, whose 180 s sleep outlasted the
runner's 60 s job bound: the runner would have killed it and rebooted at 60 s,
and the "no press in 180 s" line it printed could never be written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
…is no hang

The attended press on the T14 (#713 at b3b9ccd) ended its log at the
supervisor's "(Shutdown)" line, and the machine stayed on until a second
press. The same stop path, run for a reboot in ACPI mode on the
acpi_server_events boot, reached "Rebooting." 8 ms after the supervisor's
line; a power-off differs from it only in arch::power::off, which then
wrote SLP_EN and halted for ever: a machine that is on, silent, and that
the next boot cannot tell from one the power left.

off() now gives the platform two seconds after SLP_EN and then panics,
naming PM1a_CNT before and after, SCI_EN, the PM1 status and enable, and
the SMI count either side of the write: the panel shows it and the black
box carries it through the panic's reset. Measured on QEMU: the press's
whole stop takes 20 ms there, so no QEMU test reaches the T14's stall.

toyos-metal judged the press boot a hang because S5 takes the black box's
DRAM with it, which a correct power-off does too: a boot whose log ends
asking for a power-off now passes the stick's verdict on the next pass
finding no record. The press row reads that instead of a "Shutting down."
no S5 can leave, and a new acpi_power_off row asks for the same power-off
from a job, with no hand on the button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Round 3 mutation and probe patches, each applied to 7c3a7dc7d (the probe to b3b9ccd69), run, and reverted in the same script; the tree was clean after each.

M9: S5 the platform ignores — cargo test --test toyos-build -- machine_shutdown EXIT=1, the kernel's power: S5 did not take panic on the console.

diff --git a/kernel/src/arch/x86_64/power.rs b/kernel/src/arch/x86_64/power.rs
index 93b4bf320..96ff97cc8 100644
--- a/kernel/src/arch/x86_64/power.rs
+++ b/kernel/src/arch/x86_64/power.rs
@@ -177,7 +177,7 @@ pub fn off() -> ! {
     if held & SCI_EN != 0 {
         super::acpi_mode::quiet();
     }
-    let typed = held & !(SLP_TYP | SLP_EN) | u16::from(SLP_TYPA.load(Ordering::Relaxed)) << 10;
+    let typed = held & !(SLP_TYP | SLP_EN) | 7 << 10;
     let smis_before = super::counters::read().smi;
     // SAFETY: the block `init_off` declared and the `SLP_TYPa` the DSDT's `\_S5_` names, both decoded before `SOFT_OFF` was set.
     unsafe {

Probe (not a mutation): the QEMU press's console after the press — cargo test --test toyos-build -- acpi_power_button EXIT=0; the press's whole stop took 20 ms.

diff --git a/tests/common/power.rs b/tests/common/power.rs
index 0c845bf28..e10dd406a 100644
--- a/tests/common/power.rs
+++ b/tests/common/power.rs
@@ -505,6 +505,7 @@ pub fn acpi_power_button(test_config: &Path) -> Result<(), String> {
     stop.power_button();
     let pressed_at = console.len();
     ended(&mut qemu, &mut stop, &mut console, SHUTTING_DOWN, "guest-shutdown")?;
+    eprintln!("PROBE-CONSOLE-BEGIN\n{}\nPROBE-CONSOLE-END", &console[pressed_at..]);
     let after = serial::Serial::named("the press", console[pressed_at..].to_string());
     after.must_say(ACPI_PRESSED)?;
     after.must_say(&format!("{} (Shutdown)", toyos_build::bootlog::STOPPING))?;

@Japabu Japabu changed the title ACPI stage 1: the machine in ACPI mode for a userland server's claim; its SCI, power button and EC events served ACPI stage 1: the machine in ACPI mode for a userland server, its SCI, power button and embedded controller served Oct 4, 2026
@Japabu Japabu changed the title ACPI stage 1: the machine in ACPI mode for a userland server, its SCI, power button and embedded controller served ACPI stage 1: the machine in ACPI mode for a userland server's claim; its SCI, power button and EC events served Oct 4, 2026
@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

T14 results at 7c3a7dc7d (orchestrator's runs; worktree clean at head, each image's sha256 checked against the request before its flash; both boots attended by the owner).

boot sha256 row row verdict judge exit
testcases-off bb142f8abc4a5e5ec35c092143529f0477a3ba3e07d416da0843ca44daef9220 acpi_power_off PASS — the machine stayed off; the owner powered it on EXIT=1
testcases-press (second attempt) 5697490f43c832f50ef6790998790a2cd2170936971da9b3c212ea7c0f39642b acpi_power_button_pressed PASS — acpiserver: the power button was pressed, on SCI 7 of this boot; asking the supervisor to power off at 4.821 s EXIT=1

Both judges exit 1 on the record rows alone, not on the rows under test:

FAIL boot.testcases-off.panel_max_us: this boot recorded none
FAIL boot.testcases-off.panel_us: this boot recorded none
FAIL boot.testcases-press.panel_max_us: this boot recorded none
FAIL boot.testcases-press.panel_us: this boot recorded none

A boot that ends in a power-off records no panel timing; the harness expects it of every boot.

The first press attempt was red: acpi_hold: held to 54000 ms, and nothing stopped the machine — the owner's press came after the window (no on-screen cue). Its readback was overwritten by the second attempt.

ACPI mode on the T14: ACPI_ENABLE 0xf0 written to SMI_CMD 0xb2, SCI_EN set 16930ns after; cpu0's SMI count 4806 before the write and 4807 after.

Logs: orch/acpi1-r3/metal/judge-acpi_power_off.log, judge-acpi_power_button_pressed.log and the readbacks beside them in the orchestrator's job directory.

Japabu and others added 3 commits October 4, 2026 16:22
Conflicts, every hunk of both sides kept:
- kernel/src/sync.rs, kernel/src/watch.rs: this branch moved `Masked` into
  `sync.rs`; #716 changed its `lock` to `self.0.lock_masked(closed)`. The
  moved type carries #716's line, and `Lock::lock_masked` is now private to
  `sync`, so only `Masked` reaches it (#716's deferred visibility change:
  lockdep exempts a lock only if every take of it is masked). Main's
  `OwedLock` kept beside it.
- tests/toyos.rs: `counters_on_metal`'s doc carries main's HWP request and
  power-envelope checks and this branch's ACPI-mode SMI flatness.
- system.toml: acpiserver's entry and main's compositor comment.
- issues/: the branch's five issues move into the flat tracker; every
  citation of a subdirectory path in the branch's files is moved with them.
  The track keeps the ECDT ruling and main's power-off-through-the-server stage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
The panel's census crosses to the host only on the black-box page, and S5
takes the page with it. At 7c3a7dc both power-off rows passed on the T14
(`acpi_power_off`, `acpi_power_button_pressed`) and each judge still exited 1
on `boot.<label>.panel_us`/`panel_max_us: this boot recorded none`.

Whether a boot owes the census is now decided on its log's own last word:
`bootlog::asked_to_power_off`, the supervisor's stop line naming `Shutdown`,
the same string `boot_verdict` passes a recordless power-off on. A boot whose
stop asked for a reboot still owes it and is red without it.

`metal_power_off_owes_no_panel` plants both: green and `complete_ms` alone
for the power-off, red and no record for the reboot. With the judge change
reverted it reds (EXIT=101, `left: (true, None)`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
The exit: `acpi_power_off` and `acpi_power_button_pressed` pass on the T14,
each read off a boot of the same head. Both boots ran at 7c3a7dc (the
orchestrator's T14 runs, PR #713's comment 5980916904): `acpi_power_off` —
the machine stayed off until the owner powered it on; the press — the
server's `the power button was pressed, on SCI 7 of this boot` at 4.821 s and
the machine went off. Each judge then exited 1 only on the panel census a
power-off cannot leave; re-judged with the census fix at 619a7f0, each
exits 0 (`acpi_power_off EXIT=0`, `acpi_power_button_pressed EXIT=0`).

The no-hand power-off and the press both power off, so the stall at
b3b9ccd did not recur on either; its root cause stays unread. The
instrument the issue asked for stays at its site: `power::off` panics
naming the registers if the machine still runs two seconds after `SLP_EN`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Round 4 negative control of the judge fix, applied to 619a7f05c with git apply, run, and reversed in the same script; the tree was clean after it. cargo test --test toyos-checks -- metal_power_off_owes_no_panel EXIT=101, left: (true, None) against right: (false, Some(["boot.poweroff.complete_ms"])).

diff --git b/tests/common/metal.rs a/tests/common/metal.rs
index b2f660671..ea887072c 100644
--- b/tests/common/metal.rs
+++ a/tests/common/metal.rs
@@ -1053,10 +1053,8 @@ pub fn judge_readbacks(
         }
         let mut findings: Vec<String> = Vec::new();
         // The census crosses only on the page, and a page the pass after the
-        // reset cleared as another image's carries none; nor does a boot whose
-        // log ends asking for a power-off, which takes the page with it.
-        let owes_a_panel = bootlog::foreign_done(&back.loader).is_err()
-            && !bootlog::asked_to_power_off(&back.log);
+        // reset cleared as another image's carries none.
+        let owes_a_panel = bootlog::foreign_done(&back.loader).is_err();
         for (field, value, owed) in [
             ("complete_ms", back.boot_ms, true),
             ("panel_max_us", panel.map(|panel| panel.max_micros), owes_a_panel),

The attended testcases-press boot at ee6aade powered off correctly and the
driver refused it: nobody powered the T14 on within return_secs(), so it
wrote no readback. Its log, copied out of the stick's partition saved before
the next flash, shows the press reached acpiserver 17.552 s after EC query
0x28 was first taken; at b3b9ccd the gap was 10.009 s, at 7c3a7dc 17 ms.
0x28 is taken on the three attended press boots and on no unattended boot,
and no table of the T14 defines _Q28.

Built into a readback directory with toyos-fat32 and bootlog::split_listing,
the boot's logs judged by `--metal --metal-readback <dir>
acpi_power_button_pressed` exit 1 on the missing verdict.txt: back_secs,
stick_secs and the loop's verdict were never measured, and are not forged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 1 of #713 at fe36f86f9, against .claude/agents/reviewer.md, high-risk bar (devices, a security boundary, interrupts).

Net: git diff --shortstat origin/main...fe36f86f9: 77 files, +3333/−502. Production (everything outside tests/, src/, toyos-acpi/tests/, issues/) +2360/−428; tests and harness +768/−70; issues +205/−4. git merge-tree against origin/main (010a283a9, three landings ahead: #711, #724, #721) is clean.

BLOCKER

  • PR body, "T14 rows" — the unattended rows at ee6aadecb are listed only as "staged"; their results (acpi1-r4/metal/judge-acpi_server_death.log, judge-acpi_server_events.log, judge-acpi_table_inventory.log, judge-acpi_power_off.log, acpi1-r4/metal-counters/judge-counters.log, each PASS, "1 passed"/"3 passed") are in no body line and no comment — a hardware claim stands only on a measurement in the body: put each row's command, exit and log there.
  • tests/toyos.rs acpi_power_button_pressed — it has no verdict at any head that carries the merged kernel: at ee6aadecb the driver wrote no readback and the re-judge is EXIT=1 (acpi1-r6/judge-press.log); its last green is 7c3a7dc7d, before the merge of c4ab2b1e1 changed the kernel. It needs a fresh attended run before landing (answer below).
  • kernel/src/isa.rs:125, kernel/src/arch/x86_64/pio.rs, toyos-userbound/src/port.rs — the I/O permission bitmap now covers all 0x10000 ports, the rows are runtime, and claim_row's holder refusal replaces i8042::drives(). The T14 rows that exercise these, isa_ports_are_the_binders_alone and isa_lines_reach_their_holder (the isa-withheld boot), and the shared member isa_claim_refused, show no run at any head of this branch in the body. M3 was never run, and the body names that T14 member as its only oracle. Run all three at the landing head, and run M3 (patch in comment 5977460273) to show isa_claim_refused red on the T14.
  • PR body, "The attended press at b3b9ccd69: where it stopped" — it concludes that "the T14 did not act on that write within ~5 s, or something stalled there". The branch's own table (issues/the-t14s-power-button-event-trails-ec-query-0x28-by-up-to-17-s.md) puts query 0x28 at 6.696 s and the served press at 16.705 s on that boot, and the owner reported a second press that turned the machine off at once. The record fits a first press that raised 0x28 and no PWRBTN_STS, followed by a second press that was served and powered off. Neither reading is ruled out, so the body may not state the stall as the finding: correct it.
  • issues/the-t14s-power-button-event-trails-ec-query-0x28-by-up-to-17-s.md:33 — "whether the owner pressed once, is not in any record" is false: this PR's body records his second press at b3b9ccd69. The title and body also assert a lag, when the record fits a lost first press (2 of 3 press boots) just as well. Say both readings, cite the owner's account, and rename the slug if it no longer holds.
  • userland/acpiserver/src/aml.rs:8-39, userland/acpiserver/src/main.rs:110,191-202, userland/acpiserver/src/sci.rs:19,26,55 — dead in stage 1. runtime_gpes() returns an empty Vec, so Event::Runtime is never built outside a test, and gpe() is unreachable!. Trigger and Gpe exist only for that arm, and Disposition has one variant. Delete them: Served.runtime, Event::Runtime, aml::{gpe, Gpe, Trigger, runtime_gpes}, and Disposition (with query returning nothing). Every GPE but the EC's is then refused as Unserved::Gpe, and M8 retargets to "a GPE taken as the EC's". An interpreter that wants this shape writes it.
  • issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:9 — "nothing writes ACPI_ENABLE to SMI_CMD, and nothing handles an SCI" is false at this head, in a file this branch edits.
  • issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:85-93 — the "Ruled (owner, 2026-10-04, "Stopgap, delete later")" paragraph puts two designs of the branch's own under his ruling. The first is the control-method power-button refusal ("as a machine whose power button is a control method device does"). The second is "A machine its firmware hands over in ACPI mode is served whatever it has". His choice was the stopgap, with deletion when the interpreter reads the EC, and no-ECDT machines waiting. State those two sentences as the stage's design, outside the ruling.
  • issues/the-t14s-firmware-interrupts-every-cpu-every-2-2-s-under-toyos.md:36 — "ToyOS performs no ACPI enable handshake" is false at this head. Its owner is this stage, and counters at ee6aadecb read "SMI flat on each over 12218 ms" after the enable. Close it in this branch with that row as the evidence, or name what of its exit is unmet: it asks for the second read "at the stop's report", and the row reads at spin.

NOTE

  • userland/supervisor/src/main.rs:1843-1846 — ClaimError::Unusable reaches the supervisor as NotSupported, whose line sends the reader to "the kernel's pcidev: or partclaim: line". An acpi refusal is the acpi: line.
  • kernel/src/arch/x86_64/ioapic.rs:97,102 — Unit::read/write accept any &LockGuard<'_, ()>, not the guard of self.registers, so the parameter proves nothing about the pair being held. Tie it to the unit.
  • kernel/src/arch/x86_64/power.rs:77-92 with toyos-acpi/src/fadt.rs fixed_hardware — the PM1a control block is decoded twice, once from the 32-bit field alone and once with its X_ twin, and acpi_mode::init:90 reconciles the two with a filter. Keep one decoder.
  • kernel/src/arch/x86_64/pio.rs:114 — taken_back asserts a claimed stop, not "every userland thread has stopped" as its doc says. On a stop that fell short (stopped_the_machine() false, kernel/src/syscall/machine.rs), the holder may still run while quiet() rewrites its enables.
  • PR body, "Unsure" — it does not say what the T14's firmware did in legacy mode with the EC queries that now go unserved (0x4f, 0x28). The stage ruling rests on "nothing the firmware does in legacy mode today is lost".
  • issues/the-acpi-servers-holder-drives-the-embedded-controller-unfiltered.md — it does not say whether the command port reaches the controller's own firmware update. The owner's "Refuse external, record reflash" asks that such an escape be recorded.
  • kernel/src/arch/aarch64/acpi_mode.rs:13, kernel/src/arch/aarch64/pio.rs — fine. RMRR at hand-over, _OSI like Windows and refuse-external bear on nothing in this diff: no IOMMU change, no interpreter. "One power-off path" is a later stage, and the stage-1 exit names SYS_SHUTDOWN. The ECDT stopgap is recorded at the site (acpi_mode.rs:17-20) and matches the code.

REMOVE

  • kernel/src/arch/x86_64/acpi_mode.rs:47-48 — "The T14 answers in 2.13 ms (issues/…)": measurement provenance in source, and this branch's T14 logs read 13-17 µs.
  • tests/toyos.rs:3435-3436 — "Linux on the same machine read none in 120 s; in legacy mode the count rose alike on every CPU, about every 2.2 s."
  • userland/acpiserver/src/sci.rs:93 — "Fix 2 of the design's roast:".

Does acpi_power_button_pressed need a fresh attended T14 run at this head?

Yes, but not at fe36f86f9: run it at the head that lands, after this round's changes and a merge of main. #721 changes the loader's lines, which the judges read. Four reasons:

  1. No boot of the merged kernel has a verdict on this row: at ee6aadecb it is EXIT=1, unjudged.
  2. The run must decide whether the first press is lost, so it has to record the presses. The owner presses once, briefly, and waits at least 20 s before any second press. Whoever runs it writes the host time of each press into the run's log.
  3. The owner powers the T14 on within return_secs() (420 s) of it going off, or the driver writes no readback (issues/the-metal-driver-reads-a-machine-left-in-s5-as-one-that-did-not-come-back.md).
  4. The same holds for acpi_power_off, which also needs a hand.

A green row with one recorded press, with no 0x28 more than a second before the served press, makes the row good evidence. A first press that leaves only 0x28 is a defect in the press path, and the stage-1 exit's "a press of the power button stops the machine" is not met on the T14.

SEND BACK

@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

T14 results at ee6aadecb (orchestrator's runs; worktree clean at head; each image's sha256 checked against the request before its flash; all boots rc=0 unless said):

row boots (sha256) judge
acpi_server_death acpicase d0265fbe…9405 EXIT=0, 1 passed
acpi_table_inventory testcases 1543ad03…6b92 EXIT=0, 1 passed
acpi_server_events testcases-hold 78783e9d…1d81 EXIT=0, 1 passed
counters shared f9a8fef9…1bc3, shared-debug e5cda9fd…0f18, testcases aaee8d3b…57f7 EXIT=0, 3 passed
acpi_power_off (attended) testcases-off 452738d3…91ea EXIT=0, 1 passed
acpi_power_button_pressed (attended) testcases-press fb6d048e…4abe boot rc=1: the driver timed out at 420 s because the machine stayed off until the owner powered it on; no readback, judge EXIT=2. The stick's log partition was saved afterwards and is analysed in the round-5/6 comments.

Judge logs: orch/acpi1-r4/metal/judge-<row>.log, orch/acpi1-r4/metal-counters/judge-counters.log; run log orch/logs/t14-713r4-testcases-press.log — all in the orchestrator's job directory. This comment was owed earlier; the orchestrator held it back and should not have.

Japabu and others added 2 commits October 4, 2026 18:20
No conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
…ds corrected

acpiserver: stage 1 enables no GPE but the embedded controller's, so
`aml::{runtime_gpes, gpe, Gpe, Trigger, Disposition}`, `Served.runtime` and
`Event::Runtime` go; every other GPE is refused as `Unserved::Gpe`, and
`aml::query` returns nothing. The armed line loses its "0 GPE(s) the
namespace runs".

toyos-acpi: `pm1a_control` is the one decoder of the PM1a control block,
`X_`-aware, which both `power::init_off` and `fixed_hardware`'s caller use;
`FixedHardware` loses its copy, and `acpi_mode::init` no longer reconciles
two decodes with a filter.

ioapic: a unit's register pair is a `Window` inside its `Masked` lock, so a
read or write is reachable only through that unit's guard.

pio/quiesce: `taken_back` answers only after a stop that stopped every
userland thread but its caller (`quiesce::userland_stopped`); after one that
fell short the power-off's quiet panics by name rather than racing a holder
that may still run, and the S5 panic's PM1 reading says it is unread.

supervisor: a `NotSupported` claim names the `isa:` and `acpi:` lines too.

Issues: the track's false first sentence goes, and the "Stopgap" ruling
carries only what the owner ruled, the stage's two design lines beside it;
the firmware-interrupt issue loses its false "no ACPI enable handshake" line
and records the `counters` row's ACPI-mode reading at `ee6aadecb` and what of
its exit stays unmet (the second read is at `spin`); the press issue is
renamed from a lag to what the record shows, with both readings and the
owner's account; the EC issue records that the command port takes the
maker's commands too, firmware update not ruled out.

REMOVE: the T14's handover time in `acpi_mode.rs`, Linux's SMI reading in
the counters row's doc, "Fix 2 of the design's roast" in `sci.rs`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Round 7 mutation patches at 5d0278a60, each applied with git apply, run or staged, and reversed in the same script; git status --porcelain --ignore-submodules=none empty after each.

M8 (retargeted): another GPE taken as the EC's — cargo test --manifest-path userland/acpiserver/Cargo.toml --target <host> EXIT=101, an_enabled_event_outside_the_served_set_is_refused_by_name FAILED.

diff --git a/userland/acpiserver/src/sci.rs b/userland/acpiserver/src/sci.rs
index 675c796a6..8a8b22e23 100644
--- a/userland/acpiserver/src/sci.rs
+++ b/userland/acpiserver/src/sci.rs
@@ -48,7 +48,7 @@ pub fn events(served: &Served, pm1: (u16, u16), gpe0: &[(u8, u8)]) -> Result<Vec
         for bit in (0..8).filter(|bit| fired & 1 << bit != 0) {
             let n = (byte * 8 + bit) as u16;
             events.push(match n {
-                n if served.ec_gpe == Some(n) => Event::Ec,
+                _ if served.ec_gpe.is_some() => Event::Ec,
                 n => return Err(Unserved::Gpe(n)),
             });
         }

M7 (retargeted to the shared address decoder): an X_ disagreement unrefused — cargo test --manifest-path toyos-acpi/Cargo.toml --test corpus EXIT=101, fixed_hardware_this_kernel_does_not_serve_is_refused_by_name FAILED (corpus.rs:733, the PM1a control block's Disagrees).

diff --git a/toyos-acpi/src/fadt.rs b/toyos-acpi/src/fadt.rs
--- a/toyos-acpi/src/fadt.rs
+++ b/toyos-acpi/src/fadt.rs
@@ -276,9 +276,6 @@ fn address<P: Phys>(fadt: &Table<P>, field: Field, legacy_at: usize, x_at: usize
     if space != SPACE_SYSTEM_IO {
         return Err(FixedRefused::NotSystemIo { field, space });
     }
-    if legacy != 0 && u64::from(legacy) != extended {
-        return Err(FixedRefused::Disagrees { field, legacy, extended });
-    }
     Ok(extended)
 }
 

M3: claim_row skips the holder check — the T14 arm, staged only: cargo test --test toyos-build -- --metal --metal-readback orch/acpi1-r7/metal-m3 isa_claim_refused EXIT=2 (staged, machine untouched), image shared sha256 94cf5dcd321c796bce1edf334b4e7ebda79ccb7d8d588dccdbff411824d17ea6. The image carries the mutation: 's ports occurs twice in it against three in the clean metal-isa/shared image (the refusal's log line compiled out). Expected: isa_claim_refused red on the T14.

diff --git a/kernel/src/isa.rs b/kernel/src/isa.rs
--- a/kernel/src/isa.rs
+++ b/kernel/src/isa.rs
@@ -124,7 +124,7 @@ pub fn claim(set: IsaId) -> Result<usize, ClaimError> {
 /// left masked for the holder's first acknowledgement.
 pub fn claim_row(row: usize) -> Result<usize, ClaimError> {
     let function = function(row).ok_or(ClaimError::Absent)?;
-    if let Some((run, holder)) = function.runs.iter().find_map(|&run| pio::holder(run).map(|h| (run, h))) {
+    if let Some((run, holder)) = function.runs.iter().find_map(|&run| pio::holder(run).map(|h| (run, h))).filter(|_| false) {
         log!("isa: {}'s ports {:#x}+{} are {holder}'s", function.name, run.first(), run.count());
         return Err(ClaimError::KernelDriven);
     }

@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

T14 results at 5d0278a60, unattended rows (orchestrator's run; worktree clean at head; each image's sha256 checked against images.sha256 before its flash; all nine boots rc=0):

row(s) boots judge
isa_ (isa_ports_are_the_binders_alone, isa_lines_reach_their_holder, isa_claim_refused) isa-withheld 1c94d48a…5851, shared e6a3af04…cb79 EXIT=0, 3 passed
acpi_server_ acpicase b885d938…f2cd, testcases-hold 7ea430cd…8834 EXIT=0, 2 passed
acpi_table_inventory testcases 21abae72…4fc4 EXIT=0, 1 passed
counters shared c5bd53bb…f46f, shared-debug fb9d93d9…d051, testcases 8ea26fa7…99ed EXIT=0, 3 passed
M3 arm (m3-claim-skips-holder.patch), expected RED shared 94cf5dcd…7ea6 isa_claim_refused: EXIT=1, FAIL test_rs_isa_claim_refused: … exited 101 on the T14

Note on M3: judging its directory with the isa_ filter exits 2 (the filter also wants isa-withheld, which the M3 request did not stage) and that judging run restaged the clean head's images over metal-m3/ (the readback files survived; the image no longer is M3's). The row filter isa_claim_refused judges the M3 readback alone: red as intended.

The two attended rows (acpi_power_off, acpi_power_button_pressed) are not run yet. Judge logs: orch/acpi1-r7/<dir>/judge-*.log, M3's orch/acpi1-r7/metal-m3/judge2-isa_claim_refused.log, in the orchestrator's job directory.

@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 2 of #713 at 5d0278a60, against .claude/agents/reviewer.md, at the high-risk bar.

Net: git diff --shortstat origin/main...5d0278a60 is 79 files, +3337/−525. Round 7 alone (43f99ee95..5d0278a60) is +196/−215. git merge-tree --write-tree origin/main 5d0278a60 exits 0 with no conflicts against 2328e4488 (#727, #717, #730, three landings ahead). The files both sides touch are cpu.rs, system.toml, tests/toyos.rs, toyos-abi/src/{lib,syscall}.rs and userland/Cargo.{toml,lock}. In the merged tree, Acpi = 10 is still the only class 10. acpiserver has the description that #727 requires. The in/out wrappers in cpu.rs name their registers, as #730 requires. Merge 43f99ee95 has no hand resolution (git show --cc is empty).

Round-1 BLOCKERs

  • Body: no unattended row results. CLOSED: the body's "Results at ee6aadecb" table names each row's command, exit and log. The same defect is back at this head; see the first new BLOCKER.
  • acpi_power_button_pressed: no verdict at a merged head. OPEN: no attended run since ee6aadecb.
  • isa_ rows and M3 on the T14. CLOSED: orchestrator comment 5982813833 has isa_ EXIT=0, "3 passed" on isa-withheld and shared. M3's arm (shared, 94cf5dcd…7ea6) has isa_claim_refused EXIT=1 (acpi1-r7/metal-m3/judge2-isa_claim_refused.log). Its kernel log shows the right red: a claim on the i8042 answered Ok(()), not PermissionDenied, with GSI 1 and 12 routed to the claimant.
  • Body: the stall stated as the finding. CLOSED: "Two readings fit, and neither is ruled out".
  • Press issue: the false "whether the owner pressed once", and a lag asserted. CLOSED: renamed issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md. It states both readings with the owner's account, owner stage 1, and an exit a row reads. No citation of the old slug is left in the merged tree.
  • acpiserver: dead runtime-GPE paths. CLOSED: Trigger, Gpe, Disposition, runtime_gpes, gpe, Served.runtime and Event::Runtime are gone. Retargeted M8 is EXIT=101 (acpi1-r7/m8.log), and --ci host runs that test (host.log, userland/acpiserver).
  • Track :9, a false first sentence. CLOSED.
  • Track: two branch designs put under the owner's ruling. CLOSED: the ruling now carries only the ECDT stopgap and the no-ECDT machines. The other two are stated as "Stage 1's design, not a ruling".
  • Firmware-interrupt issue: false "no ACPI enable handshake". CLOSED: the line is gone, the counters reading at ee6aadecb is recorded, and "the row's second read is at spin, not at the stop's report" names what is unmet. It stays open.

Round-1 NOTEs and REMOVEs: the supervisor line, Window, the single PM1a decoder, the EC queries in "Unsure", the reflash paragraph and the three REMOVEs are all done. taken_back is answered by a change that is itself a BLOCKER (below).

BLOCKER

  • kernel/src/arch/x86_64/acpi_mode.rs:282-284 with kernel/src/quiesce.rs:180,187: quiet() now panics whenever quiesce::userland_stopped() is false. That is any stop that ended with a userland thread still running, not only a stop that left the ACPI holder running. quiesce::PARK's own doc says such a thread can outlast the budget without any kernel bug: one block::OPERATION inside the block layer, and "its expiry is a clause in the record". quiesce() in syscall/machine.rs says "the reset lands anyway".

    • quiet() runs whenever SCI_EN is set and the row exists (hardware() is filled at boot). The row has no holder in either of these cases:
      • on q35, whose firmware hands over in ACPI mode, on every image;
      • on any image without acpiserver.
    • So at this head, a userland program that keeps a thread in the block layer past PARK turns SYS_SHUTDOWN into a kernel panic. Before round 7 it was a power-off. That breaks "the kernel never crashes from userland", on a path where no holder may exist at all.
    • The hazard round 1 named is only the holder's writes. Make the condition that, and make it unable to fail on userland's timing. One way: take the row's ports out of the holder's I/O permission before quiet writes. Another: answer from whether the row is held at all.
    • Add a test that reds on the panic: a short stop followed by a power-off, at the cheapest tier that reaches it. The body says no guest or T14 boot stages one. Then a reader is the only check on a path that ends the machine, and a defect here lands unseen.
  • PR body, "Negative control and mutations" and "T14 rows": at 5d0278a60 the body still says M3 is "Not yet run" and lists every unattended row as "Staged". The results at this head exist only in comment 5982813833. A hardware claim stands only on a measurement in the body. For each row at 5d0278a60 (isa_, acpi_server_, acpi_table_inventory, counters, and the M3 arm), put its command, exit and judge log there, and remove "Not yet run".

  • acpi1-r7/owner-acpi_power_off/ and acpi1-r7/owner-acpi_power_button_pressed/ (RUN-INSTRUCTIONS.txt, request.txt, images.sha256): both attended rows are staged at 5d0278a60. The head that lands differs from it in two ways:

    Staged as they are, the owner's runs would be evidence for a head that does not land. Restage both images at the landing head and rewrite the instructions' first lines to name that head. Round-1 BLOCKER 2 stays open until both rows' commands, exits and logs at that head are in the body.

NOTE

  • owner-acpi_power_button_pressed/RUN-INSTRUCTIONS.txt step 2: "between about 2 s and 30 s after boot" gives the presser no event to count from. The first attempt at 7c3a7dc7d went red for that reason: the press came after the window, with no on-screen cue. Name what the owner watches for, such as the driver line or panel line that starts the count, and press on it.
  • owner-acpi_power_button_pressed/RUN-INSTRUCTIONS.txt step 4: the press's host time is recorded, but the boot's log times count from boot. Nothing in the instructions ties one to the other, so a recorded host time cannot be set against 0x28's 6.696 s-style stamp. Have the runner also note the host time of a named driver line whose boot time the log carries. Otherwise only the press count decides the reading.
  • toyos-acpi/src/fadt.rs:561-562: pm1a_control refuses a block that neither field names as Length { len }, carrying a length that is not wrong. init_off now logs that where main logged "FADT has no PM1a control block". Refuse absence by its own name.

REMOVE

None.

SEND BACK

Japabu and others added 2 commits October 4, 2026 20:34
…'s record says

Review round 2 at 5d0278a, BLOCKER 1: `acpi_mode::quiet` panicked
whenever the stop ended with any userland thread still running, which
`quiesce::PARK` says a thread in the block layer can do with no kernel bug.
On q35 (handed over in ACPI mode, no holder needed) and on any image with
acpiserver, a userland program could so turn SYS_SHUTDOWN into a kernel
panic.

The hazard is only the holder writing the row's ports after `quiet`. A thread
writes a port only from Ring 3, and once the stop's stage is open every return
to Ring 3 passes `leave_user_if_due`, which stops every thread but the
caller. So `pio::take_back` issues a TLB shootdown (`Origin::Stop`), which
returns only once every other CPU has answered from Ring 0: after it no thread
but the caller can be in Ring 3. The condition no longer reads the record, and
`quiesce::STOPPED`/`userland_stopped` go. `quiesce::stop` returns a
`Stopping` witness beside the record, threaded through `power::shutdown` to
`arch::power::off`, so the row can be taken back only after a stop.

`quiesce::stop` arms its progress watch before the stage opens rather than
after: nothing between the opening and the first sweep is then a point where a
pass can take the caller's CPU, which is what makes the new test exact.

`machine_shutdown_short_stop` (guest, q35, one CPU, actuator
`stop-budget-spent`): `test_rs_stop_short` asks for the power-off with a
thread spinning, the stop's one sweep finds it queued behind the caller, the
record says threads were left running, and QEMU must still stop for
`guest-shutdown`.

Review NOTE 3: `toyos_acpi` refuses a PM1a event or control block neither
field names as `FixedRefused::Absent`, not as a `Length` carrying a length that
is not wrong.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
@Japabu

Japabu commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

Round 8 patches at 3e73ab0ae, each applied with git apply --check then git apply, run, and reverted with git apply -R in the same script, the tree clean after (git status --porcelain --ignore-submodules=none empty).

Negative control — the whole fix reverted onto 3e73ab0ae (the eight product files back to the merge 2746aef8), keeping only the test, its binary and the stop-budget-spent budget in quiesce::stop. cargo test -- machine_shutdown_short_stop: EXIT=1, QEMU had not exited 25 s after it was asked to; the guest console (captured by a second run of the same patch plus one line in the test that writes the console out) carries stop: 14 of 17 userland thread(s) stopped across 1 cpu(s) in 0 ms of a 0 ms budget over 1 sweep(s) and then PANIC: panicked at src/arch/x86_64/acpi_mode.rs:283:9: power: the stop left userland running, so the events its ACPI holder enabled cannot be quieted for S5.

diff --git a/kernel/src/arch/aarch64/power.rs b/kernel/src/arch/aarch64/power.rs
index 477042084..91144dcae 100644
--- a/kernel/src/arch/aarch64/power.rs
+++ b/kernel/src/arch/aarch64/power.rs
@@ -40,7 +40,7 @@ pub fn reset() -> ! {
 /// known state first, and this is DEN0022 §5.10.3's own way to. The budget
 /// for all of them is [`DEAF_CPU`]'s span from the SGI: a CPU PSCI still
 /// answers on at its end is named, and the machine powers off regardless.
-pub fn off(_stopping: crate::quiesce::Stopping) -> ! {
+pub fn off() -> ! {
     cpu::disable_interrupts();
     let Some(psci) = psci::conduit() else { cpu::halt() };
     irqchip::off_all_but_self();
diff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index f266b0aad..d7d9ad3a4 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -33,7 +33,7 @@ use toyos_acpi::{Ec, FixedHardware, PowerButton};
 use toyos_userbound::Ports;
 
 use super::cpu;
-use super::pio::{self, Declared, TakenBack};
+use super::pio::{self, Declared};
 use super::power::SCI_EN;
 use crate::device::ClaimError;
 use crate::isa::{self, Function};
@@ -265,21 +265,25 @@ fn leave(hardware: &Hardware) {
 const PM1_STATUS: u16 = 1 << 0 | 1 << 4 | 1 << 5 | 1 << 8 | 1 << 9 | 1 << 10 | 1 << 14 | 1 << 15;
 
 /// What the PM1 event block reads, status then enable, for a power-off that
-/// did not take.
-pub fn pm1_events(taken: &TakenBack) -> String {
+/// did not take; once userland has stopped, as [`quiet`] is.
+pub fn pm1_events() -> String {
     let Some(hardware) = hardware() else { return "no ACPI row, so no PM1 event block read".into() };
-    let events = taken.run(run(hardware.fixed.pm1a_event));
+    let Some(events) = pio::taken_back(run(hardware.fixed.pm1a_event)) else {
+        return "the PM1 event block unread: the stop left userland running".into();
+    };
     let half = hardware.fixed.pm1a_event.len / 2;
     format!("PM1 status {:#06x} under enable {:#06x}", cpu::inw(events.port(0)), cpu::inw(events.port(half)))
 }
 
 /// Every fixed and general-purpose event disabled and its status cleared:
-/// the power-off's, on a machine in ACPI mode.
-pub fn quiet(taken: &TakenBack) {
+/// the power-off's, on a machine in ACPI mode, once userland has stopped.
+pub fn quiet() {
     let Some(hardware) = hardware() else { return };
-    let events = taken.run(run(hardware.fixed.pm1a_event));
+    let Some(events) = pio::taken_back(run(hardware.fixed.pm1a_event)) else {
+        panic!("power: the stop left userland running, so the events its ACPI holder enabled cannot be quieted for S5");
+    };
     let half = hardware.fixed.pm1a_event.len / 2;
-    // SAFETY: the PM1a event block the FADT names, taken back from any holder.
+    // SAFETY: the PM1a event block the FADT names, taken back from a holder that no longer runs.
     unsafe {
         cpu::outw(events.port(half), 0);
         cpu::outw(events.port(0), PM1_STATUS);
@@ -287,7 +291,7 @@ pub fn quiet(taken: &TakenBack) {
     if hardware.fixed.gpe0.len == 0 {
         return;
     }
-    let gpe = taken.run(run(hardware.fixed.gpe0));
+    let gpe = pio::taken_back(run(hardware.fixed.gpe0)).expect("the PM1 block was taken back after the same stop");
     let half = hardware.fixed.gpe0.len / 2;
     for byte in 0..half {
         // SAFETY: the GPE0 block, taken back as the PM1 block is; its status bits clear on a one.
diff --git a/kernel/src/arch/x86_64/pio.rs b/kernel/src/arch/x86_64/pio.rs
index f2f32fb3c..02b4fdcc1 100644
--- a/kernel/src/arch/x86_64/pio.rs
+++ b/kernel/src/arch/x86_64/pio.rs
@@ -109,23 +109,12 @@ pub fn holder(ports: Ports) -> Option<&'static str> {
     FIXED.iter().find(|(_, fixed)| fixed.0.overlaps(ports)).map(|&(name, _)| name).or_else(|| RUNTIME.lock().holder(ports))
 }
 
-/// Every row's ports, the kernel's again: the power-off's, and nobody else's.
-pub struct TakenBack(());
-
-/// Take every row's ports back from whoever holds them, whatever the stop's
-/// record says. Once `stopping` exists a thread enters Ring 3 only past
-/// `scheduler::leave_user_if_due`, which stops all but the stop's caller; the
-/// shootdown returns only once every other CPU has answered it from Ring 0,
-/// so no thread that was in Ring 3 before is there still.
-pub fn take_back(_stopping: &crate::quiesce::Stopping) -> TakenBack {
-    super::tlb::shootdown(crate::invalidation::Origin::Stop);
-    TakenBack(())
-}
-
-impl TakenBack {
-    pub fn run(&self, ports: Ports) -> Declared {
-        Declared(ports)
-    }
+/// A run some row grants, taken back by the kernel once this boot's stop has
+/// stopped every userland thread but its caller, which never returns to Ring
+/// 3: the power-off's, and nobody else's. `None` after a stop that fell short,
+/// whose holder may still run.
+pub fn taken_back(ports: Ports) -> Option<Declared> {
+    crate::quiesce::userland_stopped().then_some(Declared(ports))
 }
 
 /// A [`Declared`] kept where a later reader finds it; empty until set.
diff --git a/kernel/src/arch/x86_64/power.rs b/kernel/src/arch/x86_64/power.rs
index 573164ea1..51b85b60f 100644
--- a/kernel/src/arch/x86_64/power.rs
+++ b/kernel/src/arch/x86_64/power.rs
@@ -166,13 +166,12 @@ const S5_TAKES: Tripwire = Tripwire::absurd(
 /// the panel shows it, and the black box carries it through the panic's reset,
 /// where a halt would leave a machine that is on, silent, and indistinguishable
 /// from one the power left.
-pub fn off(stopping: crate::quiesce::Stopping) -> ! {
+pub fn off() -> ! {
     let (Some(control), true) = (PM1A_CNT.get(), SOFT_OFF.load(Ordering::Acquire)) else { cpu::halt() };
     let control = control.port(0);
-    let taken = pio::take_back(&stopping);
     let held = cpu::inw(control);
     if held & SCI_EN != 0 {
-        super::acpi_mode::quiet(&taken);
+        super::acpi_mode::quiet();
     }
     let typed = held & !(SLP_TYP | SLP_EN) | u16::from(SLP_TYPA.load(Ordering::Relaxed)) << 10;
     let smis_before = super::counters::read().smi;
@@ -191,7 +190,7 @@ pub fn off(stopping: crate::quiesce::Stopping) -> ! {
          the write of {:#06x} and reads {now:#06x} now, SCI_EN {}; {}; cpu{}'s SMI count {} before the write and {} now",
         typed | SLP_EN,
         if now & SCI_EN == 0 { "clear" } else { "set" },
-        super::acpi_mode::pm1_events(&taken),
+        super::acpi_mode::pm1_events(),
         super::percpu::cpu_id(),
         smis_before.map_or_else(|| "unread".into(), |n| alloc::format!("{n}")),
         super::counters::read().smi.map_or_else(|| "unread".into(), |n| alloc::format!("{n}")),
diff --git a/kernel/src/invalidation.rs b/kernel/src/invalidation.rs
index bf6511946..e12d820a5 100644
--- a/kernel/src/invalidation.rs
+++ b/kernel/src/invalidation.rs
@@ -5,8 +5,7 @@
 /// `Shared` window or rollback unmap), `Pcid` (pool reclaim), `Mmio`, `Unmap`
 /// (`Unmapped::drop`), `Pipe`, `Staged` (the ack-delay actuator), `Bench`
 /// (`arch::tlb::bench`'s own, so a measured shootdown is never counted as one
-/// a path in this kernel needed), `Stop` (the power-off's, for the answer from
-/// Ring 0 every other CPU owes it, not for a flush).
+/// a path in this kernel needed).
 #[derive(Clone, Copy)]
 #[repr(usize)]
 pub enum Origin {
@@ -19,14 +18,11 @@ pub enum Origin {
     Staged,
     #[cfg_attr(not(feature = "boot-actuators"), allow(dead_code))]
     Bench,
-    // Ports are x86-64's alone, so AArch64 builds a variant it never issues.
-    #[allow(dead_code)]
-    Stop,
 }
 
 impl Origin {
-    pub const COUNT: usize = 8;
+    pub const COUNT: usize = 7;
     /// Order matches the variants; `tests/toyos.rs`'s `irq_census_conservation` reads the line back.
     pub const NAMES: [&'static str; Self::COUNT] =
-        ["dlopen", "pcid", "mmio", "unmap", "pipe", "staged", "bench", "stop"];
+        ["dlopen", "pcid", "mmio", "unmap", "pipe", "staged", "bench"];
 }
diff --git a/kernel/src/power.rs b/kernel/src/power.rs
index cfca578ed..0b39a9d64 100644
--- a/kernel/src/power.rs
+++ b/kernel/src/power.rs
@@ -48,12 +48,12 @@ pub fn reset_now() -> ! {
 }
 
 /// Power the machine off, or halt on one that offers no power-off.
-pub fn shutdown(stopping: crate::quiesce::Stopping) -> ! {
+pub fn shutdown() -> ! {
     // Last chance: nothing drains the log ring after this point.
     serial::flush_final();
     // A power-off takes VBUS with it on a machine whose ports are not
     // always-on and takes nothing on one whose are, so the devices are handed
     // back here for the same reason as at a reboot.
     stop::before_reset();
-    crate::arch::power::off(stopping)
+    crate::arch::power::off()
 }
diff --git a/kernel/src/quiesce.rs b/kernel/src/quiesce.rs
index 4f79aa36b..fa43c5260 100644
--- a/kernel/src/quiesce.rs
+++ b/kernel/src/quiesce.rs
@@ -36,7 +36,7 @@
 //!
 //! Lock order: [`process::PROCESS_TABLE`] alone.
 
-use core::sync::atomic::{AtomicBool, AtomicU32, Ordering::AcqRel, Ordering::Relaxed};
+use core::sync::atomic::{AtomicBool, AtomicU32, Ordering::AcqRel, Ordering::Acquire, Ordering::Relaxed, Ordering::Release};
 
 use toyos_quiesce::{must_stop, Record, Sweep, ThreadId};
 use kernel::sched::task::WaitClass;
@@ -123,10 +123,6 @@ pub fn note_progress() {
     }
 }
 
-/// This boot's stop has begun: from here every thread but its caller that
-/// returns to Ring 3 is stopped at that boundary, whatever the [`Record`] says.
-pub struct Stopping(());
-
 /// Stop every userland thread but the caller, and answer with what it took.
 ///
 /// Returns when the machine is stopped or when [`PARK`] is spent, never
@@ -134,25 +130,23 @@ pub struct Stopping(());
 /// it lands, because a machine nobody can turn off is worse than one whose
 /// last word overlapped somebody's syscall.
 #[must_use]
-pub fn stop() -> (Record, Stopping) {
+pub fn stop() -> Record {
     // Refused by name rather than defaulted: a caller with no task identity is
     // not a reboot syscall.
     let caller = ThreadId {
         pid: percpu::current_pid().expect("quiesce::stop: the caller holds no process").raw(),
         tid: percpu::current_tid().expect("quiesce::stop: the caller holds no thread").raw(),
     };
-    // Armed before the first sweep, so a transition landing between a sweep
-    // and the park after it leaves a record that park returns on at once; and
-    // before the stage opens, so nothing between the opening and the first
-    // sweep is a point where a pass can take this CPU.
-    let parkable = crate::scheduler::Parkable::at_entry();
-    let armed = watch::arm(&PROGRESS, 0, WaitClass::Other)
-        .expect("quiesce::stop: the caller holds no task to park");
     CALLER_PID.store(caller.pid, Relaxed);
     CALLER_TID.store(caller.tid, Relaxed);
     // Last: a gate that sees the stop sees the caller it must not stop.
     STAGE.open(STOPPING);
 
+    // Armed before the first sweep, so a transition landing between a sweep
+    // and the park after it leaves a record that park returns on at once.
+    let parkable = crate::scheduler::Parkable::at_entry();
+    let armed = watch::arm(&PROGRESS, 0, WaitClass::Other)
+        .expect("quiesce::stop: the caller holds no task to park");
     crate::arch::irqchip::kick_all_but_self();
     let cpus = crate::smp::cpu_count();
 
@@ -175,21 +169,28 @@ pub fn stop() -> (Record, Stopping) {
         // moment the stop ended, and every line between here and the record's
         // own would open more.
         let (in_flight, begun) = crate::block::userland_operations();
-        return (
-            Record {
-                sweep: swept,
-                elapsed_ms: elapsed / 1_000_000,
-                budget_ms: budget.nanos() / 1_000_000,
-                sweeps,
-                cpus,
-                in_flight,
-                begun,
-            },
-            Stopping(()),
-        );
+        let record = Record {
+            sweep: swept,
+            elapsed_ms: elapsed / 1_000_000,
+            budget_ms: budget.nanos() / 1_000_000,
+            sweeps,
+            cpus,
+            in_flight,
+            begun,
+        };
+        STOPPED.store(record.stopped_the_machine(), Release);
+        return record;
     }
 }
 
+/// Whether this boot's stop ended with every userland thread but its caller
+/// stopped.
+pub fn userland_stopped() -> bool {
+    STOPPED.load(Acquire)
+}
+
+static STOPPED: AtomicBool = AtomicBool::new(false);
+
 /// Mark every parked thread but the caller and count the rest.
 ///
 /// The table lock is held for the walk and given up before the park: a thread
diff --git a/kernel/src/syscall/machine.rs b/kernel/src/syscall/machine.rs
index c9ee138b0..ccb143d81 100644
--- a/kernel/src/syscall/machine.rs
+++ b/kernel/src/syscall/machine.rs
@@ -66,7 +66,7 @@ fn read_on_cursor<C: crate::user_ptr::UserSafe>(
     }
 }
 
-fn quiesce(last: &str) -> Result<crate::quiesce::Stopping, SyscallError> {
+fn quiesce(last: &str) -> Result<(), SyscallError> {
     // Refused by name, and first: nothing below runs twice.
     if !crate::quiesce::claim_the_shutdown() {
         log!("power: this machine is already stopping, so this caller stops with the rest");
@@ -90,7 +90,7 @@ fn quiesce(last: &str) -> Result<crate::quiesce::Stopping, SyscallError> {
     crate::arch::watchdog::disarm();
     // Every userland thread stops here, the log's writer with the rest:
     // `/system/bin/supervisor` had it flush before it asked for this stop.
-    let (stopped, stopping) = crate::quiesce::stop();
+    let stopped = crate::quiesce::stop();
     crate::log::console::drain_for_the_stop();
     // The final census: no process runs after this to report another.
     crate::irq_census::log_census();
@@ -130,7 +130,7 @@ fn quiesce(last: &str) -> Result<crate::quiesce::Stopping, SyscallError> {
     // `power::reboot`/`power::shutdown` do — which every reset this kernel
     // performs goes through. It is bounded, and the reset follows either way.
     crate::drivers::xhci::seal_shut();
-    Ok(stopping)
+    Ok(())
 }
 
 /// Powers the machine off; requires a `SysCap` carrying [`Rights::POWER`]. Returns only when refused.
@@ -138,10 +138,10 @@ pub(super) fn sys_shutdown(syscap: RawHandle) -> u64 {
     if let Err(e) = demand_syscap(syscap, Rights::POWER) {
         return e.refuse();
     }
-    match quiesce("Shutting down.") {
-        Ok(stopping) => power::shutdown(stopping),
-        Err(e) => e.to_u64(),
+    if let Err(e) = quiesce("Shutting down.") {
+        return e.to_u64();
     }
+    power::shutdown();
 }
 
 /// Returns the machine to firmware; requires a `SysCap` carrying [`Rights::POWER`]. Returns only when refused.

M10 — take_back issues no shootdown. cargo test -- machine_shutdown: EXIT=0, both green (see the body for why no test reaches it).

--- a/kernel/src/arch/x86_64/pio.rs
+++ b/kernel/src/arch/x86_64/pio.rs
@@ -119,5 +119,4 @@
 /// so no thread that was in Ring 3 before is there still.
 pub fn take_back(_stopping: &crate::quiesce::Stopping) -> TakenBack {
-    super::tlb::shootdown(crate::invalidation::Origin::Stop);
     TakenBack(())
 }

@Japabu
Japabu marked this pull request as draft October 5, 2026 00:47
@Japabu

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Round 13 mutation at 8d7004d3b: mut-old-head-fixture.patch, the power-off fixture put back in the pre-#737 head. cargo test --lib a_power_off_is_the_supervisors EXIT=101, panicked at src/bootlog.rs:556:9; the tree was restored clean (log: orch/acpi1-r13/mut-old-head-fixture.log).

diff --git a/src/bootlog.rs b/src/bootlog.rs
index 5fd2d9e28..7d0fea692 100644
--- a/src/bootlog.rs
+++ b/src/bootlog.rs
@@ -551,8 +551,8 @@ mod tests {
     /// Only the supervisor's own stop line, naming a shutdown, is a power-off.
     #[test]
     fn a_power_off_is_the_supervisors_stop_naming_a_shutdown() {
-        let booted = "[ 1.151 cpu0 kernel] Boot: complete (1151ms)\n";
-        let stop = |how: &str| format!("{booted}[16.705 supervisor] {STOPPING} ({how})\n");
+        let booted = "[kernel 1.151 cpu0] Boot: complete (1151ms)\n";
+        let stop = |how: &str| format!("{booted}{{16.705 supervisor}} {STOPPING} ({how})\n");
         assert!(asked_to_power_off(&stop("Shutdown")));
         assert!(!asked_to_power_off(&stop("Reboot")));
         assert!(!asked_to_power_off(booted));

@Japabu

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

T14 results at 8d7004d3b, unattended rows (orchestrator's run; worktree clean at head; each image's sha256 checked against images.sha256 before its flash; all eight boots rc=0):

metal-isa isa_ EXIT=0 [metal] 3 passed, 0 failed, 2 boot(s)
metal-acpi_server acpi_server_ EXIT=0 [metal] 2 passed, 0 failed, 2 boot(s)
metal-acpi_table_inventory acpi_table_inventory EXIT=0 [metal] 1 passed, 0 failed, 1 boot(s)
metal-counters counters EXIT=0 [metal] 3 passed, 0 failed, 3 boot(s)
done

The two attended rows follow with the owner. Judge logs: orch/acpi1-r13/metal-*/judge-*.log in the orchestrator's job directory.

@Japabu

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Attended T14 results at 8d7004d3b (orchestrator's runs with the owner; worktree clean at head; each image's sha256 checked against images.sha256 before its flash):

row boot judge
acpi_power_off testcases-off fe9002a0…e582, rc=0 EXIT=0, 1 passed
acpi_power_button_pressed testcases-press 65e17dac…c880, rc=0 EXIT=0, 1 passed

The press, in #737's line shape (stamps from the counter's zero):

[30.550 acpiserver] acpiserver: embedded controller query 0x28 taken for the first time, served by nothing: stage 1 runs no AML
[30.566 acpiserver] acpiserver: the power button was pressed, on SCI 17 of this boot; asking the supervisor to power off
[30.567 supervisor] supervisor: power: the machine stops, and logkeeper makes the log whole first (Shutdown)

One press; 0x28 to the power-button event 16 ms, as at ff4945d6d. Judge logs: orch/acpi1-r13/metal-acpi_power_*/judge-*.log in the orchestrator's job directory.

@Japabu

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 7 of #713 at 8d7004d3b, against .claude/agents/reviewer.md on origin/main (f260e0b98). Scope: the merge 8d7004d3b (#737) alone. Net origin/main...8d7004d3b: 86 files, +3591/−585; the merge adds +8 in tests and harness and nothing in production.

Merge with origin/main

origin/main is f260e0b98, the merge's second parent, so it is an ancestor of head. git merge-tree --write-tree origin/main 8d7004d3b exits 0 (0875a7e78…), and GitHub reports MERGEABLE.

Earlier findings

Round 6 had no BLOCKER. Its one NOTE was about the body's prose, and it is superseded (see below).

The resolution, read by git show --remerge-diff 8d7004d3b

  • src/bootlog.rs: asked_to_power_off reads the stop line through stopping_line (main's, tag supervisor via program_line) and then compares said.text.strip_prefix(STOPPING) == Some(" (Shutdown)") exactly. Main's LOADER_CLOCK_*, LOGKEEPER_* and one_clock are kept whole. The fixtures are in the one head, so the forged test-runner line is still refused by tag. Mutation comment 5986276592 shows an old-head fixture red, EXIT=101 at src/bootlog.rs:556.
  • src/metal.rs and tests/checks/metal.rs: the fixtures are in the one head, with the seconds right-aligned as Head writes them (BOOTED is main's). Both registrations are in tests/checks.rs.
  • counters_metal.rs: acpi_said reads program lines through program_line by tag, and the kernel's first-interrupt line through parse with Source::Kernel and exact text. The record_ms plus "] isa: …" suffix reader is gone. Both imports are kept.
  • tests/toyos.rs acpi_events_on_metal: it picks the server's lines by program_line's tag, not by the bare word anywhere in a line.
  • I searched the branch's whole src/ and tests/ diff for any reader of a head outside toyos_logstream::parse and its wrappers, and found none. No old {… supervisor} or [kernel …] shape remains. acpi_release.rs reads the server's own piped stdout, which has no head, so its starts_with("acpiserver: armed: ") is correct.

Evidence at 8d7004d3b

  • --ci host: acpi1-r13/host-8d7004d3b.exit EXIT=0, and host-8d7004d3b.log:7611 reads "Host: 76 step(s), all green".

  • Guest suite: guest-8d7004d3b.exit EXIT=0, and guest-8d7004d3b.log:1071 reads "30 passed, 30 total".

  • Staging: stage.head = 8d7004d3b…, stage.status is empty, and each stage exited 2 with the machine untouched.

  • T14 judge logs:

    • metal-isa "3 passed, 0 failed"
    • metal-acpi_server "2 passed, 0 failed"
    • metal-acpi_table_inventory "1 passed, 0 failed"
    • metal-counters "3 passed, 0 failed"
    • metal-acpi_power_off "1 passed, 0 failed"
    • metal-acpi_power_button_pressed "1 passed, 0 failed"

    The attended press is in Every line of the log opens with one head, time first, counted from the CPU counter's zero #737's shape ([30.567 supervisor] … (Shutdown)), and asked_to_power_off passed it.

BLOCKER

None.

NOTE

  • tests/common/power.rs:571 — acpi_power_button still checks the supervisor's stop as after.must_say("{STOPPING} (Shutdown)"). That is a substring match anywhere in a console line. It sits beside the exact reader this merge made, bootlog::asked_to_power_off. The same fact should be read once: assert bootlog::asked_to_power_off(after.text()), and measure that test green.
  • PR body — it is false of the record at head:

LAND AFTER NAMED CHANGES

@Japabu

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 7 of #713 at 8d7004d3b. This replaces comment 5989630003: its LAND AFTER NAMED CHANGES was given before the owner's account of the attended press. Scope:

Net origin/main...8d7004d3b: 86 files, +3591/−585. The merge adds +8 in tests and harness and nothing in production.

Earlier findings

Round 6 had no BLOCKER. Its one NOTE was about the body's prose, and it is superseded below.

Merge with origin/main

origin/main is f260e0b98, the merge's second parent, so it is an ancestor of head. git merge-tree --write-tree origin/main 8d7004d3b exits 0, and GitHub reports MERGEABLE.

The resolution (git show --remerge-diff 8d7004d3b)

It is sound: every line is read through #737's one parser, and there is no second reader of a head.

  • asked_to_power_off = main's stopping_line (tag supervisor via program_line) plus an exact strip_prefix(STOPPING) == Some(" (Shutdown)").
  • The fixtures in src/bootlog.rs, src/metal.rs and tests/checks/metal.rs are in the one head, and the forged test-runner line is still refused by tag. The mutation in comment 5986276592 is red, EXIT=101, at src/bootlog.rs:556.
  • acpi_said reads through program_line and through parse with Source::Kernel and exact text. acpi_events_on_metal picks lines by program_line's tag.
  • No old-head shape is left in the branch's src/ or tests/ diff. acpi_release.rs reads the server's own piped stdout, which has no head.

Evidence at 8d7004d3b

  • --ci host: EXIT=0, host-8d7004d3b.log:7611 "Host: 76 step(s), all green".
  • Guest suite: EXIT=0, guest-8d7004d3b.log:1071 "30 passed, 30 total".
  • Six T14 judge logs, all "N passed, 0 failed".
  • The attended press row passed on a boot where the owner says the first press did nothing and only a later press stopped the machine.

What the readback (acpi1-r13/metal-acpi_power_button_pressed/testcases-press/kernel.log) shows:

  • The server armed at 14.363 s (line 354).
  • Its first SCI and query 0x4f came at 15.606 s (366–367).
  • Nothing more until 0x28's first sighting at 30.550 s (368).
  • The served press at 30.566 s is "SCI 17 of this boot" (369), and the stop follows (370).

So 0x28 came 16 ms before the press that was served, not with the lost one. Every SCI's take reads PM1 status (userland/acpiserver/src/main.rs, take), and SCIs keep coming on this machine: the unattended testcases-hold boot logs "28 SCIs" by 43.319 s, about one a second. The SCIs after the lost press therefore read no latched PWRBTN_STS. The press was lost before the server; the server did not drop it.

The log records nothing of a press that never set PWRBTN_STS. So no judge that reads only the log can tell this boot from a clean one.

BLOCKER

  • tests/toyos.rs:3807 acpi_press_on_metal cannot fail on a lost first press. This is a device row on high-risk code, and at this head a recorded real failure (the owner's account, the boot above) passes it green.

    The owner's ruling of 2026-10-05 ("Land it, record the gap") lets stage 1 land with the gap. The same ruling requires "the press test is fixed to fail when the first press is lost". The named-changes round must do all of the following:

    1. The row takes the press from a source outside the guest. The log cannot see a press that never reached PWRBTN_STS. Record the presses on the host side of the attended run, as the owner's count or host times, in the readback the judge reads. Then the judge reds unless the first press is the one the server logged and the stop followed. One press, served, is green. A second press before the stop, or none served, is red, and the judge names it.
    2. A negative control for that judge. Judge this head's testcases-press readback, acpi1-r13/metal-acpi_power_button_pressed/testcases-press/, under the new row with the owner's record of three presses. The result must be red, run with --metal-readback, which touches no machine. A green on a one-press record is the positive arm. Put both, with commands, exits and logs, in the body.
    3. The gap is recorded. In issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:
      • add this boot: 0x28 at 30.550 s, the press at 30.566 s on SCI 17, and the owner's account of a lost first press;
      • correct the "lost first press raised 0x28" reading, which this boot contradicts;
      • record the owner's ruling verbatim;
      • change its owner from stage 1 to the AML stage, which the ruling names as the one that closes it;
      • give it an exit an intermittent loss cannot meet by one lucky boot. Its present exit (power-button line within 1 s of 0x28, one recorded press) passes the lucky single press ff4945d6d already showed. The exit must be one the fixed row can red.
    4. The track's stage-1 exit in issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md stops claiming what stage 1 does not meet. Under the ruling, "a press of the power button stops the machine" is carried by the press issue into the AML stage, and stage 1's exit says so. That way no close of stage 1 rests on an unmet exit.
    5. The acpi_power_button_pressed registration comment (tests/toyos.rs:481, "presses the power button once") and acpi_hold.rs's module doc must describe the new protocol.

NOTE

  • tests/common/power.rs:571: acpi_power_button checks the supervisor's stop as a substring, must_say("{STOPPING} (Shutdown)"), beside the exact reader this merge made. Assert bootlog::asked_to_power_off(after.text()) instead, and measure it green.
  • PR body and record. Each of these is false of the record at head:

SEND BACK

… count

The attended press at 8d7004d passed green on a boot where the owner
says his first press did nothing and only a later press stopped the
machine. A press that never latched PWRBTN_STS leaves the log as clean
as no press at all, so no judge that reads only the log can tell that
boot from a clean one.

The row now takes the presses from outside the guest: the attended run
writes the owner's count into the readback's presses.txt once the
machine is off, and the judge reds unless that count is one and the
server served it. presses.txt is one of READBACK_FILES, so the loop
clears it before every boot and a count is always of the boot beside
it.

acpi_power_button's QEMU check of the supervisor's stop reads through
bootlog::asked_to_power_off, the one exact reader, rather than a
substring.

The press issue records the 8d7004d boot and the owner's account,
drops the reading that a lost first press raised 0x28, which that boot
refutes, records the owner's ruling of 2026-10-05, moves to the AML
interpreter's stages and takes an exit ten consecutive green attended
boots meet. Stage 1's exit no longer claims that every press stops the
machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
@Japabu

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Evidence for round 8 at 47ac0ce19, run by the orchestrator on the Mac.

Negative control for the press row. It uses --metal-readback only and touches no machine. The readback is the attended testcases-press boot from 8d7004d3b, with the owner's count written to presses.txt.

  • Three presses (the owner's record of that boot): cargo test --test toyos-build -- --metal --metal-readback press-3 acpi_power_button_pressed → EXIT=1, [metal] 0 passed, 1 failed, 1 boot(s)

    FAIL acpi_power_button_pressed: the owner pressed 3 times before the machine stopped, and the server served one press: the first 2 were lost before it (… 30.566 acpiserver] acpiserver: the power button was pressed, on SCI 17 of this boot; asking the supervisor to power off)

  • One press (positive arm, same boot): the same command on press-1 → EXIT=0, [metal] 1 passed, 0 failed, 1 boot(s), PASS acpi_power_button_pressed

Suites

  • cargo run -- --ci host → EXIT=0, Host: 76 step(s), all green
  • cargo test (guest) → EXIT=0, test result: ok. 30 passed, 30 total

The worktree was clean after both judgements.

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 8 of #713 at 47ac0ce19, against origin/main f260e0b98, which is the merge base; git merge-tree --write-tree origin/main 47ac0ce19 exits 0. It is read against origin/main's reviewer.md and the owner's ruling of 2026-10-05: "A test that requires manual steps from me is forbidden."

Net size:

  • origin/main...47ac0ce19: 86 files, +3640/−590. By path: production +2482/−471, tests/ +903/−101, issues/ +255/−18.
  • 47ac0ce19 alone: 7 files, +103/−59. Of that, issues/ is +57/−49 and src/metal.rs plus tests/ is +46/−10. No production code.

Round 7

  • Named change 1 (the press row takes its count from outside the guest): SUPERSEDED by the ruling. 47ac0ce19 built it as presses.txt (src/metal.rs:2223-2226,2251, tests/common/metal.rs:246-256, tests/toyos.rs:3817-3830). The ruling deletes it (BLOCKER 1).
  • Named change 2 (a negative control for that judge): SUPERSEDED. The control in comment 5989793202 (press-3 EXIT=1, press-1 EXIT=0) goes with the row.
  • Named change 3 (the gap recorded in the press issue): four parts CLOSED, one SUPERSEDED.
    • CLOSED: the 8d7004d3b boot is in the table and the owner's account is quoted (issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:21,35-37).
    • CLOSED: the 0x28 reading is corrected (:39-53).
    • CLOSED: the first 2026-10-05 ruling is recorded verbatim (:55-58).
    • CLOSED: the owner moved to the AML stages (:60-62).
    • SUPERSEDED: the exit (:64-68) asks for ten attended boots counted by presses.txt. That is a count of manual presses, which the ruling forbids (BLOCKER 2).
  • Named change 4 (stage 1's exit): CLOSED against round 7's text (issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:78-87), then reopened by the ruling. :78-81 still has "a T14 row" read the press and its stop, and that row is the one the ruling deletes (BLOCKER 1).
  • Named change 5 (the registration comment and acpi_hold.rs's doc): CLOSED (tests/toyos.rs:481-487, tests/toyos-rust-tests/src/bin/acpi_hold.rs:4-9). Both describe the row that now goes.
  • NOTE tests/common/power.rs:571: CLOSED. :571-573 reads bootlog::asked_to_power_off, and the guest suite is EXIT=0, 30/30, at 47ac0ce19 (comment 5989793202). That comment has no log line naming acpi_power_button PASS; the fix head's evidence must have one (NOTE below).
  • NOTE PR body: OPEN. pr-body.md is unchanged since round 7, and the orchestrator owns it.

What the two attended rows read, and which unattended tests read it at head

  • A press reaches the server, which has the supervisor stop the machine. Present.
    • QEMU acpi_power_button (tests/common/power.rs:553-577, registered at tests/toyos.rs:261, dispatched at :2740). It sends QMP system_powerdown, then reads the server's line on SCI 1 and the supervisor's (Shutdown) through asked_to_power_off, and ends on QEMU's guest-shutdown.
    • Host: userland/acpiserver/src/sci.rs:71-101 decodes PWRBTN and refuses a PM1 bit the server does not serve.
  • The power-off in ACPI mode takes, with the server's events quieted. Present on q35 only.
    • QEMU tests: machine_shutdown_short_stop (power.rs:71-109), acpi_power_button and machine_shutdown.
    • OVMF hands q35 over already in ACPI mode (power.rs:561), so these tests never run the T14's path.
    • Missing: the T14's path, a power-off after the kernel's own ACPI_ENABLE, together with power::off's S5_TAKES panic on that platform. Once acpi_power_off goes, no unattended test of any tier reads it. It can only be recorded (BLOCKER 1).
  • The T14's own button latches PWRBTN_STS in its PM1a block at 0x1800 and reaches the server over gsi 9. Missing.
    • acpi_server_events (tests/toyos.rs:453-457) reads only that the server armed with the button served.
    • Today nothing but a hand presses that button. The press issue carries this gap (BLOCKER 2).

BLOCKER

  1. tests/toyos.rs:470-493: both rows need the owner, which the ruling forbids. acpi_power_off needs him to power the T14 on from S5 within return_secs() (issues/the-metal-driver-reads-a-machine-left-in-s5-as-one-that-did-not-come-back.md:10-14). acpi_power_button_pressed needs his press and his presses.txt. The named changes, all in one diff:
    • Delete the rows and their judges. Delete both METAL rows, which removes the testcases-off and testcases-press arms. Delete acpi_press_on_metal, acpi_off_on_metal and powered_off_in_acpi_mode (tests/toyos.rs:3808-3860), Readback::presses (tests/common/metal.rs:246-256), and READBACK_PRESSES with its READBACK_FILES entry (src/metal.rs:2223-2226,2251).

    • Delete the harness's acceptance of a boot that ends in S5. It is the attended mode: only a boot that a hand powered on reaches it, because otherwise ride_the_reboot refuses before read_log (S5 issue :16-23). Delete:

      • boot_verdict's asked_to_power_off arm (src/metal.rs:2014-2018) and its test a_power_off_leaves_no_record_and_is_no_hang (:3415-3437);
      • judge_readbacks' && !bootlog::asked_to_power_off (tests/common/metal.rs:1078-1081);
      • a_power_off_owes_no_panel (tests/checks/metal.rs:369-396) and its registration (tests/checks.rs:860-863).

      bootlog::asked_to_power_off and its test stay, because QEMU's acpi_power_button reads them.

    • Rewrite the S5 issue as the gap the deletion leaves. Rename its slug to that gap and move every citation. It states that no T14 row reads ToyOS's power-off in ACPI mode, or power::off's S5_TAKES panic there, because nothing brings the machine back from S5 without a person. Its last readings are at ff4945d6d and 8d7004d3b. Its owner stays issues/the-t14-reboots-through-ubuntu-for-every-test.md. Its exit becomes: a T14 row whose boot ends in that power-off is judged off its log with no person powering the machine on. The present exit, "powered on only after return_secs()", is met only by a manual step.

    • Rewrite stage 1's exit (issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:73-87):

      • QEMU's acpi_power_button reads that a press the server serves stops the machine through SYS_SHUTDOWN.
      • On the T14, counters reads SMI flat, acpi_server_events reads each EC query once with its count, and acpi_server_death reads SCI_EN clear.
      • The T14's press goes to the press issue, and its power-off to the rewritten S5 issue.
      • Record the new 2026-10-05 ruling verbatim beside the 2026-10-03 "The attended press waits for the owner" (:37-39), and say that it supersedes that ruling.
  2. issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:64-68: the exit is ten attended boots counted by the owner's presses.txt, which the ruling forbids. Also, :55-58 records "the press test is fixed to fail when the first press is lost" as standing, and nothing says it is superseded. The named changes:
    • Record the new ruling verbatim, and what it supersedes.
    • Keep the owner, the AML stage.
    • Say that no row reads the T14's press until this exit is met.
    • Make the exit one an unattended run can red. This proposal is the reviewer's, not the owner's: a T14 row presses the power button by a means the harness drives, with no person, on a boot held open. It reds unless the boot's first press is the one the server logs and the supervisor's power-off follows. It passes on ten consecutive boots of one head.
    • Record that the exit is blocked on two things: the bench having such a means, and the S5 issue above. A bench device is the owner's to rule, and the orchestrator asks him before the fix round. Whatever he rules, the exit is never a hand count.

NOTE

  • issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:47-49: "before the server armed, while the firmware still had the machine in legacy mode" is false of the tree. The kernel enables ACPI mode when it mints the claim (userland/acpiserver/src/main.rs:3-5). arm then clears every latched status, PWRBTN_STS included (main.rs:10-13,96-97: "one before it is lost"). So ToyOS drops, by design, any press that comes between the enable and the arm. Name that window as one place a press is lost.
  • issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md: the track names no stage for the AML interpreter. The press issue is owned by "the AML interpreter's stages" (:60-62), but the only staged work after stage 1 is "power-off through the server". Name the stage that owns it.
  • issues/a-stop-shows-nothing-on-the-panel.md:16-17: "A boot held open for an attended press" describes a boot the ruling deletes.
  • pr-body.md will be false of the fix head wherever it describes or reports either attended row: lines 15-16 (the S5 acceptance and the panel exemption, both going), 102, 129, 139-142, 152-153, 159-171, 192, 200-201, and the three-press control. The body must state the deletion and the coverage above, and that the T14's press and its power-off are unguarded until their issues' exits are met.
  • The fix head owes this evidence in the body, each with command, exit and log, or the next round blocks:
    • cargo run -- --ci host EXIT=0.
    • The guest suite EXIT=0, with acpi_power_button, machine_shutdown and machine_shutdown_short_stop PASS read from its log.
    • --metal-readback of counters, acpi_server_events and acpi_server_death at the fix head, judged on the 8d7004d3b readbacks (acpi1-r13).
    • Beside those readbacks, an empty git diff --stat 8d7004d3b <fix> over every image source, so that their T14 readings stand for the fix head without a flash.

SEND BACK


Generated by Claude Code

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 8 of #713 at 47ac0ce19, against origin/main f260e0b98, which is the merge base; git merge-tree --write-tree origin/main 47ac0ce19 exits 0. It is read against origin/main's reviewer.md and the owner's ruling of 2026-10-05: "A test that requires manual steps from me is forbidden."

Net size:

  • origin/main...47ac0ce19: 86 files, +3640/−590. By path: production +2482/−471, tests/ +903/−101, issues/ +255/−18.
  • 47ac0ce19 alone: 7 files, +103/−59. Of that, issues/ is +57/−49 and src/metal.rs plus tests/ is +46/−10. No production code.

Round 7

  • Named change 1 (the press row takes its count from outside the guest): SUPERSEDED by the ruling. 47ac0ce19 built it as presses.txt (src/metal.rs:2223-2226,2251, tests/common/metal.rs:246-256, tests/toyos.rs:3817-3830). The ruling deletes it (BLOCKER 1).
  • Named change 2 (a negative control for that judge): SUPERSEDED. The control in comment 5989793202 (press-3 EXIT=1, press-1 EXIT=0) goes with the row.
  • Named change 3 (the gap recorded in the press issue): four parts CLOSED, one SUPERSEDED.
    • CLOSED: the 8d7004d3b boot is in the table (issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:22) and the owner's account is quoted (:35-37).
    • CLOSED: the 0x28 reading is corrected (:39-53). One boot whose lost press raised no 0x28 refutes "a lost press raises 0x28" as the mechanism. Nothing at b3b9ccd69 restores it: 0x28 was taken at 6.696 s, and the served press at 16.705 s came about 5 s after the lost one (:18,32-33). That puts the lost press near 11.7 s, about 5 s after 0x28.
    • CLOSED: the first 2026-10-05 ruling is recorded verbatim (:55-58).
    • CLOSED: the owner moved to the AML stages (:60-62). The NOTE below says the track names no such stage.
    • SUPERSEDED: the exit (:64-68) asks for ten attended boots counted by presses.txt. That is a count of manual presses, which the ruling forbids (BLOCKER 2).
  • Named change 4 (stage 1's exit): CLOSED against round 7's text (issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:75-87), then reopened by the ruling. :78-81 still has "a T14 row" read the press and its stop, and that row is the one the ruling deletes (BLOCKER 1).
  • Named change 5 (the registration comment and acpi_hold.rs's doc): CLOSED (tests/toyos.rs:481-487, tests/toyos-rust-tests/src/bin/acpi_hold.rs:4-9). Both describe the row that now goes, and so do two comments round 7 did not name (BLOCKER 1).
  • NOTE tests/common/power.rs:571: CLOSED in code. :571-573 reads bootlog::asked_to_power_off. OPEN in measurement. The only reading is comment 5989793202, a 30 passed line with no log naming acpi_power_button PASS, and it is not in the body. The fix head owes that line from its guest log (NOTE below).
  • NOTE PR body: OPEN. pr-body.md is unchanged since round 7, and the orchestrator owns it.

What the two attended rows read, and which unattended tests read it at head

  • A press reaches the server, which has the supervisor stop the machine. Present.
    • QEMU acpi_power_button (tests/common/power.rs:553-577, registered at tests/toyos.rs:261, dispatched at :2740). It sends QMP system_powerdown, then reads the server's line on SCI 1 and the supervisor's power-off through asked_to_power_off, and ends on QEMU's guest-shutdown. It also reds a press the server loses, since nothing else stops that boot before the hang ceiling.
    • Host: userland/acpiserver/src/sci.rs:71-101 decodes PWRBTN and refuses a PM1 bit the server does not serve.
  • The machine went into ACPI mode for the server and stayed there, with the EC on GPE 0x6e. Present on the T14, unattended.
    • counters reds on acpi: legacy mode again (tests/toyos.rs:3690-3692).
    • acpi_server_events reads the ACPI row and the server's armed: line (:3763-3771).
    • Those are the non-S5 halves of powered_off_in_acpi_mode and acpi_off_on_metal.
  • SLP_EN takes after the kernel's own ACPI_ENABLE, so power::off's S5_TAKES panic (kernel/src/arch/x86_64/power.rs:185-198) does not fire. Present on q35 only.
    • The QEMU tests are machine_shutdown_short_stop (power.rs:71-109), acpi_power_button and machine_shutdown.
    • OVMF hands q35 over already in ACPI mode (power.rs:559-561), so the enable and its wait (kernel/src/arch/x86_64/acpi_mode.rs:5-8) never run before a QEMU power-off.
    • On the T14 only acpi_power_off read this, through the absence of PREVIOUS_PANIC and the presence of HUNG_WITHOUT_A_RECORD after the reset. Its last readings are at ff4945d6d and 8d7004d3b.
    • No measurement at this head shows whether a QEMU boot can reach this path. QEMU's ICH9 is understood to apply ACPI_ENABLE written to its APM port 0xb2 to SCI_EN, but OVMF sets SCI_EN before the kernel runs. A kernel or loader knob that stages legacy mode for a test would ship for tests alone. The fix either names an unattended QEMU test that reaches this path or records, in the S5 gap issue, why none can (BLOCKER 1).
  • The T14's own button latches PWRBTN_STS in its PM1a block at 0x1800 and reaches the server over gsi 9. Missing.
    • acpi_server_events reads only that the server armed with the button served.
    • Today nothing but a hand presses that button. The press issue carries this gap (BLOCKER 2).

BLOCKER

  1. tests/toyos.rs:468-493: both rows need the owner, which the ruling forbids. acpi_power_off needs him to power the T14 on from S5 within return_secs() (issues/the-metal-driver-reads-a-machine-left-in-s5-as-one-that-did-not-come-back.md:10-14). acpi_power_button_pressed needs his press and his presses.txt. The named changes, all in one diff:
    • Delete the rows and their judges.

      • Delete both METAL rows, which removes the testcases-off and testcases-press arms.
      • Delete acpi_press_on_metal, acpi_off_on_metal and powered_off_in_acpi_mode (tests/toyos.rs:3808-3860).
      • Delete Readback::presses (tests/common/metal.rs:246-256), and READBACK_PRESSES with its READBACK_FILES entry (src/metal.rs:2223-2226,2251).
    • Delete the comments that name the deleted row.

      • tests/toyos.rs:164-166: acpi_hold is then run by acpi_server_events alone.
      • tests/toyos.rs:259-260: it then cites no T14 row for the button.
      • tests/toyos.rs:481-487.
      • acpi_hold.rs:4-9's press-row sentence. "Two metal rows" becomes one.
    • Delete the harness's acceptance of a boot that ends in S5. It is the attended mode: only a boot a hand powered on reaches it, because otherwise ride_the_reboot refuses before read_log (S5 issue :16-23). Delete:

      • boot_verdict's asked_to_power_off arm (src/metal.rs:2014-2018) and its test a_power_off_leaves_no_record_and_is_no_hang (:3415-3437);
      • judge_readbacks' && !bootlog::asked_to_power_off (tests/common/metal.rs:1078-1081);
      • a_power_off_owes_no_panel (tests/checks/metal.rs:369-396) and its registration (tests/checks.rs:860-863).

      bootlog::asked_to_power_off and its test stay, because QEMU's acpi_power_button reads them. All of this is the branch's own: git grep asked_to_power_off origin/main is empty.

    • Rewrite the S5 issue as the gap the deletion leaves.

      • Rename its slug to that gap and move every citation (the press issue :29 is one).
      • It states that no T14 row reads ToyOS's power-off after the kernel's own ACPI_ENABLE, because nothing brings the machine back from S5 without a person. Its last readings are at ff4945d6d and 8d7004d3b.
      • It states whether QEMU can reach that path (above), with the reason measured.
      • Its owner stays issues/the-t14-reboots-through-ubuntu-for-every-test.md.
      • Its exit becomes: a T14 row whose boot ends in that power-off is judged off its log with no person powering the machine on. The present exit, "powered on only after return_secs()" (:40-41), is met only by a manual step.
    • Rewrite stage 1's exit (issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:75-87).

      • QEMU's acpi_power_button reads that a press the server serves stops the machine through SYS_SHUTDOWN.
      • On the T14, counters reads SMI flat and ACPI mode held, acpi_server_events reads each EC query once with its count, and acpi_server_death reads SCI_EN clear.
      • The T14's press goes to the press issue, and its power-off to the rewritten S5 issue.
      • Record the new 2026-10-05 ruling verbatim beside the 2026-10-03 "The attended press waits for the owner" (:37-39), and say that it supersedes that ruling.
      • The owner's "Land it" lists power-off among what stage 1 lands (press issue :56). Stage 1 still lands it, read on q35 and at 8d7004d3b on the T14. Moving its unattended T14 reader out of stage 1's exit is the orchestrator's placement, and the issue says so; it does not present the move as his.
  2. issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:64-68: the exit is ten attended boots counted by the owner's presses.txt, which the ruling forbids. Also, :55-58 records "the press test is fixed to fail when the first press is lost" as standing, and nothing says it is superseded. The named changes:
    • Record the new ruling verbatim, and what it supersedes.
    • Keep the owner, the AML stage.
    • Say that no row reads the T14's press until this exit is met.
    • Make the exit one an unattended run can red. This proposal is the reviewer's, not the owner's: a T14 row presses the power button by a means the harness drives, with no person, on a boot held open. It reds unless the boot's first press is the one the server logs and the supervisor's power-off follows. It passes on ten consecutive boots of one head.
    • Record that the exit is blocked on two things: the bench having such a means, and the S5 issue above. A bench device is the owner's to rule, and the orchestrator asks him before the fix round. Whatever he rules, the exit is never a hand count.

NOTE

  • issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:47-49: "before the server armed, while the firmware still had the machine in legacy mode" is false of the tree.
    • The kernel enables ACPI mode when it mints the claim (userland/acpiserver/src/main.rs:3-5).
    • arm then clears every latched status, PWRBTN_STS included (main.rs:10-14: "one before it is lost").
    • So ToyOS drops, by design, any press that comes between the enable and the arm. Name that window as one place a press is lost.
  • issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md: the track names no stage for the AML interpreter. The press issue is owned by "the AML interpreter's stages" (:60-62). The track says only that the interpreter "follows as later stages" (:23), and the only staged work it names after stage 1 is "power-off through the server" (:101). Name the stage that owns the press issue.
  • issues/a-stop-shows-nothing-on-the-panel.md:16-17: "A boot held open for an attended press" describes a boot the ruling deletes.
  • pr-body.md will be false of the fix head wherever it describes or reports either attended row, the S5 acceptance, the panel exemption or the three-press control. That includes lines 15-16, 102, 129, 139-142, 152-153, 159-171, 192 and 200-201. The body must state:
    • the deletion;
    • the coverage map above;
    • that the T14's press and its post-enable power-off are unguarded until their issues' exits are met.
  • The fix head owes this evidence in the body, each with command, exit and log. Under reviewer.md's Evidence section, each is a BLOCKER at the fix round if it is missing:
    • cargo run -- --ci host EXIT=0.
    • The guest suite EXIT=0, with acpi_power_button, machine_shutdown and machine_shutdown_short_stop PASS read from its log.
    • --metal-readback of counters, acpi_server_events and acpi_server_death at the fix head, judged on the 8d7004d3b readbacks (acpi1-r13).
    • Beside those readbacks, git diff 8d7004d3b <fix> over every image source, showing that it changes comments alone, so that their T14 readings stand for the fix head without a flash. The diff cannot be empty: acpi_hold.rs, which the testcases-hold image builds, already changed its doc at 47ac0ce19, and the fix changes it again.

REMOVE

  • src/bootlog.rs:378-381: the paragraph "A power-off leaves the next loader pass no record … keeps the page" is the reason for the metal boot_verdict arm BLOCKER 1 deletes. With that arm gone, the paragraph describes nothing asked_to_power_off is read for.

SEND BACK


Generated by Claude Code

Japabu commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 8 of #713 at 47ac0ce19, against origin/main f260e0b98, which is the merge base; git merge-tree --write-tree origin/main 47ac0ce19 exits 0. It is read against origin/main's reviewer.md and the owner's ruling of 2026-10-05: "A test that requires manual steps from me is forbidden."

Net size:

  • origin/main...47ac0ce19: 86 files, +3640/−590. By path: production +2482/−471, tests/ +903/−101, issues/ +255/−18.
  • 47ac0ce19 alone: 7 files, +103/−59. Of that, issues/ is +57/−49 and src/metal.rs plus tests/ is +46/−10. No production code.

Round 7

  • Named change 1 (the press row takes its count from outside the guest): SUPERSEDED by the ruling. 47ac0ce19 built it as presses.txt (src/metal.rs:2223-2226,2251, tests/common/metal.rs:246-256, tests/toyos.rs:3817-3830). The ruling deletes it (BLOCKER 1).
  • Named change 2 (a negative control for that judge): SUPERSEDED. The control in comment 5989793202 (press-3 EXIT=1, press-1 EXIT=0) goes with the row.
  • Named change 3 (the gap recorded in the press issue): four parts CLOSED, one SUPERSEDED.
    • CLOSED: the 8d7004d3b boot is in the table (issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:22) and the owner's account is quoted (:35-37).
    • CLOSED: the 0x28 reading is corrected (:39-53). One boot whose lost press raised no 0x28 refutes "a lost press raises 0x28" as the mechanism. Nothing at b3b9ccd69 restores it: 0x28 was taken at 6.696 s, and the served press at 16.705 s came about 5 s after the lost one (:18,32-33). That puts the lost press near 11.7 s, about 5 s after 0x28.
    • CLOSED: the first 2026-10-05 ruling is recorded verbatim (:55-58).
    • CLOSED: the owner moved to the AML stages (:60-62). The NOTE below says the track names no such stage.
    • SUPERSEDED: the exit (:64-68) asks for ten attended boots counted by presses.txt. That is a count of manual presses, which the ruling forbids (BLOCKER 2).
  • Named change 4 (stage 1's exit): CLOSED against round 7's text (issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:75-87), then reopened by the ruling. :78-81 still has "a T14 row" read the press and its stop, and that row is the one the ruling deletes (BLOCKER 1).
  • Named change 5 (the registration comment and acpi_hold.rs's doc): CLOSED (tests/toyos.rs:481-487, tests/toyos-rust-tests/src/bin/acpi_hold.rs:4-9). Both describe the row that now goes, and so do two comments round 7 did not name (BLOCKER 1).
  • NOTE tests/common/power.rs:571: CLOSED in code. :571-573 reads bootlog::asked_to_power_off. OPEN in measurement. The only reading is comment 5989793202, a 30 passed line with no log naming acpi_power_button PASS, and it is not in the body. The fix head owes that line from its guest log (NOTE below).
  • NOTE PR body: OPEN. pr-body.md is unchanged since round 7, and the orchestrator owns it.

What the two attended rows read, and which unattended tests read it at head

  • A press reaches the server, which has the supervisor stop the machine. Present.
    • QEMU acpi_power_button (tests/common/power.rs:553-577, registered at tests/toyos.rs:261, dispatched at :2740). It sends QMP system_powerdown, then reads the server's line on SCI 1 and the supervisor's power-off through asked_to_power_off, and ends on QEMU's guest-shutdown. It also reds a press the server loses, since nothing else stops that boot before the hang ceiling.
    • Host: userland/acpiserver/src/sci.rs:71-101 decodes PWRBTN and refuses a PM1 bit the server does not serve.
  • The machine went into ACPI mode for the server and stayed there, with the EC on GPE 0x6e. Present on the T14, unattended.
    • counters reds on acpi: legacy mode again (tests/toyos.rs:3690-3692).
    • acpi_server_events reads the ACPI row and the server's armed: line (:3763-3771).
    • Those are the non-S5 halves of powered_off_in_acpi_mode and acpi_off_on_metal.
  • SLP_EN takes after the kernel's own ACPI_ENABLE, so power::off's S5_TAKES panic (kernel/src/arch/x86_64/power.rs:185-198) does not fire. Present on q35 only.
    • The QEMU tests are machine_shutdown_short_stop (power.rs:71-109), acpi_power_button and machine_shutdown.
    • OVMF hands q35 over already in ACPI mode (power.rs:559-561), so the enable and its wait (kernel/src/arch/x86_64/acpi_mode.rs:5-8) never run before a QEMU power-off.
    • On the T14 only acpi_power_off read this, through the absence of PREVIOUS_PANIC and the presence of HUNG_WITHOUT_A_RECORD after the reset. Its last readings are at ff4945d6d and 8d7004d3b.
    • No measurement at this head shows whether a QEMU boot can reach this path. QEMU's ICH9 is understood to apply ACPI_ENABLE written to its APM port 0xb2 to SCI_EN, but OVMF sets SCI_EN before the kernel runs. A kernel or loader knob that stages legacy mode for a test would ship for tests alone. The fix either names an unattended QEMU test that reaches this path or records, in the S5 gap issue, why none can (BLOCKER 1).
  • The T14's own button latches PWRBTN_STS in its PM1a block at 0x1800 and reaches the server over gsi 9. Missing.
    • acpi_server_events reads only that the server armed with the button served.
    • Today nothing but a hand presses that button. The press issue carries this gap (BLOCKER 2).

BLOCKER

  1. tests/toyos.rs:468-493: both rows need the owner, which the ruling forbids. acpi_power_off needs him to power the T14 on from S5 within return_secs() (issues/the-metal-driver-reads-a-machine-left-in-s5-as-one-that-did-not-come-back.md:10-14). acpi_power_button_pressed needs his press and his presses.txt. The named changes, all in one diff:
    • Delete the rows and their judges.

      • Delete both METAL rows, which removes the testcases-off and testcases-press arms.
      • Delete acpi_press_on_metal, acpi_off_on_metal and powered_off_in_acpi_mode (tests/toyos.rs:3808-3860).
      • Delete Readback::presses (tests/common/metal.rs:246-256), and READBACK_PRESSES with its READBACK_FILES entry (src/metal.rs:2223-2226,2251).
    • Delete the comments that name the deleted row.

      • tests/toyos.rs:164-166: acpi_hold is then run by acpi_server_events alone.
      • tests/toyos.rs:259-260: it then cites no T14 row for the button.
      • tests/toyos.rs:481-487.
      • acpi_hold.rs:4-9's press-row sentence. "Two metal rows" becomes one.
    • Delete the harness's acceptance of a boot that ends in S5. It is the attended mode: only a boot a hand powered on reaches it, because otherwise ride_the_reboot refuses before read_log (S5 issue :16-23). Delete:

      • boot_verdict's asked_to_power_off arm (src/metal.rs:2014-2018) and its test a_power_off_leaves_no_record_and_is_no_hang (:3415-3437);
      • judge_readbacks' && !bootlog::asked_to_power_off (tests/common/metal.rs:1078-1081);
      • a_power_off_owes_no_panel (tests/checks/metal.rs:369-396) and its registration (tests/checks.rs:860-863).

      bootlog::asked_to_power_off and its test stay, because QEMU's acpi_power_button reads them. All of this is the branch's own: git grep asked_to_power_off origin/main is empty.

    • Rewrite the S5 issue as the gap the deletion leaves.

      • Rename its slug to that gap and move every citation (the press issue :29 is one).
      • It states that no T14 row reads ToyOS's power-off after the kernel's own ACPI_ENABLE, because nothing brings the machine back from S5 without a person. Its last readings are at ff4945d6d and 8d7004d3b.
      • It states whether QEMU can reach that path (above), with the reason measured.
      • Its owner stays issues/the-t14-reboots-through-ubuntu-for-every-test.md.
      • Its exit becomes: a T14 row whose boot ends in that power-off is judged off its log with no person powering the machine on. The present exit, "powered on only after return_secs()" (:40-41), is met only by a manual step.
    • Rewrite stage 1's exit (issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:75-87).

      • QEMU's acpi_power_button reads that a press the server serves stops the machine through SYS_SHUTDOWN.
      • On the T14, counters reads SMI flat and ACPI mode held, acpi_server_events reads each EC query once with its count, and acpi_server_death reads SCI_EN clear.
      • The T14's press goes to the press issue, and its power-off to the rewritten S5 issue.
      • Record the new 2026-10-05 ruling verbatim beside the 2026-10-03 "The attended press waits for the owner" (:37-39), and say that it supersedes that ruling.
      • The owner's "Land it" lists power-off among what stage 1 lands (press issue :56). Stage 1 still lands it, read on q35 and at 8d7004d3b on the T14. Moving its unattended T14 reader out of stage 1's exit is the orchestrator's placement, and the issue says so; it does not present the move as his.
  2. issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:64-68: the exit is ten attended boots counted by the owner's presses.txt, which the ruling forbids. Also, :55-58 records "the press test is fixed to fail when the first press is lost" as standing, and nothing says it is superseded. The named changes:
    • Record the new ruling verbatim, and what it supersedes.
    • Keep the owner, the AML stage.
    • Say that no row reads the T14's press until this exit is met.
    • Make the exit one an unattended run can red. This proposal is the reviewer's, not the owner's: a T14 row presses the power button by a means the harness drives, with no person, on a boot held open. It reds unless the boot's first press is the one the server logs and the supervisor's power-off follows. It passes on ten consecutive boots of one head.
    • Record that the exit is blocked on two things: the bench having such a means, and the S5 issue above. A bench device is the owner's to rule, and the orchestrator asks him before the fix round. Whatever he rules, the exit is never a hand count.

NOTE

  • issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:47-49: "before the server armed, while the firmware still had the machine in legacy mode" is false of the tree.
    • The kernel enables ACPI mode when it mints the claim (userland/acpiserver/src/main.rs:3-5).
    • arm then clears every latched status, PWRBTN_STS included (main.rs:10-14: "one before it is lost").
    • So ToyOS drops, by design, any press that comes between the enable and the arm. Name that window as one place a press is lost.
  • issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md: the track names no stage for the AML interpreter. The press issue is owned by "the AML interpreter's stages" (:60-62). The track says only that the interpreter "follows as later stages" (:23), and the only staged work it names after stage 1 is "power-off through the server" (:101). Name the stage that owns the press issue.
  • issues/a-stop-shows-nothing-on-the-panel.md:16-17: "A boot held open for an attended press" describes a boot the ruling deletes.
  • pr-body.md will be false of the fix head wherever it describes or reports either attended row, the S5 acceptance, the panel exemption or the three-press control. That includes lines 15-16, 102, 129, 139-142, 152-153, 159-171, 192 and 200-201. The body must state:
    • the deletion;
    • the coverage map above;
    • that the T14's press and its post-enable power-off are unguarded until their issues' exits are met.
  • The fix head owes this evidence in the body, each with command, exit and log. Under reviewer.md's Evidence section, each is a BLOCKER at the fix round if it is missing:
    • cargo run -- --ci host EXIT=0.
    • The guest suite EXIT=0, with acpi_power_button, machine_shutdown and machine_shutdown_short_stop PASS read from its log.
    • --metal-readback of counters, acpi_server_events and acpi_server_death at the fix head, judged on the 8d7004d3b readbacks (acpi1-r13).
    • Beside those readbacks, git diff 8d7004d3b <fix> over every image source, showing that it changes comments alone, so that their T14 readings stand for the fix head without a flash. The diff cannot be empty: acpi_hold.rs, which the testcases-hold image builds, already changed its doc at 47ac0ce19, and the fix changes it again.

REMOVE

  • src/bootlog.rs:378-381: the paragraph "A power-off leaves the next loader pass no record … keeps the page" is the reason for the metal boot_verdict arm BLOCKER 1 deletes. With that arm gone, the paragraph describes nothing asked_to_power_off is read for.

SEND BACK


Generated by Claude Code

Japabu and others added 2 commits October 7, 2026 14:52
Review round 8 of #713, on the owner's rulings "A test that requires manual
steps from me is forbidden." and "No automated test is allowed that requires
physical buttons to be pressed or anything we cant do now with the t14. I can
test it on demand but no ci there not always someone available physically".

Deleted: the metal rows acpi_power_off and acpi_power_button_pressed, their
judges (acpi_off_on_metal, acpi_press_on_metal, powered_off_in_acpi_mode),
Readback::presses and READBACK_PRESSES, and the harness's acceptance of a boot
that ends in S5: boot_verdict's asked_to_power_off arm with its test,
judge_readbacks' panel exemption with a_power_off_owes_no_panel. Only a boot a
hand powered on again ever reached that acceptance. asked_to_power_off stays
for QEMU's acpi_power_button.

Issues: the S5 issue is renamed to the gap the deletion leaves, that no T14
row reads the power-off after the kernel's own ACPI_ENABLE, and records what
QEMU reads of it. Measured on QEMU 11.1.1's q35 under OVMF and TCG, bare,
through the monitor: PM1a_CNT (0x604) read 0x0001 as OVMF left it, 0x0000
after `o/b 0xb2 3`, 0x0001 after `o/b 0xb2 2`, so a harness can put a guest in
legacy mode with nothing shipped for it; no test does yet. The press issue's
exit is an on-demand check by the owner, and it names the window between the
enable and the server's clear in which a press is dropped. Stage 1's exit
names the rows that read it, and the track names the interpreter stage that
owns the press issue.

acpi_mode::release wrote ACPI_DISABLE and logged one read of PM1a_CNT, after
it had already released the row. It now writes the disable with the row still
held and reads SCI_EN until it is clear, spun and bounded at 100 ms, since the
task a claim's last handle goes with may be dying and cannot park. The row
going first let a claimant mint between the release and the disable, find
SCI_EN still set, write nothing, and lose ACPI mode to the disable that
followed. A firmware that does not clear the bit is said by name, ENABLED
stays set, and the next release writes the disable again. On the T14 at
8d7004d the one read was already clear.

FixedHardware carries `legacy: Option<LegacyMode>` in place of smi_cmd,
acpi_enable and acpi_disable: the two commands are NonZeroU8, and a FADT that
leaves any of the three zero names no way in that this kernel takes. Table 5.9
reserves each as zero on a machine without legacy mode, so a machine with
ACPI_ENABLE and no ACPI_DISABLE stays in legacy mode, refused by name, where
before the release would have written 0 to SMI_CMD.

Not run at this commit: the guest suite and the metal staging. The primary
checkout's rust/build is gone, so no worktree has a compiler to build a guest
image with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ves it no bound

The orchestrator's ruling: the QEMU reach of the enable-then-S5 path, the
monitor clearing SCI_EN before the claim is minted, is the exit of
issues/no-t14-row-reads-the-power-off-after-the-kernels-own-acpi-enable.md
and is not built in stage 1. The issue's exit says so, as his placement.

The owner's second ruling on tests, "No automated test is allowed that
requires physical buttons to be pressed ...", is dated 2026-10-05 in the three
issues that quote it.

HANDBACK's comment called the 100 ms an estimate. ACPI 6.5 was read, from the
Internet Archive's copy of uefi.org's HTML (uefi.org answers curl with a 403
challenge page): section 4.8.2.5 has OSPM write ACPI_DISABLE and poll SCI_EN
"until it is sampled as RESET" and names no bound; Table 5.9's ACPI_ENABLE row
says only that OSPM waits synchronously and the system releases ownership "as
quickly as possible"; no FADT field carries a time. The comment now says that
none is given and that the number is this kernel's. Comment only: three lines
for three.

Found in the same reading and filed, not fixed:
issues/the-kernel-writes-smi-cmd-from-whichever-cpu-its-caller-runs-on.md.
Table 5.9 has OSPM issue SMI_CMD commands from the boot processor; the kernel
writes on the claimant's CPU, and on the T14's acpi_server_death boots at
ff4945d and 8d7004d the enable was written from cpu7 and took.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

T14 at 922a6b7c7, run by the orchestrator: five unattended boots, each image's sha256 checked against the request before its flash, the worktree clean at the head before every boot and every judgement. Nobody was at the machine.

boot flash and readback judge
acpicase, testcases-hold rc=0, rc=0 --metal --metal-readback … acpi_server_ → EXIT=0, [metal] 2 passed, 0 failed, 2 boot(s) (acpi_server_events, acpi_server_death)
shared, shared-debug, testcases rc=0 each --metal --metal-readback … counters → EXIT=0, [metal] 3 passed, 0 failed, 3 boot(s)

The acpi_server_ judgement asked to record rows in tests/metal for acpicase and testcases-hold; that diff is kept as a patch beside the judge log and the worktree was restored, so the branch does not carry it yet.

@Japabu

Japabu commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 9 of #713 at 922a6b7c7, the two commits after 47ac0ce19 (04bcf041d, 922a6b7c7). Merge base is f260e0b98; origin/main is now df1a77221 (#743) and git merge-tree --write-tree origin/main 922a6b7c7 exits 0.

Net size, git diff --shortstat origin/main...922a6b7c7: 83 files, +3624/−592. Production +2458/−470, tests/ + src/ + toyos-acpi/tests/ +808/−100, issues/ +358/−22. This round alone: 19 files, +284/−302; production +81/−39 (acpi_mode.rs, fadt.rs, lib.rs), tests and harness +32/−191, issues/ +171/−72. The production growth is the poll and the LegacyMode type; accepted.

Round 8

  • BLOCKER 1 (both attended rows and what served them): CLOSED in the tree, one part moved to BLOCKER 1 below.
    • Rows, judges, Readback::presses, READBACK_PRESSES, boot_verdict's power-off arm and its test, the panel exemption and a_power_off_owes_no_panel with its registration are gone. git grep at head for acpi_power_off, acpi_power_button_pressed, presses.txt, testcases-press, testcases-off, the three judge names and the old slug finds only the two issues that record the deleted rows by name.
    • bootlog::asked_to_power_off keeps one reader, tests/common/power.rs:571, and its host test ran (acpi1-r16/host.log:26).
    • The S5 issue is rewritten as the gap, its one citation moved (press issue :29). Stage 1's exit names its readers and both placements are labelled the orchestrator's.
    • Whether QEMU reaches the path: answered as "it can be staged, no test does". The measurement behind that answer has no log (BLOCKER 2).
  • BLOCKER 2 (the press issue's exit): CLOSED. Both rulings are verbatim, the superseded sentence is named, the exit is an on-demand check no test or CI job waits on, and "Ten is not the owner's" stays. Two NOTEs on it below.
  • REMOVE src/bootlog.rs:378-381: CLOSED.
  • NOTE press issue :47-49: CLOSED. The enable-to-clear window is named, with 14.361 s and 14.363 s, which acpi1-r13/metal-acpi_power_button_pressed/testcases-press/kernel.log:348,354 carry.
  • NOTE the track names no interpreter stage: CLOSED (issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:116-123), labelled as the orchestrator's placement.
  • NOTE issues/a-stop-shows-nothing-on-the-panel.md:16-17: CLOSED.
  • NOTE tests/common/power.rs:571 owed its guest line: CLOSED. gates.sh at gates.head 922a6b7c7…, guest EXIT=0; guest.log:664 PASS acpi_power_button, :709 PASS machine_shutdown, :779 PASS machine_shutdown_short_stop, :882 30 of 30.
  • Evidence owed: host CLOSED (host EXIT=0, host.log:7440, 76 steps; :1211 ran fixed_hardware_reads_whichever_form_names_a_block). Guest CLOSED. Head's judges on the 8d7004d3b readbacks CLOSED (judge-old.exits: both 0; 2 passed and 3 passed). The image-source diff is not comments alone, as the body says itself: the kernel in every image changed. That is BLOCKER 1.

What the round added, read

  • acpi_mode::leave (kernel/src/arch/x86_64/acpi_mode.rs:291-321): the SMI_CMD lock is dropped before the poll, so nothing is held across it. The claim's hook runs "from the deferred queue with no lock held" (kernel/src/object/mod.rs:116), and Held::release drops outside its own lock, so the spin holds nothing on the release path either. The bound is checked on every pass and the expiry is said by name. Not a flat wait.
  • Release order (:281-286): the row stays minted through leave, so claim_row answers Owned until the disable is read as taken. Inside the bound the race the commit names is closed. Past the bound it is not (NOTE).
  • ENABLED set straight after the outb (:249): a mint that times out or is killed reaches leave with it set, reads SCI_EN clear on the first pass and clears it. Consistent with the static's stated meaning.
  • FixedHardware.legacy (toyos-acpi/src/fadt.rs:364-368): the three zero cases are host-tested one by one (toyos-acpi/tests/corpus.rs:775-778), so widening the match to accept a zero ACPI_DISABLE reds 53..54. No user of the three old fields is left outside the crate's tests and acpi_mode.rs.
  • acpi_death_on_metal losing its ends_with branch: the kernel writes legacy mode again only after a read with the bit clear, and the expiry writes a different line, so the judge still reds on a release that did not take.
  • The specification quotes hold against the two captures under acpi1-r16/spec/ (sha256 1ff59e14…d0f6, 6a238690…6339): §4.8.2.5 "polls the SCI_EN bit until it is sampled as RESET" with no time; Table 4.13's two sentences; Table 5.9's "synchronously from the boot processor", "as quickly as possible" and both reserved-as-zero sentences.
  • The new issues' quoted T14 lines hold against acpi1-r13 and acpi1-r9: cpu7 and 16687ns on the 8d7004d3b death boot, cpu7 again at ff4945d6d, the disable on cpu0 both times, cpu0 on every other boot there; 13371ns at 13.535 s and (Shutdown) at 13.540 s on the testcases-off boot.

BLOCKER

  1. PR body :7, :123, :187 — no T14 reading at this head. reviewer.md, Evidence: a change that targets hardware owes the reading from that hardware, and QEMU never runs leave (OVMF hands q35 over in ACPI mode). The poll, the rewritten line and the new order have run on nothing. The five boots in flight close this when the body carries, for each: the image's sha256 checked against acpi1-r16/images.sha256 before its flash, the boot's rc, and the judge's command, exit and log, run from the clean tree at 922a6b7c7. What each must show:
    • acpi_server_death (acpicase, 2d8c1f2f…ff8e): judge EXIT=0 with PASS acpi_server_death. Its kernel.log carries, in this order, acpi: ACPI mode: ACPI_ENABLE 0xf0 written to SMI_CMD 0xb2, SCI_EN set … after, the server's armed: line relayed by acpi_release, and exactly one acpi: legacy mode again: ACPI_DISABLE 0xf1 written to SMI_CMD, PM1a_CNT reads 0x0000 <duration> after, SCI_EN clear. The duration is what proves this head's kernel ran, and the body states it. No acpi: still in ACPI mode and no ACPI_DISABLE not written before the job list's stop. If still in ACPI mode appears, the row is red and HANDBACK comes back with the time the firmware took.
    • acpi_server_events (testcases-hold, ae15eb50…86a0): judge EXIT=0 with PASS acpi_server_events. The mint's ACPI mode: line, the server's armed: power button served, embedded controller on GPE 0x6e at 0x66/0x62, each first-sighting line once, and a counts line. No legacy mode again and no still in ACPI mode before the supervisor's stop line.
    • counters (shared c46cc487…4195, shared-debug 2ef538f3…c6d6, testcases abb72e22…939c): judge EXIT=0, "3 passed, 0 failed, 3 boot(s)". SMI flat on each of the 8 CPUs from idle0 to spin, the mint's line with its CPU's SMI count rising by one across the write, no line stamped in the idle second, and no legacy mode again.
    • The two judge commands print 2 passed, 0 failed, 2 boot(s) and 3 passed, 0 failed, 3 boot(s).
  2. PR body :23, issues/no-t14-row-reads-the-power-off-after-the-kernels-own-acpi-enable.md:37-41 — the QEMU monitor measurement has no command line, exit or log. The readings 0x0001, 0x0000 after o/b 0xb2 3 and 0x0001 after o/b 0xb2 2 are the only evidence that the gap issue's exit can be built with nothing shipped for it, and they exist only as prose: no transcript is under acpi1-r15/ or acpi1-r16/ or anywhere in the scratchpad. Post the whole QEMU invocation, the monitor transcript and the exit as a comment, and name it in the body. No change to the tree.

NOTE

  • issues/no-t14-row-reads-the-power-off-after-the-kernels-own-acpi-enable.md:46-47 — the named owner does not fit. issues/the-t14-reboots-through-ubuntu-for-every-test.md builds T14 sessions over ssh and its exit is read on the T14; round 8 kept it when the exit was a T14 row. The exit is now a q35 guest test of code the ACPI track landed, and nothing that track of sessions builds produces it. Own it by issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md, whose "power-off through the server" stage rewrites the power-off this test would red on. The orchestrator's to place; say so as his.
  • issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:88-93 — the exit does not say where the ten logs are read. Each of its boots ends in S5, and such a boot leaves no readback (gap issue :15-17). Name the source: the stick's log partition, copied before the next flash, as at ee6aadecb.
  • issues/the-t14s-power-button-event-came-up-to-17-s-after-ec-query-0x28.md:80 — "and none will" is broader than the ruling, which says "anything we cant do now with the t14". Delete the three words.
  • kernel/src/arch/x86_64/acpi_mode.rs:307-311, :215-217 — past HANDBACK the row is released with a disable outstanding. A firmware that acts on it later than 100 ms takes ACPI mode from the next holder, whose mint found SCI_EN set and wrote nothing: the race the new order closes inside the bound. The bound is the kernel's own number and no tier reaches the path. Record it with an owner, what is known and an exit, in issues/the-kernel-writes-smi-cmd-from-whichever-cpu-its-caller-runs-on.md or a file of its own. No kernel change is asked for this round: one would void the five boots in flight.
  • tests/metal/lenovo-20w0003amz.toml — no commit of the branch carries boot.acpicase.* or boot.testcases-hold.*, and the judge asks for them (acpi1-r16/judge-old-acpi_server.log: "commit it"). Commit the six numbers from this head's run. That moves the head: the new head owes cargo run -- --ci host EXIT=0, and git diff --stat 922a6b7c7 <new> showing the record and issues/ alone, so the guest and T14 readings stand for it.
  • PR body, Unsure, "a path this round did not trace for what it holds" — kernel/src/object/mod.rs:116 answers it: the hook runs from the deferred queue with no lock held.
  • PR body :7, :123, :187-196 describe the T14 rows as staged and unread; false once the five boots are posted.

SEND BACK

Japabu and others added 2 commits October 7, 2026 16:04
…is an issue

tests/metal gains the six numbers the acpi_server_ judgement measured on the
T14 at 922a6b7 (boot.acpicase.* and boot.testcases-hold.*), which no commit
of the branch carried.

Review round 9's notes, in issues/ alone:

- The gap issue is owned by the track's "power-off through the server"
  stage, which rewrites the power-off its exit's test reds on, and no longer
  by the T14 session issue, whose exit is read on the T14. The orchestrator's
  placement.
- The press issue's exit names where its ten logs are read: each boot ends in
  S5 and leaves no readback, so each is read off the stick's log partition.
  "and none will" went: the ruling is about what the T14 can do now.
- New: past HANDBACK the row is handed back with ACPI_DISABLE unanswered, so
  a firmware slower than 100 ms takes ACPI mode from the next holder. Recorded
  with its owner, what is known and an exit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

The SCI_EN measurement behind "QEMU can be put in legacy mode from outside" (review round 9, BLOCKER 2), run again this round. It touches no tree and boots no ToyOS image: bare QEMU 11.1.1, q35 under OVMF and TCG, driven through the monitor.

The script, orch/acpi1-r17/sci-en/measure.sh, whole:

#!/bin/sh
# What q35's PM1a_CNT (0x604) reads under OVMF, and after the monitor writes
# ACPI_DISABLE (3) and ACPI_ENABLE (2) to SMI_CMD (0xb2). No guest image.
cd "$(dirname "$0")" || exit 99
rm -f mon.sock vars.fd transcript.txt qemu.out
cp /opt/homebrew/share/qemu/edk2-i386-vars.fd vars.fd && chmod 644 vars.fd || exit 98

hmp() {
    printf '>>> %s\n' "$1" >> transcript.txt
    { printf '%s\n' "$1"; sleep 1; } | nc -U mon.sock >> transcript.txt 2>&1
    printf '\n<<< nc exit %s\n' "$?" >> transcript.txt
}

set -x
qemu-system-x86_64 -machine q35 -accel tcg -nodefaults -display none -m 256 \
    -drive if=pflash,format=raw,unit=0,file=/opt/homebrew/share/qemu/edk2-x86_64-code.fd,readonly=on \
    -drive if=pflash,format=raw,unit=1,file=vars.fd,readonly=off \
    -monitor unix:mon.sock,server=on,wait=off > qemu.out 2>&1 &
set +x
pid=$!

n=0
until [ -S mon.sock ] || [ $((n += 1)) -gt 20 ]; do sleep 1; done
[ -S mon.sock ] || { echo "no monitor socket"; kill "$pid"; exit 97; }

# Wait on the event, bounded: OVMF sets SCI_EN on its way to the boot manager.
n=0
until { hmp 'i/h 0x604'; grep -q 'portw\[0x0604\] = 0x0001' transcript.txt; } || [ $((n += 1)) -gt 60 ]; do :; done
echo "polls before SCI_EN read set: $n" >> transcript.txt

hmp 'info version'
hmp 'i/h 0x604'
hmp 'o/b 0xb2 3'
hmp 'i/h 0x604'
hmp 'o/b 0xb2 2'
hmp 'i/h 0x604'
hmp 'quit'
wait "$pid"
rc=$?
echo "qemu EXIT=$rc" >> transcript.txt
rm -f vars.fd mon.sock
exit "$rc"

sh orch/acpi1-r17/sci-en/measure.sh > orch/acpi1-r17/sci-en/run.log 2>&1 → EXIT=0, which is QEMU's own exit after the monitor's quit. Its run.log, the invocation as the shell ran it:

+ set +x
+ qemu-system-x86_64 -machine q35 -accel tcg -nodefaults -display none -m 256 -drive if=pflash,format=raw,unit=0,file=/opt/homebrew/share/qemu/edk2-x86_64-code.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=vars.fd,readonly=off -monitor unix:mon.sock,server=on,wait=off

Firmware, sha256: edk2-x86_64-code.fd 33090cc07675baa5190d9f1e84bf5176b33bcbfa9bacac522961150cdb6dbb2a, edk2-i386-vars.fd (the template the store is copied from) 5d2ac383371b408398accee7ec27c8c09ea5b74a0de0ceea6513388b15be5d1e. qemu.out is empty.

The monitor transcript, transcript.txt, every exchange in order. Each command is one connection to the monitor socket, hence the banner each time. The only edit is to the echoed command line, where the monitor's line editor redraws the line once per typed character with ESC[K/ESC[D; that redraw and the carriage returns are stripped, the raw file is beside it.

>>> i/h 0x604
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) i/h 0x604
portw[0x0604] = 0x0000
(qemu) 
<<< nc exit 0
>>> i/h 0x604
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) i/h 0x604
portw[0x0604] = 0x0001
(qemu) 
<<< nc exit 0
polls before SCI_EN read set: 1
>>> info version
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) info version
11.1.1
(qemu) 
<<< nc exit 0
>>> i/h 0x604
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) i/h 0x604
portw[0x0604] = 0x0001
(qemu) 
<<< nc exit 0
>>> o/b 0xb2 3
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) o/b 0xb2 3
(qemu) 
<<< nc exit 0
>>> i/h 0x604
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) i/h 0x604
portw[0x0604] = 0x0000
(qemu) 
<<< nc exit 0
>>> o/b 0xb2 2
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) o/b 0xb2 2
(qemu) 
<<< nc exit 0
>>> i/h 0x604
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) i/h 0x604
portw[0x0604] = 0x0001
(qemu) 
<<< nc exit 0
>>> quit
QEMU 11.1.1 monitor - type 'help' for more information
(qemu) quit

<<< nc exit 0
qemu EXIT=0

What it reads: PM1a_CNT at 0x604 is 0x0000 on the first poll, before OVMF has enabled ACPI, and 0x0001 on the next, as the firmware leaves it; 0x0000 after o/b 0xb2 3 (ACPI_DISABLE); 0x0001 again after o/b 0xb2 2 (ACPI_ENABLE). The readings are of QEMU's model of the ICH9 under TCG, not of any hardware.

@Japabu

Japabu commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

Review round 10 of #713 at 9dcfa09bc: 922a6b7c7, the merge 8b7b16ad6 of origin/main (df1a77221, #743) and one commit. Merge base is now df1a77221.

Net size, git diff --shortstat origin/main...9dcfa09bc: 85 files, +3667/−592. Production +2458/−470, unchanged by this round; tests/ + src/ + toyos-acpi/tests/ +814/−100; issues/ +395/−22. This round's own commit: tests/metal/lenovo-20w0003amz.toml +6, issues/ +37/−5 over three files. No production line.

Does the reading at 922a6b7c7 stand for this head

Yes. git diff --stat 922a6b7c7 9dcfa09bc is 7 files: README.md and two issues that are the merge's and equal origin/main's (git diff --stat df1a77221 9dcfa09bc over the three is empty; origin/main's own diff since the old base, f260e0b98..df1a77221, is those three files), three files under issues/, and tests/metal/lenovo-20w0003amz.toml. git diff --stat 922a6b7c7 9dcfa09bc -- kernel userland toyos-abi toyos toyos-acpi src tests bootloader Cargo.toml Cargo.lock system.toml names the metal record alone. That record's one reader is src/metaltimings.rs:23 (DIR), the T14 judge; no image and no guest test reads it. The guest suite at 922a6b7c7 (acpi1-r16: guest EXIT=0, 30 of 30) and the five T14 boots are of the same kernel, userland and harness as this head's.

Host at this head: acpi1-r17/host.head is 9dcfa09bcdef…3276, host.exit host EXIT=0, host.log:8403 "Host: 76 step(s), all green", host.status-after empty. Load average 36.30 at its start.

Round 9

  • BLOCKER 1 (no T14 reading at the head): CLOSED. Per boot, from orch/t14-713r16.log and the readbacks under acpi1-r16/:
    • Images. The run log's five sha256 values equal acpi1-r16/images.sha256 line for line, and shasum -a 256 of the five image.img files, recomputed this round, gives the same five. Each boot's rc is 0, the script's rc is 0, every verdict.txt is passed, every boot.txt names the same machine and firmware. The judges ran the test binary toyos_build-1b8e461cc3d9c78f, the one stage.sh built at stage.head 922a6b7c7… on a tree its stage.status records clean.
    • acpi_server_death, acpicase (2d8c1f2f…ff8e): kernel.log:346 the mint's ACPI mode: ACPI_ENABLE 0xf0 written to SMI_CMD 0xb2, SCI_EN set 16752ns after on cpu7, SMI 4807 to 4808; :351 the armed: line relayed by acpi_release; :364 exit: acpiserver pid=9 code=137; :365 acpi: legacy mode again: ACPI_DISABLE 0xf1 written to SMI_CMD, PM1a_CNT reads 0x0000 17068ns after, SCI_EN clear on cpu0. That order. legacy mode again 1, acpi: ACPI mode: 1, still in ACPI mode 0, not written 0, over 385 lines; the stop is :385. The line's shape with a duration is kernel/src/arch/x86_64/acpi_mode.rs:317 at this head and no earlier kernel's, so this head's leave ran on the T14 and its firmware answered in 17068 ns, inside the 100 ms bound.
    • acpi_server_events, testcases-hold (ae15eb50…86a0): :348 the mint's line on cpu0, SMI 4818 to 4819; :354 armed: power button served, embedded controller on GPE 0x6e at 0x66/0x62; :367 query 0x4f's first sighting, once; :368 26 SCIs; embedded controller queries taken: 0x4f x13; :369 held to 54000 ms; :387 the stop at 66.203 s. legacy mode again 0, still in ACPI mode 0, not written 0.
    • counters, shared (c46cc487…4195), shared-debug (2ef538f3…c6d6), testcases (abb72e22…939c): the mint's line at :347 of each, cpu0, SMI 4818→4819, 4819→4820, 4818→4819. legacy mode again, still in ACPI mode and not written are 0 in all three. On testcases, kernel.cpu.<n>.smi occurs 24 times, 8 CPUs at each of idle0 (15266218180 ns), idle1 and spin, every one 4819; :367 is stamped 15.264 s and :368 27.244 s, so no line lies in the idle second, and the first query came at 14.968 s (:365), before it.
    • Judges: metal-acpi_server/judge-acpi_server_.log ends [metal] 2 passed, 0 failed, 2 boot(s) with PASS acpi_server_events and PASS acpi_server_death; metal-counters/judge-counters.log ends [metal] 3 passed, 0 failed, 3 boot(s) with PASS counters and "8 cpus, SMI flat on each over 12182 ms". The run log records EXIT=0 for both. The body carries all of it, per boot.
  • BLOCKER 2 (the QEMU SCI_EN measurement had no command, exit or log): CLOSED. Comment 6039735451 is byte-identical to acpi1-r17/sci-en/comment.md and carries the whole script, the QEMU invocation as the shell ran it, the firmware hashes and the transcript. run.exit is EXIT=0, the transcript ends qemu EXIT=0. The raw transcript.txt reads portw[0x0604] = 0x0000 on the first poll and 0x0001 on the second, 0x0001 before the write, 0x0000 after o/b 0xb2 3, 0x0001 after o/b 0xb2 2; the posted transcript differs from the raw one only in the line editor's redraws and carriage returns. The gap issue's three readings (:37-39) are these. The body names the comment.
  • NOTE gap issue's owner: CLOSED. issues/no-t14-row-reads-the-power-off-after-the-kernels-own-acpi-enable.md:46-49 names the stage "power-off through the server", which exists (issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md:125), and says the placement is the orchestrator's. No citation of the old owner is left in the file.
  • NOTE press issue's exit names no source for the ten logs: CLOSED (:92-94).
  • NOTE "and none will": CLOSED, deleted (:80).
  • NOTE the release past HANDBACK: CLOSED. issues/the-acpi-row-is-released-with-an-acpi-disable-the-firmware-has-not-answered.md: kind: defect, status: open, a pairing issues/README.md allows; its account matches acpi_mode.rs:214-219 (the next mint logs that nothing is written and returns Ok) and :307-311 (the expiry's line); the 17068 ns it quotes is acpicase/kernel.log:365; its owner, the ACPI track, exists; its exit is a test that reds and reaches the expiry. No kernel change, as asked.
  • NOTE the six numbers: CLOSED. The commit's hunk of tests/metal/lenovo-20w0003amz.toml is judge-acpi_server_.record-rows.patch line for line, and the numbers are the judge log's (1207 ms and 1212 ms complete). The host suite ran at the new head with them.
  • NOTE Unsure's untraced path, NOTE body lines calling the rows staged and unread: CLOSED, both rewritten in the body.

What the round added

Read whole: the three changed issues, the new issue, the metal record's hunk. Nothing outside issues/ and the record. The new issue is filed under its own slug and cited by no other file; the track file is unchanged this round and its two stage placements still say whose they are. No new finding.

BLOCKER

None.

NOTE

None.

LAND

@Japabu
Japabu marked this pull request as ready for review October 7, 2026 14:21
@Japabu
Japabu enabled auto-merge October 7, 2026 14:21
@Japabu
Japabu added this pull request to the merge queue Oct 7, 2026
Merged via the queue into main with commit 257ebea Oct 7, 2026
6 checks passed
@Japabu
Japabu deleted the wt/toyos-acpi1 branch October 7, 2026 15:22
Japabu added a commit that referenced this pull request Oct 7, 2026
userland/Cargo.toml conflicted: #713 added the member `acpiserver` on the
line this branch added `acpiserver/aml`. Both hold, in order.

The track merged without a conflict and came out with two stages named "the
interpreter": #713's, which the ACPI server runs and which owns the T14's
press issue, and this branch's, the crate and its host exit. The press issue
names its owner as the stage "the interpreter", so they are folded into one
stage carrying both exits. This branch's "inside the server that uses it" is
dropped with the fold: /system/bin/acpiserver now exists and does not link
the crate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
Japabu added a commit that referenced this pull request Oct 7, 2026
None of the three moved the fork pin or touched a file under sdk/std or
one of the 21 paths the backend left. #740 filed
issues/std-says-a-launch-moves-its-handles-to-the-launcher-even-when-the-move-is-refused.md
against the backend's old paths in the fork; its two citations now name
sdk/std/sys/process.rs and sdk/std/os/process.rs, and its owner and exit
a commit here rather than a fork commit with a gitlink bump. The comment
it quotes is at sdk/std/sys/process.rs:576, unchanged by the move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant