libvirt/libvirt-cpu-fix-cpu-compare-and-cpu-baseline-for-ARM-CPU.patch

293 lines
8.6 KiB
Diff
Raw Normal View History

2019-09-30 10:58:53 -04:00
From 57b8e156e898ccf878842c3cba1ed97a415cff6a Mon Sep 17 00:00:00 2001
From: Xu Yandong <xuyandong2@huawei.com>
Date: Fri, 6 Sep 2019 11:27:33 +0800
Subject: [PATCH] cpu: fix cpu-compare and cpu-baseline for ARM CPU
Signed-off-by: Xu Yandong <xuyandong2@huawei.com>
---
src/cpu/cpu_arm.c | 241 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 234 insertions(+), 7 deletions(-)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index 0c8cd50..1d0d3b6 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -681,12 +681,18 @@ virCPUarmUpdate(virCPUDefPtr guest,
static virCPUDefPtr
virCPUarmBaseline(virCPUDefPtr *cpus,
- unsigned int ncpus ATTRIBUTE_UNUSED,
- virDomainCapsCPUModelsPtr models ATTRIBUTE_UNUSED,
+ unsigned int ncpus,
+ virDomainCapsCPUModelsPtr models,
const char **features ATTRIBUTE_UNUSED,
bool migratable ATTRIBUTE_UNUSED)
{
virCPUDefPtr cpu = NULL;
+ virCPUarmMapPtr map = NULL;
+ virCPUarmModelPtr model = NULL;
+ virCPUarmModelPtr baseModel = NULL;
+ virCPUarmVendorPtr vendor = NULL;
+ bool outputVendor = true;
+ size_t i;
if (VIR_ALLOC(cpu) < 0 ||
VIR_STRDUP(cpu->model, cpus[0]->model) < 0) {
@@ -694,27 +700,248 @@ virCPUarmBaseline(virCPUDefPtr *cpus,
return NULL;
}
+ cpu->arch = cpus[0]->arch;
cpu->type = VIR_CPU_TYPE_GUEST;
cpu->match = VIR_CPU_MATCH_EXACT;
+ cpu->fallback = VIR_CPU_FALLBACK_FORBID;
+
+ if (!(map = virCPUarmGetMap()))
+ goto error;
+
+ if (!(baseModel = armModelFromCPU(cpus[0], map)))
+ goto error;
+
+ if (!cpus[0]->vendor) {
+ outputVendor = false;
+ } else if (!(vendor = armVendorFindByName(map, cpus[0]->vendor))) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Unknown CPU vendor %s"), cpus[0]->vendor);
+ goto error;
+ }
+
+ for (i = 1; i < ncpus; i++) {
+ const char *vn = NULL;
+
+ if (!(model = armModelFromCPU(cpus[i], map)))
+ goto error;
+
+ if (cpus[i]->vendor) {
+ vn = cpus[i]->vendor;
+ } else {
+ outputVendor = false;
+ }
+
+ if (vn) {
+ if (!vendor) {
+ if (!(vendor = armVendorFindByName(map, vn))) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Unknown CPU vendor %s"), vn);
+ goto error;
+ }
+ } else if (STRNEQ(vendor->name, vn)) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("CPU vendors do not match"));
+ goto error;
+ }
+ }
+
+ armDataIntersect(&baseModel->data, &model->data);
+ armModelFree(model);
+ model = NULL;
+ }
+
+ if (armDecode(cpu, &baseModel->data, models) < 0)
+ goto error;
+
+ if (!outputVendor)
+ VIR_FREE(cpu->vendor);
+
+ cpu->arch = VIR_ARCH_NONE;
+
+ cleanup:
+ armModelFree(baseModel);
return cpu;
+
+ error:
+ armModelFree(model);
+ virCPUDefFree(cpu);
+ cpu = NULL;
+ goto cleanup;
}
+
static virCPUCompareResult
-virCPUarmCompare(virCPUDefPtr host ATTRIBUTE_UNUSED,
- virCPUDefPtr cpu ATTRIBUTE_UNUSED,
- bool failMessages ATTRIBUTE_UNUSED)
+armCompute(virCPUDefPtr host,
+ virCPUDefPtr cpu,
+ virCPUDataPtr *guestData,
+ char **message)
{
- return VIR_CPU_COMPARE_IDENTICAL;
+ virCPUarmMapPtr map = NULL;
+ virCPUarmModelPtr hostModel = NULL;
+ virCPUarmModelPtr guestModel = NULL;
+ virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
+ virArch arch;
+ size_t i;
+
+ if (cpu->arch != VIR_ARCH_NONE) {
+ bool found = false;
+
+ for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
+ if (archs[i] == cpu->arch) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ VIR_DEBUG("CPU arch %s does not match host arch",
+ virArchToString(cpu->arch));
+ if (message &&
+ virAsprintf(message,
+ _("CPU arch %s does not match host arch"),
+ virArchToString(cpu->arch)) < 0)
+ goto cleanup;
+
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ goto cleanup;
+ }
+ arch = cpu->arch;
+ } else {
+ arch = host->arch;
+ }
+
+ if (cpu->vendor &&
+ (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
+ VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
+ cpu->vendor);
+ if (message &&
+ virAsprintf(message,
+ _("host CPU vendor does not match required "
+ "CPU vendor %s"),
+ cpu->vendor) < 0)
+ goto cleanup;
+
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ goto cleanup;
+ }
+
+ if (!(map = virCPUarmGetMap()))
+ goto cleanup;
+
+ /* Host CPU information */
+ if (!(hostModel = armModelFromCPU(host, map)))
+ goto cleanup;
+
+ if (cpu->type == VIR_CPU_TYPE_GUEST) {
+ /* Guest CPU information */
+ switch (cpu->mode) {
+ case VIR_CPU_MODE_HOST_MODEL:
+ case VIR_CPU_MODE_HOST_PASSTHROUGH:
+ /* host-model and host-passthrough:
+ * the guest CPU is the same as the host */
+ guestModel = armModelCopy(hostModel);
+ break;
+
+ case VIR_CPU_MODE_CUSTOM:
+ /* custom:
+ * look up guest CPU information */
+ guestModel = armModelFromCPU(cpu, map);
+ break;
+ }
+ } else {
+ /* Other host CPU information */
+ guestModel = armModelFromCPU(cpu, map);
+ }
+
+ if (!guestModel)
+ goto cleanup;
+
+ if (STRNEQ(guestModel->name, hostModel->name)) {
+ VIR_DEBUG("host CPU model %s does not match required CPU model %s",
+ hostModel->name, guestModel->name);
+ if (message &&
+ virAsprintf(message,
+ _("host CPU model %s does not match required "
+ "CPU model %s"),
+ hostModel->name, guestModel->name) < 0)
+ goto cleanup;
+
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ goto cleanup;
+ }
+
+ if (!armFeaturesIsSub(guestModel->data.features, hostModel->data.features)) {
+ VIR_DEBUG("guest CPU features '%s' is not subset of "
+ "host CPU features '%s'",
+ guestModel->data.features, hostModel->data.features);
+ if (message &&
+ virAsprintf(message,
+ _("guest CPU features '%s' is not subset of "
+ "host CPU features '%s'"),
+ guestModel->data.features,
+ hostModel->data.features) < 0)
+ goto cleanup;
+
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ goto cleanup;
+ }
+
+ if (guestData &&
+ !(*guestData = armMakeCPUData(arch, &guestModel->data)))
+ goto cleanup;
+
+ ret = VIR_CPU_COMPARE_IDENTICAL;
+
+ cleanup:
+ armModelFree(hostModel);
+ armModelFree(guestModel);
+ return ret;
}
+static virCPUCompareResult
+virCPUarmCompare(virCPUDefPtr host,
+ virCPUDefPtr cpu,
+ bool failIncompatible)
+{
+ virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
+ char *message = NULL;
+
+ if (!host || !host->model) {
+ if (failIncompatible) {
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s",
+ _("unknown host CPU"));
+ } else {
+ VIR_WARN("unknown host CPU");
+ ret = VIR_CPU_COMPARE_INCOMPATIBLE;
+ }
+ return ret;
+ }
+
+ ret = armCompute(host, cpu, NULL, &message);
+
+ if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
+ ret = VIR_CPU_COMPARE_ERROR;
+ if (message) {
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message);
+ } else {
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
+ }
+ }
+ VIR_FREE(message);
+
+ return ret;
+}
+
+
struct cpuArchDriver cpuDriverArm = {
.name = "arm",
.arch = archs,
.narch = ARRAY_CARDINALITY(archs),
.compare = virCPUarmCompare,
- .decode = NULL,
+ .decode = armDecodeCPUData,
.encode = NULL,
+ .dataFree = virCPUarmDataFree,
.baseline = virCPUarmBaseline,
.update = virCPUarmUpdate,
};
--
2.19.1