]> 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 020923e4313490445130517f220325f7485a4fa2..1020119226dbefe5589726758bbff2f03c70ec53 100644 (file)
@@ -222,8 +222,7 @@ void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
        kvmppc_booke_queue_irqprio(vcpu, prio);
 }
 
-void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
-                                  struct kvm_interrupt *irq)
+void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu)
 {
        clear_bit(BOOKE_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions);
        clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions);
@@ -347,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) {
@@ -428,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)
@@ -746,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();
        }
@@ -1148,6 +1156,18 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        return r;
 }
 
+static void kvmppc_set_tsr(struct kvm_vcpu *vcpu, u32 new_tsr)
+{
+       u32 old_tsr = vcpu->arch.tsr;
+
+       vcpu->arch.tsr = new_tsr;
+
+       if ((old_tsr ^ vcpu->arch.tsr) & (TSR_ENW | TSR_WIS))
+               arm_next_watchdog(vcpu);
+
+       update_timer_ints(vcpu);
+}
+
 /* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
@@ -1287,16 +1307,8 @@ static int set_sregs_base(struct kvm_vcpu *vcpu,
                kvmppc_emulate_dec(vcpu);
        }
 
-       if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) {
-               u32 old_tsr = vcpu->arch.tsr;
-
-               vcpu->arch.tsr = sregs->u.e.tsr;
-
-               if ((old_tsr ^ vcpu->arch.tsr) & (TSR_ENW | TSR_WIS))
-                       arm_next_watchdog(vcpu);
-
-               update_timer_ints(vcpu);
-       }
+       if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR)
+               kvmppc_set_tsr(vcpu, sregs->u.e.tsr);
 
        return 0;
 }
@@ -1409,84 +1421,134 @@ 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:
+               val = get_reg_val(reg->id, vcpu->arch.tcr);
+               break;
+       case KVM_REG_PPC_TSR:
+               val = get_reg_val(reg->id, vcpu->arch.tsr);
+               break;
+       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 = set_reg_val(reg->id, val);
+               kvmppc_set_tsr_bits(vcpu, tsr_bits);
+               break;
+       }
+       case KVM_REG_PPC_CLEAR_TSR: {
+               u32 tsr_bits = set_reg_val(reg->id, val);
+               kvmppc_clr_tsr_bits(vcpu, tsr_bits);
+               break;
+       }
+       case KVM_REG_PPC_TSR: {
+               u32 tsr = set_reg_val(reg->id, val);
+               kvmppc_set_tsr(vcpu, tsr);
+               break;
+       }
+       case KVM_REG_PPC_TCR: {
+               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;
 }
 
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+                                        struct kvm_guest_debug *dbg)
+{
+       return -EINVAL;
+}
+
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
        return -ENOTSUPP;
@@ -1531,7 +1593,7 @@ int kvmppc_core_prepare_memory_region(struct kvm *kvm,
 
 void kvmppc_core_commit_memory_region(struct kvm *kvm,
                                struct kvm_userspace_memory_region *mem,
-                               struct kvm_memory_slot old)
+                               const struct kvm_memory_slot *old)
 {
 }