diff mbox

[V1,1/1] arm64: Add an option to turn on/off host-backed vPMU support

Message ID 1471067570-7503-1-git-send-email-wei@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Wei Huang Aug. 13, 2016, 5:52 a.m. UTC
This patch adds a pmu=[on/off] option to enable/disable host vPMU
support in guest VM. There are several reasons to justify this option.
First, host-backed vPMU can be problematic for cross-migration between
different SoC as perf counters are architecture-dependent. It is more
flexible to have an option to turn it on/off. Secondly this option
matches the "pmu" option as supported in libvirt tool.

Note that, like "has_el3", the "pmu" option is only made available on
CPUs that support host-backed vPMU. They include:
    * cortex-a53 + kvm
    * cortex-a57 + kvm
    * host + kvm
This option is removed in other configs where it doesn't make sense
(e.g. cortex-a57 + TCG); and the default pmu support is off. This patch
has been tested under both DT/ACPI modes.

Signed-off-by: Wei Huang <wei@redhat.com>
---
 hw/arm/virt-acpi-build.c |  2 +-
 hw/arm/virt.c            |  2 +-
 target-arm/cpu.c         | 13 +++++++++++++
 target-arm/cpu.h         |  3 ++-
 target-arm/cpu64.c       |  6 ++++++
 target-arm/kvm64.c       | 10 +++++-----
 6 files changed, 28 insertions(+), 8 deletions(-)

Comments

Andrea Bolognani Aug. 15, 2016, 9:31 a.m. UTC | #1
On Sat, 2016-08-13 at 00:52 -0500, Wei Huang wrote:
> This patch adds a pmu=[on/off] option to enable/disable host vPMU
> support in guest VM. There are several reasons to justify this option.
> First, host-backed vPMU can be problematic for cross-migration between
> different SoC as perf counters are architecture-dependent. It is more
> flexible to have an option to turn it on/off. Secondly this option
> matches the "pmu" option as supported in libvirt tool.

> Note that, like "has_el3", the "pmu" option is only made available on
> CPUs that support host-backed vPMU. They include:
>     * cortex-a53 + kvm
>     * cortex-a57 + kvm
>     * host + kvm
> This option is removed in other configs where it doesn't make sense
> (e.g. cortex-a57 + TCG); and the default pmu support is off. This patch
> has been tested under both DT/ACPI modes.

> Signed-off-by: Wei Huang <wei@redhat.com>
> ---
>  hw/arm/virt-acpi-build.c |  2 +-
>  hw/arm/virt.c            |  2 +-
>  target-arm/cpu.c         | 13 +++++++++++++
>  target-arm/cpu.h         |  3 ++-
>  target-arm/cpu64.c       |  6 ++++++
>  target-arm/kvm64.c       | 10 +++++-----
>  6 files changed, 28 insertions(+), 8 deletions(-)

Did you already try driving this with libvirt? It should work
out of the box.

If you haven't, I will do it :)

-- 
Andrea Bolognani / Red Hat / Virtualization
Andrew Jones Aug. 15, 2016, 10:09 a.m. UTC | #2
On Sat, Aug 13, 2016 at 12:52:50AM -0500, Wei Huang wrote:
> This patch adds a pmu=[on/off] option to enable/disable host vPMU
> support in guest VM. There are several reasons to justify this option.
> First, host-backed vPMU can be problematic for cross-migration between
> different SoC as perf counters are architecture-dependent. It is more
> flexible to have an option to turn it on/off. Secondly this option
> matches the "pmu" option as supported in libvirt tool.
> 
> Note that, like "has_el3", the "pmu" option is only made available on
> CPUs that support host-backed vPMU. They include:
>     * cortex-a53 + kvm
>     * cortex-a57 + kvm
>     * host + kvm
> This option is removed in other configs where it doesn't make sense
> (e.g. cortex-a57 + TCG); and the default pmu support is off. This patch

Some of the PMU registers are already emulated with TCG. While it
doesn't make much sense to use perf counters in a TCG guest for
measuring anything, it may have merit for emulation completeness
and debug. With that in mind, then I think we need to add the PMU
feature to all processors that support it, and thus the 'has_pmu'
name is better. As the feature is optional, I agree it does make
sense that it's off by default, and only available with the pmu=on
property.

I think there are more processors than just A53 and A57.

> has been tested under both DT/ACPI modes.
> 
> Signed-off-by: Wei Huang <wei@redhat.com>
> ---
>  hw/arm/virt-acpi-build.c |  2 +-
>  hw/arm/virt.c            |  2 +-
>  target-arm/cpu.c         | 13 +++++++++++++
>  target-arm/cpu.h         |  3 ++-
>  target-arm/cpu64.c       |  6 ++++++
>  target-arm/kvm64.c       | 10 +++++-----
>  6 files changed, 28 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 28fc59c..22fb9d9 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -540,7 +540,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
>          gicc->uid = i;
>          gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
>  
> -        if (armcpu->has_pmu) {
> +        if (armcpu->has_host_pmu) {
>              gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
>          }
>      }
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index a193b5a..4975f38 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -477,7 +477,7 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
>  
>      CPU_FOREACH(cpu) {
>          armcpu = ARM_CPU(cpu);
> -        if (!armcpu->has_pmu ||
> +        if (!armcpu->has_host_pmu ||
>              !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ))) {
>              return;
>          }
> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> index ce8b8f4..a527128 100644
> --- a/target-arm/cpu.c
> +++ b/target-arm/cpu.c
> @@ -509,6 +509,10 @@ static Property arm_cpu_rvbar_property =
>  static Property arm_cpu_has_el3_property =
>              DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
>  
> +/* use property name "pmu" to match with other archs and libvirt */
> +static Property arm_cpu_has_host_pmu_property =
> +    DEFINE_PROP_BOOL("pmu", ARMCPU, has_host_pmu, false);
> +
>  static Property arm_cpu_has_mpu_property =
>              DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
>  
> @@ -552,6 +556,11 @@ static void arm_cpu_post_init(Object *obj)
>  #endif
>      }
>  
> +    if (arm_feature(&cpu->env, ARM_FEATURE_HOST_PMU)) {
> +        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_host_pmu_property,
> +                                 &error_abort);
> +    }
> +
>      if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
>          qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
>                                   &error_abort);
> @@ -648,6 +657,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>          cpu->id_aa64pfr0 &= ~0xf000;
>      }
>  
> +    if (!cpu->has_host_pmu) {
> +        unset_feature(env, ARM_FEATURE_HOST_PMU);
> +    }

I think this is the right approach. But we should add the feature to all
processors that can have it, and then, after checking the property's
value, we remove it when it's not desired.

> +
>      if (!arm_feature(env, ARM_FEATURE_EL2)) {
>          /* Disable the hypervisor feature bits in the processor feature
>           * registers if we don't have EL2. These are id_pfr1[15:12] and
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 76d824d..f3f6d3f 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -580,7 +580,7 @@ struct ARMCPU {
>      /* CPU has security extension */
>      bool has_el3;
>      /* CPU has PMU (Performance Monitor Unit) */
> -    bool has_pmu;
> +    bool has_host_pmu;
>  
>      /* CPU has memory protection unit */
>      bool has_mpu;
> @@ -1129,6 +1129,7 @@ enum arm_features {
>      ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */
>      ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */
>      ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
> +    ARM_FEATURE_HOST_PMU, /* PMU supported by host */
>  };
>  
>  static inline int arm_feature(CPUARMState *env, int feature)
> diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
> index 1635deb..19e8127 100644
> --- a/target-arm/cpu64.c
> +++ b/target-arm/cpu64.c
> @@ -111,6 +111,9 @@ static void aarch64_a57_initfn(Object *obj)
>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>      set_feature(&cpu->env, ARM_FEATURE_EL3);
> +    if (kvm_enabled()) {
> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
> +    }

We shouldn't need the if (kvm_enabled()) here.

>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
>      cpu->midr = 0x411fd070;
>      cpu->revidr = 0x00000000;
> @@ -166,6 +169,9 @@ static void aarch64_a53_initfn(Object *obj)
>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>      set_feature(&cpu->env, ARM_FEATURE_EL3);
> +    if (kvm_enabled()) {
> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
> +    }

Or here.

>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
>      cpu->midr = 0x410fd034;
>      cpu->revidr = 0x00000000;
> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
> index 5faa76c..588e5e3 100644
> --- a/target-arm/kvm64.c
> +++ b/target-arm/kvm64.c
> @@ -469,6 +469,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
>      set_feature(&features, ARM_FEATURE_VFP4);
>      set_feature(&features, ARM_FEATURE_NEON);
>      set_feature(&features, ARM_FEATURE_AARCH64);
> +    set_feature(&features, ARM_FEATURE_HOST_PMU);
>  
>      ahcc->features = features;
>  
> @@ -501,11 +502,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
>      if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
>          cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
>      }
> -    if (kvm_irqchip_in_kernel() &&
> -        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
> -        cpu->has_pmu = true;
> -        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
> -    }
> +    /* enable vPMU based on KVM mode, hw capability, and user setting */
> +    cpu->has_host_pmu &= kvm_irqchip_in_kernel() &&
> +        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3);
> +    cpu->kvm_init_features[0] |= cpu->has_host_pmu << KVM_ARM_VCPU_PMU_V3;

Hmm... so now if the user doesn't specify pmu=on (off by default) then we
silently disable it (I think that's a 2.6 compat issue), and if they do
specify pmu=on, but KVM doesn't support it, then it's silently disabled,
which isn't nice. I think QEMU should error out in that case, explaining
that the user specified incompatible options, i.e. they selected accel=kvm
and pmu=on, but their KVM version (or cpu model) doesn't support PMU
emulation.

>  
>      /* Do KVM_ARM_VCPU_INIT ioctl */
>      ret = kvm_arm_vcpu_init(cs);
> -- 
> 2.4.11
> 
>

Thanks,
drew
Wei Huang Aug. 15, 2016, 4:12 p.m. UTC | #3
On 8/15/16 04:31, Andrea Bolognani wrote:
> 
> On Sat, 2016-08-13 at 00:52 -0500, Wei Huang wrote:
>> This patch adds a pmu=[on/off] option to enable/disable host vPMU
>> support in guest VM. There are several reasons to justify this option.
>> First, host-backed vPMU can be problematic for cross-migration between
>> different SoC as perf counters are architecture-dependent. It is more
>> flexible to have an option to turn it on/off. Secondly this option
>> matches the "pmu" option as supported in libvirt tool.
>>  
>> Note that, like "has_el3", the "pmu" option is only made available on
>> CPUs that support host-backed vPMU. They include:
>>      * cortex-a53 + kvm
>>      * cortex-a57 + kvm
>>      * host + kvm
>> This option is removed in other configs where it doesn't make sense
>> (e.g. cortex-a57 + TCG); and the default pmu support is off. This patch
>> has been tested under both DT/ACPI modes.
>>  
>> Signed-off-by: Wei Huang <wei@redhat.com>
>> ---
>>   hw/arm/virt-acpi-build.c |  2 +-
>>   hw/arm/virt.c            |  2 +-
>>   target-arm/cpu.c         | 13 +++++++++++++
>>   target-arm/cpu.h         |  3 ++-
>>   target-arm/cpu64.c       |  6 ++++++
>>   target-arm/kvm64.c       | 10 +++++-----
>>   6 files changed, 28 insertions(+), 8 deletions(-)
> 
> Did you already try driving this with libvirt? It should work
> out of the box.
> 
> If you haven't, I will do it :)

No, I haven't. All tests were done based on command line to QEMU. :-)

-Wei

> 
> -- 
> Andrea Bolognani / Red Hat / Virtualization
>
Peter Maydell Aug. 15, 2016, 4:13 p.m. UTC | #4
On 13 August 2016 at 06:52, Wei Huang <wei@redhat.com> wrote:
> This patch adds a pmu=[on/off] option to enable/disable host vPMU
> support in guest VM. There are several reasons to justify this option.
> First, host-backed vPMU can be problematic for cross-migration between
> different SoC as perf counters are architecture-dependent. It is more
> flexible to have an option to turn it on/off. Secondly this option
> matches the "pmu" option as supported in libvirt tool.
>
> Note that, like "has_el3", the "pmu" option is only made available on
> CPUs that support host-backed vPMU. They include:
>     * cortex-a53 + kvm
>     * cortex-a57 + kvm
>     * host + kvm
> This option is removed in other configs where it doesn't make sense
> (e.g. cortex-a57 + TCG); and the default pmu support is off. This patch
> has been tested under both DT/ACPI modes.
>
> Signed-off-by: Wei Huang <wei@redhat.com>
> ---
>  hw/arm/virt-acpi-build.c |  2 +-
>  hw/arm/virt.c            |  2 +-
>  target-arm/cpu.c         | 13 +++++++++++++
>  target-arm/cpu.h         |  3 ++-
>  target-arm/cpu64.c       |  6 ++++++
>  target-arm/kvm64.c       | 10 +++++-----
>  6 files changed, 28 insertions(+), 8 deletions(-)
>
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 28fc59c..22fb9d9 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -540,7 +540,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
>          gicc->uid = i;
>          gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
>
> -        if (armcpu->has_pmu) {
> +        if (armcpu->has_host_pmu) {
>              gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
>          }
>      }
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index a193b5a..4975f38 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -477,7 +477,7 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
>
>      CPU_FOREACH(cpu) {
>          armcpu = ARM_CPU(cpu);
> -        if (!armcpu->has_pmu ||
> +        if (!armcpu->has_host_pmu ||
>              !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ))) {
>              return;
>          }
> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> index ce8b8f4..a527128 100644
> --- a/target-arm/cpu.c
> +++ b/target-arm/cpu.c
> @@ -509,6 +509,10 @@ static Property arm_cpu_rvbar_property =
>  static Property arm_cpu_has_el3_property =
>              DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
>
> +/* use property name "pmu" to match with other archs and libvirt */
> +static Property arm_cpu_has_host_pmu_property =
> +    DEFINE_PROP_BOOL("pmu", ARMCPU, has_host_pmu, false);
> +
>  static Property arm_cpu_has_mpu_property =
>              DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
>
> @@ -552,6 +556,11 @@ static void arm_cpu_post_init(Object *obj)
>  #endif
>      }
>
> +    if (arm_feature(&cpu->env, ARM_FEATURE_HOST_PMU)) {
> +        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_host_pmu_property,
> +                                 &error_abort);
> +    }
> +
>      if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
>          qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
>                                   &error_abort);
> @@ -648,6 +657,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>          cpu->id_aa64pfr0 &= ~0xf000;
>      }
>
> +    if (!cpu->has_host_pmu) {
> +        unset_feature(env, ARM_FEATURE_HOST_PMU);
> +    }
> +
>      if (!arm_feature(env, ARM_FEATURE_EL2)) {
>          /* Disable the hypervisor feature bits in the processor feature
>           * registers if we don't have EL2. These are id_pfr1[15:12] and
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 76d824d..f3f6d3f 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -580,7 +580,7 @@ struct ARMCPU {
>      /* CPU has security extension */
>      bool has_el3;
>      /* CPU has PMU (Performance Monitor Unit) */
> -    bool has_pmu;
> +    bool has_host_pmu;

Can you explain why you renamed this? "has_pmu" matches
the comment: it indicates that the emulated CPU has a PMU.
has_host_pmu would be something different (and would only
apply to KVM). It also looks weird in the code in the board
model: we should be saying "if the guest CPU has a PMU, wire
up its interrupt", not "if the host CPU has a PMU, wire
up a guest CPU interrupt".

>
>      /* CPU has memory protection unit */
>      bool has_mpu;
> @@ -1129,6 +1129,7 @@ enum arm_features {
>      ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */
>      ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */
>      ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
> +    ARM_FEATURE_HOST_PMU, /* PMU supported by host */

ARM_FEATURE_ bits are for guest CPU features, not for
recording information about the host CPU.

>  };
>
>  static inline int arm_feature(CPUARMState *env, int feature)
> diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
> index 1635deb..19e8127 100644
> --- a/target-arm/cpu64.c
> +++ b/target-arm/cpu64.c
> @@ -111,6 +111,9 @@ static void aarch64_a57_initfn(Object *obj)
>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>      set_feature(&cpu->env, ARM_FEATURE_EL3);
> +    if (kvm_enabled()) {
> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
> +    }
>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
>      cpu->midr = 0x411fd070;
>      cpu->revidr = 0x00000000;
> @@ -166,6 +169,9 @@ static void aarch64_a53_initfn(Object *obj)
>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>      set_feature(&cpu->env, ARM_FEATURE_EL3);
> +    if (kvm_enabled()) {
> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
> +    }

This definitely looks like the wrong place to be checking
kvm_enabled().

>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
>      cpu->midr = 0x410fd034;
>      cpu->revidr = 0x00000000;
> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
> index 5faa76c..588e5e3 100644
> --- a/target-arm/kvm64.c
> +++ b/target-arm/kvm64.c
> @@ -469,6 +469,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
>      set_feature(&features, ARM_FEATURE_VFP4);
>      set_feature(&features, ARM_FEATURE_NEON);
>      set_feature(&features, ARM_FEATURE_AARCH64);
> +    set_feature(&features, ARM_FEATURE_HOST_PMU);
>
>      ahcc->features = features;
>
> @@ -501,11 +502,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
>      if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
>          cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
>      }
> -    if (kvm_irqchip_in_kernel() &&
> -        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
> -        cpu->has_pmu = true;
> -        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
> -    }
> +    /* enable vPMU based on KVM mode, hw capability, and user setting */
> +    cpu->has_host_pmu &= kvm_irqchip_in_kernel() &&
> +        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3);
> +    cpu->kvm_init_features[0] |= cpu->has_host_pmu << KVM_ARM_VCPU_PMU_V3;
>
>      /* Do KVM_ARM_VCPU_INIT ioctl */
>      ret = kvm_arm_vcpu_init(cs);
> --
> 2.4.11
>

thanks
-- PMM
Andrea Bolognani Aug. 15, 2016, 4:59 p.m. UTC | #5
On Mon, 2016-08-15 at 12:09 +0200, Andrew Jones wrote:
> Hmm... so now if the user doesn't specify pmu=on (off by default) then we
> silently disable it (I think that's a 2.6 compat issue), and if they do
> specify pmu=on, but KVM doesn't support it, then it's silently disabled,
> which isn't nice. I think QEMU should error out in that case, explaining
> that the user specified incompatible options, i.e. they selected accel=kvm
> and pmu=on, but their KVM version (or cpu model) doesn't support PMU
> emulation.

I agree. Asking qemu to provide a feature that it can't provide
should definitely result in a big fat error.

-- 
Andrea Bolognani / Red Hat / Virtualization
Andrea Bolognani Aug. 15, 2016, 5:24 p.m. UTC | #6
On Mon, 2016-08-15 at 11:12 -0500, Wei Huang wrote:
> > Did you already try driving this with libvirt? It should work
> > out of the box.
> > 
> > If you haven't, I will do it :)

> No, I haven't. All tests were done based on command line to QEMU. :-)

Fair enough :)

I did some testing on my own using libvirt to drive a QEMU
binary that included your patch, and it looks like everything
is working as expected: if I turn PMU on using the appropriate
XML element (<pmu state='on'/>) I can access the performance
counters from inside the guest; if I disable it explicitly or
don't enable it, I can't.

The host-side testing involved making sure the 'pmu' flag
was passed, or not passed, to QEMU and the value, if any,
matched the guest XML.

The guest-side testing involved running

  $ dmesg | grep -i pmu
  $ perf list | grep 'Hardware event'

and making sure some output was returned in both cases, and
making sure the 'instructions' counter was not marked as '<not
supported>' in the output of

  $ perf stat true

If the kind of testing I performed is not good enough, please
let me know and I'll do another round.

This was tested only with <cpu mode='host-passthrough'/> (the
libvirt equivalent of -cpu host), because the aarch64 CPU
driver in libvirt is not currently capable of handling other
CPU models for KVM guests.

I also verified that TCG guests didn't accept the 'pmu' flag.

-- 
Andrea Bolognani / Red Hat / Virtualization
Wei Huang Aug. 15, 2016, 9:05 p.m. UTC | #7
On 08/15/2016 05:09 AM, Andrew Jones wrote:
> On Sat, Aug 13, 2016 at 12:52:50AM -0500, Wei Huang wrote:
>> This patch adds a pmu=[on/off] option to enable/disable host vPMU
>> support in guest VM. There are several reasons to justify this option.
>> First, host-backed vPMU can be problematic for cross-migration between
>> different SoC as perf counters are architecture-dependent. It is more
>> flexible to have an option to turn it on/off. Secondly this option
>> matches the "pmu" option as supported in libvirt tool.
>>
>> Note that, like "has_el3", the "pmu" option is only made available on
>> CPUs that support host-backed vPMU. They include:
>>     * cortex-a53 + kvm
>>     * cortex-a57 + kvm
>>     * host + kvm
>> This option is removed in other configs where it doesn't make sense
>> (e.g. cortex-a57 + TCG); and the default pmu support is off. This patch
> 
> Some of the PMU registers are already emulated with TCG. While it
> doesn't make much sense to use perf counters in a TCG guest for
> measuring anything, it may have merit for emulation completeness
> and debug. With that in mind, then I think we need to add the PMU
> feature to all processors that support it, and thus the 'has_pmu'

The TCG case you mentioned was one reason I changed the naming. The
existing "has_pmu" variable was introduced recently and it didn't cover
the case of TCG. Reading 5c0a3819, it is only turned on when KVM is
enabled and PMU_V3_extension is available. If we want to extend the
meaning of "has_pmu" for all PMU cases (i.e. KVM + TCG), we probably
need to address cases of has_pmu=ON + TCG=ON.

> name is better. As the feature is optional, I agree it does make
> sense that it's off by default, and only available with the pmu=on
> property.
> 
> I think there are more processors than just A53 and A57.

host-backed vPMU is only available on A53/A57/host. But TCG supports
more than A53/A57.

> 
>> has been tested under both DT/ACPI modes.
>>
>> Signed-off-by: Wei Huang <wei@redhat.com>
>> ---
>>  hw/arm/virt-acpi-build.c |  2 +-
>>  hw/arm/virt.c            |  2 +-
>>  target-arm/cpu.c         | 13 +++++++++++++
>>  target-arm/cpu.h         |  3 ++-
>>  target-arm/cpu64.c       |  6 ++++++
>>  target-arm/kvm64.c       | 10 +++++-----
>>  6 files changed, 28 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>> index 28fc59c..22fb9d9 100644
>> --- a/hw/arm/virt-acpi-build.c
>> +++ b/hw/arm/virt-acpi-build.c
>> @@ -540,7 +540,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
>>          gicc->uid = i;
>>          gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
>>  
>> -        if (armcpu->has_pmu) {
>> +        if (armcpu->has_host_pmu) {
>>              gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
>>          }
>>      }
>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
>> index a193b5a..4975f38 100644
>> --- a/hw/arm/virt.c
>> +++ b/hw/arm/virt.c
>> @@ -477,7 +477,7 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
>>  
>>      CPU_FOREACH(cpu) {
>>          armcpu = ARM_CPU(cpu);
>> -        if (!armcpu->has_pmu ||
>> +        if (!armcpu->has_host_pmu ||
>>              !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ))) {
>>              return;
>>          }
>> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
>> index ce8b8f4..a527128 100644
>> --- a/target-arm/cpu.c
>> +++ b/target-arm/cpu.c
>> @@ -509,6 +509,10 @@ static Property arm_cpu_rvbar_property =
>>  static Property arm_cpu_has_el3_property =
>>              DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
>>  
>> +/* use property name "pmu" to match with other archs and libvirt */
>> +static Property arm_cpu_has_host_pmu_property =
>> +    DEFINE_PROP_BOOL("pmu", ARMCPU, has_host_pmu, false);
>> +
>>  static Property arm_cpu_has_mpu_property =
>>              DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
>>  
>> @@ -552,6 +556,11 @@ static void arm_cpu_post_init(Object *obj)
>>  #endif
>>      }
>>  
>> +    if (arm_feature(&cpu->env, ARM_FEATURE_HOST_PMU)) {
>> +        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_host_pmu_property,
>> +                                 &error_abort);
>> +    }
>> +
>>      if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
>>          qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
>>                                   &error_abort);
>> @@ -648,6 +657,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>>          cpu->id_aa64pfr0 &= ~0xf000;
>>      }
>>  
>> +    if (!cpu->has_host_pmu) {
>> +        unset_feature(env, ARM_FEATURE_HOST_PMU);
>> +    }
> 
> I think this is the right approach. But we should add the feature to all
> processors that can have it, and then, after checking the property's
> value, we remove it when it's not desired.
> 
>> +
>>      if (!arm_feature(env, ARM_FEATURE_EL2)) {
>>          /* Disable the hypervisor feature bits in the processor feature
>>           * registers if we don't have EL2. These are id_pfr1[15:12] and
>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>> index 76d824d..f3f6d3f 100644
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -580,7 +580,7 @@ struct ARMCPU {
>>      /* CPU has security extension */
>>      bool has_el3;
>>      /* CPU has PMU (Performance Monitor Unit) */
>> -    bool has_pmu;
>> +    bool has_host_pmu;
>>  
>>      /* CPU has memory protection unit */
>>      bool has_mpu;
>> @@ -1129,6 +1129,7 @@ enum arm_features {
>>      ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */
>>      ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */
>>      ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
>> +    ARM_FEATURE_HOST_PMU, /* PMU supported by host */
>>  };
>>  
>>  static inline int arm_feature(CPUARMState *env, int feature)
>> diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
>> index 1635deb..19e8127 100644
>> --- a/target-arm/cpu64.c
>> +++ b/target-arm/cpu64.c
>> @@ -111,6 +111,9 @@ static void aarch64_a57_initfn(Object *obj)
>>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>>      set_feature(&cpu->env, ARM_FEATURE_EL3);
>> +    if (kvm_enabled()) {
>> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
>> +    }
> 
> We shouldn't need the if (kvm_enabled()) here.
> 
>>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
>>      cpu->midr = 0x411fd070;
>>      cpu->revidr = 0x00000000;
>> @@ -166,6 +169,9 @@ static void aarch64_a53_initfn(Object *obj)
>>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>>      set_feature(&cpu->env, ARM_FEATURE_EL3);
>> +    if (kvm_enabled()) {
>> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
>> +    }
> 
> Or here.
> 
>>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
>>      cpu->midr = 0x410fd034;
>>      cpu->revidr = 0x00000000;
>> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
>> index 5faa76c..588e5e3 100644
>> --- a/target-arm/kvm64.c
>> +++ b/target-arm/kvm64.c
>> @@ -469,6 +469,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
>>      set_feature(&features, ARM_FEATURE_VFP4);
>>      set_feature(&features, ARM_FEATURE_NEON);
>>      set_feature(&features, ARM_FEATURE_AARCH64);
>> +    set_feature(&features, ARM_FEATURE_HOST_PMU);
>>  
>>      ahcc->features = features;
>>  
>> @@ -501,11 +502,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
>>      if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
>>          cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
>>      }
>> -    if (kvm_irqchip_in_kernel() &&
>> -        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
>> -        cpu->has_pmu = true;
>> -        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
>> -    }
>> +    /* enable vPMU based on KVM mode, hw capability, and user setting */
>> +    cpu->has_host_pmu &= kvm_irqchip_in_kernel() &&
>> +        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3);
>> +    cpu->kvm_init_features[0] |= cpu->has_host_pmu << KVM_ARM_VCPU_PMU_V3;
> 
> Hmm... so now if the user doesn't specify pmu=on (off by default) then we
> silently disable it (I think that's a 2.6 compat issue), and if they do
^^^^^^^^^^^^^ True. I will see if I can create a patch backward
compatible with 2.6.

> specify pmu=on, but KVM doesn't support it, then it's silently disabled,
> which isn't nice. I think QEMU should error out in that case, explaining
> that the user specified incompatible options, i.e. they selected accel=kvm
> and pmu=on, but their KVM version (or cpu model) doesn't support PMU
> emulation.

True. This can be fixed.

> 
>>  
>>      /* Do KVM_ARM_VCPU_INIT ioctl */
>>      ret = kvm_arm_vcpu_init(cs);
>> -- 
>> 2.4.11
>>
>>
> 
> Thanks,
> drew 
>
Wei Huang Aug. 15, 2016, 9:15 p.m. UTC | #8
On 8/15/16 11:13, Peter Maydell wrote:
> On 13 August 2016 at 06:52, Wei Huang <wei@redhat.com> wrote:
>> This patch adds a pmu=[on/off] option to enable/disable host vPMU
>> support in guest VM. There are several reasons to justify this option.
>> First, host-backed vPMU can be problematic for cross-migration between
>> different SoC as perf counters are architecture-dependent. It is more
>> flexible to have an option to turn it on/off. Secondly this option
>> matches the "pmu" option as supported in libvirt tool.
>>
>> Note that, like "has_el3", the "pmu" option is only made available on
>> CPUs that support host-backed vPMU. They include:
>>     * cortex-a53 + kvm
>>     * cortex-a57 + kvm
>>     * host + kvm
>> This option is removed in other configs where it doesn't make sense
>> (e.g. cortex-a57 + TCG); and the default pmu support is off. This patch
>> has been tested under both DT/ACPI modes.
>>
>> Signed-off-by: Wei Huang <wei@redhat.com>
>> ---
>>  hw/arm/virt-acpi-build.c |  2 +-
>>  hw/arm/virt.c            |  2 +-
>>  target-arm/cpu.c         | 13 +++++++++++++
>>  target-arm/cpu.h         |  3 ++-
>>  target-arm/cpu64.c       |  6 ++++++
>>  target-arm/kvm64.c       | 10 +++++-----
>>  6 files changed, 28 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>> index 28fc59c..22fb9d9 100644
>> --- a/hw/arm/virt-acpi-build.c
>> +++ b/hw/arm/virt-acpi-build.c
>> @@ -540,7 +540,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
>>          gicc->uid = i;
>>          gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
>>
>> -        if (armcpu->has_pmu) {
>> +        if (armcpu->has_host_pmu) {
>>              gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
>>          }
>>      }
>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
>> index a193b5a..4975f38 100644
>> --- a/hw/arm/virt.c
>> +++ b/hw/arm/virt.c
>> @@ -477,7 +477,7 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
>>
>>      CPU_FOREACH(cpu) {
>>          armcpu = ARM_CPU(cpu);
>> -        if (!armcpu->has_pmu ||
>> +        if (!armcpu->has_host_pmu ||
>>              !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ))) {
>>              return;
>>          }
>> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
>> index ce8b8f4..a527128 100644
>> --- a/target-arm/cpu.c
>> +++ b/target-arm/cpu.c
>> @@ -509,6 +509,10 @@ static Property arm_cpu_rvbar_property =
>>  static Property arm_cpu_has_el3_property =
>>              DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
>>
>> +/* use property name "pmu" to match with other archs and libvirt */
>> +static Property arm_cpu_has_host_pmu_property =
>> +    DEFINE_PROP_BOOL("pmu", ARMCPU, has_host_pmu, false);
>> +
>>  static Property arm_cpu_has_mpu_property =
>>              DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
>>
>> @@ -552,6 +556,11 @@ static void arm_cpu_post_init(Object *obj)
>>  #endif
>>      }
>>
>> +    if (arm_feature(&cpu->env, ARM_FEATURE_HOST_PMU)) {
>> +        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_host_pmu_property,
>> +                                 &error_abort);
>> +    }
>> +
>>      if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
>>          qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
>>                                   &error_abort);
>> @@ -648,6 +657,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
>>          cpu->id_aa64pfr0 &= ~0xf000;
>>      }
>>
>> +    if (!cpu->has_host_pmu) {
>> +        unset_feature(env, ARM_FEATURE_HOST_PMU);
>> +    }
>> +
>>      if (!arm_feature(env, ARM_FEATURE_EL2)) {
>>          /* Disable the hypervisor feature bits in the processor feature
>>           * registers if we don't have EL2. These are id_pfr1[15:12] and
>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>> index 76d824d..f3f6d3f 100644
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -580,7 +580,7 @@ struct ARMCPU {
>>      /* CPU has security extension */
>>      bool has_el3;
>>      /* CPU has PMU (Performance Monitor Unit) */
>> -    bool has_pmu;
>> +    bool has_host_pmu;
> 
> Can you explain why you renamed this? "has_pmu" matches
> the comment: it indicates that the emulated CPU has a PMU.
> has_host_pmu would be something different (and would only

The existing "has_pmu" was added and only enabled under KVM. So its
existing meaning is a bit misleading. It doesn't address the case of TCG.


> apply to KVM). It also looks weird in the code in the board
> model: we should be saying "if the guest CPU has a PMU, wire
> up its interrupt", not "if the host CPU has a PMU, wire
> up a guest CPU interrupt".

I can change it back to "has_pmu" as suggested by you and Drew; but we
need to be careful of using it, especially under TCG mode. For instance,
with "-M virt,accel=tcg -cpu host,pmu=off", we expect PMU is turned off.
But TCG still emulates some PMU counters (e.g. pmccntr).

> 
>>
>>      /* CPU has memory protection unit */
>>      bool has_mpu;
>> @@ -1129,6 +1129,7 @@ enum arm_features {
>>      ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */
>>      ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */
>>      ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
>> +    ARM_FEATURE_HOST_PMU, /* PMU supported by host */
> 
> ARM_FEATURE_ bits are for guest CPU features, not for
> recording information about the host CPU.

OK, will address it.

> 
>>  };
>>
>>  static inline int arm_feature(CPUARMState *env, int feature)
>> diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
>> index 1635deb..19e8127 100644
>> --- a/target-arm/cpu64.c
>> +++ b/target-arm/cpu64.c
>> @@ -111,6 +111,9 @@ static void aarch64_a57_initfn(Object *obj)
>>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>>      set_feature(&cpu->env, ARM_FEATURE_EL3);
>> +    if (kvm_enabled()) {
>> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
>> +    }
>>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
>>      cpu->midr = 0x411fd070;
>>      cpu->revidr = 0x00000000;
>> @@ -166,6 +169,9 @@ static void aarch64_a53_initfn(Object *obj)
>>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>>      set_feature(&cpu->env, ARM_FEATURE_EL3);
>> +    if (kvm_enabled()) {
>> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
>> +    }
> 
> This definitely looks like the wrong place to be checking
> kvm_enabled().
> 
>>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
>>      cpu->midr = 0x410fd034;
>>      cpu->revidr = 0x00000000;
>> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
>> index 5faa76c..588e5e3 100644
>> --- a/target-arm/kvm64.c
>> +++ b/target-arm/kvm64.c
>> @@ -469,6 +469,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
>>      set_feature(&features, ARM_FEATURE_VFP4);
>>      set_feature(&features, ARM_FEATURE_NEON);
>>      set_feature(&features, ARM_FEATURE_AARCH64);
>> +    set_feature(&features, ARM_FEATURE_HOST_PMU);
>>
>>      ahcc->features = features;
>>
>> @@ -501,11 +502,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
>>      if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
>>          cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
>>      }
>> -    if (kvm_irqchip_in_kernel() &&
>> -        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
>> -        cpu->has_pmu = true;
>> -        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
>> -    }
>> +    /* enable vPMU based on KVM mode, hw capability, and user setting */
>> +    cpu->has_host_pmu &= kvm_irqchip_in_kernel() &&
>> +        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3);
>> +    cpu->kvm_init_features[0] |= cpu->has_host_pmu << KVM_ARM_VCPU_PMU_V3;
>>
>>      /* Do KVM_ARM_VCPU_INIT ioctl */
>>      ret = kvm_arm_vcpu_init(cs);
>> --
>> 2.4.11
>>
> 
> thanks
> -- PMM
>
Wei Huang Aug. 19, 2016, 5:05 p.m. UTC | #9
On 08/15/2016 11:13 AM, Peter Maydell wrote:
<snip>
>>  static inline int arm_feature(CPUARMState *env, int feature)
>> diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
>> index 1635deb..19e8127 100644
>> --- a/target-arm/cpu64.c
>> +++ b/target-arm/cpu64.c
>> @@ -111,6 +111,9 @@ static void aarch64_a57_initfn(Object *obj)
>>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>>      set_feature(&cpu->env, ARM_FEATURE_EL3);
>> +    if (kvm_enabled()) {
>> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
>> +    }
>>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
>>      cpu->midr = 0x411fd070;
>>      cpu->revidr = 0x00000000;
>> @@ -166,6 +169,9 @@ static void aarch64_a53_initfn(Object *obj)
>>      set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
>>      set_feature(&cpu->env, ARM_FEATURE_CRC);
>>      set_feature(&cpu->env, ARM_FEATURE_EL3);
>> +    if (kvm_enabled()) {
>> +        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
>> +    }
> 
> This definitely looks like the wrong place to be checking
> kvm_enabled().

If we don't want to check kvm_enabled() in aarch64_a5x_initfn(), one
viable place is to move it up to cpu.c file, like in
arm_cpu_realizefn(). Do you have any other suggestions?

> 
>>      cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
>>      cpu->midr = 0x410fd034;
>>      cpu->revidr = 0x00000000;
diff mbox

Patch

diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 28fc59c..22fb9d9 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -540,7 +540,7 @@  build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
         gicc->uid = i;
         gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
 
-        if (armcpu->has_pmu) {
+        if (armcpu->has_host_pmu) {
             gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
         }
     }
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a193b5a..4975f38 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -477,7 +477,7 @@  static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
 
     CPU_FOREACH(cpu) {
         armcpu = ARM_CPU(cpu);
-        if (!armcpu->has_pmu ||
+        if (!armcpu->has_host_pmu ||
             !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ))) {
             return;
         }
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index ce8b8f4..a527128 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -509,6 +509,10 @@  static Property arm_cpu_rvbar_property =
 static Property arm_cpu_has_el3_property =
             DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
 
+/* use property name "pmu" to match with other archs and libvirt */
+static Property arm_cpu_has_host_pmu_property =
+    DEFINE_PROP_BOOL("pmu", ARMCPU, has_host_pmu, false);
+
 static Property arm_cpu_has_mpu_property =
             DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
 
@@ -552,6 +556,11 @@  static void arm_cpu_post_init(Object *obj)
 #endif
     }
 
+    if (arm_feature(&cpu->env, ARM_FEATURE_HOST_PMU)) {
+        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_host_pmu_property,
+                                 &error_abort);
+    }
+
     if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
         qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
                                  &error_abort);
@@ -648,6 +657,10 @@  static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         cpu->id_aa64pfr0 &= ~0xf000;
     }
 
+    if (!cpu->has_host_pmu) {
+        unset_feature(env, ARM_FEATURE_HOST_PMU);
+    }
+
     if (!arm_feature(env, ARM_FEATURE_EL2)) {
         /* Disable the hypervisor feature bits in the processor feature
          * registers if we don't have EL2. These are id_pfr1[15:12] and
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 76d824d..f3f6d3f 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -580,7 +580,7 @@  struct ARMCPU {
     /* CPU has security extension */
     bool has_el3;
     /* CPU has PMU (Performance Monitor Unit) */
-    bool has_pmu;
+    bool has_host_pmu;
 
     /* CPU has memory protection unit */
     bool has_mpu;
@@ -1129,6 +1129,7 @@  enum arm_features {
     ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */
     ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */
     ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
+    ARM_FEATURE_HOST_PMU, /* PMU supported by host */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
index 1635deb..19e8127 100644
--- a/target-arm/cpu64.c
+++ b/target-arm/cpu64.c
@@ -111,6 +111,9 @@  static void aarch64_a57_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
     set_feature(&cpu->env, ARM_FEATURE_CRC);
     set_feature(&cpu->env, ARM_FEATURE_EL3);
+    if (kvm_enabled()) {
+        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
+    }
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
     cpu->midr = 0x411fd070;
     cpu->revidr = 0x00000000;
@@ -166,6 +169,9 @@  static void aarch64_a53_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
     set_feature(&cpu->env, ARM_FEATURE_CRC);
     set_feature(&cpu->env, ARM_FEATURE_EL3);
+    if (kvm_enabled()) {
+        set_feature(&cpu->env, ARM_FEATURE_HOST_PMU);
+    }
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
     cpu->midr = 0x410fd034;
     cpu->revidr = 0x00000000;
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 5faa76c..588e5e3 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -469,6 +469,7 @@  bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
     set_feature(&features, ARM_FEATURE_VFP4);
     set_feature(&features, ARM_FEATURE_NEON);
     set_feature(&features, ARM_FEATURE_AARCH64);
+    set_feature(&features, ARM_FEATURE_HOST_PMU);
 
     ahcc->features = features;
 
@@ -501,11 +502,10 @@  int kvm_arch_init_vcpu(CPUState *cs)
     if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
         cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
     }
-    if (kvm_irqchip_in_kernel() &&
-        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
-        cpu->has_pmu = true;
-        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
-    }
+    /* enable vPMU based on KVM mode, hw capability, and user setting */
+    cpu->has_host_pmu &= kvm_irqchip_in_kernel() &&
+        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3);
+    cpu->kvm_init_features[0] |= cpu->has_host_pmu << KVM_ARM_VCPU_PMU_V3;
 
     /* Do KVM_ARM_VCPU_INIT ioctl */
     ret = kvm_arm_vcpu_init(cs);