xref: /linux/arch/powerpc/kvm/fpu.S (revision 963cf3dc6342fe60bb78c615884537621abca0bc)
1*963cf3dcSAlexander Graf/*
2*963cf3dcSAlexander Graf *  FPU helper code to use FPU operations from inside the kernel
3*963cf3dcSAlexander Graf *
4*963cf3dcSAlexander Graf *    Copyright (C) 2010 Alexander Graf (agraf@suse.de)
5*963cf3dcSAlexander Graf *
6*963cf3dcSAlexander Graf *  This program is free software; you can redistribute it and/or
7*963cf3dcSAlexander Graf *  modify it under the terms of the GNU General Public License
8*963cf3dcSAlexander Graf *  as published by the Free Software Foundation; either version
9*963cf3dcSAlexander Graf *  2 of the License, or (at your option) any later version.
10*963cf3dcSAlexander Graf *
11*963cf3dcSAlexander Graf */
12*963cf3dcSAlexander Graf
13*963cf3dcSAlexander Graf#include <asm/reg.h>
14*963cf3dcSAlexander Graf#include <asm/page.h>
15*963cf3dcSAlexander Graf#include <asm/mmu.h>
16*963cf3dcSAlexander Graf#include <asm/pgtable.h>
17*963cf3dcSAlexander Graf#include <asm/cputable.h>
18*963cf3dcSAlexander Graf#include <asm/cache.h>
19*963cf3dcSAlexander Graf#include <asm/thread_info.h>
20*963cf3dcSAlexander Graf#include <asm/ppc_asm.h>
21*963cf3dcSAlexander Graf#include <asm/asm-offsets.h>
22*963cf3dcSAlexander Graf
23*963cf3dcSAlexander Graf/* Instructions operating on single parameters */
24*963cf3dcSAlexander Graf
25*963cf3dcSAlexander Graf/*
26*963cf3dcSAlexander Graf * Single operation with one input operand
27*963cf3dcSAlexander Graf *
28*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
29*963cf3dcSAlexander Graf * R4 = (short*)&result
30*963cf3dcSAlexander Graf * R5 = (short*)&param1
31*963cf3dcSAlexander Graf */
32*963cf3dcSAlexander Graf#define FPS_ONE_IN(name) 					\
33*963cf3dcSAlexander Graf_GLOBAL(fps_ ## name);							\
34*963cf3dcSAlexander Graf	lfd	0,0(r3);		/* load up fpscr value */	\
35*963cf3dcSAlexander Graf	MTFSF_L(0);							\
36*963cf3dcSAlexander Graf	lfs	0,0(r5);						\
37*963cf3dcSAlexander Graf									\
38*963cf3dcSAlexander Graf	name	0,0;							\
39*963cf3dcSAlexander Graf									\
40*963cf3dcSAlexander Graf	stfs	0,0(r4);						\
41*963cf3dcSAlexander Graf	mffs	0;							\
42*963cf3dcSAlexander Graf	stfd	0,0(r3);	/* save new fpscr value */	\
43*963cf3dcSAlexander Graf	blr
44*963cf3dcSAlexander Graf
45*963cf3dcSAlexander Graf/*
46*963cf3dcSAlexander Graf * Single operation with two input operands
47*963cf3dcSAlexander Graf *
48*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
49*963cf3dcSAlexander Graf * R4 = (short*)&result
50*963cf3dcSAlexander Graf * R5 = (short*)&param1
51*963cf3dcSAlexander Graf * R6 = (short*)&param2
52*963cf3dcSAlexander Graf */
53*963cf3dcSAlexander Graf#define FPS_TWO_IN(name) 					\
54*963cf3dcSAlexander Graf_GLOBAL(fps_ ## name);							\
55*963cf3dcSAlexander Graf	lfd	0,0(r3);		/* load up fpscr value */	\
56*963cf3dcSAlexander Graf	MTFSF_L(0);							\
57*963cf3dcSAlexander Graf	lfs	0,0(r5);						\
58*963cf3dcSAlexander Graf	lfs	1,0(r6);						\
59*963cf3dcSAlexander Graf									\
60*963cf3dcSAlexander Graf	name	0,0,1;							\
61*963cf3dcSAlexander Graf									\
62*963cf3dcSAlexander Graf	stfs	0,0(r4);						\
63*963cf3dcSAlexander Graf	mffs	0;							\
64*963cf3dcSAlexander Graf	stfd	0,0(r3);		/* save new fpscr value */	\
65*963cf3dcSAlexander Graf	blr
66*963cf3dcSAlexander Graf
67*963cf3dcSAlexander Graf/*
68*963cf3dcSAlexander Graf * Single operation with three input operands
69*963cf3dcSAlexander Graf *
70*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
71*963cf3dcSAlexander Graf * R4 = (short*)&result
72*963cf3dcSAlexander Graf * R5 = (short*)&param1
73*963cf3dcSAlexander Graf * R6 = (short*)&param2
74*963cf3dcSAlexander Graf * R7 = (short*)&param3
75*963cf3dcSAlexander Graf */
76*963cf3dcSAlexander Graf#define FPS_THREE_IN(name) 					\
77*963cf3dcSAlexander Graf_GLOBAL(fps_ ## name);							\
78*963cf3dcSAlexander Graf	lfd	0,0(r3);		/* load up fpscr value */	\
79*963cf3dcSAlexander Graf	MTFSF_L(0);							\
80*963cf3dcSAlexander Graf	lfs	0,0(r5);						\
81*963cf3dcSAlexander Graf	lfs	1,0(r6);						\
82*963cf3dcSAlexander Graf	lfs	2,0(r7);						\
83*963cf3dcSAlexander Graf									\
84*963cf3dcSAlexander Graf	name	0,0,1,2;						\
85*963cf3dcSAlexander Graf									\
86*963cf3dcSAlexander Graf	stfs	0,0(r4);						\
87*963cf3dcSAlexander Graf	mffs	0;							\
88*963cf3dcSAlexander Graf	stfd	0,0(r3);		/* save new fpscr value */	\
89*963cf3dcSAlexander Graf	blr
90*963cf3dcSAlexander Graf
91*963cf3dcSAlexander GrafFPS_ONE_IN(fres)
92*963cf3dcSAlexander GrafFPS_ONE_IN(frsqrte)
93*963cf3dcSAlexander GrafFPS_ONE_IN(fsqrts)
94*963cf3dcSAlexander GrafFPS_TWO_IN(fadds)
95*963cf3dcSAlexander GrafFPS_TWO_IN(fdivs)
96*963cf3dcSAlexander GrafFPS_TWO_IN(fmuls)
97*963cf3dcSAlexander GrafFPS_TWO_IN(fsubs)
98*963cf3dcSAlexander GrafFPS_THREE_IN(fmadds)
99*963cf3dcSAlexander GrafFPS_THREE_IN(fmsubs)
100*963cf3dcSAlexander GrafFPS_THREE_IN(fnmadds)
101*963cf3dcSAlexander GrafFPS_THREE_IN(fnmsubs)
102*963cf3dcSAlexander GrafFPS_THREE_IN(fsel)
103*963cf3dcSAlexander Graf
104*963cf3dcSAlexander Graf
105*963cf3dcSAlexander Graf/* Instructions operating on double parameters */
106*963cf3dcSAlexander Graf
107*963cf3dcSAlexander Graf/*
108*963cf3dcSAlexander Graf * Beginning of double instruction processing
109*963cf3dcSAlexander Graf *
110*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
111*963cf3dcSAlexander Graf * R4 = (u32*)&cr
112*963cf3dcSAlexander Graf * R5 = (double*)&result
113*963cf3dcSAlexander Graf * R6 = (double*)&param1
114*963cf3dcSAlexander Graf * R7 = (double*)&param2 [load_two]
115*963cf3dcSAlexander Graf * R8 = (double*)&param3 [load_three]
116*963cf3dcSAlexander Graf * LR = instruction call function
117*963cf3dcSAlexander Graf */
118*963cf3dcSAlexander Graffpd_load_three:
119*963cf3dcSAlexander Graf	lfd	2,0(r8)			/* load param3 */
120*963cf3dcSAlexander Graffpd_load_two:
121*963cf3dcSAlexander Graf	lfd	1,0(r7)			/* load param2 */
122*963cf3dcSAlexander Graffpd_load_one:
123*963cf3dcSAlexander Graf	lfd	0,0(r6)			/* load param1 */
124*963cf3dcSAlexander Graffpd_load_none:
125*963cf3dcSAlexander Graf	lfd	3,0(r3)			/* load up fpscr value */
126*963cf3dcSAlexander Graf	MTFSF_L(3)
127*963cf3dcSAlexander Graf	lwz	r6, 0(r4)		/* load cr */
128*963cf3dcSAlexander Graf	mtcr	r6
129*963cf3dcSAlexander Graf	blr
130*963cf3dcSAlexander Graf
131*963cf3dcSAlexander Graf/*
132*963cf3dcSAlexander Graf * End of double instruction processing
133*963cf3dcSAlexander Graf *
134*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
135*963cf3dcSAlexander Graf * R4 = (u32*)&cr
136*963cf3dcSAlexander Graf * R5 = (double*)&result
137*963cf3dcSAlexander Graf * LR = caller of instruction call function
138*963cf3dcSAlexander Graf */
139*963cf3dcSAlexander Graffpd_return:
140*963cf3dcSAlexander Graf	mfcr	r6
141*963cf3dcSAlexander Graf	stfd	0,0(r5)			/* save result */
142*963cf3dcSAlexander Graf	mffs	0
143*963cf3dcSAlexander Graf	stfd	0,0(r3)			/* save new fpscr value */
144*963cf3dcSAlexander Graf	stw	r6,0(r4)		/* save new cr value */
145*963cf3dcSAlexander Graf	blr
146*963cf3dcSAlexander Graf
147*963cf3dcSAlexander Graf/*
148*963cf3dcSAlexander Graf * Double operation with no input operand
149*963cf3dcSAlexander Graf *
150*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
151*963cf3dcSAlexander Graf * R4 = (u32*)&cr
152*963cf3dcSAlexander Graf * R5 = (double*)&result
153*963cf3dcSAlexander Graf */
154*963cf3dcSAlexander Graf#define FPD_NONE_IN(name) 						\
155*963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
156*963cf3dcSAlexander Graf	mflr	r12;							\
157*963cf3dcSAlexander Graf	bl	fpd_load_none;						\
158*963cf3dcSAlexander Graf	mtlr	r12;							\
159*963cf3dcSAlexander Graf									\
160*963cf3dcSAlexander Graf	name.	0;			/* call instruction */		\
161*963cf3dcSAlexander Graf	b	fpd_return
162*963cf3dcSAlexander Graf
163*963cf3dcSAlexander Graf/*
164*963cf3dcSAlexander Graf * Double operation with one input operand
165*963cf3dcSAlexander Graf *
166*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
167*963cf3dcSAlexander Graf * R4 = (u32*)&cr
168*963cf3dcSAlexander Graf * R5 = (double*)&result
169*963cf3dcSAlexander Graf * R6 = (double*)&param1
170*963cf3dcSAlexander Graf */
171*963cf3dcSAlexander Graf#define FPD_ONE_IN(name) 						\
172*963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
173*963cf3dcSAlexander Graf	mflr	r12;							\
174*963cf3dcSAlexander Graf	bl	fpd_load_one;						\
175*963cf3dcSAlexander Graf	mtlr	r12;							\
176*963cf3dcSAlexander Graf									\
177*963cf3dcSAlexander Graf	name.	0,0;			/* call instruction */		\
178*963cf3dcSAlexander Graf	b	fpd_return
179*963cf3dcSAlexander Graf
180*963cf3dcSAlexander Graf/*
181*963cf3dcSAlexander Graf * Double operation with two input operands
182*963cf3dcSAlexander Graf *
183*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
184*963cf3dcSAlexander Graf * R4 = (u32*)&cr
185*963cf3dcSAlexander Graf * R5 = (double*)&result
186*963cf3dcSAlexander Graf * R6 = (double*)&param1
187*963cf3dcSAlexander Graf * R7 = (double*)&param2
188*963cf3dcSAlexander Graf * R8 = (double*)&param3
189*963cf3dcSAlexander Graf */
190*963cf3dcSAlexander Graf#define FPD_TWO_IN(name) 						\
191*963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
192*963cf3dcSAlexander Graf	mflr	r12;							\
193*963cf3dcSAlexander Graf	bl	fpd_load_two;						\
194*963cf3dcSAlexander Graf	mtlr	r12;							\
195*963cf3dcSAlexander Graf									\
196*963cf3dcSAlexander Graf	name.	0,0,1;			/* call instruction */		\
197*963cf3dcSAlexander Graf	b	fpd_return
198*963cf3dcSAlexander Graf
199*963cf3dcSAlexander Graf/*
200*963cf3dcSAlexander Graf * CR Double operation with two input operands
201*963cf3dcSAlexander Graf *
202*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
203*963cf3dcSAlexander Graf * R4 = (u32*)&cr
204*963cf3dcSAlexander Graf * R5 = (double*)&param1
205*963cf3dcSAlexander Graf * R6 = (double*)&param2
206*963cf3dcSAlexander Graf * R7 = (double*)&param3
207*963cf3dcSAlexander Graf */
208*963cf3dcSAlexander Graf#define FPD_TWO_IN_CR(name)						\
209*963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
210*963cf3dcSAlexander Graf	lfd	1,0(r6);		/* load param2 */		\
211*963cf3dcSAlexander Graf	lfd	0,0(r5);		/* load param1 */		\
212*963cf3dcSAlexander Graf	lfd	3,0(r3);		/* load up fpscr value */	\
213*963cf3dcSAlexander Graf	MTFSF_L(3);							\
214*963cf3dcSAlexander Graf	lwz	r6, 0(r4);		/* load cr */			\
215*963cf3dcSAlexander Graf	mtcr	r6;							\
216*963cf3dcSAlexander Graf									\
217*963cf3dcSAlexander Graf	name	0,0,1;			/* call instruction */		\
218*963cf3dcSAlexander Graf	mfcr	r6;							\
219*963cf3dcSAlexander Graf	mffs	0;							\
220*963cf3dcSAlexander Graf	stfd	0,0(r3);		/* save new fpscr value */	\
221*963cf3dcSAlexander Graf	stw	r6,0(r4);		/* save new cr value */		\
222*963cf3dcSAlexander Graf	blr
223*963cf3dcSAlexander Graf
224*963cf3dcSAlexander Graf/*
225*963cf3dcSAlexander Graf * Double operation with three input operands
226*963cf3dcSAlexander Graf *
227*963cf3dcSAlexander Graf * R3 = (double*)&fpscr
228*963cf3dcSAlexander Graf * R4 = (u32*)&cr
229*963cf3dcSAlexander Graf * R5 = (double*)&result
230*963cf3dcSAlexander Graf * R6 = (double*)&param1
231*963cf3dcSAlexander Graf * R7 = (double*)&param2
232*963cf3dcSAlexander Graf * R8 = (double*)&param3
233*963cf3dcSAlexander Graf */
234*963cf3dcSAlexander Graf#define FPD_THREE_IN(name) 						\
235*963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
236*963cf3dcSAlexander Graf	mflr	r12;							\
237*963cf3dcSAlexander Graf	bl	fpd_load_three;						\
238*963cf3dcSAlexander Graf	mtlr	r12;							\
239*963cf3dcSAlexander Graf									\
240*963cf3dcSAlexander Graf	name.	0,0,1,2;		/* call instruction */		\
241*963cf3dcSAlexander Graf	b	fpd_return
242*963cf3dcSAlexander Graf
243*963cf3dcSAlexander GrafFPD_ONE_IN(fsqrts)
244*963cf3dcSAlexander GrafFPD_ONE_IN(frsqrtes)
245*963cf3dcSAlexander GrafFPD_ONE_IN(fres)
246*963cf3dcSAlexander GrafFPD_ONE_IN(frsp)
247*963cf3dcSAlexander GrafFPD_ONE_IN(fctiw)
248*963cf3dcSAlexander GrafFPD_ONE_IN(fctiwz)
249*963cf3dcSAlexander GrafFPD_ONE_IN(fsqrt)
250*963cf3dcSAlexander GrafFPD_ONE_IN(fre)
251*963cf3dcSAlexander GrafFPD_ONE_IN(frsqrte)
252*963cf3dcSAlexander GrafFPD_ONE_IN(fneg)
253*963cf3dcSAlexander GrafFPD_ONE_IN(fabs)
254*963cf3dcSAlexander GrafFPD_TWO_IN(fadds)
255*963cf3dcSAlexander GrafFPD_TWO_IN(fsubs)
256*963cf3dcSAlexander GrafFPD_TWO_IN(fdivs)
257*963cf3dcSAlexander GrafFPD_TWO_IN(fmuls)
258*963cf3dcSAlexander GrafFPD_TWO_IN_CR(fcmpu)
259*963cf3dcSAlexander GrafFPD_TWO_IN(fcpsgn)
260*963cf3dcSAlexander GrafFPD_TWO_IN(fdiv)
261*963cf3dcSAlexander GrafFPD_TWO_IN(fadd)
262*963cf3dcSAlexander GrafFPD_TWO_IN(fmul)
263*963cf3dcSAlexander GrafFPD_TWO_IN_CR(fcmpo)
264*963cf3dcSAlexander GrafFPD_TWO_IN(fsub)
265*963cf3dcSAlexander GrafFPD_THREE_IN(fmsubs)
266*963cf3dcSAlexander GrafFPD_THREE_IN(fmadds)
267*963cf3dcSAlexander GrafFPD_THREE_IN(fnmsubs)
268*963cf3dcSAlexander GrafFPD_THREE_IN(fnmadds)
269*963cf3dcSAlexander GrafFPD_THREE_IN(fsel)
270*963cf3dcSAlexander GrafFPD_THREE_IN(fmsub)
271*963cf3dcSAlexander GrafFPD_THREE_IN(fmadd)
272*963cf3dcSAlexander GrafFPD_THREE_IN(fnmsub)
273*963cf3dcSAlexander GrafFPD_THREE_IN(fnmadd)
274