[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 2/3] target-arm: kvm: use KVM_GET_MSRS/KVM_SET_MSRS
From: |
Rusty Russell |
Subject: |
[Qemu-devel] [PATCH 2/3] target-arm: kvm: use KVM_GET_MSRS/KVM_SET_MSRS for CP15 registers. |
Date: |
Fri, 13 Jul 2012 13:13:30 +0930 |
User-agent: |
Notmuch/0.12 (http://notmuchmail.org) Emacs/23.3.1 (i686-pc-linux-gnu) |
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 <address@hidden>
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, ®s);
if (ret < 0)
- return ret;
+ ret = kvm_vcpu_ioctl(env, KVM_GET_REGS_MODERN, ®s);
+ 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, ®s);
+ 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, ®s);
+ if (ret < 0) {
+ ret = kvm_vcpu_ioctl(env, KVM_SET_REGS_MODERN, ®s);
+ 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, ®s);
if (ret < 0)
+ ret = kvm_vcpu_ioctl(env, KVM_GET_REGS_MODERN, ®s);
+ 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;
}