240 lines
6.9 KiB
Diff
240 lines
6.9 KiB
Diff
|
|
From 1a70b1e3bdbd8d0dcf9281341bc23b4ff2ffaa3a Mon Sep 17 00:00:00 2001
|
||
|
|
From: Xu Yandong <xuyandong2@huawei.com>
|
||
|
|
Date: Mon, 20 Apr 2020 19:33:49 +0800
|
||
|
|
Subject: cpu/arm: implment cpu compare function
|
||
|
|
|
||
|
|
Signed-off-by: Xu Yandong <xuyandong2@huawei.com>
|
||
|
|
---
|
||
|
|
src/cpu/cpu_arm.c | 196 +++++++++++++++++++++++++++++++++++++++++++++-
|
||
|
|
1 file changed, 193 insertions(+), 3 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
|
||
|
|
index a7c9523..3ef54b9 100644
|
||
|
|
--- a/src/cpu/cpu_arm.c
|
||
|
|
+++ b/src/cpu/cpu_arm.c
|
||
|
|
@@ -21,6 +21,7 @@
|
||
|
|
|
||
|
|
#include <config.h>
|
||
|
|
|
||
|
|
+#include "virlog.h"
|
||
|
|
#include "viralloc.h"
|
||
|
|
#include "cpu.h"
|
||
|
|
#include "cpu_map.h"
|
||
|
|
@@ -30,6 +31,8 @@
|
||
|
|
|
||
|
|
#define VIR_FROM_THIS VIR_FROM_CPU
|
||
|
|
|
||
|
|
+VIR_LOG_INIT("cpu.cpu_arm");
|
||
|
|
+
|
||
|
|
static const char *sysinfoCpuinfo = "/proc/cpuinfo";
|
||
|
|
|
||
|
|
#define CPUINFO sysinfoCpuinfo
|
||
|
|
@@ -806,14 +809,201 @@ virCPUarmBaseline(virCPUDefPtr *cpus,
|
||
|
|
return g_steal_pointer(&cpu);
|
||
|
|
}
|
||
|
|
|
||
|
|
+static bool
|
||
|
|
+virCPUarmFeaturesIsSub(char *subFeatures,
|
||
|
|
+ char *fullFeatures)
|
||
|
|
+{
|
||
|
|
+ bool ret = false;
|
||
|
|
+ char **sub = NULL;
|
||
|
|
+ char **full = NULL;
|
||
|
|
+ size_t subCount = 0;
|
||
|
|
+ size_t fullCount = 0;
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ if (virStringIsEmpty(subFeatures))
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
+ if (virStringIsEmpty(fullFeatures))
|
||
|
|
+ return ret;
|
||
|
|
+
|
||
|
|
+ if (STREQ(subFeatures, fullFeatures))
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
+ if (!(sub = virStringSplitCount(subFeatures, " ", 0, &subCount)) ||
|
||
|
|
+ !(full = virStringSplitCount(fullFeatures, " ", 0, &fullCount)) ||
|
||
|
|
+ subCount > fullCount)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < subCount; i++) {
|
||
|
|
+ if (!virStringListHasString((const char**)full, sub[i]))
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = true;
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ virStringListFree(sub);
|
||
|
|
+ virStringListFree(full);
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static virCPUDataPtr
|
||
|
|
+armMakeCPUData(virArch arch,
|
||
|
|
+ virCPUarmData *data)
|
||
|
|
+{
|
||
|
|
+ virCPUDataPtr cpuData;
|
||
|
|
+
|
||
|
|
+ if (!(cpuData = virCPUDataNew(arch)))
|
||
|
|
+ return NULL;
|
||
|
|
+
|
||
|
|
+ virCPUarmDataCopy(&cpuData->data.arm, data);
|
||
|
|
+
|
||
|
|
+ return cpuData;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static virCPUCompareResult
|
||
|
|
-virCPUarmCompare(virCPUDefPtr host G_GNUC_UNUSED,
|
||
|
|
- virCPUDefPtr cpu G_GNUC_UNUSED,
|
||
|
|
- bool failMessages G_GNUC_UNUSED)
|
||
|
|
+armCompute(virCPUDefPtr host,
|
||
|
|
+ virCPUDefPtr cpu,
|
||
|
|
+ virCPUDataPtr *guestData,
|
||
|
|
+ char **message)
|
||
|
|
{
|
||
|
|
+ virCPUarmMapPtr map = NULL;
|
||
|
|
+ g_autoptr(virCPUarmModel) hostModel = NULL;
|
||
|
|
+ g_autoptr(virCPUarmModel) guestModel = NULL;
|
||
|
|
+ virArch arch;
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ if (cpu->arch != VIR_ARCH_NONE) {
|
||
|
|
+ bool found = false;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < G_N_ELEMENTS(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)
|
||
|
|
+ *message = g_strdup_printf(_("CPU arch %s does not match host arch"),
|
||
|
|
+ virArchToString(cpu->arch));
|
||
|
|
+
|
||
|
|
+ return VIR_CPU_COMPARE_INCOMPATIBLE;
|
||
|
|
+ }
|
||
|
|
+ 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)
|
||
|
|
+ *message = g_strdup_printf(_("host CPU vendor does not match required "
|
||
|
|
+ "CPU vendor %s"),
|
||
|
|
+ cpu->vendor);
|
||
|
|
+
|
||
|
|
+ return VIR_CPU_COMPARE_INCOMPATIBLE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!(map = virCPUarmGetMap()))
|
||
|
|
+ return VIR_CPU_COMPARE_ERROR;
|
||
|
|
+
|
||
|
|
+ /* Host CPU information */
|
||
|
|
+ if (!(hostModel = virCPUarmModelFromCPU(host, map)))
|
||
|
|
+ return VIR_CPU_COMPARE_ERROR;
|
||
|
|
+
|
||
|
|
+ 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 = virCPUarmModelCopy(hostModel);
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case VIR_CPU_MODE_CUSTOM:
|
||
|
|
+ /* custom:
|
||
|
|
+ * look up guest CPU information */
|
||
|
|
+ guestModel = virCPUarmModelFromCPU(cpu, map);
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ } else {
|
||
|
|
+ /* Other host CPU information */
|
||
|
|
+ guestModel = virCPUarmModelFromCPU(cpu, map);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!guestModel)
|
||
|
|
+ return VIR_CPU_COMPARE_ERROR;
|
||
|
|
+
|
||
|
|
+ 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)
|
||
|
|
+ *message = g_strdup_printf(_("host CPU model %s does not match required "
|
||
|
|
+ "CPU model %s"),
|
||
|
|
+ hostModel->name, guestModel->name);
|
||
|
|
+
|
||
|
|
+ return VIR_CPU_COMPARE_INCOMPATIBLE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!virCPUarmFeaturesIsSub(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)
|
||
|
|
+ *message = g_strdup_printf(_("guest CPU features '%s' is not subset of "
|
||
|
|
+ "host CPU features '%s'"),
|
||
|
|
+ guestModel->data.features,
|
||
|
|
+ hostModel->data.features);
|
||
|
|
+
|
||
|
|
+ return VIR_CPU_COMPARE_INCOMPATIBLE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (guestData &&
|
||
|
|
+ !(*guestData = armMakeCPUData(arch, &guestModel->data)))
|
||
|
|
+ return VIR_CPU_COMPARE_ERROR;
|
||
|
|
+
|
||
|
|
return VIR_CPU_COMPARE_IDENTICAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static virCPUCompareResult
|
||
|
|
+virCPUarmCompare(virCPUDefPtr host,
|
||
|
|
+ virCPUDefPtr cpu,
|
||
|
|
+ bool failMessages)
|
||
|
|
+{
|
||
|
|
+ virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
|
||
|
|
+ g_autofree char *message = NULL;
|
||
|
|
+
|
||
|
|
+ if (!host || !host->model) {
|
||
|
|
+ if (failMessages) {
|
||
|
|
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s",
|
||
|
|
+ _("unknown host CPU"));
|
||
|
|
+ } else {
|
||
|
|
+ VIR_WARN("unknown host CPU");
|
||
|
|
+ return VIR_CPU_COMPARE_INCOMPATIBLE;
|
||
|
|
+ }
|
||
|
|
+ return VIR_CPU_COMPARE_ERROR;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = armCompute(host, cpu, NULL, &message);
|
||
|
|
+
|
||
|
|
+ if (failMessages && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
|
||
|
|
+ if (message) {
|
||
|
|
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message);
|
||
|
|
+ } else {
|
||
|
|
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
|
||
|
|
+ }
|
||
|
|
+ return VIR_CPU_COMPARE_ERROR;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static int
|
||
|
|
virCPUarmValidateFeatures(virCPUDefPtr cpu)
|
||
|
|
{
|
||
|
|
--
|
||
|
|
2.23.0
|
||
|
|
|