Private tier: the virtio framework (misc/virtio) and ddi::private::virtio #6

Merged
toasterson merged 8 commits from r4-virtio into main 2026-10-05 16:34:42 +00:00
Owner

Stacked on #5 (r2-private-fd). Needed by illumos-drm's virtio-gpu driver (R4, WI-456).

What

  • illumos-kernel-private-virtio-sys, a new private-tier crate for the gate's virtio framework (misc/virtio, uts/common/io/virtio/virtio.h): every function of the header, the four opaque types, virtio_direction_t, VIRTIO_ANY_INTR_TYPE and two feature bits. Each item cites its gate line at cda5b9a49f; the crate is empty unless built with unstable-gate-cda5b9a49f. It is a crate of its own rather than a module of illumos-kernel-private-sys because the framework is its own kernel module: only virtio drivers should get -N misc/virtio (the §4 boundary rule).
  • ddi::private::virtio, the safe wrapper (feature unstable-gate-cda5b9a49f-virtio), which makes the framework's VERIFYs and panics unreachable from safe code (DESIGN.md §5.13):
    • The phases are types: VirtioSetup::init(&OwnNode), then negotiate → VirtioNegotiated (queues, configuration writes), then complete → the running Virtio. complete registers the configuration handler, calls virtio_init_complete once, asks virtio_intr_pri only when interrupts were added, refuses high-level priorities, and builds the state with the priority through an InitView that has no queues.
    • Queue handlers only record the queue and dispatch the device's task queue (Pending), so drivers complete in thread context (VirtioHandler::queue_work).
    • Chains are never driver values. Queue::submit takes the request (a ChainData) and a closure that can only name VirtioDma reached through the request; the queue owns it until poll. Empty chains are refused.
    • Dropping a Virtio disables interrupts, waits for the task queue, shuts the device down, evacuates and drops every request, drops the state, and only then calls virtio_fini.
    • A repeated queue index is refused before the framework's error path could zero the live queue's ring addresses.
    • VirtioDma copies with bounds checks. Configuration offsets are checked against the driver's unsafe VirtioConfig::SIZE.
  • lint-man knows the new crate. CI runs clippy, the host tests, the doctests (stable and the pinned nightly) and rustdoc with the virtio feature.

Verification

  • cargo check/clippy -D warnings/fmt --check, workspace and with the feature.
  • cargo test -p ddi --no-default-features --features unstable-gate-cda5b9a49f-virtio --lib: 13 passed, 4 of them new for virtio. They cover configuration ranges, cookie splitting, repeated indexes, and a no-lost-signal test with 8 marker threads and a worker, 20 rounds.
  • Nightly doctests with the feature: 27 passed. The new ones are four compile_fail tests with error codes (E0308 DevInfo for init, E0599 late queue allocation, E0599 queues from InitView, E0597 a buffer outside the request) and their compiling twins.
  • cargo xtask lint-man --gate <checkout of cda5b9a49f>: 77 private citations, 0 errors. The one other error is ddi_ncpus_expected, which postdates that gate. Against a newer gate, virtio.h moved and lint-man reports the citations as moved, as designed.
  • cargo xtask kernel-check against oibldofgate (illumos cda5b9a49f, virtio loaded by vioblk/vioif): illumos-kernel-private-virtio-sys: sizes 1/1, offsets 0/0, symbols 48/48. All other crates are as before; gld and ktest are not loaded.
  • In the kernel with a real device (2026-09-30; illumos-drm#7's virtio_gpu, pinned at be78455670, in a QEMU 6.2 guest with virtio-gpu-gl-pci, illumos cda5b9a49f): setup, negotiation (0x110000003 of 0x130000003), both queues, the configuration handler and the running device work; the driver completed 19,543 requests (7,224 fenced, 5 queue-full waits, 0 failures, 0 timeouts) from its task queue, 8 threads submitting at once, and Virtio's teardown ran on each clean unload (two in the final boot: after run-r4-test.sh's refused detaches, and after Mesa's virgl driver had used the device). No panic. Logs are with illumos-drm#7.
    • The runs met illumos bug 18358 in that gate (the framework caches the BAR register number of the first modern device, fixed upstream in 36d8c52c14): with a transitional vioblk attached first, virtio_init for the GPU fails with "Failed to map CAP 1 @ BAR4". The wrapper reports it as the init error, which is all it can do; dd0c90c (rewrapped in d3bb84b) records it in DESIGN.md §5.13. The guests used disable-modern=on for the disk.

Earlier text of this item, when the PR was opened while the test host was down: "Not run yet: the wrapper in the kernel with a real device. Its first user is the illumos-drm virtio-gpu driver, whose QEMU guest run is pending; the host was unreachable."

Two rows in DESIGN.md §5.13 (the InitView queues and the repeated index) came from the local review, before any run.

Stacked on #5 (`r2-private-fd`). Needed by illumos-drm's virtio-gpu driver (R4, WI-456). ## What - **`illumos-kernel-private-virtio-sys`**, a new private-tier crate for the gate's virtio framework (`misc/virtio`, `uts/common/io/virtio/virtio.h`): every function of the header, the four opaque types, `virtio_direction_t`, `VIRTIO_ANY_INTR_TYPE` and two feature bits. Each item cites its gate line at `cda5b9a49f`; the crate is empty unless built with `unstable-gate-cda5b9a49f`. It is a crate of its own rather than a module of `illumos-kernel-private-sys` because the framework is its own kernel module: only virtio drivers should get `-N misc/virtio` (the §4 boundary rule). - **`ddi::private::virtio`**, the safe wrapper (feature `unstable-gate-cda5b9a49f-virtio`), which makes the framework's `VERIFY`s and panics unreachable from safe code (DESIGN.md §5.13): - The phases are types: `VirtioSetup::init(&OwnNode)`, then `negotiate` → `VirtioNegotiated` (queues, configuration writes), then `complete` → the running `Virtio`. `complete` registers the configuration handler, calls `virtio_init_complete` once, asks `virtio_intr_pri` only when interrupts were added, refuses high-level priorities, and builds the state with the priority through an `InitView` that has no queues. - Queue handlers only record the queue and dispatch the device's task queue (`Pending`), so drivers complete in thread context (`VirtioHandler::queue_work`). - Chains are never driver values. `Queue::submit` takes the request (a `ChainData`) and a closure that can only name `VirtioDma` reached through the request; the queue owns it until `poll`. Empty chains are refused. - Dropping a `Virtio` disables interrupts, waits for the task queue, shuts the device down, evacuates and drops every request, drops the state, and only then calls `virtio_fini`. - A repeated queue index is refused before the framework's error path could zero the live queue's ring addresses. - `VirtioDma` copies with bounds checks. Configuration offsets are checked against the driver's `unsafe` `VirtioConfig::SIZE`. - `lint-man` knows the new crate. CI runs clippy, the host tests, the doctests (stable and the pinned nightly) and rustdoc with the virtio feature. ## Verification - `cargo check`/`clippy -D warnings`/`fmt --check`, workspace and with the feature. - `cargo test -p ddi --no-default-features --features unstable-gate-cda5b9a49f-virtio --lib`: 13 passed, 4 of them new for virtio. They cover configuration ranges, cookie splitting, repeated indexes, and a no-lost-signal test with 8 marker threads and a worker, 20 rounds. - Nightly doctests with the feature: 27 passed. The new ones are four `compile_fail` tests with error codes (E0308 `DevInfo` for init, E0599 late queue allocation, E0599 queues from `InitView`, E0597 a buffer outside the request) and their compiling twins. - `cargo xtask lint-man --gate <checkout of cda5b9a49f>`: 77 private citations, 0 errors. The one other error is `ddi_ncpus_expected`, which postdates that gate. Against a newer gate, virtio.h moved and lint-man reports the citations as moved, as designed. - `cargo xtask kernel-check` against oibldofgate (illumos `cda5b9a49f`, `virtio` loaded by vioblk/vioif): `illumos-kernel-private-virtio-sys: sizes 1/1, offsets 0/0, symbols 48/48`. All other crates are as before; gld and ktest are not loaded. - **In the kernel with a real device** (2026-09-30; illumos-drm#7's `virtio_gpu`, pinned at `be78455670`, in a QEMU 6.2 guest with `virtio-gpu-gl-pci`, illumos `cda5b9a49f`): setup, negotiation (`0x110000003` of `0x130000003`), both queues, the configuration handler and the running device work; the driver completed 19,543 requests (7,224 fenced, 5 queue-full waits, 0 failures, 0 timeouts) from its task queue, 8 threads submitting at once, and `Virtio`'s teardown ran on each clean unload (two in the final boot: after `run-r4-test.sh`'s refused detaches, and after Mesa's virgl driver had used the device). No panic. Logs are with illumos-drm#7. - The runs met illumos bug 18358 in that gate (the framework caches the BAR register number of the first modern device, fixed upstream in `36d8c52c14`): with a transitional vioblk attached first, `virtio_init` for the GPU fails with "Failed to map CAP 1 @ BAR4". The wrapper reports it as the `init` error, which is all it can do; `dd0c90c` (rewrapped in `d3bb84b`) records it in DESIGN.md §5.13. The guests used `disable-modern=on` for the disk. _Earlier text of this item, when the PR was opened while the test host was down:_ "Not run yet: the wrapper in the kernel with a real device. Its first user is the illumos-drm virtio-gpu driver, whose QEMU guest run is pending; the host was unreachable." Two rows in DESIGN.md §5.13 (the `InitView` queues and the repeated index) came from the local review, before any run.
The private crate for misc/virtio: every function of
uts/common/io/virtio/virtio.h, the four opaque types, virtio_direction_t
and the two feature bits of virtio_spec.h, each citing its gate line at
cda5b9a49f. It is a crate of its own because the framework is a module of
its own: only drivers of virtio devices should be linked with
-N misc/virtio. Empty unless built with unstable-gate-cda5b9a49f.

lint-man checks its citations like the other private crate's; they match
a checkout of cda5b9a49f (77 citations, 0 errors) and are reported as
moved against a newer gate, where virtio.h changed.
VirtioSetup (virtio_init against the OwnNode), VirtioNegotiated (queues,
configuration writes) and Virtio (running) make the framework's VERIFYs
unreachable: queues and the configuration change handler only before
virtio_init_complete, which runs once; virtio_intr_pri only when
interrupts were added; high-level priorities refused.

Queue interrupts only record the queue and dispatch the device's task
queue, which calls VirtioHandler::queue_work in thread context. Chains are
never driver values: Queue::submit takes the request (a ChainData) and a
closure that can only name DMA memory reached through the request, and
the queue owns it until poll. Dropping the Virtio disables interrupts,
waits for the task queue, shuts the device down, evacuates and drops
every request in flight, drops the state and then calls virtio_fini.
VirtioDma copies with bounds checks; configuration offsets are checked
against the driver's unsafe VirtioConfig::SIZE.

Feature unstable-gate-cda5b9a49f-virtio. compile_fail doctests (OwnNode,
late queue allocation, a buffer outside the request) with compiling
twins, host tests of the range and cookie-splitting logic, and CI steps
with the feature.
The queue interrupt's record-and-schedule logic is now Pending: mark
records bits and says whether to dispatch a run, a run clears the
scheduled flag before it takes the bits. A host test has eight threads
mark bits while a worker executes the runs they schedule and checks that
no signal is left behind.
ddi::private::virtio: no queue before the device runs; one queue per index
All checks were successful
ci / kmod-illumos (pull_request) Successful in 3m2s
ci / check-hosted (pull_request) Successful in 3m23s
be78455670
Review of R4: InitView handed out queues, so the state's constructor
could submit a chain and then fail, and virtio_fini would VERIFY-panic
on the chain in flight; queues are now reachable only through the
running Virtio (compile_fail doctest on InitView). A repeated queue
index made the framework's error path zero the ring addresses of the
queue already there, which virtio_init_complete would then enable at bus
address 0; alloc_queue refuses it first (host test). The phases hold
their record in a ManuallyDrop instead of an Option, which removes two
unreachable!() from kernel code. DESIGN.md 5.13 gains both rows and the
VirtioDma lifetime limit.
DESIGN.md: gate bug 18358 (virtio_map_cap BAR cache) met by the virtio-gpu run
All checks were successful
ci / check-hosted (pull_request) Successful in 9m23s
ci / kmod-illumos (pull_request) Successful in 10m56s
dd0c90ccbe
DESIGN.md: rewrap the gate bug 18358 note
All checks were successful
ci / check-hosted (pull_request) Successful in 3m45s
ci / kmod-illumos (pull_request) Successful in 13m6s
d3bb84b222
toasterson changed target branch from r2-private-fd to main 2026-10-05 16:34:22 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
illumos/illumos-ddi!6
No description provided.