Skip to content

Commit 76d883c

Browse files
Shannon ZhaoMarc Zyngier
authored andcommitted
arm64: KVM: Add access handler for PMOVSSET and PMOVSCLR register
Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use reset_unknown for its reset handler. Add a handler to emulate writing PMOVSSET or PMOVSCLR register. When writing non-zero value to PMOVSSET, the counter and its interrupt is enabled, kick this vcpu to sync PMU interrupt. Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org> Reviewed-by: Andrew Jones <drjones@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent 9db52c7 commit 76d883c

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ enum vcpu_sysreg {
128128
PMCCFILTR_EL0, /* Cycle Count Filter Register */
129129
PMCNTENSET_EL0, /* Count Enable Set Register */
130130
PMINTENSET_EL1, /* Interrupt Enable Set Register */
131+
PMOVSSET_EL0, /* Overflow Flag Status Set Register */
131132

132133
/* 32bit specific registers. Keep them at the end of the range */
133134
DACR32_EL2, /* Domain Access Control Register */

arch/arm64/kvm/sys_regs.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,28 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
650650
return true;
651651
}
652652

653+
static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
654+
const struct sys_reg_desc *r)
655+
{
656+
u64 mask = kvm_pmu_valid_counter_mask(vcpu);
657+
658+
if (!kvm_arm_pmu_v3_ready(vcpu))
659+
return trap_raz_wi(vcpu, p, r);
660+
661+
if (p->is_write) {
662+
if (r->CRm & 0x2)
663+
/* accessing PMOVSSET_EL0 */
664+
kvm_pmu_overflow_set(vcpu, p->regval & mask);
665+
else
666+
/* accessing PMOVSCLR_EL0 */
667+
vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
668+
} else {
669+
p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
670+
}
671+
672+
return true;
673+
}
674+
653675
/* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
654676
#define DBG_BCR_BVR_WCR_WVR_EL1(n) \
655677
/* DBGBVRn_EL1 */ \
@@ -857,7 +879,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
857879
access_pmcnten, NULL, PMCNTENSET_EL0 },
858880
/* PMOVSCLR_EL0 */
859881
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
860-
trap_raz_wi },
882+
access_pmovs, NULL, PMOVSSET_EL0 },
861883
/* PMSWINC_EL0 */
862884
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
863885
trap_raz_wi },
@@ -884,7 +906,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
884906
trap_raz_wi },
885907
/* PMOVSSET_EL0 */
886908
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
887-
trap_raz_wi },
909+
access_pmovs, reset_unknown, PMOVSSET_EL0 },
888910

889911
/* TPIDR_EL0 */
890912
{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
@@ -1198,7 +1220,7 @@ static const struct sys_reg_desc cp15_regs[] = {
11981220
{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
11991221
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcnten },
12001222
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcnten },
1201-
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
1223+
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovs },
12021224
{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
12031225
{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
12041226
{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
@@ -1208,6 +1230,7 @@ static const struct sys_reg_desc cp15_regs[] = {
12081230
{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
12091231
{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pminten },
12101232
{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pminten },
1233+
{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovs },
12111234

12121235
{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
12131236
{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },

include/kvm/arm_pmu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
4343
u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu);
4444
void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
4545
void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
46+
void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
4647
void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
4748
u64 select_idx);
4849
#else
@@ -63,6 +64,7 @@ static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
6364
}
6465
static inline void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
6566
static inline void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
67+
static inline void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
6668
static inline void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu,
6769
u64 data, u64 select_idx) {}
6870
#endif

virt/kvm/arm/pmu.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,37 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
149149
}
150150
}
151151

152+
static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
153+
{
154+
u64 reg = 0;
155+
156+
if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E))
157+
reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
158+
reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
159+
reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
160+
reg &= kvm_pmu_valid_counter_mask(vcpu);
161+
162+
return reg;
163+
}
164+
165+
/**
166+
* kvm_pmu_overflow_set - set PMU overflow interrupt
167+
* @vcpu: The vcpu pointer
168+
* @val: the value guest writes to PMOVSSET register
169+
*/
170+
void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
171+
{
172+
u64 reg;
173+
174+
if (val == 0)
175+
return;
176+
177+
vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= val;
178+
reg = kvm_pmu_overflow_status(vcpu);
179+
if (reg != 0)
180+
kvm_vcpu_kick(vcpu);
181+
}
182+
152183
static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
153184
{
154185
return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&

0 commit comments

Comments
 (0)