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