From: Peng Liang liangpeng10@huawei.com
hulk inclusion category: feature bugzilla: NA CVE: NA
To emulate the ID registers, we need a place to storage the values of the ID regsiters. Maybe putting in kvm_arch_vcpu is a good idea.
This commit has no functional changes but only code refactor. When initializing a vcpu, get the values of the ID registers from arm64_ftr_regs and storage them in kvm_arch_vcpu. And we just read the value from kvm_arch_vcpu when getting/setting the value of the ID regs.
Signed-off-by: zhanghailiang zhang.zhanghailiang@huawei.com Signed-off-by: Peng Liang liangpeng10@huawei.com Reviewed-by: Xiangyou Xie xiexiangyou@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- arch/arm64/include/asm/kvm_host.h | 2 ++ arch/arm64/kvm/sys_regs.c | 47 +++++++++++++++++++++++-------- include/uapi/linux/kvm.h | 11 ++++++++ virt/kvm/arm/arm.c | 22 +++++++++++++++ 4 files changed, 71 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 354bd5b9f1792..f3c1a2263623b 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -330,6 +330,8 @@ struct kvm_vcpu_arch { bool pv_unhalted; gpa_t base; } pvsched; + + struct id_registers idregs; };
/* vcpu_arch flags field values: */ diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index c557eb95cb8e7..ccb868dc0efa7 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1031,12 +1031,35 @@ static bool access_cntp_cval(struct kvm_vcpu *vcpu, return true; }
+static struct id_reg_info *kvm_id_reg(struct kvm_vcpu *vcpu, u64 id) +{ + int i; + + for (i = 0; i < vcpu->arch.idregs.num; ++i) { + if (vcpu->arch.idregs.regs[i].sys_id == id) + return &vcpu->arch.idregs.regs[i]; + } + return NULL; +} + +static u64 kvm_get_id_reg(struct kvm_vcpu *vcpu, u64 id) +{ + struct id_reg_info *ri = kvm_id_reg(vcpu, id); + + if (!ri) { + WARN_ON(1); + return 0; + } + return ri->sys_val; +} + /* Read a sanitised cpufeature ID register by sys_reg_desc */ -static u64 read_id_reg(struct sys_reg_desc const *r, bool raz) +static u64 read_id_reg(struct kvm_vcpu *vcpu, + struct sys_reg_desc const *r, bool raz) { u32 id = sys_reg((u32)r->Op0, (u32)r->Op1, (u32)r->CRn, (u32)r->CRm, (u32)r->Op2); - u64 val = raz ? 0 : read_sanitised_ftr_reg(id); + u64 val = raz ? 0 : kvm_get_id_reg(vcpu, id);
if (id == SYS_ID_AA64PFR0_EL1) { if (val & (0xfUL << ID_AA64PFR0_SVE_SHIFT)) @@ -1063,7 +1086,7 @@ static bool __access_id_reg(struct kvm_vcpu *vcpu, if (p->is_write) return write_to_read_only(vcpu, p, r);
- p->regval = read_id_reg(r, raz); + p->regval = read_id_reg(vcpu, r, raz); return true; }
@@ -1092,16 +1115,18 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg); * are stored, and for set_id_reg() we don't allow the effective value * to be changed. */ -static int __get_id_reg(const struct sys_reg_desc *rd, void __user *uaddr, +static int __get_id_reg(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, void __user *uaddr, bool raz) { const u64 id = sys_reg_to_index(rd); - const u64 val = read_id_reg(rd, raz); + const u64 val = read_id_reg(vcpu, rd, raz);
return reg_to_user(uaddr, &val, id); }
-static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr, +static int __set_id_reg(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, void __user *uaddr, bool raz) { const u64 id = sys_reg_to_index(rd); @@ -1113,7 +1138,7 @@ static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr, return err;
/* This is what we mean by invariant: you can't change it. */ - if (val != read_id_reg(rd, raz)) + if (val != read_id_reg(vcpu, rd, raz)) return -EINVAL;
return 0; @@ -1122,25 +1147,25 @@ static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr, static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, const struct kvm_one_reg *reg, void __user *uaddr) { - return __get_id_reg(rd, uaddr, false); + return __get_id_reg(vcpu, rd, uaddr, false); }
static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, const struct kvm_one_reg *reg, void __user *uaddr) { - return __set_id_reg(rd, uaddr, false); + return __set_id_reg(vcpu, rd, uaddr, false); }
static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, const struct kvm_one_reg *reg, void __user *uaddr) { - return __get_id_reg(rd, uaddr, true); + return __get_id_reg(vcpu, rd, uaddr, true); }
static int set_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, const struct kvm_one_reg *reg, void __user *uaddr) { - return __set_id_reg(rd, uaddr, true); + return __set_id_reg(vcpu, rd, uaddr, true); }
/* sys_reg_desc initialiser for known cpufeature ID registers */ diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 211888d0c4e14..4735689dc8eb2 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1197,6 +1197,17 @@ struct kvm_vfio_spapr_tce { __s32 tablefd; };
+#define ID_REG_MAX_NUMS 64 +struct id_reg_info { + uint64_t sys_id; + uint64_t sys_val; +}; + +struct id_registers { + struct id_reg_info regs[ID_REG_MAX_NUMS]; + uint64_t num; +}; + /* * ioctls for VM fds */ diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 3c484da5aa3e8..cd6710630b52d 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -277,6 +277,24 @@ void kvm_arch_free_vm(struct kvm *kvm) vfree(kvm); }
+static int get_cpu_ftr(u32 id, u64 val, void *argp) +{ + struct id_registers *idregs = argp; + + /* + * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), + * where 1<=crm<8, 0<=op2<8. + */ + if (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && + sys_reg_CRn(id) == 0 && sys_reg_CRm(id) > 0) { + idregs->regs[idregs->num].sys_id = id; + idregs->regs[idregs->num].sys_val = val; + idregs->num++; + } + + return 0; +} + struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) { int err; @@ -302,6 +320,10 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) if (err) goto free_vcpu;
+ err = arm64_cpu_ftr_regs_traverse(get_cpu_ftr, &vcpu->arch.idregs); + if (err) + goto free_vcpu; + err = create_hyp_mappings(vcpu, vcpu + 1, PAGE_HYP); if (err) goto vcpu_uninit;