No structures at all any more.

Note: the encoding of general registers makes sense, but it's not
completely logical so the code is quite messy.  It would actually be
far neater to expose the struct kvm_vcpu_regs, and use offsets into
that as the ABI.

Peter?

Signed-off-by: Rusty Russell <[email protected]>

diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h
index a3daa67..1f7190b 100644
--- a/arch/arm/include/asm/kvm.h
+++ b/arch/arm/include/asm/kvm.h
@@ -96,4 +96,28 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_32_CRN_START       11      /* Mask: 0x00007800 */
 #define KVM_REG_ARM_32_CRN_LEN         4
 
+/* Normal registers are mapped as coprocessor 0. */
+#define KVM_REG_ARM_CORE               (0x0000 << KVM_REG_ARM_COPROC_START)
+#define KVM_REG_ARM_CORE_REG_START     0       /* Mask: 0x000000FF */
+#define KVM_REG_ARM_CORE_REG_LEN       8
+#define KVM_REG_ARM_CORE_MODE_START    8       /* Mask: 0x00002F00 */
+#define KVM_REG_ARM_CORE_MODE_LEN      6
+
+/* Registers r0-r15 are just 0 to 15 as expected. */
+#define KVM_REG_ARM_CORE_REG_PC                0x0000000F
+#define KVM_REG_ARM_CORE_REG_SPSR      0x00000010
+#define KVM_REG_ARM_CORE_REG_CPSR      0x00000011
+
+/* Banked registers appear in multiple modes. */
+#define KVM_REG_ARM_CORE_MODE_USR      0x00001000
+#define KVM_REG_ARM_CORE_MODE_FIQ      0x00001100
+#define KVM_REG_ARM_CORE_MODE_IRQ      0x00001200
+#define KVM_REG_ARM_CORE_MODE_SVC      0x00001300
+#define KVM_REG_ARM_CORE_MODE_MON      0x00001600
+#define KVM_REG_ARM_CORE_MODE_ABT      0x00001700
+#define KVM_REG_ARM_CORE_MODE_HYP      0x00001A00
+#define KVM_REG_ARM_CORE_MODE_UND      0x00001B00
+#define KVM_REG_ARM_CORE_MODE_SYS      0x00001F00
+#define KVM_REG_ARM_CORE_MODE_UNBANKED 0x00002000
+
 #endif /* __ARM_KVM_H__ */
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 64fa65f..340fada 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -192,4 +192,10 @@ static inline int kvm_test_age_hva(struct kvm *kvm, 
unsigned long hva)
 {
        return 0;
 }
+
+int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu);
+struct kvm_one_reg;
+int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 0b9e8b4..ed78a66 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -756,7 +756,7 @@ static int set_invariant_cp15(u64 index, void __user *uaddr)
        return 0;
 }
 
-int kvm_arch_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg 
*reg)
 {
        const struct coproc_reg *r;
        void __user *uaddr = (void __user *)(long)reg->addr;
@@ -772,7 +772,7 @@ int kvm_arch_get_reg(struct kvm_vcpu *vcpu, const struct 
kvm_one_reg *reg)
        return reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id);
 }
 
-int kvm_arch_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg 
*reg)
 {
        const struct coproc_reg *r;
        void __user *uaddr = (void __user *)(long)reg->addr;
@@ -876,27 +876,18 @@ static int walk_msrs(struct kvm_vcpu *vcpu, u64 __user 
*uind)
        return total;
 }
 
-/**
- * kvm_arch_num_regs - how many registers do we present via KVM_GET_ONE_REG
- *
- * This is for special registers, particularly cp15.
- */
-unsigned long kvm_arch_num_regs(struct kvm_vcpu *vcpu)
+unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu)
 {
-       return ARRAY_SIZE(invariant_cp15) + walk_msrs(vcpu, (u64 __user *)NULL);
+       return ARRAY_SIZE(invariant_cp15)
+               + walk_msrs(vcpu, (u64 __user *)NULL);
 }
 
-/**
- * kvm_arch_copy_reg_indices - copy a series of coprocessor registers.
- *
- * This is for special registers, particularly cp15.
- */
-int kvm_arch_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
        unsigned int i;
        int err;
 
-       /* First give them all the invariant registers' indices. */
+       /* Then give them all the invariant registers' indices. */
        for (i = 0; i < ARRAY_SIZE(invariant_cp15); i++) {
                if (put_user(cp15_to_index(&invariant_cp15[i]), uindices))
                        return -EFAULT;
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 53f72a0..a9a7d72 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -38,75 +38,256 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
+       u32 __user *uaddr = (u32 __user *)(long)reg->addr;
        struct kvm_vcpu_regs *vcpu_regs = &vcpu->arch.regs;
+       u32 mode, r;
 
-       /*
-        * GPRs and PSRs
-        */
-       memcpy(regs->regs0_7, &(vcpu_regs->usr_regs[0]), sizeof(u32) * 8);
-       memcpy(regs->usr_regs8_12, &(vcpu_regs->usr_regs[8]), sizeof(u32) * 5);
-       memcpy(regs->fiq_regs8_12, &(vcpu_regs->fiq_regs[0]), sizeof(u32) * 5);
-       regs->reg13[MODE_FIQ] = vcpu_regs->fiq_regs[5];
-       regs->reg14[MODE_FIQ] = vcpu_regs->fiq_regs[6];
-       regs->reg13[MODE_IRQ] = vcpu_regs->irq_regs[0];
-       regs->reg14[MODE_IRQ] = vcpu_regs->irq_regs[1];
-       regs->reg13[MODE_SVC] = vcpu_regs->svc_regs[0];
-       regs->reg14[MODE_SVC] = vcpu_regs->svc_regs[1];
-       regs->reg13[MODE_ABT] = vcpu_regs->abt_regs[0];
-       regs->reg14[MODE_ABT] = vcpu_regs->abt_regs[1];
-       regs->reg13[MODE_UND] = vcpu_regs->und_regs[0];
-       regs->reg14[MODE_UND] = vcpu_regs->und_regs[1];
-       regs->reg13[MODE_USR] = vcpu_regs->usr_regs[13];
-       regs->reg14[MODE_USR] = vcpu_regs->usr_regs[14];
-
-       regs->spsr[MODE_FIQ]  = vcpu_regs->fiq_regs[7];
-       regs->spsr[MODE_IRQ]  = vcpu_regs->irq_regs[2];
-       regs->spsr[MODE_SVC]  = vcpu_regs->svc_regs[2];
-       regs->spsr[MODE_ABT]  = vcpu_regs->abt_regs[2];
-       regs->spsr[MODE_UND]  = vcpu_regs->und_regs[2];
-
-       regs->reg15 = vcpu_regs->pc;
-       regs->cpsr = vcpu_regs->cpsr;
+       if (KVM_REG_LEN(reg->id) != 4)
+               return -ENOENT;
 
-       return 0;
+       /* This var deliberately includes the unused bits. */
+       mode = reg->id >> KVM_REG_ARM_CORE_MODE_START;
+       r = (reg->id >> KVM_REG_ARM_CORE_REG_START)
+               & ((1 << KVM_REG_ARM_CORE_REG_LEN) - 1);
+
+       switch (mode) {
+       case KVM_REG_ARM_CORE_MODE_UNBANKED:
+               if (r < 8)
+                       return put_user(vcpu_regs->usr_regs[r], uaddr);
+               else if (r == KVM_REG_ARM_CORE_REG_PC)
+                       return put_user(vcpu_regs->pc, uaddr);
+               else if (r == KVM_REG_ARM_CORE_REG_CPSR)
+                       return put_user(vcpu_regs->cpsr, uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_USR:
+               if (r >= 8 && r <= 14)
+                       return put_user(vcpu_regs->usr_regs[r], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_FIQ:
+               if (r >= 8 && r <= 14)
+                       return put_user(vcpu_regs->fiq_regs[r - 8], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return put_user(vcpu_regs->fiq_regs[7], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_IRQ:
+               if (r == 13 || r == 14)
+                       return put_user(vcpu_regs->irq_regs[r - 13], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return put_user(vcpu_regs->irq_regs[2], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_SVC:
+               if (r == 13 || r == 14)
+                       return put_user(vcpu_regs->svc_regs[r - 13], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return put_user(vcpu_regs->svc_regs[2], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_ABT:
+               if (r == 13 || r == 14)
+                       return put_user(vcpu_regs->abt_regs[r - 13], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return put_user(vcpu_regs->abt_regs[2], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_UND:
+               if (r == 13 || r == 14)
+                       return put_user(vcpu_regs->und_regs[r - 13], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return put_user(vcpu_regs->und_regs[2], uaddr);
+               break;
+       }
+
+       return -ENOENT;
 }
 
-int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
+       const u32 __user *uaddr = (u32 __user *)(long)reg->addr;
        struct kvm_vcpu_regs *vcpu_regs = &vcpu->arch.regs;
+       u32 mode, r;
+
+       if (KVM_REG_LEN(reg->id) != 4)
+               return -ENOENT;
+
+       mode = reg->id >> KVM_REG_ARM_CORE_MODE_START;
+       r = (reg->id >> KVM_REG_ARM_CORE_REG_START)
+               & ((1 << KVM_REG_ARM_CORE_REG_LEN) - 1);
+
+       switch (mode) {
+       case KVM_REG_ARM_CORE_MODE_UNBANKED:
+               if (r < 8)
+                       return get_user(vcpu_regs->usr_regs[r], uaddr);
+               else if (r == KVM_REG_ARM_CORE_REG_PC)
+                       return get_user(vcpu_regs->pc, uaddr);
+               else if (r == KVM_REG_ARM_CORE_REG_CPSR) {
+                       u32 cpsr;
+                       if (get_user(cpsr, uaddr))
+                               return -EFAULT;
+
+                       if (__vcpu_mode(cpsr) == 0xf)
+                               return -EINVAL;
+                       vcpu_regs->cpsr = cpsr;
+                       return 0;
+               }
+               break;
+       case KVM_REG_ARM_CORE_MODE_USR:
+               if (r >= 8 && r <= 14)
+                       return get_user(vcpu_regs->usr_regs[r], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_FIQ:
+               if (r >= 8 && r <= 14)
+                       return get_user(vcpu_regs->fiq_regs[r - 8], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return get_user(vcpu_regs->fiq_regs[7], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_IRQ:
+               if (r == 13 || r == 14)
+                       return get_user(vcpu_regs->irq_regs[r - 13], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return get_user(vcpu_regs->irq_regs[2], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_SVC:
+               if (r == 13 || r == 14)
+                       return get_user(vcpu_regs->svc_regs[r - 13], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return get_user(vcpu_regs->svc_regs[2], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_ABT:
+               if (r == 13 || r == 14)
+                       return get_user(vcpu_regs->abt_regs[r - 13], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return get_user(vcpu_regs->abt_regs[2], uaddr);
+               break;
+       case KVM_REG_ARM_CORE_MODE_UND:
+               if (r == 13 || r == 14)
+                       return get_user(vcpu_regs->und_regs[r - 13], uaddr);
+               if (r == KVM_REG_ARM_CORE_REG_SPSR)
+                       return get_user(vcpu_regs->und_regs[2], uaddr);
+               break;
+       }
+
+       return -ENOENT;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+       return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+       return -EINVAL;
+}
+
+static unsigned long num_core_regs(void)
+{
+       return sizeof(struct kvm_vcpu_regs) / sizeof(u32);
+}
+
+/**
+ * kvm_arch_num_regs - how many registers do we present via KVM_GET_ONE_REG
+ *
+ * This is for all registers.
+ */
+unsigned long kvm_arch_num_regs(struct kvm_vcpu *vcpu)
+{
+       return num_core_regs() + kvm_arm_num_coproc_regs(vcpu);
+}
+
+/**
+ * kvm_arch_copy_reg_indices - get indices of all registers.
+ *
+ * We do core registers right here, then we apppend coproc regs.
+ */
+int kvm_arch_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+       unsigned int i;
+       u64 __user *start = uindices;
+       u64 mode;
+       const int banked_modes[] = { KVM_REG_ARM_CORE_MODE_USR,
+                                    KVM_REG_ARM_CORE_MODE_SVC,
+                                    KVM_REG_ARM_CORE_MODE_ABT,
+                                    KVM_REG_ARM_CORE_MODE_UND,
+                                    KVM_REG_ARM_CORE_MODE_IRQ,
+                                    KVM_REG_ARM_CORE_MODE_FIQ,
+       };
+
+       /* R0 - R7 (unbanked) */
+       mode = KVM_REG_ARM|KVM_REG_ARM_CORE_MODE_UNBANKED;
+       for (i = 0; i <= 7; i++) {
+               if (put_user(mode|i, uindices))
+                       return -EFAULT;
+               uindices++;
+       }
+       /* PC and CPSR (unbanked) */
+       if (put_user(mode|KVM_REG_ARM_CORE_REG_PC, uindices))
+               return -EFAULT;
+       uindices++;
+       if (put_user(mode|KVM_REG_ARM_CORE_REG_CPSR, uindices))
+               return -EFAULT;
+       uindices++;
+
+       /* USR and FIQ have banked R8-R12. */
+       mode = KVM_REG_ARM|KVM_REG_ARM_CORE_MODE_USR;
+       for (i = 8; i <= 12; i++) {
+               if (put_user(mode|i, uindices))
+                       return -EFAULT;
+               uindices++;
+       }
+       mode = KVM_REG_ARM|KVM_REG_ARM_CORE_MODE_FIQ;
+       for (i = 8; i <= 12; i++) {
+               if (put_user(mode|i, uindices))
+                       return -EFAULT;
+               uindices++;
+       }
 
-       if (__vcpu_mode(regs->cpsr) == 0xf)
+       /* Banked SP, LR and SPSR for each mode (no SPSR for USR mode though) */
+       for (i = 0; i < ARRAY_SIZE(banked_modes); i++) {
+               mode = KVM_REG_ARM|banked_modes[i];
+               if (put_user(mode|13, uindices))
+                       return -EFAULT;
+               uindices++;
+               if (put_user(mode|14, uindices))
+                       return -EFAULT;
+               uindices++;
+               if (banked_modes[i] != KVM_REG_ARM_CORE_MODE_USR) {
+                       if (put_user(mode|KVM_REG_ARM_CORE_REG_SPSR, uindices))
+                               return -EFAULT;
+                       uindices++;
+               }
+       }
+
+       BUG_ON(start - uindices != num_core_regs());
+
+       return kvm_arm_copy_coproc_indices(vcpu, uindices);
+}
+
+int kvm_arch_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       /* We currently only use lower 32 bits for arch-specific stuff. */
+       if ((reg->id & KVM_REG_ARCH_MASK & ~KVM_REG_SIZE_MASK & 0xFFFFFFFFUL)
+           != KVM_REG_ARM)
                return -EINVAL;
 
-       memcpy(&(vcpu_regs->usr_regs[0]), regs->regs0_7, sizeof(u32) * 8);
-       memcpy(&(vcpu_regs->usr_regs[8]), regs->usr_regs8_12, sizeof(u32) * 5);
-       memcpy(&(vcpu_regs->fiq_regs[0]), regs->fiq_regs8_12, sizeof(u32) * 5);
-
-       vcpu_regs->fiq_regs[5] = regs->reg13[MODE_FIQ];
-       vcpu_regs->fiq_regs[6] = regs->reg14[MODE_FIQ];
-       vcpu_regs->irq_regs[0] = regs->reg13[MODE_IRQ];
-       vcpu_regs->irq_regs[1] = regs->reg14[MODE_IRQ];
-       vcpu_regs->svc_regs[0] = regs->reg13[MODE_SVC];
-       vcpu_regs->svc_regs[1] = regs->reg14[MODE_SVC];
-       vcpu_regs->abt_regs[0] = regs->reg13[MODE_ABT];
-       vcpu_regs->abt_regs[1] = regs->reg14[MODE_ABT];
-       vcpu_regs->und_regs[0] = regs->reg13[MODE_UND];
-       vcpu_regs->und_regs[1] = regs->reg14[MODE_UND];
-       vcpu_regs->usr_regs[13] = regs->reg13[MODE_USR];
-       vcpu_regs->usr_regs[14] = regs->reg14[MODE_USR];
-
-       vcpu_regs->fiq_regs[7] = regs->spsr[MODE_FIQ];
-       vcpu_regs->irq_regs[2] = regs->spsr[MODE_IRQ];
-       vcpu_regs->svc_regs[2] = regs->spsr[MODE_SVC];
-       vcpu_regs->abt_regs[2] = regs->spsr[MODE_ABT];
-       vcpu_regs->und_regs[2] = regs->spsr[MODE_UND];
-
-       vcpu_regs->pc = regs->reg15;
-       vcpu_regs->cpsr = regs->cpsr;
+       /* Coprocessor 0 means we want a core register. */
+       if ((u32)reg->id >> KVM_REG_ARM_COPROC_START == 0)
+               return get_core_reg(vcpu, reg);
 
-       return 0;
+       return kvm_arm_coproc_get_reg(vcpu, reg);
+}
+
+int kvm_arch_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       /* We currently only use lower 32 bits for arch-specific stuff. */
+       if ((reg->id & KVM_REG_ARCH_MASK & ~KVM_REG_SIZE_MASK & 0xFFFFFFFFUL)
+           != KVM_REG_ARM)
+               return -EINVAL;
+
+       /* Coprocessor 0 means we want a core register. */
+       if ((u32)reg->id >> KVM_REG_ARM_COPROC_START == 0)
+               return set_core_reg(vcpu, reg);
+
+       return kvm_arm_coproc_set_reg(vcpu, reg);
 }
 
 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to