src/conf/virdomainobjlist.c
src/conf/virsecretobj.c
src/cpu/cpu.c
+src/cpu/cpu_arm.c
src/cpu/cpu_map.c
src/cpu/cpu_ppc64.c
src/cpu/cpu_x86.c
/**
- * cpuUpdate:
+ * virCPUUpdate:
*
- * @guest: guest CPU definition
+ * @arch: CPU architecture
+ * @guest: guest CPU definition to be updated
* @host: host CPU definition
*
* Updates @guest CPU definition according to @host CPU. This is required to
- * support guest CPU definition which are relative to host CPU, such as CPUs
- * with VIR_CPU_MODE_CUSTOM and optional features or VIR_CPU_MATCH_MINIMUM, or
- * CPUs with non-custom mode (VIR_CPU_MODE_HOST_MODEL,
- * VIR_CPU_MODE_HOST_PASSTHROUGH).
+ * support guest CPU definitions specified relatively to host CPU, such as
+ * CPUs with VIR_CPU_MODE_CUSTOM and optional features or
+ * VIR_CPU_MATCH_MINIMUM, or CPUs with VIR_CPU_MODE_HOST_MODEL.
+ * When the guest CPU was not specified relatively, the function does nothing
+ * and returns success.
*
* Returns 0 on success, -1 on error.
*/
int
-cpuUpdate(virCPUDefPtr guest,
- const virCPUDef *host)
+virCPUUpdate(virArch arch,
+ virCPUDefPtr guest,
+ const virCPUDef *host)
{
struct cpuArchDriver *driver;
- VIR_DEBUG("guest=%p, host=%p", guest, host);
+ VIR_DEBUG("arch=%s, guest=%p mode=%s model=%s, host=%p model=%s",
+ virArchToString(arch), guest, virCPUModeTypeToString(guest->mode),
+ NULLSTR(guest->model), host, NULLSTR(host ? host->model : NULL));
- if ((driver = cpuGetSubDriver(host->arch)) == NULL)
+ if (!(driver = cpuGetSubDriver(arch)))
return -1;
- if (driver->update == NULL) {
+ if (guest->mode == VIR_CPU_MODE_HOST_PASSTHROUGH)
+ return 0;
+
+ if (guest->mode == VIR_CPU_MODE_CUSTOM &&
+ guest->match != VIR_CPU_MATCH_MINIMUM) {
+ size_t i;
+ bool optional = false;
+
+ for (i = 0; i < guest->nfeatures; i++) {
+ if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
+ optional = true;
+ break;
+ }
+ }
+
+ if (!optional)
+ return 0;
+ }
+
+ /* We get here if guest CPU is either
+ * - host-model
+ * - custom with minimum match
+ * - custom with optional features
+ */
+ if (!driver->update) {
virReportError(VIR_ERR_NO_SUPPORT,
- _("cannot update guest CPU data for %s architecture"),
- virArchToString(host->arch));
+ _("cannot update guest CPU for %s architecture"),
+ virArchToString(arch));
return -1;
}
- return driver->update(guest, host);
+ if (driver->update(guest, host) < 0)
+ return -1;
+
+ VIR_DEBUG("model=%s", NULLSTR(guest->model));
+ return 0;
}
unsigned int flags);
typedef int
-(*cpuArchUpdate) (virCPUDefPtr guest,
- const virCPUDef *host);
+(*virCPUArchUpdate)(virCPUDefPtr guest,
+ const virCPUDef *host);
typedef int
(*cpuArchHasFeature) (const virCPUData *data,
cpuArchNodeData nodeData;
cpuArchGuestData guestData;
cpuArchBaseline baseline;
- cpuArchUpdate update;
+ virCPUArchUpdate update;
cpuArchHasFeature hasFeature;
cpuArchDataFormat dataFormat;
cpuArchDataParse dataParse;
ATTRIBUTE_NONNULL(1);
int
-cpuUpdate (virCPUDefPtr guest,
+virCPUUpdate(virArch arch,
+ virCPUDefPtr guest,
const virCPUDef *host)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+ ATTRIBUTE_NONNULL(2);
int
cpuHasFeature(const virCPUData *data,
VIR_FREE(data);
}
+
static int
-armUpdate(virCPUDefPtr guest,
- const virCPUDef *host)
+virCPUarmUpdate(virCPUDefPtr guest,
+ const virCPUDef *host)
{
+ int ret = -1;
+ virCPUDefPtr updated = NULL;
+
+ if (guest->mode != VIR_CPU_MODE_HOST_MODEL)
+ return 0;
+
+ if (!host) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("unknown host CPU model"));
+ goto cleanup;
+ }
+
+ if (!(updated = virCPUDefCopyWithoutModel(guest)))
+ goto cleanup;
+
+ updated->mode = VIR_CPU_MODE_CUSTOM;
+ if (virCPUDefCopyModel(updated, host, true) < 0)
+ goto cleanup;
+
+ virCPUDefStealModel(guest, updated);
+ guest->mode = VIR_CPU_MODE_CUSTOM;
guest->match = VIR_CPU_MATCH_EXACT;
- virCPUDefFreeModel(guest);
- return virCPUDefCopyModel(guest, host, true);
+ ret = 0;
+
+ cleanup:
+ virCPUDefFree(updated);
+ return ret;
}
+
static virCPUCompareResult
armGuestData(virCPUDefPtr host ATTRIBUTE_UNUSED,
virCPUDefPtr guest ATTRIBUTE_UNUSED,
.nodeData = NULL,
.guestData = armGuestData,
.baseline = armBaseline,
- .update = armUpdate,
+ .update = virCPUarmUpdate,
.hasFeature = NULL,
};
}
static int
-ppc64DriverUpdate(virCPUDefPtr guest,
- const virCPUDef *host)
+virCPUppc64Update(virCPUDefPtr guest,
+ const virCPUDef *host ATTRIBUTE_UNUSED)
{
- switch ((virCPUMode) guest->mode) {
- case VIR_CPU_MODE_HOST_PASSTHROUGH:
+ /*
+ * - host-passthrough doesn't even get here
+ * - host-model is used for host CPU running in a compatibility mode and
+ * it needs to remain unchanged
+ * - custom doesn't support any optional features, there's nothing to
+ * update
+ */
+
+ if (guest->mode == VIR_CPU_MODE_CUSTOM)
guest->match = VIR_CPU_MATCH_EXACT;
- guest->fallback = VIR_CPU_FALLBACK_FORBID;
- virCPUDefFreeModel(guest);
- return virCPUDefCopyModel(guest, host, true);
- case VIR_CPU_MODE_HOST_MODEL:
- case VIR_CPU_MODE_CUSTOM:
- return 0;
-
- case VIR_CPU_MODE_LAST:
- break;
- }
-
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unexpected CPU mode: %d"), guest->mode);
- return -1;
+ return 0;
}
static virCPUDefPtr
.nodeData = ppc64DriverNodeData,
.guestData = ppc64DriverGuestData,
.baseline = ppc64DriverBaseline,
- .update = ppc64DriverUpdate,
+ .update = virCPUppc64Update,
.hasFeature = NULL,
.getModels = ppc64DriverGetModels,
};
}
-static int
-x86ModelSubtractCPU(virCPUx86ModelPtr model,
- const virCPUDef *cpu,
- virCPUx86MapPtr map)
-{
- virCPUx86ModelPtr cpu_model;
- size_t i;
-
- if (!(cpu_model = x86ModelFind(map, cpu->model))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unknown CPU model %s"),
- cpu->model);
- return -1;
- }
-
- x86DataSubtract(&model->data, &cpu_model->data);
-
- for (i = 0; i < cpu->nfeatures; i++) {
- virCPUx86FeaturePtr feature;
-
- if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unknown CPU feature %s"),
- cpu->features[i].name);
- return -1;
- }
-
- x86DataSubtract(&model->data, &feature->data);
- }
-
- return 0;
-}
-
-
static virCPUx86CompareResult
x86ModelCompare(virCPUx86ModelPtr model1,
virCPUx86ModelPtr model2)
static int
-x86UpdateCustom(virCPUDefPtr guest,
- const virCPUDef *host)
+x86UpdateHostModel(virCPUDefPtr guest,
+ const virCPUDef *host,
+ virCPUx86MapPtr map)
{
- int ret = -1;
+ virCPUDefPtr updated = NULL;
size_t i;
- virCPUx86MapPtr map;
- virCPUx86ModelPtr host_model = NULL;
+ int ret = -1;
- if (!(map = virCPUx86GetMap()) ||
- !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)))
+ if (!(updated = virCPUDefCopyWithoutModel(host)))
goto cleanup;
- for (i = 0; i < guest->nfeatures; i++) {
- if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
- int supported = x86FeatureInData(guest->features[i].name,
- &host_model->data, map);
+ /* Remove non-migratable features by default */
+ updated->type = VIR_CPU_TYPE_GUEST;
+ updated->mode = VIR_CPU_MODE_CUSTOM;
+ if (virCPUDefCopyModel(updated, host, true) < 0)
+ goto cleanup;
- if (supported < 0)
- goto cleanup;
- else if (supported)
- guest->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
- else
- guest->features[i].policy = VIR_CPU_FEATURE_DISABLE;
+ i = 0;
+ while (i < updated->nfeatures) {
+ if (x86FeatureIsMigratable(updated->features[i].name, map) &&
+ STRNEQ(updated->features[i].name, "cmt") &&
+ STRNEQ(updated->features[i].name, "mbm_total") &&
+ STRNEQ(updated->features[i].name, "mbm_local")) {
+ i++;
+ } else {
+ VIR_FREE(updated->features[i].name);
+ VIR_DELETE_ELEMENT_INPLACE(updated->features, i, updated->nfeatures);
}
}
- if (guest->match == VIR_CPU_MATCH_MINIMUM) {
- guest->match = VIR_CPU_MATCH_EXACT;
- if (x86ModelSubtractCPU(host_model, guest, map) ||
- x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE,
- &host_model->data, map))
+ if (guest->vendor_id) {
+ VIR_FREE(updated->vendor_id);
+ if (VIR_STRDUP(updated->vendor_id, guest->vendor_id) < 0)
+ goto cleanup;
+ }
+
+ for (i = 0; i < guest->nfeatures; i++) {
+ if (virCPUDefUpdateFeature(updated,
+ guest->features[i].name,
+ guest->features[i].policy) < 0)
goto cleanup;
}
+ virCPUDefStealModel(guest, updated);
+ guest->mode = VIR_CPU_MODE_CUSTOM;
+ guest->match = VIR_CPU_MATCH_EXACT;
ret = 0;
cleanup:
- x86ModelFree(host_model);
+ virCPUDefFree(updated);
return ret;
}
static int
-x86UpdateHostModel(virCPUDefPtr guest,
- const virCPUDef *host,
- bool passthrough)
+virCPUx86Update(virCPUDefPtr guest,
+ const virCPUDef *host)
{
- virCPUDefPtr oldguest = NULL;
+ virCPUx86ModelPtr model = NULL;
virCPUx86MapPtr map;
- size_t i;
int ret = -1;
+ size_t i;
- if (!(map = virCPUx86GetMap()))
- goto cleanup;
+ if (!host) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("unknown host CPU model"));
+ return -1;
+ }
- /* update the host model according to the desired configuration */
- if (!(oldguest = virCPUDefCopy(guest)))
- goto cleanup;
+ if (!(map = virCPUx86GetMap()))
+ return -1;
- virCPUDefFreeModel(guest);
- if (virCPUDefCopyModel(guest, host, true) < 0)
+ if (!(model = x86ModelFromCPU(host, map, -1)))
goto cleanup;
- if (oldguest->vendor_id) {
- VIR_FREE(guest->vendor_id);
- if (VIR_STRDUP(guest->vendor_id, oldguest->vendor_id) < 0)
- goto cleanup;
- }
-
- /* Remove non-migratable features and CMT related features which QEMU
- * knows nothing about.
- * Note: this only works as long as no CPU model contains non-migratable
- * features directly */
- i = 0;
- while (i < guest->nfeatures) {
- if (x86FeatureIsMigratable(guest->features[i].name, map) &&
- STRNEQ(guest->features[i].name, "cmt") &&
- STRNEQ(guest->features[i].name, "mbm_total") &&
- STRNEQ(guest->features[i].name, "mbm_local")) {
- i++;
- } else {
- VIR_FREE(guest->features[i].name);
- VIR_DELETE_ELEMENT_INPLACE(guest->features, i, guest->nfeatures);
+ for (i = 0; i < guest->nfeatures; i++) {
+ if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
+ int supported = x86FeatureInData(guest->features[i].name,
+ &model->data, map);
+ if (supported < 0)
+ goto cleanup;
+ else if (supported)
+ guest->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
+ else
+ guest->features[i].policy = VIR_CPU_FEATURE_DISABLE;
}
}
- for (i = 0; !passthrough && i < oldguest->nfeatures; i++) {
- if (virCPUDefUpdateFeature(guest,
- oldguest->features[i].name,
- oldguest->features[i].policy) < 0)
- goto cleanup;
- }
- ret = 0;
+ if (guest->mode == VIR_CPU_MODE_HOST_MODEL ||
+ guest->match == VIR_CPU_MATCH_MINIMUM)
+ ret = x86UpdateHostModel(guest, host, map);
+ else
+ ret = 0;
cleanup:
- virCPUDefFree(oldguest);
+ x86ModelFree(model);
return ret;
}
-static int
-x86Update(virCPUDefPtr guest,
- const virCPUDef *host)
-{
- switch ((virCPUMode) guest->mode) {
- case VIR_CPU_MODE_CUSTOM:
- return x86UpdateCustom(guest, host);
-
- case VIR_CPU_MODE_HOST_MODEL:
- guest->match = VIR_CPU_MATCH_EXACT;
- return x86UpdateHostModel(guest, host, false);
-
- case VIR_CPU_MODE_HOST_PASSTHROUGH:
- guest->match = VIR_CPU_MATCH_MINIMUM;
- return x86UpdateHostModel(guest, host, true);
-
- case VIR_CPU_MODE_LAST:
- break;
- }
-
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unexpected CPU mode: %d"), guest->mode);
- return -1;
-}
-
-
static int
x86HasFeature(const virCPUData *data,
const char *name)
#endif
.guestData = x86GuestData,
.baseline = x86Baseline,
- .update = x86Update,
+ .update = virCPUx86Update,
.hasFeature = x86HasFeature,
.dataFormat = x86CPUDataFormat,
.dataParse = x86CPUDataParse,
cpuGuestData;
cpuHasFeature;
cpuNodeData;
-cpuUpdate;
+virCPUUpdate;
# cpu/cpu_x86.h
if (cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
!migrating &&
- cpuUpdate(cpu, host) < 0)
+ virCPUUpdate(def->os.arch, cpu, host) < 0)
goto cleanup;
if (compareAgainstHost &&
goto cleanup;
}
- if (cpuUpdate(def->cpu, caps->host.cpu) < 0)
+ if (virCPUUpdate(def->os.arch, def->cpu, caps->host.cpu) < 0)
goto cleanup;
}
if (cpu->mode == VIR_CPU_MODE_HOST_MODEL &&
flags & VIR_QEMU_PROCESS_START_NEW &&
- cpuUpdate(cpu, host) < 0)
+ virCPUUpdate(vm->def->os.arch, cpu, host) < 0)
goto cleanup;
cmp = cpuGuestData(host, cpu, &data, &compare_msg);
!(cpu = cpuTestLoadXML(data->arch, data->name)))
goto cleanup;
- if (cpuUpdate(cpu, host) < 0)
+ if (virCPUUpdate(host->arch, cpu, host) < 0)
goto cleanup;
if (virAsprintf(&result, "%s+%s", data->host, data->name) < 0)
host "/" cpu " (" #result ")", \
host, cpu, NULL, 0, NULL, 0, result)
+#define DO_TEST_UPDATE_ONLY(arch, host, cpu) \
+ DO_TEST(arch, cpuTestUpdate, \
+ cpu " on " host, \
+ host, cpu, NULL, 0, NULL, 0, 0) \
+
#define DO_TEST_UPDATE(arch, host, cpu, result) \
do { \
- DO_TEST(arch, cpuTestUpdate, \
- cpu " on " host, \
- host, cpu, NULL, 0, NULL, 0, 0); \
+ DO_TEST_UPDATE_ONLY(arch, host, cpu); \
DO_TEST_COMPARE(arch, host, host "+" cpu, result); \
} while (0)
DO_TEST_UPDATE("x86", "host", "guest", VIR_CPU_COMPARE_SUPERSET);
DO_TEST_UPDATE("x86", "host", "host-model", VIR_CPU_COMPARE_IDENTICAL);
DO_TEST_UPDATE("x86", "host", "host-model-nofallback", VIR_CPU_COMPARE_IDENTICAL);
- DO_TEST_UPDATE("x86", "host", "host-passthrough", VIR_CPU_COMPARE_IDENTICAL);
DO_TEST_UPDATE("x86", "host-invtsc", "host-model", VIR_CPU_COMPARE_SUPERSET);
+ DO_TEST_UPDATE_ONLY("x86", "host", "host-passthrough");
+ DO_TEST_UPDATE_ONLY("x86", "host", "host-passthrough-features");
DO_TEST_UPDATE("ppc64", "host", "guest", VIR_CPU_COMPARE_IDENTICAL);
DO_TEST_UPDATE("ppc64", "host", "guest-nofallback", VIR_CPU_COMPARE_INCOMPATIBLE);
-<cpu mode='host-model' match='exact'>
+<cpu mode='custom' match='exact'>
<model fallback='forbid'>Penryn</model>
<vendor>Intel</vendor>
<topology sockets='1' cores='2' threads='1'/>
-<cpu mode='host-model' match='exact'>
+<cpu mode='custom' match='exact'>
<model fallback='allow'>Penryn</model>
<vendor>Intel</vendor>
<feature policy='require' name='dca'/>
--- /dev/null
+<cpu mode='host-passthrough'>
+ <feature policy='disable' name='dca'/>
+ <feature policy='force' name='vmx'/>
+</cpu>
-<cpu mode='host-passthrough' match='minimum'>
- <model>Penryn</model>
- <vendor>Intel</vendor>
- <feature policy='require' name='dca'/>
- <feature policy='require' name='xtpr'/>
- <feature policy='require' name='tm2'/>
- <feature policy='require' name='est'/>
- <feature policy='require' name='vmx'/>
- <feature policy='require' name='ds_cpl'/>
- <feature policy='require' name='monitor'/>
- <feature policy='require' name='pbe'/>
- <feature policy='require' name='tm'/>
- <feature policy='require' name='ht'/>
- <feature policy='require' name='ss'/>
- <feature policy='require' name='acpi'/>
- <feature policy='require' name='ds'/>
- <feature policy='require' name='vme'/>
-</cpu>
+<cpu mode='host-passthrough'/>
<cpu mode='custom' match='exact'>
<model fallback='allow'>Penryn</model>
- <feature policy='require' name='vme'/>
- <feature policy='require' name='ds'/>
- <feature policy='require' name='acpi'/>
- <feature policy='require' name='ss'/>
- <feature policy='require' name='ht'/>
- <feature policy='require' name='tm'/>
- <feature policy='require' name='pbe'/>
- <feature policy='require' name='monitor'/>
- <feature policy='require' name='ds_cpl'/>
- <feature policy='require' name='vmx'/>
- <feature policy='require' name='est'/>
- <feature policy='require' name='tm2'/>
- <feature policy='require' name='xtpr'/>
+ <vendor>Intel</vendor>
<feature policy='require' name='dca'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='vme'/>
</cpu>
<cpu mode='custom' match='exact'>
- <model fallback='allow'>pentium3</model>
- <feature policy='require' name='apic'/>
- <feature policy='require' name='clflush'/>
- <feature policy='require' name='ds'/>
- <feature policy='require' name='acpi'/>
- <feature policy='require' name='sse2'/>
- <feature policy='require' name='ss'/>
- <feature policy='require' name='ht'/>
- <feature policy='require' name='tm'/>
- <feature policy='require' name='pbe'/>
- <feature policy='require' name='pni'/>
- <feature policy='require' name='monitor'/>
- <feature policy='require' name='ds_cpl'/>
- <feature policy='require' name='vmx'/>
- <feature policy='require' name='est'/>
- <feature policy='require' name='tm2'/>
- <feature policy='require' name='ssse3'/>
- <feature policy='require' name='cx16'/>
- <feature policy='require' name='xtpr'/>
+ <model fallback='allow'>Penryn</model>
+ <vendor>Intel</vendor>
<feature policy='require' name='dca'/>
- <feature policy='require' name='sse4.1'/>
- <feature policy='require' name='syscall'/>
- <feature policy='require' name='nx'/>
- <feature policy='require' name='lm'/>
- <feature policy='require' name='lahf_lm'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='vme'/>
</cpu>
-<cpu mode='host-model' match='exact'>
+<cpu mode='custom' match='exact'>
<model fallback='allow'>SandyBridge</model>
<vendor>Intel</vendor>
<feature policy='require' name='osxsave'/>
--- /dev/null
+<cpu mode='host-passthrough'>
+ <feature policy='disable' name='dca'/>
+ <feature policy='force' name='vmx'/>
+</cpu>