To emulate paired single instructions, we need to be able to call FPU
operations from within the kernel. Since we don't want gcc to spill
arbitrary FPU code everywhere, we tell it to use a soft fpu.

Since we know we can really call the FPU in safe areas, let's also add
some calls that we can later use to actually execute real world FPU
operations on the host's FPU.

Signed-off-by: Alexander Graf <ag...@suse.de>
---
 arch/powerpc/include/asm/kvm_fpu.h |   45 +++++++++++++++++++++
 arch/powerpc/kernel/ppc_ksyms.c    |    2 +
 arch/powerpc/kvm/Makefile          |    1 +
 arch/powerpc/kvm/fpu.S             |   77 ++++++++++++++++++++++++++++++++++++
 4 files changed, 125 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/kvm_fpu.h
 create mode 100644 arch/powerpc/kvm/fpu.S

diff --git a/arch/powerpc/include/asm/kvm_fpu.h 
b/arch/powerpc/include/asm/kvm_fpu.h
new file mode 100644
index 0000000..2e42eb7
--- /dev/null
+++ b/arch/powerpc/include/asm/kvm_fpu.h
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright Novell Inc. 2010
+ *
+ * Authors: Alexander Graf <ag...@suse.de>
+ */
+
+#ifndef __ASM_KVM_FPU_H__
+#define __ASM_KVM_FPU_H__
+
+#include <linux/types.h>
+
+extern void fp_fres(struct thread_struct *t, u32 *dst, u32 *src1);
+extern void fp_frsqrte(struct thread_struct *t, u32 *dst, u32 *src1);
+extern void fp_fsqrts(struct thread_struct *t, u32 *dst, u32 *src1);
+
+extern void fp_fadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+extern void fp_fdivs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+extern void fp_fmuls(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+extern void fp_fsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+
+extern void fp_fmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                     u32 *src3);
+extern void fp_fmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                     u32 *src3);
+extern void fp_fnmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                      u32 *src3);
+extern void fp_fnmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                      u32 *src3);
+extern void fp_fsel(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+                   u32 *src3);
+
+#endif
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index ab3e392..58fdb3a 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -101,6 +101,8 @@ EXPORT_SYMBOL(pci_dram_offset);
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
 
+EXPORT_SYMBOL_GPL(cvt_df);
+EXPORT_SYMBOL_GPL(cvt_fd);
 EXPORT_SYMBOL(giveup_fpu);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL(giveup_altivec);
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 56484d6..e575cfd 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -40,6 +40,7 @@ kvm-objs-$(CONFIG_KVM_E500) := $(kvm-e500-objs)
 
 kvm-book3s_64-objs := \
        $(common-objs-y) \
+       fpu.o \
        book3s.o \
        book3s_64_emulate.o \
        book3s_64_interrupts.o \
diff --git a/arch/powerpc/kvm/fpu.S b/arch/powerpc/kvm/fpu.S
new file mode 100644
index 0000000..50575ac
--- /dev/null
+++ b/arch/powerpc/kvm/fpu.S
@@ -0,0 +1,77 @@
+/*
+ *  FPU helper code to use FPU operations from inside the kernel
+ *
+ *    Copyright (C) 2010 Alexander Graf (ag...@suse.de)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+#define FPS_ONE_IN(name)                                       \
+_GLOBAL(fp_ ## name);                                                  \
+       lfd     0,THREAD_FPSCR(r3);     /* load up fpscr value */       \
+       MTFSF_L(0);                                                     \
+       lfs     0,0(r5);                                                \
+                                                                       \
+       name    0,0;                                                    \
+                                                                       \
+       stfs    0,0(r4);                                                \
+       mffs    0;                                                      \
+       stfd    0,THREAD_FPSCR(r3);     /* save new fpscr value */      \
+       blr
+
+#define FPS_TWO_IN(name)                                       \
+_GLOBAL(fp_ ## name);                                                  \
+       lfd     0,THREAD_FPSCR(r3);     /* load up fpscr value */       \
+       MTFSF_L(0);                                                     \
+       lfs     0,0(r5);                                                \
+       lfs     1,0(r6);                                                \
+                                                                       \
+       name    0,0,1;                                                  \
+                                                                       \
+       stfs    0,0(r4);                                                \
+       mffs    0;                                                      \
+       stfd    0,THREAD_FPSCR(r3);     /* save new fpscr value */      \
+       blr
+
+#define FPS_THREE_IN(name)                                     \
+_GLOBAL(fp_ ## name);                                                  \
+       lfd     0,THREAD_FPSCR(r3);     /* load up fpscr value */       \
+       MTFSF_L(0);                                                     \
+       lfs     0,0(r5);                                                \
+       lfs     1,0(r6);                                                \
+       lfs     2,0(r7);                                                \
+                                                                       \
+       name    0,0,1,2;                                                \
+                                                                       \
+       stfs    0,0(r4);                                                \
+       mffs    0;                                                      \
+       stfd    0,THREAD_FPSCR(r3);     /* save new fpscr value */      \
+       blr
+
+FPS_ONE_IN(fres)
+FPS_ONE_IN(frsqrte)
+FPS_ONE_IN(fsqrts)
+FPS_TWO_IN(fadds)
+FPS_TWO_IN(fdivs)
+FPS_TWO_IN(fmuls)
+FPS_TWO_IN(fsubs)
+FPS_THREE_IN(fmadds)
+FPS_THREE_IN(fmsubs)
+FPS_THREE_IN(fnmadds)
+FPS_THREE_IN(fnmsubs)
+FPS_THREE_IN(fsel)
+
-- 
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to