From edb878ddcc88b3ccf91ede8b9578699036e8d4f5 Mon Sep 17 00:00:00 2001 From: "re:fi.64" Date: Tue, 21 Jul 2026 20:43:19 -0500 Subject: [PATCH] spindle/microvm: add support for using virtio+pci instead of mmio Some distros do not build with MMIO support enabled, in which case the virtio devices will fail to appear entirely. --- spindle/engines/microvm/image.go | 17 +++++++++++++++++ spindle/engines/microvm/qemu.go | 20 ++++++++++---------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/spindle/engines/microvm/image.go b/spindle/engines/microvm/image.go index efe3b6be..71518ce8 100644 --- a/spindle/engines/microvm/image.go +++ b/spindle/engines/microvm/image.go @@ -16,6 +16,15 @@ type RunnerConfig struct { Machine string `json:"machine,omitempty"` Console string `json:"console,omitempty"` ExtraArgs []string `json:"extraArgs,omitempty"` + + // Selects the virtio transport to pass to QEMU, as `-virtio-DEVICE-TRANSPORT`. + // One of: + // device: The microvm machine's preferred transport, MMIO: + // https://www.qemu.org/docs/master/system/i386/microvm.html + // Requires the virtio-mmio kernel module in the guest. + // pci: Use this if the guest kernel does not support MMIO (CONFIG_VIRTIO_MMIO). + // Requires the virtio-pci kernel module in the guest. + VirtioTransport string `json:"virtioTransport,omitempty"` } type ImageSpec struct { @@ -73,6 +82,9 @@ func LoadImageSpec(path string) (ImageSpec, error) { spec.Kernel = resolveImageSpecPath(base, spec.Kernel) spec.Initrd = resolveImageSpecPath(base, spec.Initrd) spec.StoreDisk = resolveImageSpecPath(base, spec.StoreDisk) + if spec.RunnerConfig.VirtioTransport == "" { + spec.RunnerConfig.VirtioTransport = "device" + } if err := spec.Validate(); err != nil { return ImageSpec{}, err @@ -100,6 +112,11 @@ func (s ImageSpec) Validate() error { if s.RunnerConfig.Machine == "" { return fmt.Errorf("microvm image spec missing runnerConfig.machine for qemu runner") } + if s.RunnerConfig.VirtioTransport != "" && + s.RunnerConfig.VirtioTransport != "device" && + s.RunnerConfig.VirtioTransport != "pci" { + return fmt.Errorf("microvm image spec virtioTransport unknown: %s", s.RunnerConfig.VirtioTransport) + } } if s.MemoryMiB <= 0 { return fmt.Errorf("microvm image spec memoryMiB must be positive") diff --git a/spindle/engines/microvm/qemu.go b/spindle/engines/microvm/qemu.go index 14ad4038..da62d4ab 100644 --- a/spindle/engines/microvm/qemu.go +++ b/spindle/engines/microvm/qemu.go @@ -638,11 +638,11 @@ func qemuArgs(cfg qemuArgsConfig) ([]string, error) { return nil, err } - if err := addQEMUNetworkArgs(&b, cfg.Image.NetworkInterfaces); err != nil { + if err := addQEMUNetworkArgs(&b, cfg); err != nil { return nil, err } - b.Optf("-device", "vhost-vsock-device,guest-cid=%d", cfg.CID) + b.Optf("-device", "vhost-vsock-%s,guest-cid=%d", cfg.Image.RunnerConfig.VirtioTransport, cfg.CID) if len(cfg.Image.RunnerConfig.ExtraArgs) > 0 { b.Add(cfg.Image.RunnerConfig.ExtraArgs...) @@ -667,7 +667,7 @@ func addQEMUMachineArgs(b *argBuilder, cfg qemuArgsConfig, uuid uuid.UUID) { b.Opt("-kernel", cfg.Image.Kernel) b.Opt("-initrd", cfg.Image.Initrd) - b.Opt("-device", "virtio-rng-device") + b.Optf("-device", "virtio-rng-%s", cfg.Image.RunnerConfig.VirtioTransport) b.Optf("-smbios", "type=1,uuid=%s", uuid) b.Opt("-serial", "file:"+cfg.SerialLogPath) @@ -677,7 +677,7 @@ func addQEMUMachineArgs(b *argBuilder, cfg qemuArgsConfig, uuid uuid.UUID) { // support serial itself for early kernel boot but thats OK. if cfg.Image.RunnerConfig.Console == "hvc0" { b.Optf("-chardev", "file,id=virtiocon0,path=%s,append=on", cfg.SerialLogPath) - b.Add("-device", "virtio-serial-device") + b.Optf("-device", "virtio-serial-%s", cfg.Image.RunnerConfig.VirtioTransport) b.Opt("-device", "virtconsole,chardev=virtiocon0") } b.Opt("-display", "none") @@ -699,7 +699,7 @@ func addQEMUStoreArgs(b *argBuilder, cfg qemuArgsConfig) { drive.Add("aio=io_uring") b.Opt("-drive", drive.String()) - b.Opt("-device", "virtio-blk-device,drive=store") + b.Optf("-device", "virtio-blk-%s,drive=store", cfg.Image.RunnerConfig.VirtioTransport) } func addQEMUKVMArgs(b *argBuilder, image ImageSpec) { @@ -730,14 +730,14 @@ func addQEMUVolumeArgs(b *argBuilder, cfg qemuArgsConfig) error { drive.Add("cache=none") b.Opt("-drive", drive.String()) - b.Optf("-device", "virtio-blk-device,drive=%s", driveID) + b.Optf("-device", "virtio-blk-%s,drive=%s", cfg.Image.RunnerConfig.VirtioTransport, driveID) } return nil } -func addQEMUNetworkArgs(b *argBuilder, interfaces []NetworkInterface) error { - for _, networkInterface := range interfaces { +func addQEMUNetworkArgs(b *argBuilder, cfg qemuArgsConfig) error { + for _, networkInterface := range cfg.Image.NetworkInterfaces { if networkInterface.Type != "slirp4netns" { return fmt.Errorf("unsupported microvm network interface type %q", networkInterface.Type) } @@ -752,8 +752,8 @@ func addQEMUNetworkArgs(b *argBuilder, interfaces []NetworkInterface) error { b.Opt("-netdev", netdevOpts.String()) b.Optf( - "-device", "virtio-net-device,netdev=%s,mac=%s", - networkInterface.ID, networkInterface.MAC, + "-device", "virtio-net-%s,netdev=%s,mac=%s", + cfg.Image.RunnerConfig.VirtioTransport, networkInterface.ID, networkInterface.MAC, ) } -- 2.51.2