xref: /linux/arch/powerpc/kvm/fpu.S (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
12874c5fdSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */
2963cf3dcSAlexander Graf/*
3963cf3dcSAlexander Graf *  FPU helper code to use FPU operations from inside the kernel
4963cf3dcSAlexander Graf *
5963cf3dcSAlexander Graf *    Copyright (C) 2010 Alexander Graf (agraf@suse.de)
6963cf3dcSAlexander Graf */
7963cf3dcSAlexander Graf
865fddcfcSMike Rapoport#include <linux/pgtable.h>
9*2da37761SChristophe Leroy#include <linux/linkage.h>
10*2da37761SChristophe Leroy
11963cf3dcSAlexander Graf#include <asm/reg.h>
12963cf3dcSAlexander Graf#include <asm/page.h>
13963cf3dcSAlexander Graf#include <asm/mmu.h>
14963cf3dcSAlexander Graf#include <asm/cputable.h>
15963cf3dcSAlexander Graf#include <asm/cache.h>
16963cf3dcSAlexander Graf#include <asm/thread_info.h>
17963cf3dcSAlexander Graf#include <asm/ppc_asm.h>
18963cf3dcSAlexander Graf#include <asm/asm-offsets.h>
19963cf3dcSAlexander Graf
20963cf3dcSAlexander Graf/* Instructions operating on single parameters */
21963cf3dcSAlexander Graf
22963cf3dcSAlexander Graf/*
23963cf3dcSAlexander Graf * Single operation with one input operand
24963cf3dcSAlexander Graf *
25963cf3dcSAlexander Graf * R3 = (double*)&fpscr
26963cf3dcSAlexander Graf * R4 = (short*)&result
27963cf3dcSAlexander Graf * R5 = (short*)&param1
28963cf3dcSAlexander Graf */
29963cf3dcSAlexander Graf#define FPS_ONE_IN(name) 					\
30963cf3dcSAlexander Graf_GLOBAL(fps_ ## name);							\
31963cf3dcSAlexander Graf	lfd	0,0(r3);		/* load up fpscr value */	\
32963cf3dcSAlexander Graf	MTFSF_L(0);							\
33963cf3dcSAlexander Graf	lfs	0,0(r5);						\
34963cf3dcSAlexander Graf									\
35963cf3dcSAlexander Graf	name	0,0;							\
36963cf3dcSAlexander Graf									\
37963cf3dcSAlexander Graf	stfs	0,0(r4);						\
38963cf3dcSAlexander Graf	mffs	0;							\
39963cf3dcSAlexander Graf	stfd	0,0(r3);	/* save new fpscr value */	\
40963cf3dcSAlexander Graf	blr
41963cf3dcSAlexander Graf
42963cf3dcSAlexander Graf/*
43963cf3dcSAlexander Graf * Single operation with two input operands
44963cf3dcSAlexander Graf *
45963cf3dcSAlexander Graf * R3 = (double*)&fpscr
46963cf3dcSAlexander Graf * R4 = (short*)&result
47963cf3dcSAlexander Graf * R5 = (short*)&param1
48963cf3dcSAlexander Graf * R6 = (short*)&param2
49963cf3dcSAlexander Graf */
50963cf3dcSAlexander Graf#define FPS_TWO_IN(name) 					\
51963cf3dcSAlexander Graf_GLOBAL(fps_ ## name);							\
52963cf3dcSAlexander Graf	lfd	0,0(r3);		/* load up fpscr value */	\
53963cf3dcSAlexander Graf	MTFSF_L(0);							\
54963cf3dcSAlexander Graf	lfs	0,0(r5);						\
55963cf3dcSAlexander Graf	lfs	1,0(r6);						\
56963cf3dcSAlexander Graf									\
57963cf3dcSAlexander Graf	name	0,0,1;							\
58963cf3dcSAlexander Graf									\
59963cf3dcSAlexander Graf	stfs	0,0(r4);						\
60963cf3dcSAlexander Graf	mffs	0;							\
61963cf3dcSAlexander Graf	stfd	0,0(r3);		/* save new fpscr value */	\
62963cf3dcSAlexander Graf	blr
63963cf3dcSAlexander Graf
64963cf3dcSAlexander Graf/*
65963cf3dcSAlexander Graf * Single operation with three input operands
66963cf3dcSAlexander Graf *
67963cf3dcSAlexander Graf * R3 = (double*)&fpscr
68963cf3dcSAlexander Graf * R4 = (short*)&result
69963cf3dcSAlexander Graf * R5 = (short*)&param1
70963cf3dcSAlexander Graf * R6 = (short*)&param2
71963cf3dcSAlexander Graf * R7 = (short*)&param3
72963cf3dcSAlexander Graf */
73963cf3dcSAlexander Graf#define FPS_THREE_IN(name) 					\
74963cf3dcSAlexander Graf_GLOBAL(fps_ ## name);							\
75963cf3dcSAlexander Graf	lfd	0,0(r3);		/* load up fpscr value */	\
76963cf3dcSAlexander Graf	MTFSF_L(0);							\
77963cf3dcSAlexander Graf	lfs	0,0(r5);						\
78963cf3dcSAlexander Graf	lfs	1,0(r6);						\
79963cf3dcSAlexander Graf	lfs	2,0(r7);						\
80963cf3dcSAlexander Graf									\
81963cf3dcSAlexander Graf	name	0,0,1,2;						\
82963cf3dcSAlexander Graf									\
83963cf3dcSAlexander Graf	stfs	0,0(r4);						\
84963cf3dcSAlexander Graf	mffs	0;							\
85963cf3dcSAlexander Graf	stfd	0,0(r3);		/* save new fpscr value */	\
86963cf3dcSAlexander Graf	blr
87963cf3dcSAlexander Graf
88963cf3dcSAlexander GrafFPS_ONE_IN(fres)
89963cf3dcSAlexander GrafFPS_ONE_IN(frsqrte)
90963cf3dcSAlexander GrafFPS_ONE_IN(fsqrts)
91963cf3dcSAlexander GrafFPS_TWO_IN(fadds)
92963cf3dcSAlexander GrafFPS_TWO_IN(fdivs)
93963cf3dcSAlexander GrafFPS_TWO_IN(fmuls)
94963cf3dcSAlexander GrafFPS_TWO_IN(fsubs)
95963cf3dcSAlexander GrafFPS_THREE_IN(fmadds)
96963cf3dcSAlexander GrafFPS_THREE_IN(fmsubs)
97963cf3dcSAlexander GrafFPS_THREE_IN(fnmadds)
98963cf3dcSAlexander GrafFPS_THREE_IN(fnmsubs)
99963cf3dcSAlexander GrafFPS_THREE_IN(fsel)
100963cf3dcSAlexander Graf
101963cf3dcSAlexander Graf
102963cf3dcSAlexander Graf/* Instructions operating on double parameters */
103963cf3dcSAlexander Graf
104963cf3dcSAlexander Graf/*
105963cf3dcSAlexander Graf * Beginning of double instruction processing
106963cf3dcSAlexander Graf *
107963cf3dcSAlexander Graf * R3 = (double*)&fpscr
108963cf3dcSAlexander Graf * R4 = (u32*)&cr
109963cf3dcSAlexander Graf * R5 = (double*)&result
110963cf3dcSAlexander Graf * R6 = (double*)&param1
111963cf3dcSAlexander Graf * R7 = (double*)&param2 [load_two]
112963cf3dcSAlexander Graf * R8 = (double*)&param3 [load_three]
113963cf3dcSAlexander Graf * LR = instruction call function
114963cf3dcSAlexander Graf */
115*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_load_three)
116963cf3dcSAlexander Graf	lfd	2,0(r8)			/* load param3 */
117*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_load_two)
118963cf3dcSAlexander Graf	lfd	1,0(r7)			/* load param2 */
119*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_load_one)
120963cf3dcSAlexander Graf	lfd	0,0(r6)			/* load param1 */
121*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_load_none)
122963cf3dcSAlexander Graf	lfd	3,0(r3)			/* load up fpscr value */
123963cf3dcSAlexander Graf	MTFSF_L(3)
124963cf3dcSAlexander Graf	lwz	r6, 0(r4)		/* load cr */
125963cf3dcSAlexander Graf	mtcr	r6
126963cf3dcSAlexander Graf	blr
127*2da37761SChristophe LeroySYM_FUNC_END(fpd_load_none)
128*2da37761SChristophe LeroySYM_FUNC_END(fpd_load_one)
129*2da37761SChristophe LeroySYM_FUNC_END(fpd_load_two)
130*2da37761SChristophe LeroySYM_FUNC_END(fpd_load_three)
131963cf3dcSAlexander Graf
132963cf3dcSAlexander Graf/*
133963cf3dcSAlexander Graf * End of double instruction processing
134963cf3dcSAlexander Graf *
135963cf3dcSAlexander Graf * R3 = (double*)&fpscr
136963cf3dcSAlexander Graf * R4 = (u32*)&cr
137963cf3dcSAlexander Graf * R5 = (double*)&result
138963cf3dcSAlexander Graf * LR = caller of instruction call function
139963cf3dcSAlexander Graf */
140*2da37761SChristophe LeroySYM_FUNC_START_LOCAL(fpd_return)
141963cf3dcSAlexander Graf	mfcr	r6
142963cf3dcSAlexander Graf	stfd	0,0(r5)			/* save result */
143963cf3dcSAlexander Graf	mffs	0
144963cf3dcSAlexander Graf	stfd	0,0(r3)			/* save new fpscr value */
145963cf3dcSAlexander Graf	stw	r6,0(r4)		/* save new cr value */
146963cf3dcSAlexander Graf	blr
147*2da37761SChristophe LeroySYM_FUNC_END(fpd_return)
148963cf3dcSAlexander Graf
149963cf3dcSAlexander Graf/*
150963cf3dcSAlexander Graf * Double operation with no input operand
151963cf3dcSAlexander Graf *
152963cf3dcSAlexander Graf * R3 = (double*)&fpscr
153963cf3dcSAlexander Graf * R4 = (u32*)&cr
154963cf3dcSAlexander Graf * R5 = (double*)&result
155963cf3dcSAlexander Graf */
156963cf3dcSAlexander Graf#define FPD_NONE_IN(name) 						\
157963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
158963cf3dcSAlexander Graf	mflr	r12;							\
159963cf3dcSAlexander Graf	bl	fpd_load_none;						\
160963cf3dcSAlexander Graf	mtlr	r12;							\
161963cf3dcSAlexander Graf									\
162963cf3dcSAlexander Graf	name.	0;			/* call instruction */		\
163963cf3dcSAlexander Graf	b	fpd_return
164963cf3dcSAlexander Graf
165963cf3dcSAlexander Graf/*
166963cf3dcSAlexander Graf * Double operation with one input operand
167963cf3dcSAlexander Graf *
168963cf3dcSAlexander Graf * R3 = (double*)&fpscr
169963cf3dcSAlexander Graf * R4 = (u32*)&cr
170963cf3dcSAlexander Graf * R5 = (double*)&result
171963cf3dcSAlexander Graf * R6 = (double*)&param1
172963cf3dcSAlexander Graf */
173963cf3dcSAlexander Graf#define FPD_ONE_IN(name) 						\
174963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
175963cf3dcSAlexander Graf	mflr	r12;							\
176963cf3dcSAlexander Graf	bl	fpd_load_one;						\
177963cf3dcSAlexander Graf	mtlr	r12;							\
178963cf3dcSAlexander Graf									\
179963cf3dcSAlexander Graf	name.	0,0;			/* call instruction */		\
180963cf3dcSAlexander Graf	b	fpd_return
181963cf3dcSAlexander Graf
182963cf3dcSAlexander Graf/*
183963cf3dcSAlexander Graf * Double operation with two input operands
184963cf3dcSAlexander Graf *
185963cf3dcSAlexander Graf * R3 = (double*)&fpscr
186963cf3dcSAlexander Graf * R4 = (u32*)&cr
187963cf3dcSAlexander Graf * R5 = (double*)&result
188963cf3dcSAlexander Graf * R6 = (double*)&param1
189963cf3dcSAlexander Graf * R7 = (double*)&param2
190963cf3dcSAlexander Graf * R8 = (double*)&param3
191963cf3dcSAlexander Graf */
192963cf3dcSAlexander Graf#define FPD_TWO_IN(name) 						\
193963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
194963cf3dcSAlexander Graf	mflr	r12;							\
195963cf3dcSAlexander Graf	bl	fpd_load_two;						\
196963cf3dcSAlexander Graf	mtlr	r12;							\
197963cf3dcSAlexander Graf									\
198963cf3dcSAlexander Graf	name.	0,0,1;			/* call instruction */		\
199963cf3dcSAlexander Graf	b	fpd_return
200963cf3dcSAlexander Graf
201963cf3dcSAlexander Graf/*
202963cf3dcSAlexander Graf * CR Double operation with two input operands
203963cf3dcSAlexander Graf *
204963cf3dcSAlexander Graf * R3 = (double*)&fpscr
205963cf3dcSAlexander Graf * R4 = (u32*)&cr
206963cf3dcSAlexander Graf * R5 = (double*)&param1
207963cf3dcSAlexander Graf * R6 = (double*)&param2
208963cf3dcSAlexander Graf * R7 = (double*)&param3
209963cf3dcSAlexander Graf */
210963cf3dcSAlexander Graf#define FPD_TWO_IN_CR(name)						\
211963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
212963cf3dcSAlexander Graf	lfd	1,0(r6);		/* load param2 */		\
213963cf3dcSAlexander Graf	lfd	0,0(r5);		/* load param1 */		\
214963cf3dcSAlexander Graf	lfd	3,0(r3);		/* load up fpscr value */	\
215963cf3dcSAlexander Graf	MTFSF_L(3);							\
216963cf3dcSAlexander Graf	lwz	r6, 0(r4);		/* load cr */			\
217963cf3dcSAlexander Graf	mtcr	r6;							\
218963cf3dcSAlexander Graf									\
219963cf3dcSAlexander Graf	name	0,0,1;			/* call instruction */		\
220963cf3dcSAlexander Graf	mfcr	r6;							\
221963cf3dcSAlexander Graf	mffs	0;							\
222963cf3dcSAlexander Graf	stfd	0,0(r3);		/* save new fpscr value */	\
223963cf3dcSAlexander Graf	stw	r6,0(r4);		/* save new cr value */		\
224963cf3dcSAlexander Graf	blr
225963cf3dcSAlexander Graf
226963cf3dcSAlexander Graf/*
227963cf3dcSAlexander Graf * Double operation with three input operands
228963cf3dcSAlexander Graf *
229963cf3dcSAlexander Graf * R3 = (double*)&fpscr
230963cf3dcSAlexander Graf * R4 = (u32*)&cr
231963cf3dcSAlexander Graf * R5 = (double*)&result
232963cf3dcSAlexander Graf * R6 = (double*)&param1
233963cf3dcSAlexander Graf * R7 = (double*)&param2
234963cf3dcSAlexander Graf * R8 = (double*)&param3
235963cf3dcSAlexander Graf */
236963cf3dcSAlexander Graf#define FPD_THREE_IN(name) 						\
237963cf3dcSAlexander Graf_GLOBAL(fpd_ ## name);							\
238963cf3dcSAlexander Graf	mflr	r12;							\
239963cf3dcSAlexander Graf	bl	fpd_load_three;						\
240963cf3dcSAlexander Graf	mtlr	r12;							\
241963cf3dcSAlexander Graf									\
242963cf3dcSAlexander Graf	name.	0,0,1,2;		/* call instruction */		\
243963cf3dcSAlexander Graf	b	fpd_return
244963cf3dcSAlexander Graf
245963cf3dcSAlexander GrafFPD_ONE_IN(fsqrts)
246963cf3dcSAlexander GrafFPD_ONE_IN(frsqrtes)
247963cf3dcSAlexander GrafFPD_ONE_IN(fres)
248963cf3dcSAlexander GrafFPD_ONE_IN(frsp)
249963cf3dcSAlexander GrafFPD_ONE_IN(fctiw)
250963cf3dcSAlexander GrafFPD_ONE_IN(fctiwz)
251963cf3dcSAlexander GrafFPD_ONE_IN(fsqrt)
252963cf3dcSAlexander GrafFPD_ONE_IN(fre)
253963cf3dcSAlexander GrafFPD_ONE_IN(frsqrte)
254963cf3dcSAlexander GrafFPD_ONE_IN(fneg)
255963cf3dcSAlexander GrafFPD_ONE_IN(fabs)
256963cf3dcSAlexander GrafFPD_TWO_IN(fadds)
257963cf3dcSAlexander GrafFPD_TWO_IN(fsubs)
258963cf3dcSAlexander GrafFPD_TWO_IN(fdivs)
259963cf3dcSAlexander GrafFPD_TWO_IN(fmuls)
260963cf3dcSAlexander GrafFPD_TWO_IN_CR(fcmpu)
261963cf3dcSAlexander GrafFPD_TWO_IN(fcpsgn)
262963cf3dcSAlexander GrafFPD_TWO_IN(fdiv)
263963cf3dcSAlexander GrafFPD_TWO_IN(fadd)
264963cf3dcSAlexander GrafFPD_TWO_IN(fmul)
265963cf3dcSAlexander GrafFPD_TWO_IN_CR(fcmpo)
266963cf3dcSAlexander GrafFPD_TWO_IN(fsub)
267963cf3dcSAlexander GrafFPD_THREE_IN(fmsubs)
268963cf3dcSAlexander GrafFPD_THREE_IN(fmadds)
269963cf3dcSAlexander GrafFPD_THREE_IN(fnmsubs)
270963cf3dcSAlexander GrafFPD_THREE_IN(fnmadds)
271963cf3dcSAlexander GrafFPD_THREE_IN(fsel)
272963cf3dcSAlexander GrafFPD_THREE_IN(fmsub)
273963cf3dcSAlexander GrafFPD_THREE_IN(fmadd)
274963cf3dcSAlexander GrafFPD_THREE_IN(fnmsub)
275963cf3dcSAlexander GrafFPD_THREE_IN(fnmadd)
27649f6be8eSAndreas Schwab
27749f6be8eSAndreas Schwab_GLOBAL(kvm_cvt_fd)
27849f6be8eSAndreas Schwab	lfs	0,0(r3)
27949f6be8eSAndreas Schwab	stfd	0,0(r4)
28049f6be8eSAndreas Schwab	blr
28149f6be8eSAndreas Schwab
28249f6be8eSAndreas Schwab_GLOBAL(kvm_cvt_df)
28349f6be8eSAndreas Schwab	lfd	0,0(r3)
28449f6be8eSAndreas Schwab	stfs	0,0(r4)
28549f6be8eSAndreas Schwab	blr
286