<div dir="ltr">Introduce getHost support for ARM CPU driver, read<br>CPU vendor_id, part_id and flags from registers<br>directly. These codes will only be compiled on<br>aarch64 hardwares.<br><br>Signed-off-by: Zhenyu Zheng <<a href="mailto:zhengzhenyulixi@gmail.com">zhengzhenyulixi@gmail.com</a>><br>---<br> src/cpu/cpu_arm.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++<br> 1 file changed, 201 insertions(+)<br><br>diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c<br>index 24404eac2c..887932cc5a 100644<br>--- a/src/cpu/cpu_arm.c<br>+++ b/src/cpu/cpu_arm.c<br>@@ -21,6 +21,10 @@<br>  */<br> <br> #include <config.h><br>+#if defined(__aarch64__)<br>+# include <asm/hwcap.h><br>+# include <sys/auxv.h><br>+#endif<br> <br> #include "viralloc.h"<br> #include "cpu.h"<br>@@ -31,6 +35,12 @@<br> #include "virxml.h"<br> <br> #define VIR_FROM_THIS VIR_FROM_CPU<br>+#if defined(__aarch64__)<br>+/* Shift bit mask for parsing cpu flags */<br>+# define BIT_SHIFTS(n) (1UL << (n))<br>+/* The current max number of cpu flags on ARM is 32 */<br>+# define MAX_CPU_FLAGS 32<br>+#endif<br> <br> VIR_LOG_INIT("cpu.cpu_arm");<br> <br>@@ -495,12 +505,203 @@ virCPUarmValidateFeatures(virCPUDefPtr cpu)<br>     return 0;<br> }<br> <br>+#if defined(__aarch64__)<br>+/**<br>+ * virCPUarmCpuDataFromRegs:<br>+ *<br>+ * @data: 64-bit arm CPU specific data<br>+ *<br>+ * Fetches CPU vendor_id and part_id from MIDR_EL1 register, parse CPU<br>+ * flags from AT_HWCAP. There are currently 32 valid flags  on ARM arch<br>+ * represented by each bit.<br>+ */<br>+static int<br>+virCPUarmCpuDataFromRegs(virCPUarmData *data)<br>+{<br>+    /* Generate human readable flag list according to the order of */<br>+    /* AT_HWCAP bit map */<br>+    const char *flag_list[MAX_CPU_FLAGS] = {<br>+        "fp", "asimd", "evtstrm", "aes", "pmull", "sha1", "sha2",<br>+        "crc32", "atomics", "fphp", "asimdhp", "cpuid", "asimdrdm",<br>+        "jscvt", "fcma", "lrcpc", "dcpop", "sha3", "sm3", "sm4",<br>+        "asimddp", "sha512", "sve", "asimdfhm", "dit", "uscat",<br>+        "ilrcpc", "flagm", "ssbs", "sb", "paca", "pacg"};<br>+    unsigned long cpuid, hwcaps;<br>+    char **features = NULL;<br>+    g_autofree char *cpu_feature_str = NULL;<br>+    int cpu_feature_index = 0;<br>+    size_t i;<br>+<br>+    if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {<br>+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",<br>+                       _("CPUID registers unavailable"));<br>+            return -1;<br>+    }<br>+<br>+    /* read the cpuid data from MIDR_EL1 register */<br>+    asm("mrs %0, MIDR_EL1" : "=r" (cpuid));<br>+    VIR_DEBUG("CPUID read from register:  0x%016lx", cpuid);<br>+<br>+    /* parse the coresponding part_id bits */<br>+    data->pvr = cpuid>>4&0xFFF;<br>+    /* parse the coresponding vendor_id bits */<br>+    data->vendor_id = cpuid>>24&0xFF;<br>+<br>+    hwcaps = getauxval(AT_HWCAP);<br>+    VIR_DEBUG("CPU flags read from register:  0x%016lx", hwcaps);<br>+<br>+    if (VIR_ALLOC_N(features, MAX_CPU_FLAGS) < 0)<br>+        return -1;<br>+<br>+    /* shift bit map mask to parse for CPU flags */<br>+    for (i = 0; i< MAX_CPU_FLAGS; i++) {<br>+        if (hwcaps & BIT_SHIFTS(i)) {<br>+            features[cpu_feature_index] = g_strdup(flag_list[i]);<br>+            cpu_feature_index++;<br>+        }<br>+    }<br>+<br>+    if (cpu_feature_index > 1) {<br>+        cpu_feature_str = virStringListJoin((const char **)features, " ");<br>+        if (!cpu_feature_str)<br>+            goto error;<br>+    }<br>+    data->features = g_strdup(cpu_feature_str);<br>+<br>+    return 0;<br>+<br>+ error:<br>+    virStringListFree(features);<br>+    return -1;<br>+}<br>+<br>+static int<br>+virCPUarmDataParseFeatures(virCPUDefPtr cpu,<br>+                           const virCPUarmData *cpuData)<br>+{<br>+    int ret = -1;<br>+    size_t i;<br>+    char **features;<br>+<br>+    if (!cpu || !cpuData)<br>+        return ret;<br>+<br>+    if (!(features = virStringSplitCount(cpuData->features, " ",<br>+                                         0, &cpu->nfeatures)))<br>+        return ret;<br>+    if (cpu->nfeatures) {<br>+        if (VIR_ALLOC_N(cpu->features, cpu->nfeatures) < 0)<br>+            goto error;<br>+<br>+        for (i = 0; i < cpu->nfeatures; i++) {<br>+            cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE;<br>+            cpu->features[i].name = g_strdup(features[i]);<br>+        }<br>+    }<br>+<br>+    ret = 0;<br>+<br>+ cleanup:<br>+    virStringListFree(features);<br>+    return ret;<br>+<br>+ error:<br>+    for (i = 0; i < cpu->nfeatures; i++)<br>+        VIR_FREE(cpu->features[i].name);<br>+    VIR_FREE(cpu->features);<br>+    cpu->nfeatures = 0;<br>+    goto cleanup;<br>+}<br>+<br>+static int<br>+virCPUarmDecode(virCPUDefPtr cpu,<br>+                const virCPUarmData *cpuData,<br>+                virDomainCapsCPUModelsPtr models)<br>+{<br>+    virCPUarmMapPtr map;<br>+    virCPUarmModelPtr model;<br>+    virCPUarmVendorPtr vendor = NULL;<br>+<br>+    if (!cpuData || !(map = virCPUarmGetMap()))<br>+        return -1;<br>+<br>+    if (!(model = virCPUarmModelFindByPVR(map, cpuData->pvr))) {<br>+        virReportError(VIR_ERR_OPERATION_FAILED,<br>+                       _("Cannot find CPU model with PVR 0x%03lx"),<br>+                       cpuData->pvr);<br>+        return -1;<br>+    }<br>+<br>+    if (!virCPUModelIsAllowed(model->name, models)) {<br>+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,<br>+                       _("CPU model %s is not supported by hypervisor"),<br>+                       model->name);<br>+        return -1;<br>+    }<br>+<br>+    cpu->model = g_strdup(model->name);<br>+<br>+    if (cpuData->vendor_id &&<br>+        !(vendor = virCPUarmVendorFindByID(map, cpuData->vendor_id))) {<br>+        virReportError(VIR_ERR_OPERATION_FAILED,<br>+                       _("Cannot find CPU vendor with vendor id 0x%02lx"),<br>+                       cpuData->vendor_id);<br>+        return -1;<br>+    }<br>+<br>+    if (vendor)<br>+        cpu->vendor = g_strdup(vendor->name);<br>+<br>+    if (cpuData->features &&<br>+        virCPUarmDataParseFeatures(cpu, cpuData) < 0)<br>+        return -1;<br>+<br>+    return 0;<br>+}<br>+<br>+static int<br>+virCPUarmDecodeCPUData(virCPUDefPtr cpu,<br>+                       const virCPUData *data,<br>+                       virDomainCapsCPUModelsPtr models)<br>+{<br>+    return virCPUarmDecode(cpu, &data->data.arm, models);<br>+}<br>+<br>+static int<br>+virCPUarmGetHost(virCPUDefPtr cpu,<br>+                 virDomainCapsCPUModelsPtr models)<br>+{<br>+    virCPUDataPtr cpuData = NULL;<br>+    int ret = -1;<br>+<br>+    if (virCPUarmDriverInitialize() < 0)<br>+        goto cleanup;<br>+<br>+    if (!(cpuData = virCPUDataNew(archs[0])))<br>+        goto cleanup;<br>+<br>+    if (virCPUarmCpuDataFromRegs(&cpuData->data.arm) < 0)<br>+        goto cleanup;<br>+<br>+    ret = virCPUarmDecodeCPUData(cpu, cpuData, models);<br>+<br>+ cleanup:<br>+    virCPUarmDataFree(cpuData);<br>+    return ret;<br>+}<br>+#endif<br>+<br> struct cpuArchDriver cpuDriverArm = {<br>     .name = "arm",<br>     .arch = archs,<br>     .narch = G_N_ELEMENTS(archs),<br>     .compare = virCPUarmCompare,<br>+#if defined(__aarch64__)<br>+    .getHost = virCPUarmGetHost,<br>+    .decode = virCPUarmDecodeCPUData,<br>+#else<br>     .decode = NULL,<br>+#endif<br>     .encode = NULL,<br>     .dataFree = virCPUarmDataFree,<br>     .baseline = virCPUarmBaseline,<br>-- <br>2.26.2<br></div>