[PATCH V2 0/5] Introduce getHost support for ARM CPU driver

Introduce getHost support for ARM CPU driver. First add some data about commonly used ARM CPU models, and their vendors into cpu_map, then added some helper methods as callbacks to load them. Read and parse vendor_id, part_id and CPU flags of local CPU from corresponding registers. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> Zhenyu Zheng (5): cpu_map: Introduce ARM cpu models cpu: Introduce virCPUarmData to virCPUData cpu: Introduce ARM related structs cpu: Add helper funtions to parse vendor and model cpu: Introduce getHost support for ARM CPU driver src/cpu/Makefile.inc.am | 1 + src/cpu/cpu.h | 2 + src/cpu/cpu_arm.c | 445 +++++++++++++++++++++++++++++- src/cpu/cpu_arm_data.h | 31 +++ src/cpu_map/Makefile.inc.am | 7 + src/cpu_map/arm_Falkor.xml | 16 ++ src/cpu_map/arm_Kunpeng-920.xml | 24 ++ src/cpu_map/arm_ThunderX299xx.xml | 16 ++ src/cpu_map/arm_cortex-a53.xml | 16 ++ src/cpu_map/arm_cortex-a57.xml | 15 + src/cpu_map/arm_cortex-a72.xml | 15 + src/cpu_map/arm_vendors.xml | 14 + src/cpu_map/index.xml | 15 + 13 files changed, 614 insertions(+), 3 deletions(-) create mode 100644 src/cpu/cpu_arm_data.h create mode 100644 src/cpu_map/arm_Falkor.xml create mode 100644 src/cpu_map/arm_Kunpeng-920.xml create mode 100644 src/cpu_map/arm_ThunderX299xx.xml create mode 100644 src/cpu_map/arm_cortex-a53.xml create mode 100644 src/cpu_map/arm_cortex-a57.xml create mode 100644 src/cpu_map/arm_cortex-a72.xml create mode 100644 src/cpu_map/arm_vendors.xml -- 2.26.0.windows.1

Introduce vendors and some commonly used models for ARM arch, these will be used for virConnectionGetCapabilities for ARM CPUs. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu_map/Makefile.inc.am | 7 +++++++ src/cpu_map/arm_Falkor.xml | 16 ++++++++++++++++ src/cpu_map/arm_Kunpeng-920.xml | 24 ++++++++++++++++++++++++ src/cpu_map/arm_ThunderX299xx.xml | 16 ++++++++++++++++ src/cpu_map/arm_cortex-a53.xml | 16 ++++++++++++++++ src/cpu_map/arm_cortex-a57.xml | 15 +++++++++++++++ src/cpu_map/arm_cortex-a72.xml | 15 +++++++++++++++ src/cpu_map/arm_vendors.xml | 14 ++++++++++++++ src/cpu_map/index.xml | 15 +++++++++++++++ 9 files changed, 138 insertions(+) create mode 100644 src/cpu_map/arm_Falkor.xml create mode 100644 src/cpu_map/arm_Kunpeng-920.xml create mode 100644 src/cpu_map/arm_ThunderX299xx.xml create mode 100644 src/cpu_map/arm_cortex-a53.xml create mode 100644 src/cpu_map/arm_cortex-a57.xml create mode 100644 src/cpu_map/arm_cortex-a72.xml create mode 100644 src/cpu_map/arm_vendors.xml diff --git a/src/cpu_map/Makefile.inc.am b/src/cpu_map/Makefile.inc.am index be64c9a0d4..5d9190e27d 100644 --- a/src/cpu_map/Makefile.inc.am +++ b/src/cpu_map/Makefile.inc.am @@ -2,7 +2,14 @@ cpumapdir = $(pkgdatadir)/cpu_map cpumap_DATA = \ + cpu_map/arm_cortex-a53.xml \ + cpu_map/arm_cortex-a57.xml \ + cpu_map/arm_cortex-a72.xml \ cpu_map/arm_features.xml \ + cpu_map/arm_Kunpeng-920.xml \ + cpu_map/arm_ThunderX299xx.xml \ + cpu_map/arm_Falkor.xml \ + cpu_map/arm_vendors.xml \ cpu_map/index.xml \ cpu_map/ppc64_vendors.xml \ cpu_map/ppc64_POWER7.xml \ diff --git a/src/cpu_map/arm_Falkor.xml b/src/cpu_map/arm_Falkor.xml new file mode 100644 index 0000000000..902ed2b6ba --- /dev/null +++ b/src/cpu_map/arm_Falkor.xml @@ -0,0 +1,16 @@ +<cpus> + <model name='Falkor'> + <vendor name='Qualcomm'/> + <pvr value='0xc00'/> + <feature name="fp"/> + <feature name="asimd"/> + <feature name="evtstrm"/> + <feature name="aes"/> + <feature name="pmull"/> + <feature name="sha1"/> + <feature name="sha2"/> + <feature name="crc32"/> + <feature name="cpuid"/> + <feature name="asimdrdm"/> + </model> +</cpus> diff --git a/src/cpu_map/arm_Kunpeng-920.xml b/src/cpu_map/arm_Kunpeng-920.xml new file mode 100644 index 0000000000..668b8b50dc --- /dev/null +++ b/src/cpu_map/arm_Kunpeng-920.xml @@ -0,0 +1,24 @@ +<cpus> + <model name='Kunpeng-920'> + <vendor name='HiSilicon'/> + <pvr value='0xd01'/> + <feature name="fp"/> + <feature name="asimd"/> + <feature name="evtstrm"/> + <feature name="aes"/> + <feature name="pmull"/> + <feature name="sha1"/> + <feature name="sha2"/> + <feature name="crc32"/> + <feature name="atomics"/> + <feature name="fphp"/> + <feature name="asimdhp"/> + <feature name="cpuid"/> + <feature name="asimdrdm"/> + <feature name="jscvt"/> + <feature name="fcma"/> + <feature name="dcpop"/> + <feature name="asimddp"/> + <feature name="asimdfhm"/> + </model> +</cpus> diff --git a/src/cpu_map/arm_ThunderX299xx.xml b/src/cpu_map/arm_ThunderX299xx.xml new file mode 100644 index 0000000000..9ab3d939e9 --- /dev/null +++ b/src/cpu_map/arm_ThunderX299xx.xml @@ -0,0 +1,16 @@ +<cpus> + <model name='ThunderX2 99xx'> + <vendor name='Cavium'/> + <pvr value='0x0af'/> + <feature name="fp"/> + <feature name="asimd"/> + <feature name="evtstrm"/> + <feature name="aes"/> + <feature name="pmull"/> + <feature name="sha1"/> + <feature name="sha2"/> + <feature name="crc32"/> + <feature name="cpuid"/> + <feature name="asimdrdm"/> + </model> +</cpus> diff --git a/src/cpu_map/arm_cortex-a53.xml b/src/cpu_map/arm_cortex-a53.xml new file mode 100644 index 0000000000..963d6d36e3 --- /dev/null +++ b/src/cpu_map/arm_cortex-a53.xml @@ -0,0 +1,16 @@ +<cpus> + <model name='cortex-a53'> + <vendor name='ARM'/> + <pvr value='0xd03'/> + <feature name="fp"/> + <feature name="asimd"/> + <feature name="evtstrm"/> + <feature name="aes"/> + <feature name="pmull"/> + <feature name="sha1"/> + <feature name="sha2"/> + <feature name="crc32"/> + <feature name="cpuid"/> + <feature name="asimdrdm"/> + </model> +</cpus> diff --git a/src/cpu_map/arm_cortex-a57.xml b/src/cpu_map/arm_cortex-a57.xml new file mode 100644 index 0000000000..92a044ea92 --- /dev/null +++ b/src/cpu_map/arm_cortex-a57.xml @@ -0,0 +1,15 @@ +<cpus> + <model name='cortex-a57'> + <vendor name='ARM'/> + <pvr value='0xd07'/> + <feature name="fp"/> + <feature name="asimd"/> + <feature name="evtstrm"/> + <feature name="aes"/> + <feature name="pmull"/> + <feature name="sha1"/> + <feature name="sha2"/> + <feature name="crc32"/> + <feature name="cpuid"/> + </model> +</cpus> diff --git a/src/cpu_map/arm_cortex-a72.xml b/src/cpu_map/arm_cortex-a72.xml new file mode 100644 index 0000000000..9664eacd7b --- /dev/null +++ b/src/cpu_map/arm_cortex-a72.xml @@ -0,0 +1,15 @@ +<cpus> + <model name='cortex-a72'> + <vendor name='ARM'/> + <pvr value='0xd08'/> + <feature name="fp"/> + <feature name="asimd"/> + <feature name="evtstrm"/> + <feature name="aes"/> + <feature name="pmull"/> + <feature name="sha1"/> + <feature name="sha2"/> + <feature name="crc32"/> + <feature name="cpuid"/> + </model> +</cpus> diff --git a/src/cpu_map/arm_vendors.xml b/src/cpu_map/arm_vendors.xml new file mode 100644 index 0000000000..703c2112b1 --- /dev/null +++ b/src/cpu_map/arm_vendors.xml @@ -0,0 +1,14 @@ +<cpus> + <vendor name="ARM" value="0x41"/> + <vendor name="Broadcom" value="0x42"/> + <vendor name="Cavium" value="0x43"/> + <vendor name="DigitalEquipment" value="0x44"/> + <vendor name="HiSilicon" value="0x48"/> + <vendor name="Infineon" value="0x49"/> + <vendor name="Freescale" value="0x4D"/> + <vendor name="NVIDIA" value="0x4E"/> + <vendor name="APM" value="0x50"/> + <vendor name="Qualcomm" value="0x51"/> + <vendor name="Marvell" value="0x56"/> + <vendor name="Intel" value="0x69"/> +</cpus> diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml index 50b030de29..20646a031c 100644 --- a/src/cpu_map/index.xml +++ b/src/cpu_map/index.xml @@ -85,6 +85,21 @@ </arch> <arch name='arm'> + <include filename="arm_vendors.xml"/> <include filename='arm_features.xml'/> + + <!-- ARM-based CPU models --> + <include filename="arm_cortex-a53.xml"/> + <include filename="arm_cortex-a57.xml"/> + <include filename="arm_cortex-a72.xml"/> + + <!-- Qualcomm-based CPU models --> + <include filename='arm_Falkor.xml'/> + + <!-- Cavium-based CPU models --> + <include filename='arm_ThunderX299xx.xml'/> + + <!-- Hisilicon-based CPU models --> + <include filename="arm_Kunpeng-920.xml"/> </arch> </cpus> -- 2.26.0.windows.1

On Thu, Apr 02, 2020 at 05:03:51PM +0800, Zhenyu Zheng wrote:
Introduce vendors and some commonly used models for ARM arch, these will be used for virConnectionGetCapabilities for ARM CPUs.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu_map/Makefile.inc.am | 7 +++++++ src/cpu_map/arm_Falkor.xml | 16 ++++++++++++++++ src/cpu_map/arm_Kunpeng-920.xml | 24 ++++++++++++++++++++++++ src/cpu_map/arm_ThunderX299xx.xml | 16 ++++++++++++++++ src/cpu_map/arm_cortex-a53.xml | 16 ++++++++++++++++ src/cpu_map/arm_cortex-a57.xml | 15 +++++++++++++++ src/cpu_map/arm_cortex-a72.xml | 15 +++++++++++++++ src/cpu_map/arm_vendors.xml | 14 ++++++++++++++ src/cpu_map/index.xml | 15 +++++++++++++++ 9 files changed, 138 insertions(+) create mode 100644 src/cpu_map/arm_Falkor.xml create mode 100644 src/cpu_map/arm_Kunpeng-920.xml create mode 100644 src/cpu_map/arm_ThunderX299xx.xml create mode 100644 src/cpu_map/arm_cortex-a53.xml create mode 100644 src/cpu_map/arm_cortex-a57.xml create mode 100644 src/cpu_map/arm_cortex-a72.xml create mode 100644 src/cpu_map/arm_vendors.xml
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Introduce virCPUarmData to virCPUData Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/Makefile.inc.am | 1 + src/cpu/cpu.h | 2 ++ src/cpu/cpu_arm_data.h | 31 +++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/cpu/cpu_arm_data.h diff --git a/src/cpu/Makefile.inc.am b/src/cpu/Makefile.inc.am index 0abeee87b6..bea203fb5c 100644 --- a/src/cpu/Makefile.inc.am +++ b/src/cpu/Makefile.inc.am @@ -10,6 +10,7 @@ CPU_SOURCES = \ cpu/cpu_s390.c \ cpu/cpu_arm.h \ cpu/cpu_arm.c \ + cpu/cpu_arm_data.h \ cpu/cpu_ppc64.h \ cpu/cpu_ppc64.c \ cpu/cpu_ppc64_data.h \ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index f779d2be17..ec22a183a1 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -27,6 +27,7 @@ #include "cpu_conf.h" #include "cpu_x86_data.h" #include "cpu_ppc64_data.h" +#include "cpu_arm_data.h" typedef struct _virCPUData virCPUData; @@ -36,6 +37,7 @@ struct _virCPUData { union { virCPUx86Data x86; virCPUppc64Data ppc64; + virCPUarmData arm; /* generic driver needs no data */ } data; }; diff --git a/src/cpu/cpu_arm_data.h b/src/cpu/cpu_arm_data.h new file mode 100644 index 0000000000..cf12ca8c2e --- /dev/null +++ b/src/cpu/cpu_arm_data.h @@ -0,0 +1,31 @@ +/* + * cpu_arm_data.h: 64-bit arm CPU specific data + * + * Copyright (C) 2020 Huawei Technologies Co., Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#define VIR_CPU_ARM_DATA_INIT { 0 } + +typedef struct _virCPUarmData virCPUarmData; +struct _virCPUarmData { + unsigned long vendor_id; + unsigned long pvr; + char *features; +}; -- 2.26.0.windows.1

On Thu, Apr 02, 2020 at 05:03:53PM +0800, Zhenyu Zheng wrote:
Introduce virCPUarmData to virCPUData
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/Makefile.inc.am | 1 + src/cpu/cpu.h | 2 ++ src/cpu/cpu_arm_data.h | 31 +++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/cpu/cpu_arm_data.h
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Introduce vendor and model struct and related cleanup functions for ARM cpu. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index ee5802198f..c757c24a37 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -1,6 +1,7 @@ /* * cpu_arm.c: CPU driver for arm CPUs * + * Copyright (C) 2020 Huawei Technologies Co., Ltd. * Copyright (C) 2013 Red Hat, Inc. * Copyright (C) Canonical Ltd. 2012 * @@ -23,12 +24,16 @@ #include "viralloc.h" #include "cpu.h" +#include "cpu_arm.h" #include "cpu_map.h" +#include "virlog.h" #include "virstring.h" #include "virxml.h" #define VIR_FROM_THIS VIR_FROM_CPU +VIR_LOG_INIT("cpu.cpu_arm"); + static const virArch archs[] = { VIR_ARCH_ARMV6L, VIR_ARCH_ARMV7B, @@ -36,6 +41,21 @@ static const virArch archs[] = { VIR_ARCH_AARCH64, }; +typedef struct _virCPUarmVendor virCPUarmVendor; +typedef virCPUarmVendor *virCPUarmVendorPtr; +struct _virCPUarmVendor { + char *name; + unsigned long value; +}; + +typedef struct _virCPUarmModel virCPUarmModel; +typedef virCPUarmModel *virCPUarmModelPtr; +struct _virCPUarmModel { + char *name; + virCPUarmVendorPtr vendor; + virCPUarmData data; +}; + typedef struct _virCPUarmFeature virCPUarmFeature; typedef virCPUarmFeature *virCPUarmFeaturePtr; struct _virCPUarmFeature { @@ -64,6 +84,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmFeature, virCPUarmFeatureFree); typedef struct _virCPUarmMap virCPUarmMap; typedef virCPUarmMap *virCPUarmMapPtr; struct _virCPUarmMap { + size_t nvendors; + virCPUarmVendorPtr *vendors; + size_t nmodels; + virCPUarmModelPtr *models; GPtrArray *features; }; @@ -81,12 +105,62 @@ virCPUarmMapNew(void) return map; } +static void +virCPUarmDataClear(virCPUarmData *data) +{ + if (!data) + return; + + VIR_FREE(data->features); +} + +static void +virCPUarmDataFree(virCPUDataPtr cpuData) +{ + if (!cpuData) + return; + + virCPUarmDataClear(&cpuData->data.arm); + VIR_FREE(cpuData); +} + +static void +armModelFree(virCPUarmModelPtr model) +{ + if (!model) + return; + + virCPUarmDataClear(&model->data); + g_free(model->name); + g_free(model); +} + +static void +armVendorFree(virCPUarmVendorPtr vendor) +{ + if (!vendor) + return; + + g_free(vendor->name); + g_free(vendor); +} + static void virCPUarmMapFree(virCPUarmMapPtr map) { if (!map) return; + size_t i; + + for (i = 0; i < map->nmodels; i++) + armModelFree(map->models[i]); + g_free(map->models); + + for (i = 0; i < map->nvendors; i++) + armVendorFree(map->vendors[i]); + g_free(map->vendors); + g_ptr_array_free(map->features, TRUE); g_free(map); @@ -259,6 +333,7 @@ struct cpuArchDriver cpuDriverArm = { .compare = virCPUarmCompare, .decode = NULL, .encode = NULL, + .dataFree = virCPUarmDataFree, .baseline = virCPUarmBaseline, .update = virCPUarmUpdate, .validateFeatures = virCPUarmValidateFeatures, -- 2.26.0.windows.1

On Thu, Apr 02, 2020 at 05:03:55PM +0800, Zhenyu Zheng wrote:
Introduce vendor and model struct and related cleanup functions for ARM cpu.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index ee5802198f..c757c24a37 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -1,6 +1,7 @@ /* * cpu_arm.c: CPU driver for arm CPUs * + * Copyright (C) 2020 Huawei Technologies Co., Ltd. * Copyright (C) 2013 Red Hat, Inc. * Copyright (C) Canonical Ltd. 2012 * @@ -23,12 +24,16 @@
#include "viralloc.h" #include "cpu.h" +#include "cpu_arm.h" #include "cpu_map.h" +#include "virlog.h" #include "virstring.h" #include "virxml.h"
#define VIR_FROM_THIS VIR_FROM_CPU
+VIR_LOG_INIT("cpu.cpu_arm"); + static const virArch archs[] = { VIR_ARCH_ARMV6L, VIR_ARCH_ARMV7B, @@ -36,6 +41,21 @@ static const virArch archs[] = { VIR_ARCH_AARCH64, };
+typedef struct _virCPUarmVendor virCPUarmVendor; +typedef virCPUarmVendor *virCPUarmVendorPtr; +struct _virCPUarmVendor { + char *name; + unsigned long value; +}; + +typedef struct _virCPUarmModel virCPUarmModel; +typedef virCPUarmModel *virCPUarmModelPtr; +struct _virCPUarmModel { + char *name; + virCPUarmVendorPtr vendor; + virCPUarmData data; +}; + typedef struct _virCPUarmFeature virCPUarmFeature; typedef virCPUarmFeature *virCPUarmFeaturePtr; struct _virCPUarmFeature { @@ -64,6 +84,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmFeature, virCPUarmFeatureFree); typedef struct _virCPUarmMap virCPUarmMap; typedef virCPUarmMap *virCPUarmMapPtr; struct _virCPUarmMap { + size_t nvendors; + virCPUarmVendorPtr *vendors; + size_t nmodels; + virCPUarmModelPtr *models; GPtrArray *features; };
@@ -81,12 +105,62 @@ virCPUarmMapNew(void) return map; }
+static void +virCPUarmDataClear(virCPUarmData *data) +{ + if (!data) + return; + + VIR_FREE(data->features); +} + +static void +virCPUarmDataFree(virCPUDataPtr cpuData) +{ + if (!cpuData) + return; + + virCPUarmDataClear(&cpuData->data.arm); + VIR_FREE(cpuData); +} + +static void +armModelFree(virCPUarmModelPtr model)
Normally we want the method name prefix match the struct name eg virCPUarmModelFree()
+{ + if (!model) + return; + + virCPUarmDataClear(&model->data); + g_free(model->name); + g_free(model); +} + +static void +armVendorFree(virCPUarmVendorPtr vendor)
virCPUarmVendorFree()
+{ + if (!vendor) + return; + + g_free(vendor->name); + g_free(vendor); +} +
With those two changes Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Introduce vendor and model struct and related cleanup functions for ARM cpu. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index ee5802198f..d8f571cae3 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -1,6 +1,7 @@ /* * cpu_arm.c: CPU driver for arm CPUs * + * Copyright (C) 2020 Huawei Technologies Co., Ltd. * Copyright (C) 2013 Red Hat, Inc. * Copyright (C) Canonical Ltd. 2012 * @@ -23,12 +24,16 @@ #include "viralloc.h" #include "cpu.h" +#include "cpu_arm.h" #include "cpu_map.h" +#include "virlog.h" #include "virstring.h" #include "virxml.h" #define VIR_FROM_THIS VIR_FROM_CPU +VIR_LOG_INIT("cpu.cpu_arm"); + static const virArch archs[] = { VIR_ARCH_ARMV6L, VIR_ARCH_ARMV7B, @@ -36,6 +41,21 @@ static const virArch archs[] = { VIR_ARCH_AARCH64, }; +typedef struct _virCPUarmVendor virCPUarmVendor; +typedef virCPUarmVendor *virCPUarmVendorPtr; +struct _virCPUarmVendor { + char *name; + unsigned long value; +}; + +typedef struct _virCPUarmModel virCPUarmModel; +typedef virCPUarmModel *virCPUarmModelPtr; +struct _virCPUarmModel { + char *name; + virCPUarmVendorPtr vendor; + virCPUarmData data; +}; + typedef struct _virCPUarmFeature virCPUarmFeature; typedef virCPUarmFeature *virCPUarmFeaturePtr; struct _virCPUarmFeature { @@ -64,6 +84,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmFeature, virCPUarmFeatureFree); typedef struct _virCPUarmMap virCPUarmMap; typedef virCPUarmMap *virCPUarmMapPtr; struct _virCPUarmMap { + size_t nvendors; + virCPUarmVendorPtr *vendors; + size_t nmodels; + virCPUarmModelPtr *models; GPtrArray *features; }; @@ -81,12 +105,62 @@ virCPUarmMapNew(void) return map; } +static void +virCPUarmDataClear(virCPUarmData *data) +{ + if (!data) + return; + + VIR_FREE(data->features); +} + +static void +virCPUarmDataFree(virCPUDataPtr cpuData) +{ + if (!cpuData) + return; + + virCPUarmDataClear(&cpuData->data.arm); + VIR_FREE(cpuData); +} + +static void +virCPUarmModelFree(virCPUarmModelPtr model) +{ + if (!model) + return; + + virCPUarmDataClear(&model->data); + g_free(model->name); + g_free(model); +} + +static void +virCPUarmVendorFree(virCPUarmVendorPtr vendor) +{ + if (!vendor) + return; + + g_free(vendor->name); + g_free(vendor); +} + static void virCPUarmMapFree(virCPUarmMapPtr map) { if (!map) return; + size_t i; + + for (i = 0; i < map->nmodels; i++) + virCPUarmModelFree(map->models[i]); + g_free(map->models); + + for (i = 0; i < map->nvendors; i++) + virCPUarmVendorFree(map->vendors[i]); + g_free(map->vendors); + g_ptr_array_free(map->features, TRUE); g_free(map); @@ -259,6 +333,7 @@ struct cpuArchDriver cpuDriverArm = { .compare = virCPUarmCompare, .decode = NULL, .encode = NULL, + .dataFree = virCPUarmDataFree, .baseline = virCPUarmBaseline, .update = virCPUarmUpdate, .validateFeatures = virCPUarmValidateFeatures, -- 2.26.0.windows.1 On Thu, Apr 9, 2020 at 6:16 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
On Thu, Apr 02, 2020 at 05:03:55PM +0800, Zhenyu Zheng wrote:
Introduce vendor and model struct and related cleanup functions for ARM cpu.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index ee5802198f..c757c24a37 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -1,6 +1,7 @@ /* * cpu_arm.c: CPU driver for arm CPUs * + * Copyright (C) 2020 Huawei Technologies Co., Ltd. * Copyright (C) 2013 Red Hat, Inc. * Copyright (C) Canonical Ltd. 2012 * @@ -23,12 +24,16 @@
#include "viralloc.h" #include "cpu.h" +#include "cpu_arm.h" #include "cpu_map.h" +#include "virlog.h" #include "virstring.h" #include "virxml.h"
#define VIR_FROM_THIS VIR_FROM_CPU
+VIR_LOG_INIT("cpu.cpu_arm"); + static const virArch archs[] = { VIR_ARCH_ARMV6L, VIR_ARCH_ARMV7B, @@ -36,6 +41,21 @@ static const virArch archs[] = { VIR_ARCH_AARCH64, };
+typedef struct _virCPUarmVendor virCPUarmVendor; +typedef virCPUarmVendor *virCPUarmVendorPtr; +struct _virCPUarmVendor { + char *name; + unsigned long value; +}; + +typedef struct _virCPUarmModel virCPUarmModel; +typedef virCPUarmModel *virCPUarmModelPtr; +struct _virCPUarmModel { + char *name; + virCPUarmVendorPtr vendor; + virCPUarmData data; +}; + typedef struct _virCPUarmFeature virCPUarmFeature; typedef virCPUarmFeature *virCPUarmFeaturePtr; struct _virCPUarmFeature { @@ -64,6 +84,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmFeature, virCPUarmFeatureFree); typedef struct _virCPUarmMap virCPUarmMap; typedef virCPUarmMap *virCPUarmMapPtr; struct _virCPUarmMap { + size_t nvendors; + virCPUarmVendorPtr *vendors; + size_t nmodels; + virCPUarmModelPtr *models; GPtrArray *features; };
@@ -81,12 +105,62 @@ virCPUarmMapNew(void) return map; }
+static void +virCPUarmDataClear(virCPUarmData *data) +{ + if (!data) + return; + + VIR_FREE(data->features); +} + +static void +virCPUarmDataFree(virCPUDataPtr cpuData) +{ + if (!cpuData) + return; + + virCPUarmDataClear(&cpuData->data.arm); + VIR_FREE(cpuData); +} + +static void +armModelFree(virCPUarmModelPtr model)
Normally we want the method name prefix match the struct name
eg virCPUarmModelFree()
+{ + if (!model) + return; + + virCPUarmDataClear(&model->data); + g_free(model->name); + g_free(model); +} + +static void +armVendorFree(virCPUarmVendorPtr vendor)
virCPUarmVendorFree()
+{ + if (!vendor) + return; + + g_free(vendor->name); + g_free(vendor); +} +
With those two changes
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Introduce vendor and model struct and related cleanup functions for ARM cpu. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index ee5802198f..d8f571cae3 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -1,6 +1,7 @@ /* * cpu_arm.c: CPU driver for arm CPUs * + * Copyright (C) 2020 Huawei Technologies Co., Ltd. * Copyright (C) 2013 Red Hat, Inc. * Copyright (C) Canonical Ltd. 2012 * @@ -23,12 +24,16 @@ #include "viralloc.h" #include "cpu.h" +#include "cpu_arm.h" #include "cpu_map.h" +#include "virlog.h" #include "virstring.h" #include "virxml.h" #define VIR_FROM_THIS VIR_FROM_CPU +VIR_LOG_INIT("cpu.cpu_arm"); + static const virArch archs[] = { VIR_ARCH_ARMV6L, VIR_ARCH_ARMV7B, @@ -36,6 +41,21 @@ static const virArch archs[] = { VIR_ARCH_AARCH64, }; +typedef struct _virCPUarmVendor virCPUarmVendor; +typedef virCPUarmVendor *virCPUarmVendorPtr; +struct _virCPUarmVendor { + char *name; + unsigned long value; +}; + +typedef struct _virCPUarmModel virCPUarmModel; +typedef virCPUarmModel *virCPUarmModelPtr; +struct _virCPUarmModel { + char *name; + virCPUarmVendorPtr vendor; + virCPUarmData data; +}; + typedef struct _virCPUarmFeature virCPUarmFeature; typedef virCPUarmFeature *virCPUarmFeaturePtr; struct _virCPUarmFeature { @@ -64,6 +84,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmFeature, virCPUarmFeatureFree); typedef struct _virCPUarmMap virCPUarmMap; typedef virCPUarmMap *virCPUarmMapPtr; struct _virCPUarmMap { + size_t nvendors; + virCPUarmVendorPtr *vendors; + size_t nmodels; + virCPUarmModelPtr *models; GPtrArray *features; }; @@ -81,12 +105,62 @@ virCPUarmMapNew(void) return map; } +static void +virCPUarmDataClear(virCPUarmData *data) +{ + if (!data) + return; + + VIR_FREE(data->features); +} + +static void +virCPUarmDataFree(virCPUDataPtr cpuData) +{ + if (!cpuData) + return; + + virCPUarmDataClear(&cpuData->data.arm); + VIR_FREE(cpuData); +} + +static void +virCPUarmModelFree(virCPUarmModelPtr model) +{ + if (!model) + return; + + virCPUarmDataClear(&model->data); + g_free(model->name); + g_free(model); +} + +static void +virCPUarmVendorFree(virCPUarmVendorPtr vendor) +{ + if (!vendor) + return; + + g_free(vendor->name); + g_free(vendor); +} + static void virCPUarmMapFree(virCPUarmMapPtr map) { if (!map) return; + size_t i; + + for (i = 0; i < map->nmodels; i++) + virCPUarmModelFree(map->models[i]); + g_free(map->models); + + for (i = 0; i < map->nvendors; i++) + virCPUarmVendorFree(map->vendors[i]); + g_free(map->vendors); + g_ptr_array_free(map->features, TRUE); g_free(map); @@ -259,6 +333,7 @@ struct cpuArchDriver cpuDriverArm = { .compare = virCPUarmCompare, .decode = NULL, .encode = NULL, + .dataFree = virCPUarmDataFree, .baseline = virCPUarmBaseline, .update = virCPUarmUpdate, .validateFeatures = virCPUarmValidateFeatures, -- 2.26.0.windows.1

Add helper functions to parse vendor and model from xml for ARM arch, and use them as callbacks when load cpu maps. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 176 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index c757c24a37..88b4d91946 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -206,6 +206,178 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED, return 0; } +static virCPUarmVendorPtr +armVendorFindByID(virCPUarmMapPtr map, + unsigned long vendor_id) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (map->vendors[i]->value == vendor_id) + return map->vendors[i]; + } + + return NULL; +} + + +static virCPUarmVendorPtr +armVendorFindByName(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (STREQ(map->vendors[i]->name, name)) + return map->vendors[i]; + } + + return NULL; +} + + +static int +armVendorParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = (virCPUarmMapPtr)data; + virCPUarmVendorPtr vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(vendor) < 0) + return ret; + + vendor->name = g_strdup(name); + + if (armVendorFindByName(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %s already defined"), + vendor->name); + goto cleanup; + } + + if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU vendor value")); + goto cleanup; + } + + if (armVendorFindByID(map, vendor->value)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor value 0x%2lx already defined"), + vendor->value); + goto cleanup; + } + + if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) + goto cleanup; + + ret = 0; + + cleanup: + armVendorFree(vendor); + return ret; + +} + +static virCPUarmModelPtr +armModelFind(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (STREQ(map->models[i]->name, name)) + return map->models[i]; + } + + return NULL; +} + +static virCPUarmModelPtr +armModelFindByPVR(virCPUarmMapPtr map, + unsigned long pvr) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (map->models[i]->data.pvr == pvr) + return map->models[i]; + } + + return NULL; +} + +static int +armModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = (virCPUarmMapPtr)data; + virCPUarmModel *model; + xmlNodePtr *nodes = NULL; + char *vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(model) < 0) + goto error; + + model->name = g_strdup(name); + + if (armModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), + model->name); + goto error; + } + + if (virXPathBoolean("boolean(./vendor)", ctxt)) { + vendor = virXPathString("string(./vendor/@name)", ctxt); + if (!vendor) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid vendor element in CPU model %s"), + model->name); + goto error; + } + + if (!(model->vendor = armVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %s referenced by CPU model %s"), + vendor, model->name); + goto error; + } + } + + if (!virXPathBoolean("boolean(./pvr)", ctxt)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing PVR information for CPU model %s"), + model->name); + goto error; + } + + if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR value in CPU model %s"), + model->name); + goto error; + } + + if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) + goto error; + + ret = 0; + + cleanup: + VIR_FREE(vendor); + VIR_FREE(nodes); + return ret; + + error: + armModelFree(model); + goto cleanup; +} + static virCPUarmMapPtr virCPUarmLoadMap(void) { @@ -213,8 +385,8 @@ virCPUarmLoadMap(void) map = virCPUarmMapNew(); - if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0) - return NULL; + if (cpuMapLoad("arm", armVendorParse, virCPUarmMapFeatureParse, + armModelParse, map) < 0) return g_steal_pointer(&map); } -- 2.26.0.windows.1

On Thu, Apr 02, 2020 at 05:03:57PM +0800, Zhenyu Zheng wrote:
Add helper functions to parse vendor and model from xml for ARM arch, and use them as callbacks when load cpu maps.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 176 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 2 deletions(-)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index c757c24a37..88b4d91946 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -206,6 +206,178 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED, return 0; }
+static virCPUarmVendorPtr +armVendorFindByID(virCPUarmMapPtr map, + unsigned long vendor_id)
As with previous patch, we'd expect the name to be virCPUarmVendorFindByID() and apply same naming scheme for other methods in this patch, so I won't repeat this.
+static int +armVendorParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = (virCPUarmMapPtr)data;
No need for the (virCPUarmMapPtr) cast, as 'void *' will happily cast to any other pointer in C. Only C++ needs the explicit casts.
+ virCPUarmVendorPtr vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(vendor) < 0) + return ret; + + vendor->name = g_strdup(name); + + if (armVendorFindByName(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %s already defined"), + vendor->name); + goto cleanup; + } + + if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU vendor value")); + goto cleanup; + } + + if (armVendorFindByID(map, vendor->value)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor value 0x%2lx already defined"), + vendor->value); + goto cleanup; + } + + if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) + goto cleanup; + + ret = 0; + + cleanup: + armVendorFree(vendor); + return ret; + +}
+static int +armModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = (virCPUarmMapPtr)data;
Again, no need for a cast
+ virCPUarmModel *model; + xmlNodePtr *nodes = NULL;
g_autofree xmlNodePtr *nodes = NULL;
+ char *vendor = NULL;
g_autofree char *vendor = NULL;
+ int ret = -1; + + if (VIR_ALLOC(model) < 0) + goto error; + + model->name = g_strdup(name); + + if (armModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), + model->name); + goto error; + } + + if (virXPathBoolean("boolean(./vendor)", ctxt)) { + vendor = virXPathString("string(./vendor/@name)", ctxt); + if (!vendor) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid vendor element in CPU model %s"), + model->name); + goto error; + } + + if (!(model->vendor = armVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %s referenced by CPU model %s"), + vendor, model->name); + goto error; + } + } + + if (!virXPathBoolean("boolean(./pvr)", ctxt)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing PVR information for CPU model %s"), + model->name); + goto error; + } + + if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR value in CPU model %s"), + model->name); + goto error; + } + + if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) + goto error; + + ret = 0; + + cleanup: + VIR_FREE(vendor); + VIR_FREE(nodes);
...you can drop these two thanks to the g_autofree, as well as the "cleanup:" label and "ret" variable.
+ return ret;
"return 0";
+ + error: + armModelFree(model); + goto cleanup;
...and just "return -1" here instead of goto
+} + static virCPUarmMapPtr virCPUarmLoadMap(void) { @@ -213,8 +385,8 @@ virCPUarmLoadMap(void)
map = virCPUarmMapNew();
- if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0) - return NULL; + if (cpuMapLoad("arm", armVendorParse, virCPUarmMapFeatureParse, + armModelParse, map) < 0)
return g_steal_pointer(&map); } -- 2.26.0.windows.1
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Add helper functions to parse vendor and model from xml for ARM arch, and use them as callbacks when load cpu maps. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 170 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index d8f571cae3..605e7b2d51 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -206,6 +206,172 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED, return 0; } +static virCPUarmVendorPtr +virCPUarmVendorFindByID(virCPUarmMapPtr map, + unsigned long vendor_id) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (map->vendors[i]->value == vendor_id) + return map->vendors[i]; + } + + return NULL; +} + + +static virCPUarmVendorPtr +virCPUarmVendorFindByName(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (STREQ(map->vendors[i]->name, name)) + return map->vendors[i]; + } + + return NULL; +} + + +static int +virCPUarmVendorParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmVendorPtr vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(vendor) < 0) + return ret; + + vendor->name = g_strdup(name); + + if (virCPUarmVendorFindByName(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %s already defined"), + vendor->name); + goto cleanup; + } + + if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU vendor value")); + goto cleanup; + } + + if (virCPUarmVendorFindByID(map, vendor->value)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor value 0x%2lx already defined"), + vendor->value); + goto cleanup; + } + + if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCPUarmVendorFree(vendor); + return ret; + +} + +static virCPUarmModelPtr +virCPUarmModelFind(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (STREQ(map->models[i]->name, name)) + return map->models[i]; + } + + return NULL; +} + +static virCPUarmModelPtr +virCPUarmModelFindByPVR(virCPUarmMapPtr map, + unsigned long pvr) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (map->models[i]->data.pvr == pvr) + return map->models[i]; + } + + return NULL; +} + +static int +virCPUarmModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmModel *model; + g_autofree xmlNodePtr *nodes = NULL; + g_autofree char *vendor = NULL; + + if (VIR_ALLOC(model) < 0) + goto error; + + model->name = g_strdup(name); + + if (virCPUarmModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), + model->name); + goto error; + } + + if (virXPathBoolean("boolean(./vendor)", ctxt)) { + vendor = virXPathString("string(./vendor/@name)", ctxt); + if (!vendor) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid vendor element in CPU model %s"), + model->name); + goto error; + } + + if (!(model->vendor = virCPUarmVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %s referenced by CPU model %s"), + vendor, model->name); + goto error; + } + } + + if (!virXPathBoolean("boolean(./pvr)", ctxt)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing PVR information for CPU model %s"), + model->name); + goto error; + } + + if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR value in CPU model %s"), + model->name); + goto error; + } + + if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) + goto error; + + return 0; + + error: + virCPUarmModelFree(model); + return -1 +} + static virCPUarmMapPtr virCPUarmLoadMap(void) { @@ -213,8 +379,8 @@ virCPUarmLoadMap(void) map = virCPUarmMapNew(); - if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0) - return NULL; + if (cpuMapLoad("arm", virCPUarmVendorParse, virCPUarmMapFeatureParse, + virCPUarmModelParse, map) < 0) return g_steal_pointer(&map); } -- 2.26.0.windows.1

Subject:[PATCH V2 4/5] cpu: Add helper funtions to parse vendor and model Add helper functions to parse vendor and model from xml for ARM arch, and use them as callbacks when load cpu maps. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 171 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 1 deletion(-) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index d8f571cae3..24404eac2c 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -206,6 +206,174 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED, return 0; } +static virCPUarmVendorPtr +virCPUarmVendorFindByID(virCPUarmMapPtr map, + unsigned long vendor_id) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (map->vendors[i]->value == vendor_id) + return map->vendors[i]; + } + + return NULL; +} + + +static virCPUarmVendorPtr +virCPUarmVendorFindByName(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (STREQ(map->vendors[i]->name, name)) + return map->vendors[i]; + } + + return NULL; +} + + +static int +virCPUarmVendorParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmVendorPtr vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(vendor) < 0) + return ret; + + vendor->name = g_strdup(name); + + if (virCPUarmVendorFindByName(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %s already defined"), + vendor->name); + goto cleanup; + } + + if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU vendor value")); + goto cleanup; + } + + if (virCPUarmVendorFindByID(map, vendor->value)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor value 0x%2lx already defined"), + vendor->value); + goto cleanup; + } + + if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCPUarmVendorFree(vendor); + return ret; + +} + +static virCPUarmModelPtr +virCPUarmModelFind(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (STREQ(map->models[i]->name, name)) + return map->models[i]; + } + + return NULL; +} + +#if defined(__aarch64__) +static virCPUarmModelPtr +virCPUarmModelFindByPVR(virCPUarmMapPtr map, + unsigned long pvr) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (map->models[i]->data.pvr == pvr) + return map->models[i]; + } + + return NULL; +} +#endif + +static int +virCPUarmModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmModel *model; + g_autofree xmlNodePtr *nodes = NULL; + g_autofree char *vendor = NULL; + + if (VIR_ALLOC(model) < 0) + goto error; + + model->name = g_strdup(name); + + if (virCPUarmModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), + model->name); + goto error; + } + + if (virXPathBoolean("boolean(./vendor)", ctxt)) { + vendor = virXPathString("string(./vendor/@name)", ctxt); + if (!vendor) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid vendor element in CPU model %s"), + model->name); + goto error; + } + + if (!(model->vendor = virCPUarmVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %s referenced by CPU model %s"), + vendor, model->name); + goto error; + } + } + + if (!virXPathBoolean("boolean(./pvr)", ctxt)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing PVR information for CPU model %s"), + model->name); + goto error; + } + + if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR value in CPU model %s"), + model->name); + goto error; + } + + if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) + goto error; + + return 0; + + error: + virCPUarmModelFree(model); + return -1; +} + static virCPUarmMapPtr virCPUarmLoadMap(void) { @@ -213,7 +381,8 @@ virCPUarmLoadMap(void) map = virCPUarmMapNew(); - if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0) + if (cpuMapLoad("arm", virCPUarmVendorParse, virCPUarmMapFeatureParse, + virCPUarmModelParse, map) < 0) return NULL; return g_steal_pointer(&map); -- 2.26.0.windows.1

Add helper functions to parse vendor and model from xml for ARM arch, and use them as callbacks when load cpu maps.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com>
--- src/cpu/cpu_arm.c | 171 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 1 deletion(-)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index d8f571cae3..24404eac2c 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -206,6 +206,174 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED, return 0; }
+static virCPUarmVendorPtr +virCPUarmVendorFindByID(virCPUarmMapPtr map, + unsigned long vendor_id) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (map->vendors[i]->value == vendor_id) + return map->vendors[i]; + } + + return NULL; +} + + +static virCPUarmVendorPtr +virCPUarmVendorFindByName(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (STREQ(map->vendors[i]->name, name)) + return map->vendors[i]; + } + + return NULL; +} + + +static int +virCPUarmVendorParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmVendorPtr vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(vendor) < 0) + return ret; + + vendor->name = g_strdup(name); + + if (virCPUarmVendorFindByName(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %s already defined"), + vendor->name); + goto cleanup; + } + + if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU vendor value")); + goto cleanup; + } + + if (virCPUarmVendorFindByID(map, vendor->value)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor value 0x%2lx already defined"), + vendor->value); + goto cleanup; + } + + if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCPUarmVendorFree(vendor); + return ret; + +} + +static virCPUarmModelPtr +virCPUarmModelFind(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (STREQ(map->models[i]->name, name)) + return map->models[i]; + } + + return NULL; +} + +#if defined(__aarch64__) +static virCPUarmModelPtr +virCPUarmModelFindByPVR(virCPUarmMapPtr map, + unsigned long pvr) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (map->models[i]->data.pvr == pvr) + return map->models[i]; + } + + return NULL; +} +#endif + +static int +virCPUarmModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmModel *model; + g_autofree xmlNodePtr *nodes = NULL; + g_autofree char *vendor = NULL; + + if (VIR_ALLOC(model) < 0) + goto error; + + model->name = g_strdup(name); + + if (virCPUarmModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), + model->name); + goto error; + } + + if (virXPathBoolean("boolean(./vendor)", ctxt)) { + vendor = virXPathString("string(./vendor/@name)", ctxt); + if (!vendor) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid vendor element in CPU model %s"), + model->name); + goto error; + } + + if (!(model->vendor = virCPUarmVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %s referenced by CPU model %s"), + vendor, model->name); + goto error; + } + } + + if (!virXPathBoolean("boolean(./pvr)", ctxt)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing PVR information for CPU model %s"), + model->name); + goto error; + } + + if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR value in CPU model %s"), + model->name); + goto error; + } + + if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) + goto error; + + return 0; + + error: + virCPUarmModelFree(model); + return -1; +} + static virCPUarmMapPtr virCPUarmLoadMap(void) { @@ -213,7 +381,8 @@ virCPUarmLoadMap(void)
map = virCPUarmMapNew();
- if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0) + if (cpuMapLoad("arm", virCPUarmVendorParse, virCPUarmMapFeatureParse, + virCPUarmModelParse, map) < 0) return NULL;
return g_steal_pointer(&map); -- 2.26.0.windows.1

ping for reviews On Fri, Apr 10, 2020 at 3:58 PM Zhenyu Zheng <zhengzhenyulixi@gmail.com> wrote:
Add helper functions to parse vendor and model from xml for ARM arch, and use them as callbacks when load cpu maps.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com>
--- src/cpu/cpu_arm.c | 171 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 1 deletion(-)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index d8f571cae3..24404eac2c 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -206,6 +206,174 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED, return 0; }
+static virCPUarmVendorPtr +virCPUarmVendorFindByID(virCPUarmMapPtr map, + unsigned long vendor_id) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (map->vendors[i]->value == vendor_id) + return map->vendors[i]; + } + + return NULL; +} + + +static virCPUarmVendorPtr +virCPUarmVendorFindByName(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (STREQ(map->vendors[i]->name, name)) + return map->vendors[i]; + } + + return NULL; +} + + +static int +virCPUarmVendorParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmVendorPtr vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(vendor) < 0) + return ret; + + vendor->name = g_strdup(name); + + if (virCPUarmVendorFindByName(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %s already defined"), + vendor->name); + goto cleanup; + } + + if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU vendor value")); + goto cleanup; + } + + if (virCPUarmVendorFindByID(map, vendor->value)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor value 0x%2lx already defined"), + vendor->value); + goto cleanup; + } + + if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCPUarmVendorFree(vendor); + return ret; + +} + +static virCPUarmModelPtr +virCPUarmModelFind(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (STREQ(map->models[i]->name, name)) + return map->models[i]; + } + + return NULL; +} + +#if defined(__aarch64__) +static virCPUarmModelPtr +virCPUarmModelFindByPVR(virCPUarmMapPtr map, + unsigned long pvr) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (map->models[i]->data.pvr == pvr) + return map->models[i]; + } + + return NULL; +} +#endif + +static int +virCPUarmModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmModel *model; + g_autofree xmlNodePtr *nodes = NULL; + g_autofree char *vendor = NULL; + + if (VIR_ALLOC(model) < 0) + goto error; + + model->name = g_strdup(name); + + if (virCPUarmModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), + model->name); + goto error; + } + + if (virXPathBoolean("boolean(./vendor)", ctxt)) { + vendor = virXPathString("string(./vendor/@name)", ctxt); + if (!vendor) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid vendor element in CPU model %s"), + model->name); + goto error; + } + + if (!(model->vendor = virCPUarmVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %s referenced by CPU model %s"), + vendor, model->name); + goto error; + } + } + + if (!virXPathBoolean("boolean(./pvr)", ctxt)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing PVR information for CPU model %s"), + model->name); + goto error; + } + + if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR value in CPU model %s"), + model->name); + goto error; + } + + if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) + goto error; + + return 0; + + error: + virCPUarmModelFree(model); + return -1; +} + static virCPUarmMapPtr virCPUarmLoadMap(void) { @@ -213,7 +381,8 @@ virCPUarmLoadMap(void)
map = virCPUarmMapNew();
- if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0) + if (cpuMapLoad("arm", virCPUarmVendorParse, virCPUarmMapFeatureParse, + virCPUarmModelParse, map) < 0) return NULL;
return g_steal_pointer(&map); -- 2.26.0.windows.1

From: ZhengZhenyu <zheng.zhenyu@outlook.com> Add helper functions to parse vendor and model from xml for ARM arch, and use them as callbacks when load cpu maps. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 171 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 1 deletion(-) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index d8f571cae3..24404eac2c 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -206,6 +206,174 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED, return 0; } +static virCPUarmVendorPtr +virCPUarmVendorFindByID(virCPUarmMapPtr map, + unsigned long vendor_id) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (map->vendors[i]->value == vendor_id) + return map->vendors[i]; + } + + return NULL; +} + + +static virCPUarmVendorPtr +virCPUarmVendorFindByName(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (STREQ(map->vendors[i]->name, name)) + return map->vendors[i]; + } + + return NULL; +} + + +static int +virCPUarmVendorParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmVendorPtr vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(vendor) < 0) + return ret; + + vendor->name = g_strdup(name); + + if (virCPUarmVendorFindByName(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %s already defined"), + vendor->name); + goto cleanup; + } + + if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU vendor value")); + goto cleanup; + } + + if (virCPUarmVendorFindByID(map, vendor->value)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor value 0x%2lx already defined"), + vendor->value); + goto cleanup; + } + + if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCPUarmVendorFree(vendor); + return ret; + +} + +static virCPUarmModelPtr +virCPUarmModelFind(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (STREQ(map->models[i]->name, name)) + return map->models[i]; + } + + return NULL; +} + +#if defined(__aarch64__) +static virCPUarmModelPtr +virCPUarmModelFindByPVR(virCPUarmMapPtr map, + unsigned long pvr) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (map->models[i]->data.pvr == pvr) + return map->models[i]; + } + + return NULL; +} +#endif + +static int +virCPUarmModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmModel *model; + g_autofree xmlNodePtr *nodes = NULL; + g_autofree char *vendor = NULL; + + if (VIR_ALLOC(model) < 0) + goto error; + + model->name = g_strdup(name); + + if (virCPUarmModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), + model->name); + goto error; + } + + if (virXPathBoolean("boolean(./vendor)", ctxt)) { + vendor = virXPathString("string(./vendor/@name)", ctxt); + if (!vendor) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid vendor element in CPU model %s"), + model->name); + goto error; + } + + if (!(model->vendor = virCPUarmVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %s referenced by CPU model %s"), + vendor, model->name); + goto error; + } + } + + if (!virXPathBoolean("boolean(./pvr)", ctxt)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing PVR information for CPU model %s"), + model->name); + goto error; + } + + if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR value in CPU model %s"), + model->name); + goto error; + } + + if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) + goto error; + + return 0; + + error: + virCPUarmModelFree(model); + return -1; +} + static virCPUarmMapPtr virCPUarmLoadMap(void) { @@ -213,7 +381,8 @@ virCPUarmLoadMap(void) map = virCPUarmMapNew(); - if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0) + if (cpuMapLoad("arm", virCPUarmVendorParse, virCPUarmMapFeatureParse, + virCPUarmModelParse, map) < 0) return NULL; return g_steal_pointer(&map); -- 2.26.0.windows.1

Add helper functions to parse vendor and model from xml for ARM arch, and use them as callbacks when load cpu maps. Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 171 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 1 deletion(-) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index d8f571cae3..24404eac2c 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -206,6 +206,174 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED, return 0; } +static virCPUarmVendorPtr +virCPUarmVendorFindByID(virCPUarmMapPtr map, + unsigned long vendor_id) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (map->vendors[i]->value == vendor_id) + return map->vendors[i]; + } + + return NULL; +} + + +static virCPUarmVendorPtr +virCPUarmVendorFindByName(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nvendors; i++) { + if (STREQ(map->vendors[i]->name, name)) + return map->vendors[i]; + } + + return NULL; +} + + +static int +virCPUarmVendorParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmVendorPtr vendor = NULL; + int ret = -1; + + if (VIR_ALLOC(vendor) < 0) + return ret; + + vendor->name = g_strdup(name); + + if (virCPUarmVendorFindByName(map, vendor->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor %s already defined"), + vendor->name); + goto cleanup; + } + + if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU vendor value")); + goto cleanup; + } + + if (virCPUarmVendorFindByID(map, vendor->value)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU vendor value 0x%2lx already defined"), + vendor->value); + goto cleanup; + } + + if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virCPUarmVendorFree(vendor); + return ret; + +} + +static virCPUarmModelPtr +virCPUarmModelFind(virCPUarmMapPtr map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (STREQ(map->models[i]->name, name)) + return map->models[i]; + } + + return NULL; +} + +#if defined(__aarch64__) +static virCPUarmModelPtr +virCPUarmModelFindByPVR(virCPUarmMapPtr map, + unsigned long pvr) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (map->models[i]->data.pvr == pvr) + return map->models[i]; + } + + return NULL; +} +#endif + +static int +virCPUarmModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPUarmMapPtr map = data; + virCPUarmModel *model; + g_autofree xmlNodePtr *nodes = NULL; + g_autofree char *vendor = NULL; + + if (VIR_ALLOC(model) < 0) + goto error; + + model->name = g_strdup(name); + + if (virCPUarmModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), + model->name); + goto error; + } + + if (virXPathBoolean("boolean(./vendor)", ctxt)) { + vendor = virXPathString("string(./vendor/@name)", ctxt); + if (!vendor) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid vendor element in CPU model %s"), + model->name); + goto error; + } + + if (!(model->vendor = virCPUarmVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %s referenced by CPU model %s"), + vendor, model->name); + goto error; + } + } + + if (!virXPathBoolean("boolean(./pvr)", ctxt)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing PVR information for CPU model %s"), + model->name); + goto error; + } + + if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid PVR value in CPU model %s"), + model->name); + goto error; + } + + if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0) + goto error; + + return 0; + + error: + virCPUarmModelFree(model); + return -1; +} + static virCPUarmMapPtr virCPUarmLoadMap(void) { @@ -213,7 +381,8 @@ virCPUarmLoadMap(void) map = virCPUarmMapNew(); - if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0) + if (cpuMapLoad("arm", virCPUarmVendorParse, virCPUarmMapFeatureParse, + virCPUarmModelParse, map) < 0) return NULL; return g_steal_pointer(&map); -- 2.26.0.windows.1

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

On Thu, Apr 02, 2020 at 05:03:59PM +0800, Zhenyu Zheng wrote:
Introduce getHost support for ARM CPU driver, read CPU vendor_id, part_id and flags from registers directly.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 194 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 88b4d91946..c8f5ce7e8a 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -21,6 +21,8 @@ */
#include <config.h> +#include <asm/hwcap.h> +#include <sys/auxv.h>
#include "viralloc.h" #include "cpu.h" @@ -31,6 +33,10 @@ #include "virxml.h"
#define VIR_FROM_THIS VIR_FROM_CPU +/* Shift bit mask for parsing cpu flags */ +#define BIT_SHIFTS(n) (1UL << (n)) +/* The current max number of cpu flags on ARM is 32 */ +#define MAX_CPU_FLAGS 32
VIR_LOG_INIT("cpu.cpu_arm");
@@ -498,14 +504,200 @@ virCPUarmValidateFeatures(virCPUDefPtr cpu) return 0; }
+/** + * armCpuDataFromRegs: + * + * @data: 64-bit arm CPU specific data + * + * Fetches CPU vendor_id and part_id from MIDR_EL1 register, parse CPU + * flags from AT_HWCAP. There are currently 32 valid flags on ARM arch + * represented by each bit. + */ +static int +armCpuDataFromRegs(virCPUarmData *data)
virCPUarmDataFromRegs()
+{ + /* Generate human readable flag list according to the order of */ + /* AT_HWCAP bit map */ + const char *flag_list[MAX_CPU_FLAGS] = { + "fp", "asimd", "evtstrm", "aes", "pmull", "sha1", "sha2", + "crc32", "atomics", "fphp", "asimdhp", "cpuid", "asimdrdm", + "jscvt", "fcma", "lrcpc", "dcpop", "sha3", "sm3", "sm4", + "asimddp", "sha512", "sve", "asimdfhm", "dit", "uscat", + "ilrcpc", "flagm", "ssbs", "sb", "paca", "pacg"}; + unsigned long cpuid, hwcaps; + char **features = NULL; + char *cpu_feature_str = NULL;
g_autofree
+ int cpu_feature_index = 0; + size_t i; + + if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("CPUID registers unavailable")); + return -1; + }
Indent messed up here
+ + /* read the cpuid data from MIDR_EL1 register */ + asm("mrs %0, MIDR_EL1" : "=r" (cpuid)); + VIR_DEBUG("CPUID read from register: 0x%016lx", cpuid); + + /* parse the coresponding part_id bits */ + data->pvr = cpuid>>4&0xFFF; + /* parse the coresponding vendor_id bits */ + data->vendor_id = cpuid>>24&0xFF; + + hwcaps = getauxval(AT_HWCAP); + VIR_DEBUG("CPU flags read from register: 0x%016lx", hwcaps); + + if (VIR_ALLOC_N(features, MAX_CPU_FLAGS) < 0) + return -1; + + /* shift bit map mask to parse for CPU flags */ + for (i = 0; i< MAX_CPU_FLAGS; i++) { + if (hwcaps & BIT_SHIFTS(i)) { + features[cpu_feature_index] = g_strdup(flag_list[i]); + cpu_feature_index++; + } + }
Indent of } messed up again.
+ + if (cpu_feature_index > 1) { + cpu_feature_str = virStringListJoin((const char **)features, " "); + if (!cpu_feature_str) + goto cleanup; + } + data->features = g_strdup(cpu_feature_str); + + return 0; + + cleanup:
This should be called "error", since this label is only visited for fatal errors.
+ virStringListFree(features); + VIR_FREE(cpu_feature_str);
Can avoid the VIR_FREE with g_autofree.
+ return -1; +}
+ +static int +armCpuDataParseFeatures(virCPUDefPtr cpu, + const virCPUarmData *cpuData)
virCPUarmDataParseFeatures()
+{ + int ret = -1; + size_t i; + char **features; + + if (!cpu || !cpuData) + return ret; + + if (!(features = virStringSplitCount(cpuData->features, " ", + 0, &cpu->nfeatures))) + return ret; + if (cpu->nfeatures) { + if (VIR_ALLOC_N(cpu->features, cpu->nfeatures) < 0) + goto error; + + for (i = 0; i < cpu->nfeatures; i++) { + cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE; + cpu->features[i].name = g_strdup(features[i]); + } + } + + ret = 0; + + cleanup: + virStringListFree(features); + return ret; + + error: + for (i = 0; i < cpu->nfeatures; i++) + VIR_FREE(cpu->features[i].name); + VIR_FREE(cpu->features); + cpu->nfeatures = 0; + goto cleanup; +} + +static int +armDecode(virCPUDefPtr cpu, + const virCPUarmData *cpuData, + virDomainCapsCPUModelsPtr models)
virCPUDataArmDecode
+{ + virCPUarmMapPtr map; + virCPUarmModelPtr model; + virCPUarmVendorPtr vendor = NULL; + + if (!cpuData || !(map = virCPUarmGetMap())) + return -1; + + if (!(model = armModelFindByPVR(map, cpuData->pvr))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU model with PVR 0x%03lx"), + cpuData->pvr); + return -1; + } + + if (!virCPUModelIsAllowed(model->name, models)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU model %s is not supported by hypervisor"), + model->name); + return -1; + } + + cpu->model = g_strdup(model->name); + + if (cpuData->vendor_id && + !(vendor = armVendorFindByID(map, cpuData->vendor_id))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU vendor with vendor id 0x%02lx"), + cpuData->vendor_id); + return -1; + } + + if (vendor) + cpu->vendor = g_strdup(vendor->name); + + if (cpuData->features && + armCpuDataParseFeatures(cpu, cpuData) < 0) + return -1; + + return 0; +} + +static int +armDecodeCPUData(virCPUDefPtr cpu, + const virCPUData *data, + virDomainCapsCPUModelsPtr models)
virCPUarmDecodeCPUData
+{ + return armDecode(cpu, &data->data.arm, models); +} + +static int +virCPUarmGetHost(virCPUDefPtr cpu, + virDomainCapsCPUModelsPtr models) +{ + virCPUDataPtr cpuData = NULL; + int ret = -1; + + if (virCPUarmDriverInitialize() < 0) + goto cleanup; + + if (!(cpuData = virCPUDataNew(archs[0]))) + goto cleanup; + + if (armCpuDataFromRegs(&cpuData->data.arm) < 0) + goto cleanup; + + ret = armDecodeCPUData(cpu, cpuData, models); + + cleanup: + virCPUarmDataFree(cpuData); + return ret; +} + struct cpuArchDriver cpuDriverArm = { .name = "arm", .arch = archs, .narch = G_N_ELEMENTS(archs), .compare = virCPUarmCompare, - .decode = NULL, + .decode = armDecodeCPUData, .encode = NULL, .dataFree = virCPUarmDataFree, + .getHost = virCPUarmGetHost, .baseline = virCPUarmBaseline, .update = virCPUarmUpdate, .validateFeatures = virCPUarmValidateFeatures, -- 2.26.0.windows.1
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Thu, Apr 09, 2020 at 11:28:04 +0100, Daniel P. Berrangé wrote:
On Thu, Apr 02, 2020 at 05:03:59PM +0800, Zhenyu Zheng wrote:
Introduce getHost support for ARM CPU driver, read CPU vendor_id, part_id and flags from registers directly.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 194 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 88b4d91946..c8f5ce7e8a 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -21,6 +21,8 @@ */
#include <config.h> +#include <asm/hwcap.h> +#include <sys/auxv.h>
#include "viralloc.h" #include "cpu.h" @@ -31,6 +33,10 @@ #include "virxml.h"
#define VIR_FROM_THIS VIR_FROM_CPU +/* Shift bit mask for parsing cpu flags */ +#define BIT_SHIFTS(n) (1UL << (n)) +/* The current max number of cpu flags on ARM is 32 */ +#define MAX_CPU_FLAGS 32
VIR_LOG_INIT("cpu.cpu_arm");
@@ -498,14 +504,200 @@ virCPUarmValidateFeatures(virCPUDefPtr cpu) return 0; }
+/** + * armCpuDataFromRegs: + * + * @data: 64-bit arm CPU specific data + * + * Fetches CPU vendor_id and part_id from MIDR_EL1 register, parse CPU + * flags from AT_HWCAP. There are currently 32 valid flags on ARM arch + * represented by each bit. + */ +static int +armCpuDataFromRegs(virCPUarmData *data)
virCPUarmDataFromRegs()
+{ + /* Generate human readable flag list according to the order of */ + /* AT_HWCAP bit map */ + const char *flag_list[MAX_CPU_FLAGS] = { + "fp", "asimd", "evtstrm", "aes", "pmull", "sha1", "sha2", + "crc32", "atomics", "fphp", "asimdhp", "cpuid", "asimdrdm", + "jscvt", "fcma", "lrcpc", "dcpop", "sha3", "sm3", "sm4", + "asimddp", "sha512", "sve", "asimdfhm", "dit", "uscat", + "ilrcpc", "flagm", "ssbs", "sb", "paca", "pacg"}; + unsigned long cpuid, hwcaps; + char **features = NULL; + char *cpu_feature_str = NULL;
g_autofree
+ int cpu_feature_index = 0; + size_t i; + + if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("CPUID registers unavailable")); + return -1; + }
Indent messed up here
+ + /* read the cpuid data from MIDR_EL1 register */ + asm("mrs %0, MIDR_EL1" : "=r" (cpuid)); + VIR_DEBUG("CPUID read from register: 0x%016lx", cpuid); + + /* parse the coresponding part_id bits */ + data->pvr = cpuid>>4&0xFFF; + /* parse the coresponding vendor_id bits */ + data->vendor_id = cpuid>>24&0xFF; + + hwcaps = getauxval(AT_HWCAP); + VIR_DEBUG("CPU flags read from register: 0x%016lx", hwcaps); + + if (VIR_ALLOC_N(features, MAX_CPU_FLAGS) < 0) + return -1; + + /* shift bit map mask to parse for CPU flags */ + for (i = 0; i< MAX_CPU_FLAGS; i++) { + if (hwcaps & BIT_SHIFTS(i)) { + features[cpu_feature_index] = g_strdup(flag_list[i]); + cpu_feature_index++; + } + }
Indent of } messed up again.
+ + if (cpu_feature_index > 1) { + cpu_feature_str = virStringListJoin((const char **)features, " "); + if (!cpu_feature_str) + goto cleanup; + } + data->features = g_strdup(cpu_feature_str); + + return 0; + + cleanup:
This should be called "error", since this label is only visited for fatal errors.
+ virStringListFree(features); + VIR_FREE(cpu_feature_str);
Can avoid the VIR_FREE with g_autofree.
virStringListFree can be avoided too if features is declared with VIR_AUTOSTRINGLIST. Jirka

On Thu, Apr 02, 2020 at 17:03:59 +0800, Zhenyu Zheng wrote:
Introduce getHost support for ARM CPU driver, read CPU vendor_id, part_id and flags from registers directly.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 194 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-)
In addition to all the coding style issues which Daniel pointed out...
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 88b4d91946..c8f5ce7e8a 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -21,6 +21,8 @@ */
#include <config.h> +#include <asm/hwcap.h> +#include <sys/auxv.h>
None of these header files exist on my system with linux 5.6 headers.
#include "viralloc.h" #include "cpu.h" @@ -31,6 +33,10 @@ #include "virxml.h"
#define VIR_FROM_THIS VIR_FROM_CPU +/* Shift bit mask for parsing cpu flags */ +#define BIT_SHIFTS(n) (1UL << (n)) +/* The current max number of cpu flags on ARM is 32 */ +#define MAX_CPU_FLAGS 32
VIR_LOG_INIT("cpu.cpu_arm");
@@ -498,14 +504,200 @@ virCPUarmValidateFeatures(virCPUDefPtr cpu) return 0; }
+/** + * armCpuDataFromRegs: + * + * @data: 64-bit arm CPU specific data + * + * Fetches CPU vendor_id and part_id from MIDR_EL1 register, parse CPU + * flags from AT_HWCAP. There are currently 32 valid flags on ARM arch + * represented by each bit. + */ +static int +armCpuDataFromRegs(virCPUarmData *data) +{ + /* Generate human readable flag list according to the order of */ + /* AT_HWCAP bit map */ + const char *flag_list[MAX_CPU_FLAGS] = { + "fp", "asimd", "evtstrm", "aes", "pmull", "sha1", "sha2", + "crc32", "atomics", "fphp", "asimdhp", "cpuid", "asimdrdm", + "jscvt", "fcma", "lrcpc", "dcpop", "sha3", "sm3", "sm4", + "asimddp", "sha512", "sve", "asimdfhm", "dit", "uscat", + "ilrcpc", "flagm", "ssbs", "sb", "paca", "pacg"};
I would expect these to be defined in src/cpu_map/arm_features.xml, although I'm not sure how well the new features would play with the existing ones... What do you think, Andrea?
+ unsigned long cpuid, hwcaps; + char **features = NULL; + char *cpu_feature_str = NULL; + int cpu_feature_index = 0; + size_t i; + + if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("CPUID registers unavailable")); + return -1; + } + + /* read the cpuid data from MIDR_EL1 register */ + asm("mrs %0, MIDR_EL1" : "=r" (cpuid)); + VIR_DEBUG("CPUID read from register: 0x%016lx", cpuid); + + /* parse the coresponding part_id bits */ + data->pvr = cpuid>>4&0xFFF; + /* parse the coresponding vendor_id bits */ + data->vendor_id = cpuid>>24&0xFF; + + hwcaps = getauxval(AT_HWCAP); + VIR_DEBUG("CPU flags read from register: 0x%016lx", hwcaps); + + if (VIR_ALLOC_N(features, MAX_CPU_FLAGS) < 0) + return -1; + + /* shift bit map mask to parse for CPU flags */ + for (i = 0; i< MAX_CPU_FLAGS; i++) { + if (hwcaps & BIT_SHIFTS(i)) { + features[cpu_feature_index] = g_strdup(flag_list[i]); + cpu_feature_index++; + } + } + + if (cpu_feature_index > 1) { + cpu_feature_str = virStringListJoin((const char **)features, " "); + if (!cpu_feature_str) + goto cleanup; + } + data->features = g_strdup(cpu_feature_str); + + return 0; + + cleanup: + virStringListFree(features); + VIR_FREE(cpu_feature_str); + return -1; +} + +static int +armCpuDataParseFeatures(virCPUDefPtr cpu, + const virCPUarmData *cpuData) +{ + int ret = -1; + size_t i; + char **features; + + if (!cpu || !cpuData) + return ret; + + if (!(features = virStringSplitCount(cpuData->features, " ", + 0, &cpu->nfeatures))) + return ret; + if (cpu->nfeatures) { + if (VIR_ALLOC_N(cpu->features, cpu->nfeatures) < 0) + goto error; + + for (i = 0; i < cpu->nfeatures; i++) { + cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE; + cpu->features[i].name = g_strdup(features[i]); + } + } + + ret = 0; + + cleanup: + virStringListFree(features); + return ret; + + error: + for (i = 0; i < cpu->nfeatures; i++) + VIR_FREE(cpu->features[i].name); + VIR_FREE(cpu->features); + cpu->nfeatures = 0; + goto cleanup; +} + +static int +armDecode(virCPUDefPtr cpu, + const virCPUarmData *cpuData, + virDomainCapsCPUModelsPtr models) +{ + virCPUarmMapPtr map; + virCPUarmModelPtr model; + virCPUarmVendorPtr vendor = NULL; + + if (!cpuData || !(map = virCPUarmGetMap())) + return -1; + + if (!(model = armModelFindByPVR(map, cpuData->pvr))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU model with PVR 0x%03lx"), + cpuData->pvr); + return -1; + } + + if (!virCPUModelIsAllowed(model->name, models)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU model %s is not supported by hypervisor"), + model->name); + return -1; + } + + cpu->model = g_strdup(model->name); + + if (cpuData->vendor_id && + !(vendor = armVendorFindByID(map, cpuData->vendor_id))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU vendor with vendor id 0x%02lx"), + cpuData->vendor_id); + return -1; + } + + if (vendor) + cpu->vendor = g_strdup(vendor->name); + + if (cpuData->features && + armCpuDataParseFeatures(cpu, cpuData) < 0) + return -1; + + return 0; +} + +static int +armDecodeCPUData(virCPUDefPtr cpu, + const virCPUData *data, + virDomainCapsCPUModelsPtr models) +{ + return armDecode(cpu, &data->data.arm, models); +} + +static int +virCPUarmGetHost(virCPUDefPtr cpu, + virDomainCapsCPUModelsPtr models) +{ + virCPUDataPtr cpuData = NULL; + int ret = -1; + + if (virCPUarmDriverInitialize() < 0) + goto cleanup; + + if (!(cpuData = virCPUDataNew(archs[0]))) + goto cleanup; + + if (armCpuDataFromRegs(&cpuData->data.arm) < 0) + goto cleanup; + + ret = armDecodeCPUData(cpu, cpuData, models); + + cleanup: + virCPUarmDataFree(cpuData); + return ret; +}
virCPUarmGetHost and the helpers it calls are architecture specific and should not be even compiled in on non-ARM. Jirka

Hi, Thanks alot for all the reviews, I'm updating the codes, as for those headers, hwcap.h is here: https://github.com/torvalds/linux/blob/v5.6/arch/arm/include/asm/hwcap.h and should be available for 5.6, auxv.h is from glibc: https://sourceware.org/git/?p=glibc.git;a=blob;f=misc/sys/auxv.h;h=1a563e133...
virCPUarmGetHost and the helpers it calls are architecture specific and should not be even compiled in on non-ARM.
yeah, understandable, I just don't see other archs like ppc and s390 doing this so I didn't do it. BR, On Thu, Apr 9, 2020 at 7:03 PM Jiri Denemark <jdenemar@redhat.com> wrote:
On Thu, Apr 02, 2020 at 17:03:59 +0800, Zhenyu Zheng wrote:
Introduce getHost support for ARM CPU driver, read CPU vendor_id, part_id and flags from registers directly.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 194 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-)
In addition to all the coding style issues which Daniel pointed out...
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 88b4d91946..c8f5ce7e8a 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -21,6 +21,8 @@ */
#include <config.h> +#include <asm/hwcap.h> +#include <sys/auxv.h>
None of these header files exist on my system with linux 5.6 headers.
#include "viralloc.h" #include "cpu.h" @@ -31,6 +33,10 @@ #include "virxml.h"
#define VIR_FROM_THIS VIR_FROM_CPU +/* Shift bit mask for parsing cpu flags */ +#define BIT_SHIFTS(n) (1UL << (n)) +/* The current max number of cpu flags on ARM is 32 */ +#define MAX_CPU_FLAGS 32
VIR_LOG_INIT("cpu.cpu_arm");
@@ -498,14 +504,200 @@ virCPUarmValidateFeatures(virCPUDefPtr cpu) return 0; }
+/** + * armCpuDataFromRegs: + * + * @data: 64-bit arm CPU specific data + * + * Fetches CPU vendor_id and part_id from MIDR_EL1 register, parse CPU + * flags from AT_HWCAP. There are currently 32 valid flags on ARM arch + * represented by each bit. + */ +static int +armCpuDataFromRegs(virCPUarmData *data) +{ + /* Generate human readable flag list according to the order of */ + /* AT_HWCAP bit map */ + const char *flag_list[MAX_CPU_FLAGS] = { + "fp", "asimd", "evtstrm", "aes", "pmull", "sha1", "sha2", + "crc32", "atomics", "fphp", "asimdhp", "cpuid", "asimdrdm", + "jscvt", "fcma", "lrcpc", "dcpop", "sha3", "sm3", "sm4", + "asimddp", "sha512", "sve", "asimdfhm", "dit", "uscat", + "ilrcpc", "flagm", "ssbs", "sb", "paca", "pacg"};
I would expect these to be defined in src/cpu_map/arm_features.xml, although I'm not sure how well the new features would play with the existing ones... What do you think, Andrea?
+ unsigned long cpuid, hwcaps; + char **features = NULL; + char *cpu_feature_str = NULL; + int cpu_feature_index = 0; + size_t i; + + if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("CPUID registers unavailable")); + return -1; + } + + /* read the cpuid data from MIDR_EL1 register */ + asm("mrs %0, MIDR_EL1" : "=r" (cpuid)); + VIR_DEBUG("CPUID read from register: 0x%016lx", cpuid); + + /* parse the coresponding part_id bits */ + data->pvr = cpuid>>4&0xFFF; + /* parse the coresponding vendor_id bits */ + data->vendor_id = cpuid>>24&0xFF; + + hwcaps = getauxval(AT_HWCAP); + VIR_DEBUG("CPU flags read from register: 0x%016lx", hwcaps); + + if (VIR_ALLOC_N(features, MAX_CPU_FLAGS) < 0) + return -1; + + /* shift bit map mask to parse for CPU flags */ + for (i = 0; i< MAX_CPU_FLAGS; i++) { + if (hwcaps & BIT_SHIFTS(i)) { + features[cpu_feature_index] = g_strdup(flag_list[i]); + cpu_feature_index++; + } + } + + if (cpu_feature_index > 1) { + cpu_feature_str = virStringListJoin((const char **)features, " "); + if (!cpu_feature_str) + goto cleanup; + } + data->features = g_strdup(cpu_feature_str); + + return 0; + + cleanup: + virStringListFree(features); + VIR_FREE(cpu_feature_str); + return -1; +} + +static int +armCpuDataParseFeatures(virCPUDefPtr cpu, + const virCPUarmData *cpuData) +{ + int ret = -1; + size_t i; + char **features; + + if (!cpu || !cpuData) + return ret; + + if (!(features = virStringSplitCount(cpuData->features, " ", + 0, &cpu->nfeatures))) + return ret; + if (cpu->nfeatures) { + if (VIR_ALLOC_N(cpu->features, cpu->nfeatures) < 0) + goto error; + + for (i = 0; i < cpu->nfeatures; i++) { + cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE; + cpu->features[i].name = g_strdup(features[i]); + } + } + + ret = 0; + + cleanup: + virStringListFree(features); + return ret; + + error: + for (i = 0; i < cpu->nfeatures; i++) + VIR_FREE(cpu->features[i].name); + VIR_FREE(cpu->features); + cpu->nfeatures = 0; + goto cleanup; +} + +static int +armDecode(virCPUDefPtr cpu, + const virCPUarmData *cpuData, + virDomainCapsCPUModelsPtr models) +{ + virCPUarmMapPtr map; + virCPUarmModelPtr model; + virCPUarmVendorPtr vendor = NULL; + + if (!cpuData || !(map = virCPUarmGetMap())) + return -1; + + if (!(model = armModelFindByPVR(map, cpuData->pvr))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU model with PVR 0x%03lx"), + cpuData->pvr); + return -1; + } + + if (!virCPUModelIsAllowed(model->name, models)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU model %s is not supported by hypervisor"), + model->name); + return -1; + } + + cpu->model = g_strdup(model->name); + + if (cpuData->vendor_id && + !(vendor = armVendorFindByID(map, cpuData->vendor_id))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU vendor with vendor id 0x%02lx"), + cpuData->vendor_id); + return -1; + } + + if (vendor) + cpu->vendor = g_strdup(vendor->name); + + if (cpuData->features && + armCpuDataParseFeatures(cpu, cpuData) < 0) + return -1; + + return 0; +} + +static int +armDecodeCPUData(virCPUDefPtr cpu, + const virCPUData *data, + virDomainCapsCPUModelsPtr models) +{ + return armDecode(cpu, &data->data.arm, models); +} + +static int +virCPUarmGetHost(virCPUDefPtr cpu, + virDomainCapsCPUModelsPtr models) +{ + virCPUDataPtr cpuData = NULL; + int ret = -1; + + if (virCPUarmDriverInitialize() < 0) + goto cleanup; + + if (!(cpuData = virCPUDataNew(archs[0]))) + goto cleanup; + + if (armCpuDataFromRegs(&cpuData->data.arm) < 0) + goto cleanup; + + ret = armDecodeCPUData(cpu, cpuData, models); + + cleanup: + virCPUarmDataFree(cpuData); + return ret; +}
virCPUarmGetHost and the helpers it calls are architecture specific and should not be even compiled in on non-ARM.
Jirka

On Thu, Apr 09, 2020 at 07:52:27PM +0800, Zhenyu Zheng wrote:
Hi,
Thanks alot for all the reviews, I'm updating the codes, as for those headers, hwcap.h is here: https://github.com/torvalds/linux/blob/v5.6/arch/arm/include/asm/hwcap.h and should be available for 5.6, auxv.h is from glibc: https://sourceware.org/git/?p=glibc.git;a=blob;f=misc/sys/auxv.h;h=1a563e133...
The key requirement from libvirt is that code must compile against our declared set of supported platforms https://libvirt.org/platforms.html Usually RHEL-7 is the oldest platform that causes trouble. If code can't be made to compile on old platforms, then it is acceptable to use conditional compilation to disable the code. If you want to validate your patches build on all our required platforms, you can take advantage of our recent switch to GitLab Fork the libvirt repo: https://gitlab.com/libvirt/libvirt and push your patches to a branch in your personal fork. This will trigger our automated build CI jobs across all important platforms. As an example here's a recent CI job run: https://gitlab.com/libvirt/libvirt/pipelines/134381772 Note, however, that most of the jobs are using x86, so if you have any conditionally compiled arm code, we don't have good coverage for arm on the old distros, so that may benefit from manual testing.
virCPUarmGetHost and the helpers it calls are architecture specific and should not be even compiled in on non-ARM.
yeah, understandable, I just don't see other archs like ppc and s390 doing this so I didn't do it.
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Thanks for the info, as for ARM testing, we are happy to provide some machines if the community likes. BR, On Thu, Apr 9, 2020 at 8:03 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
On Thu, Apr 09, 2020 at 07:52:27PM +0800, Zhenyu Zheng wrote:
Hi,
Thanks alot for all the reviews, I'm updating the codes, as for those headers, hwcap.h is here: https://github.com/torvalds/linux/blob/v5.6/arch/arm/include/asm/hwcap.h and should be available for 5.6, auxv.h is from glibc:
https://sourceware.org/git/?p=glibc.git;a=blob;f=misc/sys/auxv.h;h=1a563e133...
The key requirement from libvirt is that code must compile against our declared set of supported platforms
https://libvirt.org/platforms.html
Usually RHEL-7 is the oldest platform that causes trouble.
If code can't be made to compile on old platforms, then it is acceptable to use conditional compilation to disable the code.
If you want to validate your patches build on all our required platforms, you can take advantage of our recent switch to GitLab
Fork the libvirt repo:
https://gitlab.com/libvirt/libvirt
and push your patches to a branch in your personal fork. This will trigger our automated build CI jobs across all important platforms.
As an example here's a recent CI job run:
https://gitlab.com/libvirt/libvirt/pipelines/134381772
Note, however, that most of the jobs are using x86, so if you have any conditionally compiled arm code, we don't have good coverage for arm on the old distros, so that may benefit from manual testing.
virCPUarmGetHost and the helpers it calls are architecture specific and should not be even compiled in on non-ARM.
yeah, understandable, I just don't see other archs like ppc and s390 doing this so I didn't do it.
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Thu, 2020-04-09 at 13:03 +0200, Jiri Denemark wrote:
On Thu, Apr 02, 2020 at 17:03:59 +0800, Zhenyu Zheng wrote:
+static int +armCpuDataFromRegs(virCPUarmData *data) +{ + /* Generate human readable flag list according to the order of */ + /* AT_HWCAP bit map */ + const char *flag_list[MAX_CPU_FLAGS] = { + "fp", "asimd", "evtstrm", "aes", "pmull", "sha1", "sha2", + "crc32", "atomics", "fphp", "asimdhp", "cpuid", "asimdrdm", + "jscvt", "fcma", "lrcpc", "dcpop", "sha3", "sm3", "sm4", + "asimddp", "sha512", "sve", "asimdfhm", "dit", "uscat", + "ilrcpc", "flagm", "ssbs", "sb", "paca", "pacg"};
I would expect these to be defined in src/cpu_map/arm_features.xml, although I'm not sure how well the new features would play with the existing ones... What do you think, Andrea?
You tell me :) As you know, the main thing that sets x86 and ARM apart in this area is that on x86 you can basically mix and match CPU features at your heart's content, but on ARM this is not (yet) possible: the only features that you can really control are the SVE-related ones. I assume that, at some point further down the line, it will be possible to control ARM CPU features with a similar level of granularity as it's currently possible on x86, and at that point something like <cpu> <feature name='asimddp' policy='require'/> <feature name='dcpop' policy='disable'/> </cpu> will be possible, but that's certainly not the case now, and attempting to do so for non-SVE features will result in QEMU refusing to start. With that in mind, I don't think it's a problem to include these features in cpu_map upfront and report them in the context of the host CPU: any attempt to use them in guest CPU context will be blocked by QEMU anyway. Perhaps we could go one step further and fail validation in libvirt until such a time comes when QEMU is able to accept them? That would make for a more pleasant user experience, I think. Do you foresee any potential issues caused by this approach? As I said it seems to me like it would be fine, but you're the expert when it comes to the CPU drivers :) -- Andrea Bolognani / Red Hat / Virtualization

Ping for reviews On Fri, Apr 10, 2020 at 5:55 PM Andrea Bolognani <abologna@redhat.com> wrote:
On Thu, 2020-04-09 at 13:03 +0200, Jiri Denemark wrote:
On Thu, Apr 02, 2020 at 17:03:59 +0800, Zhenyu Zheng wrote:
+static int +armCpuDataFromRegs(virCPUarmData *data) +{ + /* Generate human readable flag list according to the order of */ + /* AT_HWCAP bit map */ + const char *flag_list[MAX_CPU_FLAGS] = { + "fp", "asimd", "evtstrm", "aes", "pmull", "sha1", "sha2", + "crc32", "atomics", "fphp", "asimdhp", "cpuid", "asimdrdm", + "jscvt", "fcma", "lrcpc", "dcpop", "sha3", "sm3", "sm4", + "asimddp", "sha512", "sve", "asimdfhm", "dit", "uscat", + "ilrcpc", "flagm", "ssbs", "sb", "paca", "pacg"};
I would expect these to be defined in src/cpu_map/arm_features.xml, although I'm not sure how well the new features would play with the existing ones... What do you think, Andrea?
You tell me :)
As you know, the main thing that sets x86 and ARM apart in this area is that on x86 you can basically mix and match CPU features at your heart's content, but on ARM this is not (yet) possible: the only features that you can really control are the SVE-related ones.
I assume that, at some point further down the line, it will be possible to control ARM CPU features with a similar level of granularity as it's currently possible on x86, and at that point something like
<cpu> <feature name='asimddp' policy='require'/> <feature name='dcpop' policy='disable'/> </cpu>
will be possible, but that's certainly not the case now, and attempting to do so for non-SVE features will result in QEMU refusing to start.
With that in mind, I don't think it's a problem to include these features in cpu_map upfront and report them in the context of the host CPU: any attempt to use them in guest CPU context will be blocked by QEMU anyway.
Perhaps we could go one step further and fail validation in libvirt until such a time comes when QEMU is able to accept them? That would make for a more pleasant user experience, I think.
Do you foresee any potential issues caused by this approach? As I said it seems to me like it would be fine, but you're the expert when it comes to the CPU drivers :)
-- Andrea Bolognani / Red Hat / Virtualization

On Fri, Apr 17, 2020 at 16:53:18 +0800, Zhenyu Zheng wrote:
Ping for reviews
Could you please resend the new version of patches as a separate series (don't forget to update the subject to v3)? Hunting for the new patches hidden in random replies to the reviewers comments or original patches is not exactly easy. And even harder when they use the same subject as version 2. Jirka

Yes, I will do that. On Mon, Apr 20, 2020 at 10:12 PM Jiri Denemark <jdenemar@redhat.com> wrote:
On Fri, Apr 17, 2020 at 16:53:18 +0800, Zhenyu Zheng wrote:
Ping for reviews
Could you please resend the new version of patches as a separate series (don't forget to update the subject to v3)? Hunting for the new patches hidden in random replies to the reviewers comments or original patches is not exactly easy. And even harder when they use the same subject as version 2.
Jirka

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

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

Hi Daniel, Jirka Thanks alot for the review and info, I have updated the code to only compile on aarch64 platform, and I've done the gitlab CI testing as suggested: https://gitlab.com/ZhengZhenyu/libvirt/pipelines/134657317 and manually tested on aarch64. BR, On Fri, Apr 10, 2020 at 4:21 PM ZhengZhenyu <zheng.zhenyu@foxmail.com> wrote:
Introduce getHost support for ARM CPU driver, read CPU vendor_id, part_id and flags from registers directly.
Signed-off-by: Zhenyu Zheng <zhengzhenyulixi@gmail.com> --- src/cpu/cpu_arm.c | 202 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 1 deletion(-)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 24404eac2c..8d6d435bee 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -21,6 +21,10 @@ */
#include <config.h> +#if defined(__aarch64__) +# include <asm/hwcap.h> +# include <sys/auxv.h> +#endif
#include "viralloc.h" #include "cpu.h" @@ -31,6 +35,12 @@ #include "virxml.h"
#define VIR_FROM_THIS VIR_FROM_CPU +#if defined(__aarch64__) +/* Shift bit mask for parsing cpu flags */ +# define BIT_SHIFTS(n) (1UL << (n)) +/* The current max number of cpu flags on ARM is 32 */ +# define MAX_CPU_FLAGS 32 +#endif
VIR_LOG_INIT("cpu.cpu_arm");
@@ -495,13 +505,203 @@ virCPUarmValidateFeatures(virCPUDefPtr cpu) return 0; }
+#if defined(__aarch64__) +/** + * virCPUarmCpuDataFromRegs: + * + * @data: 64-bit arm CPU specific data + * + * Fetches CPU vendor_id and part_id from MIDR_EL1 register, parse CPU + * flags from AT_HWCAP. There are currently 32 valid flags on ARM arch + * represented by each bit. + */ +static int +virCPUarmCpuDataFromRegs(virCPUarmData *data) +{ + /* Generate human readable flag list according to the order of */ + /* AT_HWCAP bit map */ + const char *flag_list[MAX_CPU_FLAGS] = { + "fp", "asimd", "evtstrm", "aes", "pmull", "sha1", "sha2", + "crc32", "atomics", "fphp", "asimdhp", "cpuid", "asimdrdm", + "jscvt", "fcma", "lrcpc", "dcpop", "sha3", "sm3", "sm4", + "asimddp", "sha512", "sve", "asimdfhm", "dit", "uscat", + "ilrcpc", "flagm", "ssbs", "sb", "paca", "pacg"}; + unsigned long cpuid, hwcaps; + char **features = NULL; + g_autofree char *cpu_feature_str = NULL; + int cpu_feature_index = 0; + size_t i; + + if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("CPUID registers unavailable")); + return -1; + } + + /* read the cpuid data from MIDR_EL1 register */ + asm("mrs %0, MIDR_EL1" : "=r" (cpuid)); + VIR_DEBUG("CPUID read from register: 0x%016lx", cpuid); + + /* parse the coresponding part_id bits */ + data->pvr = cpuid>>4&0xFFF; + /* parse the coresponding vendor_id bits */ + data->vendor_id = cpuid>>24&0xFF; + + hwcaps = getauxval(AT_HWCAP); + VIR_DEBUG("CPU flags read from register: 0x%016lx", hwcaps); + + if (VIR_ALLOC_N(features, MAX_CPU_FLAGS) < 0) + return -1; + + /* shift bit map mask to parse for CPU flags */ + for (i = 0; i< MAX_CPU_FLAGS; i++) { + if (hwcaps & BIT_SHIFTS(i)) { + features[cpu_feature_index] = g_strdup(flag_list[i]); + cpu_feature_index++; + } + } + + if (cpu_feature_index > 1) { + cpu_feature_str = virStringListJoin((const char **)features, " "); + if (!cpu_feature_str) + goto error; + } + data->features = g_strdup(cpu_feature_str); + + return 0; + + error: + virStringListFree(features); + return -1; +} + +static int +virCPUarmDataParseFeatures(virCPUDefPtr cpu, + const virCPUarmData *cpuData) +{ + int ret = -1; + size_t i; + char **features; + + if (!cpu || !cpuData) + return ret; + + if (!(features = virStringSplitCount(cpuData->features, " ", + 0, &cpu->nfeatures))) + return ret; + if (cpu->nfeatures) { + if (VIR_ALLOC_N(cpu->features, cpu->nfeatures) < 0) + goto error; + + for (i = 0; i < cpu->nfeatures; i++) { + cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE; + cpu->features[i].name = g_strdup(features[i]); + } + } + + ret = 0; + + cleanup: + virStringListFree(features); + return ret; + + error: + for (i = 0; i < cpu->nfeatures; i++) + VIR_FREE(cpu->features[i].name); + VIR_FREE(cpu->features); + cpu->nfeatures = 0; + goto cleanup; +} + +static int +virCPUarmDecode(virCPUDefPtr cpu, + const virCPUarmData *cpuData, + virDomainCapsCPUModelsPtr models) +{ + virCPUarmMapPtr map; + virCPUarmModelPtr model; + virCPUarmVendorPtr vendor = NULL; + + if (!cpuData || !(map = virCPUarmGetMap())) + return -1; + + if (!(model = virCPUarmModelFindByPVR(map, cpuData->pvr))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU model with PVR 0x%03lx"), + cpuData->pvr); + return -1; + } + + if (!virCPUModelIsAllowed(model->name, models)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU model %s is not supported by hypervisor"), + model->name); + return -1; + } + + cpu->model = g_strdup(model->name); + + if (cpuData->vendor_id && + !(vendor = virCPUarmVendorFindByID(map, cpuData->vendor_id))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU vendor with vendor id 0x%02lx"), + cpuData->vendor_id); + return -1; + } + + if (vendor) + cpu->vendor = g_strdup(vendor->name); + + if (cpuData->features && + virCPUarmDataParseFeatures(cpu, cpuData) < 0) + return -1; + + return 0; +} + +static int +virCPUarmDecodeCPUData(virCPUDefPtr cpu, + const virCPUData *data, + virDomainCapsCPUModelsPtr models) +{ + return virCPUarmDecode(cpu, &data->data.arm, models); +} + +static int +virCPUarmGetHost(virCPUDefPtr cpu, + virDomainCapsCPUModelsPtr models) +{ + virCPUDataPtr cpuData = NULL; + int ret = -1; + + if (virCPUarmDriverInitialize() < 0) + goto cleanup; + + if (!(cpuData = virCPUDataNew(archs[0]))) + goto cleanup; + + if (virCPUarmCpuDataFromRegs(&cpuData->data.arm) < 0) + goto cleanup; + + ret = virCPUarmDecodeCPUData(cpu, cpuData, models); + + cleanup: + virCPUarmDataFree(cpuData); + return ret; +} +#endif + struct cpuArchDriver cpuDriverArm = { .name = "arm", .arch = archs, .narch = G_N_ELEMENTS(archs), .compare = virCPUarmCompare, - .decode = NULL, +#if defined(__aarch64__) + .getHost = virCPUarmGetHost, + .decode = virCPUarmDecodeCPUData, +#else .encode = NULL, +#endif .dataFree = virCPUarmDataFree, .baseline = virCPUarmBaseline, .update = virCPUarmUpdate, -- 2.26.0.windows.1
participants (6)
-
Andrea Bolognani
-
Daniel P. Berrangé
-
Jiri Denemark
-
ZhengZhenyu
-
Zhenyu Zheng
-
Zhenyu Zheng