diff --git a/qemu/qemu.go b/qemu/qemu.go index a518da52c4..f26f093922 100644 --- a/qemu/qemu.go +++ b/qemu/qemu.go @@ -91,8 +91,52 @@ const ( // VirtioBalloon is the memory balloon device driver. VirtioBalloon DeviceDriver = "virtio-balloon" + + //VhostUserSCSI represents a SCSI vhostuser device type. + VhostUserSCSI DeviceDriver = "vhost-user-scsi-pci" + + //VhostUserNet represents a net vhostuser device type. + VhostUserNet DeviceDriver = "virtio-net-pci" + + //VhostUserBlk represents a block vhostuser device type. + VhostUserBlk DeviceDriver = "vhost-user-blk-pci" + + // VfioPCI represent a VFIO device type. + VfioPCI DeviceDriver = "vfio-pci" + + // VirtioScsiPCI represents a SCSI device type. + VirtioScsiPCI DeviceDriver = "virtio-scsi-pci" + + // PCIBridgeDriver represents a PCI bridge device type. + PCIBridgeDriver DeviceDriver = "pci-bridge" + + // PCIePCIBridgeDriver represents a PCIe to PCI bridge device type. + PCIePCIBridgeDriver DeviceDriver = "pcie-pci-bridge" ) +// isVirtioPCI is a map indicating if a DeviceDriver is considered as a +// virtio PCI device, which is helpful to determine if the option "romfile" +// applies or not to this specific device. +var isVirtioPCI = map[DeviceDriver]bool{ + NVDIMM: false, + Virtio9P: true, + VirtioNet: true, + VirtioNetPCI: true, + VirtioSerial: true, + VirtioBlock: true, + Console: false, + VirtioSerialPort: false, + VHostVSockPCI: true, + VirtioRng: true, + VirtioBalloon: true, + VhostUserSCSI: true, + VhostUserBlk: true, + VfioPCI: true, + VirtioScsiPCI: true, + PCIBridgeDriver: true, + PCIePCIBridgeDriver: true, +} + // ObjectType is a string representing a qemu object type. type ObjectType string @@ -219,6 +263,9 @@ type FSDevice struct { // DisableModern prevents qemu from relying on fast MMIO. DisableModern bool + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the FSDevice structure is valid and complete. @@ -242,6 +289,9 @@ func (fsdev FSDevice) QemuParams(config *Config) []string { } deviceParams = append(deviceParams, fmt.Sprintf(",fsdev=%s", fsdev.ID)) deviceParams = append(deviceParams, fmt.Sprintf(",mount_tag=%s", fsdev.MountTag)) + if isVirtioPCI[fsdev.Driver] { + deviceParams = append(deviceParams, fmt.Sprintf(",romfile=%s", fsdev.ROMFile)) + } fsParams = append(fsParams, string(fsdev.FSDriver)) fsParams = append(fsParams, fmt.Sprintf(",id=%s", fsdev.ID)) @@ -299,6 +349,9 @@ type CharDevice struct { // DisableModern prevents qemu from relying on fast MMIO. DisableModern bool + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the CharDevice structure is valid and complete. @@ -328,6 +381,9 @@ func (cdev CharDevice) QemuParams(config *Config) []string { if cdev.Name != "" { deviceParams = append(deviceParams, fmt.Sprintf(",name=%s", cdev.Name)) } + if isVirtioPCI[cdev.Driver] { + deviceParams = append(deviceParams, fmt.Sprintf(",romfile=%s", cdev.ROMFile)) + } cdevParams = append(cdevParams, string(cdev.Backend)) cdevParams = append(cdevParams, fmt.Sprintf(",id=%s", cdev.ID)) @@ -391,7 +447,7 @@ func (n NetDeviceType) QemuNetdevParam() string { } // QemuDeviceParam converts to the QEMU -device parameter notation -func (n NetDeviceType) QemuDeviceParam() string { +func (n NetDeviceType) QemuDeviceParam() DeviceDriver { switch n { case TAP: return "virtio-net-pci" @@ -450,6 +506,9 @@ type NetDevice struct { // DisableModern prevents qemu from relying on fast MMIO. DisableModern bool + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the NetDevice structure is valid and complete. @@ -476,8 +535,7 @@ func (netdev NetDevice) QemuDeviceParams(config *Config) []string { return nil } - deviceParams = append(deviceParams, "driver=") - deviceParams = append(deviceParams, netdev.Type.QemuDeviceParam()) + deviceParams = append(deviceParams, fmt.Sprintf("driver=%s", netdev.Type.QemuDeviceParam())) deviceParams = append(deviceParams, fmt.Sprintf(",netdev=%s", netdev.ID)) deviceParams = append(deviceParams, fmt.Sprintf(",mac=%s", netdev.MACAddress)) @@ -513,6 +571,10 @@ func (netdev NetDevice) QemuDeviceParams(config *Config) []string { deviceParams = append(deviceParams, fmt.Sprintf(",vectors=%d", vectors)) } + if isVirtioPCI[netdev.Driver] { + deviceParams = append(deviceParams, fmt.Sprintf(",romfile=%s", netdev.ROMFile)) + } + return deviceParams } @@ -601,6 +663,9 @@ type SerialDevice struct { // DisableModern prevents qemu from relying on fast MMIO. DisableModern bool + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the SerialDevice structure is valid and complete. @@ -622,6 +687,9 @@ func (dev SerialDevice) QemuParams(config *Config) []string { deviceParams = append(deviceParams, ",disable-modern=true") } deviceParams = append(deviceParams, fmt.Sprintf(",id=%s", dev.ID)) + if isVirtioPCI[dev.Driver] { + deviceParams = append(deviceParams, fmt.Sprintf(",romfile=%s", dev.ROMFile)) + } qemuParams = append(qemuParams, "-device") qemuParams = append(qemuParams, strings.Join(deviceParams, "")) @@ -672,6 +740,9 @@ type BlockDevice struct { // DisableModern prevents qemu from relying on fast MMIO. DisableModern bool + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the BlockDevice structure is valid and complete. @@ -702,6 +773,10 @@ func (blkdev BlockDevice) QemuParams(config *Config) []string { deviceParams = append(deviceParams, ",config-wce=off") } + if isVirtioPCI[blkdev.Driver] { + deviceParams = append(deviceParams, fmt.Sprintf(",romfile=%s", blkdev.ROMFile)) + } + blkParams = append(blkParams, fmt.Sprintf("id=%s", blkdev.ID)) blkParams = append(blkParams, fmt.Sprintf(",file=%s", blkdev.File)) blkParams = append(blkParams, fmt.Sprintf(",aio=%s", blkdev.AIO)) @@ -717,18 +792,6 @@ func (blkdev BlockDevice) QemuParams(config *Config) []string { return qemuParams } -// VhostUserDeviceType is a qemu vhost-user device type. -type VhostUserDeviceType string - -const ( - //VhostUserSCSI represents a SCSI vhostuser device type - VhostUserSCSI = "vhost-user-scsi-pci" - //VhostUserNet represents a net vhostuser device type - VhostUserNet = "virtio-net-pci" - //VhostUserBlk represents a block vhostuser device type - VhostUserBlk = "vhost-user-blk-pci" -) - // VhostUserDevice represents a qemu vhost-user device meant to be passed // in to the guest type VhostUserDevice struct { @@ -736,7 +799,10 @@ type VhostUserDevice struct { CharDevID string TypeDevID string //variable QEMU parameter based on value of VhostUserType Address string //used for MAC address in net case - VhostUserType VhostUserDeviceType + VhostUserType DeviceDriver + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if there is a valid structure defined for VhostUserDevice @@ -769,6 +835,7 @@ func (vhostuserDev VhostUserDevice) QemuParams(config *Config) []string { var charParams []string var netParams []string var devParams []string + var driver DeviceDriver charParams = append(charParams, "socket") charParams = append(charParams, fmt.Sprintf("id=%s", vhostuserDev.CharDevID)) @@ -777,20 +844,23 @@ func (vhostuserDev VhostUserDevice) QemuParams(config *Config) []string { switch vhostuserDev.VhostUserType { // if network based vhost device: case VhostUserNet: + driver = VhostUserNet netParams = append(netParams, "type=vhost-user") netParams = append(netParams, fmt.Sprintf("id=%s", vhostuserDev.TypeDevID)) netParams = append(netParams, fmt.Sprintf("chardev=%s", vhostuserDev.CharDevID)) netParams = append(netParams, "vhostforce") - devParams = append(devParams, VhostUserNet) + devParams = append(devParams, string(driver)) devParams = append(devParams, fmt.Sprintf("netdev=%s", vhostuserDev.TypeDevID)) devParams = append(devParams, fmt.Sprintf("mac=%s", vhostuserDev.Address)) case VhostUserSCSI: - devParams = append(devParams, VhostUserSCSI) + driver = VhostUserSCSI + devParams = append(devParams, string(driver)) devParams = append(devParams, fmt.Sprintf("id=%s", vhostuserDev.TypeDevID)) devParams = append(devParams, fmt.Sprintf("chardev=%s", vhostuserDev.CharDevID)) case VhostUserBlk: - devParams = append(devParams, VhostUserBlk) + driver = VhostUserBlk + devParams = append(devParams, string(driver)) devParams = append(devParams, "logical_block_size=4096") devParams = append(devParams, "size=512M") devParams = append(devParams, fmt.Sprintf("chardev=%s", vhostuserDev.CharDevID)) @@ -798,6 +868,10 @@ func (vhostuserDev VhostUserDevice) QemuParams(config *Config) []string { return nil } + if isVirtioPCI[driver] { + devParams = append(devParams, fmt.Sprintf("romfile=%s", vhostuserDev.ROMFile)) + } + qemuParams = append(qemuParams, "-chardev") qemuParams = append(qemuParams, strings.Join(charParams, ",")) @@ -816,6 +890,9 @@ func (vhostuserDev VhostUserDevice) QemuParams(config *Config) []string { type VFIODevice struct { // Bus-Device-Function of device BDF string + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the VFIODevice structure is valid and complete. @@ -830,10 +907,17 @@ func (vfioDev VFIODevice) Valid() bool { // QemuParams returns the qemu parameters built out of this vfio device. func (vfioDev VFIODevice) QemuParams(config *Config) []string { var qemuParams []string + var deviceParams []string + + driver := VfioPCI + + deviceParams = append(deviceParams, fmt.Sprintf("%s,host=%s", driver, vfioDev.BDF)) + if isVirtioPCI[driver] { + deviceParams = append(deviceParams, fmt.Sprintf(",romfile=%s", vfioDev.ROMFile)) + } - deviceParam := fmt.Sprintf("vfio-pci,host=%s", vfioDev.BDF) qemuParams = append(qemuParams, "-device") - qemuParams = append(qemuParams, deviceParam) + qemuParams = append(qemuParams, strings.Join(deviceParams, "")) return qemuParams } @@ -853,6 +937,9 @@ type SCSIController struct { // IOThread is the IO thread on which IO will be handled IOThread string + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the SCSIController structure is valid and complete. @@ -869,7 +956,8 @@ func (scsiCon SCSIController) QemuParams(config *Config) []string { var qemuParams []string var devParams []string - devParams = append(devParams, fmt.Sprintf("virtio-scsi-pci,id=%s", scsiCon.ID)) + driver := VirtioScsiPCI + devParams = append(devParams, fmt.Sprintf("%s,id=%s", driver, scsiCon.ID)) if scsiCon.Bus != "" { devParams = append(devParams, fmt.Sprintf("bus=%s", scsiCon.Bus)) } @@ -882,6 +970,9 @@ func (scsiCon SCSIController) QemuParams(config *Config) []string { if scsiCon.IOThread != "" { devParams = append(devParams, fmt.Sprintf("iothread=%s", scsiCon.IOThread)) } + if isVirtioPCI[driver] { + devParams = append(devParams, fmt.Sprintf("romfile=%s", scsiCon.ROMFile)) + } qemuParams = append(qemuParams, "-device") qemuParams = append(qemuParams, strings.Join(devParams, ",")) @@ -919,6 +1010,9 @@ type BridgeDevice struct { // PCI Slot Addr string + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the BridgeDevice structure is valid and complete. @@ -941,28 +1035,35 @@ func (bridgeDev BridgeDevice) Valid() bool { // QemuParams returns the qemu parameters built out of this bridge device. func (bridgeDev BridgeDevice) QemuParams(config *Config) []string { var qemuParams []string - var deviceParam string + var deviceParam []string + var driver DeviceDriver switch bridgeDev.Type { case PCIEBridge: - deviceParam = fmt.Sprintf("pcie-pci-bridge,bus=%s,id=%s", bridgeDev.Bus, bridgeDev.ID) + driver = PCIePCIBridgeDriver + deviceParam = append(deviceParam, fmt.Sprintf("%s,bus=%s,id=%s", driver, bridgeDev.Bus, bridgeDev.ID)) default: + driver = PCIBridgeDriver shpc := "off" if bridgeDev.SHPC { shpc = "on" } - deviceParam = fmt.Sprintf("pci-bridge,bus=%s,id=%s,chassis_nr=%d,shpc=%s", bridgeDev.Bus, bridgeDev.ID, bridgeDev.Chassis, shpc) + deviceParam = append(deviceParam, fmt.Sprintf("%s,bus=%s,id=%s,chassis_nr=%d,shpc=%s", driver, bridgeDev.Bus, bridgeDev.ID, bridgeDev.Chassis, shpc)) } if bridgeDev.Addr != "" { addr, err := strconv.Atoi(bridgeDev.Addr) if err == nil && addr >= 0 { - deviceParam += fmt.Sprintf(",addr=%x", addr) + deviceParam = append(deviceParam, fmt.Sprintf(",addr=%x", addr)) } } + if isVirtioPCI[driver] { + deviceParam = append(deviceParam, fmt.Sprintf(",romfile=%s", bridgeDev.ROMFile)) + } + qemuParams = append(qemuParams, "-device") - qemuParams = append(qemuParams, deviceParam) + qemuParams = append(qemuParams, strings.Join(deviceParam, "")) return qemuParams } @@ -978,16 +1079,14 @@ type VSOCKDevice struct { // DisableModern prevents qemu from relying on fast MMIO. DisableModern bool + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } const ( // MinimalGuestCID is the smallest valid context ID for a guest. MinimalGuestCID uint32 = 3 -) - -const ( - // VhostVSOCKPCI is the VSOCK vhost device type. - VhostVSOCKPCI = "vhost-vsock-pci" // VSOCKGuestCID is the VSOCK guest CID parameter. VSOCKGuestCID = "guest-cid" @@ -1007,7 +1106,8 @@ func (vsock VSOCKDevice) QemuParams(config *Config) []string { var deviceParams []string var qemuParams []string - deviceParams = append(deviceParams, fmt.Sprintf("%s", VhostVSOCKPCI)) + driver := VHostVSockPCI + deviceParams = append(deviceParams, fmt.Sprintf("%s", driver)) if vsock.DisableModern { deviceParams = append(deviceParams, ",disable-modern=true") } @@ -1018,6 +1118,10 @@ func (vsock VSOCKDevice) QemuParams(config *Config) []string { deviceParams = append(deviceParams, fmt.Sprintf(",id=%s", vsock.ID)) deviceParams = append(deviceParams, fmt.Sprintf(",%s=%d", VSOCKGuestCID, vsock.ContextID)) + if isVirtioPCI[driver] { + deviceParams = append(deviceParams, fmt.Sprintf(",romfile=%s", vsock.ROMFile)) + } + qemuParams = append(qemuParams, "-device") qemuParams = append(qemuParams, strings.Join(deviceParams, "")) @@ -1034,6 +1138,8 @@ type RngDevice struct { MaxBytes uint // Period is duration of a read period in seconds Period uint + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // Valid returns true if the RngDevice structure is valid and complete. @@ -1054,12 +1160,17 @@ func (v RngDevice) QemuParams(_ *Config) []string { //-device virtio-rng-pci,rng=rng0,max-bytes=1024,period=1000 var deviceParams []string + driver := VirtioRng objectParams = append(objectParams, "rng-random") objectParams = append(objectParams, "id="+v.ID) - deviceParams = append(deviceParams, string(VirtioRng)) + deviceParams = append(deviceParams, string(driver)) deviceParams = append(deviceParams, "rng="+v.ID) + if isVirtioPCI[driver] { + deviceParams = append(deviceParams, fmt.Sprintf("romfile=%s", v.ROMFile)) + } + if v.Filename != "" { objectParams = append(objectParams, "filename="+v.Filename) } @@ -1086,6 +1197,9 @@ type BalloonDevice struct { DeflateOnOOM bool DisableModern bool ID string + + // ROMFile specifies the ROM file being used for this device. + ROMFile string } // QemuParams returns the qemu parameters built out of the BalloonDevice. @@ -1093,12 +1207,17 @@ func (b BalloonDevice) QemuParams(_ *Config) []string { var qemuParams []string var deviceParams []string - deviceParams = append(deviceParams, string(VirtioBalloon)) + driver := VirtioBalloon + deviceParams = append(deviceParams, string(driver)) if b.ID != "" { deviceParams = append(deviceParams, "id="+b.ID) } + if isVirtioPCI[driver] { + deviceParams = append(deviceParams, fmt.Sprintf("romfile=%s", b.ROMFile)) + } + if b.DeflateOnOOM { deviceParams = append(deviceParams, "deflate-on-oom=on") } else { diff --git a/qemu/qemu_test.go b/qemu/qemu_test.go index e1d9fb341b..e1c70e56d1 100644 --- a/qemu/qemu_test.go +++ b/qemu/qemu_test.go @@ -126,7 +126,7 @@ func TestAppendDeviceNVDIMM(t *testing.T) { testAppend(object, deviceNVDIMMString, t) } -var deviceFSString = "-device virtio-9p-pci,disable-modern=true,fsdev=workload9p,mount_tag=rootfs -fsdev local,id=workload9p,path=/var/lib/docker/devicemapper/mnt/e31ebda2,security_model=none" +var deviceFSString = "-device virtio-9p-pci,disable-modern=true,fsdev=workload9p,mount_tag=rootfs,romfile=efi-virtio.rom -fsdev local,id=workload9p,path=/var/lib/docker/devicemapper/mnt/e31ebda2,security_model=none" func TestAppendDeviceFS(t *testing.T) { fsdev := FSDevice{ @@ -137,12 +137,13 @@ func TestAppendDeviceFS(t *testing.T) { MountTag: "rootfs", SecurityModel: None, DisableModern: true, + ROMFile: "efi-virtio.rom", } testAppend(fsdev, deviceFSString, t) } -var deviceNetworkString = "-netdev tap,id=tap0,vhost=on,ifname=ceth0,downscript=no,script=no -device driver=virtio-net-pci,netdev=tap0,mac=01:02:de:ad:be:ef,disable-modern=true" +var deviceNetworkString = "-netdev tap,id=tap0,vhost=on,ifname=ceth0,downscript=no,script=no -device driver=virtio-net-pci,netdev=tap0,mac=01:02:de:ad:be:ef,disable-modern=true,romfile=efi-virtio.rom" func TestAppendDeviceNetwork(t *testing.T) { netdev := NetDevice{ @@ -155,12 +156,13 @@ func TestAppendDeviceNetwork(t *testing.T) { VHost: true, MACAddress: "01:02:de:ad:be:ef", DisableModern: true, + ROMFile: "efi-virtio.rom", } testAppend(netdev, deviceNetworkString, t) } -var deviceNetworkStringMq = "-netdev tap,id=tap0,vhost=on,fds=3:4 -device driver=virtio-net-pci,netdev=tap0,mac=01:02:de:ad:be:ef,disable-modern=true,mq=on,vectors=6" +var deviceNetworkStringMq = "-netdev tap,id=tap0,vhost=on,fds=3:4 -device driver=virtio-net-pci,netdev=tap0,mac=01:02:de:ad:be:ef,disable-modern=true,mq=on,vectors=6,romfile=efi-virtio.rom" func TestAppendDeviceNetworkMq(t *testing.T) { foo, _ := ioutil.TempFile(os.TempDir(), "govmm-qemu-test") @@ -184,12 +186,13 @@ func TestAppendDeviceNetworkMq(t *testing.T) { VHost: true, MACAddress: "01:02:de:ad:be:ef", DisableModern: true, + ROMFile: "efi-virtio.rom", } testAppend(netdev, deviceNetworkStringMq, t) } -var deviceNetworkPCIString = "-netdev tap,id=tap0,vhost=on,ifname=ceth0,downscript=no,script=no -device driver=virtio-net-pci,netdev=tap0,mac=01:02:de:ad:be:ef,bus=/pci-bus/pcie.0,addr=ff,disable-modern=true" +var deviceNetworkPCIString = "-netdev tap,id=tap0,vhost=on,ifname=ceth0,downscript=no,script=no -device driver=virtio-net-pci,netdev=tap0,mac=01:02:de:ad:be:ef,bus=/pci-bus/pcie.0,addr=ff,disable-modern=true,romfile=efi-virtio.rom" func TestAppendDeviceNetworkPCI(t *testing.T) { @@ -205,12 +208,13 @@ func TestAppendDeviceNetworkPCI(t *testing.T) { VHost: true, MACAddress: "01:02:de:ad:be:ef", DisableModern: true, + ROMFile: "efi-virtio.rom", } testAppend(netdev, deviceNetworkPCIString, t) } -var deviceNetworkPCIStringMq = "-netdev tap,id=tap0,vhost=on,fds=3:4 -device driver=virtio-net-pci,netdev=tap0,mac=01:02:de:ad:be:ef,bus=/pci-bus/pcie.0,addr=ff,disable-modern=true,mq=on,vectors=6" +var deviceNetworkPCIStringMq = "-netdev tap,id=tap0,vhost=on,fds=3:4 -device driver=virtio-net-pci,netdev=tap0,mac=01:02:de:ad:be:ef,bus=/pci-bus/pcie.0,addr=ff,disable-modern=true,mq=on,vectors=6,romfile=efi-virtio.rom" func TestAppendDeviceNetworkPCIMq(t *testing.T) { foo, _ := ioutil.TempFile(os.TempDir(), "govmm-qemu-test") @@ -236,18 +240,20 @@ func TestAppendDeviceNetworkPCIMq(t *testing.T) { VHost: true, MACAddress: "01:02:de:ad:be:ef", DisableModern: true, + ROMFile: "efi-virtio.rom", } testAppend(netdev, deviceNetworkPCIStringMq, t) } -var deviceSerialString = "-device virtio-serial-pci,disable-modern=true,id=serial0" +var deviceSerialString = "-device virtio-serial-pci,disable-modern=true,id=serial0,romfile=efi-virtio.rom" func TestAppendDeviceSerial(t *testing.T) { sdev := SerialDevice{ Driver: VirtioSerial, ID: "serial0", DisableModern: true, + ROMFile: "efi-virtio.rom", } testAppend(sdev, deviceSerialString, t) @@ -268,7 +274,7 @@ func TestAppendDeviceSerialPort(t *testing.T) { testAppend(chardev, deviceSerialPortString, t) } -var deviceBlockString = "-device virtio-blk,disable-modern=true,drive=hd0,scsi=off,config-wce=off -drive id=hd0,file=/var/lib/vm.img,aio=threads,format=qcow2,if=none" +var deviceBlockString = "-device virtio-blk,disable-modern=true,drive=hd0,scsi=off,config-wce=off,romfile=efi-virtio.rom -drive id=hd0,file=/var/lib/vm.img,aio=threads,format=qcow2,if=none" func TestAppendDeviceBlock(t *testing.T) { blkdev := BlockDevice{ @@ -281,14 +287,15 @@ func TestAppendDeviceBlock(t *testing.T) { SCSI: false, WCE: false, DisableModern: true, + ROMFile: "efi-virtio.rom", } testAppend(blkdev, deviceBlockString, t) } -var deviceVhostUserNetString = "-chardev socket,id=char1,path=/tmp/nonexistentsocket.socket -netdev type=vhost-user,id=net1,chardev=char1,vhostforce -device virtio-net-pci,netdev=net1,mac=00:11:22:33:44:55" -var deviceVhostUserSCSIString = "-chardev socket,id=char1,path=/tmp/nonexistentsocket.socket -device vhost-user-scsi-pci,id=scsi1,chardev=char1" -var deviceVhostUserBlkString = "-chardev socket,id=char2,path=/tmp/nonexistentsocket.socket -device vhost-user-blk-pci,logical_block_size=4096,size=512M,chardev=char2" +var deviceVhostUserNetString = "-chardev socket,id=char1,path=/tmp/nonexistentsocket.socket -netdev type=vhost-user,id=net1,chardev=char1,vhostforce -device virtio-net-pci,netdev=net1,mac=00:11:22:33:44:55,romfile=efi-virtio.rom" +var deviceVhostUserSCSIString = "-chardev socket,id=char1,path=/tmp/nonexistentsocket.socket -device vhost-user-scsi-pci,id=scsi1,chardev=char1,romfile=efi-virtio.rom" +var deviceVhostUserBlkString = "-chardev socket,id=char2,path=/tmp/nonexistentsocket.socket -device vhost-user-blk-pci,logical_block_size=4096,size=512M,chardev=char2,romfile=efi-virtio.rom" func TestAppendDeviceVhostUser(t *testing.T) { @@ -298,6 +305,7 @@ func TestAppendDeviceVhostUser(t *testing.T) { TypeDevID: "", Address: "", VhostUserType: VhostUserBlk, + ROMFile: "efi-virtio.rom", } testAppend(vhostuserBlkDevice, deviceVhostUserBlkString, t) @@ -307,6 +315,7 @@ func TestAppendDeviceVhostUser(t *testing.T) { TypeDevID: "scsi1", Address: "", VhostUserType: VhostUserSCSI, + ROMFile: "efi-virtio.rom", } testAppend(vhostuserSCSIDevice, deviceVhostUserSCSIString, t) @@ -316,21 +325,23 @@ func TestAppendDeviceVhostUser(t *testing.T) { TypeDevID: "net1", Address: "00:11:22:33:44:55", VhostUserType: VhostUserNet, + ROMFile: "efi-virtio.rom", } testAppend(vhostuserNetDevice, deviceVhostUserNetString, t) } -var deviceVFIOString = "-device vfio-pci,host=02:10.0" +var deviceVFIOString = "-device vfio-pci,host=02:10.0,romfile=efi-virtio.rom" func TestAppendDeviceVFIO(t *testing.T) { vfioDevice := VFIODevice{ - BDF: "02:10.0", + BDF: "02:10.0", + ROMFile: "efi-virtio.rom", } testAppend(vfioDevice, deviceVFIOString, t) } -var deviceVSOCKString = "-device vhost-vsock-pci,disable-modern=true,id=vhost-vsock-pci0,guest-cid=4" +var deviceVSOCKString = "-device vhost-vsock-pci,disable-modern=true,id=vhost-vsock-pci0,guest-cid=4,romfile=efi-virtio.rom" func TestAppendVSOCK(t *testing.T) { vsockDevice := VSOCKDevice{ @@ -338,6 +349,7 @@ func TestAppendVSOCK(t *testing.T) { ContextID: 4, VHostFD: nil, DisableModern: true, + ROMFile: "efi-virtio.rom", } testAppend(vsockDevice, deviceVSOCKString, t) @@ -364,9 +376,10 @@ func TestVSOCKValid(t *testing.T) { func TestAppendVirtioRng(t *testing.T) { var objectString = "-object rng-random,id=rng0" - var deviceString = "-device " + string(VirtioRng) + ",rng=rng0" + var deviceString = "-device " + string(VirtioRng) + ",rng=rng0,romfile=efi-virtio.rom" rngDevice := RngDevice{ - ID: "rng0", + ID: "rng0", + ROMFile: "efi-virtio.rom", } testAppend(rngDevice, objectString+" "+deviceString, t) @@ -406,11 +419,12 @@ func TestVirtioRngValid(t *testing.T) { func TestAppendVirtioBalloon(t *testing.T) { balloonDevice := BalloonDevice{ - ID: "balloon", + ID: "balloon", + ROMFile: "efi-virtio.rom", } var deviceString = "-device " + string(VirtioBalloon) - deviceString += ",id=" + balloonDevice.ID + deviceString += ",id=" + balloonDevice.ID + ",romfile=" + balloonDevice.ROMFile var OnDeflateOnOMM = ",deflate-on-oom=on" var OffDeflateOnOMM = ",deflate-on-oom=off" @@ -443,12 +457,13 @@ func TestVirtioBalloonValid(t *testing.T) { } } -var deviceSCSIControllerStr = "-device virtio-scsi-pci,id=foo" -var deviceSCSIControllerBusAddrStr = "-device virtio-scsi-pci,id=foo,bus=pci.0,addr=00:04.0,disable-modern=true,iothread=iothread1" +var deviceSCSIControllerStr = "-device virtio-scsi-pci,id=foo,romfile=efi-virtio.rom" +var deviceSCSIControllerBusAddrStr = "-device virtio-scsi-pci,id=foo,bus=pci.0,addr=00:04.0,disable-modern=true,iothread=iothread1,romfile=efi-virtio.rom" func TestAppendDeviceSCSIController(t *testing.T) { scsiCon := SCSIController{ - ID: "foo", + ID: "foo", + ROMFile: "efi-virtio.rom", } testAppend(scsiCon, deviceSCSIControllerStr, t) @@ -459,7 +474,7 @@ func TestAppendDeviceSCSIController(t *testing.T) { testAppend(scsiCon, deviceSCSIControllerBusAddrStr, t) } -var devicePCIBridgeString = "-device pci-bridge,bus=/pci-bus/pcie.0,id=mybridge,chassis_nr=5,shpc=on,addr=ff" +var devicePCIBridgeString = "-device pci-bridge,bus=/pci-bus/pcie.0,id=mybridge,chassis_nr=5,shpc=on,addr=ff,romfile=efi-virtio.rom" func TestAppendPCIBridgeDevice(t *testing.T) { @@ -470,20 +485,22 @@ func TestAppendPCIBridgeDevice(t *testing.T) { Addr: "255", Chassis: 5, SHPC: true, + ROMFile: "efi-virtio.rom", } testAppend(bridge, devicePCIBridgeString, t) } -var devicePCIEBridgeString = "-device pcie-pci-bridge,bus=/pci-bus/pcie.0,id=mybridge,addr=ff" +var devicePCIEBridgeString = "-device pcie-pci-bridge,bus=/pci-bus/pcie.0,id=mybridge,addr=ff,romfile=efi-virtio.rom" func TestAppendPCIEBridgeDevice(t *testing.T) { bridge := BridgeDevice{ - Type: PCIEBridge, - ID: "mybridge", - Bus: "/pci-bus/pcie.0", - Addr: "255", + Type: PCIEBridge, + ID: "mybridge", + Bus: "/pci-bus/pcie.0", + Addr: "255", + ROMFile: "efi-virtio.rom", } testAppend(bridge, devicePCIEBridgeString, t) diff --git a/qemu/qmp.go b/qemu/qmp.go index aac906f440..134608ec7d 100644 --- a/qemu/qmp.go +++ b/qemu/qmp.go @@ -756,7 +756,7 @@ func (q *QMP) ExecuteBlockdevAdd(ctx context.Context, device, blockdevID string) // add. Both strings must be valid QMP identifiers. driver is the name of the // driver,e.g., virtio-blk-pci, and bus is the name of the bus. bus is optional. // shared denotes if the drive can be shared allowing it to be passed more than once. -func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus string, shared bool) error { +func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus, romfile string, shared bool) error { args := map[string]interface{}{ "id": devID, "driver": driver, @@ -768,6 +768,10 @@ func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, b if shared && (q.version.Major > 2 || (q.version.Major == 2 && q.version.Minor >= 10)) { args["share-rw"] = "on" } + if isVirtioPCI[DeviceDriver(driver)] { + args["romfile"] = romfile + } + return q.executeCommand(ctx, "device_add", args, nil) } @@ -779,7 +783,7 @@ func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, b // scsiID is the SCSI id, lun is logical unit number. scsiID and lun are optional, a negative value // for scsiID and lun is ignored. shared denotes if the drive can be shared allowing it // to be passed more than once. -func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus string, scsiID, lun int, shared bool) error { +func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus, romfile string, scsiID, lun int, shared bool) error { // TBD: Add drivers for scsi passthrough like scsi-generic and scsi-block drivers := []string{"scsi-hd", "scsi-cd", "scsi-disk"} @@ -810,6 +814,9 @@ func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, drive if shared && (q.version.Major > 2 || (q.version.Major == 2 && q.version.Minor >= 10)) { args["share-rw"] = "on" } + if isVirtioPCI[DeviceDriver(driver)] { + args["romfile"] = romfile + } return q.executeCommand(ctx, "device_add", args, nil) } @@ -901,13 +908,14 @@ func (q *QMP) ExecuteNetdevDel(ctx context.Context, netdevID string) error { // using the device_add command. devID is the id of the device to add. // Must be valid QMP identifier. netdevID is the id of nic added by previous netdev_add. // queues is the number of queues of a nic. -func (q *QMP) ExecuteNetPCIDeviceAdd(ctx context.Context, netdevID, devID, macAddr, addr, bus string, queues int) error { +func (q *QMP) ExecuteNetPCIDeviceAdd(ctx context.Context, netdevID, devID, macAddr, addr, bus, romfile string, queues int) error { args := map[string]interface{}{ - "id": devID, - "driver": VirtioNetPCI, - "netdev": netdevID, - "mac": macAddr, - "addr": addr, + "id": devID, + "driver": VirtioNetPCI, + "netdev": netdevID, + "mac": macAddr, + "addr": addr, + "romfile": romfile, } if bus != "" { @@ -950,7 +958,7 @@ func (q *QMP) ExecuteDeviceDel(ctx context.Context, devID string) error { // to hot plug PCI devices on PCI(E) bridges, unlike ExecuteDeviceAdd this function receive the // device address on its parent bus. bus is optional. shared denotes if the drive can be shared // allowing it to be passed more than once. -func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver, addr, bus string, shared bool) error { +func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver, addr, bus, romfile string, shared bool) error { args := map[string]interface{}{ "id": devID, "driver": driver, @@ -963,6 +971,9 @@ func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver if shared && (q.version.Major > 2 || (q.version.Major == 2 && q.version.Minor >= 10)) { args["share-rw"] = "on" } + if isVirtioPCI[DeviceDriver(driver)] { + args["romfile"] = romfile + } return q.executeCommand(ctx, "device_add", args, nil) } @@ -971,11 +982,12 @@ func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver // using the device_add command. devID is the id of the device to add. // Must be valid QMP identifier. bdf is the PCI bus-device-function // of the pci device. -func (q *QMP) ExecuteVFIODeviceAdd(ctx context.Context, devID, bdf string) error { +func (q *QMP) ExecuteVFIODeviceAdd(ctx context.Context, devID, bdf, romfile string) error { args := map[string]interface{}{ - "id": devID, - "driver": "vfio-pci", - "host": bdf, + "id": devID, + "driver": "vfio-pci", + "host": bdf, + "romfile": romfile, } return q.executeCommand(ctx, "device_add", args, nil) } @@ -985,12 +997,13 @@ func (q *QMP) ExecuteVFIODeviceAdd(ctx context.Context, devID, bdf string) error // ExecuteVFIODeviceAdd this function receives the bus and the device address on its parent bus. // bus is optional. devID is the id of the device to add.Must be valid QMP identifier. bdf is the // PCI bus-device-function of the pci device. -func (q *QMP) ExecutePCIVFIODeviceAdd(ctx context.Context, devID, bdf, addr, bus string) error { +func (q *QMP) ExecutePCIVFIODeviceAdd(ctx context.Context, devID, bdf, addr, bus, romfile string) error { args := map[string]interface{}{ - "id": devID, - "driver": "vfio-pci", - "host": bdf, - "addr": addr, + "id": devID, + "driver": "vfio-pci", + "host": bdf, + "addr": addr, + "romfile": romfile, } if bus != "" { args["bus"] = bus @@ -1003,11 +1016,12 @@ func (q *QMP) ExecutePCIVFIODeviceAdd(ctx context.Context, devID, bdf, addr, bus // ExecuteVFIODeviceAdd this function receives the bus and the device address on its parent bus. // devID is the id of the device to add. Must be valid QMP identifier. sysfsdev is the VFIO mediated device. // Both bus and addr are optional. If they are both set to be empty, the system will pick up an empty slot on root bus. -func (q *QMP) ExecutePCIVFIOMediatedDeviceAdd(ctx context.Context, devID, sysfsdev, addr, bus string) error { +func (q *QMP) ExecutePCIVFIOMediatedDeviceAdd(ctx context.Context, devID, sysfsdev, addr, bus, romfile string) error { args := map[string]interface{}{ "id": devID, "driver": "vfio-pci", "sysfsdev": sysfsdev, + "romfile": romfile, } if bus != "" { args["bus"] = bus @@ -1022,7 +1036,7 @@ func (q *QMP) ExecutePCIVFIOMediatedDeviceAdd(ctx context.Context, devID, sysfsd // driver is the CPU model, cpuID must be a unique ID to identify the CPU, socketID is the socket number within // node/board the CPU belongs to, coreID is the core number within socket the CPU belongs to, threadID is the // thread number within core the CPU belongs to. -func (q *QMP) ExecuteCPUDeviceAdd(ctx context.Context, driver, cpuID, socketID, coreID, threadID string) error { +func (q *QMP) ExecuteCPUDeviceAdd(ctx context.Context, driver, cpuID, socketID, coreID, threadID, romfile string) error { args := map[string]interface{}{ "driver": driver, "id": cpuID, @@ -1030,6 +1044,11 @@ func (q *QMP) ExecuteCPUDeviceAdd(ctx context.Context, driver, cpuID, socketID, "core-id": coreID, "thread-id": threadID, } + + if isVirtioPCI[DeviceDriver(driver)] { + args["romfile"] = romfile + } + return q.executeCommand(ctx, "device_add", args, nil) } @@ -1188,13 +1207,14 @@ func (q *QMP) ExecuteBalloon(ctx context.Context, bytes uint64) error { } // ExecutePCIVSockAdd adds a vhost-vsock-pci bus -func (q *QMP) ExecutePCIVSockAdd(ctx context.Context, id, guestCID, vhostfd, addr, bus string, disableModern bool) error { +func (q *QMP) ExecutePCIVSockAdd(ctx context.Context, id, guestCID, vhostfd, addr, bus, romfile string, disableModern bool) error { args := map[string]interface{}{ "driver": VHostVSockPCI, "id": id, "guest-cid": guestCID, "vhostfd": vhostfd, "addr": addr, + "romfile": romfile, } if bus != "" { diff --git a/qemu/qmp_test.go b/qemu/qmp_test.go index b7c201f02e..a1a784dd6e 100644 --- a/qemu/qmp_test.go +++ b/qemu/qmp_test.go @@ -504,7 +504,7 @@ func TestQMPNetPCIDeviceAdd(t *testing.T) { cfg := QMPConfig{Logger: qmpTestLogger{}} q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) checkVersion(t, connectedCh) - err := q.ExecuteNetPCIDeviceAdd(context.Background(), "br0", "virtio-0", "02:42:ac:11:00:02", "0x7", "", 8) + err := q.ExecuteNetPCIDeviceAdd(context.Background(), "br0", "virtio-0", "02:42:ac:11:00:02", "0x7", "", "", 8) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -529,7 +529,7 @@ func TestQMPDeviceAdd(t *testing.T) { blockdevID := fmt.Sprintf("drive_%s", volumeUUID) devID := fmt.Sprintf("device_%s", volumeUUID) err := q.ExecuteDeviceAdd(context.Background(), blockdevID, devID, - "virtio-blk-pci", "", true) + "virtio-blk-pci", "", "", true) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -554,7 +554,7 @@ func TestQMPSCSIDeviceAdd(t *testing.T) { blockdevID := fmt.Sprintf("drive_%s", volumeUUID) devID := fmt.Sprintf("device_%s", volumeUUID) err := q.ExecuteSCSIDeviceAdd(context.Background(), blockdevID, devID, - "scsi-hd", "scsi0.0", 1, 2, true) + "scsi-hd", "scsi0.0", "", 1, 2, true) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -972,7 +972,7 @@ func TestQMPPCIDeviceAdd(t *testing.T) { blockdevID := fmt.Sprintf("drive_%s", volumeUUID) devID := fmt.Sprintf("device_%s", volumeUUID) err := q.ExecutePCIDeviceAdd(context.Background(), blockdevID, devID, - "virtio-blk-pci", "0x1", "", true) + "virtio-blk-pci", "0x1", "", "", true) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -996,7 +996,7 @@ func TestQMPPCIVFIOMediatedDeviceAdd(t *testing.T) { checkVersion(t, connectedCh) sysfsDev := "/sys/bus/pci/devices/0000:00:02.0/a297db4a-f4c2-11e6-90f6-d3b88d6c9525" devID := fmt.Sprintf("device_%s", volumeUUID) - err := q.ExecutePCIVFIOMediatedDeviceAdd(context.Background(), devID, sysfsDev, "0x1", "") + err := q.ExecutePCIVFIOMediatedDeviceAdd(context.Background(), devID, sysfsDev, "0x1", "", "") if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -1018,7 +1018,7 @@ func TestQMPCPUDeviceAdd(t *testing.T) { socketID := "0" coreID := "1" threadID := "0" - err := q.ExecuteCPUDeviceAdd(context.Background(), driver, cpuID, socketID, coreID, threadID) + err := q.ExecuteCPUDeviceAdd(context.Background(), driver, cpuID, socketID, coreID, threadID, "") if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -1237,7 +1237,7 @@ func TestExecutePCIVSockAdd(t *testing.T) { cfg := QMPConfig{Logger: qmpTestLogger{}} q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) checkVersion(t, connectedCh) - err := q.ExecutePCIVSockAdd(context.Background(), "vsock-pci0", "3", "1", "1", "1", true) + err := q.ExecutePCIVSockAdd(context.Background(), "vsock-pci0", "3", "1", "1", "1", "", true) if err != nil { t.Fatalf("Unexpected error %v", err) }