提交 228be998 编写于 作者: P Peng Liang 提交者: Yang Yingliang

kvm: arm64: emulate the ID registers

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: Nzhanghailiang <zhang.zhanghailiang@huawei.com>
Signed-off-by: NPeng Liang <liangpeng10@huawei.com>
Reviewed-by: NXiangyou Xie <xiexiangyou@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 c8e1b4e4
......@@ -330,6 +330,8 @@ struct kvm_vcpu_arch {
bool pv_unhalted;
gpa_t base;
} pvsched;
struct id_registers idregs;
};
/* vcpu_arch flags field values: */
......
......@@ -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 */
......
......@@ -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
*/
......
......@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册