This sets the vCPU device attribute to unconditionally enable partitioning when a PMU is available on an ARM host. Note that this patch is experimental to demonstrate the API. That is why it aborts immediately if the call does not succeed. For the call to succeed, the host must be running a kernel with the ARM64 PMU Partitioning feature [1] and set the kernel command line arm_pmuv3.reserved_host_counters=n where n is between 0 and the number of counters on the system, inclusive. [1] https://lore.kernel.org/kvmarm/20260209221414.2169465-1-coltonlewis@google.com/ Signed-off-by: Colton Lewis --- hw/arm/virt.c | 1 + linux-headers/asm-arm64/kvm.h | 2 ++ target/arm/kvm-stub.c | 5 +++++ target/arm/kvm.c | 18 ++++++++++++++++++ target/arm/kvm_arm.h | 1 + 5 files changed, 27 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 50865e8115..29082df31c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2234,6 +2234,7 @@ static void virt_post_cpus_gic_realized(VirtMachineState *vms, if (kvm_irqchip_in_kernel()) { kvm_arm_pmu_set_irq(ARM_CPU(cpu), VIRTUAL_PMU_IRQ); } + kvm_arm_pmu_set_partition(ARM_CPU(cpu), true); kvm_arm_pmu_init(ARM_CPU(cpu)); } if (steal_time) { diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 46ffbddab5..69309a182e 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -424,6 +424,8 @@ enum { #define KVM_ARM_VCPU_PMU_V3_FILTER 2 #define KVM_ARM_VCPU_PMU_V3_SET_PMU 3 #define KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS 4 +#define KVM_ARM_VCPU_PMU_V3_ENABLE_PARTITION 5 + #define KVM_ARM_VCPU_TIMER_CTRL 1 #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c index ea67deea52..afbfffe2cd 100644 --- a/target/arm/kvm-stub.c +++ b/target/arm/kvm-stub.c @@ -80,6 +80,11 @@ void kvm_arm_pmu_set_irq(ARMCPU *cpu, int irq) g_assert_not_reached(); } +void kvm_arm_pmu_set_partition(ARMCPU *cpu, bool partition) +{ + g_assert_not_reached(); +} + void kvm_arm_pmu_init(ARMCPU *cpu) { g_assert_not_reached(); diff --git a/target/arm/kvm.c b/target/arm/kvm.c index ded582e0da..db1d564462 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -1817,6 +1817,24 @@ void kvm_arm_pmu_set_irq(ARMCPU *cpu, int irq) } } +void kvm_arm_pmu_set_partition(ARMCPU *cpu, bool partition) +{ + struct kvm_device_attr part_attr = { + .group = KVM_ARM_VCPU_PMU_V3_CTRL, + .attr = KVM_ARM_VCPU_PMU_V3_ENABLE_PARTITION, + .addr = (uint64_t)&partition + }; + + if (!cpu->has_pmu) { + return; + } + + if (!kvm_arm_set_device_attr(cpu, &part_attr, "PMU partition")) { + error_report("failed to set PMU partition"); + abort(); + } +} + void kvm_arm_pvtime_init(ARMCPU *cpu, uint64_t ipa) { struct kvm_device_attr attr = { diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index cc0b374254..2b55f2956e 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -248,6 +248,7 @@ int kvm_arm_vgic_probe(void); void kvm_arm_pmu_init(ARMCPU *cpu); void kvm_arm_pmu_set_irq(ARMCPU *cpu, int irq); +void kvm_arm_pmu_set_partition(ARMCPU *cpu, bool partition); /** * kvm_arm_pvtime_init: base-commit: afe653676dc6dfd49f0390239ff90b2f0052c2b8 -- 2.53.0.414.gf7e9f6c205-goog