[PATCH RFC 3/7] ARM64: KVM: Reset ID registers when creating the VCPUs

2017-01-16 Thread Shannon Zhao
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

2017-01-28 Thread Andrew Jones
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