virCPUDefFree;
virCPUDefFreeModel;
virCPUDefParseXML;
+virCPUModeTypeToString;
# datatypes.h
"no-acpi",
"fsdev-readonly",
- "virtio-blk-pci.scsi",
+ "virtio-blk-pci.scsi", /* 80 */
"blk-sg-io",
"drive-copy-on-read",
+ "cpu-host",
);
struct qemu_feature_flags {
*/
if (version >= 12000)
qemuCapsSet(flags, QEMU_CAPS_PCI_ROMBAR);
+
+ if (version >= 11000)
+ qemuCapsSet(flags, QEMU_CAPS_CPU_HOST);
}
/* We parse the output of 'qemu -help' to get the QEMU
QEMU_CAPS_VIRTIO_BLK_SCSI = 80, /* virtio-blk-pci.scsi */
QEMU_CAPS_VIRTIO_BLK_SG_IO = 81, /* support for SG_IO commands, reportedly added in 0.11 */
QEMU_CAPS_DRIVE_COPY_ON_READ = 82, /* -drive copy-on-read */
+ QEMU_CAPS_CPU_HOST = 83, /* support for -cpu host */
QEMU_CAPS_LAST, /* this must always be the last item */
};
virBitmapPtr qemuCaps,
const struct utsname *ut,
char **opt,
- bool *hasHwVirt)
+ bool *hasHwVirt,
+ bool migrating)
{
const virCPUDefPtr host = driver->caps->host.cpu;
virCPUDefPtr guest = NULL;
+ virCPUDefPtr cpu = NULL;
unsigned int ncpus = 0;
const char **cpus = NULL;
union cpuData *data = NULL;
*hasHwVirt = false;
- if (def->cpu && def->cpu->model) {
+ if (def->cpu &&
+ (def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) {
+ if (!(cpu = virCPUDefCopy(def->cpu)))
+ goto cleanup;
+ if (cpu->mode != VIR_CPU_MODE_CUSTOM &&
+ !migrating &&
+ cpuUpdate(cpu, host) < 0)
+ goto cleanup;
+ }
+
+ if (cpu) {
+ virCPUCompareResult cmp;
+ const char *preferred;
+ int hasSVM;
+
if (host &&
qemuCapsProbeCPUModels(emulator, qemuCaps, host->arch,
&ncpus, &cpus) < 0)
_("CPU specification not supported by hypervisor"));
goto cleanup;
}
- }
- if (ncpus > 0 && host) {
- virCPUCompareResult cmp;
- const char *preferred;
- int hasSVM;
-
- cmp = cpuGuestData(host, def->cpu, &data);
+ cmp = cpuGuestData(host, cpu, &data);
switch (cmp) {
case VIR_CPU_COMPARE_INCOMPATIBLE:
- qemuReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("guest CPU is not compatible with host CPU"));
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest CPU is not compatible with host CPU"));
/* fall through */
case VIR_CPU_COMPARE_ERROR:
goto cleanup;
break;
}
- if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(host->arch)))
- goto no_memory;
-
- if (def->cpu->match == VIR_CPU_MATCH_MINIMUM)
- preferred = host->model;
- else
- preferred = def->cpu->model;
-
- guest->type = VIR_CPU_TYPE_GUEST;
- guest->fallback = def->cpu->fallback;
- if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
- goto cleanup;
-
/* Only 'svm' requires --enable-nesting. The nested
* 'vmx' patches now simply hook off the CPU features
*/
- hasSVM = cpuHasFeature(guest->arch, data, "svm");
+ hasSVM = cpuHasFeature(host->arch, data, "svm");
if (hasSVM < 0)
goto cleanup;
*hasHwVirt = hasSVM > 0 ? true : false;
- virBufferAdd(&buf, guest->model, -1);
- for (i = 0; i < guest->nfeatures; i++) {
- char sign;
- if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE)
- sign = '-';
+ if (cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) {
+ const char *mode = virCPUModeTypeToString(cpu->mode);
+ if (!qemuCapsGet(qemuCaps, QEMU_CAPS_CPU_HOST)) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("CPU mode '%s' is not supported by QEMU"
+ " binary"), mode);
+ goto cleanup;
+ }
+ if (def->virtType != VIR_DOMAIN_VIRT_KVM) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("CPU mode '%s' is only supported with kvm"),
+ mode);
+ goto cleanup;
+ }
+ virBufferAddLit(&buf, "host");
+ } else {
+ if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(host->arch)))
+ goto no_memory;
+
+ if (cpu->match == VIR_CPU_MATCH_MINIMUM)
+ preferred = host->model;
else
- sign = '+';
+ preferred = cpu->model;
- virBufferAsprintf(&buf, ",%c%s", sign, guest->features[i].name);
+ guest->type = VIR_CPU_TYPE_GUEST;
+ guest->fallback = cpu->fallback;
+ if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
+ goto cleanup;
+
+ virBufferAdd(&buf, guest->model, -1);
+ for (i = 0; i < guest->nfeatures; i++) {
+ char sign;
+ if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE)
+ sign = '-';
+ else
+ sign = '+';
+
+ virBufferAsprintf(&buf, ",%c%s", sign, guest->features[i].name);
+ }
}
- }
- else {
+ } else {
/*
* Need to force a 32-bit guest CPU type if
*
if (guest)
cpuDataFree(guest->arch, data);
virCPUDefFree(guest);
+ virCPUDefFree(cpu);
if (cpus) {
for (i = 0; i < ncpus; i++)
virCommandAddArgList(cmd, "-M", def->os.machine, NULL);
if (qemuBuildCpuArgStr(driver, def, emulator, qemuCaps,
- &ut, &cpu, &hasHwVirt) < 0)
+ &ut, &cpu, &hasHwVirt, !!migrateFrom) < 0)
goto error;
if (cpu) {
QEMU_CAPS_NO_SHUTDOWN,
QEMU_CAPS_PCI_ROMBAR,
QEMU_CAPS_NO_ACPI,
- QEMU_CAPS_VIRTIO_BLK_SG_IO);
+ QEMU_CAPS_VIRTIO_BLK_SG_IO,
+ QEMU_CAPS_CPU_HOST);
DO_TEST("qemu-kvm-0.12.1.2-rhel60", 12001, 1, 0,
QEMU_CAPS_VNC_COLON,
QEMU_CAPS_NO_REBOOT,
QEMU_CAPS_NO_SHUTDOWN,
QEMU_CAPS_PCI_ROMBAR,
QEMU_CAPS_NO_ACPI,
- QEMU_CAPS_VIRTIO_BLK_SG_IO);
+ QEMU_CAPS_VIRTIO_BLK_SG_IO,
+ QEMU_CAPS_CPU_HOST);
DO_TEST("qemu-kvm-0.12.3", 12003, 1, 0,
QEMU_CAPS_VNC_COLON,
QEMU_CAPS_NO_REBOOT,
QEMU_CAPS_NO_SHUTDOWN,
QEMU_CAPS_PCI_ROMBAR,
QEMU_CAPS_NO_ACPI,
- QEMU_CAPS_VIRTIO_BLK_SG_IO);
+ QEMU_CAPS_VIRTIO_BLK_SG_IO,
+ QEMU_CAPS_CPU_HOST);
DO_TEST("qemu-kvm-0.13.0", 13000, 1, 0,
QEMU_CAPS_VNC_COLON,
QEMU_CAPS_NO_REBOOT,
QEMU_CAPS_NO_SHUTDOWN,
QEMU_CAPS_PCI_ROMBAR,
QEMU_CAPS_NO_ACPI,
- QEMU_CAPS_VIRTIO_BLK_SG_IO);
+ QEMU_CAPS_VIRTIO_BLK_SG_IO,
+ QEMU_CAPS_CPU_HOST);
DO_TEST("qemu-kvm-0.12.1.2-rhel61", 12001, 1, 0,
QEMU_CAPS_VNC_COLON,
QEMU_CAPS_NO_REBOOT,
QEMU_CAPS_PCI_ROMBAR,
QEMU_CAPS_NO_ACPI,
QEMU_CAPS_VIRTIO_BLK_SCSI,
- QEMU_CAPS_VIRTIO_BLK_SG_IO);
+ QEMU_CAPS_VIRTIO_BLK_SG_IO,
+ QEMU_CAPS_CPU_HOST);
DO_TEST("qemu-kvm-0.12.1.2-rhel62-beta", 12001, 1, 0,
QEMU_CAPS_VNC_COLON,
QEMU_CAPS_NO_REBOOT,
QEMU_CAPS_NO_ACPI,
QEMU_CAPS_VIRTIO_BLK_SCSI,
QEMU_CAPS_VIRTIO_BLK_SG_IO,
- QEMU_CAPS_DRIVE_COPY_ON_READ);
+ QEMU_CAPS_DRIVE_COPY_ON_READ,
+ QEMU_CAPS_CPU_HOST);
DO_TEST("qemu-1.0", 1000000, 0, 0,
QEMU_CAPS_VNC_COLON,
QEMU_CAPS_NO_REBOOT,
QEMU_CAPS_NO_ACPI,
QEMU_CAPS_FSDEV_READONLY,
QEMU_CAPS_VIRTIO_BLK_SCSI,
- QEMU_CAPS_VIRTIO_BLK_SG_IO);
+ QEMU_CAPS_VIRTIO_BLK_SG_IO,
+ QEMU_CAPS_CPU_HOST);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--- /dev/null
+candidates="/usr/bin/qemu-kvm
+ /usr/libexec/qemu-kvm
+ /usr/bin/qemu-system-x86_64
+ /usr/bin/qemu"
+qemu=
+for candidate in $candidates; do
+ if test -x $candidate; then
+ qemu=$candidate
+ break
+ fi
+done
+
+real_qemu()
+{
+ if test x$qemu != x; then
+ exec $qemu "$@"
+ else
+ return 1
+ fi
+}
+
+faked_machine()
+{
+ echo "pc"
+}
+
+faked_cpu()
+{
+ cat <<EOF
+x86 Opteron_G3
+x86 Opteron_G2
+x86 Opteron_G1
+x86 Nehalem
+x86 Penryn
+x86 Conroe
+x86 [n270]
+x86 [athlon]
+x86 [pentium3]
+x86 [pentium2]
+x86 [pentium]
+x86 [486]
+x86 [coreduo]
+x86 [qemu32]
+x86 [kvm64]
+x86 [core2duo]
+x86 [phenom]
+x86 [qemu64]
+x86 [host]
+EOF
+}
--- /dev/null
+#! /bin/sh
+
+. $(dirname $0)/qemu-lib.sh
+
+case $* in
+"-M ?")
+ faked_machine
+ ;;
+"-cpu ?")
+ faked_cpu | grep -Fv '['
+ ;;
+*)
+ real_qemu "$@"
+ ;;
+esac
#! /bin/sh
-candidates="/usr/bin/qemu-kvm
- /usr/libexec/qemu-kvm
- /usr/bin/qemu-system-x86_64
- /usr/bin/qemu"
-qemu=
-for candidate in $candidates; do
- if test -x $candidate; then
- qemu=$candidate
- break
- fi
-done
-
-real_qemu()
-{
- if test x$qemu != x; then
- exec $qemu "$@"
- else
- return 1
- fi
-}
-
-faked_machine()
-{
- echo "pc"
-}
-
-faked_cpu()
-{
- cat <<EOF
-x86 Opteron_G3
-x86 Opteron_G2
-x86 Opteron_G1
-x86 Nehalem
-x86 Penryn
-x86 Conroe
-x86 [n270]
-x86 [athlon]
-x86 [pentium3]
-x86 [pentium2]
-x86 [pentium]
-x86 [486]
-x86 [coreduo]
-x86 [qemu32]
-x86 [kvm64]
-x86 [core2duo]
-x86 [phenom]
-x86 [qemu64]
-x86 [host]
-EOF
-}
+. $(dirname $0)/qemu-lib.sh
case $* in
"-M ?")
--- /dev/null
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+./qemu-supported-cpus.sh \
+-S \
+-M pc \
+-cpu Penryn,+xtpr,+tm2,+est,+vmx,+ds_cpl,+monitor,+pbe,+tm,+ht,+ss,+acpi,+ds,+vme,-sse4.1 \
+-m 214 \
+-smp 6 \
+-nographic \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-boot n \
+-net none \
+-serial none \
+-parallel none \
+-usb
--- /dev/null
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>6</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='network'/>
+ </os>
+ <cpu mode='host-model'/>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/./qemu-supported-cpus.sh</emulator>
+ </devices>
+</domain>
--- /dev/null
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>6</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='network'/>
+ </os>
+ <cpu mode='host-model'>
+ <model fallback='forbid'/>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/./qemu-supported-cpus.sh</emulator>
+ </devices>
+</domain>
--- /dev/null
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+./qemu.sh \
+-S \
+-M pc \
+-cpu core2duo,+lahf_lm,+xtpr,+cx16,+tm2,+est,+vmx,+ds_cpl,+pbe,+tm,+ht,+ss,+acpi,+ds \
+-m 214 \
+-smp 6 \
+-nographic \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-boot n \
+-net none \
+-serial none \
+-parallel none \
+-usb
--- /dev/null
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>6</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='network'/>
+ </os>
+ <cpu mode='host-model'/>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/./qemu.sh</emulator>
+ </devices>
+</domain>
--- /dev/null
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+./qemu.sh \
+-S \
+-M pc \
+-cpu host \
+-m 214 \
+-smp 6 \
+-nographic \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-boot n \
+-net none \
+-serial none \
+-parallel none \
+-usb
--- /dev/null
+<domain type='kvm'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>6</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='network'/>
+ </os>
+ <cpu mode='host-passthrough'/>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/./qemu.sh</emulator>
+ </devices>
+</domain>
--- /dev/null
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>6</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='network'/>
+ </os>
+ <cpu mode='host-passthrough'/>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/./qemu.sh</emulator>
+ </devices>
+</domain>
DO_TEST("cpu-strict1", false, NONE);
DO_TEST("cpu-numa1", false, NONE);
DO_TEST("cpu-numa2", false, QEMU_CAPS_SMP_TOPOLOGY);
+ DO_TEST("cpu-host-model", false, NONE);
+ DO_TEST("cpu-host-model-fallback", false, NONE);
+ DO_TEST_FAILURE("cpu-host-model-nofallback", NONE);
+ DO_TEST("cpu-host-passthrough", false, QEMU_CAPS_KVM, QEMU_CAPS_CPU_HOST);
+ DO_TEST_FAILURE("cpu-host-passthrough", NONE);
+ DO_TEST_FAILURE("cpu-qemu-host-passthrough",
+ QEMU_CAPS_KVM, QEMU_CAPS_CPU_HOST);
DO_TEST("memtune", false, QEMU_CAPS_NAME);
DO_TEST("blkiotune", false, QEMU_CAPS_NAME);