Skip to content

Commit 164b5e2

Browse files
Marc Zyngieroupton
authored andcommitted
KVM: arm64: nv: Handle CNTHCTL_EL2 specially
Accessing CNTHCTL_EL2 is fraught with danger if running with HCR_EL2.E2H=1: half of the bits are held in CNTKCTL_EL1, and thus can be changed behind our back, while the rest lives in the CNTHCTL_EL2 shadow copy that is memory-based. Yes, this is a lot of fun! Make sure that we merge the two on read access, while we can write to CNTKCTL_EL1 in a more straightforward manner. Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent dfeb916 commit 164b5e2

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

arch/arm64/kvm/sys_regs.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,21 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
157157
if (!is_hyp_ctxt(vcpu))
158158
goto memory_read;
159159

160+
/*
161+
* CNTHCTL_EL2 requires some special treatment to
162+
* account for the bits that can be set via CNTKCTL_EL1.
163+
*/
164+
switch (reg) {
165+
case CNTHCTL_EL2:
166+
if (vcpu_el2_e2h_is_set(vcpu)) {
167+
val = read_sysreg_el1(SYS_CNTKCTL);
168+
val &= CNTKCTL_VALID_BITS;
169+
val |= __vcpu_sys_reg(vcpu, reg) & ~CNTKCTL_VALID_BITS;
170+
return val;
171+
}
172+
break;
173+
}
174+
160175
/*
161176
* If this register does not have an EL1 counterpart,
162177
* then read the stored EL2 version.
@@ -207,6 +222,19 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
207222
*/
208223
__vcpu_sys_reg(vcpu, reg) = val;
209224

225+
switch (reg) {
226+
case CNTHCTL_EL2:
227+
/*
228+
* If E2H=0, CNHTCTL_EL2 is a pure shadow register.
229+
* Otherwise, some of the bits are backed by
230+
* CNTKCTL_EL1, while the rest is kept in memory.
231+
* Yes, this is fun stuff.
232+
*/
233+
if (vcpu_el2_e2h_is_set(vcpu))
234+
write_sysreg_el1(val, SYS_CNTKCTL);
235+
return;
236+
}
237+
210238
/* No EL1 counterpart? We're done here.? */
211239
if (reg == el1r)
212240
return;

include/kvm/arm_arch_timer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ u64 timer_get_cval(struct arch_timer_context *ctxt);
147147
void kvm_timer_cpu_up(void);
148148
void kvm_timer_cpu_down(void);
149149

150+
/* CNTKCTL_EL1 valid bits as of DDI0487J.a */
151+
#define CNTKCTL_VALID_BITS (BIT(17) | GENMASK_ULL(9, 0))
152+
150153
static inline bool has_cntpoff(void)
151154
{
152155
return (has_vhe() && cpus_have_final_cap(ARM64_HAS_ECV_CNTPOFF));

0 commit comments

Comments
 (0)