Patchwork [2/3] target-arm: kvm: use KVM_GET_MSRS/KVM_SET_MSRS for CP15 registers.

login
register
mail settings
Submitter Rusty Russell
Date July 13, 2012, 3:43 a.m.
Message ID <874npcz5p9.fsf@rustcorp.com.au>
Download mbox | patch
Permalink /patch/170774/
State New
Headers show

Comments

Rusty Russell - July 13, 2012, 3:43 a.m.
Recent kernels use this to set the CP15 registers, rather than putting
them in 'struct kvm_regs'.  The changed size of that struct changes the
ioctl number, so we have a temporary hack to try both.

Signed-off-by: Rusty Russell <rusty.russell@linaro.org>
Blue Swirl - July 13, 2012, 2:27 p.m.
On Fri, Jul 13, 2012 at 3:43 AM, Rusty Russell <rusty.russell@linaro.org> wrote:
> Recent kernels use this to set the CP15 registers, rather than putting
> them in 'struct kvm_regs'.  The changed size of that struct changes the
> ioctl number, so we have a temporary hack to try both.
>
> Signed-off-by: Rusty Russell <rusty.russell@linaro.org>
>
> diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
> index 988890a..4842e85 100644
> --- a/linux-headers/asm-arm/kvm.h
> +++ b/linux-headers/asm-arm/kvm.h
> @@ -75,6 +75,37 @@ struct kvm_sregs {
>         __u32 features[14];
>  };
>
> +/* Exactly like x86. */
> +struct kvm_msr_entry {
> +       __u32 index;
> +       __u32 reserved;
> +       __u64 data;
> +};
> +
> +/* for KVM_GET_MSRS and KVM_SET_MSRS */
> +struct kvm_msrs {
> +       __u32 nmsrs; /* number of msrs in entries */
> +       __u32 pad;
> +
> +       struct kvm_msr_entry entries[0];
> +};
> +
> +/* for KVM_GET_MSR_INDEX_LIST */
> +struct kvm_msr_list {
> +       __u32 nmsrs; /* number of msrs in entries */
> +       __u32 indices[0];
> +};
> +
> +/* If you need to interpret the index values, here's the key. */
> +#define KVM_ARM_MSR_COPROC_MASK                0xFFFF0000
> +#define KVM_ARM_MSR_64_BIT_MASK                0x00008000
> +#define KVM_ARM_MSR_64_OPC1_MASK       0x000000F0
> +#define KVM_ARM_MSR_64_CRM_MASK                0x0000000F
> +#define KVM_ARM_MSR_32_CRM_MASK                0x0000000F
> +#define KVM_ARM_MSR_32_OPC2_MASK       0x00000070
> +#define KVM_ARM_MSR_32_CRN_MASK                0x00000780
> +#define KVM_ARM_MSR_32_OPC1_MASK       0x00003800
> +
>  struct kvm_fpu {
>  };
>
> diff --git a/target-arm/kvm.c b/target-arm/kvm.c
> index 67d005f..2c149bd 100644
> --- a/target-arm/kvm.c
> +++ b/target-arm/kvm.c
> @@ -43,15 +43,28 @@ int kvm_arch_init_vcpu(CPUARMState *env)
>      return kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs) ? 0 : 0;
>  }
>
> +#define MSR32_INDEX_OF(coproc, crn, opc1, crm, opc2) \
> +       (((coproc)<<16) | ((opc1)<<11) | ((crn)<<7) | ((opc2)<<4) | (crm))
> +
> +/* A modern kernel has a smaller struct kvm_regs, so ioctls differ: */
> +#define KVM_GET_REGS_MODERN 2157227649U
> +#define KVM_SET_REGS_MODERN 1083485826U
> +
>  int kvm_arch_put_registers(CPUARMState *env, int level)
>  {
>      struct kvm_regs regs;
>      int mode, bn;
> +    struct cp15 {
> +           struct kvm_msrs hdr;
> +           struct kvm_msr_entry e[2];
> +    } cp15;
>      int ret;
>
>      ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
>      if (ret < 0)
> -        return ret;
> +       ret = kvm_vcpu_ioctl(env, KVM_GET_REGS_MODERN, &regs);
> +    if (ret < 0)
> +       return ret;

Braces.

>
>      /* We make sure the banked regs are properly set */
>      mode = env->uncached_cpsr & CPSR_M;
> @@ -91,8 +104,18 @@ int kvm_arch_put_registers(CPUARMState *env, int level)
>      regs.cp15.c0_midr = env->cp15.c0_cpuid;
>      regs.cp15.c1_sys = env->cp15.c1_sys;
>
> -    ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
> +    cp15.hdr.nmsrs = ARRAY_SIZE(cp15.e);
> +    cp15.e[0].index = MSR32_INDEX_OF(15, 0, 0, 0, 0); /* MIDR */
> +    cp15.e[0].data = env->cp15.c0_cpuid;
> +    cp15.e[1].index = MSR32_INDEX_OF(15, 1, 0, 0, 0); /* SCTLR */
> +    cp15.e[1].data = env->cp15.c1_sys;
>
> +    ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
> +    if (ret < 0) {
> +       ret = kvm_vcpu_ioctl(env, KVM_SET_REGS_MODERN, &regs);
> +       if (ret == 0)
> +           ret = kvm_vcpu_ioctl(env, KVM_SET_MSRS, &cp15);

Again. Please use checkpatch.pl to avoid these issues.

> +    }
>      return ret;
>  }
>
> @@ -101,11 +124,27 @@ int kvm_arch_get_registers(CPUARMState *env)
>      struct kvm_regs regs;
>      int mode, bn;
>      int32_t ret;
> +    struct cp15 {
> +           struct kvm_msrs hdr;
> +           struct kvm_msr_entry e[6];
> +    } cp15;
>
>      ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
>      if (ret < 0)
> +       ret = kvm_vcpu_ioctl(env, KVM_GET_REGS_MODERN, &regs);
> +    if (ret < 0)

Ditto.

>          return ret;
>
> +    cp15.hdr.nmsrs = ARRAY_SIZE(cp15.e);
> +    cp15.e[0].index = MSR32_INDEX_OF(15, 0, 0, 0, 0); /* MIDR */
> +    cp15.e[1].index = MSR32_INDEX_OF(15, 1, 0, 0, 0); /* SCTLR */
> +    cp15.e[2].index = MSR32_INDEX_OF(15, 2, 0, 0, 0); /* TTBR0 */
> +    cp15.e[3].index = MSR32_INDEX_OF(15, 2, 0, 0, 1); /* TTBR1 */
> +    cp15.e[4].index = MSR32_INDEX_OF(15, 2, 0, 0, 2); /* TTBCR */
> +    cp15.e[5].index = MSR32_INDEX_OF(15, 3, 0, 0, 0); /* DACR */
> +
> +    ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &cp15);
> +
>      /* First, let's transfer the banked state */
>      cpsr_write(env, regs.cpsr, 0xFFFFFFFF);
>      memcpy(env->regs, regs.regs0_7, sizeof(uint32_t) * 8);
> @@ -142,18 +181,33 @@ int kvm_arch_get_registers(CPUARMState *env)
>      env->regs[14] = env->banked_r14[bn];
>      env->spsr = env->banked_spsr[bn];
>
> -    //env->cp15.c0_cpuid = regs.cp15.c0_midr;
> -    env->cp15.c1_sys = regs.cp15.c1_sys;
> -    env->cp15.c2_base0 = regs.cp15.c2_base0;
> -    env->cp15.c2_base1 = regs.cp15.c2_base1;
> +    /* Old KVM version. */
> +    if (ret != 0) {
> +           //env->cp15.c0_cpuid = regs.cp15.c0_midr;

I see that this is code movement, but please change the C99 comment to C89.

> +           env->cp15.c1_sys = regs.cp15.c1_sys;
> +           env->cp15.c2_base0 = regs.cp15.c2_base0;
> +           env->cp15.c2_base1 = regs.cp15.c2_base1;
>
> -    /* This is ugly, but necessary for GDB compatibility */
> -    env->cp15.c2_control = regs.cp15.c2_control;
> -    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> regs.cp15.c2_control);
> -    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> regs.cp15.c2_control);
> +           /* This is ugly, but necessary for GDB compatibility */
> +           env->cp15.c2_control = regs.cp15.c2_control;
> +           env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> regs.cp15.c2_control);
> +           env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> regs.cp15.c2_control);
>
> -    env->cp15.c3 = regs.cp15.c3_dacr;
> +           env->cp15.c3 = regs.cp15.c3_dacr;
> +           return 0;
> +    }
> +
> +    //env->cp15.c0_cpuid = cp15.e[0].data;

Ditto.

> +    env->cp15.c1_sys = cp15.e[1].data;
> +    env->cp15.c2_base0 = cp15.e[2].data;
> +    env->cp15.c2_base1 = cp15.e[3].data;
> +
> +    /* This is ugly, but necessary for GDB compatibility */
> +    env->cp15.c2_control = cp15.e[4].data;
> +    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> cp15.e[4].data);
> +    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> cp15.e[4].data);
>
> +    env->cp15.c3 = cp15.e[5].data;
>      return 0;
>  }
>
>

Patch

diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
index 988890a..4842e85 100644
--- a/linux-headers/asm-arm/kvm.h
+++ b/linux-headers/asm-arm/kvm.h
@@ -75,6 +75,37 @@  struct kvm_sregs {
 	__u32 features[14];
 };
 
+/* Exactly like x86. */
+struct kvm_msr_entry {
+	__u32 index;
+	__u32 reserved;
+	__u64 data;
+};
+
+/* for KVM_GET_MSRS and KVM_SET_MSRS */
+struct kvm_msrs {
+	__u32 nmsrs; /* number of msrs in entries */
+	__u32 pad;
+
+	struct kvm_msr_entry entries[0];
+};
+
+/* for KVM_GET_MSR_INDEX_LIST */
+struct kvm_msr_list {
+	__u32 nmsrs; /* number of msrs in entries */
+	__u32 indices[0];
+};
+
+/* If you need to interpret the index values, here's the key. */
+#define KVM_ARM_MSR_COPROC_MASK		0xFFFF0000
+#define KVM_ARM_MSR_64_BIT_MASK		0x00008000
+#define KVM_ARM_MSR_64_OPC1_MASK	0x000000F0
+#define KVM_ARM_MSR_64_CRM_MASK		0x0000000F
+#define KVM_ARM_MSR_32_CRM_MASK		0x0000000F
+#define KVM_ARM_MSR_32_OPC2_MASK	0x00000070
+#define KVM_ARM_MSR_32_CRN_MASK		0x00000780
+#define KVM_ARM_MSR_32_OPC1_MASK	0x00003800
+
 struct kvm_fpu {
 };
 
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 67d005f..2c149bd 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -43,15 +43,28 @@  int kvm_arch_init_vcpu(CPUARMState *env)
     return kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs) ? 0 : 0;
 }
 
+#define MSR32_INDEX_OF(coproc, crn, opc1, crm, opc2) \
+	(((coproc)<<16) | ((opc1)<<11) | ((crn)<<7) | ((opc2)<<4) | (crm))
+
+/* A modern kernel has a smaller struct kvm_regs, so ioctls differ: */
+#define KVM_GET_REGS_MODERN 2157227649U
+#define KVM_SET_REGS_MODERN 1083485826U
+
 int kvm_arch_put_registers(CPUARMState *env, int level)
 {
     struct kvm_regs regs;
     int mode, bn;
+    struct cp15 {
+	    struct kvm_msrs hdr;
+	    struct kvm_msr_entry e[2];
+    } cp15;
     int ret;
 
     ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
     if (ret < 0)
-        return ret;
+	ret = kvm_vcpu_ioctl(env, KVM_GET_REGS_MODERN, &regs);
+    if (ret < 0)
+	return ret;
 
     /* We make sure the banked regs are properly set */
     mode = env->uncached_cpsr & CPSR_M;
@@ -91,8 +104,18 @@  int kvm_arch_put_registers(CPUARMState *env, int level)
     regs.cp15.c0_midr = env->cp15.c0_cpuid;
     regs.cp15.c1_sys = env->cp15.c1_sys;
 
-    ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
+    cp15.hdr.nmsrs = ARRAY_SIZE(cp15.e);
+    cp15.e[0].index = MSR32_INDEX_OF(15, 0, 0, 0, 0); /* MIDR */
+    cp15.e[0].data = env->cp15.c0_cpuid;
+    cp15.e[1].index = MSR32_INDEX_OF(15, 1, 0, 0, 0); /* SCTLR */
+    cp15.e[1].data = env->cp15.c1_sys;
 
+    ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
+    if (ret < 0) {
+	ret = kvm_vcpu_ioctl(env, KVM_SET_REGS_MODERN, &regs);
+	if (ret == 0)
+	    ret = kvm_vcpu_ioctl(env, KVM_SET_MSRS, &cp15);
+    }
     return ret;
 }
 
@@ -101,11 +124,27 @@  int kvm_arch_get_registers(CPUARMState *env)
     struct kvm_regs regs;
     int mode, bn;
     int32_t ret;
+    struct cp15 {
+	    struct kvm_msrs hdr;
+	    struct kvm_msr_entry e[6];
+    } cp15;
 
     ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
     if (ret < 0)
+	ret = kvm_vcpu_ioctl(env, KVM_GET_REGS_MODERN, &regs);
+    if (ret < 0)
         return ret;
 
+    cp15.hdr.nmsrs = ARRAY_SIZE(cp15.e);
+    cp15.e[0].index = MSR32_INDEX_OF(15, 0, 0, 0, 0); /* MIDR */
+    cp15.e[1].index = MSR32_INDEX_OF(15, 1, 0, 0, 0); /* SCTLR */
+    cp15.e[2].index = MSR32_INDEX_OF(15, 2, 0, 0, 0); /* TTBR0 */
+    cp15.e[3].index = MSR32_INDEX_OF(15, 2, 0, 0, 1); /* TTBR1 */
+    cp15.e[4].index = MSR32_INDEX_OF(15, 2, 0, 0, 2); /* TTBCR */
+    cp15.e[5].index = MSR32_INDEX_OF(15, 3, 0, 0, 0); /* DACR */
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &cp15);
+
     /* First, let's transfer the banked state */
     cpsr_write(env, regs.cpsr, 0xFFFFFFFF);
     memcpy(env->regs, regs.regs0_7, sizeof(uint32_t) * 8);
@@ -142,18 +181,33 @@  int kvm_arch_get_registers(CPUARMState *env)
     env->regs[14] = env->banked_r14[bn];
     env->spsr = env->banked_spsr[bn];
 
-    //env->cp15.c0_cpuid = regs.cp15.c0_midr;
-    env->cp15.c1_sys = regs.cp15.c1_sys;
-    env->cp15.c2_base0 = regs.cp15.c2_base0;
-    env->cp15.c2_base1 = regs.cp15.c2_base1;
+    /* Old KVM version. */
+    if (ret != 0) {
+	    //env->cp15.c0_cpuid = regs.cp15.c0_midr;
+	    env->cp15.c1_sys = regs.cp15.c1_sys;
+	    env->cp15.c2_base0 = regs.cp15.c2_base0;
+	    env->cp15.c2_base1 = regs.cp15.c2_base1;
 
-    /* This is ugly, but necessary for GDB compatibility */
-    env->cp15.c2_control = regs.cp15.c2_control;
-    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> regs.cp15.c2_control);
-    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> regs.cp15.c2_control);
+	    /* This is ugly, but necessary for GDB compatibility */
+	    env->cp15.c2_control = regs.cp15.c2_control;
+	    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> regs.cp15.c2_control);
+	    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> regs.cp15.c2_control);
 
-    env->cp15.c3 = regs.cp15.c3_dacr;
+	    env->cp15.c3 = regs.cp15.c3_dacr;
+	    return 0;
+    }
+
+    //env->cp15.c0_cpuid = cp15.e[0].data;
+    env->cp15.c1_sys = cp15.e[1].data;
+    env->cp15.c2_base0 = cp15.e[2].data;
+    env->cp15.c2_base1 = cp15.e[3].data;
+
+    /* This is ugly, but necessary for GDB compatibility */
+    env->cp15.c2_control = cp15.e[4].data;
+    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> cp15.e[4].data);
+    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> cp15.e[4].data);
 
+    env->cp15.c3 = cp15.e[5].data;
     return 0;
 }