Repository navigation
usbd drives one xHCI controller the kernel was told to leave alone (xhci-leave=), naming every device over inspect - #827
Conversation
Stage 1 of moving USB out of the kernel. A test-only switch, `xhci-leave=<vendor>:<device>` behind `boot-actuators`, has the kernel's xHCI bring-up skip one controller before anything touches it, so it is never recorded as kernel-driven and a process may claim it. /system/bin/usbd takes that claim: the xHCI 1.2 section 4.22.1 handoff, a reset, every ring and context in one grant from SYS_DEVICE_DMA_ALLOC, interrupter 0 on the MSI the claim armed, a No-Op command, and every root-hub device reset, enumerated in toyos-xhci's order up to its configuration descriptor and named over `inspect`. It waits only on its poller; the event ring is read only on an interrupt record, so an answer found there by an operation's deadline is counted as unannounced. toyos-xhci gains, as additions: `descriptor` (the device descriptor and a configuration's interfaces, decoded from device-chosen bytes), `xecp` (the extended capability walk and the handoff's decisions) and `PortState::adopt`, the inherited reset for a port found connected at bring-up by a driver that steps its ports from the start. The actuator is the first that carries a value: a name ending in `=`, which `build::arms` matches as a prefix for the build's parameter check, the harness's, and the T14 flash gate, where it has its own ruling. Guest: `usbd_drives_the_spare` boots HeadlessUsbSpare (a qemu-xhci with MSI stated on, a stick and a keyboard) and has `usbd_spare` claim the controller, start usbd, read it, kill it and start it again, then aim the function past its grant for the unit's DMA FAULT record, and on a boot without the switch find the claim refused because the kernel drives it. Metal: `usbd_drives_the_type_c_controller` stages the same job on the T14 with `xhci-leave=8086:9a13`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
Firmware owns neither xHCI on the T14: both read USBLEGSUP 0x01002201 and USBLEGCTLSTS 0xe0000000 in every boot:testcases readback, so the stage-1 stop condition on firmware ownership does not apply. No boot has printed which reset either advertises; the stage-1 metal row's release does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
QEMU 11.1's qemu-xhci acts on PORTSC.PR and returns from the write before it applies the write-1-to-clear bits beside it, so the connect change a port was found by survived the reset that acknowledged it. The port machine then read it, after the enumeration, as a replug of the device just enumerated, and the keyboard on the spare was torn down and enumerated a second time on every start. Measured in usbd's own lines: PORTSC 0x00220e03 at enumeration before, 0x00200e03 after. usbd says each port's PORTSC where it finds a device, where it enumerates one and where one leaves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…ke without an event A line per such event was the controller's to flood; `inspect` reads the count instead. The parked check held `wakes.device` and the events still, which a port event on the T14's spare may move without usbd polling; what parked means is that no timeout and no empty claim woke it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
|
Mutation patches for #827, each applied at m1-no-interrupt-enablediff --git a/userland/usbd/src/hc.rs b/userland/usbd/src/hc.rs
index 001f4cf3d..8d9c560b3 100644
--- a/userland/usbd/src/hc.rs
+++ b/userland/usbd/src/hc.rs
@@ -51,7 +51,7 @@ const IR0_ERSTSZ: usize = 0x28;
const IR0_ERSTBA: usize = 0x30;
const IR0_ERDP: usize = 0x38;
/// IMAN's Interrupt Pending (write 1 to clear) and Interrupt Enable.
-const IMAN_IP_IE: u32 = 0b11;
+const IMAN_IP_IE: u32 = 0b01;
/// ERDP's Event Handler Busy, written 1 to clear (§5.5.2.3.3).
const ERDP_EHB: u64 = 1 << 3;
m2-poll-when-idlediff --git a/userland/usbd/src/main.rs b/userland/usbd/src/main.rs
index dd8654a5a..d39fb7af5 100644
--- a/userland/usbd/src/main.rs
+++ b/userland/usbd/src/main.rs
@@ -98,7 +98,7 @@ fn main() {
for p in &pending {
poller.watch(&p.conn, READABLE, TOKEN_PENDING + u64::from(p.conn.as_handle().0));
}
- let mut timeout = wake_at.map_or(u64::MAX, |at| at.saturating_sub(now()));
+ let mut timeout = wake_at.map_or(10_000_000, |at| at.saturating_sub(now()));
if let Some(first) = pending.iter().map(|p| p.since).min() {
let left = HANDSHAKE_TIMEOUT.saturating_sub(first.elapsed());
timeout = timeout.min(left.as_nanos() as u64);m3-aim-inside-the-grantdiff --git a/tests/toyos-rust-tests/src/bin/usbd_spare.rs b/tests/toyos-rust-tests/src/bin/usbd_spare.rs
index def8b2064..e06ae4b8f 100644
--- a/tests/toyos-rust-tests/src/bin/usbd_spare.rs
+++ b/tests/toyos-rust-tests/src/bin/usbd_spare.rs
@@ -51,7 +51,7 @@ const PARKED_SPAN: Duration = Duration::from_millis(500);
/// What the fault arm aims the command ring at: a gigabyte past its one
/// grant, which nothing in the claim's domain maps.
-const PAST_THE_GRANT: u64 = 1 << 30;
+const PAST_THE_GRANT: u64 = 0;
fn main() {
let cap: SysCap = Endowments::get().take(SYSCAP_LABEL).expect("test-runner endows a device-minting capability");m4-kernel-drives-the-sparediff --git a/kernel/src/drivers/xhci/wait/boot.rs b/kernel/src/drivers/xhci/wait/boot.rs
index 92915c6f2..1f3452292 100644
--- a/kernel/src/drivers/xhci/wait/boot.rs
+++ b/kernel/src/drivers/xhci/wait/boot.rs
@@ -116,7 +116,7 @@ pub fn init(devices: &[PciDevice]) {
for pci_dev in devices.iter().filter(|d| d.matches_class(0x0C, 0x03, Some(0x30))) {
// Before anything that touches the function, `enable_bus_master`'s
// record of it as this kernel's above all: that is what refuses a claim.
- if crate::actuator::xhci_left().is_some_and(|id| pci_dev.is_id(id.vendor, id.device)) {
+ if crate::actuator::xhci_left().is_some_and(|id| pci_dev.is_id(id.vendor, id.device)) && false {
log!("xHCI: leaving PCI {:02x}:{:02x}.{} {:04x}:{:04x} to a claim (xhci-leave)",
pci_dev.bus, pci_dev.dev, pci_dev.func, pci_dev.vendor_id(), pci_dev.device_id());
continue; |
|
T14 at |
|
Review of #827 at Net: What was checked and holds:
BLOCKER
NOTE
SEND BACK |
tests/toyos.rs: both machine tests stand, usbd_drives_the_spare and main's usb_keyboard_rollover, each in MACHINE_TESTS and run_machine_test. The track issue: main's sentence on where QEMU's and the T14's xHCI keep their MSI-X tables replaces this branch's "is not measured", which the stage-1 paragraph below it made false. The resolution also corrects that paragraph's "which reset either advertises no boot has printed": the T14 run of usbd_drives_the_type_c_controller at 20a40cd printed 00:0d.0's release as reset by nothing. And it records two compromises the review of #827 named, owned by the whole-xHCI move: the kernel's parse_config beside toyos-xhci's descriptor decoder, and the kernel's legacy.rs beside toyos-xhci's xecp, which the orchestrator ruled is not moved onto the crate's since it is deleted whole at the cutover. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…on, and names no class The review of #827's notes, each: - usbd's `function` changed nothing at stage 1 (Learnt::Function and Learnt::Nothing both end in `named`) and disagreed with the kernel's classification. It goes; the configuration descriptor learns Nothing, and which class binds is the class driver's stage's to decide. - toyos-xhci's Device drops `ep0_packet` and `release`, which nothing read (`descriptor::ep0_packet` is what usbd reads), and Class drops its USB-IF name table, read only by a `class_name` inspect key and a log line; both now say the triple. - HCCPARAMS1.AC64 clear is refused by name before the handoff: the kernel does not place a grant below 4 GiB, and a 32-bit controller would truncate every address usbd hands it. - FLASHABLE rules on `xhci-leave=8086:9a13` alone: a bare `xhci-leave=` cleared `xhci-leave=8086:a0ed`, which leaves the boot stick's controller to nobody on a flashed T14. `flashable` is back to an exact match, and `every_ruling_names_a_parameter_the_kernel_declares` matches a valued ruling to its actuator with `arms`. - The barrier issue names usbd's rings and doorbell beside netd and soundd, and the deferred-release issue names usbd_spare's claim-return loop, so each exit covers them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
The whole guest suite at f44d4c6 went red on netstack_streams alone, its boot silent after 64 s, at load averages near 70 on 14 cores; its sibling on the same netcase image was green. Recorded in the open defect with the load, as the rule for a red seen only under load asks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
|
Round 2 mutation patches for #827, each applied at m1-no-interrupt-enablediff --git a/userland/usbd/src/hc.rs b/userland/usbd/src/hc.rs
index 001f4cf3d..8d9c560b3 100644
--- a/userland/usbd/src/hc.rs
+++ b/userland/usbd/src/hc.rs
@@ -51,7 +51,7 @@ const IR0_ERSTSZ: usize = 0x28;
const IR0_ERSTBA: usize = 0x30;
const IR0_ERDP: usize = 0x38;
/// IMAN's Interrupt Pending (write 1 to clear) and Interrupt Enable.
-const IMAN_IP_IE: u32 = 0b11;
+const IMAN_IP_IE: u32 = 0b01;
/// ERDP's Event Handler Busy, written 1 to clear (§5.5.2.3.3).
const ERDP_EHB: u64 = 1 << 3;
m2-poll-when-idlediff --git a/userland/usbd/src/main.rs b/userland/usbd/src/main.rs
index dd8654a5a..d39fb7af5 100644
--- a/userland/usbd/src/main.rs
+++ b/userland/usbd/src/main.rs
@@ -98,7 +98,7 @@ fn main() {
for p in &pending {
poller.watch(&p.conn, READABLE, TOKEN_PENDING + u64::from(p.conn.as_handle().0));
}
- let mut timeout = wake_at.map_or(u64::MAX, |at| at.saturating_sub(now()));
+ let mut timeout = wake_at.map_or(10_000_000, |at| at.saturating_sub(now()));
if let Some(first) = pending.iter().map(|p| p.since).min() {
let left = HANDSHAKE_TIMEOUT.saturating_sub(first.elapsed());
timeout = timeout.min(left.as_nanos() as u64);m3-aim-inside-the-grantdiff --git a/tests/toyos-rust-tests/src/bin/usbd_spare.rs b/tests/toyos-rust-tests/src/bin/usbd_spare.rs
index def8b2064..e06ae4b8f 100644
--- a/tests/toyos-rust-tests/src/bin/usbd_spare.rs
+++ b/tests/toyos-rust-tests/src/bin/usbd_spare.rs
@@ -51,7 +51,7 @@ const PARKED_SPAN: Duration = Duration::from_millis(500);
/// What the fault arm aims the command ring at: a gigabyte past its one
/// grant, which nothing in the claim's domain maps.
-const PAST_THE_GRANT: u64 = 1 << 30;
+const PAST_THE_GRANT: u64 = 0;
fn main() {
let cap: SysCap = Endowments::get().take(SYSCAP_LABEL).expect("test-runner endows a device-minting capability");m4-kernel-drives-the-sparediff --git a/kernel/src/drivers/xhci/wait/boot.rs b/kernel/src/drivers/xhci/wait/boot.rs
index 92915c6f2..1f3452292 100644
--- a/kernel/src/drivers/xhci/wait/boot.rs
+++ b/kernel/src/drivers/xhci/wait/boot.rs
@@ -116,7 +116,7 @@ pub fn init(devices: &[PciDevice]) {
for pci_dev in devices.iter().filter(|d| d.matches_class(0x0C, 0x03, Some(0x30))) {
// Before anything that touches the function, `enable_bus_master`'s
// record of it as this kernel's above all: that is what refuses a claim.
- if crate::actuator::xhci_left().is_some_and(|id| pci_dev.is_id(id.vendor, id.device)) {
+ if crate::actuator::xhci_left().is_some_and(|id| pci_dev.is_id(id.vendor, id.device)) && false {
log!("xHCI: leaving PCI {:02x}:{:02x}.{} {:04x}:{:04x} to a claim (xhci-leave)",
pci_dev.bus, pci_dev.dev, pci_dev.func, pci_dev.vendor_id(), pci_dev.device_id());
continue;m5-refuse-a-64-bit-controllerdiff --git a/userland/usbd/src/hc.rs b/userland/usbd/src/hc.rs
index 9276019ec..ee584e232 100644
--- a/userland/usbd/src/hc.rs
+++ b/userland/usbd/src/hc.rs
@@ -279,7 +279,7 @@ impl Controller {
if scratch > MAX_SCRATCH {
return Err(Refusal::Scratchpad(scratch));
}
- if hccparams1 & HCCPARAMS1_AC64 == 0 {
+ if hccparams1 & HCCPARAMS1_AC64 != 0 {
return Err(Refusal::Addresses32);
}
run.sh#!/bin/zsh
# Apply one checked mutation, build and run the guest test, report, restore.
cd /Users/jan/Dev/jan/toyos-usbd || exit 9
P=$1; NAME=$(basename $P .patch); OUT=$(dirname $P)/$NAME.log
git apply --check $P || { echo "$NAME: patch does not apply"; exit 9; }
git apply $P
cargo test --test toyos-build -- usbd_drives_the_spare > $OUT 2>&1; RC=$?
git apply -R $P
echo "$NAME: test EXIT=$RC"; git status --porcelain --ignore-submodules=none |
|
Review of #827 at Net:
Earlier BLOCKERs
The
|
|
T14 at |
…nsole wire (#805), into usbd usbd_drives_the_spare and usb_keyboard_rollover read kernel records on the console wire the stop now takes from klogd; they are rerun at this merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at Load, from |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Round 3 log at |
|
Review of #827 at Net:
Earlier BLOCKERs
BLOCKERNone. NOTENone. LAND |
…812), TCP window scaling (#820) and the stop's hold of the console wire (#805), into virtio-sound and the shared PCI claim Both conflicts are two additions at one site, and both sides are kept whole: - tests/common/qemu.rs: this branch's Profile::HeadlessVirtioGpu and main's Profile::HeadlessUsbSpare, each in the enum, the x86-64 arm of arch() and shape(). - tests/toyos.rs: RUST_SKIP takes both virtio_sound_counts and usbd_spare; run_machine_test takes this branch's virtio_sound_counts arm beside main's machine_shutdown_wire_* , usbd_drives_the_spare and usb_keyboard_rollover. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…h toyos-sha2 - userland/update/src/main.rs: the branch's stream_root over the block service's Disk (STREAM_BLOCKS of BLOCK bytes), hashed with main's toyos_sha2::Sha256 in place of sha2. - tests/toyos.rs: both sides' RUST_SKIP entries, MACHINE_TESTS entries, dispatch arms and functions kept, the branch's first; the branch's update_writes_the_idle_slot_through_the_block_service keeps its own close. - Cargo.lock: main's, regenerated by cargo against the merged manifests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…ring-up (#825) and the hotkey removal (#824), into consent The one conflict is Profile::arch in tests/common/qemu.rs: main adds HeadlessUsbSpare and this branch adds Desktop to the same x86-64 arm; both stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
… batch: the icons' and wallpaper's digests hash with toyos-sha2 Cargo.toml keeps both sides' entries: main's toyos-sha2 and usbd members and toyos-sha2 dependency, and the batch's removal of `image`. `sha2` was replaced by toyos-sha2 on main and left in place on the batch, whose #813 and #814 added two tests hashing with it; as main meant every SHA-256 the build takes to be toyos-sha2's, those two tests now hash with toyos-sha2 and the root manifest drops `sha2`. Cargo.lock is the batch's, re-resolved by `cargo metadata --offline`; its delta from the batch's head is exactly main's delta from the merge base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
, #826, #835, #833, #831 and #822, into wt/toyos-netperf No hunk conflicted. userland/netstack/src/main.rs took both sides: main's removal of `mod device` and the branch's batched `node.receive` and its module-doc line. The TCP window-scaling and loss-probe commits main carries were already in the branch from #820, so their files merged to main's text plus the branch's own delta. Both lockfiles are main's and pass `cargo metadata --locked`. The branch's new issue still cites `VirtioNet::poll_rx` and `toyos_i219::RX_BUDGET` as they stand on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
Stage 1 of moving USB out of the kernel (plan's "First stage's brief"):
/system/bin/usbddrives one xHCI controller that a test-only kernel switch leaves alone. The kernel's own xHCI driver is untouched apart from the skip, and no shipped manifest runs usbd.Head
62930a2e2, withorigin/maina1eb2c0b9merged in. Round 2 answers the review at20a40cd77, round 3 the one at23fc14d3b; see "Round 2" and "Round 3" below.What changed, per decision
xhci-leave=<vendor>:<device>, behindboot-actuators.xhci::initskips the named function before it touches it. That meansenable_bus_masternever records it as kernel-driven, so a claim on it is not refusedKernelDriven. The kernel saysxHCI: leaving PCI <bdf> <id> to a claim (xhci-leave).actuators!block asxhci_leave = "xhci-leave=": a wire name ending in=carries the rest of its token.actuator::initarms the name and keeps the value;actuator::xhci_left()reads it back.=through one function,toyos_build::build::arms: the build's--kernel-paramcheck (src/build.rs) and the harness'skernel_paramscheck (tests/common/qemu.rs). The T14 flash gate (src/metal.rs::flashable) stays an exact match; its test that every ruling names a declared parameter matches a valued ruling to its actuator witharms.FLASHABLErules onxhci-leave=8086:9a13alone, the Type-C controller the row leaves: a barexhci-leave=would clearxhci-leave=8086:a0ed, which leaves the boot stick's controller to nobody on a flashed T14. The ruling cites the stage-0 readings: firmware owns neither T14 controller and every SMI enable is clear.no_actuator_is_also_a_cargo_featurenow admits a trailing=.userland/usbd, new; about 1.25k lines).dev:pci:label, as diskserver does, and answersinspectonserve:usb.hc.rsis the register file and the memory layout, written once:Refusal::Addresses32): the kernel does not place a grant below 4 GiB, and every device address usbd hands over is above it (0x400002000000, measured);SYS_DEVICE_DMA_ALLOC, taken after the reset, holding the DCBAA, the scratchpad array and buffers, the command ring, the ERST, the event ring, the input context, a data page and a block per device;bus.rssteps every port throughtoyos_xhci::portand enumerates each device intoyos_xhci::enumerate's order. One operation is outstanding at a time (job::Outstanding), matched by TRB address. A device is named and stops there: the sequence runs to the configuration descriptor, which learnsLearnt::Nothing, and the act after it is where a class driver would take over. usbd does not classify a function: which class binds is the class driver's stage's to decide, intoyos-xhci. No class is bound. The device keeps its slot and its address.u64::MAX.usbd: an answer is on the event ring and no interrupt said so. ERDP and EHB are written once per drain.inspectanswersusb.*:timed,device,empty,client);toyos-xhci, additions only.descriptor: the device descriptor and a configuration's alternate-0 interfaces, decoded from device-chosen bytes. Every length is bounded by what the descriptor claims and by what arrived; a zero- or one-byte length is refused rather than walked.Devicecarries the class, vendor and product, the fields a caller reads; there is no class-name table. It has host tests and a 200,000-case no-panic fuzz.xecp: the extended capability walk, bounded by the window and byMAX_CAPS;handoff, the semaphore's verdict; andsmis_off. Host tests use the T14's own words.PortState::adopt: the inherited reset for a port found connected at bring-up, for a driver that steps its ports from the start rather than scanning in place. It answers two writes: the arrival's connect acknowledge, then the reset. QEMU 11.1'sqemu-xhciacts on PR and returns before applying the write-1-to-clear bits beside it. With one write, the arrival's CSC survived the reset and the keyboard read asRepluggedright after its enumeration. usbd's own lines measured it: PORTSC0x00220e03at enumeration before,0x00200e03after.toyos_inspect::USB(root: "usb", port: "usb") is not amongOWNERS. The reader refuses a whole answer over an owner it holds no connector for, and no shipped manifest runs usbd yet. The job asks usbd directly.Profile::HeadlessUsbSpareis Headless with a second controller,qemu-xhci,id=spare,msix=off,msi=on. On that controller sit ausb-storageover anull-coblockdev and ausb-kbd.Shape.blockdevsholds that blockdev. It is refused by name unless a USB device names it.TestResult.serialkeeps the window's kernel records.stdoutdrops them, and the claim's records are this test's evidence.Where this is not what the brief said
msi=onis stated on the spare. Withmsix=offalone, QEMU 11.1.1'sqemu-xhcioffers no MSI capability either. The kernel refused the claim withpcidev: PCI 00:02.0 NOT HANDED OVER — neither its MSI-X nor its MSI could be armed(measured: guest3). Withmsi=onit was handed over,msi address=0xfee00038was written through irte1, andpcidev: slot 1 took its first message. So this is not the stop condition "QEMU's MSI withmsix=offdoes not deliver".[programs.usbd]) and does not namepci:1b36:000d. Killing and restarting usbd needs a holder of usbd's process, and no supervisor path kills a service on a test's word. So the jobusbd_spareclaims the controller itself (test-runner holdsdevice), makes theusbport, starts usbd, kills it, and starts it again on a fresh claim. This is theacpicaseacpiserver pattern. A supervisor row naming the device would hold the claim the job needs. The job names both spares,1b36:000dand the T14's8086:9a13, and takes the one this machine has.DMA FAULTcontrol is the job's, not usbd's. usbd ships no code to aim a transfer wrong. The job claims the same function with no usbd, takes a one-page grant (which starts bus mastering), and aims the command ring 1 GiB past that grant. The control checks the claim's domain, which is what bounds every transfer usbd makes.kernel/src/actuator.rs: the switch's parsing.src/build.rs,src/metal.rs: the valued actuator's readers and itsFLASHABLEruling. The T14 row cannot be flashed without them.toyos-inspect: the owner constant.Cargo.toml: the member.tests/common/qemu.rs:TestResult.serial.issues/assembly-outside-an-arch-module-in-userland-and-guest-probes.mdandissues/deferred-release-outlives-its-syscall.md: usbd's barrier gap andusbd_spare's claim-return loop named, so each exit covers them.issues/a-netcase-boot-under-host-load-said-nothing-past-the-firmwares-screen-clears.md: this round's suite red, recorded as a witness.Checks this high-risk change names (a userland DMA driver, interrupts through remapping)
46f4:0001(usb-storage) and0627:0001(usb-kbd), and class triples08:06:50and03:01:01. The unit's fault record is a third party's account:iommu: DMA FAULT owner=slot1 unit0 stream=00:02.0 addr=0x0000400042000000 access=read reason=0x06 ... read-permission. Its address equals the one the job aimed at.DMA FAULTrecord against its slot, and the claim then answersIo.PermissionDeniedand the kernel sayspcidev: PCI 00:02.0 is driven by this kernel and cannot be claimed.f44d4c6c1as a checked patch, built, run (cargo test --test toyos-build -- usbd_drives_the_spare) and reverted in one script, leaving the tree clean. The patches and the script are in usbd drives one xHCI controller the kernel was told to leave alone (xhci-leave=), naming every device over inspect #827 (comment).an event no interrupt announced(3); usbd saidthe bring-up's No-Op command: Silentusb.wakes.timed moved while usbd had nothing to do(0 before the span, 36 after)the claim answered WouldBlock, not the unit's refusalthe kernel never said it left 1b36:000d aloneit addresses only 32 bits (HCCPARAMS1.AC64 clear), and a grant is not placed below 4 GiB. QEMU's and the T14's controllers both set AC64, so no tier reaches the refusal itself; m5 shows the check sits on the bring-up path and reads the bit the controller sets.Why the new guest test needs QEMU
usbd is one binary that owns its controller and has no host build.
toyos-xhci's host tests and simulator hold every decision usbd takes, the newdescriptor,xecpandadoptincluded. None of them holds the effects:The T14 row reaches the first two on the Type-C controller. That controller has no device on it, and its unit is not asked to fault.
Round 2: the review at
20a40cd7720a40cd77(usbd drives one xHCI controller the kernel was told to leave alone (xhci-leave=), naming every device over inspect #827 (comment)):usbd_drives_the_type_c_controllerEXIT=0, the claim handed over, MSI through its remapping entry, the first message, the No-Op answered by interrupt. Both releases readreset by nothing (Express: no capability; AF: no capability; PM: No_Soft_Reset set), which the track now records.toyos-xhci::xecpbesidekernel/src/drivers/xhci/legacy.rs: not moved, by the orchestrator's ruling this round, quoted: "do NOT switchkernel/src/drivers/xhci/legacy.rstotoyos_xhci::xecp. The kernel's firmware handoff is deleted whole at the usbd cutover (stage 5), with the rest of the kernel xHCI driver, so refactoring it now spends a T14 boot on code about to go. Instead record the duplication in the track issue as a compromise with owner = stage 5 (the cutover) and exit =legacy.rsdeleted". The track records it so, beside the descriptor compromise;legacy.rsis untouched, so noboot:testcasesrun is owed.origin/main5a3b74345merged.tests/toyos.rskeeps both machine tests (usbd_drives_the_spare,usb_keyboard_rollover). In the track, main's sentence on where the MSI-X tables are replaces the false "is not measured".parse_configand itsxhci-descriptor-selftestactuator go with the kernel's driver.function: deleted; the configuration descriptor learnsLearnt::Nothing.Device.ep0_packet,Device.releaseandClass::namedeleted, with theclass_nameinspect key; usbd's naming line prints the triple.FLASHABLE: rules onxhci-leave=8086:9a13alone;flashableis back tocontains.Refusal::Addresses32, before the handoff; m5 above.usbd_spare's claim-return loop named in the deferred-release issue. The loop copies the supervisor'sCLAIM_RETURN.Round 3: the review at
23fc14d3bcargo run -- --ci hostat the head: run at the merged head62930a2e2, EXIT=0,[ci] Host: 78 step(s), all green. The log is below.23fc14d3b(usbd drives one xHCI controller the kernel was told to leave alone (xhci-leave=), naming every device over inspect #827 (comment)). It was EXIT=0, and the AC64 check passed on 00:0d.0. It carries to62930a2e2on usbd's side.git diff 23fc14d3b 62930a2e2 -- userland/usbd toyos-xhci kernel/src/actuator.rstouches onlykernel/src/actuator.rs, +14. Those lines are The stop takes the console wire from klogd for good and holds it to the machine's end; flush_final goes #805's hunks exactly asgit diff 5a3b74345 a1eb2c0b9 -- kernel/src/actuator.rsgives them; only the index hashes and one hunk's line offset differ. They add threewire-*actuators and oneIMPLIESrow, and the T14 row arms none of them.userland/usbdandtoyos-xhciare byte-identical. What the merge does change in the T14's image is The stop takes the console wire from klogd for good and holds it to the machine's end; flush_final goes #805's kernel console handoff (kernel/src/log/,drivers/serial.rs,power.rs,sched/driver.rs,sleeplock.rs,syscall/machine.rs). That is main's code, measured on main's own metal gate, and no T14 run is requested at the merge.origin/maina1eb2c0b9(The stop takes the console wire from klogd for good and holds it to the machine's end; flush_final goes #805) merged without conflict. The merge commit is62930a2e2. The two issue files The stop takes the console wire from klogd for good and holds it to the machine's end; flush_final goes #805 deletes are cited nowhere on this branch; the only matches are inside main's own issue files. Both tests that read kernel records on the console wire were then run at the merged head, alone and in the whole suite:usbd_drives_the_spare: EXIT=0. Its line:[usbd] 00:02.0: two devices named twice; aimed at 0x400042000000: [ 8.708 cpu0 kernel] iommu: DMA FAULT owner=slot1 unit0 stream=00:02.0 addr=0x0000400042000000 access=read reason=0x06 domain=6 bme=cleared unitfaults=1 streamfaults=1 first=y read-permission.usb_keyboard_rollover: EXIT=0.Gates
At the head
62930a2e2. The log of each run is posted to this pull request, scrubbed of home-directory paths:cargo run -- --ci host(78 steps, all green)cargo run -- --build-onlycargo run -- --build-only --arch aarch64cargo test --test toyos-build -- usbd_drives_the_spare --nocapturecargo test --test toyos-build -- usb_keyboard_rollover --nocapturecargo test: the whole guest suite, 51 passed of 51,usbd_drives_the_spareandusb_keyboard_rolloveramong them. Load averages were 48.83 50.91 59.99 before and 37.71 47.23 57.48 after, on 14 cores.Earlier heads:
cargo test -p toyos-xhci --lib(163 tests)f44d4c6c1f44d4c6c1usbd_drives_the_type_c_controller, the orchestrator's T14 run23fc14d3btoyos-xhciis unchanged sincef44d4c6c1, and its tests also ran inside the host suite at62930a2e2.At
f44d4c6c1the whole suite was red once, onnetstack_streams. It printed[qemu] Boot timed out waiting for ===READY===; the console carried: nothing at allafter 64 s, whilenetstack_streams_e1000epassed on the same netcase image. That is the shape of the open defectissues/a-netcase-boot-under-host-load-said-nothing-past-the-firmwares-screen-clears.md, and it is recorded there as a third witness with that run's load. It was not re-run. The round-2 review judged it not this branch's.What the guest test read at
20a40cd77(round 1, run with--nocapture; not re-read this round):wakes.timedandwakes.emptydid not move across the parked span.qemu-xhciadvertises no reset, so the second usbd's grant was placed at the first one's range on fresh pages.At
f44d4c6c1, the suite's own line:[usbd] 00:02.0: two devices named twice; aimed at 0x400042000000: ... iommu: DMA FAULT owner=slot1 unit0 stream=00:02.0 addr=0x0000400042000000 ... read-permission.T14 readings, recorded in the track
Stage 0: both controllers (00:0d.0, 8086:9a13, the Type-C one; 00:14.0, 8086:a0ed) read
USBLEGSUP 0x01002201andUSBLEGCTLSTS 0xe0000000in everyboot:testcasesreadback. Firmware's semaphore is clear, every SMI enable is clear, and only the three RW1C status bits are latched. Both are armed on MSI. At20a40cd77the usbd row printed 00:0d.0's release twice as reset by nothing. Which reset 00:14.0 advertises no boot has printed.What I am unsure of
events.unannounced = 0), and no operation went unanswered (operations.silent = 0). m1 shows the test reds when interrupts stop.drivers/xhci/legacy.rs) and its configuration parse (device.rs) besidetoyos-xhci's, by ruling, until the kernel's driver is deleted.dev:pci:claim, it panics by name. A refused bring-up panics with its reason, as netstack's undrivable card does.Net:
git diff --shortstat origin/main...62930a2e2gives 23 files, +2389 −6. Round 2's fix commit is 7 files, +38 −72. Round 3 adds only the merge.🤖 Generated with Claude Code
https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C