Skip to content

Commit ea9ca90

Browse files
reijiw-kvmoupton
authored andcommitted
KVM: arm64: PMU: Allow userspace to limit PMCR_EL0.N for the guest
KVM does not yet support userspace modifying PMCR_EL0.N (With the previous patch, KVM ignores what is written by userspace). Add support userspace limiting PMCR_EL0.N. Disallow userspace to set PMCR_EL0.N to a value that is greater than the host value as KVM doesn't support more event counters than what the host HW implements. Also, make this register immutable after the VM has started running. To maintain the existing expectations, instead of returning an error, KVM returns a success for these two cases. Finally, ignore writes to read-only bits that are cleared on vCPU reset, and RES{0,1} bits (including writable bits that KVM doesn't support yet), as those bits shouldn't be modified (at least with the current KVM). Co-developed-by: Marc Zyngier <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Reiji Watanabe <[email protected]> Signed-off-by: Raghavendra Rao Ananta <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent 27131b1 commit ea9ca90

File tree

1 file changed

+42
-4
lines changed

1 file changed

+42
-4
lines changed

arch/arm64/kvm/sys_regs.c

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -719,9 +719,9 @@ static unsigned int pmu_visibility(const struct kvm_vcpu *vcpu,
719719

720720
static u64 reset_pmu_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
721721
{
722-
u64 n, mask = BIT(ARMV8_PMU_CYCLE_IDX);
722+
u64 mask = BIT(ARMV8_PMU_CYCLE_IDX);
723+
u8 n = vcpu->kvm->arch.pmcr_n;
723724

724-
n = vcpu->kvm->arch.pmcr_n;
725725
if (n)
726726
mask |= GENMASK(n - 1, 0);
727727

@@ -1136,6 +1136,44 @@ static int get_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
11361136
return 0;
11371137
}
11381138

1139+
static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
1140+
u64 val)
1141+
{
1142+
u8 new_n = (val >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
1143+
struct kvm *kvm = vcpu->kvm;
1144+
1145+
mutex_lock(&kvm->arch.config_lock);
1146+
1147+
/*
1148+
* The vCPU can't have more counters than the PMU hardware
1149+
* implements. Ignore this error to maintain compatibility
1150+
* with the existing KVM behavior.
1151+
*/
1152+
if (!kvm_vm_has_ran_once(kvm) &&
1153+
new_n <= kvm_arm_pmu_get_max_counters(kvm))
1154+
kvm->arch.pmcr_n = new_n;
1155+
1156+
mutex_unlock(&kvm->arch.config_lock);
1157+
1158+
/*
1159+
* Ignore writes to RES0 bits, read only bits that are cleared on
1160+
* vCPU reset, and writable bits that KVM doesn't support yet.
1161+
* (i.e. only PMCR.N and bits [7:0] are mutable from userspace)
1162+
* The LP bit is RES0 when FEAT_PMUv3p5 is not supported on the vCPU.
1163+
* But, we leave the bit as it is here, as the vCPU's PMUver might
1164+
* be changed later (NOTE: the bit will be cleared on first vCPU run
1165+
* if necessary).
1166+
*/
1167+
val &= ARMV8_PMU_PMCR_MASK;
1168+
1169+
/* The LC bit is RES1 when AArch32 is not supported */
1170+
if (!kvm_supports_32bit_el0())
1171+
val |= ARMV8_PMU_PMCR_LC;
1172+
1173+
__vcpu_sys_reg(vcpu, r->reg) = val;
1174+
return 0;
1175+
}
1176+
11391177
/* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
11401178
#define DBG_BCR_BVR_WCR_WVR_EL1(n) \
11411179
{ SYS_DESC(SYS_DBGBVRn_EL1(n)), \
@@ -2201,8 +2239,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
22012239
{ SYS_DESC(SYS_CTR_EL0), access_ctr },
22022240
{ SYS_DESC(SYS_SVCR), undef_access },
22032241

2204-
{ PMU_SYS_REG(PMCR_EL0), .access = access_pmcr,
2205-
.reset = reset_pmcr, .reg = PMCR_EL0, .get_user = get_pmcr },
2242+
{ PMU_SYS_REG(PMCR_EL0), .access = access_pmcr, .reset = reset_pmcr,
2243+
.reg = PMCR_EL0, .get_user = get_pmcr, .set_user = set_pmcr },
22062244
{ PMU_SYS_REG(PMCNTENSET_EL0),
22072245
.access = access_pmcnten, .reg = PMCNTENSET_EL0,
22082246
.get_user = get_pmreg, .set_user = set_pmreg },

0 commit comments

Comments
 (0)