qemuBuildCpuModelArgStr(virQEMUDriverPtr driver,
const virDomainDef *def,
virBufferPtr buf,
- virQEMUCapsPtr qemuCaps,
- bool *hasHwVirt,
- bool migrating)
+ virQEMUCapsPtr qemuCaps)
{
int ret = -1;
size_t i;
- virCPUDefPtr host = NULL;
- virCPUDefPtr guest = NULL;
- virCPUDefPtr cpu = NULL;
- virCPUDefPtr featCpu = NULL;
- size_t ncpus = 0;
- char **cpus = NULL;
- virCPUDataPtr data = NULL;
- const char *preferred;
virCapsPtr caps = NULL;
- bool compareAgainstHost = ((def->virtType == VIR_DOMAIN_VIRT_KVM ||
- def->cpu->mode != VIR_CPU_MODE_CUSTOM) &&
- def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH);
+ virCPUDefPtr cpu = def->cpu;
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
goto cleanup;
- host = caps->host.cpu;
-
- if (!(cpu = virCPUDefCopy(def->cpu)))
- goto cleanup;
-
- if (cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
- !migrating &&
- virCPUUpdate(def->os.arch, cpu, host) < 0)
- goto cleanup;
-
- if (compareAgainstHost &&
- cpuGuestData(host, cpu, &data, NULL) == VIR_CPU_COMPARE_ERROR)
- goto cleanup;
-
- /* Only 'svm' requires --enable-nesting. The nested
- * 'vmx' patches now simply hook off the CPU features
- */
- if ((def->os.arch == VIR_ARCH_X86_64 || def->os.arch == VIR_ARCH_I686) &&
- compareAgainstHost) {
- int hasSVM = virCPUDataCheckFeature(data, "svm");
- if (hasSVM < 0)
- goto cleanup;
- *hasHwVirt = hasSVM > 0 ? true : false;
- }
-
- if ((cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) ||
- ((cpu->mode == VIR_CPU_MODE_HOST_MODEL) &&
- ARCH_IS_PPC64(def->os.arch))) {
- if (def->virtType != VIR_DOMAIN_VIRT_KVM) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("CPU mode '%s' is only supported with kvm"),
- virCPUModeTypeToString(cpu->mode));
- goto cleanup;
- }
+ switch ((virCPUMode) cpu->mode) {
+ case VIR_CPU_MODE_HOST_PASSTHROUGH:
virBufferAddLit(buf, "host");
if (def->os.arch == VIR_ARCH_ARMV7L &&
"aarch64 host"));
goto cleanup;
}
-
virBufferAddLit(buf, ",aarch64=off");
}
+ break;
- if (ARCH_IS_PPC64(def->os.arch) &&
- cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
- def->cpu->model != NULL) {
- virBufferAsprintf(buf, ",compat=%s", def->cpu->model);
+ case VIR_CPU_MODE_HOST_MODEL:
+ if (ARCH_IS_PPC64(def->os.arch)) {
+ virBufferAddLit(buf, "host");
+ if (cpu->model)
+ virBufferAsprintf(buf, ",compat=%s", cpu->model);
} else {
- featCpu = cpu;
- }
- } else {
- if (VIR_ALLOC(guest) < 0)
- goto cleanup;
- if (VIR_STRDUP(guest->vendor_id, cpu->vendor_id) < 0)
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected host-model CPU for %s architecture"),
+ virArchToString(def->os.arch));
goto cleanup;
+ }
+ break;
- if (compareAgainstHost) {
- guest->arch = host->arch;
- if (cpu->match == VIR_CPU_MATCH_MINIMUM)
- preferred = host->model;
- else
- preferred = cpu->model;
+ case VIR_CPU_MODE_CUSTOM:
+ virBufferAdd(buf, cpu->model, -1);
+ break;
- guest->type = VIR_CPU_TYPE_GUEST;
- guest->fallback = cpu->fallback;
+ case VIR_CPU_MODE_LAST:
+ break;
+ }
- if (virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus, &ncpus) < 0)
- goto cleanup;
+ if (cpu->vendor_id)
+ virBufferAsprintf(buf, ",vendor=%s", cpu->vendor_id);
- if (cpuDecode(guest, data,
- (const char **)cpus, ncpus, preferred) < 0)
- goto cleanup;
- } else {
- guest->arch = def->os.arch;
- if (VIR_STRDUP(guest->model, cpu->model) < 0)
- goto cleanup;
- }
- virBufferAdd(buf, guest->model, -1);
- if (guest->vendor_id)
- virBufferAsprintf(buf, ",vendor=%s", guest->vendor_id);
- featCpu = guest;
- }
+ for (i = 0; i < cpu->nfeatures; i++) {
+ switch ((virCPUFeaturePolicy) cpu->features[i].policy) {
+ case VIR_CPU_FEATURE_FORCE:
+ case VIR_CPU_FEATURE_REQUIRE:
+ virBufferAsprintf(buf, ",+%s", cpu->features[i].name);
+ break;
- if (featCpu) {
- for (i = 0; i < featCpu->nfeatures; i++) {
- char sign;
- if (featCpu->features[i].policy == VIR_CPU_FEATURE_DISABLE)
- sign = '-';
- else
- sign = '+';
+ case VIR_CPU_FEATURE_DISABLE:
+ case VIR_CPU_FEATURE_FORBID:
+ virBufferAsprintf(buf, ",-%s", cpu->features[i].name);
+ break;
- virBufferAsprintf(buf, ",%c%s", sign, featCpu->features[i].name);
+ case VIR_CPU_FEATURE_OPTIONAL:
+ case VIR_CPU_FEATURE_LAST:
+ break;
}
}
ret = 0;
cleanup:
virObjectUnref(caps);
- cpuDataFree(data);
- virCPUDefFree(guest);
- virCPUDefFree(cpu);
- virStringFreeListCount(cpus, ncpus);
return ret;
}
qemuBuildCpuCommandLine(virCommandPtr cmd,
virQEMUDriverPtr driver,
const virDomainDef *def,
- virQEMUCapsPtr qemuCaps,
- bool migrating)
+ virQEMUCapsPtr qemuCaps)
{
virArch hostarch = virArchFromHost();
char *cpu = NULL;
if (def->cpu &&
(def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) {
- if (qemuBuildCpuModelArgStr(driver, def, &buf, qemuCaps,
- &hasHwVirt, migrating) < 0)
+ if (qemuBuildCpuModelArgStr(driver, def, &buf, qemuCaps) < 0)
goto cleanup;
have_cpu = true;
+
+ /* Only 'svm' requires --enable-nesting. The nested 'vmx' patches now
+ * simply hook off the CPU features. */
+ if (ARCH_IS_X86(def->os.arch) &&
+ def->virtType == VIR_DOMAIN_VIRT_KVM) {
+ virCPUDefPtr cpuDef = NULL;
+
+ if (def->cpu->mode == VIR_CPU_MODE_CUSTOM)
+ cpuDef = def->cpu;
+ else if (def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH)
+ cpuDef = virQEMUCapsGetHostModel(qemuCaps);
+
+ if (cpuDef) {
+ int svm = virCPUCheckFeature(def->os.arch, cpuDef, "svm");
+ if (svm < 0)
+ goto cleanup;
+ hasHwVirt = svm > 0;
+ }
+ }
} else {
/*
* Need to force a 32-bit guest CPU type if
if (qemuBuildMachineCommandLine(cmd, cfg, def, qemuCaps) < 0)
goto error;
- if (qemuBuildCpuCommandLine(cmd, driver, def, qemuCaps, !!migrateURI) < 0)
+ if (qemuBuildCpuCommandLine(cmd, driver, def, qemuCaps) < 0)
goto error;
if (qemuBuildDomainLoaderCommandLine(cmd, def, qemuCaps) < 0)
/* Update guest CPU requirements according to host CPU */
if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) &&
def->cpu &&
- (def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) {
- if (!caps->host.cpu ||
- !caps->host.cpu->model) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("cannot get host CPU capabilities"));
- goto cleanup;
- }
-
+ (def->cpu->mode != VIR_CPU_MODE_CUSTOM ||
+ def->cpu->model)) {
if (virCPUUpdate(def->os.arch, def->cpu, caps->host.cpu) < 0)
goto cleanup;
}
{
virDomainDefPtr def;
- if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef)
+ if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef) {
def = vm->newDef;
- else
+ } else {
def = vm->def;
+ if (virDomainObjIsActive(vm))
+ flags &= ~VIR_DOMAIN_XML_UPDATE_CPU;
+ }
return qemuDomainDefFormatXML(driver, def, flags);
}
}
}
- if (qemuProcessStartValidateGuestCPU(vm, qemuCaps, caps, flags) < 0)
- return -1;
-
return 0;
}
}
-static int
-qemuProcessStartValidateGuestCPU(virDomainObjPtr vm,
- virQEMUCapsPtr qemuCaps,
- virCapsPtr caps,
- unsigned int flags)
-{
- int ret = -1;
- virCPUDefPtr host = NULL;
- virCPUDefPtr cpu = NULL;
- size_t ncpus = 0;
- char **cpus = NULL;
- bool noTSX = false;
- virCPUCompareResult cmp;
- virCPUDataPtr data = NULL;
- virCPUDataPtr hostData = NULL;
- char *compare_msg = NULL;
-
- if (!vm->def->cpu ||
- (vm->def->cpu->mode == VIR_CPU_MODE_CUSTOM &&
- !vm->def->cpu->model))
- return 0;
-
- if ((vm->def->virtType != VIR_DOMAIN_VIRT_KVM &&
- vm->def->cpu->mode == VIR_CPU_MODE_CUSTOM) ||
- vm->def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH)
- return 0;
-
- host = caps->host.cpu;
-
- if (virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus, &ncpus) < 0)
- goto cleanup;
-
- if (!host || !host->model || ncpus == 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("CPU specification not supported by hypervisor"));
- goto cleanup;
- }
-
- if (!(cpu = virCPUDefCopy(vm->def->cpu)))
- goto cleanup;
-
- if (cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
- flags & VIR_QEMU_PROCESS_START_NEW &&
- virCPUUpdate(vm->def->os.arch, cpu, host) < 0)
- goto cleanup;
-
- cmp = cpuGuestData(host, cpu, &data, &compare_msg);
- switch (cmp) {
- case VIR_CPU_COMPARE_INCOMPATIBLE:
- if (cpuEncode(host->arch, host, NULL, &hostData,
- NULL, NULL, NULL, NULL) == 0 &&
- (!virCPUDataCheckFeature(hostData, "hle") ||
- !virCPUDataCheckFeature(hostData, "rtm")) &&
- (STREQ_NULLABLE(cpu->model, "Haswell") ||
- STREQ_NULLABLE(cpu->model, "Broadwell")))
- noTSX = true;
-
- if (compare_msg) {
- if (noTSX) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("guest and host CPU are not compatible: "
- "%s; try using '%s-noTSX' CPU model"),
- compare_msg, cpu->model);
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("guest and host CPU are not compatible: "
- "%s"),
- compare_msg);
- }
- } else {
- if (noTSX) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("guest CPU is not compatible with host "
- "CPU; try using '%s-noTSX' CPU model"),
- cpu->model);
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("guest CPU is not compatible with host "
- "CPU"));
- }
- }
- /* fall through */
- case VIR_CPU_COMPARE_ERROR:
- goto cleanup;
-
- default:
- break;
- }
-
- ret = 0;
-
- cleanup:
- VIR_FREE(compare_msg);
- cpuDataFree(data);
- cpuDataFree(hostData);
- virCPUDefFree(cpu);
- virStringFreeListCount(cpus, ncpus);
- return ret;
-}
-
-
/**
* qemuProcessStartValidate:
* @vm: domain object
}
+static int
+qemuProcessUpdateGuestCPU(virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ virCapsPtr caps,
+ unsigned int flags)
+{
+ int ret = -1;
+ size_t nmodels = 0;
+ char **models = NULL;
+
+ if (!def->cpu)
+ return 0;
+
+ /* nothing to do if only topology part of CPU def is used */
+ if (def->cpu->mode == VIR_CPU_MODE_CUSTOM && !def->cpu->model)
+ return 0;
+
+ /* Old libvirt added host CPU model to host-model CPUs for migrations,
+ * while new libvirt just turns host-model into custom mode. We need
+ * to fix the mode to maintain backward compatibility and to avoid
+ * the CPU model to be replaced in virCPUUpdate.
+ */
+ if (!(flags & VIR_QEMU_PROCESS_START_NEW) &&
+ ARCH_IS_X86(def->os.arch) &&
+ def->cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
+ def->cpu->model) {
+ def->cpu->mode = VIR_CPU_MODE_CUSTOM;
+ }
+
+ if (!virQEMUCapsIsCPUModeSupported(qemuCaps, caps, def->virtType,
+ def->cpu->mode)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("CPU mode '%s' for %s %s domain on %s host is not "
+ "supported by hypervisor"),
+ virCPUModeTypeToString(def->cpu->mode),
+ virArchToString(def->os.arch),
+ virDomainVirtTypeToString(def->virtType),
+ virArchToString(caps->host.arch));
+ return -1;
+ }
+
+ /* nothing to update for host-passthrough */
+ if (def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH)
+ return 0;
+
+ /* custom CPUs in TCG mode don't need to be compared to host CPU */
+ if (def->virtType != VIR_DOMAIN_VIRT_QEMU ||
+ def->cpu->mode != VIR_CPU_MODE_CUSTOM) {
+ if (virCPUCompare(caps->host.arch, virQEMUCapsGetHostModel(qemuCaps),
+ def->cpu, true) < 0)
+ return -1;
+ }
+
+ if (virCPUUpdate(def->os.arch, def->cpu,
+ virQEMUCapsGetHostModel(qemuCaps)) < 0)
+ goto cleanup;
+
+ if (virQEMUCapsGetCPUDefinitions(qemuCaps, &models, &nmodels) < 0 ||
+ virCPUTranslate(def->os.arch, def->cpu, models, nmodels) < 0)
+ goto cleanup;
+
+ def->cpu->fallback = VIR_CPU_FALLBACK_FORBID;
+ ret = 0;
+
+ cleanup:
+ virStringFreeListCount(models, nmodels);
+ return ret;
+}
+
+
/**
* qemuProcessPrepareDomain
*
priv->monStart = 0;
priv->gotShutdown = false;
+ VIR_DEBUG("Updating guest CPU definition");
+ if (qemuProcessUpdateGuestCPU(vm->def, priv->qemuCaps, caps, flags) < 0)
+ goto cleanup;
+
ret = 0;
cleanup:
VIR_FREE(nodeset);
-name QEMUGuest1 \
-S \
-M pc \
--cpu Haswell \
+-cpu Haswell,+rtm,+hle \
-m 214 \
-smp 6,sockets=6,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-name QEMUGuest1 \
-S \
-M pc \
--cpu core2duo,+ds,+ht,+tm,+ds_cpl,+xtpr,+3dnowext,+lahf_lm,-nx \
+-cpu core2duo,+ds,+ht,+tm,+ds_cpl,+xtpr,+3dnowext,+lahf_lm,-nx,-cx16,-tm2,-pbe,\
+-ss,-sse4a,-wdt \
-m 214 \
-smp 6,sockets=6,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-name QEMUGuest1 \
-S \
-M pc \
--cpu core2duo,+ds,+ht,+tm,+ds_cpl,+xtpr,+3dnowext,+lahf_lm,-nx \
+-cpu core2duo,+ds,+ht,+tm,+ds_cpl,+xtpr,+3dnowext,+lahf_lm,-nx,-cx16,-tm2,-pbe,\
+-ss,-sse4a,-wdt \
-m 214 \
-smp 6,sockets=6,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-name QEMUGuest1 \
-S \
-M pc \
--cpu Penryn,-sse4.1 \
+-cpu Penryn,-sse4.1,-sse4.2,-popcnt,-aes \
-m 214 \
-smp 6,sockets=6,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-S \
-M pc \
-cpu Haswell,+vme,+ds,+acpi,+ss,+ht,+tm,+pbe,+dtes64,+monitor,+ds_cpl,+vmx,\
-+smx,+est,+tm2,+xtpr,+pdcm,+osxsave,+f16c,+rdrand,+pdpe1gb,+abm \
++smx,+est,+tm2,+xtpr,+pdcm,+osxsave,+f16c,+rdrand,+pdpe1gb,+abm,+lahf_lm \
-m 214 \
-smp 6,sockets=6,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-S \
-M pc \
-cpu Penryn,+vme,+ds,+acpi,+ss,+ht,+tm,+pbe,+monitor,+ds_cpl,+vmx,+est,+tm2,\
-+xtpr,-sse4.1 \
++xtpr,-sse4.1,+cx16,+lahf_lm \
-m 214 \
-smp 6,sockets=6,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-S \
-M pc \
-cpu core2duo,+ds,+acpi,+ss,+ht,+tm,+pbe,+ds_cpl,+vmx,+est,+tm2,+cx16,+xtpr,\
-+lahf_lm,-syscall,-nx,-lm \
++lahf_lm,-syscall,-nx,-lm,-svm \
-m 214 \
-smp 6,sockets=6,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-name QEMUGuest1 \
-S \
-M pc \
--cpu core2duo,+ds,+acpi,+ht,+tm,+ds_cpl,+vmx,+est,+xtpr,+3dnowext,+lahf_lm,-nx \
+-cpu core2duo,+ds,+acpi,+ht,+tm,+ds_cpl,+vmx,+est,+xtpr,+3dnowext,+lahf_lm,-nx,\
+-cx16,-tm2,-pbe,-ss,-sse4a,-wdt \
-m 214 \
-smp 6,sockets=6,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \