github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/qemu_arch_base.go (about) 1 // Copyright (c) 2018 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package virtcontainers 7 8 import ( 9 "context" 10 "encoding/hex" 11 "errors" 12 "fmt" 13 "os" 14 "strconv" 15 "strings" 16 17 govmmQemu "github.com/kata-containers/govmm/qemu" 18 19 "github.com/kata-containers/runtime/virtcontainers/device/config" 20 "github.com/kata-containers/runtime/virtcontainers/types" 21 "github.com/kata-containers/runtime/virtcontainers/utils" 22 ) 23 24 type qemuArch interface { 25 // enableNestingChecks nesting checks will be honoured 26 enableNestingChecks() 27 28 // disableNestingChecks nesting checks will be ignored 29 disableNestingChecks() 30 31 // runNested indicates if the hypervisor runs in a nested environment 32 runNested() bool 33 34 // enableVhostNet vhost will be enabled 35 enableVhostNet() 36 37 // disableVhostNet vhost will be disabled 38 disableVhostNet() 39 40 // machine returns the machine type 41 machine() (govmmQemu.Machine, error) 42 43 // qemuPath returns the path to the QEMU binary 44 qemuPath() (string, error) 45 46 // kernelParameters returns the kernel parameters 47 // if debug is true then kernel debug parameters are included 48 kernelParameters(debug bool) []Param 49 50 //capabilities returns the capabilities supported by QEMU 51 capabilities() types.Capabilities 52 53 // bridges sets the number bridges for the machine type 54 bridges(number uint32) 55 56 // cpuTopology returns the CPU topology for the given amount of vcpus 57 cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP 58 59 // cpuModel returns the CPU model for the machine type 60 cpuModel() string 61 62 // memoryTopology returns the memory topology using the given amount of memoryMb and hostMemoryMb 63 memoryTopology(memoryMb, hostMemoryMb uint64, slots uint8) govmmQemu.Memory 64 65 // appendConsole appends a console to devices 66 appendConsole(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) 67 68 // appendImage appends an image to devices 69 appendImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) 70 71 // appendBlockImage appends an image as block device 72 appendBlockImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) 73 74 // appendNvdimmImage appends an image as nvdimm device 75 appendNvdimmImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) 76 77 // appendSCSIController appens a SCSI controller to devices 78 appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread, error) 79 80 // appendBridges appends bridges to devices 81 appendBridges(devices []govmmQemu.Device) []govmmQemu.Device 82 83 // append9PVolume appends a 9P volume to devices 84 append9PVolume(devices []govmmQemu.Device, volume types.Volume) ([]govmmQemu.Device, error) 85 86 // appendSocket appends a socket to devices 87 appendSocket(devices []govmmQemu.Device, socket types.Socket) []govmmQemu.Device 88 89 // appendVSock appends a vsock PCI to devices 90 appendVSock(devices []govmmQemu.Device, vsock types.VSock) ([]govmmQemu.Device, error) 91 92 // appendNetwork appends a endpoint device to devices 93 appendNetwork(devices []govmmQemu.Device, endpoint Endpoint) ([]govmmQemu.Device, error) 94 95 // appendBlockDevice appends a block drive to devices 96 appendBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) ([]govmmQemu.Device, error) 97 98 // appendVhostUserDevice appends a vhost user device to devices 99 appendVhostUserDevice(devices []govmmQemu.Device, drive config.VhostUserDeviceAttrs) ([]govmmQemu.Device, error) 100 101 // appendVFIODevice appends a VFIO device to devices 102 appendVFIODevice(devices []govmmQemu.Device, vfioDevice config.VFIODev) []govmmQemu.Device 103 104 // appendRNGDevice appends a RNG device to devices 105 appendRNGDevice(devices []govmmQemu.Device, rngDevice config.RNGDev) ([]govmmQemu.Device, error) 106 107 // addDeviceToBridge adds devices to the bus 108 addDeviceToBridge(ID string, t types.Type) (string, types.Bridge, error) 109 110 // removeDeviceFromBridge removes devices to the bus 111 removeDeviceFromBridge(ID string) error 112 113 // getBridges grants access to Bridges 114 getBridges() []types.Bridge 115 116 // setBridges grants access to Bridges 117 setBridges(bridges []types.Bridge) 118 119 // addBridge adds a new Bridge to the list of Bridges 120 addBridge(types.Bridge) 121 122 // getPFlash() get pflash from configuration 123 getPFlash() ([]string, error) 124 125 // setPFlash() grants access to pflash 126 setPFlash([]string) 127 128 // handleImagePath handles the Hypervisor Config image path 129 handleImagePath(config HypervisorConfig) 130 131 // supportGuestMemoryHotplug returns if the guest supports memory hotplug 132 supportGuestMemoryHotplug() bool 133 134 // setIgnoreSharedMemoryMigrationCaps set bypass-shared-memory capability for migration 135 setIgnoreSharedMemoryMigrationCaps(context.Context, *govmmQemu.QMP) error 136 137 // appendPCIeRootPortDevice appends a pcie-root-port device to pcie.0 bus 138 appendPCIeRootPortDevice(devices []govmmQemu.Device, number uint32) []govmmQemu.Device 139 140 // append vIOMMU device 141 appendIOMMU(devices []govmmQemu.Device) ([]govmmQemu.Device, error) 142 } 143 144 type qemuArchBase struct { 145 machineType string 146 memoryOffset uint32 147 nestedRun bool 148 vhost bool 149 disableNvdimm bool 150 dax bool 151 networkIndex int 152 qemuPaths map[string]string 153 supportedQemuMachines []govmmQemu.Machine 154 kernelParamsNonDebug []Param 155 kernelParamsDebug []Param 156 kernelParams []Param 157 Bridges []types.Bridge 158 PFlash []string 159 } 160 161 const ( 162 defaultCores uint32 = 1 163 defaultThreads uint32 = 1 164 defaultCPUModel = "host" 165 defaultBridgeBus = "pcie.0" 166 defaultPCBridgeBus = "pci.0" 167 maxDevIDSize = 31 168 defaultMsize9p = 8192 169 pcieRootPortPrefix = "rp" 170 ) 171 172 // This is the PCI start address assigned to the first bridge that 173 // is added on the qemu command line. In case of x86_64, the first two PCI 174 // addresses (0 and 1) are used by the platform while in case of ARM, address 175 // 0 is reserved. 176 const bridgePCIStartAddr = 2 177 178 const ( 179 // QemuPCLite is the QEMU pc-lite machine type for amd64 180 QemuPCLite = "pc-lite" 181 182 // QemuPC is the QEMU pc machine type for amd64 183 QemuPC = "pc" 184 185 // QemuQ35 is the QEMU Q35 machine type for amd64 186 QemuQ35 = "q35" 187 188 // QemuMicrovm is the QEMU microvm machine type for amd64 189 QemuMicrovm = "microvm" 190 191 // QemuVirt is the QEMU virt machine type for aarch64 or amd64 192 QemuVirt = "virt" 193 194 // QemuPseries is a QEMU virt machine type for ppc64le 195 QemuPseries = "pseries" 196 197 // QemuCCWVirtio is a QEMU virt machine type for for s390x 198 QemuCCWVirtio = "s390-ccw-virtio" 199 200 qmpCapMigrationIgnoreShared = "x-ignore-shared" 201 202 qemuNvdimmOption = "nvdimm" 203 ) 204 205 // kernelParamsNonDebug is a list of the default kernel 206 // parameters that will be used in standard (non-debug) mode. 207 var kernelParamsNonDebug = []Param{ 208 {"quiet", ""}, 209 } 210 211 // kernelParamsSystemdNonDebug is a list of the default systemd related 212 // kernel parameters that will be used in standard (non-debug) mode. 213 var kernelParamsSystemdNonDebug = []Param{ 214 {"systemd.show_status", "false"}, 215 } 216 217 // kernelParamsDebug is a list of the default kernel 218 // parameters that will be used in debug mode (as much boot output as 219 // possible). 220 var kernelParamsDebug = []Param{ 221 {"debug", ""}, 222 } 223 224 // kernelParamsSystemdDebug is a list of the default systemd related kernel 225 // parameters that will be used in debug mode (as much boot output as 226 // possible). 227 var kernelParamsSystemdDebug = []Param{ 228 {"systemd.show_status", "true"}, 229 {"systemd.log_level", "debug"}, 230 } 231 232 func (q *qemuArchBase) enableNestingChecks() { 233 q.nestedRun = true 234 } 235 236 func (q *qemuArchBase) disableNestingChecks() { 237 q.nestedRun = false 238 } 239 240 func (q *qemuArchBase) runNested() bool { 241 return q.nestedRun 242 } 243 244 func (q *qemuArchBase) enableVhostNet() { 245 q.vhost = true 246 } 247 248 func (q *qemuArchBase) disableVhostNet() { 249 q.vhost = false 250 } 251 252 func (q *qemuArchBase) machine() (govmmQemu.Machine, error) { 253 for _, m := range q.supportedQemuMachines { 254 if m.Type == q.machineType { 255 return m, nil 256 } 257 } 258 259 return govmmQemu.Machine{}, fmt.Errorf("unrecognised machine type: %v", q.machineType) 260 } 261 262 func (q *qemuArchBase) qemuPath() (string, error) { 263 p, ok := q.qemuPaths[q.machineType] 264 if !ok { 265 return "", fmt.Errorf("Unknown machine type: %s", q.machineType) 266 } 267 268 return p, nil 269 } 270 271 func (q *qemuArchBase) kernelParameters(debug bool) []Param { 272 params := q.kernelParams 273 274 if debug { 275 params = append(params, q.kernelParamsDebug...) 276 } else { 277 params = append(params, q.kernelParamsNonDebug...) 278 } 279 280 return params 281 } 282 283 func (q *qemuArchBase) capabilities() types.Capabilities { 284 var caps types.Capabilities 285 caps.SetBlockDeviceHotplugSupport() 286 caps.SetMultiQueueSupport() 287 caps.SetFsSharingSupport() 288 return caps 289 } 290 291 func (q *qemuArchBase) bridges(number uint32) { 292 for i := uint32(0); i < number; i++ { 293 q.Bridges = append(q.Bridges, types.NewBridge(types.PCI, fmt.Sprintf("%s-bridge-%d", types.PCI, i), make(map[uint32]string), 0)) 294 } 295 } 296 297 func (q *qemuArchBase) cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP { 298 smp := govmmQemu.SMP{ 299 CPUs: vcpus, 300 Sockets: maxvcpus, 301 Cores: defaultCores, 302 Threads: defaultThreads, 303 MaxCPUs: maxvcpus, 304 } 305 306 return smp 307 } 308 309 func (q *qemuArchBase) cpuModel() string { 310 return defaultCPUModel 311 } 312 313 func (q *qemuArchBase) memoryTopology(memoryMb, hostMemoryMb uint64, slots uint8) govmmQemu.Memory { 314 memMax := fmt.Sprintf("%dM", hostMemoryMb) 315 mem := fmt.Sprintf("%dM", memoryMb) 316 memory := govmmQemu.Memory{ 317 Size: mem, 318 Slots: slots, 319 MaxMem: memMax, 320 } 321 322 return memory 323 } 324 325 func (q *qemuArchBase) appendConsole(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 326 serial := govmmQemu.SerialDevice{ 327 Driver: govmmQemu.VirtioSerial, 328 ID: "serial0", 329 DisableModern: q.nestedRun, 330 MaxPorts: uint(2), 331 } 332 333 devices = append(devices, serial) 334 335 console := govmmQemu.CharDevice{ 336 Driver: govmmQemu.Console, 337 Backend: govmmQemu.Socket, 338 DeviceID: "console0", 339 ID: "charconsole0", 340 Path: path, 341 } 342 343 devices = append(devices, console) 344 345 return devices, nil 346 } 347 348 func genericImage(path string) (config.BlockDrive, error) { 349 if _, err := os.Stat(path); os.IsNotExist(err) { 350 return config.BlockDrive{}, err 351 } 352 353 randBytes, err := utils.GenerateRandomBytes(8) 354 if err != nil { 355 return config.BlockDrive{}, err 356 } 357 358 id := utils.MakeNameID("image", hex.EncodeToString(randBytes), maxDevIDSize) 359 360 drive := config.BlockDrive{ 361 File: path, 362 Format: "raw", 363 ID: id, 364 ShareRW: true, 365 ReadOnly: true, 366 } 367 368 return drive, nil 369 } 370 371 func (q *qemuArchBase) appendNvdimmImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 372 imageFile, err := os.Open(path) 373 if err != nil { 374 return nil, err 375 } 376 defer imageFile.Close() 377 378 imageStat, err := imageFile.Stat() 379 if err != nil { 380 return nil, err 381 } 382 383 object := govmmQemu.Object{ 384 Driver: govmmQemu.NVDIMM, 385 Type: govmmQemu.MemoryBackendFile, 386 DeviceID: "nv0", 387 ID: "mem0", 388 MemPath: path, 389 Size: (uint64)(imageStat.Size()), 390 } 391 392 devices = append(devices, object) 393 394 return devices, nil 395 } 396 397 func (q *qemuArchBase) appendImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 398 return q.appendBlockImage(devices, path) 399 } 400 401 func (q *qemuArchBase) appendBlockImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 402 drive, err := genericImage(path) 403 if err != nil { 404 return nil, err 405 } 406 devices, err = q.appendBlockDevice(devices, drive) 407 if err != nil { 408 return nil, err 409 } 410 return devices, nil 411 } 412 413 func genericSCSIController(enableIOThreads, nestedRun bool) (govmmQemu.SCSIController, *govmmQemu.IOThread) { 414 scsiController := govmmQemu.SCSIController{ 415 ID: scsiControllerID, 416 DisableModern: nestedRun, 417 } 418 419 var t *govmmQemu.IOThread 420 421 if enableIOThreads { 422 randBytes, _ := utils.GenerateRandomBytes(8) 423 424 t = &govmmQemu.IOThread{ 425 ID: fmt.Sprintf("%s-%s", "iothread", hex.EncodeToString(randBytes)), 426 } 427 428 scsiController.IOThread = t.ID 429 } 430 431 return scsiController, t 432 } 433 434 func (q *qemuArchBase) appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread, error) { 435 d, t := genericSCSIController(enableIOThreads, q.nestedRun) 436 devices = append(devices, d) 437 return devices, t, nil 438 } 439 440 // appendBridges appends to devices the given bridges 441 func (q *qemuArchBase) appendBridges(devices []govmmQemu.Device) []govmmQemu.Device { 442 for idx, b := range q.Bridges { 443 if b.Type == types.CCW { 444 continue 445 } 446 t := govmmQemu.PCIBridge 447 if b.Type == types.PCIE { 448 t = govmmQemu.PCIEBridge 449 } 450 451 q.Bridges[idx].Addr = bridgePCIStartAddr + idx 452 453 devices = append(devices, 454 govmmQemu.BridgeDevice{ 455 Type: t, 456 Bus: defaultBridgeBus, 457 ID: b.ID, 458 // Each bridge is required to be assigned a unique chassis id > 0 459 Chassis: idx + 1, 460 SHPC: true, 461 Addr: strconv.FormatInt(int64(q.Bridges[idx].Addr), 10), 462 }, 463 ) 464 } 465 466 return devices 467 } 468 469 func generic9PVolume(volume types.Volume, nestedRun bool) govmmQemu.FSDevice { 470 devID := fmt.Sprintf("extra-9p-%s", volume.MountTag) 471 if len(devID) > maxDevIDSize { 472 devID = devID[:maxDevIDSize] 473 } 474 475 return govmmQemu.FSDevice{ 476 Driver: govmmQemu.Virtio9P, 477 FSDriver: govmmQemu.Local, 478 ID: devID, 479 Path: volume.HostPath, 480 MountTag: volume.MountTag, 481 SecurityModel: govmmQemu.None, 482 DisableModern: nestedRun, 483 Multidev: govmmQemu.Remap, 484 } 485 } 486 487 func genericAppend9PVolume(devices []govmmQemu.Device, volume types.Volume, nestedRun bool) (govmmQemu.FSDevice, error) { 488 d := generic9PVolume(volume, nestedRun) 489 return d, nil 490 } 491 492 func (q *qemuArchBase) append9PVolume(devices []govmmQemu.Device, volume types.Volume) ([]govmmQemu.Device, error) { 493 if volume.MountTag == "" || volume.HostPath == "" { 494 return devices, nil 495 } 496 497 d, err := genericAppend9PVolume(devices, volume, q.nestedRun) 498 if err != nil { 499 return nil, err 500 } 501 502 devices = append(devices, d) 503 return devices, nil 504 } 505 506 func (q *qemuArchBase) appendSocket(devices []govmmQemu.Device, socket types.Socket) []govmmQemu.Device { 507 devID := socket.ID 508 if len(devID) > maxDevIDSize { 509 devID = devID[:maxDevIDSize] 510 } 511 512 devices = append(devices, 513 govmmQemu.CharDevice{ 514 Driver: govmmQemu.VirtioSerialPort, 515 Backend: govmmQemu.Socket, 516 DeviceID: socket.DeviceID, 517 ID: devID, 518 Path: socket.HostPath, 519 Name: socket.Name, 520 }, 521 ) 522 523 return devices 524 } 525 526 func (q *qemuArchBase) appendVSock(devices []govmmQemu.Device, vsock types.VSock) ([]govmmQemu.Device, error) { 527 devices = append(devices, 528 govmmQemu.VSOCKDevice{ 529 ID: fmt.Sprintf("vsock-%d", vsock.ContextID), 530 ContextID: vsock.ContextID, 531 VHostFD: vsock.VhostFd, 532 DisableModern: q.nestedRun, 533 }, 534 ) 535 536 return devices, nil 537 538 } 539 540 func networkModelToQemuType(model NetInterworkingModel) govmmQemu.NetDeviceType { 541 switch model { 542 case NetXConnectMacVtapModel: 543 return govmmQemu.MACVTAP 544 default: 545 //TAP should work for most other cases 546 return govmmQemu.TAP 547 } 548 } 549 550 func genericNetwork(endpoint Endpoint, vhost, nestedRun bool, index int) (govmmQemu.NetDevice, error) { 551 var d govmmQemu.NetDevice 552 switch ep := endpoint.(type) { 553 case *VethEndpoint, *BridgedMacvlanEndpoint, *IPVlanEndpoint: 554 netPair := ep.NetworkPair() 555 d = govmmQemu.NetDevice{ 556 Type: networkModelToQemuType(netPair.NetInterworkingModel), 557 Driver: govmmQemu.VirtioNet, 558 ID: fmt.Sprintf("network-%d", index), 559 IFName: netPair.TAPIface.Name, 560 MACAddress: netPair.TAPIface.HardAddr, 561 DownScript: "no", 562 Script: "no", 563 VHost: vhost, 564 DisableModern: nestedRun, 565 FDs: netPair.VMFds, 566 VhostFDs: netPair.VhostFds, 567 } 568 case *MacvtapEndpoint: 569 d = govmmQemu.NetDevice{ 570 Type: govmmQemu.MACVTAP, 571 Driver: govmmQemu.VirtioNet, 572 ID: fmt.Sprintf("network-%d", index), 573 IFName: ep.Name(), 574 MACAddress: ep.HardwareAddr(), 575 DownScript: "no", 576 Script: "no", 577 VHost: vhost, 578 DisableModern: nestedRun, 579 FDs: ep.VMFds, 580 VhostFDs: ep.VhostFds, 581 } 582 case *TuntapEndpoint: 583 netPair := ep.NetworkPair() 584 d = govmmQemu.NetDevice{ 585 Type: govmmQemu.NetDeviceType("tap"), 586 Driver: govmmQemu.VirtioNet, 587 ID: fmt.Sprintf("network-%d", index), 588 IFName: netPair.TAPIface.Name, 589 MACAddress: netPair.TAPIface.HardAddr, 590 DownScript: "no", 591 Script: "no", 592 VHost: vhost, 593 DisableModern: nestedRun, 594 FDs: netPair.VMFds, 595 VhostFDs: netPair.VhostFds, 596 } 597 default: 598 return govmmQemu.NetDevice{}, fmt.Errorf("Unknown type for endpoint") 599 } 600 601 return d, nil 602 } 603 604 func (q *qemuArchBase) appendNetwork(devices []govmmQemu.Device, endpoint Endpoint) ([]govmmQemu.Device, error) { 605 d, err := genericNetwork(endpoint, q.vhost, q.nestedRun, q.networkIndex) 606 if err != nil { 607 return devices, fmt.Errorf("Failed to append network %v", err) 608 } 609 q.networkIndex++ 610 devices = append(devices, d) 611 return devices, nil 612 } 613 614 func genericBlockDevice(drive config.BlockDrive, nestedRun bool) (govmmQemu.BlockDevice, error) { 615 if drive.File == "" || drive.ID == "" || drive.Format == "" { 616 return govmmQemu.BlockDevice{}, fmt.Errorf("Empty File, ID or Format for drive %v", drive) 617 } 618 619 if len(drive.ID) > maxDevIDSize { 620 drive.ID = drive.ID[:maxDevIDSize] 621 } 622 623 return govmmQemu.BlockDevice{ 624 Driver: govmmQemu.VirtioBlock, 625 ID: drive.ID, 626 File: drive.File, 627 AIO: govmmQemu.Threads, 628 Format: govmmQemu.BlockDeviceFormat(drive.Format), 629 Interface: "none", 630 DisableModern: nestedRun, 631 ShareRW: drive.ShareRW, 632 ReadOnly: drive.ReadOnly, 633 }, nil 634 } 635 636 func (q *qemuArchBase) appendBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) ([]govmmQemu.Device, error) { 637 d, err := genericBlockDevice(drive, q.nestedRun) 638 if err != nil { 639 return devices, fmt.Errorf("Failed to append block device %v", err) 640 } 641 devices = append(devices, d) 642 return devices, nil 643 } 644 645 func (q *qemuArchBase) appendVhostUserDevice(devices []govmmQemu.Device, attr config.VhostUserDeviceAttrs) ([]govmmQemu.Device, error) { 646 qemuVhostUserDevice := govmmQemu.VhostUserDevice{} 647 648 switch attr.Type { 649 case config.VhostUserNet: 650 qemuVhostUserDevice.TypeDevID = utils.MakeNameID("net", attr.DevID, maxDevIDSize) 651 qemuVhostUserDevice.Address = attr.MacAddress 652 qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserNet 653 case config.VhostUserSCSI: 654 qemuVhostUserDevice.TypeDevID = utils.MakeNameID("scsi", attr.DevID, maxDevIDSize) 655 qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserSCSI 656 case config.VhostUserBlk: 657 qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserBlk 658 case config.VhostUserFS: 659 qemuVhostUserDevice.TypeDevID = utils.MakeNameID("fs", attr.DevID, maxDevIDSize) 660 qemuVhostUserDevice.Tag = attr.Tag 661 qemuVhostUserDevice.CacheSize = attr.CacheSize 662 qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserFS 663 } 664 665 qemuVhostUserDevice.SocketPath = attr.SocketPath 666 qemuVhostUserDevice.CharDevID = utils.MakeNameID("char", attr.DevID, maxDevIDSize) 667 668 devices = append(devices, qemuVhostUserDevice) 669 670 return devices, nil 671 } 672 673 func (q *qemuArchBase) appendVFIODevice(devices []govmmQemu.Device, vfioDev config.VFIODev) []govmmQemu.Device { 674 if vfioDev.BDF == "" { 675 return devices 676 } 677 678 devices = append(devices, 679 govmmQemu.VFIODevice{ 680 BDF: vfioDev.BDF, 681 VendorID: vfioDev.VendorID, 682 DeviceID: vfioDev.DeviceID, 683 Bus: vfioDev.Bus, 684 }, 685 ) 686 687 return devices 688 } 689 690 func (q *qemuArchBase) appendRNGDevice(devices []govmmQemu.Device, rngDev config.RNGDev) ([]govmmQemu.Device, error) { 691 devices = append(devices, 692 govmmQemu.RngDevice{ 693 ID: rngDev.ID, 694 Filename: rngDev.Filename, 695 }, 696 ) 697 698 return devices, nil 699 } 700 701 func (q *qemuArchBase) handleImagePath(config HypervisorConfig) { 702 if config.ImagePath != "" { 703 kernelRootParams := commonVirtioblkKernelRootParams 704 if !q.disableNvdimm { 705 for i := range q.supportedQemuMachines { 706 q.supportedQemuMachines[i].Options = strings.Join([]string{ 707 q.supportedQemuMachines[i].Options, 708 qemuNvdimmOption, 709 }, ",") 710 } 711 if q.dax { 712 kernelRootParams = commonNvdimmKernelRootParams 713 } else { 714 kernelRootParams = commonNvdimmNoDAXKernelRootParams 715 } 716 } 717 q.kernelParams = append(q.kernelParams, kernelRootParams...) 718 q.kernelParamsNonDebug = append(q.kernelParamsNonDebug, kernelParamsSystemdNonDebug...) 719 q.kernelParamsDebug = append(q.kernelParamsDebug, kernelParamsSystemdDebug...) 720 } 721 } 722 723 func (q *qemuArchBase) supportGuestMemoryHotplug() bool { 724 return true 725 } 726 727 func (q *qemuArchBase) setIgnoreSharedMemoryMigrationCaps(ctx context.Context, qmp *govmmQemu.QMP) error { 728 err := qmp.ExecSetMigrationCaps(ctx, []map[string]interface{}{ 729 { 730 "capability": qmpCapMigrationIgnoreShared, 731 "state": true, 732 }, 733 }) 734 return err 735 } 736 737 func (q *qemuArchBase) addDeviceToBridge(ID string, t types.Type) (string, types.Bridge, error) { 738 var err error 739 var addr uint32 740 741 if len(q.Bridges) == 0 { 742 return "", types.Bridge{}, errors.New("failed to get available address from bridges") 743 } 744 745 // looking for an empty address in the bridges 746 for _, b := range q.Bridges { 747 if t != b.Type { 748 continue 749 } 750 addr, err = b.AddDevice(ID) 751 if err == nil { 752 switch t { 753 case types.CCW: 754 return fmt.Sprintf("%04x", addr), b, nil 755 case types.PCI, types.PCIE: 756 return fmt.Sprintf("%02x", addr), b, nil 757 } 758 } 759 } 760 761 return "", types.Bridge{}, fmt.Errorf("no more bridge slots available") 762 } 763 764 func (q *qemuArchBase) removeDeviceFromBridge(ID string) error { 765 var err error 766 for _, b := range q.Bridges { 767 err = b.RemoveDevice(ID) 768 if err == nil { 769 // device was removed correctly 770 return nil 771 } 772 } 773 774 return err 775 } 776 777 func (q *qemuArchBase) getBridges() []types.Bridge { 778 return q.Bridges 779 } 780 781 func (q *qemuArchBase) setBridges(bridges []types.Bridge) { 782 q.Bridges = bridges 783 } 784 785 func (q *qemuArchBase) addBridge(b types.Bridge) { 786 q.Bridges = append(q.Bridges, b) 787 } 788 789 // appendPCIeRootPortDevice appends to devices the given pcie-root-port 790 func (q *qemuArchBase) appendPCIeRootPortDevice(devices []govmmQemu.Device, number uint32) []govmmQemu.Device { 791 return genericAppendPCIeRootPort(devices, number, q.machineType) 792 793 } 794 795 // appendIOMMU appends a virtual IOMMU device 796 func (q *qemuArchBase) appendIOMMU(devices []govmmQemu.Device) ([]govmmQemu.Device, error) { 797 switch q.machineType { 798 case QemuQ35: 799 iommu := govmmQemu.IommuDev{ 800 Intremap: true, 801 DeviceIotlb: true, 802 CachingMode: true, 803 } 804 805 devices = append(devices, iommu) 806 return devices, nil 807 default: 808 return devices, fmt.Errorf("Machine Type %s does not support vIOMMU", q.machineType) 809 } 810 } 811 812 func (q *qemuArchBase) getPFlash() ([]string, error) { 813 return q.PFlash, nil 814 } 815 816 func (q *qemuArchBase) setPFlash(p []string) { 817 q.PFlash = p 818 }