[kvmarm] [PATCH 00/17] KVM Model and CP15 interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 12 Jul 2012 11:27:34 +0200, Marc Zyngier <marc.zyngier at arm.com> wrote:
> From: Rusty Russell [rusty.russell at linaro.org] Sent: Thursday, July 12,
> 2012 6:54 AM
> 
> > Hi all,
> > 
> >         This turned out to be a longer patch series than I expected.
> > The idea is that qemu tells us exactly what CPU (and cpu features) the
> > guest should have, and we tell it exactly what CP15 registers we have.
> > 
> > This allows us to be futureproof: if we want to emulate an A9 in
> > future, this interface would let us do that.  If a future host CPU can
> > create a guest environment which looks like an A15, we can do that, too.
> 
> Brilliant! Is there a corresponding Qemu patch somewhere? I'd love to give
> this a spin...

I have a terrible hack to check it works, see below; I wanted to discuss
the transition with Peter before writing something decent.  Or let him
do the qemu side :)

If you don't apply the final patch, then you just need the
kvm_arch_init_vcpu() call to KVM_SET_SREGS.  If we ignore the return
value, then it works with older kernels too.

Cheers,
Rusty.

diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
index 38ff1d6..988890a 100644
--- a/linux-headers/asm-arm/kvm.h
+++ b/linux-headers/asm-arm/kvm.h
@@ -66,7 +66,13 @@ struct kvm_regs {
 
 };
 
+/* Supported Processor Types */
+#define KVM_ARM_TARGET_CORTEX_A15	(0xC0F)
+
 struct kvm_sregs {
+	__u32 target;
+	__u32 num_features;
+	__u32 features[14];
 };
 
 struct kvm_fpu {


diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 29bb51f..650c9b3 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -32,8 +32,153 @@ int kvm_arch_init(KVMState *s)
     return 0;
 }
 
+/* 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
+
+static void print_index(__u32 idx)
+{
+    int coproc, opc1, crm, crn, opc2;
+    coproc = (idx & KVM_ARM_MSR_COPROC_MASK) >> 16;
+    if (coproc > 15) {
+	printf("Special (%u) => %u",
+	       coproc, idx & ~KVM_ARM_MSR_COPROC_MASK);
+    } else if (idx & KVM_ARM_MSR_64_BIT_MASK) {
+	opc1 = (idx & KVM_ARM_MSR_64_OPC1_MASK) >> 4;
+	crm = idx & KVM_ARM_MSR_64_CRM_MASK;
+	printf("cp%u CRm(%u) Op1(%u)", coproc, crm, opc1);
+    } else {
+	opc1 = (idx & KVM_ARM_MSR_32_OPC1_MASK) >> 11;
+	crn = (idx & KVM_ARM_MSR_32_CRN_MASK) >> 7;
+	opc2 = (idx & KVM_ARM_MSR_32_OPC2_MASK) >> 4;
+	crm = idx & KVM_ARM_MSR_32_CRM_MASK;
+	printf("cp%u CRn(%u) CRm(%u) Op1(%u) Op2(%u)",
+	       coproc, crn, crm, opc1, opc2);
+    }
+}
+
+static void play_with_msrs(CPUARMState *env)
+{
+    int ret, i;
+    struct kvm_msr_list *list = malloc(4096);
+    struct kvm_msrs *msrs;
+
+    list->nmsrs = 1;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_MSR_INDEX_LIST, list);
+    printf("KVM_GET_MSR_INDEX_LIST(nmsrs=1) => %u, %s\n",
+	    list->nmsrs, strerror(-ret));
+
+    if (ret == -EINVAL)
+	return;
+
+    assert(ret == -E2BIG);
+
+    list->nmsrs = 1023;
+    ret = kvm_vcpu_ioctl(env, KVM_GET_MSR_INDEX_LIST, list);
+    printf("KVM_GET_MSR_INDEX_LIST(nmsrs=1023) => %u, %s\n",
+	    list->nmsrs, strerror(-ret));
+    assert(ret == 0);
+
+    for (i = 0; i < list->nmsrs; i++) {
+	printf("  ");
+	print_index(list->indices[i]);
+	printf("\n");
+    }
+
+    msrs = malloc(sizeof(*msrs) + sizeof(msrs->entries[0])*list->nmsrs);
+
+    /* Test invalid set/get */
+    msrs->nmsrs = 1;
+    msrs->entries[0].index = 0xDEADBEEF;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, msrs);
+    printf("KVM_GET_MSRS(nmsrs=1,entry[0]=0xDEADBEEF) => %s\n",
+	    strerror(-ret));
+    assert(ret == -EINVAL);
+    ret = kvm_vcpu_ioctl(env, KVM_SET_MSRS, msrs);
+    printf("KVM_SET_MSRS(nmsrs=1,entry[0]=0xDEADBEEF) => %s\n",
+	    strerror(-ret));
+    assert(ret == -EINVAL);
+
+    msrs->nmsrs = list->nmsrs;
+    for (i = 0; i < list->nmsrs; i++)
+	msrs->entries[i].index = list->indices[i];
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, msrs);
+    printf("KVM_GET_MSRS(nmsrs=%u) => %s\n",
+	   list->nmsrs, strerror(-ret));
+    assert(ret == 0);
+    assert(msrs->nmsrs == list->nmsrs);
+
+    for (i = 0; i < msrs->nmsrs; i++) {
+	print_index(msrs->entries[i].index);
+	printf(" = 0x%llx\n", (long long)msrs->entries[i].data);
+    }
+
+    ret = kvm_vcpu_ioctl(env, KVM_SET_MSRS, msrs);
+    printf("KVM_SET_MSRS(nmsrs=%u) => %s\n",
+	   msrs->nmsrs, strerror(-ret));
+    assert(ret == 0);
+
+    /* Should not be able to change a fixed value. */
+    msrs->entries[0].data ^= 1;
+    ret = kvm_vcpu_ioctl(env, KVM_SET_MSRS, msrs);
+    printf("KVM_SET_MSRS(nmsrs=%u,entries[0]=changed) => %s\n",
+	   msrs->nmsrs, strerror(-ret));
+    assert(ret == -EINVAL);
+
+    msrs->entries[0].data ^= 1;
+
+    /* Should be able to change a variable one. */
+    msrs->entries[msrs->nmsrs - 1].data ^= 1;
+    ret = kvm_vcpu_ioctl(env, KVM_SET_MSRS, msrs);
+    printf("KVM_SET_MSRS(nmsrs=%u,entries[%u]=changed) => %s\n",
+	   msrs->nmsrs, msrs->nmsrs-1, strerror(-ret));
+    assert(ret == 0);
+
+    free(list);
+    free(msrs);
+}    
+
 int kvm_arch_init_vcpu(CPUARMState *env)
 {
+    struct kvm_sregs sregs;
+    int ret;
+
+    sregs.target = KVM_ARM_TARGET_CORTEX_A15;
+    sregs.num_features = 0;
+
+    ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs);
+    if (ret == 0)
+	play_with_msrs(env);
     return 0;
 }
 


[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux