Skip to content

Commit a45f41d

Browse files
rananta468oupton
authored andcommitted
KVM: arm64: Add {get,set}_user for PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR}
For unimplemented counters, the bits in PM{C,I}NTEN{SET,CLR} and PMOVS{SET,CLR} registers are expected to RAZ. To honor this, explicitly implement the {get,set}_user functions for these registers to mask out unimplemented counters for userspace reads and writes. Co-developed-by: Marc Zyngier <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Raghavendra Rao Ananta <[email protected]> Link: https://lore.kernel.org/r/[email protected] [Oliver: drop unnecessary locking] Signed-off-by: Oliver Upton <[email protected]>
1 parent 4d20deb commit a45f41d

File tree

1 file changed

+45
-6
lines changed

1 file changed

+45
-6
lines changed

arch/arm64/kvm/sys_regs.c

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,39 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
987987
return true;
988988
}
989989

990+
static int set_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 val)
991+
{
992+
bool set;
993+
994+
val &= kvm_pmu_valid_counter_mask(vcpu);
995+
996+
switch (r->reg) {
997+
case PMOVSSET_EL0:
998+
/* CRm[1] being set indicates a SET register, and CLR otherwise */
999+
set = r->CRm & 2;
1000+
break;
1001+
default:
1002+
/* Op2[0] being set indicates a SET register, and CLR otherwise */
1003+
set = r->Op2 & 1;
1004+
break;
1005+
}
1006+
1007+
if (set)
1008+
__vcpu_sys_reg(vcpu, r->reg) |= val;
1009+
else
1010+
__vcpu_sys_reg(vcpu, r->reg) &= ~val;
1011+
1012+
return 0;
1013+
}
1014+
1015+
static int get_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 *val)
1016+
{
1017+
u64 mask = kvm_pmu_valid_counter_mask(vcpu);
1018+
1019+
*val = __vcpu_sys_reg(vcpu, r->reg) & mask;
1020+
return 0;
1021+
}
1022+
9901023
static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
9911024
const struct sys_reg_desc *r)
9921025
{
@@ -2116,9 +2149,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
21162149
/* PMBIDR_EL1 is not trapped */
21172150

21182151
{ PMU_SYS_REG(PMINTENSET_EL1),
2119-
.access = access_pminten, .reg = PMINTENSET_EL1 },
2152+
.access = access_pminten, .reg = PMINTENSET_EL1,
2153+
.get_user = get_pmreg, .set_user = set_pmreg },
21202154
{ PMU_SYS_REG(PMINTENCLR_EL1),
2121-
.access = access_pminten, .reg = PMINTENSET_EL1 },
2155+
.access = access_pminten, .reg = PMINTENSET_EL1,
2156+
.get_user = get_pmreg, .set_user = set_pmreg },
21222157
{ SYS_DESC(SYS_PMMIR_EL1), trap_raz_wi },
21232158

21242159
{ SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 },
@@ -2169,11 +2204,14 @@ static const struct sys_reg_desc sys_reg_descs[] = {
21692204
{ PMU_SYS_REG(PMCR_EL0), .access = access_pmcr,
21702205
.reset = reset_pmcr, .reg = PMCR_EL0, .get_user = get_pmcr },
21712206
{ PMU_SYS_REG(PMCNTENSET_EL0),
2172-
.access = access_pmcnten, .reg = PMCNTENSET_EL0 },
2207+
.access = access_pmcnten, .reg = PMCNTENSET_EL0,
2208+
.get_user = get_pmreg, .set_user = set_pmreg },
21732209
{ PMU_SYS_REG(PMCNTENCLR_EL0),
2174-
.access = access_pmcnten, .reg = PMCNTENSET_EL0 },
2210+
.access = access_pmcnten, .reg = PMCNTENSET_EL0,
2211+
.get_user = get_pmreg, .set_user = set_pmreg },
21752212
{ PMU_SYS_REG(PMOVSCLR_EL0),
2176-
.access = access_pmovs, .reg = PMOVSSET_EL0 },
2213+
.access = access_pmovs, .reg = PMOVSSET_EL0,
2214+
.get_user = get_pmreg, .set_user = set_pmreg },
21772215
/*
21782216
* PM_SWINC_EL0 is exposed to userspace as RAZ/WI, as it was
21792217
* previously (and pointlessly) advertised in the past...
@@ -2201,7 +2239,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
22012239
{ PMU_SYS_REG(PMUSERENR_EL0), .access = access_pmuserenr,
22022240
.reset = reset_val, .reg = PMUSERENR_EL0, .val = 0 },
22032241
{ PMU_SYS_REG(PMOVSSET_EL0),
2204-
.access = access_pmovs, .reg = PMOVSSET_EL0 },
2242+
.access = access_pmovs, .reg = PMOVSSET_EL0,
2243+
.get_user = get_pmreg, .set_user = set_pmreg },
22052244

22062245
{ SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
22072246
{ SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },

0 commit comments

Comments
 (0)