Repository navigation
A device function is claimed by its arrival, and a drives row has one process per function (lifecycle stage 1.2) - #926
Conversation
… process per function Stage 1.2 of issues/a-device-function-is-driven-from-its-arrival-to-its-end.md. The kernel no longer resolves a vendor:device id to a function. Each inventory `Pci` record carries an `Arrival`, the function's number for the boot, and `DeviceRequest::Function(arrival)` names it; deciding which function a row asks for is userland's. `DeviceRequest::Pci`, `toyos_pci::claimed` and its `Unclaimable` go. `ClaimError::Ambiguous` stays only where it is still true, a partition GUID carried twice. `lib/manifest` owns the PCI matcher grammar (`pci:CC:SS:PP` and `pci:CC:SS:PP/VVVV:DDDD`, `device::PciMatch`). Every matcher carries its class, so two entries one function can answer are refused when the manifest renders, naming both rows and entries; that refusal also takes over `one_claimant_per_device`'s duplicate class, `isa` and `part:` names. A `drives` row is one process per function its matcher names and the kernel does not drive: it serves nothing, holds no `devices`, has no `roles`, is in no `[boot] start`, and reaches its consumer through `receives`. The supervisor's lifecycle decisions are a pure crate, `toyos-supervisor` (`system/supervisor/lifecycle`), host-tested: restart policy and its budget, the claims a restart is owed, the one function a single-process `devices` matcher names (two refuse that row's start, naming both), and which functions a `drives` row has a process on. A refused start leaves its function alone until its inventory record changes, and every start of a function after its first spends its budget, so a reading that changed nothing starts nothing. The supervisor watches each child's `Process` handle on its loop's own poller and on the file worker's wait; the waiter threads, `Kept`'s mutex, the wake pipe and `Program::supervised` go. vdagent is a `drives` row, and its "no virtio-serial function" exit goes with it. Every `pci:` entry in the images gains its class, read from QEMU 11.1.1's configuration space. The test images whose jobs claim a function hold `inventory`, and the jobs find a function's arrival through one helper. `a_drives_row_holds_one_process_per_function` boots a q35 with two `edu` (`Profile::HeadlessTwoEdu`, `tests/images/drivescase.toml`): one `pciholder` per function, each saying its own, both still held when the job judges them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
…o complex Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… it say so The track records #926 as stage 1.2 and its present state. The child's-end track's stage 1 (the waiter threads) is done by it; the supervisor track's stage 2 starts from the `toyos-supervisor` crate it made; and the kernel track's step 10 names its usbd as this track's stage 4, a `drives` row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
diskserver's NVMe row is a class matcher with QEMU's id, matched by the supervisor, and two matching controllers refuse its start; the class grammar its exit names is `toyos_manifest::device::PciMatch`. `ClaimError::Ambiguous` is a partition GUID carried twice. The 3.8 ms claim keeps its measured figures, with a note that the path no longer exists in that form; it is not re-measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
|
Pushed since the draft opened:
The metal rows passed (T14 |
|
Review of #926 at ArchitectureThe ownership is right. The kernel now owns only what it must: a boot-stable number per function (
Brief item 1:
FindingsBLOCKERB1.
B2.
B3.
Records (brief item 5): sentences now falseThe track marks 1.2 done truthfully. The three folded tracks are updated accurately:
In the three issues the body names, these sentences are false at this head:
Confirmed (brief items 2, 3, 4 and 6)
SUGGESTION
VerdictSEND BACK: three small blockers (B1, B2, B3), and the record corrections above, which the orchestrator has said land in this PR. Once those are resolved this is LAND, pending the T14 and AMD bench rows. None of the three blockers changes behavior any test reads, so fixing them needs host checks only, not another guest run. |
…s a child runs B1: `PciMatch` parses its `VVVV:DDDD` card with `lib/manifest`'s own four-lowercase-digit rule, and the spelling test moved there. `PciId::parse` stays in the ABI as the `xhci-leave=` parameter's spelling alone, which its doc now says. B2: `exit_of` reads a wait without parking through `toyos_supervisor::restart::exited`: `WouldBlock` is a process still running, an exit code its end, and any other answer on the supervisor's own handle panics, as the deleted waiter did. Host-tested, both arms. B3: `DeviceRequest`'s doc says only what reads its spelling. S1: the drives arm counts the kernel's hand-overs and the holders' lines as lists, so a function handed over twice is red. S3: a `drives` row named in another row's `starts` is a render refusal, as one in `[boot] start` is: a launch would start it holding no function. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
…its exit reads a claim no boot makes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
|
Review round 1 (6173329461) answered at
Rerun: |
…it, and the issue names what remains - A bridge records the bus it sits on, and `bridge::path` walks from a function's bus to its root bus: each step is the one bridge whose secondary bus is the one reached, sitting on a lower bus, with the function's bus in its subordinate range. A bridge firmware never configured (both bus numbers 0) or one claiming every bus is no step, so no bus-0 function leaves the root runs on its word; two bridges naming one secondary bus refuse that bus's functions alone (`PathAmbiguous`). Host tests: the T14's bus-0 shape with such bridges, a two-level climb, the duplicate, and `Bridge::forwards`'s kind rule. - Candidates behind a bridge are cut from the firmware memory map too, as the root runs are. - A prefetchable BAR tries its port's prefetchable window first. - `trying` holds a candidate while it is probed and no longer; `cut` and `place_bar` say what they do for a candidate from either source; `NoRoutedRun` says only what is known. - The issue the interim refuted is renamed to the defect left, a BAR behind a bridge with no free 2 MiB of its windows, and `there-is-no-wifi` cites it by its new name. Before this branch every candidate behind a bridge lay outside it, since the root runs exclude every forwarded range. Merges origin/main e136c77 (#926), keeping both new q35 profiles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
…w moves to P1 Conflicts: `usbd_spare` claims by arrival as #926 has every job do, in the shared `src/usbd_spare.rs` this branch moved its arms into: the one function of a spare's card the kernel does not drive, or, where it drives every one, the only one (the AMD bench's `03:00.3` and `03:00.4` share an id). `tests/toyos.rs` keeps #926's `drives` row beside this branch's refusal rows. `amdvi_usbd_drives_its_own_entry` leaves the registered AMD rows for P1's exit in `issues/there-is-no-wifi.md`: on the AMD bench `03:00.4`'s only BAR sits behind port `00:08.1`, whose window `0xd0000000..0xd0500000` bus 3 fills, so it cannot move to a 2 MiB slot of its own and stays where firmware put it, which only P1's 4 KiB pages hand over. Its jobs stay; its judge `amdvi_usbd` goes and comes back with P1 (at c648c14). `issues/an-amd-vi-machine-isolates-no-device.md` closes: its rows passed on the AMD bench at c648c14 (`amdvi_translates_the_stick_controller`, `amdvi_remaps_the_stick_controller` with `SmiFEn` and `SmiFLogEn` set, `amdvi_claim_refused_without_remapping`), its remaining claim reading is P1's. Every citation of it is rewritten. The MSI-X issue stays open, depending on P1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
Stage 1.2 of
issues/a-device-function-is-driven-from-its-arrival-to-its-end.md, after #910 (stage 1.1). It follows the design accepted on #910 (6153045378 D1–D5, 6153203682 B2/B3/B8, 6153972713's split).Problem
A
devicesrow named a PCI function by vendor and device. The kernel resolved that name, and it refusedAmbiguouson a machine with two of one card, so the decision about which function a row wants sat in the kernel. A row had one process, started only from[boot] start. One supervisor thread per service parked inSYS_PROCESS_WAITto see it end. The restart policy was spread acrosslib/manifest, a waiter thread and the loop.Change
toyos_abi::inventory::Pcirecord carries anArrival: the function's number for the boot, never another's (bytes 16..20 of the record).DeviceRequest::Function(arrival)names a function.DeviceRequest::Pci, thepci:spelling intoyos-abi,toyos_pci::claimedandUnclaimableare deleted.SysCap::claim_pcibecomesclaim_function.endow::pci_functionbecomesendow::claim(name), which looks a claim up by its entry's spelling.lib/manifest's (device::Entry,device::PciMatch):pci:CC:SS:PPandpci:CC:SS:PP/VVVV:DDDD, the card spelled by the manifest's own four-digit rule.PciId::parsestays in the ABI only as the kernel'sxhci-leave=parameter. Fixed rows (classes,part:,isa:) keep the ABI's spelling. Every matcher carries its class, so overlap is decided from text alone.toyos_manifest::renderrefuses the following, and the build panics with the error, so every config is held to them byevery_config_renders_its_manifest:RenderError::Overlap). This replacesone_claimant_per_deviceand keeps its refusal of duplicate class,isaandpart:names;drivesentry that is no PCI matcher;drivesrow withserves,rolesordevices, or one listed in[boot] startor in another row'sstarts.toyos-supervisor(system/supervisor/lifecycle, pure, host-tested) holds:restart, moved out oflib/manifestalong withProgram::supervised);devicesmatcher names (claims). Two matching functions refuse that row's start, naming both;drivesrow has a process on (drives). A refused start, and an end owed no restart, leave the function alone until its inventory record differs from the first one read after. Every start of a function after its first spends that function's budget, and a spent budget gives the function up.Processhandle on its loop's poller and on the file worker's wait. A wait without parking reads as running only onWouldBlock; any other refusal on its own handle panics (restart::exited), as the deleted waiter did. The waiter threads,Kept's mutex, the wake pipe andclose_when_it_endsare deleted. It reads the inventory at boot and after every end, and performs whatDrives::decideanswers. Adrivesprocess is started with its function's claim under the matcher's spelling, its row'sreceives, and a log ring of its own.drivesrow (pci:07:80:00/1af4:1043). Its "no virtio-serial function" exit is deleted: no instance starts where nothing matches, and the T14 starts none.pci:entry gains its class, read from QEMU 11.1.1's configuration space rather than assumed (evidenceclasses/): NVMe01:08:02, virtio-net02:00:00, virtio-sound04:01:00, virtio-serial07:80:00,edu00:ff:00. netstack's I219 and 82574 matchers are02:00:00from the PCI Code and ID Assignment class; no image names either.Decisions to check
ClaimError::Ambiguousstays, for partitions only. The brief said it goes, but a GPT unique GUID carried twice (gpt::seek) still names two partitions. It has no arrival to choose by, andInvalidArgumentis still the honest answer. Only its PCI meaning is deleted.serves:servesnames only the shared-service role here, so it is refused on adrivesrow. Adrivesprocess reaches its consumer as a client throughreceives, wired as every row's is. I also refuserolesanddeviceson such a row: a single-process claim held by one of several processes has no meaning.drivenincluded, so a function a competing holder gives back is retried. One consequence: after a failed spawn, the supervisor's own dropped claim is released throughZERO_QUEUE(a live process's close;issues/deferred-release-outlives-its-syscall.md). If the next reading sees that release still pending, the function counts as changed and is retried once more. The budget bounds this, and readings happen only at an end, so nothing spins.MAX_CHILDREN(216) is what one poller can watch beside the loop's own tokens. Adrivesprocess past it is refused by name.test-runnergainsinventoryintestcasesandvirtclaimcase, whose jobs find a function's arrival throughtests/guest/rust-tests/src/function.rs.Tests
toyos-supervisor13 tests, among thema_refused_start_is_not_retried_until_its_record_changes,a_function_that_keeps_refusing_is_given_up_onandtwo_matching_functions_refuse_the_start_naming_both. Grammar, overlap and refusal tests are intoyos-manifest.two_rows_on_one_function_are_a_build_refusal_by_nameis in the build crate.a_drives_row_holds_one_process_per_function(new, QEMU x86-64,Profile::HeadlessTwoEdu: theHeadlessq35 plus twoedu;tests/images/drivescase.toml). It needs a guest because the claims by arrival, the two spawns and each holder's own function have no host build. No bench has two identical functions left to a claim, so it has no metal row. What it checks:eduover exactly once (counted, not a set);pciholders (tests/guest/pciholder, test-only) each print the function they hold, and the two printed sets are equal;test_rs_drives_judgedthen reads both asClaimedbypciholder, under distinct pids.usbd_drives_the_spare,the_opening_exchange_with_qemus_agent_completes(vdagent as adrivesprocess),bar_map_again,lent_device_memory_refused,iommu_virtio_platform(its supervisor lines now spell the matcher) andvirt_claim_lpi(aarch64).cargo run -- --ci host14a707b1b, and28360a6e5after review round 1cargo test --test toyos-build -- --nocapture a_drives_row_holds_one_process_per_function28360a6e5cargo run -- --build-only14a707b1bcargo test --test toyos-build -- --nocapture a_drives_row_holds_one_process_per_function usbd_drives_the_spare the_opening_exchange_with_qemus_agent_completes bar_map_again lent_device_memory_refused iommu_virtio_platform virt_claim_lpi14a707b1btoyos-supervisortests14a707b1b+patchtoyos-supervisortests14a707b1b+patchtoyos-manifesttests14a707b1b+patch14a707b1b+patchusbd_drives_the_type_c_controller(testcases-xhci-leave, its two jobs and assertions unchanged), run by the orchestratorc3f4e070famdvi_translates_the_stick_controller(testcasesboot), run by the orchestratorc3f4e070fc3f4e070fand9029901b5change onlyissues/after14a707b1b. Review round 1 (28360a6e5) changes the manifest's card parse,exit_of's classification, a doc, a render refusal and the drives arm's judge: the host run and the drives arm were rerun; the other six QEMU rows and the benches were not, since none of them reads those paths (exit_of's new arm is an error path, held by the crate's host tests). Every check before the merge of main, at26609b4cd, was rerun after it, because #916 changedpcidev.The whole-change control cannot run as a test: the base has no
drivesfield, so the guest arm's image does not build there. The informative controls are the four mutations above.Evidence: https://github.com/ToyOSOrg/evidence/tree/d05131156f8d780c6d6a231d2c5aacb69c9bbb01/lifecycle-s1/stage-1-2 (the metal runs, masked, under
metal-runs/; review round 1 underreview-1/).Records
toyos-supervisor, and the kernel track's step 10 names usbd as this track's stage 4drivesrow.9029901b5):issues/diskserver-claims-qemus-nvme-by-its-pci-id.md: its row's spelling, who matches it, the two-controller refusal and the grammar its exit names. Its class-only rows and itsuse-intel-idboot are still owed.issues/a-claims-own-refusals-are-read-by-nothing.md:ClaimError::Ambiguousis a partition GUID carried twice.issues/the-supervisors-claim-of-a-pci-function-the-t14-lacks-holds-preemption-off-for-3-8-ms.md: the 3.8 ms stays as measured, with a note that the path no longer exists in that form, that one unmeasuredSYS_DEVICE_INVENTORYread replaced it, and that its exit reads a claim no boot now makes (8d9503f47). It is not re-measured.Declined
usbd_spareandend_returns_claimsstill endow and print the oldpci:VVVV:DDDDform. usbd looks its claim up by thedev:pci:prefix, so either spelling works, and changing it would changeusbd_drives_the_spare's and the T14 row's asserted lines. Stage 4'sdrivesrow for usbd is where the matcher spellingpci:0c:03:30/…becomes its label.Cost
toyos-supervisoris about 250 lines and its tests about 220. The manifest grammar is about 200 lines, under half of them tests. The supervisor is +328/−271. Kernel, ABI and SDK are net −78 (+128/−206), as the review measured.pciholder), one 50-line judge job, one image and one profile.Risks
🤖 Generated with Claude Code
https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1