← Back · part of NextBSD Research · sibling of the virtio-gpu DRM plan · decision record: arm64 KMS options · console policy: quiet console plan
Apple’s VM stack is the one arm64 target where NextBSD has never booted, and the reason turned out not to be ACPI, GIC, or graphics. It was USB. This page records what was measured on real hardware, what the remaining blockers are, who else is already working on them, and the order to fix them in.
Root-caused 2026-08-18 The “Internal Virtualization error” is xHCI. Apple’s virtual xHCI controller aborts the entire VMM — Security Assertion Hit → __os_crash → brk #0x1 on the vCPU thread — when a guest writes a register it does not model, and FreeBSD’s xhci(4) does exactly that. Any VZUSBKeyboardConfiguration, VZUSBScreenCoordinatePointingDeviceConfiguration, or VZUSBMassStorageDevice instantiates that controller. Remove them and the crash goes away: 6–8 s crash → 121 s and still running, guest idle at 0.1 % CPU.
Still blocked Booting is not fixed, only unblocked. With USB removed the guest reaches the kernel and then sits idle without networking. It is mute — no GOP, no UART, no SPCR — so the next blocker cannot be identified without first giving the guest a console. That, not ACPI, is the critical path.
Updated 2026-08-19 Two of the three blockers on this page are now closed in tree, and neither of them was the boot hang. The vtgpu attach spin (§4 #4) is fixed by kernel patch 0011, which bounds the control-queue wait and calls virtio_stop() on timeout instead of spinning a vCPU forever. The fbdev gap (§6) is closed outright: drm_fbdev_shmem is built and shipping, and a stock arm64 boot now reaches /dev/dri/card0 with a drmfb console unattended. Neither depends on a firmware framebuffer, so both carry over to VZ, where there is no GOP at all.
What is left for VZ is exactly one thing: the early hang. With USB removed the guest reaches the kernel and goes idle before the virtio bus is probed — earlier than any console this project can register, which is why the consdev (§8 Phase 1) is resident, correct, and silent. The next move is the PSCI tracer (§8 Phase 2): it needs no console at all. Everything else on this page is either measured-and-eliminated or now shipped.
A NextBSD arm64 install was copied out of its UTM qcow2 to a sparse raw image and booted under Virtualization.framework through a ~90-line Swift harness, ad-hoc signed with com.apple.security.virtualization. Everything below is first-hand.
| Question | Result | How it was established |
|---|---|---|
| Does Apple’s EFI read a FreeBSD disk? | Yes | lsdev at the loader prompt: disk0: ISO9660 / GPT+ESP raw image; kernel and mfsroot load normally |
| Device tree? | None | Loader: No valid device tree blob found! — a warning, not a failure; bootinfo.c prints it whenever acpi.revision is unset |
| ACPI? | Yes | show acpi.rsdp → 0x00000000efbf0018; show acpi.oem → APPLE |
| GOP / framebuffer? | None at all | gop list → gop: Graphics Output Protocol not present. Not Blt-only — absent |
| Kernel output after ExitBootServices? | Zero, ever | Screen freezes mid-word on the loader’s last line; nothing follows on any configuration |
| With USB devices attached | VMM aborts in 6–8 s | VZErrorDomain Code=1; EXC_BREAKPOINT/SIGTRAP on com.apple.virtualization.thread.cpu-0 |
| With no USB devices | Survives; idle | 121 s+ alive, VMM at 0.1 % CPU, no DHCP lease |
Stock kernel (with virtio_gpu) | Hangs, spinning | VM alive but pegged ~199 % across 2 vCPUs — a different failure from the idle case |
Does virtio_gpu(4) drive Apple’s virtio-gpu? | No evidence it does | A kernel containing it produced no console under VZ |
Linux under VZEFIBootLoader (GRUB on the guest ESP) | Boots, console works | ACPI path confirmed (rtc-efi, not pl031). Tables present: APIC DSDT FACP GTDT MCFG — no SPCR |
| MADT GIC Distributor version | GicVersion = 3 | Not 0. The carried GIC-version fallback patch is inert here and was dropped. GICD base 0x10000000, GICv2m MSI frame 0x1fff0000 |
| GTDT / FADT | Well-formed | VirtualTimer INTID 27 (what Linux uses), NonSecureEL1 30, EL2 26; FADT rev 6 with HW_REDUCED_ACPI, PSCI_COMPLIANT and PSCI_USE_HVC all set |
Linux via VZLinuxBootLoader (direct kernel) | Boots, DT path | VZ’s own DTB captured: arm,gic-v3, psci method hvc, RAM at 0x70000000, PL031 0x20050000, PL061 0x20060000, no serial node |
| NextBSD + VZ graphics device | 199 % spin | Every kernel containing base virtio_gpu(4) spins; the one built nodevice virtio_gpu does not |
| NextBSD, no graphics device | Idle 0.1 % | No console output even with the consdev patch resident — so it stops before virtio device probe. Cause unknown |
Stock FreeBSD 16.0-CURRENT VM image (-ufs.raw, 2026-08-04 snapshot) | Same 199 % spin, no lease | Loader menu renders normally under Apple’s EFI, Loading kernel…, then two vCPUs pegged for 151 s+ with no DHCP. Not a NextBSD bug |
Stock FreeBSD disc1.iso as VZ media | Not bootable | No loader output, then a clean power-off. macOS also refuses that ESP (mount -t msdos → error 71) while NextBSD’s mounts as FAT12 EFISYS. Two independent readers failing on the same image points at the media, not the kernel |
Media caveat Test FreeBSD releases with a VM image or memstick, never disc1.iso. An install ISO that Apple’s EFI cannot read produces exactly the same outward signature as a kernel that fails to boot — black screen, no output — so it is an easy way to draw a wrong conclusion. This may be what vfkit #446 actually is, reported there as “missing device tree”.
The crash/hang split is diagnostic, not cosmetic: a crash means the guest touched a device model Apple refuses; an idle guest means the kernel stopped scheduling; a spin means it is looping. The triggered thread name in ~/Library/Logs/DiagnosticReports/com.apple.Virtualization.VirtualMachine-*.ips discriminates further — thread.cpu-N is a guest-triggered device assertion, virtual-machine-service is a configuration the VMM refused at start.
The crash report’s faulting function, disassembled, references only xHCI MMIO-decode strings:
"Security Assertion Hit: "
"Guest attempted to write into RsvdP in the Host Controller Runtime Registers's
Interrupter Register Set \"%u\". "
"Guest attempted to write into a Host Controller Operational Registers' port
register at offset \"0x%x\". The offset is past MaxPorts of this device."
"Unhandled endpoint type %d" "Non-zero doorbell target %u is unexpected"
The call site is adrp x1, "Report an error"; bl …, and that callee ends in adrp x0, "assertion failed"; bl __os_crash; brk #0x1. This is a deliberate design choice: an unmodelled guest write kills the VMM rather than being ignored.
It also matches the only known-good FreeBSD-on-VZ writeup independently, whose blocker #4 reads verbatim “USB/XHCI is fatal — any USB device makes VZ present an XHCI controller and FreeBSD’s USB stack dies”.
Two independent belts. Host side: never configure keyboards, pointing devices, USB mass storage, or an explicit VZXHCIControllerConfiguration. Guest side: nodevice xhci in KERNCONF, or hint.xhci.0.disabled="1". The guest-side belt is the one that matters, because it protects users running third-party VZ front-ends we do not control — and every published VZ tool configures a keyboard by default.
Sources: local crash reports 2026-08-18; networkextension/FreeBSD-vz.
VZ gives an arm64 guest no console path that FreeBSD can currently use. This is a platform fact, not a bug in our configuration:
vt_efifb can never attach, and there is no MODINFOMD_EFI_FB to hand over. The fallback graphics route does not exist on this platform.RSDP/XSDT/FACP/DSDT/GTDT/APIC/MCFG, OEM APPLE, creator Apple Vz). SPCR is generated per configured device, and the public API configures none that qualify. Note FreeBSD ignores DBG2 anyway unless hw.acpi.enable_dbg2=yes, and SPCR structurally cannot describe a virtio console — its Interface Type byte defers to DBG2 serial subtypes, all of which are UART variants.sys/dev/virtio/console/virtio_console.c creates /dev/ttyV0.x but registers no consdev/cnputc, so it cannot carry printf from early boot. Linux uses the same device as hvc0, which is why every VZ tool’s “serial output” works for Linux guests and not for us — including swift-vm-cli, which wires VZVirtioConsoleDeviceSerialPortConfiguration to stdio in raw mode.consdevRecommended ~250 LOC, already written by someone else, no entitlements, ships to users.
The FreeBSD-vz fork carries a low-level console for virtio_console(4) (cf50f191e, +252 lines). This is the only console VZ hands an unentitled harness, it needs no private API, and it is the piece that makes NextBSD debuggable on this platform for good. It also benefits std.virt generally — the one-line device virtio_console is worth adding regardless of what else lands.
Reconcile with driver delivery §3: console (vt) sits in the compiled-in tier. A console-capable virtio_console must join it there, or take an explicit documented exception.
Debug harness only Zero kernel LOC — but entitlement-gated, and unusable by end users.
Binary analysis of Virtualization.framework shows a private _VZPL011SerialPortConfiguration (serial port type 1) beside the public virtio console (type 2), plus a device table giving four slots at 0x20010000 + n*0x10000, GSIV 32+n. QEMU’s clean-room vmapple machine model places a PL011 at exactly 0x20010000, which corroborates it. FreeBSD would then need only:
hw.uart.console="mm:0x20010000,br:115200,rs:2,rw:4,xo:0"
Measured caveat: the class passes validate() but start() fails with Code=1 under an ad-hoc signature, trapping on virtual-machine-service — the com.apple.private.virtualization gate. Unlocking it means weakening SIP/AMFI. Fine for a lab, never for a shipped tool. Treat as a debugging accelerator, not a solution.
Downstream The eventual product, not a debugging tool.
Since VZ has no GOP, the only way a VZ guest ever gets a graphical console is a virtio-gpu driver that publishes one — which is the virtio-gpu plan plus the fbdev work in §6. It cannot help diagnose early boot (it needs a fully running kernel), so it is sequenced last.
Settled 2026-08-18 Four of these six are now eliminated by measurement (§1): the MADT reports GicVersion = 3, there is no SPCR to be malformed, the GTDT virtual timer is INTID 27, and the FADT sets both PSCI flags. VZ’s firmware description is well formed — the blocker is not in the tables.
Two failures, not one #4 was real and is now fixed. Base virtio_gpu(4) attaching to Apple’s virtio-gpu pegged both vCPUs, because vtgpu_attach() waited on the control queue with an unbounded virtqueue_poll(9). Kernel patch 0011 replaces that with a 5 s bounded dequeue loop that reports and calls virtio_stop() rather than spinning. The spin is gone without removing the graphics device from the VM.
What remains underneath is the second, earlier failure, and it is now the only one: the guest goes idle at 0.1 % with no console output at all, which places it before virtio device probe — early enough that no device-attach-time console, the consdev included, can ever report it.
With xHCI removed, the guest reaches the kernel and goes idle. These are the candidates, ranked by how well they fit that signature, each with the cheapest test. Status reflects what has since been measured.
| # | Hypothesis | Fit | Cheapest test / known fix |
|---|---|---|---|
| 1 | MADT GICD Version == 0 → gic_v3_acpi_identify() bails → panic: No usable event timer found | High — explains an idle guest with no output | Dump APIC from a Linux VZ guest and read the version byte. Fix exists: read GICD_PIDR2 as Linux does — aabce0c83 on networkextension:apple-vz-gic-version-none, not upstream |
| 2 | Zeroed/bad SPCR geometry (rs:0,rw:1 vs rs:2,rw:4) | High | FreeBSD bug 282936 is the same signature; fixed upstream by dea3eef94caf (D47946), not in releng/14.3. Kernel-side SerialPort.Address == 0 guard analogous to d82698ac68c2 is still unfiled |
| 3 | virtio feature negotiation — VZ is strict/all-or-nothing | High | Probe with hw.vtnet.{csum,tso,lro,mq}_disable="1"; then cherry-pick f9a4dd60b0cf, 8bdc312dac55 (VIRTIO_F_RING_RESET), d4ddf8eaee93, 5481c2d3ac1f from main — none are MFC’d to stable/15 |
| 4 | vtgpu hangs at attach fixed | Was medium-high — it was the 199 % spin | Fixed in tree by patch 0011: bounded control-queue wait (5 s, 10 µs interval) then device_printf + virtio_stop() + ETIMEDOUT. No nodevice needed, and the fix helps qemu guests too |
| 5 | GTDT virtual-timer interrupt wrong — an EL1 guest uses GT_VIRT only; vmapple wires only INTID 27 | Medium | Same ACPI dump, iasl -d GTDT |
| 6 | PSCI conduit resolved to SMC — psci_acpi_get_callfn() reads FADT ArmBootFlags with no probe or fallback; an SMC faults on a guest with no EL3 | Low — VZ’s DT says hvc | iasl -d FACP, check bits 0/1 |
Do this first One Linux guest settles four hypotheses at once. Boot arm64 Linux under VZEFIBootLoader on the same host and copy out /sys/firmware/acpi/tables/{APIC,GTDT,FACP,SPCR,MCFG,DSDT}, then iasl -d them. That answers #1, #2, #5 and #6 with no NextBSD changes at all. A second, direct-kernel boot (VZLinuxBootLoader) yields VZ’s own DTB via dtc -I fs -O dts /sys/firmware/devicetree/base — which could be handed to loader.efi in /boot/dtb/ and selected with kern.cfg.order=fdt, bypassing the ACPI path entirely as a bring-up shortcut.
Note also that bus_probe() in sys/arm64/arm64/machdep.c has no health check and no fallback — the presence of an RSDP alone wins, even if the tables that follow are unusable. And FreeBSD detects hypervisors only via SMBIOS, so under VZ vm_guest is unset and no guest quirks apply (bug 292082 / D54595 proposes boot_el-based detection).
Measured 2026-08-18 Upstream main does not boot under VZ either. The stock FreeBSD 16.0-CURRENT arm64 VM image — which already carries the four merged virtio fixes and ACPI-by-default — loads its kernel and then spins two vCPUs indefinitely with no networking, exactly as NextBSD’s stock kernel does. This removes NextBSD from the suspect list entirely and makes the out-of-tree patch set in §5 a hard dependency, not an optimisation. It also means a VZ boot cannot be fixed by rebasing.
| Who | Status | What it gives us |
|---|---|---|
| networkextension/FreeBSD-vz | FreeBSD 16.0-CURRENT boots to multiuser under VZ, headless, 2026-07-06 | The proof it is possible, a VZ KERNCONF, the GIC-version patch, and the virtio-console consdev port. Their dmesg shows acpi0: <APPLE Apple Vz>, gic0 … v3.0, vtnet0/vtcon0/vtblk0/vtrnd0 |
| tjfontaine/freebsd-apple-virtualization | Publishes dated evidence runs | Raw ACPI blobs — potentially skips our §4 dump entirely |
| Faraz Vahedi, freebsd-src PRs 2319 / 2322 | Merged to main, 2026-07 | The four virtio commits VZ needs. Not MFC’d — if NextBSD tracks releng/15.0 we must carry them |
| OpenBSD 7.9, 2026-05-19 | “Made OpenBSD work on Apple Virtualization.” | Every blocker they hit was virtio feature negotiation, not boot: VIRTIO_NET_F_MTU (VZ refuses to work without it), TSO-without-MRG_RXBUF, and a viogpu mmap returning a KVA where a physical address was required. Also the architectural idea worth stealing: their bootloader synthesizes an FDT from ACPI (efiacpi.c) so the kernel only ever sees FDT |
| Apple, containerization | Reference guest config | The authoritative device list: GICv3, PSCI, arch timer, PCI-generic, virtio-PCI, PL011, PL061, PL031, EFI stub. Console is hvc0; shutdown is PL061 GPIO → gpio-keys, not ACPI PWRBTN |
| UTM / vfkit | Explicitly unsupported | UTM documents macOS and Linux only; vfkit issue 446 has FreeBSD 15.0 failing with “missing device tree”. Nobody ships this — being early is the point |
Worth recording because it differs from QEMU’s virt in ways that break assumptions: RAM is at 0x7000_0000, not 0x4000_0000 (PCIe ECAM sits there instead); GICv3 only, no ITS and no MSI/MSI-X — PCIe is legacy INTx on SPIs; PSCI 0.2 with HVC conduit and an EL1-only guest, so SMC faults; virtio-PCI modern only, no virtio-mmio; 4K or 16K granule, never 64K. Our own acpi.rsdp = 0xefbf0018 is consistent with the 0x70000000 RAM base and inconsistent with a QEMU-virt layout — a useful independent confirmation.
Shipped 2026-08-19 This section is now history rather than plan. drm_fbdev_shmem.c is vendored into graphics/drivers/gpu/drm/ with four #ifdef __linux__ guards, built by drm_shmem_helpers, and called by default from the virtio-gpu kext (hw.virtio_gpu_drm.fbdev=0 opts out) — kernel-modules#38. The prediction below held: no deferred I/O was required. One further fix was needed that this section did not anticipate — lkpinew_pci_dev() created a pci_dev with no DMA tags, so the first dma_map_sgtable() page-faulted; kernel patch 0012 gives it tags via linux_pdev_dma_init(). With both in place: card0 + renderD128, VT: Replacing driver "virtio_gpu" with new "drmfb", and zero alignment warnings or [drm] *ERROR* lines.
This closes the open question left dangling in the graphics plan §10 (“Did drm-kmod’s core build with CONFIG_DRM_FBDEV_EMULATION?”) and corrects the rationale currently written into graphics/drm_shmem_helpers/Makefile.
Enabling drm_fbdev_shmem.c in CI produced exactly 8 errors, no missing headers, no incomplete types: fb_deferred_io_init/_cleanup undeclared, fb_WARN_ON_ONCE undeclared, and fbdefio missing from struct drm_fb_helper and struct linux_fb_info.
Corrected Deferred I/O is not needed at all. The Makefile’s note that “wiring deferred I/O into drm-kmod’s fb_helper is its own piece of work” is wrong. drm_fbdev_ttm.c — which drm-kmod does build, and which is why BochsGraphics has a console — makes the identical calls and simply wraps them in #ifdef __linux__. Everything in Linux’s fb_defio.c exists to service a userspace mmap() of /dev/fbN, and drm-kmod creates no such cdev.
The console’s damage path is separate and already implemented and exported: vt_drmfb draws only through info->fbops->fb_imageblit → drm_fb_helper_damage_area() → fb_dirty → our drm_atomic_helper_dirtyfb → virtio_gpu_cmd_transfer_to_host_2d() + resource_flush. vt(4) already batches at 25 Hz (VT_TIMERFREQ) — the same order as Linux’s HZ/20 defio delay, with exact damage clips rather than full-screen blasts.
So the fix is ~20–40 LOC of stubs, with upstream precedent: drm-kmod commit 2ac98d2787 (wulf@, 2026-06-14, on master but not yet 6.12-lts) adds the empty fb_deferred_io_cleanup() and drops the __linux__ guard; Phabricator D57488 moves this code into base keeping the stubs. Implementing real deferred I/O would fight the direction of travel and needs VM plumbing FreeBSD lacks (vm_page has no lru).
Three runtime traps the compiler will not catch: drm_fb_helper_deferred_io is declared but __linux__-guarded out (undefined symbol at load — tools/check-kext-symbols.py catches it); fb_deferred_io_mmap() is a live panic(); and shmem’s fix.smem_start == 0 means vt_fb_mmap() would hand out pages nothing ever flushes, so set FB_FLAG_NOMMAP.
Scope note: this unlocks shmem-backed fbdev only — i.e. virtio-gpu, plus the other shmem consumers (ast, mgag200, cirrus, hyperv) our drm_shmem_helpers module already pays for. Bochs and VBox are unaffected: they are TTM-backed and already work.
OpenBSD’s viogpu.c is the counter-example worth knowing: it transfers and flushes the whole screen every 10 ms with no damage tracking, from a non-DRM wsdisplay driver. It proves a crude periodic flush is viable, and simultaneously that FreeBSD’s vt_drmfb path is the better of the two.
The virtio-gpu plan carries standing constraint V7: never add device virtio_gpu to the NEXTBSD kernel config, and arm64 KMS options §Option D recommends nodevice virtio_gpu, because base’s driver registers at VD_PRIORITY_GENERIC+10 against efifb’s +1 and displaces the console that works.
Both remain correct, with one qualification neither page states: they assume a firmware framebuffer exists. That holds when QemuRamfbDxe produces a GOP with a real linear framebuffer. It does not hold on a VM whose only display device is the virtio-gpu — there OVMF’s GOP is Blt-only, and under Apple’s EFI there is no GOP at all. On such a machine nodevice virtio_gpu leaves VT: init without driver and a black screen from kernel start until a kext loads. Measured on a UTM guest configured -vga none -device virtio-gpu-pci.
Settled 2026-08-19 — the other way V7 and Option D are withdrawn for virtio-gpu. Base virtio_gpu(4) stays compiled in, and the kext takes the device from it. The reasoning above is why: on a machine whose only display is the virtio-gpu — which is every VZ guest — base is not a nuisance competing with efifb, it is the only console there is. nodevice buys KMS at the price of a blind boot from the first kernel message until userland loads a kext, panics included. That is the wrong trade on the one platform we cannot currently debug.
Restated constraint: “never rely on base virtio_gpu(4) as the final console, but do keep it as the first one, and hand the device over explicitly once the KMS kext is resident.”
The handover mechanism, since newbus will not do it for us. It remains true that there is no re-bid — bus_generic_driver_added() re-probes only DS_NOTPRESENT children, and releng/15.1 has no DF_REBID — so an attached vtgpu0 is never displaced by a better driver arriving later. Two pieces close that:
virtio_pci to a base-shadowed virtio-gpu, exactly as it already looks through vgapci to an unbound drmn. Without it nothing ever asks kextd for the bundle: device_nomatch does not fire for a device base matched perfectly well.device_detach() then device_probe_and_attach(), inside one bus_topo_lock() section, on a deferred task. That is DEV_SET_DRIVER’s sequence written in exported functions, and BUS_PROBE_VENDOR (kernel-modules#37) is what wins the resulting bid.Measured 2026-08-19 Atomicity is the whole design, not a detail. Detaching whichever driver currently owns the console panics the machine seconds later, when the next console write reaches a driver that is gone — vtgpu_detach() calls vt_deallocate() and nothing repaints until a replacement registers. Both devctl detach vtgpu0 and devctl clear driver -f virtio_gpu_drm0 did exactly that, the latter twice; clear driver is just as fatal because it detaches first and re-attaches only if device_probe() succeeds. The atomic form, devctl set driver -f vtgpu0 virtio_gpu_drm, hands over cleanly. Any in-kernel trigger must do the same and never a bare detach.
Result, on a stock arm64 boot with nothing typed: base paints the console from VT: initialize with new VT driver "virtio_gpu", kextd loads the bundle the scan asked for, the kext takes the device, and vt switches to drmfb — console the whole way through, plus card0. This is the shape VZ will inherit for free once it boots at all.
Remove USB from the harness; add nodevice xhci / hint.xhci.0.disabled="1" to the guest side so third-party front-ends cannot trip it. Exit criterion met: guest survives >120 s.
Done: the consdev landed as patch 0010 in nextbsd-kernel (arm64 GENERIC already includes std.virt, so no config change was needed), and VZ’s ACPI tables were dumped from a Linux guest booted on the same host. A carried GIC-version patch was landed alongside it and then dropped once the MADT proved it inert.
Exit criterion not yet met. The consdev is resident and correct (cn_pri = CN_NORMAL, cnadd(9) at attach) but produces nothing, because the guest stops before the virtio bus is probed. A console that registers at device-attach time cannot report a pre-attach failure — a limitation worth recording, since it is the whole premise of Route A.
the only thing left The table-driven theories are spent and the vtgpu spin is fixed (patch 0011), so this is now the whole remaining task. Since the guest is mute before device probe, the one technique that needs no console is a PSCI tracer: patch an HVC SYSTEM_OFF (0x84000008) in at a chosen early point and watch for a clean power-off on the host — guestDidStop is observable from the harness — then binary-search the boot path. Roughly log₂(N) CI builds, and it reports through the hypervisor rather than through any guest device, which is precisely why it survives a failure this early.
Note what this no longer needs: no console work, no graphics work, no ACPI work. Those were the plausible-looking prerequisites, and every one has since been either measured away (§1) or shipped (§6, §7). Exit criterion: multiuser, DHCP lease, ssh.
Landed as kernel-modules#37 (probe priority), #38 (drm_fbdev_shmem), #39 (atomic takeover) and kernel#76 (present-scan look-through), with kernel patch 0012 supplying the DMA tags the fbdev path needs. Exit criterion met on arm64 qemu, unattended, on a stock boot:
vtgpu0: <VirtIO GPU> on virtio_pci1
VT: initialize with new VT driver "virtio_gpu".
vtgpu0: detached
virtio_gpu_drm0: <VirtIO GPU (DRM/KMS)> on virtio_pci1
[drm] Initialized virtio_gpu 0.1.0 for virtio_pci1 on minor 0
VT: Replacing driver "virtio_gpu" with new "drmfb".
/dev/dri/card0 /dev/dri/renderD128
The VZ half remains untested, for the obvious reason — it needs Phase 2 first. Nothing in this path depends on a GOP or a firmware framebuffer, so it should carry over unchanged; that expectation is reasoned, not measured, and is flagged as such deliberately.
Offer the virtio-console consdev and the GIC-version fallback to FreeBSD; add a VZ boot lane once a headless boot is reproducible. Note the boot-test guard in kernel-modules greps kldstat, which cannot see a compiled-in driver — it should read kern.conftxt.
main only.virtio_console join the compiled-in tier in driver delivery §3, or take a documented exception?main spins (§5), their patch set is the dependency; the question is whether we carry it, or help push it upstream.bus_probe() has no fallback when ACPI is present but unusable?Sub-plan of the NextBSD graphics plan where it touches the console; a peer of the virtio-gpu DRM plan and the arm64 KMS decision record, which it amends in §7. Everything tagged measured was observed on 2026-08-18 (VZ, macOS 26.5.2) or 2026-08-19 (arm64 qemu guest, kernel 20260819-184420) against NextBSD arm64; upstream claims are linked to source. Claims derived from disassembling Apple’s framework are marked and are the least durable material here — they describe private, undocumented API and may change without notice.