Skip to content

Commit b7628c7

Browse files
author
Marc Zyngier
committed
KVM: arm64: Allow userspace to limit the number of PMU counters for EL2 VMs
As long as we had purely EL1 VMs, we could easily update the number of guest-visible counters by letting userspace write to PMCR_EL0.N. With VMs started at EL2, PMCR_EL1.N only reflects MDCR_EL2.HPMN, and we don't have a good way to limit it. For this purpose, introduce a new PMUv3 attribute that allows limiting the maximum number of counters. This requires the explicit selection of a PMU. Suggested-by: Oliver Upton <oliver.upton@linux.dev> Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 0224353 commit b7628c7

File tree

3 files changed

+53
-4
lines changed

3 files changed

+53
-4
lines changed

Documentation/virt/kvm/devices/vcpu.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,30 @@ exit_reason = KVM_EXIT_FAIL_ENTRY and populate the fail_entry struct by setting
137137
hardare_entry_failure_reason field to KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED and
138138
the cpu field to the processor id.
139139

140+
1.5 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS
141+
--------------------------------------------------
142+
143+
:Parameters: in kvm_device_attr.addr the address to an unsigned int
144+
representing the maximum value taken by PMCR_EL0.N
145+
146+
:Returns:
147+
148+
======= ====================================================
149+
-EBUSY PMUv3 already initialized, a VCPU has already run or
150+
an event filter has already been set
151+
-EFAULT Error accessing the value pointed to by addr
152+
-ENODEV PMUv3 not supported or GIC not initialized
153+
-EINVAL No PMUv3 explicitly selected, or value of N out of
154+
range
155+
======= ====================================================
156+
157+
Set the number of implemented event counters in the virtual PMU. This
158+
mandates that a PMU has explicitly been selected via
159+
KVM_ARM_VCPU_PMU_V3_SET_PMU, and will fail when no PMU has been
160+
explicitly selected, or the number of counters is out of range for the
161+
selected PMU. Selecting a new PMU cancels the effect of setting this
162+
attribute.
163+
140164
2. GROUP: KVM_ARM_VCPU_TIMER_CTRL
141165
=================================
142166

arch/arm64/include/uapi/asm/kvm.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -431,10 +431,11 @@ enum {
431431

432432
/* Device Control API on vcpu fd */
433433
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
434-
#define KVM_ARM_VCPU_PMU_V3_IRQ 0
435-
#define KVM_ARM_VCPU_PMU_V3_INIT 1
436-
#define KVM_ARM_VCPU_PMU_V3_FILTER 2
437-
#define KVM_ARM_VCPU_PMU_V3_SET_PMU 3
434+
#define KVM_ARM_VCPU_PMU_V3_IRQ 0
435+
#define KVM_ARM_VCPU_PMU_V3_INIT 1
436+
#define KVM_ARM_VCPU_PMU_V3_FILTER 2
437+
#define KVM_ARM_VCPU_PMU_V3_SET_PMU 3
438+
#define KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS 4
438439
#define KVM_ARM_VCPU_TIMER_CTRL 1
439440
#define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
440441
#define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1

arch/arm64/kvm/pmu-emul.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,20 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
11041104
return ret;
11051105
}
11061106

1107+
static int kvm_arm_pmu_v3_set_nr_counters(struct kvm_vcpu *vcpu, unsigned int n)
1108+
{
1109+
struct kvm *kvm = vcpu->kvm;
1110+
1111+
if (!kvm->arch.arm_pmu)
1112+
return -EINVAL;
1113+
1114+
if (n > kvm_arm_pmu_get_max_counters(kvm))
1115+
return -EINVAL;
1116+
1117+
kvm_arm_set_nr_counters(kvm, n);
1118+
return 0;
1119+
}
1120+
11071121
int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
11081122
{
11091123
struct kvm *kvm = vcpu->kvm;
@@ -1200,6 +1214,15 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
12001214

12011215
return kvm_arm_pmu_v3_set_pmu(vcpu, pmu_id);
12021216
}
1217+
case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS: {
1218+
unsigned int __user *uaddr = (unsigned int __user *)(long)attr->addr;
1219+
unsigned int n;
1220+
1221+
if (get_user(n, uaddr))
1222+
return -EFAULT;
1223+
1224+
return kvm_arm_pmu_v3_set_nr_counters(vcpu, n);
1225+
}
12031226
case KVM_ARM_VCPU_PMU_V3_INIT:
12041227
return kvm_arm_pmu_v3_init(vcpu);
12051228
}
@@ -1238,6 +1261,7 @@ int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
12381261
case KVM_ARM_VCPU_PMU_V3_INIT:
12391262
case KVM_ARM_VCPU_PMU_V3_FILTER:
12401263
case KVM_ARM_VCPU_PMU_V3_SET_PMU:
1264+
case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS:
12411265
if (kvm_vcpu_has_pmu(vcpu))
12421266
return 0;
12431267
}

0 commit comments

Comments
 (0)