Merge branch 'imx-for-2.6.38' of git://git.pengutronix.de/git/ukl/linux-2.6 into...
[pandora-kernel.git] / arch / powerpc / kvm / powerpc.c
index 72a4ad8..38f756f 100644 (file)
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-       return !(v->arch.msr & MSR_WE) || !!(v->arch.pending_exceptions);
+       return !(v->arch.shared->msr & MSR_WE) ||
+              !!(v->arch.pending_exceptions);
 }
 
+int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
+{
+       int nr = kvmppc_get_gpr(vcpu, 11);
+       int r;
+       unsigned long __maybe_unused param1 = kvmppc_get_gpr(vcpu, 3);
+       unsigned long __maybe_unused param2 = kvmppc_get_gpr(vcpu, 4);
+       unsigned long __maybe_unused param3 = kvmppc_get_gpr(vcpu, 5);
+       unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6);
+       unsigned long r2 = 0;
+
+       if (!(vcpu->arch.shared->msr & MSR_SF)) {
+               /* 32 bit mode */
+               param1 &= 0xffffffff;
+               param2 &= 0xffffffff;
+               param3 &= 0xffffffff;
+               param4 &= 0xffffffff;
+       }
+
+       switch (nr) {
+       case HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE:
+       {
+               vcpu->arch.magic_page_pa = param1;
+               vcpu->arch.magic_page_ea = param2;
+
+               r2 = KVM_MAGIC_FEAT_SR;
+
+               r = HC_EV_SUCCESS;
+               break;
+       }
+       case HC_VENDOR_KVM | KVM_HC_FEATURES:
+               r = HC_EV_SUCCESS;
+#if defined(CONFIG_PPC_BOOK3S) /* XXX Missing magic page on BookE */
+               r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);
+#endif
+
+               /* Second return value is in r4 */
+               break;
+       default:
+               r = HC_EV_UNIMPLEMENTED;
+               break;
+       }
+
+       kvmppc_set_gpr(vcpu, 4, r2);
+
+       return r;
+}
 
 int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
@@ -145,8 +192,10 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PPC_SEGSTATE:
        case KVM_CAP_PPC_PAIRED_SINGLES:
        case KVM_CAP_PPC_UNSET_IRQ:
+       case KVM_CAP_PPC_IRQ_LEVEL:
        case KVM_CAP_ENABLE_CAP:
        case KVM_CAP_PPC_OSI:
+       case KVM_CAP_PPC_GET_PVINFO:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -534,16 +583,54 @@ out:
        return r;
 }
 
+static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
+{
+       u32 inst_lis = 0x3c000000;
+       u32 inst_ori = 0x60000000;
+       u32 inst_nop = 0x60000000;
+       u32 inst_sc = 0x44000002;
+       u32 inst_imm_mask = 0xffff;
+
+       /*
+        * The hypercall to get into KVM from within guest context is as
+        * follows:
+        *
+        *    lis r0, r0, KVM_SC_MAGIC_R0@h
+        *    ori r0, KVM_SC_MAGIC_R0@l
+        *    sc
+        *    nop
+        */
+       pvinfo->hcall[0] = inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask);
+       pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask);
+       pvinfo->hcall[2] = inst_sc;
+       pvinfo->hcall[3] = inst_nop;
+
+       return 0;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
                        unsigned int ioctl, unsigned long arg)
 {
+       void __user *argp = (void __user *)arg;
        long r;
 
        switch (ioctl) {
+       case KVM_PPC_GET_PVINFO: {
+               struct kvm_ppc_pvinfo pvinfo;
+               memset(&pvinfo, 0, sizeof(pvinfo));
+               r = kvm_vm_ioctl_get_pvinfo(&pvinfo);
+               if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) {
+                       r = -EFAULT;
+                       goto out;
+               }
+
+               break;
+       }
        default:
                r = -ENOTTY;
        }
 
+out:
        return r;
 }