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