Linux contains quite some bits of code to load FPU, Altivec and VSX lazily for
a task. It calls those bits in real mode, coming from an interrupt handler.
For KVM we better reuse those, so let's wrap a bit of trampoline magic around
them and then we can call them from normal module code.
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
 extern u32 kvmppc_trampoline_lowmem;
 extern u32 kvmppc_trampoline_enter;
 extern void kvmppc_rmcall(ulong srr0, ulong srr1);
+extern void kvmppc_load_up_fpu(void);
+extern void kvmppc_load_up_altivec(void);
+extern void kvmppc_load_up_vsx(void);
 
 static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
 {
 
 EXPORT_SYMBOL_GPL(kvmppc_trampoline_enter);
 EXPORT_SYMBOL_GPL(kvmppc_trampoline_lowmem);
 EXPORT_SYMBOL_GPL(kvmppc_rmcall);
+EXPORT_SYMBOL_GPL(kvmppc_load_up_fpu);
+#ifdef CONFIG_ALTIVEC
+EXPORT_SYMBOL_GPL(kvmppc_load_up_altivec);
+#endif
+#ifdef CONFIG_VSX
+EXPORT_SYMBOL_GPL(kvmppc_load_up_vsx);
+#endif
 
        mtsrr1  r4
        RFI
 
+/*
+ * Activate current's external feature (FPU/Altivec/VSX)
+ */
+#define define_load_up(what)                           \
+                                                       \
+_GLOBAL(kvmppc_load_up_ ## what);                      \
+       subi    r1, r1, INT_FRAME_SIZE;                 \
+       mflr    r3;                                     \
+       std     r3, _LINK(r1);                          \
+       mfmsr   r4;                                     \
+       std     r31, GPR3(r1);                          \
+       mr      r31, r4;                                \
+       li      r5, MSR_DR;                             \
+       oris    r5, r5, MSR_EE@h;                       \
+       andc    r4, r4, r5;                             \
+       mtmsr   r4;                                     \
+                                                       \
+       bl      .load_up_ ## what;                      \
+                                                       \
+       mtmsr   r31;                                    \
+       ld      r3, _LINK(r1);                          \
+       ld      r31, GPR3(r1);                          \
+       addi    r1, r1, INT_FRAME_SIZE;                 \
+       mtlr    r3;                                     \
+       blr
+
+define_load_up(fpu)
+#ifdef CONFIG_ALTIVEC
+define_load_up(altivec)
+#endif
+#ifdef CONFIG_VSX
+define_load_up(vsx)
+#endif
+
 .global kvmppc_trampoline_lowmem
 kvmppc_trampoline_lowmem:
        .long kvmppc_handler_lowmem_trampoline - _stext