[PATCH RFC 3/7] ARM64: KVM: Reset ID registers when creating the VCPUs
From: Shannon Zhao Reset ID registers when creating the VCPUs and store the values per VCPU. Also modify the get_invariant_sys_reg and set_invariant_sys_reg to get/set the ID register from vcpu context. Signed-off-by: Shannon Zhao --- arch/arm64/include/asm/kvm_coproc.h | 1 + arch/arm64/kvm/guest.c | 1 + arch/arm64/kvm/sys_regs.c | 58 ++--- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/arch/arm64/include/asm/kvm_coproc.h b/arch/arm64/include/asm/kvm_coproc.h index 0b52377..0801b66 100644 --- a/arch/arm64/include/asm/kvm_coproc.h +++ b/arch/arm64/include/asm/kvm_coproc.h @@ -24,6 +24,7 @@ #include void kvm_reset_sys_regs(struct kvm_vcpu *vcpu); +void kvm_reset_id_sys_regs(struct kvm_vcpu *vcpu); struct kvm_sys_reg_table { const struct sys_reg_desc *table; diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index b37446a..92abe2b 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -48,6 +48,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) { + kvm_reset_id_sys_regs(vcpu); return 0; } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index bf71eb4..7c5fa03 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1440,11 +1440,11 @@ static const struct sys_reg_desc cp15_64_regs[] = { * the guest, or a future kvm may trap them. */ -#define FUNCTION_INVARIANT(reg) \ - static void get_##reg(struct kvm_vcpu *v, \ - const struct sys_reg_desc *r) \ +#define FUNCTION_INVARIANT(register) \ + static void get_##register(struct kvm_vcpu *v, \ + const struct sys_reg_desc *r)\ { \ - ((struct sys_reg_desc *)r)->val = read_sysreg(reg); \ + vcpu_id_sys_reg(v, r->reg) = read_sysreg(register); \ } FUNCTION_INVARIANT(midr_el1) @@ -1480,7 +1480,6 @@ FUNCTION_INVARIANT(id_aa64mmfr1_el1) FUNCTION_INVARIANT(clidr_el1) FUNCTION_INVARIANT(aidr_el1) -/* ->val is filled in by kvm_sys_reg_table_init() */ static struct sys_reg_desc invariant_sys_regs[] = { { Op0(0b11), Op1(0b000), CRn(0b), CRm(0b), Op2(0b000), NULL, get_midr_el1, MIDR_EL1 }, @@ -1952,43 +1951,43 @@ static int reg_to_user(void __user *uaddr, const u64 *val, u64 id) return 0; } -static int get_invariant_sys_reg(u64 id, void __user *uaddr) +static int get_invariant_sys_reg(struct kvm_vcpu *vcpu, +const struct kvm_one_reg *reg) { struct sys_reg_params params; const struct sys_reg_desc *r; + void __user *uaddr = (void __user *)(unsigned long)reg->addr; - if (!index_to_params(id, ¶ms)) + if (!index_to_params(reg->id, ¶ms)) return -ENOENT; r = find_reg(¶ms, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs)); if (!r) return -ENOENT; - return reg_to_user(uaddr, &r->val, id); + if (r->get_user) + return (r->get_user)(vcpu, r, reg, uaddr); + + return reg_to_user(uaddr, &vcpu_id_sys_reg(vcpu, r->reg), reg->id); } -static int set_invariant_sys_reg(u64 id, void __user *uaddr) +static int set_invariant_sys_reg(struct kvm_vcpu *vcpu, +const struct kvm_one_reg *reg) { struct sys_reg_params params; const struct sys_reg_desc *r; - int err; - u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */ + void __user *uaddr = (void __user *)(unsigned long)reg->addr; - if (!index_to_params(id, ¶ms)) + if (!index_to_params(reg->id, ¶ms)) return -ENOENT; r = find_reg(¶ms, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs)); if (!r) return -ENOENT; - err = reg_from_user(&val, uaddr, id); - if (err) - return err; - - /* This is what we mean by invariant: you can't change it. */ - if (r->val != val) - return -EINVAL; + if (r->set_user) + return (r->set_user)(vcpu, r, reg, uaddr); - return 0; + return reg_from_user(&vcpu_id_sys_reg(vcpu, r->reg), uaddr, reg->id); } static bool is_valid_cache(u32 val) @@ -2086,7 +2085,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg r = index_to_sys_reg_desc(vcpu, reg->id); if (!r) - return get_invariant_sys_reg(reg->id, uaddr); + return get_invariant_sys_reg(vcpu, reg); if (r->get_user) return (r->get_user)(vcpu, r, reg, uaddr); @@ -2107,7 +2106,7 @@ int kvm_arm_sys_reg_set_reg(str
Re: [PATCH RFC 3/7] ARM64: KVM: Reset ID registers when creating the VCPUs
On Mon, Jan 16, 2017 at 05:33:30PM +0800, Shannon Zhao wrote: > From: Shannon Zhao > > Reset ID registers when creating the VCPUs and store the values per > VCPU. Also modify the get_invariant_sys_reg and set_invariant_sys_reg > to get/set the ID register from vcpu context. The patch does more than that. It also prepares the table to be used with get/set_one_reg. The name 'invariant' is less and less fitting, and should probably be changed before this patch to 'id', or we should just integrate these ID registers into the sys_reg table. I still haven't seen the motivation for not doing that yet. > > Signed-off-by: Shannon Zhao > --- > arch/arm64/include/asm/kvm_coproc.h | 1 + > arch/arm64/kvm/guest.c | 1 + > arch/arm64/kvm/sys_regs.c | 58 > ++--- > 3 files changed, 31 insertions(+), 29 deletions(-) > > diff --git a/arch/arm64/include/asm/kvm_coproc.h > b/arch/arm64/include/asm/kvm_coproc.h > index 0b52377..0801b66 100644 > --- a/arch/arm64/include/asm/kvm_coproc.h > +++ b/arch/arm64/include/asm/kvm_coproc.h > @@ -24,6 +24,7 @@ > #include > > void kvm_reset_sys_regs(struct kvm_vcpu *vcpu); > +void kvm_reset_id_sys_regs(struct kvm_vcpu *vcpu); > > struct kvm_sys_reg_table { > const struct sys_reg_desc *table; > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c > index b37446a..92abe2b 100644 > --- a/arch/arm64/kvm/guest.c > +++ b/arch/arm64/kvm/guest.c > @@ -48,6 +48,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { > > int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) > { > + kvm_reset_id_sys_regs(vcpu); This call should go in kvm_reset_vcpu > return 0; > } > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index bf71eb4..7c5fa03 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1440,11 +1440,11 @@ static const struct sys_reg_desc cp15_64_regs[] = { > * the guest, or a future kvm may trap them. > */ > > -#define FUNCTION_INVARIANT(reg) > \ > - static void get_##reg(struct kvm_vcpu *v, \ > - const struct sys_reg_desc *r) \ > +#define FUNCTION_INVARIANT(register) \ > + static void get_##register(struct kvm_vcpu *v, \ > +const struct sys_reg_desc *r)\ > { \ > - ((struct sys_reg_desc *)r)->val = read_sysreg(reg); \ > + vcpu_id_sys_reg(v, r->reg) = read_sysreg(register); \ > } > > FUNCTION_INVARIANT(midr_el1) > @@ -1480,7 +1480,6 @@ FUNCTION_INVARIANT(id_aa64mmfr1_el1) > FUNCTION_INVARIANT(clidr_el1) > FUNCTION_INVARIANT(aidr_el1) > > -/* ->val is filled in by kvm_sys_reg_table_init() */ > static struct sys_reg_desc invariant_sys_regs[] = { > { Op0(0b11), Op1(0b000), CRn(0b), CRm(0b), Op2(0b000), > NULL, get_midr_el1, MIDR_EL1 }, > @@ -1952,43 +1951,43 @@ static int reg_to_user(void __user *uaddr, const u64 > *val, u64 id) > return 0; > } > > -static int get_invariant_sys_reg(u64 id, void __user *uaddr) > +static int get_invariant_sys_reg(struct kvm_vcpu *vcpu, > + const struct kvm_one_reg *reg) > { > struct sys_reg_params params; > const struct sys_reg_desc *r; > + void __user *uaddr = (void __user *)(unsigned long)reg->addr; > > - if (!index_to_params(id, ¶ms)) > + if (!index_to_params(reg->id, ¶ms)) > return -ENOENT; > > r = find_reg(¶ms, invariant_sys_regs, > ARRAY_SIZE(invariant_sys_regs)); > if (!r) > return -ENOENT; > > - return reg_to_user(uaddr, &r->val, id); > + if (r->get_user) > + return (r->get_user)(vcpu, r, reg, uaddr); > + > + return reg_to_user(uaddr, &vcpu_id_sys_reg(vcpu, r->reg), reg->id); > } > > -static int set_invariant_sys_reg(u64 id, void __user *uaddr) > +static int set_invariant_sys_reg(struct kvm_vcpu *vcpu, > + const struct kvm_one_reg *reg) > { > struct sys_reg_params params; > const struct sys_reg_desc *r; > - int err; > - u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */ > + void __user *uaddr = (void __user *)(unsigned long)reg->addr; > > - if (!index_to_params(id, ¶ms)) > + if (!index_to_params(reg->id, ¶ms)) > return -ENOENT; > r = find_reg(¶ms, invariant_sys_regs, > ARRAY_SIZE(invariant_sys_regs)); > if (!r) > return -ENOENT; > > - err = reg_from_user(&val, uaddr, id); > - if (err) > - return err; > - > - /* This is what we mean by invariant: you can't change it. */ > - if (r->val != val) > - return -EINVAL; > + if (r->set_user) > + return (r->set_user)(vcpu, r, reg