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

source code of linux/arch/powerpc/kvm/fpu.S