Repository navigation
AMD-Vi stage 6: interrupt remapping, and claims only where every unit filters SMIs - #921
Conversation
…invalidation Stage 6 of issues/an-amd-vi-machine-isolates-no-device.md encodes, against AMD 48882 rev 3.11's own field positions: - a device table entry's interrupt half (Table 7, bits 191:128): IV, a 256-entry table (IntTabLen 1000b) at its root, IntCtl 00b (aborted) or 10b (remapped), and the pass bits where Table 7 puts Table 106's; `Setting::CLAIMED`, which passes nothing and gives no SysMgt (review B2 of the stage 5 design); - the 128-bit remapping entry, GuestMode 0 (Figure 17, Table 22; Figure 19 with XTEn): RemapEn, fixed, physical, the vector at 71:64, an 8-bit or a 32-bit destination; - INVALIDATE_INTERRUPT_TABLE (Figure 48), CONTROL's GAEn and XTEn, and EFR's GASup and XTSup. Host tests hold each against the specification's bit positions, and the bench's EFR as having GASup and XTSup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
Stage 6 takes a claim's vector from #918's allocator (`idt::user_dev`, `kernel::owners`) rather than beside it, as the orchestrator directed. No conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
…8-bit entries, claims through their own Stage 6 of issues/an-amd-vi-machine-isolates-no-device.md, the second PR of the design accepted on #909 (AMD 48882 rev 3.11). - Where every programmed unit has GASup (and XTSup where the CPUs run in x2APIC) and the IVRS names every I/O APIC the MADT has, the kernel remaps: CONTROL gains GAEn (and XTEn on x2APIC), every device table entry's interrupt half is IV with IntCtl 00b (each requester's fixed messages aborted) before IommuEn, and a requester's first entry makes it a 256-entry table of its own (IntTabLen 1000b), named by one 64-bit write and an INVALIDATE_DEVTAB_ENTRY (§2.2.2.2). Otherwise every interrupt half stays invalid and messages pass as written, and the remapping decision says which requirement is missing. - The table is indexed by MSI data bits 10:0 (Figure 14), so with fixed delivery the entry is the message's own vector: a function keeps the compatibility message it would carry with no unit, and reaches only the vectors its own table holds present. Source verification is the table's. - Kernel drivers' messages, claims' and I/O APIC pins' each write the entry at their vector; a pin keeps its redirection entry's ordinary format, so a level pin's EOI names the vector the CPU took. A claim takes its vector from #918's allocator; its release writes the entry absent and invalidates before the vector is given back. - A claim marks its function claimed: from then on its entry passes nothing firmware declared (no NMI, INIT, ExtInt, LINT) and gives it no SysMgt, whichever domain it names (stage 5 review B2). - A claim on a function no programmed unit serves, or one an IVMD names, is refused at the claim (`Refusal::NotIsolated`), before a domain or a vector is spent (stage 5 review S2). - `iommu_unit::interrupt` dispatches to the backend that remaps; the message, pin and refusal types it shares move there from VT-d, whose module keeps only its entries. - Harness: `Unit::AmdVi { intremap }` (`intremap=on,xtsup=on` and the split irqchip), `Profile::HeadlessUsbSpareAmdVi`, and `usbd_drives_the_spare_amdvi`, which also reads the claim's entry present at its vector. The AMD bench's row `amdvi_remaps_the_stick_controller` reads GAEn, every I/O APIC named, and each kernel-driven xHCI armed through its own entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
|
Orchestrator ruling: on a machine where every unit remaps, The refusal in This PR takes up that issue: it rewrites the exit to the remapping condition and keeps the non-remapping arm recorded. |
…-leave takes an address; the AMD bench's claim rows The orchestrator's ruling on #921: on a machine where every unit remaps, the BAR holding a function's MSI-X table is handed over, because the unit's per-requester table is the guard: a message the holder writes there reaches only the claim's own interrupt, and anything else is refused and recorded. A claim exists only where the machine remaps (`Refusal::NotRemapped` first), so `place_bars` takes the `Remapping` witness and no longer keeps the table's BAR back; `msix_bar` goes. The release masks the entry where the table is now, since its BAR may have moved since it was armed. Takes up issues/a-controller-whose-msix-table-is-in-bar-0-cannot-be-driven-from-userland.md, its exit rewritten to that condition. - `xhci-leave=` names a function by `bus:device.function`: the AMD bench's two xHCI controllers share one id. The T14 row names `00:0d.0`; QEMU's spare is pinned at `00:10.0`. - `usbd_spare`'s arms move to `tests/guest/rust-tests/src/usbd_spare.rs`, with a binary each for the fault, foreign-vector and unremapped-refusal arms, because a metal job takes no argument. The new `vector` arm rewrites the claim's own MSI-X entry, through the BAR it now holds, to a vector not the claim's, and reads that usbd is never told of its No-Op. - QEMU: `Profile::HeadlessUsbSpareAmdVi`'s spare is armed on MSI-X with its table in its register BAR; `usbd_drives_the_spare_amdvi` adds the foreign-vector arm; `usbd_refused_without_amdvi_remapping` boots the AMD unit with `intremap=off` and reads the claim refused before anything on the function changes. QEMU records no fault for the refused message, filed as issues/qemus-amd-iommu-records-no-fault-for-a-message-its-table-refuses.md. - AMD bench rows: `amdvi_usbd_drives_its_own_entry` (`03:00.4` handed over with its table's BAR, its No-Op answered through its own entry, aimed past its grant and recorded at that address, its holder's foreign vector refused and recorded and absent from the stop's unclaimed census), and `amdvi_claim_refused_without_remapping` (`iommu-no-remap`); the AMD unit now says when that actuator stands in for a unit that cannot remap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
…gain #918 moved since 9b39b7c: review round 1 and two merges of main (#895, #917 and more). No conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
#918 landed; main's copy now stands where the pre-merged branch did. No conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
|
Build review: #921 at AssessmentThe stage-6 architecture is the one accepted on #909, and it is built well:
The encodings match the specification:
The index = vector rule holds because The release order is right:
S2's refusal comes before Three things fall short of what the ruling and the PR claim:
Two test and judge defects would make the bench row red regardless of the hardware, or make a QEMU arm unable to fail (B4, B5). FindingsB1 BLOCKER: on AMD-Vi, a holder of a handed-over MSI-X table can raise SMIs, so the ruling's premise does not hold. Locations:
Problem:
Consequence: the holder of Fix: this changes the basis of an orchestrator ruling, so it goes back to the orchestrator. The options I see:
Either way, the pcidev header should state the actual condition. B2 BLOCKER: B2 and per-requester isolation fail for a function that shares its requester id with an IVHD special entry. Locations: Problem:
Consequence: a claim on such a function writes its vector into the I/O APIC's table. Its entry keeps every pass bit, and it reaches every pin vector. On the bench Fix:
B3 BLOCKER: release asserts on device-supplied config space. Locations: Problem: Fix: compute the entry's address from the kernel's own record:
No config re-read and no assert on external input. Alternatively, arm after B4 BLOCKER: the bench judge reads the stop's census from a log that never carries it. Location: Problem: Consequence: Fix: read the census from B5 BLOCKER: the QEMU foreign-vector arm cannot fail, and three texts claim it shows a refusal. Locations:
Problem: the arm asserts only that usbd was never told of its No-Op. A unit that forwarded the message unmapped to 0x43 passes it too, because 0x43 is an unheld claim vector that Fix (cheapest): have the QEMU arm read the census after a clean stop and assert that 0x43 is absent. That gives QEMU an oracle, and the issue's wording then becomes true. Otherwise drop the arm from QEMU and correct all three texts to say the bench row holds the refusal. B6 BLOCKER: stale or false records and contracts.
S1 SUGGESTION: S2 SUGGESTION: S3 SUGGESTION: S4 SUGGESTION: S5 SUGGESTION: the handover also applies on AArch64 ITS machines through the same Evidence
What the three bench boots must show (re-judged after B4's fix):
A green SEND BACK |
|
Orchestrator on the build review (6163050204): send back, with this ruling on blocker 1. B1, ruled: the unit's SMI filter is enabled, logged, on every AMD-Vi unit the kernel programs (48882's SMI filter registers), and a BAR holding a function's MSI-X table is handed over on AMD-Vi only where every programmed unit filters SMIs; where a unit cannot (no
|
No conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
…e messages are fenced, and the build review's fixes Build review of #921 (6163050204) and the orchestrator's rulings (6163086612). - B1, ruled: every AMD-Vi unit with an SMI filter (EFR `SmiFSup` 01b) has it on and logging (CONTROL `SmiFEn`, `SmiFLogEn`; 48882 §2.1.5), its registers left as firmware set them and each said at boot. An SMI is no remapped message (Table 10, Table 19), so a holder's own MSI-X table could otherwise send one to every CPU. `Remapping::fences_tables` says whether a message written into a claim's table is fenced: VT-d and the ITS always, AMD-Vi only where every programmed unit filters. Where not, `pcidev` keeps the table's BAR back and says so by name. A refused SMI from a requester no claim holds is said and the machine goes on; a claimed function's is its holder's fault. - B2: a claim on a requester id an IVHD special entry uses (I/O APIC, HPET), or one the SMI filter passes, is refused at the claim (`iommu::isolates`, `unclaimable`); a claim asserts no other source wrote its requester's remapping table first. - B3: the release masks the MSI-X entry at an address from the BIR and offset captured at arming and the BAR address the kernel placed, never the device's answer; nothing there can panic on the device. - B4: the bench row reads the stop's census after the reset. - B5: QEMU's unit has no SMI filter, so under the ruling it hands no table over and the foreign-vector arm leaves QEMU; its spare is armed on MSI again. `usbd_table_kept_without_smi_filter` reads, on an MSI-X spare, the table's BAR kept back by name and the claim refused. The two issues' texts say what was measured. - B6: `device_bar_map`'s contract, the track issue's remaining work and exit, the guest-test registration, `iommu-no-remap`'s contract and the spare list's doc are true of the tree. - `FLASHABLE` rows for `xhci-leave=00:0d.0` and `xhci-leave=03:00.4`, the old id form gone; `iommu-no-remap`'s row covers AMD-Vi. - `usbd_spare`'s refusal arm is `unhanded`, for any refusal whose reason the kernel's line gives. One helper for an entry's interrupt half; the xHCI driver names the left controller by `pcidev::requester`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
|
Focused re-review: #921 at AssessmentMost of the round is right, and B2–B6 are fixed as ruled.
One finding goes back to the orchestrator because it changes where the ruled fence belongs. On AMD-Vi, the MSI-X table is not the only way a holder can make its function send an SMI: any DMA write the holder points at the interrupt range is one too. So withholding the table's BAR does not fence SMIs where a unit has no filter. The fence belongs at the claim, and putting it there would also delete most of this round's withholding machinery. FindingsR1 BLOCKER (orchestrator decision): on AMD-Vi without an SMI filter, a granted claim still lets its holder raise SMIs; keeping the table's BAR back does not stop it. Locations: Why:
Consequence: wherever Options for the orchestrator:
R2 BLOCKER: The mask Consequence: if the unit writes those reserved bits as ones, a refused SMI from a function this kernel drives is not recognised. It falls through to Fix: mask R3 BLOCKER: the ITS doc comment is misplaced. Location:
R4 BLOCKER: the doc of a profile this PR relies on is now false. Location: It still says the spare is "the controller R5 BLOCKER: the 03:00.4 The measured facts in the row are right:
But the survival argument is "firmware … takes it back at the next power-on". The gate's criterion (
The T14 row ( R6 BLOCKER: this round's QEMU and host evidence is stamped on an uncommitted tree, and the PR table presents it as head. Location: PR body, "Build-review round" table.
I re-ran both at the clean head, so this needs only a body correction:
S1 SUGGESTION: S2 SUGGESTION: S3 SUGGESTION: the comment at S4 SUGGESTION: consider locking the filter registers ( B1–B6 against the rulings
Records
Evidence (this review)
For the running bench rows, as inference: this round enables the filter before the kernel's xHCI handoff on a platform whose controllers have SMI-on-ownership armed. A boot that shows SEND BACK |
|
Orchestrator rulings on review 6166411911 (round 3).
Focused re-review on the fixes after the bench rows. |
…and every claim needs it Round-3 review and the AMD bench's hang at 4f1d6fc. The hang: 4f1d6fc turned every unit's SMI filter on in `program`, before the kernel took its xHCI controllers from firmware, with no register valid on the bench (firmware names no source there). This bench resets through `SMI_CMD` (its FADT's reset register is port 0xB0), and an SMI the chipset raises upstream is what the filter refuses (48882 §2.1.5.1); with every source refused, neither the boot deadline's reset nor a panic's could end the boot. That is an inference from the earlier boot's log and the specification; the hung boot's own log is unread. - The filter is planned at `init` and turned on by `iommu::drivers_settled`, after every kernel driver took its functions and before userland runs. It passes what firmware left valid and every id the IVRS names the chipset's I/O APIC and HPET by, every register locked (§2.1.5.3); a unit with too few free registers filters nothing, said. The chipset raising the platform's SMIs under those ids is an inference the bench reads. - Every unit's filter is off before the reset register or `SLP_EN` is written, lock-free from the fault handler's unit table. - R1 (ruling a): a write to the interrupt range is an interrupt (§2.1.4.2), so withholding the table's BAR closed nothing. `iommu::remapping` is now the one gate: a claim exists only where every message reaches only its own interrupt, which on AMD-Vi needs every unit filtering SMIs; the refusal names which. The withheld-BAR path, `fences_tables`, `HeadlessUsbSpareAmdViMsix` and `usbd_table_kept_without_smi_filter` are gone; `usbd_drives_the_spare_amdvi` is `usbd_refused_without_smi_filter`. - R2: an SMI's address is read by Table 4's fields only, bits 63:48 not read; `toyos_amdvi::queue::event` decodes `RefusedSmi` itself. A claimed function's refused SMI is its holder's fault; any other's is logged, bounded, and the machine goes on. Whether a claim holds the function is read without a side effect (S1). - R3, R4, R5: `fences_claims` and `is_armed` documented apart; the spare's profile names 00:10.0; the FLASHABLE rows argue from the reset that ends every boot. - S2: the special entry's reason is a match on its variety. S3: the claim's comment names `pcidev::claim` for a kernel driver's function, and the SMI rationale lives at `fences_claims`. S4: the filter's registers are locked once written. - `amdvi_remaps` reads `SmiFEn` and `SmiFLogEn` on every unit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
…intremap pcidev: main's root-bridge declaration (`windows` to `bring_up` and `place_bars`, the `Undeclared` and `AperturesRefused` refusals) beside this branch's `NotRemapped` reasons and `NotIsolated`; the table's BAR is placed like any other, so `table_bar` goes. amdvi: `domain::start` takes main's optional reserved ranges and this branch's platform ids. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Round 4 on the AMD bench at
Cause (my reading of the log): |
|
The round-3 hang, witnessed on the panel. The owner re-ran the So it was a panic, not a silent halt: with the filter on and no source admitted, the unit logged the chipset's refused SMI (stream |
|
Correction to my round-4 reading above (6173159858). The red |
…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
The round-3 panic on the AMD bench, photographed on its panel, shows the unit's IO_PAGE_FAULT for a message it refused from 00:14.0 at 0xfffffffdf8000020: bits 63:40 all ones, the interrupt range as 48882 §2.2.5 writes its base (FFFF_FFFD_F800_0000h), where Table 4 gives an SMI's 47:40 as zero. `smi` now takes 63:40 all zero or all ones; any other value there is no SMI's. The host test holds both forms and a partial extension. That record's MT reads 000b, not Table 4's SMI 010b, so this decoder still reads it as a requester's fault; whether the filter or the remapping table refused it is not settled by one reading (the PR says so). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
The merge's claim by arrival bound one arm's `Pci` by reference twice and the other once; the guest job did not build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
pcidev: #928's bridge windows (`Bridge`, `msix`) beside this branch's table BAR placed like any other. On the AMD bench `03:00.4`'s one BAR, which holds its MSI-X table, now meets `NoRoutedRun` behind `00:08.1` and the claim is refused `NoMappableBar`; the issue #928 opened says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
|
Orchestrator ruling on the open risk (a platform message the filter does not pass). A record in the interrupt address range (48882 §2.2.5's form or Table 4's) from a requester id the IVRS gives to the platform (I/O APIC, HPET, any special entry) is the platform's message, whatever its type field says: it is logged with its id, type and address and the machine keeps running. It is never a kernel DMA fault, because no kernel driver owns those ids and no claim can hold them (B2 refuses them at the claim). The bug fence stays for every other stream. A second boot with the filter passing only |
…'s, whatever its type The orchestrator's ruling on #921 (6179195333). The round-3 panic's record was an IO_PAGE_FAULT from 00:14.0, the id the IVRS gives the chipset's I/O APIC and HPET, at 0xfffffffdf8000020: the interrupt range, `MT` 000b. Read as a DMA fault on a kernel-owned stream, it panicked the kernel. No kernel driver drives a platform id and a claim on one is refused (`domain::unclaimable`), so nothing of this kernel's went wrong. `toyos_amdvi::queue::event` decodes any IO_PAGE_FAULT at an interrupt-range address (Table 3, either address form) as `Event::Interrupt`, and `disposition` says whose it is: a platform id's whatever its type, a held function's its holder's fault, an SMI from anyone else said, any other a fault. The drain reads the platform ids from a lock-free table `init` publishes before any unit is armed, and says a platform message or an SMI with its id, type and address, bounded to powers of two. Host tests: the decoding of both address forms, and the disposition of the round-3 record from 00:14.0 (platform) and from anyone else (fault). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
|
AMD bench readbacks at
Readbacks:
|
|
Focused landing re-review: #921 at AssessmentThe kernel side is right and matches the rulings.
What remains are records and one ABI doc that still describe the deleted BAR-withholding. FindingsB1 BLOCKER —
B2 BLOCKER — two open issues still describe and require the mechanism this PR deletes.
B3 BLOCKER — the MSI-X-table records contradict each other.
S1 SUGGESTION —
S2 SUGGESTION —
S3 SUGGESTION — wording.
S4 SUGGESTION — the Records and PR body (for the orchestrator)
SEND BACK |
…issue closed into P1, `I` read as an interrupt B1: `device_bar_map`'s contract names no withheld BAR; on a machine that would not fence a message the claim is refused whole. B2: `issues/a-claims-own-refusals-are-read-by-nothing.md` loses the withheld-table bullet and exit clause; its subject, a claim's refusals read by nothing, stands. `every-driver-is-still-in-the-kernel.md` and `the-kernel-is-small-interrupts-post-and-threads-wait.md` no longer cite `pcidev::msix_bar` or a claim refused for its table's BAR. B3, ruled: `issues/a-controller-whose-msix-table-is-in-bar-0-cannot-be-driven-from-userland.md` closes into P1 of `issues/there-is-no-wifi.md`, whose `03:00.4` bullet carries the dependency and its reason; P1's bullet rewriting that issue's exit goes, and so does the hypervisor issue's citation of it. The rule it leaves: a claim exists only where every message its function sends reaches only its own interrupt, and there the table's BAR is placed like any other (`kernel/src/pcidev/mod.rs`'s header). S1: an `IO_PAGE_FAULT` with `I` [51] set is `Event::Interrupt` whatever address it names (Table 57), so a refused platform message in another address form is the platform's too. S2: the platform ids are published once each. S3: `drivers_settled`'s doc and the claim's re-claim case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1
Stage 6 of the AMD-Vi track: interrupt remapping and the SMI filter, the second PR of the design accepted on #909. Draft, for the landing round. It closes
issues/an-amd-vi-machine-isolates-no-device.md: its translation and remapping rows passed on the AMD bench, and its claimed-function clause, a claim's message delivered through its own remapping entry with a foreign one refused, did not pass but moved to P1 ofissues/there-is-no-wifi.md(the03:00.4bullet, with its reason). It also closesissues/a-controller-whose-msix-table-is-in-bar-0-cannot-be-driven-from-userland.mdinto P1 (ruled): the table's BAR is no longer withheld, and what remains is P1's placement.Source: AMD 48882 rev 3.11, SHA-256
f7c375a15db5ed63de760356867211063d164a2ed59f2d38613daec95894ce22, cited at each site.What this PR does
GASup(andXTSupon an x2APIC machine) and the IVRS names every I/O APIC the MADT has. Otherwise every interrupt half stays invalid and messages pass as written, said by name.iommu-no-remapstands in for a unit that cannot remap.CONTROLgainsGAEn(andXTEnon x2APIC). Every device table entry's interrupt half aborts fixed and arbitrated messages until its requester has a 256-entry table of its own, indexed by vector. Kernel drivers, claims and I/O APIC pins each write the entry at their vector and invalidate it. A message on a vector the requester's table does not hold is aborted and recorded.initeach unit withSmiFSuphas its filter planned: what firmware left valid, plus the ids the IVRS names the chipset's I/O APIC and HPET by, every register locked (§2.1.5.3).iommu::drivers_settled()runs after the kernel's drivers have taken their controllers from firmware and before userland starts. It writes the registers and setsSmiFEn | SmiFLogEn, loggingSMI filter on control=… passing …. A unit with too few free registers filters nothing, said.SLP_ENis written.IO_PAGE_FAULTat an interrupt-range address (Table 3; bits 63:40 all zero, or all ones as the unit writes the range's base).toyos_amdvi::queue::dispositionsays whose it is:IO_PAGE_FAULTwithI[51] set (Table 57) is a refused message too, whatever address it names;iommu::remapping()grants a claim only where every message its function sends reaches only its own interrupt, whatever its holder writes into its MSI-X table or aims a DMA at. On VT-d and the ITS that means remapping. On AMD-Vi it also needs every unit filtering SMIs, since a write to the interrupt range is an interrupt (§2.1.4.2) and an SMI no remapped message (Table 10). Where a claim is granted, the MSI-X table's BAR is placed like any other. Refusals say which reason applies:its interrupts would not be remapped…oran IOMMU unit on this machine filters no SMI….SysMgt, for the rest of the boot.usbd_refused_without_smi_filterreads that refusal.The round-3 panic, and its fix
At
4f1d6fc3athetestcasesimage hung the AMD bench, which never reset itself. The owner's photo of the panel (photo, metadata stripped; transcribed in comment 6173269406) shows its end:That tree turned the filter on in
program, before the kernel's xHCI handoff, with no register valid. Firmware leaves the filter off on this bench, with 2 registers. The unit then refused a message from00:14.0, the id the IVRS gives the chipset's I/O APIC and HPET, and recorded it as anIO_PAGE_FAULT. The decoder read that record as a DMA fault on a kernel-owned stream, and the kernel's bug fence panicked. The panic's reset writesSMI_CMD(0xb0 <- 0xfbon this bench). The SMI the chipset raises for it would reach the filter under the same refused id, which explains, as an inference, why the machine never reset. The stick held only the loader's log.Round 4 changed three things:
00:14.0and00:00.1);At
c648c1439the bench readiommu: amdvi unit0 SMI filter on control=0x000000000142140d, passing 00:14.0 00:00.1, logged no refused message, and reset itself.The record's type. Its address
0xfffffffdf8000020has bits 63:40 all ones, the interrupt range as §2.2.5 writes its base, and itsMTreads 000b, a fixed interrupt, not Table 4's SMI 010b. Whether the filter or00:14.0's remapping table refused it is not settled by one reading. Under the orchestrator's ruling (6179195333) that no longer matters: since1ceab43bc, a refused message from a platform requester id is the platform's whatever its type, logged and survived, never a kernel DMA fault. No kernel driver drives those ids, and a claim on one is refused.P1 dependency
amdvi_usbd_drives_its_own_entrycannot pass on the AMD bench before P1 ofissues/there-is-no-wifi.md. The row claims03:00.4, whose only BAR holds its MSI-X table. That BAR sits behind port00:08.1, which forwards only0xd0000000..0xd0500000, and bus 3's BARs fill that window. The claim needs a BAR placed where the bridge forwards it, and a 2 MiB slot of its own does not exist there. Atc648c1439, before #928, the claim probed addresses the bridge does not forward and was refused withits BAR was moved onto 8 64-bit address(es) … and the function answered at none of them. With #928 merged (335927b83), this branch places the table's BAR like any other, so03:00.4's one BAR meetsNoRoutedRun(keeps BAR 0 where firmware put it and hands it to nobody — no 2 MiB the bridges above it forward is free) and the claim is refusedNoMappableBar. The issue #928 opened now says so. The AMD-Vi filter is not involved.The row therefore leaves the registered AMD rows and goes into P1's exit. Its four jobs stay (
usbd_spare,usbd_spare_fault,end_returns_claims,usbd_spare_vector), and its judgeamdvi_usbdcomes back with P1 fromc648c1439. The T14'susbd_drives_the_type_c_controllerrow is unchanged. Thexhci-leaveimage is no longer staged: no registered row judges that boot, and the named refusal is #928's to read, not this PR's.#928 landed and is merged here.
AMD bench at
639028982(orchestrator's run, the landing images)3 of 3 rows pass in 2 boots (judge):
amdvi_translates_the_stick_controller,amdvi_remaps_the_stick_controllertestcasesSMI filter on control=0x000000000142140d, passing 00:14.0 00:00.1; no event record; the machine reset itselfamdvi_claim_refused_without_remappingtestcases-amd-no-remapReadbacks: testcases kernel log, no-remap kernel log, manifest, runner log. The
testcasesboot'sACPI_ENABLEwrite toSMI_CMDat 7.411 s, after the filter went on at 7.368 s, setSCI_EN: the platform's runtime SMI passes with the filter on. The commits since (1ceab43bc, and this round'sIbit) change only the event decoder, which acts only on a record; these boots wrote none.AMD bench at
c648c1439(orchestrator's run)amdvi_translates_the_stick_controller,amdvi_remaps_the_stick_controllertestcases, alone first00:14.0 00:00.1; the machine reset itselfamdvi_claim_refused_without_remappingtestcases-amd-no-remapamdvi_usbd_drives_its_own_entrytestcases-amd-xhci-leaveReadbacks: judge, testcases alone, judge, all three, testcases kernel log, no-remap kernel log, xhci-leave kernel log, manifests r4a and r4b. Machine, stick and user identifiers are masked.
Checks at
4b052d558(the landing re-review's records,Iread as an interrupt)cargo run -- --ci hosttoyos-amdvi22 tests,a_refused_message_is_told_from_a_dma_faultanda_page_fault_is_its_requesters_with_its_accessnow holding anI-set record asEvent::Interruptcargo test --test toyos-build -- amdvi_selftest amdvi_firmware_left usbd_refused_without_smi_filter usbd_refused_without_amdvi_remappingI-set selftest record still readsowner=kernel … access=none … IO_PAGE_FAULTThis round also:
device_bar_map's contract no longer names a withheld BAR (B1). The two issues that still described the withheld table BAR are corrected (B2). The MSI-X-table issue is closed into P1 (B3, ruled). The platform ids are published once each (S2). Two comments are reworded (S3). Theusbd_sparevectorandfaultjobs stay, because P1's03:00.4bullet names them; their judgeamdvi_usbdcomes back fromc648c1439with P1 (S4).Checks at
1ceab43bc(the platform-message ruling, on639028982)cargo run -- --ci hosttoyos-amdvi22 tests, witha_refused_message_is_told_from_a_dma_faultanda_platform_message_is_the_platforms_whatever_its_type(the round-3 record,MT000b from00:14.0: the platform's; from anyone else: a fault)cargo test --test toyos-build -- amdvi_selftest amdvi_firmware_leftdispositioncalling a platform id's message the platform's only when it is an SMI (patch);cargo test -p toyos-amdvia_platform_message_is_the_platforms_whatever_its_typeredNo third bench boot for this change. It changes only the fault decoder and the drain, which act only when the unit writes an event record. The bench's boots at
c648c1439wrote none, and the two staged boots at639028982judge the same rows. Theamdvi_remapsjudge's change is print-only: it prints the drain's new… said so farlines instead of the oldSMI filter refusedones, and passes or fails on the same lines as before. The kernel's wiring, a lock-free table of the platform's ids published before any unit is armed, has no QEMU oracle: QEMU's unit writes no such record.Checks at
639028982(main335927b83merged, clean tree)cargo run -- --ci hostcargo run -- --build-only/--arch aarch64cargo test --test toyos-build -- usbd_drives_the_spare usbd_refused_without_smi_filter usbd_refused_without_amdvi_remapping amdvi_selftest amdvi_firmware_left iommu_virtio_platform virt_claim_lpiintremapon and off), VT-d, virt/ITS--metal --metal-readback … amdvi_claim_refused_without_remapping amdvi_remaps_the_stick_controller amdvi_translates_the_stick_controllera8791b689(the #928 merge after it changed neither the gate nor its row's path, which refuses before placement): the AMD-Vi SMI gate madefalse &&(patch);… usbd_refused_without_smi_filter00:10.0handed over, the job panics on the grantsmitaking only Table 4's zero bits 63:40 (patch);cargo test -p toyos-amdvian_smi_the_filter_refused_is_told_from_a_dma_faultredRound 4's host controls on the filter plan still hold, because
reg.rsis unchanged since: registers left unlocked, and a missing source skipped instead of refused, each red (nolock, noroom).Earlier rounds
b85bbb0ca): QEMUintremap=on,xtsup=onclaim through its own entry, and the entry-off-by-one negative control (s6). On the bench,amdvi_remaps_the_stick_controllerpassed and the no-remapping control went red (bench).c22745327): the MSI-X table's BAR handed over where the machine remaps;xhci-leave=by address; the metal claim rows (s6r2).4f1d6fc3a): the first SMI filter, which caused the panic above. Itsg8.logandci-host5.logran ate81f97f53with the fix uncommitted, not at4f1d6fc3a; the reviewer reran both clean at4f1d6fc3a(s6r3).c648c1439): R1(a) one gate, R2 decoder, the filter after the handoff and off before reset, R3 to R6, S1 to S4 (s6r4).Risks
00:14.0and00:00.1, reset itself throughSMI_CMD, and logged no refused SMI in its three boots. A platform SMI raised under another id would still be refused, and logged, while the machine runs.Setting::CLAIMEDfor the rest of the boot. This is stricter than firmware's byte.XTEnit targets APIC 0.🤖 Generated with Claude Code
https://claude.ai/code/session_016UzbDnM9m6nQWhbjGi6Lv1