1/*
2 * Floating-point, VMX/Altivec and VSX loads and stores
3 * for use in instruction emulation.
4 *
5 * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
6 *
7 *  This program is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU General Public License
9 *  as published by the Free Software Foundation; either version
10 *  2 of the License, or (at your option) any later version.
11 */
12
13#include <asm/processor.h>
14#include <asm/ppc_asm.h>
15#include <asm/ppc-opcode.h>
16#include <asm/reg.h>
17#include <asm/asm-offsets.h>
18#include <linux/errno.h>
19
20#ifdef CONFIG_PPC_FPU
21
22#define STKFRM	(PPC_MIN_STKFRM + 16)
23
24	.macro	extab	instr,handler
25	.section __ex_table,"a"
26	PPC_LONG \instr,\handler
27	.previous
28	.endm
29
30	.macro	inst32	op
31reg = 0
32	.rept	32
3320:	\op	reg,0,r4
34	b	3f
35	extab	20b,99f
36reg = reg + 1
37	.endr
38	.endm
39
40/* Get the contents of frN into fr0; N is in r3. */
41_GLOBAL(get_fpr)
42	mflr	r0
43	rlwinm	r3,r3,3,0xf8
44	bcl	20,31,1f
45	blr			/* fr0 is already in fr0 */
46	nop
47reg = 1
48	.rept	31
49	fmr	fr0,reg
50	blr
51reg = reg + 1
52	.endr
531:	mflr	r5
54	add	r5,r3,r5
55	mtctr	r5
56	mtlr	r0
57	bctr
58
59/* Put the contents of fr0 into frN; N is in r3. */
60_GLOBAL(put_fpr)
61	mflr	r0
62	rlwinm	r3,r3,3,0xf8
63	bcl	20,31,1f
64	blr			/* fr0 is already in fr0 */
65	nop
66reg = 1
67	.rept	31
68	fmr	reg,fr0
69	blr
70reg = reg + 1
71	.endr
721:	mflr	r5
73	add	r5,r3,r5
74	mtctr	r5
75	mtlr	r0
76	bctr
77
78/* Load FP reg N from float at *p.  N is in r3, p in r4. */
79_GLOBAL(do_lfs)
80	PPC_STLU r1,-STKFRM(r1)
81	mflr	r0
82	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
83	mfmsr	r6
84	ori	r7,r6,MSR_FP
85	cmpwi	cr7,r3,0
86	MTMSRD(r7)
87	isync
88	beq	cr7,1f
89	stfd	fr0,STKFRM-16(r1)
901:	li	r9,-EFAULT
912:	lfs	fr0,0(r4)
92	li	r9,0
933:	bl	put_fpr
94	beq	cr7,4f
95	lfd	fr0,STKFRM-16(r1)
964:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
97	mtlr	r0
98	MTMSRD(r6)
99	isync
100	mr	r3,r9
101	addi	r1,r1,STKFRM
102	blr
103	extab	2b,3b
104
105/* Load FP reg N from double at *p.  N is in r3, p in r4. */
106_GLOBAL(do_lfd)
107	PPC_STLU r1,-STKFRM(r1)
108	mflr	r0
109	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
110	mfmsr	r6
111	ori	r7,r6,MSR_FP
112	cmpwi	cr7,r3,0
113	MTMSRD(r7)
114	isync
115	beq	cr7,1f
116	stfd	fr0,STKFRM-16(r1)
1171:	li	r9,-EFAULT
1182:	lfd	fr0,0(r4)
119	li	r9,0
1203:	beq	cr7,4f
121	bl	put_fpr
122	lfd	fr0,STKFRM-16(r1)
1234:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
124	mtlr	r0
125	MTMSRD(r6)
126	isync
127	mr	r3,r9
128	addi	r1,r1,STKFRM
129	blr
130	extab	2b,3b
131
132/* Store FP reg N to float at *p.  N is in r3, p in r4. */
133_GLOBAL(do_stfs)
134	PPC_STLU r1,-STKFRM(r1)
135	mflr	r0
136	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
137	mfmsr	r6
138	ori	r7,r6,MSR_FP
139	cmpwi	cr7,r3,0
140	MTMSRD(r7)
141	isync
142	beq	cr7,1f
143	stfd	fr0,STKFRM-16(r1)
144	bl	get_fpr
1451:	li	r9,-EFAULT
1462:	stfs	fr0,0(r4)
147	li	r9,0
1483:	beq	cr7,4f
149	lfd	fr0,STKFRM-16(r1)
1504:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
151	mtlr	r0
152	MTMSRD(r6)
153	isync
154	mr	r3,r9
155	addi	r1,r1,STKFRM
156	blr
157	extab	2b,3b
158
159/* Store FP reg N to double at *p.  N is in r3, p in r4. */
160_GLOBAL(do_stfd)
161	PPC_STLU r1,-STKFRM(r1)
162	mflr	r0
163	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
164	mfmsr	r6
165	ori	r7,r6,MSR_FP
166	cmpwi	cr7,r3,0
167	MTMSRD(r7)
168	isync
169	beq	cr7,1f
170	stfd	fr0,STKFRM-16(r1)
171	bl	get_fpr
1721:	li	r9,-EFAULT
1732:	stfd	fr0,0(r4)
174	li	r9,0
1753:	beq	cr7,4f
176	lfd	fr0,STKFRM-16(r1)
1774:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
178	mtlr	r0
179	MTMSRD(r6)
180	isync
181	mr	r3,r9
182	addi	r1,r1,STKFRM
183	blr
184	extab	2b,3b
185
186#ifdef CONFIG_ALTIVEC
187/* Get the contents of vrN into vr0; N is in r3. */
188_GLOBAL(get_vr)
189	mflr	r0
190	rlwinm	r3,r3,3,0xf8
191	bcl	20,31,1f
192	blr			/* vr0 is already in vr0 */
193	nop
194reg = 1
195	.rept	31
196	vor	vr0,reg,reg	/* assembler doesn't know vmr? */
197	blr
198reg = reg + 1
199	.endr
2001:	mflr	r5
201	add	r5,r3,r5
202	mtctr	r5
203	mtlr	r0
204	bctr
205
206/* Put the contents of vr0 into vrN; N is in r3. */
207_GLOBAL(put_vr)
208	mflr	r0
209	rlwinm	r3,r3,3,0xf8
210	bcl	20,31,1f
211	blr			/* vr0 is already in vr0 */
212	nop
213reg = 1
214	.rept	31
215	vor	reg,vr0,vr0
216	blr
217reg = reg + 1
218	.endr
2191:	mflr	r5
220	add	r5,r3,r5
221	mtctr	r5
222	mtlr	r0
223	bctr
224
225/* Load vector reg N from *p.  N is in r3, p in r4. */
226_GLOBAL(do_lvx)
227	PPC_STLU r1,-STKFRM(r1)
228	mflr	r0
229	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
230	mfmsr	r6
231	oris	r7,r6,MSR_VEC@h
232	cmpwi	cr7,r3,0
233	li	r8,STKFRM-16
234	MTMSRD(r7)
235	isync
236	beq	cr7,1f
237	stvx	vr0,r1,r8
2381:	li	r9,-EFAULT
2392:	lvx	vr0,0,r4
240	li	r9,0
2413:	beq	cr7,4f
242	bl	put_vr
243	lvx	vr0,r1,r8
2444:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
245	mtlr	r0
246	MTMSRD(r6)
247	isync
248	mr	r3,r9
249	addi	r1,r1,STKFRM
250	blr
251	extab	2b,3b
252
253/* Store vector reg N to *p.  N is in r3, p in r4. */
254_GLOBAL(do_stvx)
255	PPC_STLU r1,-STKFRM(r1)
256	mflr	r0
257	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
258	mfmsr	r6
259	oris	r7,r6,MSR_VEC@h
260	cmpwi	cr7,r3,0
261	li	r8,STKFRM-16
262	MTMSRD(r7)
263	isync
264	beq	cr7,1f
265	stvx	vr0,r1,r8
266	bl	get_vr
2671:	li	r9,-EFAULT
2682:	stvx	vr0,0,r4
269	li	r9,0
2703:	beq	cr7,4f
271	lvx	vr0,r1,r8
2724:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
273	mtlr	r0
274	MTMSRD(r6)
275	isync
276	mr	r3,r9
277	addi	r1,r1,STKFRM
278	blr
279	extab	2b,3b
280#endif /* CONFIG_ALTIVEC */
281
282#ifdef CONFIG_VSX
283/* Get the contents of vsrN into vsr0; N is in r3. */
284_GLOBAL(get_vsr)
285	mflr	r0
286	rlwinm	r3,r3,3,0x1f8
287	bcl	20,31,1f
288	blr			/* vsr0 is already in vsr0 */
289	nop
290reg = 1
291	.rept	63
292	XXLOR(0,reg,reg)
293	blr
294reg = reg + 1
295	.endr
2961:	mflr	r5
297	add	r5,r3,r5
298	mtctr	r5
299	mtlr	r0
300	bctr
301
302/* Put the contents of vsr0 into vsrN; N is in r3. */
303_GLOBAL(put_vsr)
304	mflr	r0
305	rlwinm	r3,r3,3,0x1f8
306	bcl	20,31,1f
307	blr			/* vr0 is already in vr0 */
308	nop
309reg = 1
310	.rept	63
311	XXLOR(reg,0,0)
312	blr
313reg = reg + 1
314	.endr
3151:	mflr	r5
316	add	r5,r3,r5
317	mtctr	r5
318	mtlr	r0
319	bctr
320
321/* Load VSX reg N from vector doubleword *p.  N is in r3, p in r4. */
322_GLOBAL(do_lxvd2x)
323	PPC_STLU r1,-STKFRM(r1)
324	mflr	r0
325	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
326	mfmsr	r6
327	oris	r7,r6,MSR_VSX@h
328	cmpwi	cr7,r3,0
329	li	r8,STKFRM-16
330	MTMSRD(r7)
331	isync
332	beq	cr7,1f
333	STXVD2X(0,r1,r8)
3341:	li	r9,-EFAULT
3352:	LXVD2X(0,0,r4)
336	li	r9,0
3373:	beq	cr7,4f
338	bl	put_vsr
339	LXVD2X(0,r1,r8)
3404:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
341	mtlr	r0
342	MTMSRD(r6)
343	isync
344	mr	r3,r9
345	addi	r1,r1,STKFRM
346	blr
347	extab	2b,3b
348
349/* Store VSX reg N to vector doubleword *p.  N is in r3, p in r4. */
350_GLOBAL(do_stxvd2x)
351	PPC_STLU r1,-STKFRM(r1)
352	mflr	r0
353	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
354	mfmsr	r6
355	oris	r7,r6,MSR_VSX@h
356	cmpwi	cr7,r3,0
357	li	r8,STKFRM-16
358	MTMSRD(r7)
359	isync
360	beq	cr7,1f
361	STXVD2X(0,r1,r8)
362	bl	get_vsr
3631:	li	r9,-EFAULT
3642:	STXVD2X(0,0,r4)
365	li	r9,0
3663:	beq	cr7,4f
367	LXVD2X(0,r1,r8)
3684:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
369	mtlr	r0
370	MTMSRD(r6)
371	isync
372	mr	r3,r9
373	addi	r1,r1,STKFRM
374	blr
375	extab	2b,3b
376
377#endif /* CONFIG_VSX */
378
379#endif	/* CONFIG_PPC_FPU */
380