293 lines
8.6 KiB
Diff
293 lines
8.6 KiB
Diff
|
|
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
|
||
|
|
|