Repository navigation
console: the VM's console is a userland virtio-serial driver's, and the UART goes quiet while it carries the log - #1062
Conversation
Review r1: #1062 at
|
…he carrier goes with the console's last handle - An IOMMU fault on a function this kernel drives halts the machine, and its line was logged before `halt_all_cpus` took the log back: `klogd` could advance past the one line that explains the halt. The drain now takes it back where it decides `Owner::Kernel`, before the line. - The console is a `deferred` object, and its carrier is released in `on_zero_handles` rather than on the last `Arc`: userland-visible lifetime rides the handle count, and a dying holder's releases run before its end is published, so logkeeper's death cannot leave the UART quiet behind a stranded reference. - The lines a carrier had not delivered when it went are recorded in `issues/the-console-loses-what-its-carrier-had-not-delivered.md`. - QEMU's source is no longer cited; the port's throttling is cited as measured (two 20 s stalls of the host's reader, no byte lost). - `images/system.toml` states the probe window as it is: a process holds the function it probes beside its own row's port until its verdict. - Both drivers share one `identify` in `toyos-virtio-serial-claim`. - `a_fatal_report_reaches_the_uart_while_a_carrier_carries_the_log` is deleted: its negative control showed it cannot see the race it was written for, and the restore test holds its harness claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… as the console The full q35 suite at the head found three rows the rewired harness broke: - `usbd_refused_without_smi_filter` and `usbd_refused_without_amdvi_remapping` boot machines whose every claim the kernel refuses. The console's driver never runs there, so the UART never goes quiet and the harness, which publishes UART lines only from the quiet line on, saw nothing. A shape now says whether its machine has the console's port: not `HeadlessNoIommu` nor the two AMD-Vi machines, whose UART is their console on stdio as metal-sim's is. - `iommu_virtio_platform` counted the virtio functions the kernel drives, which is now none: it asserts that, and the no-unit half also expects the console row's refused claim on the clipboard's function. The fourth red, `netstack_holders_exported_to_children`, hangs at the same step on `origin/main` (`2a5b446b0`); it is recorded in `issues/socket-export-hangs-at-its-race.md`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r2: #1062 at
|
…he carrier goes with the console's last handle - An IOMMU fault on a function this kernel drives halts the machine, and its line was logged before `halt_all_cpus` took the log back: `klogd` could advance past the one line that explains the halt. The drain now takes it back where it decides `Owner::Kernel`, before the line. - The console is a `deferred` object, and its carrier is released in `on_zero_handles` rather than on the last `Arc`: userland-visible lifetime rides the handle count, and a dying holder's releases run before its end is published, so logkeeper's death cannot leave the UART quiet behind a stranded reference. - The lines a carrier had not delivered when it went are recorded in `issues/the-console-loses-what-its-carrier-had-not-delivered.md`. - QEMU's source is no longer cited; the port's throttling is cited as measured (two 20 s stalls of the host's reader, no byte lost). - `images/system.toml` states the probe window as it is: a process holds the function it probes beside its own row's port until its verdict. - Both drivers share one `identify` in `toyos-virtio-serial-claim`. - `a_fatal_report_reaches_the_uart_while_a_carrier_carries_the_log` is deleted: its negative control showed it cannot see the race it was written for, and the restore test holds its harness claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… as the console The full q35 suite at the head found three rows the rewired harness broke: - `usbd_refused_without_smi_filter` and `usbd_refused_without_amdvi_remapping` boot machines whose every claim the kernel refuses. The console's driver never runs there, so the UART never goes quiet and the harness, which publishes UART lines only from the quiet line on, saw nothing. A shape now says whether its machine has the console's port: not `HeadlessNoIommu` nor the two AMD-Vi machines, whose UART is their console on stdio as metal-sim's is. - `iommu_virtio_platform` counted the virtio functions the kernel drives, which is now none: it asserts that, and the no-unit half also expects the console row's refused claim on the clipboard's function. The fourth red, `netstack_holders_exported_to_children`, hangs at the same step on `origin/main` (`2a5b446b0`); it is recorded in `issues/socket-export-hangs-at-its-race.md`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ebac17a to
ff2af0a
Compare
… the UART back first Two fatal entries wrote their reports before the log came back to the UART: x86's page fault from Ring 0, whose SMAP backtrace and `#PF` line precede `fatal_exception`, and aarch64's `exception()`, whose registers, page walk and backtrace precede its `panic!`. Both now take it back before their first record; a Ring 3 fault, which ends only its process, does not. A carry that lands after its console's last handle has gone, and so after the release that handle ran, is given back at once. The iommu tests' header and the harness shape's `virtio` field say what they check now, and the check for a kernel virtio driver that no longer exists is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The row's only red reading was the receive under traffic, with the MAC counting no frame seen, as the record's 2026-10-21 boots did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The kernel's console comes up before the root bridges are declared, so it is given no domain of its own: every domain is built clear of the declared windows. On VT-d and AMD-Vi such a function stays on the identity domain; an armed SMMUv3 aborts a stream the IORT routes through it and no claim gave a domain, so the console's first queue completed nothing and the kernel panicked in wait_used on an aarch64 `cargo run`. DeviceSpace::create now answers None for such a function, said by name, and the console declines it and stays on the UART. No IOMMU exception is made for a driver in this kernel; the console moves to userland (#1062). DeviceSpace keeps only the machine's addresses, so its never-built Own arm, and DmaPool's unmap on drop, which unmapped nothing, go. linkcase claims PCI functions through its disk drivers, so it starts acpiserver, the declarer, as the build's config test requires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… nothing An aarch64 `cargo run` at f47e0af declares its root bridges, serves its NVMe and opens vdagent's port; the console it refuses leaves the terminal empty until the console is a userland driver (#1062). The file is renamed for what remains. A departed function's BARs leave Machine::decoded, so the next arrival behind its port can be given the same addresses while a mapping made through the departed claim is still held: recorded in the lifecycle track and in the BAR-mapping issue, whose revocation at a claim's end is the exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cdbfc36 to
13af3ee
Compare
Review r3: #1062 at
|
13af3ee to
2de594d
Compare
Review r4: #1062 at
|
2de594d to
d7fd28f
Compare
…he UART goes quiet while it carries the log The kernel drove QEMU's virtio console itself: a single-port `virtconsole` the kernel replayed its records into and logkeeper's program lines through, with its own DMA pool, a kernel-driver half of `DeviceSpace` and a rule for which `1af4:1043` function was its. A `virtconsole` drops what a full host pipe refuses, and the kernel driver waited on the device from its console path, the panic path included. `/system/bin/virtio-console` is now the virtio console device's driver (virtio 1.2 §5.3): one process per virtio-serial function, holding its claim, reading the name the device gives its one port and handing the port to the endpoint its row receives for that name. The device and the services' own authority stay in different processes: - `org.toyos.console`, a `virtserialport` QEMU throttles rather than drops, goes to logkeeper's `log-carrier`: the log from its first line, and how much the host has taken (`DELIVERED`). - `com.redhat.spice.0` goes to vdagent's `vdagent` port, both ways on one connection (`toyos_vdagent::endpoint`): the host's opens, closes and bytes, and the agent's bytes. Each close is answered, and what the agent sent while any close was unanswered is dropped (`Fence`), so no session starts with an earlier one's tail. vdagent is a boot service holding the clipboard and no device; only `virtio-console` may receive `vdagent`. A port whose service the image does not run ends the driver with exit 0. The UART goes quiet while the carrier carries the log. Once the host has taken the first bytes, logkeeper tells the kernel (`SYS_CONSOLE_CARRIED` on its console) and stops writing program lines to it; klogd says so on the UART and advances past what it would have written. The UART takes the log back when the carrier goes; when its channel has taken nothing it is owed for `STALL`, until it takes more; when the machine stops, after the carrier has the log up to the flush, bounded; and for good on every fatal path, before its first record. The kernel releases the carrier with the holder's console, a deferred object, so logkeeper's own crash cannot leave the UART quiet. The UART is on a socket at the launch and in the harness, and both show its lines beside the port's through one rule (`vmconsole::merge`): what it says after the kernel's quiet line, and a kernel's death before it. The death vocabulary moves to `toyos_logstream::death` so the launch reads the harness's. Deleted with the kernel console: `drivers/virtio.rs`, `mm/dma.rs`, `DeviceSpace`, `toyos_pci::console`, the virtio backend of `serial.rs`, the backend-change replay, the untranslated-console profile and its test, and `build/kernelconsole.rs`'s firmware split. `toyos-dma` keeps only the register bound and is `toyos-register`. The PCI capability walk's self-test moves to `drivers/pci.rs` on a plain frame, without its virtio cases (6/6). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d7fd28f to
caf414e
Compare
…se's display row is granted its window, and the PSR restart point is the durable brief Rebased onto main c81fc83. #1062 took syscall 160 and #1116 took 161-163, so SYS_DEVICE_FIRMWARE_WINDOW is 164, the first commit's message notwithstanding. The profile has 166 bins, and the guard names 164. #1149 runs tgl-display in benchcase "as images/system.toml runs it", so its row carries the same `firmware = ["igd-opregion"]` grant. The display track's PSR restart line now links the clean-room brief at its durable evidence commit. Only facts.md there is an implementer's input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e device set is 164/165 Resolutions: - sdk/abi/src/syscall.rs: SYS_DEVICE_SET 164 and SYS_DEVICE_SET_READ 165, above main's SYS_CURRENT_CPU 163; 167 profile bins, the assert on 165. - kernel/src/drivers/virtio_console.rs and kernel/src/mm/dma.rs: deleted, as main deleted them (#1062 moved the VM's console to the userland virtio-serial driver). This branch's hunks there were the SMMUv3 refusal of the console's function and DmaPool's removed Drop; both go with the files. - kernel/src/iommu/mod.rs: main's, DeviceSpace deleted. Its only users were the console and dma.rs. - kernel/src/arch/x86_64/iommu_unit.rs: main's unclaimable doc, this branch's governs; untranslated and aborts_undomained deleted, both DeviceSpace's alone. - kernel/src/arch/aarch64/smmu/domain.rs: untranslated and aborts_undomained deleted for the same reason; this branch's governs and arrival-refusing unclaimable kept. - kernel/src/pcidev/mod.rs: main's toyos_register rename, this branch's hotplug import. - tests/images/{drivescase,hostedclangcase,jobcase,linkcase,netcase, proctreecase,clipboardcase}.toml: both main's virtio-console row and this branch's acpiserver row; clipboardcase starts acpiserver and main's vdagent. - tests/images/acpicase.toml: this branch's, storage-less, so without main's virtio-console row and logkeeper carrier: its first acpi holder is a job, and a PCI claimant there would wait out the declaration's deadline. - issues/an-aarch64-cargo-run-boot-hands-over-no-pci-claim.md: deleted, as this branch renamed it; main's edit described the userland console, which the renamed record is brought up to after this merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… claims are handed over The record (renamed by #934 from main's `an-aarch64-cargo-run-boot-hands-over-no-pci-claim.md`) described the kernel's virtio console refused behind the SMMUv3, which main deleted with #1062. Measured at #934's ded3c60, `cargo run -- --arch aarch64` under HVF on a pseudo-terminal: the root bridges declared, every claim handed over (NVMe, virtio-net, both virtio-serial functions), the UART quiet once the console's carrier has the log, and the terminal showing it, the disk driver's partition served and `vdagent: the host announces capabilities` among it. Both records' exits are met, so it goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…se's display row is granted its window, and the PSR restart point is the durable brief Rebased onto main c81fc83. #1062 took syscall 160 and #1116 took 161-163, so SYS_DEVICE_FIRMWARE_WINDOW is 164. The profile has 166 bins, and the guard names 164. #1149 runs tgl-display in benchcase "as images/system.toml runs it", so its row carries the same `firmware = ["igd-opregion"]` grant. The display track's PSR restart line now links the clean-room brief at its durable evidence commit. Only facts.md there is an implementer's input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
The kernel drove QEMU's virtio console itself: a single-port
virtconsolethat it replayed its records into, with logkeeper's program lines going through it too. That driver needed its own DMA pool, a kernel-driver half ofDeviceSpace, and a rule (toyos_pci::console) for which1af4:1043function belonged to the kernel. QEMU'svirtconsoledrops whatever a full host pipe refuses, and the kernel waited on the device from its console path, the panic path included.What it does now
/system/bin/virtio-consoleis the virtio console device's driver (virtio 1.2 §5.3), with one process per virtio-serial function. Each process holds its function's claim, reads the name the device gives the function's one port, and hands the port to the service that name belongs to. Its row receives exactly those services:org.toyos.console(QEMU's stdio)log-carrierDELIVEREDcounts backcom.redhat.spice.0(qemu-vdagent)vdagentporttoyos_vdagent::endpoint)vdagentand holds the compositor's clipboard, and it holds no device.virtio-consolemay receivevdagent(HELD_ALONE), and a row that receives bothvdagentandclipboardis refused.CLOSED. The driver counts the closes not yet answered and drops whatever the agent sends while any is outstanding. So no host session starts with an earlier session's tail, even when the host closes, opens and closes again before the agent reads the first close (Fence, host-tested).The UART goes quiet while the console's carrier carries the log (owner item 73.1):
SYS_CONSOLE_CARRIEDon its console and stops writing program lines to it.klogdwritesconsole: the log is carried elsewhere from here…on the UART, then advances past what it would have written.klogdsaysconsole: the UART carries the log again.STALL(5 s, measured from its last progress). logkeeper tells the kernel the UART carries the log again and keeps feeding the carrier. Once the channel takes more, the UART goes quiet again. So a wedged driver, or a device that never completes a transmit, cannot leave the operator with neither channel. While it lasts, lines can reach both channels, out of order. That trade sets the short bound: a false stall only duplicates lines, while a missed one leaves both channels silent. Under QEMU a stall is a defect, so the harness fails any capture carrying logkeeper's stall line (CARRIER_STALLED).deferredobject whose last handle releases the carrier (on_zero_handles), and a dying process's releases run before its end is published. The single carrier word iskernel::carrier, host-tested.How panic and early-boot output reach the operator
cargo runtoday.SeqCst) before its first record, andklogd's discard reads the word after each record, so it never advances past a fatal report.halt_all_cpus,panic_registers, double fault,#MC,fatal_exception, Ring 0#PF, aarch64exception()and its recursive user fault,FATAL_HALT, and the IOMMU drain's kernel-owned fault.panic_flushthen drains the ring to the UART without the carrier.halt_all_cpus/panic_registerscaller after the rebase, and main added none. The one that logs before halting, thepanel-painter-stallsboot actuator, runs before userland, when no carrier can exist.cargo runand the harness hear both, through one rule (build/vmconsole.rs:Uart,merge,UartSocket). The console port is on QEMU's stdout and the UART on a socket the host listens on./tmp/toyos-uart-early.logforcargo run).cargo run's terminal therefore shows a panic, the stop's last lines and everything after the carrier goes or stalls. Before this round those reached only the UART file.tests/common/serial.rstotoyos_logstream::death, so the launch reads the harness's one table.Deleted
drivers/virtio_console.rs,drivers/virtio.rs,mm/dma.rs(DmaPool/Dma),DeviceSpace, theuntranslatedfacades,toyos_pci::console, the virtio backend ofserial.rs, the backend-change replay, andpmm::alloc_contiguous_for_kernel(its last caller was the DMA pool).toyos-dmakeeps only the register bound, astoyos-register.drivers/pci.rs(6/6).Profile::HeadlessConsoleUntranslatedand its test,build/kernelconsole.rs's firmware split, and the issues for the kernel console's wedge and drops.Decisions
SYS_CONSOLE_CARRIEDis 160. Main's last number isSYS_MESSAGE_RECV, 159;SYSCALL_PROFILE_BINSis now 162.linkcase(new on main) andbenchcase, whichosbench_capability_groups_exit_0now boots on q35.Drives::declined, overlappingdrivesrows, and a shared claim crate) existed only on this branch. It is gone from the branch and its history: the PR is one commit, and against main it changes neither the supervisor nor the manifest.STALLEDandMAX_READERSare unchanged; the carrier is its own slot.Checks
Rebased onto
ece8ef4e6ascaf414e4a(one commit):wlan/wifirows and theHELD_ALONElist; both sides are kept.SYS_CONSOLE_CARRIEDstays 160, since main still tops out at 159.cargo run -- --ci host: exit 0, 108/108 (log).Review r2 (
d7fd28f00):STALLrationale are corrected.mergereads the UART to its end. The merge host test now writes the UART's last line after the port has ended. A negative control shows the test fails without the drain.vmconsolehost tests: 6/6;logkeeperhost tests: 17/17;a3c1c5c30's tree.One commit,
a3c1c5c30onorigin/main190f3b164, rebased unchanged onto9b3711cdbas2de594d8a; main's nine commits there touch no file this change does. Evidence: round 3 at https://github.com/ToyOSOrg/evidence/tree/96e250ea132d81c06b2c37404219c464edb50011/r3-rebase-rework, review r1 at https://github.com/ToyOSOrg/evidence/tree/7b207c5c9af4d67e1732fa4eeb5690681eed4288/r4-review-r1 (masked).Review r1 (
a3c1c5c30):cargo run -- --ci host: exit 0, 108/108.cargo build --testsand thevmconsolehost tests also pass after the rebase onto9b3711cdb.Guest rows (exit 0, 5/5):
the_opening_exchange_with_qemus_agent_completes, after B1;the_uart_carries_the_log_again_once_the_console_carrier_goes;machine_shutdown_short_stop;machine_shutdown_wire_held;a_drives_row_holds_one_process_per_function.These are the rows the merge and logkeeper's change reach.
cargo run, stdout to a file and the guest powered down over QMP after the UART went quiet. The output carries the stop's UART-only lines, fromconsole: the UART carries the log againtoShutting down.New host tests:
Fence's close, open, close case and an unaskedCLOSED;Carriage's stall: the bound runs from the last progress, it is said once, it is quiet again on progress, and an idle log is no stall;Uart's rule, whatever the cuts, and a kernel's death before the quiet line;merge's order and file, with the port's unended last line.The whole-suite run below predates this round. The round changed the harness's reader to the shared merge, and the five rows above exercise it.
Resolving the rebase:
keep_reservedand VT-dunclaimableare kept;untranslatedis dropped, since its only outside caller wasDeviceSpace.alloc_contiguous_for_kernelis deleted.FrameRx, and vdagent's IPC phase 2: a connection carries whole messages #1121 SAFETY wording was carried into the moved channel code.Host and build:
cargo run -- --ci host:f3046c768(the plain rebase): exit 0, 108/108;7d9f5d277: 107/108. The red wasServesWithoutService("vdagent"), fixed;13af3ee77: exit 0, 108/108.cargo run -- --build-onlyat13af3ee77: exit 0.Guest, whole q35 suite (
cargo test --test toyos-build) at5ff35be86: 88 of 89.osbench_capability_groups_exit_0, was the harness refusingbenchcasefor lacking the carrier rows.13af3ee77adds only those rows, and the row passes there. No other test readsbenchcase, so the suite result stands for the head.the_uart_carries_the_log_again_once_the_console_carrier_goes;the_opening_exchange_with_qemus_agent_completes, which now also requires the driver's hand-over line before the agent's;machine_shutdown_*rows;a_drives_row_holds_one_process_per_function;iommu_virtio_platform;a_link_ends_under_a_held_stream_and_comes_back;session_lifecycle.Negative control: a checked patch that makes the driver pass none of the host's bytes to the agent. The clipboard exchange stalls (exit 1); the patch was restored in the same run. Earlier rounds' controls still apply: the harness's UART merge, logkeeper's restore, and
FATAL_HALT's ordering.Host tests added in round 3:
Fence;vdagentandclipboard.Metal: no new run is requested.
klogd, for-good on fatal entries, andserial.rswithout its virtio backend. With no carrier it behaves as before.ff2af0a4d(testcasesandtestcases-watchdog: 255 passed; the 5 reds are known and independent) and at7280e0970(pci_capability_walk1/1).testcasesboot at the head would check the merged result. It is the orchestrator's call.Temporary gaps and risks
cargo run's terminal shows nothing but a kernel death. Claims are refused there today (issues/an-aarch64-cargo-run-boot-hands-over-no-pci-claim.md), so no carrier runs, and the merge holds back the pre-quiet UART lines the port would otherwise replay. The whole log is in/tmp/toyos-uart-early.log. The harness'svirtprofiles have no console port and read the PL011 as before.klogdadvanced past before logkeeper gave the UART back, and across logkeeper's own death./logkeeps the program lines.issues/the-console-loses-what-its-carrier-had-not-delivered.md.Fenceis host-tested, the close, open, close case included; vdagent's oneCLOSEDper close rests on inspection.issues/the-shared-clipboard-is-unmeasured-on-linux-and-windows-hosts.mdis the nearest record).issues/a-forced-reboots-last-userland-lines-miss-the-console.md(main) is about the console at a forced stop.session_lifecyclepassed in this suite; this PR does not claim to close it.🤖 Generated with Claude Code