mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
Merge branch 'kvm-arm64/pmu-7.3' into next
* kvm-arm64/pmu-7.3: : vPMU updates for 7.3 : : - Support for slot-based PMU events, relying on new UAPI that makes : selection of a vPMU implementation mandatory (Congkai Tan) KVM: arm64: Add KVM_ARM_VCPU_PMU_V3_STRICT vCPU feature KVM: arm64: Ignore writes to PMCR_EL0.N when using strict UAPI KVM: arm64: Advertise STALL_SLOT* in PMCEID1 under strict PMUv3 UAPI KVM: arm64: Expose PMMIR_EL1.SLOTS under strict PMUv3 UAPI Signed-off-by: Oliver Upton <oupton@kernel.org>
This commit is contained in:
commit
f181451283
|
|
@ -3515,6 +3515,17 @@ Possible features:
|
|||
Depends on KVM_CAP_ARM_PSCI_0_2.
|
||||
- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
|
||||
Depends on KVM_CAP_ARM_PMU_V3.
|
||||
- KVM_ARM_VCPU_PMU_V3_STRICT: Enable strict PMUv3 UAPI.
|
||||
Requires KVM_ARM_VCPU_PMU_V3. Depends on KVM_CAP_ARM_PMU_V3_STRICT.
|
||||
When enabled:
|
||||
|
||||
* Userspace must explicitly select a PMU implementation before
|
||||
initializing the PMU or configuring a PMU event filter
|
||||
|
||||
* If the PMU implements FEAT_PMUv3p4, PMMIR_EL1.SLOTS provides the
|
||||
hardware value of the underlying implementation
|
||||
|
||||
* Writes to PMCR_EL0.N via KVM_SET_ONE_REG are ignored
|
||||
|
||||
- KVM_ARM_VCPU_PTRAUTH_ADDRESS: Enables Address Pointer authentication
|
||||
for arm64 only.
|
||||
|
|
|
|||
|
|
@ -53,8 +53,9 @@ Returns:
|
|||
======= ======================================================
|
||||
-EEXIST Interrupt number already used
|
||||
-ENODEV PMUv3 not supported or GIC not initialized
|
||||
-ENXIO PMUv3 not supported, missing VCPU feature or interrupt
|
||||
number not set (non-GICv5 guests, only)
|
||||
-ENXIO PMUv3 not supported, missing VCPU feature, missing
|
||||
hardware PMU, or interrupt number not set (non-GICv5
|
||||
guests, only)
|
||||
-EBUSY PMUv3 already initialized
|
||||
======= ======================================================
|
||||
|
||||
|
|
@ -62,6 +63,9 @@ Request the initialization of the PMUv3. If using the PMUv3 with an in-kernel
|
|||
virtual GIC implementation, this must be done after initializing the in-kernel
|
||||
irqchip.
|
||||
|
||||
When the KVM_ARM_VCPU_PMU_V3_STRICT vCPU feature is enabled this must be done
|
||||
after selecting a hardware PMU.
|
||||
|
||||
1.3 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_FILTER
|
||||
-----------------------------------------
|
||||
|
||||
|
|
@ -108,6 +112,9 @@ hardware event. Filtering event 0x1E (CHAIN) has no effect either, as it
|
|||
isn't strictly speaking an event. Filtering the cycle counter is possible
|
||||
using event 0x11 (CPU_CYCLES).
|
||||
|
||||
When the KVM_ARM_VCPU_PMU_V3_STRICT vCPU feature is enabled this must be done
|
||||
after selecting a hardware PMU.
|
||||
|
||||
1.4 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_SET_PMU
|
||||
------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
#define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
|
||||
|
||||
#define KVM_VCPU_MAX_FEATURES 9
|
||||
#define KVM_VCPU_MAX_FEATURES 10
|
||||
#define KVM_VCPU_VALID_FEATURES (BIT(KVM_VCPU_MAX_FEATURES) - 1)
|
||||
|
||||
#define KVM_REQ_SLEEP \
|
||||
|
|
@ -387,6 +387,9 @@ struct kvm_arch {
|
|||
/* Maximum number of counters for the guest */
|
||||
u8 nr_pmu_counters;
|
||||
|
||||
/* PMMIR_EL1.SLOTS value exposed to the guest. */
|
||||
u8 pmmir_slots;
|
||||
|
||||
/* Hypercall features firmware registers' descriptor */
|
||||
struct kvm_smccc_features smccc_feat;
|
||||
struct maple_tree smccc_filter;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ struct kvm_regs {
|
|||
#define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */
|
||||
#define KVM_ARM_VCPU_HAS_EL2 7 /* Support nested virtualization */
|
||||
#define KVM_ARM_VCPU_HAS_EL2_E2H0 8 /* Limit NV support to E2H RES0 */
|
||||
#define KVM_ARM_VCPU_PMU_V3_STRICT 9 /* No default PMU creation */
|
||||
|
||||
struct kvm_vcpu_init {
|
||||
__u32 target;
|
||||
|
|
|
|||
|
|
@ -452,6 +452,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
r = get_num_wrps();
|
||||
break;
|
||||
case KVM_CAP_ARM_PMU_V3:
|
||||
case KVM_CAP_ARM_PMU_V3_STRICT:
|
||||
r = kvm_supports_guest_pmuv3();
|
||||
break;
|
||||
case KVM_CAP_ARM_INJECT_SERROR_ESR:
|
||||
|
|
@ -1563,8 +1564,10 @@ static unsigned long system_supported_vcpu_features(void)
|
|||
if (!cpus_have_final_cap(ARM64_HAS_32BIT_EL1))
|
||||
clear_bit(KVM_ARM_VCPU_EL1_32BIT, &features);
|
||||
|
||||
if (!kvm_supports_guest_pmuv3())
|
||||
if (!kvm_supports_guest_pmuv3()) {
|
||||
clear_bit(KVM_ARM_VCPU_PMU_V3, &features);
|
||||
clear_bit(KVM_ARM_VCPU_PMU_V3_STRICT, &features);
|
||||
}
|
||||
|
||||
if (!system_supports_sve())
|
||||
clear_bit(KVM_ARM_VCPU_SVE, &features);
|
||||
|
|
@ -1605,6 +1608,11 @@ static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
|
|||
test_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, &features))
|
||||
return -EINVAL;
|
||||
|
||||
/* Strict PMUv3 UAPI requires PMUv3. */
|
||||
if (test_bit(KVM_ARM_VCPU_PMU_V3_STRICT, &features) &&
|
||||
!test_bit(KVM_ARM_VCPU_PMU_V3, &features))
|
||||
return -EINVAL;
|
||||
|
||||
if (!test_bit(KVM_ARM_VCPU_EL1_32BIT, &features))
|
||||
return 0;
|
||||
|
||||
|
|
@ -1634,10 +1642,13 @@ static int kvm_setup_vcpu(struct kvm_vcpu *vcpu)
|
|||
int ret = 0;
|
||||
|
||||
/*
|
||||
* When the vCPU has a PMU, but no PMU is set for the guest
|
||||
* yet, set the default one.
|
||||
* When the vCPU has a PMU, but no PMU is set for the guest yet, set
|
||||
* the default one. If KVM_ARM_VCPU_PMU_V3_STRICT is set, no default
|
||||
* PMU is created, and userspace must select a PMU via
|
||||
* KVM_ARM_VCPU_PMU_V3_SET_PMU.
|
||||
*/
|
||||
if (kvm_vcpu_has_pmu(vcpu) && !kvm->arch.arm_pmu)
|
||||
if (kvm_vcpu_has_pmu(vcpu) && !kvm->arch.arm_pmu &&
|
||||
!kvm_vcpu_has_pmuv3_strict(vcpu))
|
||||
ret = kvm_arm_set_default_pmu(kvm);
|
||||
|
||||
/* Prepare for nested if required */
|
||||
|
|
|
|||
|
|
@ -838,9 +838,9 @@ static u64 __compute_pmceid(struct arm_pmu *pmu, bool pmceid1)
|
|||
return ((u64)hi[pmceid1] << 32) | lo[pmceid1];
|
||||
}
|
||||
|
||||
static u64 compute_pmceid0(struct arm_pmu *pmu)
|
||||
static u64 compute_pmceid0(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 val = __compute_pmceid(pmu, 0);
|
||||
u64 val = __compute_pmceid(vcpu->kvm->arch.arm_pmu, 0);
|
||||
|
||||
/* always support SW_INCR */
|
||||
val |= BIT(ARMV8_PMUV3_PERFCTR_SW_INCR);
|
||||
|
|
@ -849,32 +849,33 @@ static u64 compute_pmceid0(struct arm_pmu *pmu)
|
|||
return val;
|
||||
}
|
||||
|
||||
static u64 compute_pmceid1(struct arm_pmu *pmu)
|
||||
static u64 compute_pmceid1(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 val = __compute_pmceid(pmu, 1);
|
||||
u64 val = __compute_pmceid(vcpu->kvm->arch.arm_pmu, 1);
|
||||
|
||||
/*
|
||||
* Don't advertise STALL_SLOT*, as PMMIR_EL0 is handled
|
||||
* as RAZ
|
||||
* If KVM_ARM_VCPU_PMU_V3_STRICT is not set, PMMIR_EL1 is
|
||||
* unconditionally RAZ, so don't advertise STALL_SLOT* events.
|
||||
*/
|
||||
val &= ~(BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT - 32) |
|
||||
BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND - 32) |
|
||||
BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT_BACKEND - 32));
|
||||
if (!kvm_vcpu_has_pmuv3_strict(vcpu))
|
||||
val &= ~(BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT - 32) |
|
||||
BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND - 32) |
|
||||
BIT_ULL(ARMV8_PMUV3_PERFCTR_STALL_SLOT_BACKEND - 32));
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
|
||||
{
|
||||
struct arm_pmu *cpu_pmu = vcpu->kvm->arch.arm_pmu;
|
||||
unsigned long *bmap = vcpu->kvm->arch.pmu_filter;
|
||||
u64 val, mask = 0;
|
||||
int base, i, nr_events;
|
||||
|
||||
if (!pmceid1) {
|
||||
val = compute_pmceid0(cpu_pmu);
|
||||
val = compute_pmceid0(vcpu);
|
||||
base = 0;
|
||||
} else {
|
||||
val = compute_pmceid1(cpu_pmu);
|
||||
val = compute_pmceid1(vcpu);
|
||||
base = 32;
|
||||
}
|
||||
|
||||
|
|
@ -938,6 +939,10 @@ int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
|
|||
|
||||
static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/* Only possible when using KVM_ARM_VCPU_PMU_V3_STRICT */
|
||||
if (!vcpu->kvm->arch.arm_pmu)
|
||||
return -ENXIO;
|
||||
|
||||
if (irqchip_in_kernel(vcpu->kvm)) {
|
||||
int ret;
|
||||
|
||||
|
|
@ -1008,6 +1013,14 @@ u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
|
|||
{
|
||||
struct arm_pmu *arm_pmu = kvm->arch.arm_pmu;
|
||||
|
||||
/*
|
||||
* Under KVM_ARM_VCPU_PMU_V3_STRICT no PMU exists until userspace sets
|
||||
* one, so this can be reached before arm_pmu is set. Report no
|
||||
* counters in that case.
|
||||
*/
|
||||
if (!arm_pmu)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* PMUv3 requires that all event counters are capable of counting any
|
||||
* event, though the same may not be true of non-PMUv3 hardware.
|
||||
|
|
@ -1049,7 +1062,8 @@ static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
|
|||
}
|
||||
|
||||
/**
|
||||
* kvm_arm_set_default_pmu - No PMU set, get the default one.
|
||||
* kvm_arm_set_default_pmu - No PMU set and KVM_ARM_VCPU_PMU_V3_STRICT not
|
||||
* set, get the default one.
|
||||
* @kvm: The kvm pointer
|
||||
*
|
||||
* The observant among you will notice that the supported_cpus
|
||||
|
|
@ -1092,6 +1106,17 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
|
|||
|
||||
kvm_arm_set_pmu(kvm, arm_pmu);
|
||||
cpumask_copy(kvm->arch.supported_cpus, &arm_pmu->supported_cpus);
|
||||
|
||||
/*
|
||||
* Since a specific PMU is explicitly selected,
|
||||
* PMMIR_EL1.SLOTS is deterministic to the guest.
|
||||
* If KVM_ARM_VCPU_PMU_V3_STRICT is set, snapshot
|
||||
* the value to allow the guest to read it.
|
||||
*/
|
||||
if (kvm_vcpu_has_pmuv3_strict(vcpu))
|
||||
kvm->arch.pmmir_slots =
|
||||
FIELD_GET(ARMV8_PMU_SLOTS,
|
||||
arm_pmu->reg_pmmir);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1178,6 +1203,9 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
|
|||
if (kvm_vm_has_ran_once(kvm))
|
||||
return -EBUSY;
|
||||
|
||||
if (!kvm->arch.arm_pmu)
|
||||
return -ENXIO;
|
||||
|
||||
if (!kvm->arch.pmu_filter) {
|
||||
kvm->arch.pmu_filter = bitmap_alloc(nr_events, GFP_KERNEL_ACCOUNT);
|
||||
if (!kvm->arch.pmu_filter)
|
||||
|
|
|
|||
|
|
@ -1367,6 +1367,64 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool access_pmmir(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
return write_to_read_only(vcpu, p, r);
|
||||
|
||||
/*
|
||||
* If KVM_ARM_VCPU_PMU_V3_STRICT is set and PMU was explicitly
|
||||
* selected, the underlying hardware SLOTS value was read into this
|
||||
* field. Otherwise, it stays 0. All other PMMIR_EL1 fields are RAZ.
|
||||
*/
|
||||
p->regval = FIELD_PREP(ARMV8_PMU_SLOTS, vcpu->kvm->arch.pmmir_slots);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int get_pmmir(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
|
||||
u64 *val)
|
||||
{
|
||||
*val = FIELD_PREP(ARMV8_PMU_SLOTS, vcpu->kvm->arch.pmmir_slots);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_pmmir(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
|
||||
u64 val)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
u8 slots = FIELD_GET(ARMV8_PMU_SLOTS, val);
|
||||
|
||||
/*
|
||||
* Only the SLOTS field is exposed (get_pmmir returns just that field),
|
||||
* so reject a write that sets any other bit rather than silently
|
||||
* masking it.
|
||||
*/
|
||||
if (val & ~(u64)ARMV8_PMU_SLOTS)
|
||||
return -EINVAL;
|
||||
|
||||
guard(mutex)(&kvm->arch.config_lock);
|
||||
|
||||
/*
|
||||
* Once the VM has started PMMIR_EL1 is immutable. Reject any write
|
||||
* that does not match the current value.
|
||||
*/
|
||||
if (kvm_vm_has_ran_once(kvm))
|
||||
return slots == kvm->arch.pmmir_slots ? 0 : -EBUSY;
|
||||
|
||||
/*
|
||||
* Only SLOTS = 0 is honored for backwards compatibility with the
|
||||
* old RAZ behavior. Reject any non-zero write that does not match
|
||||
* the current value.
|
||||
*/
|
||||
if (!slots)
|
||||
kvm->arch.pmmir_slots = 0;
|
||||
else if (slots != kvm->arch.pmmir_slots)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
|
|
@ -1444,6 +1502,7 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
|
|||
*/
|
||||
if (!kvm_vm_has_ran_once(kvm) &&
|
||||
!vcpu_has_nv(vcpu) &&
|
||||
!kvm_vcpu_has_pmuv3_strict(vcpu) &&
|
||||
new_n <= kvm_arm_pmu_get_max_counters(kvm))
|
||||
kvm->arch.nr_pmu_counters = new_n;
|
||||
|
||||
|
|
@ -3448,7 +3507,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|||
{ PMU_SYS_REG(PMINTENCLR_EL1),
|
||||
.access = access_pminten, .reg = PMINTENSET_EL1,
|
||||
.get_user = get_pmreg, .set_user = set_pmreg },
|
||||
{ SYS_DESC(SYS_PMMIR_EL1), trap_raz_wi },
|
||||
{ PMU_SYS_REG(PMMIR_EL1), .access = access_pmmir, .reset = NULL,
|
||||
.get_user = get_pmmir, .set_user = set_pmmir },
|
||||
|
||||
{ SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 },
|
||||
{ SYS_DESC(SYS_PIRE0_EL1), NULL, reset_unknown, PIRE0_EL1,
|
||||
|
|
@ -4593,7 +4653,7 @@ static const struct sys_reg_desc cp15_regs[] = {
|
|||
{ CP15_PMU_SYS_REG(HI, 0, 9, 14, 4), .access = access_pmceid },
|
||||
{ CP15_PMU_SYS_REG(HI, 0, 9, 14, 5), .access = access_pmceid },
|
||||
/* PMMIR */
|
||||
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 6), .access = trap_raz_wi },
|
||||
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 6), .access = access_pmmir },
|
||||
|
||||
/* PRRR/MAIR0 */
|
||||
{ AA32(LO), Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, MAIR_EL1 },
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ void kvm_vcpu_pmu_resync_el0(void);
|
|||
#define kvm_vcpu_has_pmu(vcpu) \
|
||||
(vcpu_has_feature(vcpu, KVM_ARM_VCPU_PMU_V3))
|
||||
|
||||
#define kvm_vcpu_has_pmuv3_strict(vcpu) \
|
||||
(vcpu_has_feature(vcpu, KVM_ARM_VCPU_PMU_V3_STRICT))
|
||||
|
||||
/*
|
||||
* Updates the vcpu's view of the pmu events for this cpu.
|
||||
* Must be called before every vcpu run after disabling interrupts, to ensure
|
||||
|
|
@ -160,6 +163,7 @@ static inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
|
|||
}
|
||||
|
||||
#define kvm_vcpu_has_pmu(vcpu) ({ false; })
|
||||
#define kvm_vcpu_has_pmuv3_strict(vcpu) ({ false; })
|
||||
static inline void kvm_pmu_update_vcpu_events(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
|
||||
static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
|
||||
|
|
|
|||
|
|
@ -997,6 +997,7 @@ struct kvm_enable_cap {
|
|||
#define KVM_CAP_S390_KEYOP 247
|
||||
#define KVM_CAP_S390_VSIE_ESAMODE 248
|
||||
#define KVM_CAP_S390_HPAGE_2G 249
|
||||
#define KVM_CAP_ARM_PMU_V3_STRICT 250
|
||||
|
||||
struct kvm_irq_routing_irqchip {
|
||||
__u32 irqchip;
|
||||
|
|
|
|||
|
|
@ -532,6 +532,7 @@ static __u64 base_regs[] = {
|
|||
static __u64 pmu_regs[] = {
|
||||
ARM64_SYS_REG(3, 0, 9, 14, 1), /* PMINTENSET_EL1 */
|
||||
ARM64_SYS_REG(3, 0, 9, 14, 2), /* PMINTENCLR_EL1 */
|
||||
ARM64_SYS_REG(3, 0, 9, 14, 6), /* PMMIR_EL1 */
|
||||
ARM64_SYS_REG(3, 3, 9, 12, 0), /* PMCR_EL0 */
|
||||
ARM64_SYS_REG(3, 3, 9, 12, 1), /* PMCNTENSET_EL0 */
|
||||
ARM64_SYS_REG(3, 3, 9, 12, 2), /* PMCNTENCLR_EL0 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user