diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 50f37ae5cc..3e07360d7a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1686,6 +1686,18 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
break;
}
}
+ /* SATA controllers aren't hot-plugged, and can be put in either a
+ * PCI or PCIe slot
+ */
+ if (device->type == VIR_DOMAIN_DEVICE_CONTROLLER &&
+ device->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA)
+ flags = QEMU_PCI_CONNECT_TYPE_PCI | QEMU_PCI_CONNECT_TYPE_PCIE;
+
+ /* video cards aren't hot-plugged, and can be put in either a PCI
+ * or PCIe slot
+ */
+ if (device->type == VIR_DOMAIN_DEVICE_VIDEO)
+ flags = QEMU_PCI_CONNECT_TYPE_PCI | QEMU_PCI_CONNECT_TYPE_PCIE;
/* Ignore implicit controllers on slot 0:0:1.0:
* implicit IDE controller on 0:0:1.1 (no qemu command line)
@@ -2258,6 +2270,12 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
}
if (def->nvideos > 0) {
+ /* Because the PIIX3 integrated IDE/USB controllers are
+ * already at slot 1, when qemu looks for the first free slot
+ * to place the VGA controller (which is always the first
+ * device added after integrated devices), it *always* ends up
+ * at slot 2.
+ */
virDomainVideoDefPtr primaryVideo = def->videos[0];
if (primaryVideo->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -2318,6 +2336,136 @@ error:
}
+static bool
+qemuDomainMachineIsQ35(virDomainDefPtr def)
+{
+ return (STRPREFIX(def->os.machine, "pc-q35") ||
+ STREQ(def->os.machine, "q35"));
+}
+
+
+static int
+qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ qemuDomainPCIAddressSetPtr addrs)
+{
+ size_t i;
+ virDevicePCIAddress tmp_addr;
+ bool qemuDeviceVideoUsable = virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIDEO_PRIMARY);
+ virDevicePCIAddressPtr addrptr;
+ qemuDomainPCIConnectFlags flags = QEMU_PCI_CONNECT_TYPE_PCIE;
+
+ /* Verify that the first SATA controller is at 00:1F.2 */
+ /* the q35 machine type *always* has a SATA controller at this address */
+ for (i = 0; i < def->ncontrollers; i++) {
+ if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA &&
+ def->controllers[i]->idx == 0) {
+ if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ if (def->controllers[i]->info.addr.pci.domain != 0 ||
+ def->controllers[i]->info.addr.pci.bus != 0 ||
+ def->controllers[i]->info.addr.pci.slot != 0x1F ||
+ def->controllers[i]->info.addr.pci.function != 2) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Primary SATA controller must have PCI address 0:0:1f.2"));
+ goto error;
+ }
+ } else {
+ def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ def->controllers[i]->info.addr.pci.domain = 0;
+ def->controllers[i]->info.addr.pci.bus = 0;
+ def->controllers[i]->info.addr.pci.slot = 0x1F;
+ def->controllers[i]->info.addr.pci.function = 2;
+ }
+ }
+ }
+
+ /* Reserve slot 0x1F function 0 (ISA bridge, not in config model)
+ * and function 3 (SMBus, also not (yet) in config model). As with
+ * the SATA controller, these devices are always present in a q35
+ * machine; there is no way to not have them.
+ */
+ if (addrs->nbuses) {
+ memset(&tmp_addr, 0, sizeof(tmp_addr));
+ tmp_addr.slot = 0x1F;
+ tmp_addr.function = 0;
+ tmp_addr.multi = 1;
+ if (qemuDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags,
+ false, false) < 0)
+ goto error;
+ tmp_addr.function = 3;
+ tmp_addr.multi = 0;
+ if (qemuDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags,
+ false, false) < 0)
+ goto error;
+ }
+
+ if (def->nvideos > 0) {
+ /* NB: unlike the pc machinetypes, on q35 machinetypes the
+ * integrated devices are at slot 0x1f, so when qemu looks for
+ * the first free lot for the first VGA, it will always be at
+ * slot 1 (which was used up by the integrated PIIX3 devices
+ * on pc machinetypes).
+ */
+ virDomainVideoDefPtr primaryVideo = def->videos[0];
+ if (primaryVideo->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ primaryVideo->info.addr.pci.domain = 0;
+ primaryVideo->info.addr.pci.bus = 0;
+ primaryVideo->info.addr.pci.slot = 1;
+ primaryVideo->info.addr.pci.function = 0;
+ addrptr = &primaryVideo->info.addr.pci;
+
+ if (!qemuDomainPCIAddressValidate(addrs, addrptr, flags))
+ goto error;
+
+ if (qemuDomainPCIAddressSlotInUse(addrs, addrptr)) {
+ if (qemuDeviceVideoUsable) {
+ virResetLastError();
+ if (qemuDomainPCIAddressReserveNextSlot(addrs,
+ &primaryVideo->info,
+ flags) < 0)
+ goto error;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("PCI address 0:0:1.0 is in use, "
+ "QEMU needs it for primary video"));
+ goto error;
+ }
+ } else if (qemuDomainPCIAddressReserveSlot(addrs, addrptr, flags) < 0) {
+ goto error;
+ }
+ } else if (!qemuDeviceVideoUsable) {
+ if (primaryVideo->info.addr.pci.domain != 0 ||
+ primaryVideo->info.addr.pci.bus != 0 ||
+ primaryVideo->info.addr.pci.slot != 1 ||
+ primaryVideo->info.addr.pci.function != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Primary video card must have PCI address 0:0:1.0"));
+ goto error;
+ }
+ /* If TYPE==PCI, then qemuCollectPCIAddress() function
+ * has already reserved the address, so we must skip */
+ }
+ } else if (addrs->nbuses && !qemuDeviceVideoUsable) {
+ memset(&tmp_addr, 0, sizeof(tmp_addr));
+ tmp_addr.slot = 1;
+
+ if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
+ VIR_DEBUG("PCI address 0:0:1.0 in use, future addition of a video"
+ " device will not be possible without manual"
+ " intervention");
+ virResetLastError();
+ } else if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) {
+ goto error;
+ }
+ }
+ return 0;
+
+error:
+ return -1;
+}
+
+
/*
* This assigns static PCI slots to all configured devices.
* The ordering here is chosen to match the ordering used
@@ -2368,6 +2516,11 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
goto error;
}
+ if (qemuDomainMachineIsQ35(def) &&
+ qemuDomainValidateDevicePCISlotsQ35(def, qemuCaps, addrs) < 0) {
+ goto error;
+ }
+
/* PCI controllers */
for (i = 0; i < def->ncontrollers; i++) {
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
@@ -7679,6 +7832,9 @@ qemuBuildCommandLine(virConnectPtr conn,
_("SATA is not supported with this "
"QEMU binary"));
goto error;
+ } else if (cont->idx == 0 && qemuDomainMachineIsQ35(def)) {
+ /* first SATA controller on Q35 machines is implicit */
+ continue;
} else {
char *devstr;
@@ -7692,6 +7848,7 @@ qemuBuildCommandLine(virConnectPtr conn,
}
} else if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
cont->model == -1 &&
+ !qemuDomainMachineIsQ35(def) &&
(!virQEMUCapsGet(qemuCaps, QEMU_CAPS_PIIX3_USB_UHCI) ||
def->os.arch == VIR_ARCH_PPC64)) {
if (usblegacy) {
@@ -7716,7 +7873,7 @@ qemuBuildCommandLine(virConnectPtr conn,
}
}
- if (usbcontroller == 0)
+ if (usbcontroller == 0 && !qemuDomainMachineIsQ35(def))
virCommandAddArg(cmd, "-usb");
for (i = 0; i < def->nhubs; i++) {
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 206d471287..d0f09ae6ad 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -700,6 +700,7 @@ qemuDomainDefPostParse(virDomainDefPtr def,
void *opaque ATTRIBUTE_UNUSED)
{
bool addDefaultUSB = true;
+ bool addImplicitSATA = false;
bool addPCIRoot = false;
bool addPCIeRoot = false;
@@ -722,6 +723,7 @@ qemuDomainDefPostParse(virDomainDefPtr def,
STREQ(def->os.machine, "q35")) {
addPCIeRoot = true;
addDefaultUSB = false;
+ addImplicitSATA = true;
break;
}
if (!STRPREFIX(def->os.machine, "pc-0.") &&
@@ -754,6 +756,11 @@ qemuDomainDefPostParse(virDomainDefPtr def,
def, VIR_DOMAIN_CONTROLLER_TYPE_USB, 0, -1) < 0)
return -1;
+ if (addImplicitSATA &&
+ virDomainDefMaybeAddController(
+ def, VIR_DOMAIN_CONTROLLER_TYPE_SATA, 0, -1) < 0)
+ return -1;
+
if (addPCIRoot &&
virDomainDefMaybeAddController(
def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args
index 23db85cbef..cecef7b5ad 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.args
@@ -1,5 +1,5 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/libexec/qemu-kvm \
-S -M q35 -m 2048 -smp 2 -nographic -nodefaults \
-monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \
--device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x1 \
--device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1 -usb
+-device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x2 \
+-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.xml b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.xml
index 1aa54558de..d7fb90cde7 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-pcie-root.xml
@@ -15,7 +15,6 @@
/usr/libexec/qemu-kvm
-
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35.args b/tests/qemuxml2argvdata/qemuxml2argv-q35.args
index ddff6f0d9e..6c24407a65 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-q35.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-q35.args
@@ -1,7 +1,6 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
/usr/libexec/qemu-kvm -S -M q35 -m 2048 -smp 2 -nographic -nodefaults \
-monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c \
--device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x1 \
+-device i82801b11-bridge,id=pci.1,bus=pci.0,addr=0x2 \
-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x1 \
--usb \
-vga qxl -global qxl.ram_size=67108864 -global qxl.vram_size=18874368
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index aba0f88b66..0068d27ed2 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -995,11 +995,13 @@ mymain(void)
DO_TEST("pci-bridge-many-disks",
QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE_PCI_BRIDGE);
DO_TEST("pcie-root",
+ QEMU_CAPS_ICH9_AHCI,
QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE);
DO_TEST("q35",
QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE,
+ QEMU_CAPS_ICH9_AHCI,
QEMU_CAPS_VGA, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
QEMU_CAPS_VGA, QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL);
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml
index 25c77f1443..f10e85b2f2 100644
--- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pcie-root.xml
@@ -15,7 +15,7 @@
/usr/libexec/qemu-kvm
-
+
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml
new file mode 100644
index 0000000000..2a86e61f57
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml
@@ -0,0 +1,26 @@
+
+ q35-test
+ 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774
+ 2097152
+ 2097152
+ 2
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/libexec/qemu-kvm
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 8b4590af28..5c6730d25e 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -295,7 +295,7 @@ mymain(void)
DO_TEST_DIFFERENT("pci-autoadd-addr");
DO_TEST_DIFFERENT("pci-autoadd-idx");
DO_TEST_DIFFERENT("pcie-root");
- DO_TEST("q35");
+ DO_TEST_DIFFERENT("q35");
DO_TEST("hostdev-scsi-lsi");
DO_TEST("hostdev-scsi-virtio-scsi");