]> Pileus Git - ~andy/linux/blobdiff - arch/powerpc/kvm/booke.c
Merge tag 'please-pull-pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl...
[~andy/linux] / arch / powerpc / kvm / booke.c
index a3e2db0cf2f94c4bbad40cf388808b66c5f31c31..1020119226dbefe5589726758bbff2f03c70ec53 100644 (file)
@@ -346,7 +346,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                keep_irq = true;
        }
 
-       if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_enabled)
+       if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_flags)
                update_epr = true;
 
        switch (priority) {
@@ -427,8 +427,14 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                        set_guest_esr(vcpu, vcpu->arch.queued_esr);
                if (update_dear == true)
                        set_guest_dear(vcpu, vcpu->arch.queued_dear);
-               if (update_epr == true)
-                       kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
+               if (update_epr == true) {
+                       if (vcpu->arch.epr_flags & KVMPPC_EPR_USER)
+                               kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
+                       else if (vcpu->arch.epr_flags & KVMPPC_EPR_KERNEL) {
+                               BUG_ON(vcpu->arch.irq_type != KVMPPC_IRQ_MPIC);
+                               kvmppc_mpic_set_epr(vcpu);
+                       }
+               }
 
                new_msr &= msr_mask;
 #if defined(CONFIG_64BIT)
@@ -745,6 +751,9 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
                kvmppc_core_queue_program(vcpu, ESR_PIL);
                return RESUME_HOST;
 
+       case EMULATE_EXIT_USER:
+               return RESUME_HOST;
+
        default:
                BUG();
        }
@@ -1412,117 +1421,125 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 
 int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 {
-       int r = -EINVAL;
+       int r = 0;
+       union kvmppc_one_reg val;
+       int size;
+       long int i;
+
+       size = one_reg_size(reg->id);
+       if (size > sizeof(val))
+               return -EINVAL;
 
        switch (reg->id) {
        case KVM_REG_PPC_IAC1:
        case KVM_REG_PPC_IAC2:
        case KVM_REG_PPC_IAC3:
-       case KVM_REG_PPC_IAC4: {
-               int iac = reg->id - KVM_REG_PPC_IAC1;
-               r = copy_to_user((u64 __user *)(long)reg->addr,
-                                &vcpu->arch.dbg_reg.iac[iac], sizeof(u64));
+       case KVM_REG_PPC_IAC4:
+               i = reg->id - KVM_REG_PPC_IAC1;
+               val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac[i]);
                break;
-       }
        case KVM_REG_PPC_DAC1:
-       case KVM_REG_PPC_DAC2: {
-               int dac = reg->id - KVM_REG_PPC_DAC1;
-               r = copy_to_user((u64 __user *)(long)reg->addr,
-                                &vcpu->arch.dbg_reg.dac[dac], sizeof(u64));
+       case KVM_REG_PPC_DAC2:
+               i = reg->id - KVM_REG_PPC_DAC1;
+               val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac[i]);
                break;
-       }
        case KVM_REG_PPC_EPR: {
                u32 epr = get_guest_epr(vcpu);
-               r = put_user(epr, (u32 __user *)(long)reg->addr);
+               val = get_reg_val(reg->id, epr);
                break;
        }
 #if defined(CONFIG_64BIT)
        case KVM_REG_PPC_EPCR:
-               r = put_user(vcpu->arch.epcr, (u32 __user *)(long)reg->addr);
+               val = get_reg_val(reg->id, vcpu->arch.epcr);
                break;
 #endif
        case KVM_REG_PPC_TCR:
-               r = put_user(vcpu->arch.tcr, (u32 __user *)(long)reg->addr);
+               val = get_reg_val(reg->id, vcpu->arch.tcr);
                break;
        case KVM_REG_PPC_TSR:
-               r = put_user(vcpu->arch.tsr, (u32 __user *)(long)reg->addr);
+               val = get_reg_val(reg->id, vcpu->arch.tsr);
                break;
-       case KVM_REG_PPC_DEBUG_INST: {
-               u32 opcode = KVMPPC_INST_EHPRIV;
-               r = copy_to_user((u32 __user *)(long)reg->addr,
-                                &opcode, sizeof(u32));
+       case KVM_REG_PPC_DEBUG_INST:
+               val = get_reg_val(reg->id, KVMPPC_INST_EHPRIV);
                break;
-       }
        default:
+               r = kvmppc_get_one_reg(vcpu, reg->id, &val);
                break;
        }
+
+       if (r)
+               return r;
+
+       if (copy_to_user((char __user *)(unsigned long)reg->addr, &val, size))
+               r = -EFAULT;
+
        return r;
 }
 
 int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 {
-       int r = -EINVAL;
+       int r = 0;
+       union kvmppc_one_reg val;
+       int size;
+       long int i;
+
+       size = one_reg_size(reg->id);
+       if (size > sizeof(val))
+               return -EINVAL;
+
+       if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size))
+               return -EFAULT;
 
        switch (reg->id) {
        case KVM_REG_PPC_IAC1:
        case KVM_REG_PPC_IAC2:
        case KVM_REG_PPC_IAC3:
-       case KVM_REG_PPC_IAC4: {
-               int iac = reg->id - KVM_REG_PPC_IAC1;
-               r = copy_from_user(&vcpu->arch.dbg_reg.iac[iac],
-                            (u64 __user *)(long)reg->addr, sizeof(u64));
+       case KVM_REG_PPC_IAC4:
+               i = reg->id - KVM_REG_PPC_IAC1;
+               vcpu->arch.dbg_reg.iac[i] = set_reg_val(reg->id, val);
                break;
-       }
        case KVM_REG_PPC_DAC1:
-       case KVM_REG_PPC_DAC2: {
-               int dac = reg->id - KVM_REG_PPC_DAC1;
-               r = copy_from_user(&vcpu->arch.dbg_reg.dac[dac],
-                            (u64 __user *)(long)reg->addr, sizeof(u64));
+       case KVM_REG_PPC_DAC2:
+               i = reg->id - KVM_REG_PPC_DAC1;
+               vcpu->arch.dbg_reg.dac[i] = set_reg_val(reg->id, val);
                break;
-       }
        case KVM_REG_PPC_EPR: {
-               u32 new_epr;
-               r = get_user(new_epr, (u32 __user *)(long)reg->addr);
-               if (!r)
-                       kvmppc_set_epr(vcpu, new_epr);
+               u32 new_epr = set_reg_val(reg->id, val);
+               kvmppc_set_epr(vcpu, new_epr);
                break;
        }
 #if defined(CONFIG_64BIT)
        case KVM_REG_PPC_EPCR: {
-               u32 new_epcr;
-               r = get_user(new_epcr, (u32 __user *)(long)reg->addr);
-               if (r == 0)
-                       kvmppc_set_epcr(vcpu, new_epcr);
+               u32 new_epcr = set_reg_val(reg->id, val);
+               kvmppc_set_epcr(vcpu, new_epcr);
                break;
        }
 #endif
        case KVM_REG_PPC_OR_TSR: {
-               u32 tsr_bits;
-               r = get_user(tsr_bits, (u32 __user *)(long)reg->addr);
+               u32 tsr_bits = set_reg_val(reg->id, val);
                kvmppc_set_tsr_bits(vcpu, tsr_bits);
                break;
        }
        case KVM_REG_PPC_CLEAR_TSR: {
-               u32 tsr_bits;
-               r = get_user(tsr_bits, (u32 __user *)(long)reg->addr);
+               u32 tsr_bits = set_reg_val(reg->id, val);
                kvmppc_clr_tsr_bits(vcpu, tsr_bits);
                break;
        }
        case KVM_REG_PPC_TSR: {
-               u32 tsr;
-               r = get_user(tsr, (u32 __user *)(long)reg->addr);
+               u32 tsr = set_reg_val(reg->id, val);
                kvmppc_set_tsr(vcpu, tsr);
                break;
        }
        case KVM_REG_PPC_TCR: {
-               u32 tcr;
-               r = get_user(tcr, (u32 __user *)(long)reg->addr);
+               u32 tcr = set_reg_val(reg->id, val);
                kvmppc_set_tcr(vcpu, tcr);
                break;
        }
        default:
+               r = kvmppc_set_one_reg(vcpu, reg->id, &val);
                break;
        }
+
        return r;
 }