]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kvm/booke.c
kvm: add halt_poll_ns module parameter
[karo-tx-linux.git] / arch / powerpc / kvm / booke.c
index b4c89fa6f109ec0502380ce2f1e749aa21fb8049..6c1316a15a2729a67ed61bcb6e2ce8b90af6bdbe 100644 (file)
@@ -62,6 +62,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "inst_emu",   VCPU_STAT(emulated_inst_exits) },
        { "dec",        VCPU_STAT(dec_exits) },
        { "ext_intr",   VCPU_STAT(ext_intr_exits) },
+       { "halt_successful_poll", VCPU_STAT(halt_successful_poll) },
        { "halt_wakeup", VCPU_STAT(halt_wakeup) },
        { "doorbell", VCPU_STAT(dbell_exits) },
        { "guest doorbell", VCPU_STAT(gdbell_exits) },
@@ -124,6 +125,40 @@ static void kvmppc_vcpu_sync_spe(struct kvm_vcpu *vcpu)
 }
 #endif
 
+/*
+ * Load up guest vcpu FP state if it's needed.
+ * It also set the MSR_FP in thread so that host know
+ * we're holding FPU, and then host can help to save
+ * guest vcpu FP state if other threads require to use FPU.
+ * This simulates an FP unavailable fault.
+ *
+ * It requires to be called with preemption disabled.
+ */
+static inline void kvmppc_load_guest_fp(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_PPC_FPU
+       if (!(current->thread.regs->msr & MSR_FP)) {
+               enable_kernel_fp();
+               load_fp_state(&vcpu->arch.fp);
+               current->thread.fp_save_area = &vcpu->arch.fp;
+               current->thread.regs->msr |= MSR_FP;
+       }
+#endif
+}
+
+/*
+ * Save guest vcpu FP state into thread.
+ * It requires to be called with preemption disabled.
+ */
+static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_PPC_FPU
+       if (current->thread.regs->msr & MSR_FP)
+               giveup_fpu(current);
+       current->thread.fp_save_area = NULL;
+#endif
+}
+
 static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
 {
 #if defined(CONFIG_PPC_FPU) && !defined(CONFIG_KVM_BOOKE_HV)
@@ -134,6 +169,40 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
 #endif
 }
 
+/*
+ * Simulate AltiVec unavailable fault to load guest state
+ * from thread to AltiVec unit.
+ * It requires to be called with preemption disabled.
+ */
+static inline void kvmppc_load_guest_altivec(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_ALTIVEC
+       if (cpu_has_feature(CPU_FTR_ALTIVEC)) {
+               if (!(current->thread.regs->msr & MSR_VEC)) {
+                       enable_kernel_altivec();
+                       load_vr_state(&vcpu->arch.vr);
+                       current->thread.vr_save_area = &vcpu->arch.vr;
+                       current->thread.regs->msr |= MSR_VEC;
+               }
+       }
+#endif
+}
+
+/*
+ * Save guest vcpu AltiVec state into thread.
+ * It requires to be called with preemption disabled.
+ */
+static inline void kvmppc_save_guest_altivec(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_ALTIVEC
+       if (cpu_has_feature(CPU_FTR_ALTIVEC)) {
+               if (current->thread.regs->msr & MSR_VEC)
+                       giveup_altivec(current);
+               current->thread.vr_save_area = NULL;
+       }
+#endif
+}
+
 static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu)
 {
        /* Synchronize guest's desire to get debug interrupts into shadow MSR */
@@ -267,6 +336,16 @@ static void kvmppc_core_dequeue_watchdog(struct kvm_vcpu *vcpu)
        clear_bit(BOOKE_IRQPRIO_WATCHDOG, &vcpu->arch.pending_exceptions);
 }
 
+void kvmppc_core_queue_debug(struct kvm_vcpu *vcpu)
+{
+       kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DEBUG);
+}
+
+void kvmppc_core_dequeue_debug(struct kvm_vcpu *vcpu)
+{
+       clear_bit(BOOKE_IRQPRIO_DEBUG, &vcpu->arch.pending_exceptions);
+}
+
 static void set_guest_srr(struct kvm_vcpu *vcpu, unsigned long srr0, u32 srr1)
 {
        kvmppc_set_srr0(vcpu, srr0);
@@ -341,9 +420,15 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
        case BOOKE_IRQPRIO_ITLB_MISS:
        case BOOKE_IRQPRIO_SYSCALL:
        case BOOKE_IRQPRIO_FP_UNAVAIL:
+#ifdef CONFIG_SPE_POSSIBLE
        case BOOKE_IRQPRIO_SPE_UNAVAIL:
        case BOOKE_IRQPRIO_SPE_FP_DATA:
        case BOOKE_IRQPRIO_SPE_FP_ROUND:
+#endif
+#ifdef CONFIG_ALTIVEC
+       case BOOKE_IRQPRIO_ALTIVEC_UNAVAIL:
+       case BOOKE_IRQPRIO_ALTIVEC_ASSIST:
+#endif
        case BOOKE_IRQPRIO_AP_UNAVAIL:
                allowed = 1;
                msr_mask = MSR_CE | MSR_ME | MSR_DE;
@@ -377,7 +462,11 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                allowed = vcpu->arch.shared->msr & MSR_DE;
                allowed = allowed && !crit;
                msr_mask = MSR_ME;
-               int_class = INT_CLASS_CRIT;
+               if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC))
+                       int_class = INT_CLASS_DBG;
+               else
+                       int_class = INT_CLASS_CRIT;
+
                break;
        }
 
@@ -654,20 +743,27 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        /*
         * Since we can't trap on MSR_FP in GS-mode, we consider the guest
-        * as always using the FPU.  Kernel usage of FP (via
-        * enable_kernel_fp()) in this thread must not occur while
-        * vcpu->fpu_active is set.
+        * as always using the FPU.
         */
-       vcpu->fpu_active = 1;
-
        kvmppc_load_guest_fp(vcpu);
 #endif
 
+#ifdef CONFIG_ALTIVEC
+       /* Save userspace AltiVec state in stack */
+       if (cpu_has_feature(CPU_FTR_ALTIVEC))
+               enable_kernel_altivec();
+       /*
+        * Since we can't trap on MSR_VEC in GS-mode, we consider the guest
+        * as always using the AltiVec.
+        */
+       kvmppc_load_guest_altivec(vcpu);
+#endif
+
        /* Switch to guest debug context */
-       debug = vcpu->arch.shadow_dbg_reg;
+       debug = vcpu->arch.dbg_reg;
        switch_booke_debug_regs(&debug);
        debug = current->thread.debug;
-       current->thread.debug = vcpu->arch.shadow_dbg_reg;
+       current->thread.debug = vcpu->arch.dbg_reg;
 
        vcpu->arch.pgdir = current->mm->pgd;
        kvmppc_fix_ee_before_entry();
@@ -683,8 +779,10 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
 #ifdef CONFIG_PPC_FPU
        kvmppc_save_guest_fp(vcpu);
+#endif
 
-       vcpu->fpu_active = 0;
+#ifdef CONFIG_ALTIVEC
+       kvmppc_save_guest_altivec(vcpu);
 #endif
 
 out:
@@ -728,9 +826,36 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 
 static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
-       struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+       struct debug_reg *dbg_reg = &(vcpu->arch.dbg_reg);
        u32 dbsr = vcpu->arch.dbsr;
 
+       if (vcpu->guest_debug == 0) {
+               /*
+                * Debug resources belong to Guest.
+                * Imprecise debug event is not injected
+                */
+               if (dbsr & DBSR_IDE) {
+                       dbsr &= ~DBSR_IDE;
+                       if (!dbsr)
+                               return RESUME_GUEST;
+               }
+
+               if (dbsr && (vcpu->arch.shared->msr & MSR_DE) &&
+                           (vcpu->arch.dbg_reg.dbcr0 & DBCR0_IDM))
+                       kvmppc_core_queue_debug(vcpu);
+
+               /* Inject a program interrupt if trap debug is not allowed */
+               if ((dbsr & DBSR_TIE) && !(vcpu->arch.shared->msr & MSR_DE))
+                       kvmppc_core_queue_program(vcpu, ESR_PTR);
+
+               return RESUME_GUEST;
+       }
+
+       /*
+        * Debug resource owned by userspace.
+        * Clear guest dbsr (vcpu->arch.dbsr)
+        */
+       vcpu->arch.dbsr = 0;
        run->debug.arch.status = 0;
        run->debug.arch.address = vcpu->arch.pc;
 
@@ -868,7 +993,12 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        case BOOKE_INTERRUPT_DATA_STORAGE:
        case BOOKE_INTERRUPT_DTLB_MISS:
        case BOOKE_INTERRUPT_HV_PRIV:
-               emulated = kvmppc_get_last_inst(vcpu, false, &last_inst);
+               emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
+               break;
+       case BOOKE_INTERRUPT_PROGRAM:
+               /* SW breakpoints arrive as illegal instructions on HV */
+               if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
+                       emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
                break;
        default:
                break;
@@ -947,6 +1077,18 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                break;
 
        case BOOKE_INTERRUPT_PROGRAM:
+               if ((vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) &&
+                       (last_inst == KVMPPC_INST_SW_BREAKPOINT)) {
+                       /*
+                        * We are here because of an SW breakpoint instr,
+                        * so lets return to host to handle.
+                        */
+                       r = kvmppc_handle_debug(run, vcpu);
+                       run->exit_reason = KVM_EXIT_DEBUG;
+                       kvmppc_account_exit(vcpu, DEBUG_EXITS);
+                       break;
+               }
+
                if (vcpu->arch.shared->msr & (MSR_PR | MSR_GS)) {
                        /*
                         * Program traps generated by user-level software must
@@ -991,7 +1133,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND);
                r = RESUME_GUEST;
                break;
-#else
+#elif defined(CONFIG_SPE_POSSIBLE)
        case BOOKE_INTERRUPT_SPE_UNAVAIL:
                /*
                 * Guest wants SPE, but host kernel doesn't support it.  Send
@@ -1012,6 +1154,22 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                run->hw.hardware_exit_reason = exit_nr;
                r = RESUME_HOST;
                break;
+#endif /* CONFIG_SPE_POSSIBLE */
+
+/*
+ * On cores with Vector category, KVM is loaded only if CONFIG_ALTIVEC,
+ * see kvmppc_core_check_processor_compat().
+ */
+#ifdef CONFIG_ALTIVEC
+       case BOOKE_INTERRUPT_ALTIVEC_UNAVAIL:
+               kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_UNAVAIL);
+               r = RESUME_GUEST;
+               break;
+
+       case BOOKE_INTERRUPT_ALTIVEC_ASSIST:
+               kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_ASSIST);
+               r = RESUME_GUEST;
+               break;
 #endif
 
        case BOOKE_INTERRUPT_DATA_STORAGE:
@@ -1188,6 +1346,8 @@ out:
                else {
                        /* interrupts now hard-disabled */
                        kvmppc_fix_ee_before_entry();
+                       kvmppc_load_guest_fp(vcpu);
+                       kvmppc_load_guest_altivec(vcpu);
                }
        }
 
@@ -1243,6 +1403,11 @@ int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu)
        setup_timer(&vcpu->arch.wdt_timer, kvmppc_watchdog_func,
                    (unsigned long)vcpu);
 
+       /*
+        * Clear DBSR.MRR to avoid guest debug interrupt as
+        * this is of host interest
+        */
+       mtspr(SPRN_DBSR, DBSR_MRR);
        return 0;
 }
 
@@ -1457,144 +1622,125 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        return vcpu->kvm->arch.kvm_ops->set_sregs(vcpu, sregs);
 }
 
-int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
+                       union kvmppc_one_reg *val)
 {
        int r = 0;
-       union kvmppc_one_reg val;
-       int size;
-
-       size = one_reg_size(reg->id);
-       if (size > sizeof(val))
-               return -EINVAL;
 
-       switch (reg->id) {
+       switch (id) {
        case KVM_REG_PPC_IAC1:
-               val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac1);
+               *val = get_reg_val(id, vcpu->arch.dbg_reg.iac1);
                break;
        case KVM_REG_PPC_IAC2:
-               val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac2);
+               *val = get_reg_val(id, vcpu->arch.dbg_reg.iac2);
                break;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
        case KVM_REG_PPC_IAC3:
-               val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac3);
+               *val = get_reg_val(id, vcpu->arch.dbg_reg.iac3);
                break;
        case KVM_REG_PPC_IAC4:
-               val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac4);
+               *val = get_reg_val(id, vcpu->arch.dbg_reg.iac4);
                break;
 #endif
        case KVM_REG_PPC_DAC1:
-               val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac1);
+               *val = get_reg_val(id, vcpu->arch.dbg_reg.dac1);
                break;
        case KVM_REG_PPC_DAC2:
-               val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac2);
+               *val = get_reg_val(id, vcpu->arch.dbg_reg.dac2);
                break;
        case KVM_REG_PPC_EPR: {
                u32 epr = kvmppc_get_epr(vcpu);
-               val = get_reg_val(reg->id, epr);
+               *val = get_reg_val(id, epr);
                break;
        }
 #if defined(CONFIG_64BIT)
        case KVM_REG_PPC_EPCR:
-               val = get_reg_val(reg->id, vcpu->arch.epcr);
+               *val = get_reg_val(id, vcpu->arch.epcr);
                break;
 #endif
        case KVM_REG_PPC_TCR:
-               val = get_reg_val(reg->id, vcpu->arch.tcr);
+               *val = get_reg_val(id, vcpu->arch.tcr);
                break;
        case KVM_REG_PPC_TSR:
-               val = get_reg_val(reg->id, vcpu->arch.tsr);
+               *val = get_reg_val(id, vcpu->arch.tsr);
                break;
        case KVM_REG_PPC_DEBUG_INST:
-               val = get_reg_val(reg->id, KVMPPC_INST_EHPRIV_DEBUG);
+               *val = get_reg_val(id, KVMPPC_INST_SW_BREAKPOINT);
                break;
        case KVM_REG_PPC_VRSAVE:
-               val = get_reg_val(reg->id, vcpu->arch.vrsave);
+               *val = get_reg_val(id, vcpu->arch.vrsave);
                break;
        default:
-               r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, reg->id, &val);
+               r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, 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 kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
+                       union kvmppc_one_reg *val)
 {
        int r = 0;
-       union kvmppc_one_reg val;
-       int size;
 
-       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) {
+       switch (id) {
        case KVM_REG_PPC_IAC1:
-               vcpu->arch.dbg_reg.iac1 = set_reg_val(reg->id, val);
+               vcpu->arch.dbg_reg.iac1 = set_reg_val(id, *val);
                break;
        case KVM_REG_PPC_IAC2:
-               vcpu->arch.dbg_reg.iac2 = set_reg_val(reg->id, val);
+               vcpu->arch.dbg_reg.iac2 = set_reg_val(id, *val);
                break;
 #if CONFIG_PPC_ADV_DEBUG_IACS > 2
        case KVM_REG_PPC_IAC3:
-               vcpu->arch.dbg_reg.iac3 = set_reg_val(reg->id, val);
+               vcpu->arch.dbg_reg.iac3 = set_reg_val(id, *val);
                break;
        case KVM_REG_PPC_IAC4:
-               vcpu->arch.dbg_reg.iac4 = set_reg_val(reg->id, val);
+               vcpu->arch.dbg_reg.iac4 = set_reg_val(id, *val);
                break;
 #endif
        case KVM_REG_PPC_DAC1:
-               vcpu->arch.dbg_reg.dac1 = set_reg_val(reg->id, val);
+               vcpu->arch.dbg_reg.dac1 = set_reg_val(id, *val);
                break;
        case KVM_REG_PPC_DAC2:
-               vcpu->arch.dbg_reg.dac2 = set_reg_val(reg->id, val);
+               vcpu->arch.dbg_reg.dac2 = set_reg_val(id, *val);
                break;
        case KVM_REG_PPC_EPR: {
-               u32 new_epr = set_reg_val(reg->id, val);
+               u32 new_epr = set_reg_val(id, *val);
                kvmppc_set_epr(vcpu, new_epr);
                break;
        }
 #if defined(CONFIG_64BIT)
        case KVM_REG_PPC_EPCR: {
-               u32 new_epcr = set_reg_val(reg->id, val);
+               u32 new_epcr = set_reg_val(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);
+               u32 tsr_bits = set_reg_val(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);
+               u32 tsr_bits = set_reg_val(id, *val);
                kvmppc_clr_tsr_bits(vcpu, tsr_bits);
                break;
        }
        case KVM_REG_PPC_TSR: {
-               u32 tsr = set_reg_val(reg->id, val);
+               u32 tsr = set_reg_val(id, *val);
                kvmppc_set_tsr(vcpu, tsr);
                break;
        }
        case KVM_REG_PPC_TCR: {
-               u32 tcr = set_reg_val(reg->id, val);
+               u32 tcr = set_reg_val(id, *val);
                kvmppc_set_tcr(vcpu, tcr);
                break;
        }
        case KVM_REG_PPC_VRSAVE:
-               vcpu->arch.vrsave = set_reg_val(reg->id, val);
+               vcpu->arch.vrsave = set_reg_val(id, *val);
                break;
        default:
-               r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, reg->id, &val);
+               r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, id, val);
                break;
        }
 
@@ -1694,10 +1840,8 @@ void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
        update_timer_ints(vcpu);
 }
 
-void kvmppc_decrementer_func(unsigned long data)
+void kvmppc_decrementer_func(struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
-
        if (vcpu->arch.tcr & TCR_ARE) {
                vcpu->arch.dec = vcpu->arch.decar;
                kvmppc_emulate_dec(vcpu);
@@ -1842,7 +1986,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
        int n, b = 0, w = 0;
 
        if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
-               vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
+               vcpu->arch.dbg_reg.dbcr0 = 0;
                vcpu->guest_debug = 0;
                kvm_guest_protect_msr(vcpu, MSR_DE, false);
                return 0;
@@ -1850,15 +1994,13 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 
        kvm_guest_protect_msr(vcpu, MSR_DE, true);
        vcpu->guest_debug = dbg->control;
-       vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
-       /* Set DBCR0_EDM in guest visible DBCR0 register. */
-       vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
+       vcpu->arch.dbg_reg.dbcr0 = 0;
 
        if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
-               vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
+               vcpu->arch.dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
 
        /* Code below handles only HW breakpoints */
-       dbg_reg = &(vcpu->arch.shadow_dbg_reg);
+       dbg_reg = &(vcpu->arch.dbg_reg);
 
 #ifdef CONFIG_KVM_BOOKE_HV
        /*