Skip to content

Commit 77a0c42

Browse files
author
Marc Zyngier
committed
KVM: arm64: Add timer UAPI workaround to sysreg infrastructure
Amongst the numerous bugs that plague the KVM/arm64 UAPI, one of the most annoying thing is that the userspace view of the virtual timer has its CVAL and CNT encodings swapped. In order to reduce the amount of code that has to know about this, start by adding handling for this bug in the sys_reg code. Nothing is making use of it yet, as the code responsible for userspace interaction is catching the accesses early. Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent a92d552 commit 77a0c42

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

arch/arm64/kvm/sys_regs.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5231,15 +5231,28 @@ static int demux_c15_set(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
52315231
}
52325232
}
52335233

5234+
static u64 kvm_one_reg_to_id(const struct kvm_one_reg *reg)
5235+
{
5236+
switch(reg->id) {
5237+
case KVM_REG_ARM_TIMER_CVAL:
5238+
return TO_ARM64_SYS_REG(CNTV_CVAL_EL0);
5239+
case KVM_REG_ARM_TIMER_CNT:
5240+
return TO_ARM64_SYS_REG(CNTVCT_EL0);
5241+
default:
5242+
return reg->id;
5243+
}
5244+
}
5245+
52345246
int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
52355247
const struct sys_reg_desc table[], unsigned int num)
52365248
{
52375249
u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr;
52385250
const struct sys_reg_desc *r;
5251+
u64 id = kvm_one_reg_to_id(reg);
52395252
u64 val;
52405253
int ret;
52415254

5242-
r = id_to_sys_reg_desc(vcpu, reg->id, table, num);
5255+
r = id_to_sys_reg_desc(vcpu, id, table, num);
52435256
if (!r || sysreg_hidden(vcpu, r))
52445257
return -ENOENT;
52455258

@@ -5272,13 +5285,14 @@ int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
52725285
{
52735286
u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr;
52745287
const struct sys_reg_desc *r;
5288+
u64 id = kvm_one_reg_to_id(reg);
52755289
u64 val;
52765290
int ret;
52775291

52785292
if (get_user(val, uaddr))
52795293
return -EFAULT;
52805294

5281-
r = id_to_sys_reg_desc(vcpu, reg->id, table, num);
5295+
r = id_to_sys_reg_desc(vcpu, id, table, num);
52825296
if (!r || sysreg_hidden(vcpu, r))
52835297
return -ENOENT;
52845298

@@ -5338,10 +5352,23 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg)
53385352

53395353
static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
53405354
{
5355+
u64 idx;
5356+
53415357
if (!*uind)
53425358
return true;
53435359

5344-
if (put_user(sys_reg_to_index(reg), *uind))
5360+
switch (reg_to_encoding(reg)) {
5361+
case SYS_CNTV_CVAL_EL0:
5362+
idx = KVM_REG_ARM_TIMER_CVAL;
5363+
break;
5364+
case SYS_CNTVCT_EL0:
5365+
idx = KVM_REG_ARM_TIMER_CNT;
5366+
break;
5367+
default:
5368+
idx = sys_reg_to_index(reg);
5369+
}
5370+
5371+
if (put_user(idx, *uind))
53455372
return false;
53465373

53475374
(*uind)++;

arch/arm64/kvm/sys_regs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,10 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu);
257257
(val); \
258258
})
259259

260+
#define TO_ARM64_SYS_REG(r) ARM64_SYS_REG(sys_reg_Op0(SYS_ ## r), \
261+
sys_reg_Op1(SYS_ ## r), \
262+
sys_reg_CRn(SYS_ ## r), \
263+
sys_reg_CRm(SYS_ ## r), \
264+
sys_reg_Op2(SYS_ ## r))
265+
260266
#endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */

0 commit comments

Comments
 (0)