#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 */
        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;
        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.dbg_reg;
        switch_booke_debug_regs(&debug);
        kvmppc_save_guest_fp(vcpu);
 #endif
 
+#ifdef CONFIG_ALTIVEC
+       kvmppc_save_guest_altivec(vcpu);
+#endif
+
 out:
        vcpu->mode = OUTSIDE_GUEST_MODE;
        return ret;
                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
                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:
                        /* interrupts now hard-disabled */
                        kvmppc_fix_ee_before_entry();
                        kvmppc_load_guest_fp(vcpu);
+                       kvmppc_load_guest_altivec(vcpu);
                }
        }
 
 
 #define BOOKE_IRQPRIO_ALIGNMENT 2
 #define BOOKE_IRQPRIO_PROGRAM 3
 #define BOOKE_IRQPRIO_FP_UNAVAIL 4
+#ifdef CONFIG_SPE_POSSIBLE
 #define BOOKE_IRQPRIO_SPE_UNAVAIL 5
 #define BOOKE_IRQPRIO_SPE_FP_DATA 6
 #define BOOKE_IRQPRIO_SPE_FP_ROUND 7
+#endif
+#ifdef CONFIG_PPC_E500MC
+#define BOOKE_IRQPRIO_ALTIVEC_UNAVAIL 5
+#define BOOKE_IRQPRIO_ALTIVEC_ASSIST 6
+#endif
 #define BOOKE_IRQPRIO_SYSCALL 8
 #define BOOKE_IRQPRIO_AP_UNAVAIL 9
 #define BOOKE_IRQPRIO_DTLB_MISS 10
 
        SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR)
 kvm_handler BOOKE_INTERRUPT_ITLB_MISS, EX_PARAMS_TLB, \
        SPRN_SRR0, SPRN_SRR1, 0
-kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, EX_PARAMS(GEN), \
+kvm_handler BOOKE_INTERRUPT_ALTIVEC_UNAVAIL, EX_PARAMS(GEN), \
        SPRN_SRR0, SPRN_SRR1, 0
-kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, EX_PARAMS(GEN), \
-       SPRN_SRR0, SPRN_SRR1, 0
-kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, EX_PARAMS(GEN), \
+kvm_handler BOOKE_INTERRUPT_ALTIVEC_ASSIST, EX_PARAMS(GEN), \
        SPRN_SRR0, SPRN_SRR1, 0
 kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, EX_PARAMS(GEN), \
        SPRN_SRR0, SPRN_SRR1, 0
 kvm_handler BOOKE_INTERRUPT_DTLB_MISS, \
        SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR)
 kvm_handler BOOKE_INTERRUPT_ITLB_MISS, SPRN_SRR0, SPRN_SRR1, 0
-kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, SPRN_SRR0, SPRN_SRR1, 0
-kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, SPRN_SRR0, SPRN_SRR1, 0
-kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, SPRN_SRR0, SPRN_SRR1, 0
 kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, SPRN_SRR0, SPRN_SRR1, 0
 kvm_handler BOOKE_INTERRUPT_DOORBELL, SPRN_SRR0, SPRN_SRR1, 0
 kvm_lvl_handler BOOKE_INTERRUPT_DOORBELL_CRITICAL, \
 
                break;
 
        /* extra exceptions */
+#ifdef CONFIG_SPE_POSSIBLE
        case SPRN_IVOR32:
                vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val;
                break;
        case SPRN_IVOR34:
                vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val;
                break;
+#endif
+#ifdef CONFIG_ALTIVEC
+       case SPRN_IVOR32:
+               vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL] = spr_val;
+               break;
+       case SPRN_IVOR33:
+               vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST] = spr_val;
+               break;
+#endif
        case SPRN_IVOR35:
                vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val;
                break;
                break;
 
        /* extra exceptions */
+#ifdef CONFIG_SPE_POSSIBLE
        case SPRN_IVOR32:
                *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL];
                break;
        case SPRN_IVOR34:
                *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND];
                break;
+#endif
+#ifdef CONFIG_ALTIVEC
+       case SPRN_IVOR32:
+               *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL];
+               break;
+       case SPRN_IVOR33:
+               *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST];
+               break;
+#endif
        case SPRN_IVOR35:
                *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR];
                break;