Re: [PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-05-12 Thread Jiri Denemark
On Wed, Apr 22, 2020 at 15:11:24 +0800, ZhengZhenyu wrote:
> Introduce getHost support for ARM CPU driver, read
> CPU vendor_id, part_id and flags from registers
> directly. These codes will only be compiled on
> aarch64 hardwares.
> 
> Signed-off-by: Zhenyu Zheng 
> ---
>  src/cpu/cpu_arm.c | 204 ++
>  1 file changed, 204 insertions(+)
> 
> diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
> index 6e9ff9bf11..ec50a5615d 100644
> --- a/src/cpu/cpu_arm.c
> +++ b/src/cpu/cpu_arm.c
> @@ -21,6 +21,10 @@
>   */
>  
>  #include 
> +#if defined(__aarch64__)
> +# include 
> +# include 
> +#endif
>  
>  #include "viralloc.h"
>  #include "cpu.h"
> @@ -32,6 +36,15 @@
>  
>  #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");
> +
>  static const virArch archs[] = {
>  VIR_ARCH_ARMV6L,
>  VIR_ARCH_ARMV7B,
> @@ -491,12 +504,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"};

I'd move this array out of the function.

> +unsigned long cpuid, hwcaps;

One variable per line, please.

> +char **features = NULL;

VIR_AUTOSTRINGLIST 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;

Wrong indentation.

> +}
> +
> +/* 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;

Please, add spaces around the operators and consider using () for
clarity. So, I guess:

data->pvr = (cpuid >> 4) & 0xfff;

> +/* parse the coresponding vendor_id bits */
> +data->vendor_id = cpuid>>24&0xFF;

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;

The string list is supposed to be NULL-terminated so you need to
allocate space for MAX_CPU_FLAGS + 1:

features = g_new0(char *, MAX_CPU_FLAGS + 1);

> +
> +/* shift bit map mask to parse for CPU flags */
> +for (i = 0; i< MAX_CPU_FLAGS; i++) {

i < MAX_CPU_FLAGS

> +if (hwcaps & BIT_SHIFTS(i)) {
> +features[cpu_feature_index] = g_strdup(flag_list[i]);
> +cpu_feature_index++;
> +}

This could also be written as

if (hwcaps & BIT_SHIFTS(i))
features[cpu_feature_index++] = g_strdup(flag_list[i]);

it doesn't matter that much, though.

> +}
> +
> +if (cpu_feature_index > 1) {

This would not work for CPUs with exactly one feature.

> +cpu_feature_str = virStringListJoin((const char **)features, " ");
> +if (!cpu_feature_str)
> +goto error;
> +}
> +data->features = g_strdup(cpu_feature_str);

Just store the features string list in the data directly:

if (cpu_feature_index > 0)
data->features = g_steal_pointer();

> +
> +return 0;
> +
> + error:
> +virStringListFree(features);
> +return -1;

This can be dropped thanks to VIR_AUTOSTRINGLIST.

> +}
> +
> +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, >nfeatures)))
> +return ret;

Please don't do this. The virCPUarmData can contain the feature list
directly.

> +if (cpu->nfeatures) {
> +if 

Re: [PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-05-05 Thread Zhenyu Zheng
Thanks for the reply, any updates for the review?

On Wed, Apr 29, 2020 at 11:45 PM Jiri Denemark  wrote:

> Hi.
>
> On Wed, Apr 29, 2020 at 16:03:19 +0800, Zhenyu Zheng wrote:
> > Hi Jiri,
> >
> > Thanks alot for the help, I've updated the series to v4 and also attached
> > pipeline results for each patch as suggested.
>
> I explicitly said you don't have to send a new version just for that
> small issue...
>
> And I don't think pipeline results are needed for each patch, one result
> for the whole series should be enough to assure the code compiles on all
> tested architectures. Reviewers will usually check themselves whether
> the series can be compiled after each patch. I just wanted you to take
> the branch with all the patches and push it to gitlab, which will start
> a single CI pipeline for all the changes (just like in your v3), but the
> branch on gitlab will contain each patch of your series as is (while in
> v3 you squashed all patches into a single commit and pushed that).
>
> That said, all this is mainly a guidance for future submission. It's
> *not* a request for yet another respin of this series.
>
> In the meantime I found two AArch64 hosts with CPUs recognized by your
> changes so I'm playing with them.
>
> Jirka
>


Re: [PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-04-29 Thread Jiri Denemark
Hi.

On Wed, Apr 29, 2020 at 16:03:19 +0800, Zhenyu Zheng wrote:
> Hi Jiri,
> 
> Thanks alot for the help, I've updated the series to v4 and also attached
> pipeline results for each patch as suggested.

I explicitly said you don't have to send a new version just for that
small issue...

And I don't think pipeline results are needed for each patch, one result
for the whole series should be enough to assure the code compiles on all
tested architectures. Reviewers will usually check themselves whether
the series can be compiled after each patch. I just wanted you to take
the branch with all the patches and push it to gitlab, which will start
a single CI pipeline for all the changes (just like in your v3), but the
branch on gitlab will contain each patch of your series as is (while in
v3 you squashed all patches into a single commit and pushed that).

That said, all this is mainly a guidance for future submission. It's
*not* a request for yet another respin of this series.

In the meantime I found two AArch64 hosts with CPUs recognized by your
changes so I'm playing with them.

Jirka



Re: [PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-04-29 Thread Zhenyu Zheng
Hi Jiri,

Thanks alot for the help, I've updated the series to v4 and also attached
pipeline results for each patch as suggested.

BR,

On Tue, Apr 28, 2020 at 7:11 PM Zhenyu Zheng 
wrote:

> Thanks alot I will check again about the patch series.
>
> On Tue, Apr 28, 2020 at 6:39 PM Jiri Denemark  wrote:
>
>> On Wed, Apr 22, 2020 at 15:14:01 +0800, Zhenyu Zheng wrote:
>> >  gitlab CI testing as suggested:
>> > https://gitlab.com/ZhengZhenyu/libvirt/pipelines/134657317
>>
>> Sending results of CI pipeline makes sense only when the code submitted
>> for CI is exactly the same as submitted for review. You should just push
>> the branch with your local changes to your gitlab repo rather than
>> somehow combining all patches you sent into one or even make additional
>> changes.
>>
>> Apparently the patch pushed to gitlab is a bit different than this
>> series as this series cannot be compiled due to a missing "return NULL;"
>> line in patch 4/5.
>>
>> Anyway, I'm trying to get some ARM hosts and hoping to find at least one
>> where your series would actually detect the host CPU to see how this
>> works in real life and to confirm (or not) my suspicions. No need to
>> resent this series to fix the compilation error yet, I'll fix it myself
>> for testing.
>>
>> Thank you for your patience.
>>
>> Jirka
>>
>


Re: [PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-04-28 Thread Zhenyu Zheng
Thanks alot I will check again about the patch series.

On Tue, Apr 28, 2020 at 6:39 PM Jiri Denemark  wrote:

> On Wed, Apr 22, 2020 at 15:14:01 +0800, Zhenyu Zheng wrote:
> >  gitlab CI testing as suggested:
> > https://gitlab.com/ZhengZhenyu/libvirt/pipelines/134657317
>
> Sending results of CI pipeline makes sense only when the code submitted
> for CI is exactly the same as submitted for review. You should just push
> the branch with your local changes to your gitlab repo rather than
> somehow combining all patches you sent into one or even make additional
> changes.
>
> Apparently the patch pushed to gitlab is a bit different than this
> series as this series cannot be compiled due to a missing "return NULL;"
> line in patch 4/5.
>
> Anyway, I'm trying to get some ARM hosts and hoping to find at least one
> where your series would actually detect the host CPU to see how this
> works in real life and to confirm (or not) my suspicions. No need to
> resent this series to fix the compilation error yet, I'll fix it myself
> for testing.
>
> Thank you for your patience.
>
> Jirka
>


Re: [PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-04-28 Thread Jiri Denemark
On Wed, Apr 22, 2020 at 15:14:01 +0800, Zhenyu Zheng wrote:
>  gitlab CI testing as suggested:
> https://gitlab.com/ZhengZhenyu/libvirt/pipelines/134657317

Sending results of CI pipeline makes sense only when the code submitted
for CI is exactly the same as submitted for review. You should just push
the branch with your local changes to your gitlab repo rather than
somehow combining all patches you sent into one or even make additional
changes.

Apparently the patch pushed to gitlab is a bit different than this
series as this series cannot be compiled due to a missing "return NULL;"
line in patch 4/5.

Anyway, I'm trying to get some ARM hosts and hoping to find at least one
where your series would actually detect the host CPU to see how this
works in real life and to confirm (or not) my suspicions. No need to
resent this series to fix the compilation error yet, I'll fix it myself
for testing.

Thank you for your patience.

Jirka



Re: [PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-04-27 Thread Zhenyu Zheng
  ping for reviews

On Wed, Apr 22, 2020 at 3:12 PM ZhengZhenyu 
wrote:

> Introduce getHost support for ARM CPU driver, read
> CPU vendor_id, part_id and flags from registers
> directly. These codes will only be compiled on
> aarch64 hardwares.
>
> Signed-off-by: Zhenyu Zheng 
> ---
>  src/cpu/cpu_arm.c | 204 ++
>  1 file changed, 204 insertions(+)
>
> diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
> index 6e9ff9bf11..ec50a5615d 100644
> --- a/src/cpu/cpu_arm.c
> +++ b/src/cpu/cpu_arm.c
> @@ -21,6 +21,10 @@
>   */
>
>  #include 
> +#if defined(__aarch64__)
> +# include 
> +# include 
> +#endif
>
>  #include "viralloc.h"
>  #include "cpu.h"
> @@ -32,6 +36,15 @@
>
>  #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");
> +
>  static const virArch archs[] = {
>  VIR_ARCH_ARMV6L,
>  VIR_ARCH_ARMV7B,
> @@ -491,12 +504,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, >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))) {
> +

Re: [PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-04-22 Thread Zhenyu Zheng
 gitlab CI testing as suggested:
https://gitlab.com/ZhengZhenyu/libvirt/pipelines/134657317

On Wed, Apr 22, 2020 at 3:12 PM ZhengZhenyu 
wrote:

> Introduce getHost support for ARM CPU driver, read
> CPU vendor_id, part_id and flags from registers
> directly. These codes will only be compiled on
> aarch64 hardwares.
>
> Signed-off-by: Zhenyu Zheng 
> ---
>  src/cpu/cpu_arm.c | 204 ++
>  1 file changed, 204 insertions(+)
>
> diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
> index 6e9ff9bf11..ec50a5615d 100644
> --- a/src/cpu/cpu_arm.c
> +++ b/src/cpu/cpu_arm.c
> @@ -21,6 +21,10 @@
>   */
>
>  #include 
> +#if defined(__aarch64__)
> +# include 
> +# include 
> +#endif
>
>  #include "viralloc.h"
>  #include "cpu.h"
> @@ -32,6 +36,15 @@
>
>  #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");
> +
>  static const virArch archs[] = {
>  VIR_ARCH_ARMV6L,
>  VIR_ARCH_ARMV7B,
> @@ -491,12 +504,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, >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;
> +
> +

[PATCH V3 5/5] cpu: Introduce getHost support for ARM CPU driver

2020-04-22 Thread ZhengZhenyu
Introduce getHost support for ARM CPU driver, read
CPU vendor_id, part_id and flags from registers
directly. These codes will only be compiled on
aarch64 hardwares.

Signed-off-by: Zhenyu Zheng 
---
 src/cpu/cpu_arm.c | 204 ++
 1 file changed, 204 insertions(+)

diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index 6e9ff9bf11..ec50a5615d 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -21,6 +21,10 @@
  */
 
 #include 
+#if defined(__aarch64__)
+# include 
+# include 
+#endif
 
 #include "viralloc.h"
 #include "cpu.h"
@@ -32,6 +36,15 @@
 
 #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");
+
 static const virArch archs[] = {
 VIR_ARCH_ARMV6L,
 VIR_ARCH_ARMV7B,
@@ -491,12 +504,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, >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"),
+