Re: [PATCH v5] ARM/KVM: save and restore generic timer registers

2013-12-17 Thread Marc Zyngier
On 13/12/13 20:35, Andre Przywara wrote:
 On 12/13/2013 09:10 PM, Christoffer Dall wrote:
 On Fri, Dec 13, 2013 at 02:23:26PM +0100, Andre Przywara wrote:
 For migration to work we need to save (and later restore) the state of
 each core's virtual generic timer.
 Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export
 the three needed registers (control, counter, compare value).
 Though they live in cp15 space, we don't use the existing list, since
 they need special accessor functions and the arch timer is optional.

 Signed-off-by: Andre Przywara andre.przyw...@linaro.org
 Signed-off-by: Christoffer Dall christoffer.d...@linaro.org
 ---
 Changes from v1:
 - move code out of coproc.c and into guest.c and arch_timer.c
 - present the registers with their native CP15 addresses, but without
using space in the VCPU's cp15 array
 - do the user space copying in the accessor functions

 Changes from v2:
 - fix compilation without CONFIG_ARCH_TIMER
 - fix compilation for arm64 by defining the appropriate registers there
 - move userspace access out of arch_timer.c into coproc.c
 - Christoffer: removed whitespace in function declaration

 Changes from v3:
 - adapted Marc's SYSREG macro magic from kvmtool for nicer looking code

 Changes from v4:
 - remove ARM64-REG32 type, the ARM ARM defines no 32-bit system registers

   arch/arm/include/asm/kvm_host.h   |  3 ++
   arch/arm/include/uapi/asm/kvm.h   | 20 +
   arch/arm/kvm/guest.c  | 92 
 ++-
   arch/arm64/include/uapi/asm/kvm.h | 18 
   virt/kvm/arm/arch_timer.c | 34 +++
   5 files changed, 166 insertions(+), 1 deletion(-)

 diff --git a/arch/arm/include/asm/kvm_host.h 
 b/arch/arm/include/asm/kvm_host.h
 index 8a6f6db..098f7dd 100644
 --- a/arch/arm/include/asm/kvm_host.h
 +++ b/arch/arm/include/asm/kvm_host.h
 @@ -225,4 +225,7 @@ static inline int 
 kvm_arch_dev_ioctl_check_extension(long ext)
   int kvm_perf_init(void);
   int kvm_perf_teardown(void);

 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
 +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
 +
   #endif /* __ARM_KVM_HOST_H__ */
 diff --git a/arch/arm/include/uapi/asm/kvm.h 
 b/arch/arm/include/uapi/asm/kvm.h
 index c498b60..835b867 100644
 --- a/arch/arm/include/uapi/asm/kvm.h
 +++ b/arch/arm/include/uapi/asm/kvm.h
 @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot {
   #define KVM_REG_ARM_32_CRN_MASK   0x7800
   #define KVM_REG_ARM_32_CRN_SHIFT  11

 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \
 +   (((x)  KVM_REG_ARM_ ## n ## _SHIFT)  KVM_REG_ARM_ ## n ## _MASK)
 +
 +#define __ARM_CP15_REG(op1,crn,crm,op2) \
 +   (KVM_REG_ARM | (15  KVM_REG_ARM_COPROC_SHIFT) | \
 +   ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
 +   ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
 +   ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
 +   ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
 +
 +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | 
 KVM_REG_SIZE_U32)
 +
 +#define __ARM_CP15_REG64(op1,crm) \
 +   (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
 +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
 +
 +#define KVM_REG_ARM_TIMER_CTL  ARM_CP15_REG32(0, 14, 3, 1)
 +#define KVM_REG_ARM_TIMER_CNT  ARM_CP15_REG64(1, 14)
 +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14)
 +
   /* Normal registers are mapped as coprocessor 16. */
   #define KVM_REG_ARM_CORE  (0x0010  KVM_REG_ARM_COPROC_SHIFT)
   #define KVM_REG_ARM_CORE_REG(name)(offsetof(struct kvm_regs, 
 name) / 4)
 diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
 index 20f8d97..2786eae 100644
 --- a/arch/arm/kvm/guest.c
 +++ b/arch/arm/kvm/guest.c
 @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu 
 *vcpu, struct kvm_regs *regs)
 return -EINVAL;
   }

 +#ifndef CONFIG_KVM_ARM_TIMER
 +
 +#define NUM_TIMER_REGS 0
 +
 +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 +{
 +   return 0;
 +}
 +
 +static bool is_timer_reg(u64 index)
 +{
 +   return false;
 +}
 +
 +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
 +{
 +   return 0;
 +}
 +
 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
 +{
 +   return 0;
 +}
 +
 +#else
 +
 +#define NUM_TIMER_REGS 3
 +
 +static bool is_timer_reg(u64 index)
 +{
 +   switch (index) {
 +   case KVM_REG_ARM_TIMER_CTL:
 +   case KVM_REG_ARM_TIMER_CNT:
 +   case KVM_REG_ARM_TIMER_CVAL:
 +   return true;
 +   }
 +   return false;
 +}
 +
 +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 +{
 +   if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
 +   return -EFAULT;
 +   uindices++;
 +   if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
 +   return -EFAULT;
 +   uindices++;
 +   if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
 +   return -EFAULT;
 +
 +   return 0;
 +}
 +
 +#endif
 +
 +static int set_timer_reg(struct 

Re: [PATCH v5] ARM/KVM: save and restore generic timer registers

2013-12-17 Thread Christoffer Dall
On Tue, Dec 17, 2013 at 11:20:20AM +, Marc Zyngier wrote:
 On 13/12/13 20:35, Andre Przywara wrote:
  On 12/13/2013 09:10 PM, Christoffer Dall wrote:
  On Fri, Dec 13, 2013 at 02:23:26PM +0100, Andre Przywara wrote:
  For migration to work we need to save (and later restore) the state of
  each core's virtual generic timer.
  Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export
  the three needed registers (control, counter, compare value).
  Though they live in cp15 space, we don't use the existing list, since
  they need special accessor functions and the arch timer is optional.
 
  Signed-off-by: Andre Przywara andre.przyw...@linaro.org
  Signed-off-by: Christoffer Dall christoffer.d...@linaro.org
  ---
  Changes from v1:
  - move code out of coproc.c and into guest.c and arch_timer.c
  - present the registers with their native CP15 addresses, but without
 using space in the VCPU's cp15 array
  - do the user space copying in the accessor functions
 
  Changes from v2:
  - fix compilation without CONFIG_ARCH_TIMER
  - fix compilation for arm64 by defining the appropriate registers there
  - move userspace access out of arch_timer.c into coproc.c
  - Christoffer: removed whitespace in function declaration
 
  Changes from v3:
  - adapted Marc's SYSREG macro magic from kvmtool for nicer looking code
 
  Changes from v4:
  - remove ARM64-REG32 type, the ARM ARM defines no 32-bit system registers
 
arch/arm/include/asm/kvm_host.h   |  3 ++
arch/arm/include/uapi/asm/kvm.h   | 20 +
arch/arm/kvm/guest.c  | 92 
  ++-
arch/arm64/include/uapi/asm/kvm.h | 18 
virt/kvm/arm/arch_timer.c | 34 +++
5 files changed, 166 insertions(+), 1 deletion(-)
 
  diff --git a/arch/arm/include/asm/kvm_host.h 
  b/arch/arm/include/asm/kvm_host.h
  index 8a6f6db..098f7dd 100644
  --- a/arch/arm/include/asm/kvm_host.h
  +++ b/arch/arm/include/asm/kvm_host.h
  @@ -225,4 +225,7 @@ static inline int 
  kvm_arch_dev_ioctl_check_extension(long ext)
int kvm_perf_init(void);
int kvm_perf_teardown(void);
 
  +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
  +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
  +
#endif /* __ARM_KVM_HOST_H__ */
  diff --git a/arch/arm/include/uapi/asm/kvm.h 
  b/arch/arm/include/uapi/asm/kvm.h
  index c498b60..835b867 100644
  --- a/arch/arm/include/uapi/asm/kvm.h
  +++ b/arch/arm/include/uapi/asm/kvm.h
  @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot {
#define KVM_REG_ARM_32_CRN_MASK 0x7800
#define KVM_REG_ARM_32_CRN_SHIFT11
 
  +#define ARM_CP15_REG_SHIFT_MASK(x,n) \
  + (((x)  KVM_REG_ARM_ ## n ## _SHIFT)  KVM_REG_ARM_ ## n ## _MASK)
  +
  +#define __ARM_CP15_REG(op1,crn,crm,op2) \
  + (KVM_REG_ARM | (15  KVM_REG_ARM_COPROC_SHIFT) | \
  + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
  + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
  + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
  + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
  +
  +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | 
  KVM_REG_SIZE_U32)
  +
  +#define __ARM_CP15_REG64(op1,crm) \
  + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
  +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
  +
  +#define KVM_REG_ARM_TIMER_CTLARM_CP15_REG32(0, 14, 3, 1)
  +#define KVM_REG_ARM_TIMER_CNTARM_CP15_REG64(1, 14)
  +#define KVM_REG_ARM_TIMER_CVAL   ARM_CP15_REG64(3, 14)
  +
/* Normal registers are mapped as coprocessor 16. */
#define KVM_REG_ARM_CORE(0x0010  
  KVM_REG_ARM_COPROC_SHIFT)
#define KVM_REG_ARM_CORE_REG(name)  (offsetof(struct kvm_regs, 
  name) / 4)
  diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
  index 20f8d97..2786eae 100644
  --- a/arch/arm/kvm/guest.c
  +++ b/arch/arm/kvm/guest.c
  @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu 
  *vcpu, struct kvm_regs *regs)
return -EINVAL;
}
 
  +#ifndef CONFIG_KVM_ARM_TIMER
  +
  +#define NUM_TIMER_REGS 0
  +
  +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user 
  *uindices)
  +{
  + return 0;
  +}
  +
  +static bool is_timer_reg(u64 index)
  +{
  + return false;
  +}
  +
  +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
  +{
  + return 0;
  +}
  +
  +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
  +{
  + return 0;
  +}
  +
  +#else
  +
  +#define NUM_TIMER_REGS 3
  +
  +static bool is_timer_reg(u64 index)
  +{
  + switch (index) {
  + case KVM_REG_ARM_TIMER_CTL:
  + case KVM_REG_ARM_TIMER_CNT:
  + case KVM_REG_ARM_TIMER_CVAL:
  + return true;
  + }
  + return false;
  +}
  +
  +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user 
  *uindices)
  +{
  + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
  + return -EFAULT;
  + uindices++;
  + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
  + return 

[PATCH v5] ARM/KVM: save and restore generic timer registers

2013-12-13 Thread Andre Przywara
For migration to work we need to save (and later restore) the state of
each core's virtual generic timer.
Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export
the three needed registers (control, counter, compare value).
Though they live in cp15 space, we don't use the existing list, since
they need special accessor functions and the arch timer is optional.

Signed-off-by: Andre Przywara andre.przyw...@linaro.org
Signed-off-by: Christoffer Dall christoffer.d...@linaro.org
---
Changes from v1:
- move code out of coproc.c and into guest.c and arch_timer.c
- present the registers with their native CP15 addresses, but without
  using space in the VCPU's cp15 array
- do the user space copying in the accessor functions

Changes from v2:
- fix compilation without CONFIG_ARCH_TIMER
- fix compilation for arm64 by defining the appropriate registers there
- move userspace access out of arch_timer.c into coproc.c
- Christoffer: removed whitespace in function declaration

Changes from v3:
- adapted Marc's SYSREG macro magic from kvmtool for nicer looking code

Changes from v4:
- remove ARM64-REG32 type, the ARM ARM defines no 32-bit system registers

 arch/arm/include/asm/kvm_host.h   |  3 ++
 arch/arm/include/uapi/asm/kvm.h   | 20 +
 arch/arm/kvm/guest.c  | 92 ++-
 arch/arm64/include/uapi/asm/kvm.h | 18 
 virt/kvm/arm/arch_timer.c | 34 +++
 5 files changed, 166 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 8a6f6db..098f7dd 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -225,4 +225,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long 
ext)
 int kvm_perf_init(void);
 int kvm_perf_teardown(void);
 
+u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
+int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index c498b60..835b867 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -119,6 +119,26 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_32_CRN_MASK0x7800
 #define KVM_REG_ARM_32_CRN_SHIFT   11
 
+#define ARM_CP15_REG_SHIFT_MASK(x,n) \
+   (((x)  KVM_REG_ARM_ ## n ## _SHIFT)  KVM_REG_ARM_ ## n ## _MASK)
+
+#define __ARM_CP15_REG(op1,crn,crm,op2) \
+   (KVM_REG_ARM | (15  KVM_REG_ARM_COPROC_SHIFT) | \
+   ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
+   ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
+   ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
+   ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
+
+#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32)
+
+#define __ARM_CP15_REG64(op1,crm) \
+   (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
+#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
+
+#define KVM_REG_ARM_TIMER_CTL  ARM_CP15_REG32(0, 14, 3, 1)
+#define KVM_REG_ARM_TIMER_CNT  ARM_CP15_REG64(1, 14) 
+#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) 
+
 /* Normal registers are mapped as coprocessor 16. */
 #define KVM_REG_ARM_CORE   (0x0010  KVM_REG_ARM_COPROC_SHIFT)
 #define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4)
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 20f8d97..2786eae 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, 
struct kvm_regs *regs)
return -EINVAL;
 }
 
+#ifndef CONFIG_KVM_ARM_TIMER
+
+#define NUM_TIMER_REGS 0
+
+static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+   return 0;
+}
+
+static bool is_timer_reg(u64 index)
+{
+   return false;
+}
+
+int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
+{
+   return 0;
+}
+
+u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
+{
+   return 0;
+}
+
+#else
+
+#define NUM_TIMER_REGS 3
+
+static bool is_timer_reg(u64 index)
+{
+   switch (index) {
+   case KVM_REG_ARM_TIMER_CTL:
+   case KVM_REG_ARM_TIMER_CNT:
+   case KVM_REG_ARM_TIMER_CVAL:
+   return true;
+   }
+   return false;
+}
+
+static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+   if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
+   return -EFAULT;
+   uindices++;
+   if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
+   return -EFAULT;
+   uindices++;
+   if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
+   return -EFAULT;
+
+   return 0;
+}
+
+#endif
+
+static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+   void __user *uaddr = (void __user *)(long)reg-addr;
+   u64 val;
+   int ret;
+
+   ret = copy_from_user(val, uaddr, 

Re: [PATCH v5] ARM/KVM: save and restore generic timer registers

2013-12-13 Thread Christoffer Dall
On Fri, Dec 13, 2013 at 02:23:26PM +0100, Andre Przywara wrote:
 For migration to work we need to save (and later restore) the state of
 each core's virtual generic timer.
 Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export
 the three needed registers (control, counter, compare value).
 Though they live in cp15 space, we don't use the existing list, since
 they need special accessor functions and the arch timer is optional.
 
 Signed-off-by: Andre Przywara andre.przyw...@linaro.org
 Signed-off-by: Christoffer Dall christoffer.d...@linaro.org
 ---
 Changes from v1:
 - move code out of coproc.c and into guest.c and arch_timer.c
 - present the registers with their native CP15 addresses, but without
   using space in the VCPU's cp15 array
 - do the user space copying in the accessor functions
 
 Changes from v2:
 - fix compilation without CONFIG_ARCH_TIMER
 - fix compilation for arm64 by defining the appropriate registers there
 - move userspace access out of arch_timer.c into coproc.c
 - Christoffer: removed whitespace in function declaration
 
 Changes from v3:
 - adapted Marc's SYSREG macro magic from kvmtool for nicer looking code
 
 Changes from v4:
 - remove ARM64-REG32 type, the ARM ARM defines no 32-bit system registers
 
  arch/arm/include/asm/kvm_host.h   |  3 ++
  arch/arm/include/uapi/asm/kvm.h   | 20 +
  arch/arm/kvm/guest.c  | 92 
 ++-
  arch/arm64/include/uapi/asm/kvm.h | 18 
  virt/kvm/arm/arch_timer.c | 34 +++
  5 files changed, 166 insertions(+), 1 deletion(-)
 
 diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
 index 8a6f6db..098f7dd 100644
 --- a/arch/arm/include/asm/kvm_host.h
 +++ b/arch/arm/include/asm/kvm_host.h
 @@ -225,4 +225,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long 
 ext)
  int kvm_perf_init(void);
  int kvm_perf_teardown(void);
  
 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
 +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
 +
  #endif /* __ARM_KVM_HOST_H__ */
 diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
 index c498b60..835b867 100644
 --- a/arch/arm/include/uapi/asm/kvm.h
 +++ b/arch/arm/include/uapi/asm/kvm.h
 @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot {
  #define KVM_REG_ARM_32_CRN_MASK  0x7800
  #define KVM_REG_ARM_32_CRN_SHIFT 11
  
 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \
 + (((x)  KVM_REG_ARM_ ## n ## _SHIFT)  KVM_REG_ARM_ ## n ## _MASK)
 +
 +#define __ARM_CP15_REG(op1,crn,crm,op2) \
 + (KVM_REG_ARM | (15  KVM_REG_ARM_COPROC_SHIFT) | \
 + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
 + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
 + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
 + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
 +
 +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32)
 +
 +#define __ARM_CP15_REG64(op1,crm) \
 + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
 +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
 +
 +#define KVM_REG_ARM_TIMER_CTLARM_CP15_REG32(0, 14, 3, 1)
 +#define KVM_REG_ARM_TIMER_CNTARM_CP15_REG64(1, 14) 
 +#define KVM_REG_ARM_TIMER_CVAL   ARM_CP15_REG64(3, 14) 
 +
  /* Normal registers are mapped as coprocessor 16. */
  #define KVM_REG_ARM_CORE (0x0010  KVM_REG_ARM_COPROC_SHIFT)
  #define KVM_REG_ARM_CORE_REG(name)   (offsetof(struct kvm_regs, name) / 4)
 diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
 index 20f8d97..2786eae 100644
 --- a/arch/arm/kvm/guest.c
 +++ b/arch/arm/kvm/guest.c
 @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, 
 struct kvm_regs *regs)
   return -EINVAL;
  }
  
 +#ifndef CONFIG_KVM_ARM_TIMER
 +
 +#define NUM_TIMER_REGS 0
 +
 +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 +{
 + return 0;
 +}
 +
 +static bool is_timer_reg(u64 index)
 +{
 + return false;
 +}
 +
 +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
 +{
 + return 0;
 +}
 +
 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
 +{
 + return 0;
 +}
 +
 +#else
 +
 +#define NUM_TIMER_REGS 3
 +
 +static bool is_timer_reg(u64 index)
 +{
 + switch (index) {
 + case KVM_REG_ARM_TIMER_CTL:
 + case KVM_REG_ARM_TIMER_CNT:
 + case KVM_REG_ARM_TIMER_CVAL:
 + return true;
 + }
 + return false;
 +}
 +
 +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 +{
 + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
 + return -EFAULT;
 + uindices++;
 + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
 + return -EFAULT;
 + uindices++;
 + if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
 + return -EFAULT;
 +
 + return 0;
 +}
 +
 +#endif
 +
 +static int set_timer_reg(struct kvm_vcpu *vcpu, const struct 

Re: [PATCH v5] ARM/KVM: save and restore generic timer registers

2013-12-13 Thread Andre Przywara

On 12/13/2013 09:10 PM, Christoffer Dall wrote:

On Fri, Dec 13, 2013 at 02:23:26PM +0100, Andre Przywara wrote:

For migration to work we need to save (and later restore) the state of
each core's virtual generic timer.
Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export
the three needed registers (control, counter, compare value).
Though they live in cp15 space, we don't use the existing list, since
they need special accessor functions and the arch timer is optional.

Signed-off-by: Andre Przywara andre.przyw...@linaro.org
Signed-off-by: Christoffer Dall christoffer.d...@linaro.org
---
Changes from v1:
- move code out of coproc.c and into guest.c and arch_timer.c
- present the registers with their native CP15 addresses, but without
   using space in the VCPU's cp15 array
- do the user space copying in the accessor functions

Changes from v2:
- fix compilation without CONFIG_ARCH_TIMER
- fix compilation for arm64 by defining the appropriate registers there
- move userspace access out of arch_timer.c into coproc.c
- Christoffer: removed whitespace in function declaration

Changes from v3:
- adapted Marc's SYSREG macro magic from kvmtool for nicer looking code

Changes from v4:
- remove ARM64-REG32 type, the ARM ARM defines no 32-bit system registers

  arch/arm/include/asm/kvm_host.h   |  3 ++
  arch/arm/include/uapi/asm/kvm.h   | 20 +
  arch/arm/kvm/guest.c  | 92 ++-
  arch/arm64/include/uapi/asm/kvm.h | 18 
  virt/kvm/arm/arch_timer.c | 34 +++
  5 files changed, 166 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 8a6f6db..098f7dd 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -225,4 +225,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long 
ext)
  int kvm_perf_init(void);
  int kvm_perf_teardown(void);

+u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
+int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
+
  #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index c498b60..835b867 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -119,6 +119,26 @@ struct kvm_arch_memory_slot {
  #define KVM_REG_ARM_32_CRN_MASK   0x7800
  #define KVM_REG_ARM_32_CRN_SHIFT  11

+#define ARM_CP15_REG_SHIFT_MASK(x,n) \
+   (((x)  KVM_REG_ARM_ ## n ## _SHIFT)  KVM_REG_ARM_ ## n ## _MASK)
+
+#define __ARM_CP15_REG(op1,crn,crm,op2) \
+   (KVM_REG_ARM | (15  KVM_REG_ARM_COPROC_SHIFT) | \
+   ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
+   ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
+   ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
+   ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
+
+#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32)
+
+#define __ARM_CP15_REG64(op1,crm) \
+   (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
+#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
+
+#define KVM_REG_ARM_TIMER_CTL  ARM_CP15_REG32(0, 14, 3, 1)
+#define KVM_REG_ARM_TIMER_CNT  ARM_CP15_REG64(1, 14)
+#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14)
+
  /* Normal registers are mapped as coprocessor 16. */
  #define KVM_REG_ARM_CORE  (0x0010  KVM_REG_ARM_COPROC_SHIFT)
  #define KVM_REG_ARM_CORE_REG(name)(offsetof(struct kvm_regs, name) / 4)
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 20f8d97..2786eae 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, 
struct kvm_regs *regs)
return -EINVAL;
  }

+#ifndef CONFIG_KVM_ARM_TIMER
+
+#define NUM_TIMER_REGS 0
+
+static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+   return 0;
+}
+
+static bool is_timer_reg(u64 index)
+{
+   return false;
+}
+
+int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
+{
+   return 0;
+}
+
+u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
+{
+   return 0;
+}
+
+#else
+
+#define NUM_TIMER_REGS 3
+
+static bool is_timer_reg(u64 index)
+{
+   switch (index) {
+   case KVM_REG_ARM_TIMER_CTL:
+   case KVM_REG_ARM_TIMER_CNT:
+   case KVM_REG_ARM_TIMER_CVAL:
+   return true;
+   }
+   return false;
+}
+
+static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+   if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
+   return -EFAULT;
+   uindices++;
+   if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
+   return -EFAULT;
+   uindices++;
+   if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
+   return -EFAULT;
+
+   return 0;
+}
+
+#endif
+
+static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+   void __user *uaddr 

Re: [PATCH v5] ARM/KVM: save and restore generic timer registers

2013-12-13 Thread Christoffer Dall
On Fri, Dec 13, 2013 at 09:35:49PM +0100, Andre Przywara wrote:
 On 12/13/2013 09:10 PM, Christoffer Dall wrote:
 On Fri, Dec 13, 2013 at 02:23:26PM +0100, Andre Przywara wrote:
 For migration to work we need to save (and later restore) the state of
 each core's virtual generic timer.
 Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export
 the three needed registers (control, counter, compare value).
 Though they live in cp15 space, we don't use the existing list, since
 they need special accessor functions and the arch timer is optional.
 
 Signed-off-by: Andre Przywara andre.przyw...@linaro.org
 Signed-off-by: Christoffer Dall christoffer.d...@linaro.org
 ---
 Changes from v1:
 - move code out of coproc.c and into guest.c and arch_timer.c
 - present the registers with their native CP15 addresses, but without
using space in the VCPU's cp15 array
 - do the user space copying in the accessor functions
 
 Changes from v2:
 - fix compilation without CONFIG_ARCH_TIMER
 - fix compilation for arm64 by defining the appropriate registers there
 - move userspace access out of arch_timer.c into coproc.c
 - Christoffer: removed whitespace in function declaration
 
 Changes from v3:
 - adapted Marc's SYSREG macro magic from kvmtool for nicer looking code
 
 Changes from v4:
 - remove ARM64-REG32 type, the ARM ARM defines no 32-bit system registers
 
   arch/arm/include/asm/kvm_host.h   |  3 ++
   arch/arm/include/uapi/asm/kvm.h   | 20 +
   arch/arm/kvm/guest.c  | 92 
  ++-
   arch/arm64/include/uapi/asm/kvm.h | 18 
   virt/kvm/arm/arch_timer.c | 34 +++
   5 files changed, 166 insertions(+), 1 deletion(-)
 
 diff --git a/arch/arm/include/asm/kvm_host.h 
 b/arch/arm/include/asm/kvm_host.h
 index 8a6f6db..098f7dd 100644
 --- a/arch/arm/include/asm/kvm_host.h
 +++ b/arch/arm/include/asm/kvm_host.h
 @@ -225,4 +225,7 @@ static inline int 
 kvm_arch_dev_ioctl_check_extension(long ext)
   int kvm_perf_init(void);
   int kvm_perf_teardown(void);
 
 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
 +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
 +
   #endif /* __ARM_KVM_HOST_H__ */
 diff --git a/arch/arm/include/uapi/asm/kvm.h 
 b/arch/arm/include/uapi/asm/kvm.h
 index c498b60..835b867 100644
 --- a/arch/arm/include/uapi/asm/kvm.h
 +++ b/arch/arm/include/uapi/asm/kvm.h
 @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot {
   #define KVM_REG_ARM_32_CRN_MASK   0x7800
   #define KVM_REG_ARM_32_CRN_SHIFT  11
 
 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \
 +   (((x)  KVM_REG_ARM_ ## n ## _SHIFT)  KVM_REG_ARM_ ## n ## _MASK)
 +
 +#define __ARM_CP15_REG(op1,crn,crm,op2) \
 +   (KVM_REG_ARM | (15  KVM_REG_ARM_COPROC_SHIFT) | \
 +   ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
 +   ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
 +   ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
 +   ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
 +
 +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | 
 KVM_REG_SIZE_U32)
 +
 +#define __ARM_CP15_REG64(op1,crm) \
 +   (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
 +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
 +
 +#define KVM_REG_ARM_TIMER_CTL  ARM_CP15_REG32(0, 14, 3, 1)
 +#define KVM_REG_ARM_TIMER_CNT  ARM_CP15_REG64(1, 14)
 +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14)
 +
   /* Normal registers are mapped as coprocessor 16. */
   #define KVM_REG_ARM_CORE  (0x0010  KVM_REG_ARM_COPROC_SHIFT)
   #define KVM_REG_ARM_CORE_REG(name)(offsetof(struct kvm_regs, 
  name) / 4)
 diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
 index 20f8d97..2786eae 100644
 --- a/arch/arm/kvm/guest.c
 +++ b/arch/arm/kvm/guest.c
 @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu 
 *vcpu, struct kvm_regs *regs)
 return -EINVAL;
   }
 
 +#ifndef CONFIG_KVM_ARM_TIMER
 +
 +#define NUM_TIMER_REGS 0
 +
 +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 +{
 +   return 0;
 +}
 +
 +static bool is_timer_reg(u64 index)
 +{
 +   return false;
 +}
 +
 +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
 +{
 +   return 0;
 +}
 +
 +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
 +{
 +   return 0;
 +}
 +
 +#else
 +
 +#define NUM_TIMER_REGS 3
 +
 +static bool is_timer_reg(u64 index)
 +{
 +   switch (index) {
 +   case KVM_REG_ARM_TIMER_CTL:
 +   case KVM_REG_ARM_TIMER_CNT:
 +   case KVM_REG_ARM_TIMER_CVAL:
 +   return true;
 +   }
 +   return false;
 +}
 +
 +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 +{
 +   if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
 +   return -EFAULT;
 +   uindices++;
 +   if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
 +   return -EFAULT;
 +   uindices++;
 +   if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
 +   return -EFAULT;
 +
 +   return 0;
 +}
 +
 +#endif
 +