Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[sfrench/cifs-2.6.git] / arch / arm64 / kvm / guest.c
index aea43ec60f3794eab324c50bbe4c54505ce67723..dfb5218137ca9846efebbfc408a3eda98b764a4b 100644 (file)
@@ -101,19 +101,69 @@ static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off)
        return size;
 }
 
-static int validate_core_offset(const struct kvm_vcpu *vcpu,
-                               const struct kvm_one_reg *reg)
+static void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
        u64 off = core_reg_offset_from_id(reg->id);
        int size = core_reg_size_from_offset(vcpu, off);
 
        if (size < 0)
-               return -EINVAL;
+               return NULL;
 
        if (KVM_REG_SIZE(reg->id) != size)
-               return -EINVAL;
+               return NULL;
 
-       return 0;
+       switch (off) {
+       case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
+            KVM_REG_ARM_CORE_REG(regs.regs[30]):
+               off -= KVM_REG_ARM_CORE_REG(regs.regs[0]);
+               off /= 2;
+               return &vcpu->arch.ctxt.regs.regs[off];
+
+       case KVM_REG_ARM_CORE_REG(regs.sp):
+               return &vcpu->arch.ctxt.regs.sp;
+
+       case KVM_REG_ARM_CORE_REG(regs.pc):
+               return &vcpu->arch.ctxt.regs.pc;
+
+       case KVM_REG_ARM_CORE_REG(regs.pstate):
+               return &vcpu->arch.ctxt.regs.pstate;
+
+       case KVM_REG_ARM_CORE_REG(sp_el1):
+               return __ctxt_sys_reg(&vcpu->arch.ctxt, SP_EL1);
+
+       case KVM_REG_ARM_CORE_REG(elr_el1):
+               return __ctxt_sys_reg(&vcpu->arch.ctxt, ELR_EL1);
+
+       case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_EL1]):
+               return __ctxt_sys_reg(&vcpu->arch.ctxt, SPSR_EL1);
+
+       case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_ABT]):
+               return &vcpu->arch.ctxt.spsr_abt;
+
+       case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_UND]):
+               return &vcpu->arch.ctxt.spsr_und;
+
+       case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_IRQ]):
+               return &vcpu->arch.ctxt.spsr_irq;
+
+       case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_FIQ]):
+               return &vcpu->arch.ctxt.spsr_fiq;
+
+       case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ...
+            KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
+               off -= KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]);
+               off /= 4;
+               return &vcpu->arch.ctxt.fp_regs.vregs[off];
+
+       case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
+               return &vcpu->arch.ctxt.fp_regs.fpsr;
+
+       case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
+               return &vcpu->arch.ctxt.fp_regs.fpcr;
+
+       default:
+               return NULL;
+       }
 }
 
 static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
@@ -125,8 +175,8 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
         * off the index in the "array".
         */
        __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
-       struct kvm_regs *regs = vcpu_gp_regs(vcpu);
-       int nr_regs = sizeof(*regs) / sizeof(__u32);
+       int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32);
+       void *addr;
        u32 off;
 
        /* Our ID is an index into the kvm_regs struct. */
@@ -135,10 +185,11 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
            (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
                return -ENOENT;
 
-       if (validate_core_offset(vcpu, reg))
+       addr = core_reg_addr(vcpu, reg);
+       if (!addr)
                return -EINVAL;
 
-       if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
+       if (copy_to_user(uaddr, addr, KVM_REG_SIZE(reg->id)))
                return -EFAULT;
 
        return 0;
@@ -147,10 +198,9 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
        __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
-       struct kvm_regs *regs = vcpu_gp_regs(vcpu);
-       int nr_regs = sizeof(*regs) / sizeof(__u32);
+       int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32);
        __uint128_t tmp;
-       void *valp = &tmp;
+       void *valp = &tmp, *addr;
        u64 off;
        int err = 0;
 
@@ -160,7 +210,8 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
            (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
                return -ENOENT;
 
-       if (validate_core_offset(vcpu, reg))
+       addr = core_reg_addr(vcpu, reg);
+       if (!addr)
                return -EINVAL;
 
        if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
@@ -198,7 +249,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
                }
        }
 
-       memcpy((u32 *)regs + off, valp, KVM_REG_SIZE(reg->id));
+       memcpy(addr, valp, KVM_REG_SIZE(reg->id));
 
        if (*vcpu_cpsr(vcpu) & PSR_MODE32_BIT) {
                int i;