Repository navigation
usbd drives every xHCI controller; the kernel drives no USB - #971
Conversation
Step 10 of the small-kernel track, stage 4 of the device-function track. usbd is a `drives` row, one process per xHCI controller: its sticks are disks offered to the block service on `disk`, whose sessions it serves straight out of each client's region, and its keyboards and pointers report to the owner of input over `input`, each bound collection a `source` of its own. The driver (system/usbd/xhci, moved from lib/xhci) is rewritten as tasks on one thread, each waiting on one thing: the answer its TRB is matched by, a deadline, or a change another task made. A deadline is never a cancellation: an operation the controller holds is taken back by Command Abort or by Stop Endpoint and Set TR Dequeue Pointer, and dropping one unanswered is a panic. It is generic over toyos-device-memory's traits and tested against a stub xHC written from xHCI 1.2, with the three tests the step's exit named and the one it owed: a stick whose bulk endpoint never answers leaves a keyboard on the same controller delivering every report. Events are taken on each interrupt record: IMAN.IP is cleared before the ring is read and ERDP is written with EHB on every pass (xHCI 1.2 §4.17.2, §5.5.2.3.3), so an interrupt that found nothing still leaves the next one announced. HID interfaces are bound by their report descriptor in report protocol (lib/usbhid, moved from kernel/usbhid): arrays read as indexes, bitmaps as keys, HUT's reserved usages and 00-03 named no key, a collection this reader cannot bind costing only its own reports, absolute axes scaled onto the record's range. Mass storage keeps its Bulk-Only round trip and ladder; a disk whose port its ladder reset is held for its return and given back only to a device of the same identity. Deleted from the kernel: the xHCI driver, USB storage, the block layer, GPT, the keyboard and mouse streams, partition claims and SYS_PARTITION_*, usb_gate, irq_ring, drain_irqs, the scheduler's Operation framework, sync::OwedLock with its loom test and fence feature, and the xHCI and USB actuators. A reset stops every claimed function's bus mastering and messages (pcidev::stop_before_reset) in place of the xHCI stop. From the ABI: the Keyboard and Mouse device and file types, Partition, and the USB, block and partition inventory records. Beside it: TrySendError::Busy says a frame went nowhere, so a full peer is waited for rather than dropped; a PCI matcher may name a place (`@03:00.3`), so the AMD bench's boot controller is driven and its other one left to the claim tests; the input port's holders are ps2server and usbd. The harness loses the rows whose kernel actuators went and gains `usbd_serves_the_boot_stick`; the spare tests claim the controller no row names, with a claim on the held boot controller as their control. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
crypto_instrument_prints_its_table hung on most runs beside eleven other rows under host load. Temporary probes placed every byte on the guest's side of the pipe. logkeeper read the runner's ring through to its head and wrote every rendered byte to its console. The kernel's console queue was empty, klogd owed no record, and the runner's own watchdog showed that it had printed its end marker. The hang also happened at the branch's base and with no usbd in the image. This commit records the sighting in the issue that already owns the loss. The probes are not committed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every metal boot's /log now goes logkeeper -> the LOG file server -> diskserver -> usbd -> the boot stick. No QEMU row read that path: their console is the serial line, and the metal judges are the only readers of the stick's log volume. #971's first metal boots came back with no log file on the stick, which nothing before metal could have seen. the_log_lands_on_the_boot_stick boots testcases from a stick on Profile::Metal, asks for the shutdown, and reads the stick's log volume back on the host (toyos_build::image::log_volume_files, read with the kernel's FAT driver). It judges it with the metal judge's own verdict. Its negative control turns every write into a read in usbd's Disk adapter, so the writes never reach the stick. It is red with the metal boots' signature: no logkeeper file on the volume. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #971 at
|
Review round 1 of #971. - Device::restart returned from a failed CLEAR_FEATURE(HALT) without reclaiming the held transfer, so dropping its Op panicked usbd. That dropped every device on the controller. It now reclaims it: Recovery orders the clear after Set TR Dequeue Pointer, so the ring is already past the TRB. The stub can now halt an endpoint with its event lost (Reply::StallUnannounced) and make a stick stall CLEAR_FEATURE. a_halt_whose_clear_feature_stalls_costs_only_its_stick passes. With the fix reverted it panics at the Op drop. - Dead code and stale text: PciId::parse and its xhci-leave test, Hc::change_waiting, Inputs::not_given's accessor, CONFIG_BYTES's reset-stop rationale (now private), a link to the deleted PciDevice::message, the kernel Cargo.toml's history line, bcachefs's citation of the deleted BudgetExpired rule, end_returns_claims' xhci-leave doc, the stub's path in toyos-xhci's Cargo.toml. - The two new findings and the hot-plug defect name their owners. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 of #971. The kernel's USB keyboard path and usb_keyboard_rollover went with this PR. Before this row, no guest or metal row carried a report from a real xHC through usbd to an owner of input. a_usb_key_reaches_the_console boots images/console.toml, whose usbd receives `input`, on Profile::MetalUsbKeyboard (Metal with a usb-kbd, which every QMP key then goes to). It types `ls` and Enter, and waits for the console's shell to spawn toybox. QEMU's xHC and keyboard are the independent end the stub cannot be. Its negative control has usbd's input port drop every key record, and the row stalls. usbd_serves_the_boot_stick no longer judges the log volume's mount. It holds the kernel's part only, as its comment and #901 say. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and its controller Review round 1 of #971 (finding 1), on the orchestrator's ruling: the stick protection the kernel's xHCI stop gave, after the owner's run-18 ruling ("ToyOS must not brick a USB device"), moves into usbd's stop path. - The supervisor endows every disk-driver instance a `stop` pipe (toyos_quiesce::DRIVER_STOP). After logkeeper's flush and every file server's sync, it closes the pipes and waits for each driver to end, within DRIVERS_MS (3 s). A driver that does not end in time is named, and the machine stops without it. If the kernel refuses the stop, the drivers' functions are driven again. - usbd, told: its driver ends (`ending`, so the operations its tasks held are let go), and Hc::stop runs within STOP_NS (2 s). It resets every connected port at once while the controller still runs, which returns each device to Default with no command outstanding (USB 2.0 §7.1.7.5). TRSTRCY follows if a USB 2 device was reset. Then RS is cleared and HCH awaited, HCRST runs, and the ports are unpowered where the controller has Port Power Control. Its exit code is the account the kernel always records: 0 only if every connected port's reset finished (PR clear and PRC set after this write) and the controller halted and reset. - nvme, told: a normal shutdown (CC.SHN, awaited on CSTS.SHST, NVMe Base 2.0 §3.6.2), and it ends. - If no usbd is running when the machine stops (it died, or the boot deadline, the hard-lockup detector or a panic is what stops it), nothing resets the ports. A usbd that died had its function reset by its claim's release, FLR or the D3hot round trip, and the kernel's stop clears Bus Master. The device sees the platform reset alone, which #901 §6 accepted and stick_survives_a_reset_under_load measures. - SDK: a pipe end can be taken from the endowment table (FromHandle). Tests: - the_stop_resets_every_connected_port_then_halts_resets_and_unpowers_the_controller, on the stub, with a stick command left open. - the_log_lands_on_the_boot_stick now also judges that usbd ended with 0 between the stop's request and the kernel's stop. - Controls: the supervisor telling no driver (red on the order), and the stop writing no port reset (red on the stub and in QEMU, exit 3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r load Review round 1 of #971 (finding 1). #901 §9's row lands with the stage that deletes the kernel's port-reset stop. - stick_load (a guest job) writes /home on the stick for ever through usbd: an 8 MiB file rewritten in place, fsync'd after every MiB. - stick_survives_a_reset_under_load (metal, T14 and AMD) boots testcases with that job alone. A boot carrying it is given a 40 s deadline, below its runner's list bound, so the kernel's reset path, which touches no USB register, lands while the job writes. Judged: the deadline expired (the pass after the reset says so), the job's lines reached /log, and the stick enumerated on the next host within the bench's record (boot.usbload.stick_secs, timings::ceiling). A host check feeds the judge a passing page, a page with no load, and one handed back. - stick_load is kept off the shared boot (RUST_SKIP). - the_log_lands_on_the_boot_stick now asks for the stop under the same load (the power button, pressed while stick_load writes), so usbd's stop is exercised with writes in flight. Its three controls (usbd's writes turned into reads, the supervisor telling no driver, the stop writing no port reset) are each red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 of #971 (finding 1). These are #901 §9's other two rows. Each rides a boot that already runs, so neither costs a boot of its own. - tone_beside_a_stick_write (metal, T14 and AMD, on testcases): tone_beside_stick_write plays hda_tone's tone while a thread of its process writes /home on the stick through usbd, fsync'd every MiB. It owes at least the mebibyte the issue names. The verdict is soundserver's underruns=0 over the job's window: the exit of issues/a-megabyte-written-to-the-stick-starves-a-tone-beside-it.md. - mask_windows also reads every CPU's longest windows under stick_write (32 MiB through usbd, then an end), run after the herd on windowscase. They are judged against the bench's record (boot.windowscase.stick_write.*, timings::ceiling), which is the base #901 asks for. - Both jobs are kept off the shared boot. In QEMU (MetalTwoHda), checked by hand and not committed: stick_write wrote 32 MiB and ended 0, and tone_beside_stick_write wrote 251904 KiB beside the tone and ended 0 with underruns=0. QEMU's timings judge nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 of #971 (finding 5). - The small-kernel track: stage 4's Left, the step tally, step 4 (now done: the stick's partitions are diskserver's through usbd, and SYS_PARTITION_* are gone), and step 7 (now done on the stick too). Step 10's claim about HID was false for every test image, whose usbd receives no `input`; it now says which image delivers HID and what the stop does. Its evidence gains the stick row, the stop test and the USB key smoke. Its Left names the metal rows that have not run, the missing log file of #971's first metal boots, and the client test that /log's evidence still owes. - a-cut-bulk-only-command-does-not-brick-the-benchs-stick: every survival in its table was measured with the kernel's port reset in place. Its present state now says what replaced that reset and what does not reset ports at all, and names the guard that replaced the old one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
clippy's double_ended_iterator_last. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 of #971's suggestion: start recomputed it inline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Round 1 is answered on 1. The stick protection (on the orchestrator's ruling),
How the protection is shown before the stick test runs:
The three #901 §9 rows are in this PR, none deferred (
2. 3. x1 was rerun on the final driver code. It is red on the same assertion ( 4. The judge no longer requires the mount, as its comment and #901 say. 5. All of finding 5 is done (
6. Suggestions:
Still open.
|
…bd-2 Each conflict was resolved for both intents: - toyos-untrusted is gone (main, 6699efb) and so is kernel/usbhid (this branch). The workspace keeps lib/usbhid, and the kernel depends on neither. - kernel/src/mm/dma.rs keeps main's comment, without copy_to, which only the deleted xHCI driver called. - SYS_PARTITION_* stays deleted (dispatch.rs), as do kernel/src/drivers/xhci and the-boot-volumes-server-holds-a-claim-that-writes.md. Main's edits to them are untrue now: the boot volume is a read-only session through usbd. - tests/toyos.rs takes main's stdio and launch rows with this branch's spare wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the orchestrator's ruling in #971's review. On a bench whose units remap no message, every claim is refused, usbd's included. That machine drives no USB, so its stick receives no /log, and a judge that reads /log can only fail. amdvi_claim_refused_without_remapping is deleted, as asked, and so is claim_refused_without_remapping: the same `iommu-no-remap` boot, for the same reason. With them go everything only they used: the kernel's iommu-no-remap actuator (VT-d's and AMD-Vi's arms), its FLASHABLE entry, claims::refused_unremapped, and the usbd_spare_unhanded binary. QEMU keeps the refusal, by usbd_refused_without_amdvi_remapping and amdvi_firmware_left. The track, the IOMMU issue and the two issues that named the rows say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The T14's diagnostic boot (19c3beb56) showed the race. usbd said "settled, 0 device(s) named" at 12.622, as soon as it ran. Its ports had been powered again a moment before and its stick did not read connected yet. The block service then answered LOG and BOOT NotFound, logkeeper had no /log, and the stick's disk was offered at 12.868, 246 ms too late. QEMU's ports connect the instant they are powered, so no QEMU boot showed it. Every port is now unsettled at the start, whether or not it reads connected. A connected port settles once its device is enumerated or given up on by name, as before. An empty port settles once its attach window has passed with nothing connected. The window is the most a device present at power-on may take to be seen: TSIGATT, 100 ms on a USB 2 port (USB 2.0 §7.1.7.3, Table 7-14), and tPollingLFPSTimeout, 360 ms on a USB 3 port (USB 3.2 §7.5.4.3). The port task waits for a port status change or the window's end. A device that arrives later is a hot-plug. EMPTY_BUS_NS and SLOW_CONNECT_NS, which nothing read, are gone. Tests: - a_stick_that_connects_after_the_start_is_offered_before_the_bus_settles - an_empty_bus_settles_when_its_attach_window_ends Both are red on the old rule, which settled a port that read disconnected at the start (mut t1). QEMU cannot reproduce this. A stick hot-added there is enumerated about 600 ms after the plug, past both windows, so no QEMU row reds without the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The AMD bench's diagnostic boot (19c3beb56): usbd panicked with a
backtrace on "the kernel refused a DMA grant: Faulted". diskserver then
waited its whole 30 s bound for the driver that had died, and answered
DATA, BOOT and LOG Unusable.
- usbd: every refusal before it serves is said once ("NOT SERVING — ..."),
the block service is told the controller is unusable, and it idles until
the machine stops. This covers the claim's description, the register map,
the controller, the grant and the run. A controller lost while served
(Dead, or the claim refusing its interrupt record) is said ("ENDED —
...") and the process exits 2, which releases the claim. Only invariant
breaks still panic.
- diskserver: Known::ended. A driver that never settled is Unusable as soon
as its connection ends, so a listing or open waiting on it is answered
then. A settled driver's end is still awaited until it settles again.
Test: a_driver_that_ends_before_it_settles_is_unusable_at_once. The old
rule, which forgot the driver, is red (mut d1).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m the first hand-over The AMD bench's diagnostic boot (19c3beb56): firmware had not let go of the boot xHC after usbd's 1000 ms (USBLEGSUP 0x00010401 -> 0x01010401, BIOS Owned still set). The kernel attached the claim's domain to a function firmware left mastering the bus. The controller's own accesses were refused (cpu0 dmafault=3). The fault latched on the claim before usbd's first grant, so the grant was refused Faulted. bring_up now clears Bus Master Enable, and drains what the function posted before it, before the domain is attached. With the bit clear a function issues no memory request (PCIe Base 6.0 §7.5.1.1.3). This makes Bound::mastering, false until the first grant, true of the function and not only of the record, on a first hand-over as on every later one, where release had already cleared it. The first grant sets the bit again, after usbd has halted and reset the controller. It is not a reset, and it writes only the one bit every function has. It prevents the stale access rather than excusing a fault that was recorded, so the fault policy is unchanged: a fault after the first grant is still the holder's. The black box kept no DMA FAULT record (the probe's section was full), so 03:00.3 as the faulting function is read off the latch that refused its grant, not off a record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ant, from the first hand-over" This reverts commit cc789d1. The owner's K2 direction (2026-10-21) puts safe hand-over before DMA, with its hold-off and activation, under K (wt/toyos-dma-limit). #971 builds no kernel mechanism for it. The AMD bench's boot xHC is left unavailable by name in usbd instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eft as found The owner's K2 direction (2026-10-21) says a device without a safe path stays unavailable, with the reason stated. The AMD bench's boot xHC kept HC BIOS Owned set past usbd's 1000 ms wait (USBLEGSUP 0x00010401 -> 0x01010401), and usbd reset it anyway, under firmware that may still have been driving it. take_from_firmware follows xHCI 1.2 §4.22.1: it sets HC OS Owned and waits HANDOFF_NS for HC BIOS Owned to clear (USBLEGSUP, §7.1.1; the specification gives no bound, so this one is policy). If firmware releases the controller or never claimed it, its SMIs are turned off and the controller is usbd's. If firmware keeps it, Reset::new refuses with Refusal::FirmwareKeepsIt. Nothing more is written: no SMI change, no halt, no HCRST. usbd says NOT SERVING with that reason, tells the block service the controller is unusable, and serves nothing. A safe way to take such a controller is the kernel's to give: K's hand-over and activation (wt/toyos-dma-limit). This PR builds no kernel mechanism for it. The stub can now model firmware that keeps the semaphore. a_controller_firmware_keeps_is_refused_and_left_as_found holds the rule: USBCMD untouched, no SMI write. The old reset-anyway rule is red against it (mut f1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…judged by its seal The T14's round 3 at e729c3e found two defects. - "32204 MiB written and synced" in a 40 s boot is about 800 MB/s, far beyond any stick. The readback shows why: "this machine has no DATA partition; /apps, /config, /home and /state are in memory". A metal test image carries no DATA partition, so stick_load, stick_write and tone_beside_stick_write all wrote memory, and no row tested what it claimed. All three now write lines to /log (stick_lines.rs): - 900-byte records at 2000 a second, under logkeeper's per-child allowance, so none is suppressed; - logkeeper writes them to the stick through usbd and syncs every round. What reached the medium is counted by each judge in the file read back off the stick (metal::bytes_of_lines), never from the job's own claim. Each judge needs at least a mebibyte: stick_survives_a_reset_under_load, tone_beside_a_stick_write, and mask_windows' stick write. - usbload came back refused by the readback gate, which asks every unarmed boot for the supervisor's stop line, and a deadline boot never reaches it. ended_by_its_deadline (toyos-metal) declares a boot from its own artifact: armed to wedge, or carrying a deadline below the least list bound a runner gives, as only STICK_LOAD_JOB's boot does. Such a boot is judged as a wedge is, by the record its bound sealed, and it is refused if it handed back. Host test: a_boot_its_deadline_ends_on_purpose_is_judged_by_the_record_it_sealed. Applied to the real readback, the gate now answers Ok. - the_log_lands_on_the_boot_stick waits for 1500 of the load's lines and judges what reached the volume. It now reads the stop's request from the file and usbd's end and the kernel's stop from the console, ordered on the boot's own clock. Under a flood the console can drop the supervisor's line. Controls rerun: s1 and s2 red as before. l1 (writes made reads) now stalls waiting for the load, which is red too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
T14 round 4 at fa0f434: stick_survives_a_reset_under_load was refused because "usbload's own log is missing its parts 2 to 56". The parts were not lost to the reset. logkeeper keeps at most 16 files of a mebibyte (MAX_LOG_FILES) and deletes the oldest of this boot's own parts to stay there, as its log says ("/log holds more than 16 logs, so ..._0042.log was deleted"). At 2000 lines a second (1.8 MB/s) the load wrote 72 parts before the deadline. The 16 kept parts are on the medium whole: the readback holds 17727 of the load's lines, about 16 MB, and passed its FAT check. stick_load now says 200 lines a second, about 180 KB/s. That is still a write and a sync on the stick every logkeeper round, and a boot's log stays inside retention until the deadline ends it. The other two loads end within their boots and keep 2000 a second; say takes the rate per caller. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…leaves, and no more T14 r5 at d36af38: the usbload boot ran until its deadline, and the readback refused its log partition: "/2026-10-21-094046_0008.log: DIR_FileSize is 200402 bytes, which needs 392 clusters, and the chain holds 394; FSInfo: FSI_Free_Count is 53763 and the FAT has 53761 free clusters". That is the designed crash state, not a writer-ordering defect. toyos-fat32 claims a cluster as end-of-chain before linking it and writes the size last (lib/fat32/src/repair.rs, the open windows), so a stop inside an append leaves a chain longer than its size and a free count that is a hint (fatgen103 §5: FSI_Free_Count "is not necessarily correct"). No byte the size names is lost. The fileserver crash test reaches this state, and it now asserts that it does: a stop fell between the chain's growth and the size's write. - toyos_fat32_check::unexplained_by_a_stop says what of a check no stop can explain. It lets lost chains, one entry's copies disagreeing, the free count, and one file's chain too long through. It refuses a second grown file, a short chain, a cross-link, a cycle and every broken entry. - toyos-metal applies it only to a boot its deadline ends (ended_by_its_deadline) and prints each state it lets through. Every other boot still owes a volume with nothing to say about it. - Tests: the r5 complaints accepted for a deadline boot and refused for an ordinary one, and a short chain refused for both. The checker crate's own test covers the rule. - Nothing on the mount path takes the leak back. That is recorded with its exit in issues/a-stop-mid-append-leaves-a-fat-volume-s-leak-for-ever.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Orchestrator, T14 rounds 4–6 (hashes verified): at fa0f434 |
#974 changed the kernel xHCI driver and the old usbd binary (system/usbd/src/hc.rs), both of which this branch deletes. They stay deleted, and their new limit and start calls are carried into the new usbd in the next commit. dispatch.rs takes #974's two DMA syscalls, and SYS_PARTITION_* stays deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…troller firmware keeps On #974's hand-over contract. A claim's function masters nothing until its holder starts it (SYS_DEVICE_DMA_START), and every grant and lend is placed below the limit the holder states (SYS_DEVICE_DMA_LIMIT). - After the firmware handoff and the controller's halt and reset, usbd states its limit. That is 64 bits, or 32 where HCCPARAMS1.AC64 is clear (xHCI 1.2 §5.3.6). It then takes its grant and starts mastering before it writes any address to the controller. A controller without AC64 is no longer refused: #974 places its grants below 4 GiB. - A controller firmware keeps (HC BIOS Owned still set after HANDOFF_NS, §4.22.1) is now taken, by name, with its SMIs off. Until usbd starts it, its bus mastering is off, so the halt and reset cut no transfer of firmware's that could reach memory (PCIe Base 6.0 §7.5.1.1.3). That is the AMD bench's 03:00.3. The previous commit's refusal stood in for this contract until it landed. - A refused limit or start ends usbd by name, as every other refusal does. - Test: a_controller_firmware_keeps_is_taken_by_name_with_its_smis_off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The next commit deletes `MAX_CPUS`, which this assertion names. The owed word's own runtime bound stays: `OwedLock::try_lock_or_owe` refuses a cpu id past bit 63 by name. PR #971 deletes the kernel xHCI driver and `OwedLock` with it; once it lands this commit has nothing left to change and goes in the rebase onto it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The next commit deletes `MAX_CPUS`, which this assertion names. The owed word's own runtime bound stays: `OwedLock::try_lock_or_owe` refuses a cpu id past bit 63 by name. PR #971 deletes the kernel xHCI driver and `OwedLock` with it; once it lands this commit has nothing left to change and goes in the rebase onto it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
usb_stopped_before_the_reset matched "kernel] exit: usbd pid=" in the
console's text, but the kernel tags a record made on a thread's context
with its tid ("[15.227 cpu1 kernel tid=1] exit: usbd ..."), so a correct
stop whose exit was recorded that way was refused as missing. Each line
is now parsed by toyos_logstream and matched by its source and the start
of its text, as every other reader does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Kept this branch's deletions of the kernel xHCI, irq_ring, log recovery and the scheduler's Operation framework, and with them #976's per-CPU fields for irq_ring and the no-task operation slot. fileserver takes #975's descriptions without the partition claims this branch removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ize stated
usbd stalled the AMD bench's boot stick (1022:1639) in six of seven boots
under 2000 log lines a second: a bulk transfer the controller never
answered, with no event on the ring, and in two of three probed boots the
controller halted or in error (USBSTS HCH|HSE|HCE). The kernel's xHCI it
replaces moved every transfer through a bounce buffer as one TRB; usbd
moves a client's region directly, so a data phase that crosses 64 KiB is
a TD of several TRBs, and those broke three rules of xHCI 1.2:
- TD Size (§4.11.2.4) "shall be valid in all Transfer TRBs" (§4.11.7):
it was 0 in every TRB, which names each the last of its TD while its
Chain bit says another follows. hc::normal_td states the packets left
after each TRB.
- "A TD Fragment shall not span segments" (§4.11.5.1, §4.11.7.1): a TD
could cross the ring's Link. One that would not fit now starts on the
ring's first TRB behind a Link TD put where it would have begun, which
§4.11.7 allows ("One or more Link TDs may precede or follow a TD"); the
Link at the ring's end never carries a Chain bit now.
- "The first TRB of a TD Fragment is written last" (§4.11.7.1): each TRB
was handed over as it was written. The first is now put with the
controller's cycle state inverted and handed over once the rest is.
Which of the three this controller trips is not separated: the probes
read the controller's state, not the rule. The stub now refuses a TD that
crosses the Link; a_td_that_would_cross_the_rings_link_starts_behind_it
laps a bulk-out ring with TDs at every offset (red with the old placement:
"a TD crosses the ring's Link"), and a_tds_size_counts_the_packets_left_
after_each_trb checks hand-counted TD Sizes (red with TD Size 0).
A bulk endpoint stating a max packet size of 0 is refused at its binding.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Folding amdvi_usbd_drives_its_own_entry into the shared testcases boot (this branch dropped main's separate xhci-leave boot, as the kernel no longer drives a controller to leave) put its staged faults beside amdvi_translates_the_stick_controller and amdvi_remaps_the_stick_controller, which refused any DMA FAULT on the boot. The first AMD boots to reach those judges (r14) went red on 03:00.4's aimed read at 0x50400000: the fault test_rs_usbd_spare_fault stages, past the spare's grant on purpose. Those two now refuse every fault but the spare's, which amdvi_usbd_drives_its_own_entry judges by address and access. That row also waited for "usbd 03:00.4: the claim refused its interrupt record (Io)", which usbd says as "usbd 03:00.4: ENDED — the claim refused its interrupt record (Io); ..." since it ends by name. The six r14 readbacks, whose image this commit leaves byte-identical, judge green on all five AMD testcases rows; one with a fault on 03:00.3 added is red on both no-fault rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
r2: focused review at
|
… amdvi_usbd refuses an unstaged fault Review r2 of #971 (B3-B5). B3. Before early Links every lap wrote slots 0..=254, so each held the last lap's cycle, never the one the controller expects next (§4.9.2). A Link put early at slot t closed a lap leaving t+1..=255 with the cycle of the lap before, which is the next lap's: once that lap's tail rested in the gap, or a Set TR Dequeue put it there, the controller would run a TRB two laps old. Ring::link now writes the closing lap's cycle into every slot it skips, the ring's own Link included. the_controller_takes_each_td_and_stops_at_the_tail walks the ring as the controller does over 20000 TDs of 1 to 3 TRBs, the reviewer's lap first, and after each requires that exactly that TD is taken and the walk stops at the tail; without the marking it takes slot 254 two laps old. B4. An early Link at t followed by a TD of more than t TRBs overwrites the Link before the controller follows it. Ring::room is now (RING_TRBS - 1) / 2, so a TD that forces an early Link fits before it; the_longest_td_leaves_the_early_link_before_it_whole is red at the old bound of 255. Every TD usbd puts is at most 3 TRBs. B5. amdvi_usbd_drives_its_own_entry now counts every 03:00.4 record and requires exactly the staged two: the aimed read at the address the job names, and the foreign vector's access=none IO_PAGE_FAULT. The six r14 readbacks pass; one with a third 03:00.4 record added is red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review r2, at 421c2b3:
Checks at 421c2b3: |
r3 at
|
A one-off accuracy audit of 117 open defect records (batch 0 of 4). Each claim was checked against origin/main at 6f4d8db and the owner's uncommitted planning in the primary checkout, then brought onto db0cf63 (#971, #978, #980) and the records whose cited code #971 removed checked again there. The per-record classification, with file:line evidence, is in the PR. Deleted as fixed. For each, which halves of the exit were met, and which were judged unnecessary and why: - a-file-server-killed-mid-sync-leaves-a-half-written-btree: met whole. 3adcf42 made DATA's commit shadow paging, the superblock written last after a flush, and its host test, lib/bcachefs/tests/crash.rs, stops a commit at every block write, torn sectors and a lost block 0 included, and mounts what is left: the exit's own test. The residual defects are owned by a-write-over-a-files-committed-page-is-not-shadowed and a-crash-leaks-the-blocks-of-its-last-commit. - a-long-name-entry-whose-write-was-refused-is-on-the-volume-and-the-create-erases-nothing: the QEMU half is met by a cheaper test, the T14 half judged unnecessary. 0d73b99 removed erase_inserted; write_entry_at queues the old bytes as a repair before every write, so an entry write refused after it landed is written back. lib/fat32/tests/refused_writes.rs models the device the exit asked QEMU to stage, a write that lands and is answered with an error, as a host test: `cargo test -p toyos-fat32 --test refused_writes every_refused_write_of_a_long_name_create_is_undone` exit 0 at 6f4d8db, 24 refused and landed cases on the record's own file name, each checked by toyos-fat32-check. The T14 fat check of a usb-transport-break boot was not run: the mechanism is the crate's and the host model reaches every write, and since #971 that actuator no longer exists, so the arm cannot be staged. - a-replacement-netstack-reuses-its-predecessors-ports: met. Since 4b96de0 netstack runs ToyOS's own stack, whose TCP ephemeral ports are RFC 6056 keyed draws from keys each process takes from the system's randomness, the remedy the record named; NetDaemon's fixed 49152 is gone. Its citation in netstack-ends-for-the-boot-on-a-nic-it-cannot-drive-on.md goes with it. - a-disk-whose-port-went-away-panics-the-boot-at-roots-hold was fixed by 602cff0: its exit's code half is met, and its "green on a nightly" half by that commit's three local `--nightly` runs of usb_transport_break with a reverted negative control, not by a CI nightly. #971 deleted the record on main first, so this change no longer carries the deletion. Deleted as superseded: - a-deliberate-wedge-inside-a-driver-panics-every-other-cpu-that-wants-its-lock: the usb-wedge-* actuators it was about went in 29e1006, and 13ed7b4 (#971) took the kernel's USB driver out and its restoration out of stage E of the-guest-suite-runs-only-what-no-cheaper-tier-reaches.md. The one staged wedge left, wedge-before-reset, holds no lock when it stops. Corrected where the text no longer matched the code, the defect kept: renamed programs (init, netd, logd, fsd, soundd), moved functions and files, line numbers that drifted, guest tests cut since, citations of deleted files, and statements the tree refutes (the console's blocking read, the DMA address window's arithmetic, the mio half of the TCP_NODELAY record, the firmware-call record's account of when AML writes first reached the kernel, d2006cc, and its widening, 15536e2). On the new base the console-watch and disk-offline records are main's text, the console's carrying the residual correction to its blocking read; held-disk, the NVMe boot wait and reset-stops-xHCI are main's deletions, and the job-list record's citation of the kernel's xHCI stop now names pcidev::stop_before_reset. Left untouched because the owner's uncommitted planning edits them: a-driver-that-reflashes-its-device-escapes-its-isolation, a-file-held-across-a-file-servers-restart-answers-gone, a-machine-without-an-iommu-refuses-every-claim, and a-memory-overwrite-request-ubuntu-left-set-stays-set-under-toyos, which the owner deleted locally as superseded (claude-questions.md, item 12) together with its citation in the loader-wipe issue. Also removes a home-directory path from a-job-list-hangs-with-interrupts-on-and-the-deadline-ends-it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A one-off accuracy audit of batch 1 (117 open `kind: defect` records). Each claim was checked against origin/main at 6f4d8db. Every record that #971, #978 and #980 touched was then re-audited against db0cf63, the base this lands on. The primary checkout's uncommitted planning (requirements/, claude-questions.md) was read and not edited. Counts at db0cf63: 2 fixed, 43 partly stale, 60 still valid, 8 uncertain, and 4 already deleted by #971 (hotplug-blocks-a-scheduler- pass, a-shutdown-on-a-held-usb-disk-left-a-cpu-deaf-to-a-tlb-shootdown, an-acknowledge-after-an-enumeration-clears-a-replug-no-look-has-seen, an-xhci-storm-starves-the-cpu-that-takes-it). Still-valid and uncertain records are unchanged, except for the two extended below. Deleted, fixed: - a-second-launch-of-a-serves-program-panics-the-supervisor: no launcher client can reach the panic. `may_start` refuses a target the caller's `starts` does not list (4e20480). The build refuses a `starts` entry naming a row that serves a port or a role (`starts_name_what_a_launch_can_start`, host-tested), and a package's synthesized row serves nothing. The panic is now an internal invariant; a-comment-says-a-second-launch-is-refused-where-the- supervisor-panics records the comment above it, which still says "refused". - bus-mastering-rides-memory-decode: #971 removed the kernel xHCI driver, the last kernel site that armed bus mastering before its refusals. virtio arms in `accept` after `offer` has parsed; amdvi arms after programming, with no refusal after it; a claimed function starts mastering through its own driver's `dma_start`, after its parse (usbd, nvme). build/sourcegate.rs's `BUS_MASTER_SITES` comment no longer cites the record. Renamed, the slug's claim refuted, a residual kept, every citation moved: - a-safe-port-read-reaches-any-io-port -> a-safe-port-read-reaches-any- declared-port: a `pio::Port` is made only from a declared run, but the fixed runs are pub consts, so a safe read still bypasses `serial::Registers`. - a-wake-to-a-busy-cpu-waits-for-its-next-pass-and-no-idle-cpu-can-take- it -> no-row-holds-a-wake-beside-seven-spinners-to-100-us. #874's `wake_onto_busy` read p99 5 us (T14) and 25 us (AMD bench), with 200 of 200 wakes run off the busy CPU. What is left is the 7-spinner arm's 100 us bound, which no row holds. The 8-spinner arm moves to a-woken-thread-waits-out-a-sibling-spinners-quantum-when-every-cpu-is- busy, its owner. The speed track's two citations moved, and its stale "whole 10 ms quantum" line was corrected. - diskserver-resets-a-drive-that-is-slow-and-healthy -> the-nvme-driver- resets-a-drive-that-is-slow-and-healthy: `COMMAND_SILENCE` is the nvme driver's (system/nvme/src/main.rs), a row apart from diskserver. Extended: a-spawn-drops-an-empty-argument now covers the supervisor's `serve_launch`, which drops empty and non-UTF-8 arguments from the same blob; its exit asks for a host test of that decode. Corrected to the current code, residual defect kept: paths and names after the userland moves (fsd -> fileserver, init -> supervisor, soundd -> soundserver, netd -> netstack, blockd -> nvme); line numbers replaced by names; tests cut since filing recorded as cut (consent_prompt in ff1a11d, screen_gop_firmware_mode in 520c0d1). Some mechanisms changed under a record: netring stage 3's stream refusals; the DMA ordering behind `DmaBuffers::publish`/`observe`; blocked-time accounting's one caller; `SpawnArgs::image`; the blackbox tail keeping the newest records; the T14's HDA now driven; and `close_ends_polls`'s arms at db0cf63. a-usb3-device-attached-but-untrained-reads-as-gone takes #971's rewrite as it stands. The per-record table (class, evidence, action) is in the PR's evidence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A one-off accuracy audit of batch 1 (117 open `kind: defect` records). Each claim was checked against origin/main at 6f4d8db. Every record that #971, #978 and #980 touched was then re-audited against db0cf63, the base this lands on. The primary checkout's uncommitted planning (requirements/, claude-questions.md) was read and not edited. Counts at db0cf63: 2 fixed, 43 partly stale, 60 still valid, 8 uncertain, and 4 already deleted by #971 (hotplug-blocks-a-scheduler- pass, a-shutdown-on-a-held-usb-disk-left-a-cpu-deaf-to-a-tlb-shootdown, an-acknowledge-after-an-enumeration-clears-a-replug-no-look-has-seen, an-xhci-storm-starves-the-cpu-that-takes-it). Still-valid and uncertain records are unchanged, except for the two extended below. Deleted, fixed: - a-second-launch-of-a-serves-program-panics-the-supervisor: no launcher client can reach the panic. `may_start` refuses a target the caller's `starts` does not list (4e20480). The build refuses a `starts` entry naming a row that serves a port or a role (`starts_name_what_a_launch_can_start`, host-tested), and a package's synthesized row serves nothing. The panic is now an internal invariant; a-comment-says-a-second-launch-is-refused-where-the- supervisor-panics records the comment above it, which still says "refused". - bus-mastering-rides-memory-decode: #971 removed the kernel xHCI driver, the last kernel site that armed bus mastering before its refusals. virtio arms in `accept` after `offer` has parsed; amdvi arms after programming, with no refusal after it; a claimed function starts mastering through its own driver's `dma_start`, after its parse (usbd, nvme). build/sourcegate.rs's `BUS_MASTER_SITES` comment no longer cites the record. Renamed, the slug's claim refuted, a residual kept, every citation moved: - a-safe-port-read-reaches-any-io-port -> a-safe-port-read-reaches-any- declared-port: a `pio::Port` is made only from a declared run, but the fixed runs are pub consts, so a safe read still bypasses `serial::Registers`. - a-wake-to-a-busy-cpu-waits-for-its-next-pass-and-no-idle-cpu-can-take- it -> no-row-holds-a-wake-beside-seven-spinners-to-100-us. #874's `wake_onto_busy` read p99 5 us (T14) and 25 us (AMD bench), with 200 of 200 wakes run off the busy CPU. What is left is the 7-spinner arm's 100 us bound, which no row holds. The 8-spinner arm moves to a-woken-thread-waits-out-a-sibling-spinners-quantum-when-every-cpu-is- busy, its owner. The speed track's two citations moved, and its stale "whole 10 ms quantum" line was corrected. - diskserver-resets-a-drive-that-is-slow-and-healthy -> the-nvme-driver- resets-a-drive-that-is-slow-and-healthy: `COMMAND_SILENCE` is the nvme driver's (system/nvme/src/main.rs), a row apart from diskserver. Extended: a-spawn-drops-an-empty-argument now covers the supervisor's `serve_launch`, which drops empty and non-UTF-8 arguments from the same blob; its exit asks for a host test of that decode. Corrected to the current code, residual defect kept: paths and names after the userland moves (fsd -> fileserver, init -> supervisor, soundd -> soundserver, netd -> netstack, blockd -> nvme); line numbers replaced by names; tests cut since filing recorded as cut (consent_prompt in ff1a11d, screen_gop_firmware_mode in 520c0d1). Some mechanisms changed under a record: netring stage 3's stream refusals; the DMA ordering behind `DmaBuffers::publish`/`observe`; blocked-time accounting's one caller; `SpawnArgs::image`; the blackbox tail keeping the newest records; the T14's HDA now driven; and `close_ends_polls`'s arms at db0cf63. a-usb3-device-attached-but-untrained-reads-as-gone takes #971's rewrite as it stands. The per-record table (class, evidence, action) is in the PR's evidence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A one-off accuracy audit of 117 open defect records. Each was read against the code it cites at origin/main db0cf63, with the owner's uncommitted requirements/ and claude-questions.md beside it. After rebasing onto a8ea09d (#978, #981), each record whose cited code #978 changed was read again. Deleted, fixed: - netstack-watches-both-pipes-of-every-connection-on-every-pass: c91e72b gave a pipe end's leaving its own watch (kernel/src/pipe.rs) and made netstack submit only a changed or answered watch (watches.rs `Armed`). The commit named the record and left it. - shell-c-discards-the-cwd-its-launch-carried: `shell -c` runs in its launch's directory since b3770cf. - std-answers-every-spawn-refusal-but-notfound-as-other: std's spawn maps each refusal by name, and every SyscallError through to_io_error, since 61a283a. Deleted, superseded (the subject's code or test no longer exists): - os-toyos-io-traits-keep-a-posix-name: #978 makes a RawFd a number in the process's one descriptor table, as on unix, and gives the kernel handle its own word, std::os::toyos::io::AsRawHandle. - kernel_stack_addr-names-an-offset-not-an-address: #583 merged without the rename; the rename is a step of the-loader-does-only-what-must-precede-the-handover.md. - log-flush-retry-deadman-arm: the kernel's fsync deadman went with the durability ledger (80a1f1c), its kernel USB with usbd (13ed7b4), and the test with 9ebf080. - metal-device-probe-usbread-answered-iofailed-once-beside-other-guests: one sighting through the kernel's usb-storage, gone with 13ed7b4; test deleted 24aa318. - netstack-refused-accept-hung-waiting-for-a-wake-that-never-came: netd and its listen.rs are gone, the test was deleted (7967fba), and so is netcase_against_host. - process-stats-exits-101-beside-other-guests: both recorded reds were the test's own premise; the test is deleted (4a5b228). - screen-diag-boot-leaves-no-i8042-line-on-the-panel: the kernel's i8042 and its health line left for ps2server (febfd21); test deleted. Corrected and kept, each with what remains: - io-uring-enter-trips-the-one-queue-invariant becomes a-wait-was-registered-while-its-task-still-read-waiting: the assertion is now Watch::register's; every recorded route is gone; the cause never was found. - libc-loses-the-kernels-word-on-three-write-paths becomes ...-two-...: send's stream arm answers through stream_errno; sendto's datagram arm and stdio's sys_write still drop the kernel's word. - logkeeper-flushes-the-records-its-own-refused-flush-made becomes logkeeper-flushes-the-records-its-own-flush-made: the measured kernel retry is gone; whether any flush now makes records is unmeasured. - std-calls-undated-what-it-did-not-stat becomes std-set-times-answers-ok-and-sets-nothing: the mtime half is fixed. - remove-dir-all-empties-a-directory-and-leaves-it: std's is fixed; pkg's remove_tree still gives that as its reason. - netstack-holds-a-pending-request-for-a-client-that-left: the connect half is gone; the waiting receive is still unwatched. - netstack-keeps-receiving-for-a-client-that-closed-its-receive-end, netstack-socket-ids-are-ambient, netstack-lookup-slots-have-no-per-client-share, netstacks-places-are-one-number-for-every-client, most-t14-leases-land-one-dhcp-retry-late: restated for regions, badges and netstack. - smp-ap-hole-and-log-reserve-window-red-under-a-loaded-host: the ROOT read half is gone; the first spawn's WouldBlock is kept. - soundserver-past-due-wake-max-1: only the null sink's wait still does it. - std-says-a-launch-moves-its-handles-...: the std comment moved into toyos::spawn, where it is right; provide's doc is still wrong. - std-maps-a-device-error-to-other-not-uncategorized: the consumers that kept Other load-bearing are gone. - sharedmemory-slices-rest-on-a-size-nobody-checks: a peer's region maps through `lent`, which checks it; `adopt` does not. - sshserver-authorized-keys-unprotected: installed packages no longer see /state; every shipped program still does. - libc-munmap-refuses-part-of-a-mapping: the owner's 2026-10-21 memory checkpoint revises the refusal, so the "rule it final" exit goes. - libc-refuses-what-toyos-cannot-yet-answer: after #978 F_DUPFD_CLOEXEC, F_DUPFD's lowest free and F_GETFD's EBADF hold; the fcntl bullet keeps record locks and F_GETFL, F_SETFL, F_GETOWN, F_SETOWN. - Sites, names and paths moved for: kernel-text-is-writable..., libc-answers-einval..., libc-answers-epipe..., libc-host-tests..., listing-home..., logkeeper-ends..., map-mmio..., metalprobes-usb-read..., mio-deregister..., no-console..., one-diskserver-session..., one-write-far-past..., probe-mounts-on-a-checksum, sshserver-holds-one-channel..., sshserver-still-speaks-rsa, std-lookup-host..., null-sink-applies-one-connect (annotated, not re-seen). parallel-tests-red-under-other-suites.md loses its pointer to a deleted record. no-physical-memory-fairness is owner-held and untouched; 58 records are still valid and 9 uncertain, both unchanged; four were already deleted on main (#971, #980, #978). The per-record table with file and line evidence is in the pull request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A one-off accuracy audit of 117 open defect records. Each was read against the code it cites at origin/main db0cf63, with the owner's uncommitted requirements/ and claude-questions.md beside it. After rebasing onto a8ea09d (#978, #981), each record whose cited code #978 changed was read again. Deleted, fixed: - netstack-watches-both-pipes-of-every-connection-on-every-pass: c91e72b gave a pipe end's leaving its own watch (kernel/src/pipe.rs) and made netstack submit only a changed or answered watch (watches.rs `Armed`). The commit named the record and left it. - shell-c-discards-the-cwd-its-launch-carried: `shell -c` runs in its launch's directory since b3770cf. - std-answers-every-spawn-refusal-but-notfound-as-other: std's spawn maps each refusal by name, and every SyscallError through to_io_error, since 61a283a. Deleted, superseded: - kernel_stack_addr-names-an-offset-not-an-address: the field is still `kernel_stack_addr` (sdk/abi/src/boot.rs:9), and #583, its named owner, merged without the rename. The rename is a stated step of the-loader-does-only-what-must-precede-the-handover.md, which carries it. - os-toyos-io-traits-keep-a-posix-name: the traits still exist, and now name a real descriptor. The owner's 2026-10-21 answers supersede the 2026-08-19 "fds belong only in libc jargon" ruling (64f806d) the record rested on: keep C numbering and dup2 conventions in userland, including Rust/C descriptor interoperability; Rust std's C-style descriptor interoperation uses the same userland adaptation; one descriptor-inheritance rule honored by both libc spawning and Rust Command. #978 implements that, and the kernel handle has its own word, std::os::toyos::io::AsRawHandle. - logkeeper-flushes-the-records-its-own-refused-flush-made: the measured loop was the kernel's retry of a budget-refused fsync, whose four records made logd's next round flush again. That retry and its records went with the durability ledger (80a1f1c) and the kernel's USB storage (13ed7b4). logkeeper ends its volume on a refused append or flush (system/logkeeper/src/main.rs:625-632) and warns of a slow round once, behind its `degraded` latch (:633-643); the file server logs only an operation that failed (system/fileserver/src/data.rs:136, 461), and a failed flush ends the volume. No current route is known. The rest have code or a test that no longer exists: - log-flush-retry-deadman-arm: the kernel's fsync deadman went with the durability ledger (80a1f1c), its kernel USB with usbd (13ed7b4), and the test with 9ebf080. - metal-device-probe-usbread-answered-iofailed-once-beside-other-guests: one sighting through the kernel's usb-storage, gone with 13ed7b4; test deleted 24aa318. - netstack-refused-accept-hung-waiting-for-a-wake-that-never-came: netd and its listen.rs are gone, the test was deleted (7967fba), and so is netcase_against_host. - process-stats-exits-101-beside-other-guests: both recorded reds were the test's own premise; the test is deleted (4a5b228). - screen-diag-boot-leaves-no-i8042-line-on-the-panel: the kernel's i8042 and its health line left for ps2server (febfd21); test deleted. Corrected and kept, each with what remains: - io-uring-enter-trips-the-one-queue-invariant becomes a-wait-was-registered-while-its-task-still-read-waiting: the assertion is now Watch::register's; every recorded route is gone; the cause never was found. - libc-loses-the-kernels-word-on-three-write-paths becomes ...-two-...: send's stream arm answers through stream_errno; sendto's datagram arm and stdio's sys_write and sys_read still drop the kernel's word. - std-calls-undated-what-it-did-not-stat becomes std-set-times-answers-ok-and-sets-nothing: the mtime half is fixed. - remove-dir-all-empties-a-directory-and-leaves-it: std's is fixed; pkg's remove_tree still gives that as its reason. - netstack-holds-a-pending-request-for-a-client-that-left: the connect half is gone; the waiting receive is still unwatched. - netstack-keeps-receiving-for-a-client-that-closed-its-receive-end, netstack-socket-ids-are-ambient, netstack-lookup-slots-have-no-per-client-share, netstacks-places-are-one-number-for-every-client, most-t14-leases-land-one-dhcp-retry-late: restated for regions, badges and netstack. - smp-ap-hole-and-log-reserve-window-red-under-a-loaded-host: the ROOT read half is gone; the first spawn's WouldBlock is kept. - soundserver-past-due-wake-max-1: only the null sink's wait still does it. - std-says-a-launch-moves-its-handles-...: the std comment moved into toyos::spawn, where it is right; provide's doc is still wrong. - std-maps-a-device-error-to-other-not-uncategorized: the consumers that kept Other load-bearing are gone. - sharedmemory-slices-rest-on-a-size-nobody-checks: a peer's region maps through `lent`, which checks it; `adopt` does not. - sshserver-authorized-keys-unprotected: installed packages no longer see /state; every shipped program still does. - libc-munmap-refuses-part-of-a-mapping: the owner ruled on 2026-10-21 that whole-mapping-only unmap is not the final contract and the refusal is to be revised, so the "rule it final" exit goes. - libc-refuses-what-toyos-cannot-yet-answer: after #978 F_DUPFD_CLOEXEC, F_DUPFD's lowest free and F_GETFD's EBADF hold; the fcntl bullet keeps record locks and F_GETFL, F_SETFL, F_GETOWN, F_SETOWN. - Sites, names and paths moved for: kernel-text-is-writable..., libc-answers-einval..., libc-answers-epipe..., libc-host-tests..., listing-home..., logkeeper-ends..., map-mmio..., metalprobes-usb-read..., mio-deregister..., no-console..., one-diskserver-session..., one-write-far-past..., probe-mounts-on-a-checksum, sshserver-holds-one-channel..., sshserver-still-speaks-rsa, std-lookup-host..., null-sink-applies-one-connect (annotated, not re-seen). parallel-tests-red-under-other-suites.md loses its pointer to a deleted record. no-physical-memory-fairness is owner-held and untouched; 58 records are still valid and 9 uncertain (stdio-buffering's deleted-file citation now names its deleting commit), both unchanged; four were already deleted on main (#971, #980, #978). The per-record table with file and line evidence is in the pull request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es the toolchain pkg read a whole archive into memory under a 256 MiB ceiling and refused every link, so the toolchain M2 needs (clang, LLD and the C sysroot, 279 MB installed) could not be installed. pkg now reads an archive twice and never holds it: a survey hashes the whole file and plans it header by header within the room the volume under /apps has, and the unpack meets that plan header for header and the digest again at the end, so an archive changed between the reads installs nothing and writes nothing the plan did not check. The room replaces MAX_INFLATED as the bound on what a survey inflates. Before the manifest is written the volume is synced through /apps's capability, which refuses if any file was left unwritten: a file's last close can be refused, and std's File drops that answer. The room is a new file-server request, ROOM: the free bytes of the volume behind a capability and its allocation unit, answered by bcachefs's spare blocks, FAT32's free clusters, and none for an absent or read-only volume. A package may carry symlinks that resolve inside it: relative, `..` only first and never past the package's own directory, and nothing is written beneath a link or a file. The package's directory is no link, and the manifest is the installer's alone. Hard links, pax and GNU long names stay refused. A package's program is `<name>/<name>` or `<name>/bin/<name>`, so a manifest's program may be nested inside its directory. pkg asks ToyOS's file server for room, so it is declared exempt as ToyOS-only. `--hosted-clang` packages its clang and LLD with clang's resource headers, the C sysroot and LLVM's licence as clang-v<version>-toyos-x86_64.tar.gz, deterministic, with `cc` and `clang++` linked to clang and a `<triple>.cfg` naming the sysroot beside the binaries. hosted_clang_hello installs that package with pkg on a 1 GiB DATA and compiles and links hello.c with /apps/clang/bin. Its image starts the block service and the NVMe driver as the split of #971 has them. libc's posix_spawn reads a program a file server holds into a memory object the kernel pages the child from, as std's Command does, since the kernel opens only what it serves; clang's driver starts cc1 and ld.lld that way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es the toolchain pkg read a whole archive into memory under a 256 MiB ceiling and refused every link, so the toolchain M2 needs (clang, LLD and the C sysroot, 279 MB installed) could not be installed. pkg now reads an archive twice and never holds it: a survey hashes the whole file and plans it header by header within the room the volume under /apps has, and the unpack meets that plan header for header and the digest again at the end, so an archive changed between the reads installs nothing and writes nothing the plan did not check. The room replaces MAX_INFLATED as the bound on what a survey inflates. Before the manifest is written the volume is synced through /apps's capability, which refuses if any file was left unwritten: a file's last close can be refused, and std's File drops that answer. The room is a new file-server request, ROOM: the free bytes of the volume behind a capability and its allocation unit, answered by bcachefs's spare blocks, FAT32's free clusters, and none for an absent or read-only volume. A package may carry symlinks that resolve inside it: relative, `..` only first and never past the package's own directory, and nothing is written beneath a link or a file. The package's directory is no link, and the manifest is the installer's alone. Hard links, pax and GNU long names stay refused. A package's program is `<name>/<name>` or `<name>/bin/<name>`, so a manifest's program may be nested inside its directory. pkg asks ToyOS's file server for room, so it is declared exempt as ToyOS-only. `--hosted-clang` packages its clang and LLD with clang's resource headers, the C sysroot and LLVM's licence as clang-v<version>-toyos-x86_64.tar.gz, deterministic, with `cc` and `clang++` linked to clang and a `<triple>.cfg` naming the sysroot beside the binaries. hosted_clang_hello installs that package with pkg on a 1 GiB DATA and compiles and links hello.c with /apps/clang/bin. Its image starts the block service and the NVMe driver as the split of #971 has them. libc's posix_spawn reads a program a file server holds into a memory object the kernel pages the child from, as std's Command does, since the kernel opens only what it serves; clang's driver starts cc1 and ld.lld that way. The guest row installs and compiles, and stops at the link: clang's driver starting cc1 from /apps is refused ENOMEM, the kernel's ResourceExhausted, while a small std parent starts ld.lld from there. The image object is allocated physically contiguous, about 148 MB for clang, and the memory track's stages 1 to 3 remove that; the track and the memory issue record it as the row's blocker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es the toolchain pkg read a whole archive into memory under a 256 MiB ceiling and refused every link, so the toolchain M2 needs (clang, LLD and the C sysroot, 279 MB installed) could not be installed. pkg now reads an archive twice and never holds it: a survey hashes the whole file and plans it header by header within the room the volume under /apps has, and the unpack meets that plan header for header and the digest again at the end, so an archive changed between the reads installs nothing and writes nothing the plan did not check. The room replaces MAX_INFLATED as the bound on what a survey inflates. Before the manifest is written the volume is synced through /apps's capability, which refuses if any file was left unwritten: a file's last close can be refused, and std's File drops that answer. The room is a new file-server request, ROOM: the free bytes of the volume behind a capability and its allocation unit, answered by bcachefs's spare blocks, FAT32's free clusters, and none for an absent or read-only volume. A package may carry symlinks that resolve inside it: relative, `..` only first and never past the package's own directory, and nothing is written beneath a link or a file. The package's directory is no link, and the manifest is the installer's alone. Hard links, pax and GNU long names stay refused. A package's program is `<name>/<name>` or `<name>/bin/<name>`, so a manifest's program may be nested inside its directory. pkg asks ToyOS's file server for room, so it is declared exempt as ToyOS-only. `--hosted-clang` packages its clang and LLD with clang's resource headers, the C sysroot and LLVM's licence as clang-v<version>-toyos-x86_64.tar.gz, deterministic, with `cc` and `clang++` linked to clang and a `<triple>.cfg` naming the sysroot beside the binaries. hosted_clang_hello installs that package with pkg on a 1 GiB DATA and compiles and links hello.c with /apps/clang/bin. Its image starts the block service and the NVMe driver as the split of #971 has them. The guest row installs and compiles, and stops at the link: clang's driver, starting cc1 from /apps through libc's posix_spawn of a served image (toyos::files::read_image), is refused ENOMEM, while a small std parent starts ld.lld from there. The image object is allocated physically contiguous, about 148 MB for clang, and the memory track's stages 1 to 3 remove that; the track and the memory issue record it as the row's blocker. The package's licences and a command reached by its name are recorded as owed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This PR is step 10 of
issues/the-kernel-is-small-interrupts-post-and-threads-wait.mdand stage 4 ofissues/a-device-function-is-driven-from-its-arrival-to-its-end.md.What changes
usbd is a
drivesrow. It runs one process per xHCI controller (drives = ["pci:0c:03:30"],receives = ["disk", "input"]).disk. It serves their sessions straight out of each client's region.input. Each bound HID collection is asourceof its own.The whole xHCI leaves the kernel. Deleted, not bridged:
keyboard.rs,mouse.rsandinput_merge_test;SYS_PARTITION_*;usb_gate,irq_ring,drain_irqsand the scheduler'sOperationframework;sync::OwedLock, its loom test and theowed-fence-offfeature;From the ABI: the
KeyboardandMousedevice and file types,Partition, and the USB, block and partition inventory records. A reset now stops every claimed function's bus mastering and messages (pcidev::stop_before_reset), where it used to run the xHCI stop.The machine's stop hands every USB device back (the orchestrator's ruling in review, which keeps the owner's run-18 ruling).
stoppipe it closes). It waits up toDRIVERS_MS, 3 s, for each one to end.Hc::stop:stick_survives_a_reset_under_loadmeasures that case.The driver (
system/usbd/xhci, moved fromlib/xhci)toyos-device-memory's traits. It has 110 tests, including the three the step's exit named and the one it owed: a stick whose bulk endpoint never answers leaves a keyboard on the same controller delivering every report.HID and storage
lib/usbhid, moved fromkernel/usbhid) binds each collection by its report descriptor, in report protocol:CLEAR_FEATURE(HALT)fails takes back the transfer the ring was moved past, and does not panic.Decisions
pci:0c:03:30/1022:1639@03:00.3). Test images use it so that the AMD bench's boot controller is driven and its other controller is left to the claim tests. Shipped images name the class alone.ps2serverandusbd(HELD_ALONEholds a list now).AlreadyExists. This replacesxhci-leave.How a metal run's log reaches readback
The path is: logkeeper → the LOG file server → diskserver's
blocksession → usbd's disk on the boot stick (Bulk-Only Transport) → the stick's log partition.toyos-metalreads that partition back (--fat32-check).The kernel holds no part of this path any more. Every metal judge reads
/logoff the stick, so each staged row is also the proof of this path on its bench.usbd_serves_the_boot_stick(new, rides TESTCASES on both benches) checks four things:serving it as disk 0.On the benches:
8a93782dd: all five rows pass, and the log reaches the stick through usbd.8a93782dd:usbloadpassed:stick_survives_a_reset_under_loadpasses on its readback, with 7320 KiB of the load's lines on the stick.testcasesfailed: its/logstopped mid-append at about 16 s whiletone_beside_stick_writewrote 2000 lines a second, and the boot ran on to an orderly stop. A probe boot (r9) reproduced it; a second probe (r10) did not. The cause is not found yet (see Risks).Checks
cargo run -- --ci hostcargo run -- --build-only, then--arch aarch64cargo test --test toyos-build(68 rows)The one red is
crypto_instrument_prints_its_table: QEMU drops console bytes (issues/qemu-drops-console-output-the-harness-is-slow-to-read.md). That stall has the same signature at the base and in an image with no usbd.Negative controls, each applied as a patch, red, and restored (
mut/in both evidence trees):amdvi_usbd_drives_its_own_entryis red.x8 (IP never cleared) is red on the stub's interrupt model. Under MSI or MSI-X, IP clears itself (§5.5.2.1).
Integration tests and where they run
nec-usb-xhciandqemu-xhci):usbd_drives_the_spare,usbd_refused_without_amdvi_remapping,usbd_refused_without_smi_filter,amdvi_firmware_left,iommu_virtio_platform,a_drives_row_holds_one_process_per_functionand the other testcases rows.the_log_lands_on_the_boot_stick: a stick boot whose log volume is read back on the host, and whose stop under load is judged.a_usb_key_reaches_the_console: a key from a real xHC reaches the owner of input.usbd_serves_the_boot_stick,usbd_drives_the_type_c_controller,stick_survives_a_reset_under_load,tone_beside_a_stick_write,mask_windows.usbd_serves_the_boot_stick,amdvi_usbd_drives_its_own_entry,amdvi_translates_the_stick_controller,amdvi_remaps_the_stick_controller,stick_survives_a_reset_under_load,tone_beside_a_stick_write./logto judge.amdvi_claim_refused_without_remappingandclaim_refused_without_remappingare deleted, and with them the kernel'siommu-no-remapactuator and theusbd_spare_unhandedbinary. QEMU holds the refusal, byusbd_refused_without_amdvi_remappingandamdvi_firmware_left.These rows exercise real controllers, their interrupt remapping and the stick that carries
/log. Neither the stub nor QEMU can establish that.Risks and gaps
amdvi_firmware_leftexpects that refusal./logstopped mid-append: r8, r9, then 6 of 7 probe boots (r12, r13); main with only the tone row added, 0 of 2. Probes that report by exit codes the kernel records showed usbd's: a stick transfer unanswered, no event on the ring, the endpoint Running, and in 2 of 3 boots USBSTS HCH, HSE or HCE set. The multi-TRB TDs broke three xHCI rules (above). Since 0e0c37e follows them, 6 of 6 AMD testcases boots are clean (r14). That is a rate from 6/7 to 0/6, not a proof of which rule this controller needs.metaldevicecaseis ridden by no row. Finding filed:issues/the-device-boot-is-flashed-by-no-metal-row.md.inputbinds HID until its first open answersNotGiven. That is a few control transfers per keyboard.RawKeyEventstill lives insdk/abi. Finding filed:issues/the-key-record-the-surface-protocol-carries-is-defined-in-the-kernel-abi.md.issues/a-disk-plugged-in-after-settling-is-routed-as-soon-as-it-is-offered.md.Metal
8a93782dd:usbd_serves_the_boot_stick,usbd_drives_the_type_c_controller,stick_survives_a_reset_under_load,tone_beside_a_stick_write,mask_windows: all PASS.8a93782dd:stick_survives_a_reset_under_loadPASS. Thetestcasesboot is open (above).b07a9b1acchanges, from8a93782dd, only the refusal of a controller firmware keeps. That path ran on neither bench: firmware released 03:00.3 in about 11 ms on every boot after iommu: lowest-first device addresses below each claim's stated limit; a claim masters only when its holder starts it #974.0e0c37e66: T14 five rows PASS; AMD usbload PASS. AMD testcases six boots: all completed with clean FAT checks, andusbd_serves_the_boot_stickandtone_beside_a_stick_writePASS on all six. The three amdvi rows were red on every boot from judges, not the machine. This branch folded main's separatexhci-leaveboot into testcases, sotest_rs_usbd_spare_fault's staged fault met the no-fault rule of the translate and remap rows. And usbd's line now beginsENDED —. The fix is in the judges: the translate and remap rows refuse every fault but 03:00.4's, andamdvi_usbd_drives_its_own_entryrequires exactly 03:00.4's two staged records. The six r14 readbacks re-judged pass the amdvi rows. A copy with a fault on 03:00.3 added is red on the no-fault rows, and one with a third 03:00.4 record is red on the spare's row.421c2b32achanges the ring again (review r2, B3 and B4), so both benches are staged again there: AMD testcases six boots and usbload, and the T14's three images.🤖 Generated with Claude Code