aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib/ldstfp.S
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2010-06-15 00:48:58 -0400
committerPaul Mackerras <paulus@samba.org>2010-06-22 05:40:29 -0400
commit0016a4cf5582415849fafbf9f019dd9530824789 (patch)
tree1a8ac83d6aa7c6fff206769f97709c5f67d2d039 /arch/powerpc/lib/ldstfp.S
parent7e27d6e778cd87b6f2415515d7127eba53fe5d02 (diff)
powerpc: Emulate most Book I instructions in emulate_step()
This extends the emulate_step() function to handle a large proportion of the Book I instructions implemented on current 64-bit server processors. The aim is to handle all the load and store instructions used in the kernel, plus all of the instructions that appear between l[wd]arx and st[wd]cx., so this handles the Altivec/VMX lvx and stvx and the VSX lxv2dx and stxv2dx instructions (implemented in POWER7). The new code can emulate user mode instructions, and checks the effective address for a load or store if the saved state is for user mode. It doesn't handle little-endian mode at present. For floating-point, Altivec/VMX and VSX instructions, it checks that the saved MSR has the enable bit for the relevant facility set, and if so, assumes that the FP/VMX/VSX registers contain valid state, and does loads or stores directly to/from the FP/VMX/VSX registers, using assembly helpers in ldstfp.S. Instructions supported now include: * Loads and stores, including some but not all VMX and VSX instructions, and lmw/stmw * Atomic loads and stores (l[dw]arx, st[dw]cx.) * Arithmetic instructions (add, subtract, multiply, divide, etc.) * Compare instructions * Rotate and mask instructions * Shift instructions * Logical instructions (and, or, xor, etc.) * Condition register logical instructions * mtcrf, cntlz[wd], exts[bhw] * isync, sync, lwsync, ptesync, eieio * Cache operations (dcbf, dcbst, dcbt, dcbtst) The overflow-checking arithmetic instructions are not included, but they appear not to be ever used in C code. This uses decimal values for the minor opcodes in the switch statements because that is what appears in the Power ISA specification, thus it is easier to check that they are correct if they are in decimal. If this is used to single-step an instruction where a data breakpoint interrupt occurred, then there is the possibility that the instruction is a lwarx or ldarx. In that case we have to be careful not to lose the reservation until we get to the matching st[wd]cx., or we'll never make forward progress. One alternative is to try to arrange that we can return from interrupts and handle data breakpoint interrupts without losing the reservation, which means not using any spinlocks, mutexes, or atomic ops (including bitops). That seems rather fragile. The other alternative is to emulate the larx/stcx and all the instructions in between. This is why this commit adds support for a wide range of integer instructions. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/lib/ldstfp.S')
-rw-r--r--arch/powerpc/lib/ldstfp.S375
1 files changed, 375 insertions, 0 deletions
diff --git a/arch/powerpc/lib/ldstfp.S b/arch/powerpc/lib/ldstfp.S
new file mode 100644
index 000000000000..f6448636baf5
--- /dev/null
+++ b/arch/powerpc/lib/ldstfp.S
@@ -0,0 +1,375 @@
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#define STKFRM (PPC_MIN_STKFRM + 16)
21
22 .macro extab instr,handler
23 .section __ex_table,"a"
24 PPC_LONG \instr,\handler
25 .previous
26 .endm
27
28 .macro inst32 op
29reg = 0
30 .rept 32
3120: \op reg,0,r4
32 b 3f
33 extab 20b,99f
34reg = reg + 1
35 .endr
36 .endm
37
38/* Get the contents of frN into fr0; N is in r3. */
39_GLOBAL(get_fpr)
40 mflr r0
41 rlwinm r3,r3,3,0xf8
42 bcl 20,31,1f
43 blr /* fr0 is already in fr0 */
44 nop
45reg = 1
46 .rept 31
47 fmr fr0,reg
48 blr
49reg = reg + 1
50 .endr
511: mflr r5
52 add r5,r3,r5
53 mtctr r5
54 mtlr r0
55 bctr
56
57/* Put the contents of fr0 into frN; N is in r3. */
58_GLOBAL(put_fpr)
59 mflr r0
60 rlwinm r3,r3,3,0xf8
61 bcl 20,31,1f
62 blr /* fr0 is already in fr0 */
63 nop
64reg = 1
65 .rept 31
66 fmr reg,fr0
67 blr
68reg = reg + 1
69 .endr
701: mflr r5
71 add r5,r3,r5
72 mtctr r5
73 mtlr r0
74 bctr
75
76/* Load FP reg N from float at *p. N is in r3, p in r4. */
77_GLOBAL(do_lfs)
78 PPC_STLU r1,-STKFRM(r1)
79 mflr r0
80 PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
81 mfmsr r6
82 ori r7,r6,MSR_FP
83 cmpwi cr7,r3,0
84 mtmsrd r7
85 isync
86 beq cr7,1f
87 stfd fr0,STKFRM-16(r1)
881: li r9,-EFAULT
892: lfs fr0,0(r4)
90 li r9,0
913: bl put_fpr
92 beq cr7,4f
93 lfd fr0,STKFRM-16(r1)
944: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
95 mtlr r0
96 mtmsrd r6
97 isync
98 mr r3,r9
99 addi r1,r1,STKFRM
100 blr
101 extab 2b,3b
102
103/* Load FP reg N from double at *p. N is in r3, p in r4. */
104_GLOBAL(do_lfd)
105 PPC_STLU r1,-STKFRM(r1)
106 mflr r0
107 PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
108 mfmsr r6
109 ori r7,r6,MSR_FP
110 cmpwi cr7,r3,0
111 mtmsrd r7
112 isync
113 beq cr7,1f
114 stfd fr0,STKFRM-16(r1)
1151: li r9,-EFAULT
1162: lfd fr0,0(r4)
117 li r9,0
1183: beq cr7,4f
119 bl put_fpr
120 lfd fr0,STKFRM-16(r1)
1214: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
122 mtlr r0
123 mtmsrd r6
124 isync
125 mr r3,r9
126 addi r1,r1,STKFRM
127 blr
128 extab 2b,3b
129
130/* Store FP reg N to float at *p. N is in r3, p in r4. */
131_GLOBAL(do_stfs)
132 PPC_STLU r1,-STKFRM(r1)
133 mflr r0
134 PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
135 mfmsr r6
136 ori r7,r6,MSR_FP
137 cmpwi cr7,r3,0
138 mtmsrd r7
139 isync
140 beq cr7,1f
141 stfd fr0,STKFRM-16(r1)
142 bl get_fpr
1431: li r9,-EFAULT
1442: stfs fr0,0(r4)
145 li r9,0
1463: beq cr7,4f
147 lfd fr0,STKFRM-16(r1)
1484: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
149 mtlr r0
150 mtmsrd r6
151 isync
152 mr r3,r9
153 addi r1,r1,STKFRM
154 blr
155 extab 2b,3b
156
157/* Store FP reg N to double at *p. N is in r3, p in r4. */
158_GLOBAL(do_stfd)
159 PPC_STLU r1,-STKFRM(r1)
160 mflr r0
161 PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
162 mfmsr r6
163 ori r7,r6,MSR_FP
164 cmpwi cr7,r3,0
165 mtmsrd r7
166 isync
167 beq cr7,1f
168 stfd fr0,STKFRM-16(r1)
169 bl get_fpr
1701: li r9,-EFAULT
1712: stfd fr0,0(r4)
172 li r9,0
1733: beq cr7,4f
174 lfd fr0,STKFRM-16(r1)
1754: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
176 mtlr r0
177 mtmsrd r6
178 isync
179 mr r3,r9
180 addi r1,r1,STKFRM
181 blr
182 extab 2b,3b
183
184#ifdef CONFIG_ALTIVEC
185/* Get the contents of vrN into vr0; N is in r3. */
186_GLOBAL(get_vr)
187 mflr r0
188 rlwinm r3,r3,3,0xf8
189 bcl 20,31,1f
190 blr /* vr0 is already in vr0 */
191 nop
192reg = 1
193 .rept 31
194 vor vr0,reg,reg /* assembler doesn't know vmr? */
195 blr
196reg = reg + 1
197 .endr
1981: mflr r5
199 add r5,r3,r5
200 mtctr r5
201 mtlr r0
202 bctr
203
204/* Put the contents of vr0 into vrN; N is in r3. */
205_GLOBAL(put_vr)
206 mflr r0
207 rlwinm r3,r3,3,0xf8
208 bcl 20,31,1f
209 blr /* vr0 is already in vr0 */
210 nop
211reg = 1
212 .rept 31
213 vor reg,vr0,vr0
214 blr
215reg = reg + 1
216 .endr
2171: mflr r5
218 add r5,r3,r5
219 mtctr r5
220 mtlr r0
221 bctr
222
223/* Load vector reg N from *p. N is in r3, p in r4. */
224_GLOBAL(do_lvx)
225 PPC_STLU r1,-STKFRM(r1)
226 mflr r0
227 PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
228 mfmsr r6
229 oris r7,r6,MSR_VEC@h
230 cmpwi cr7,r3,0
231 li r8,STKFRM-16
232 mtmsrd r7
233 isync
234 beq cr7,1f
235 stvx vr0,r1,r8
2361: li r9,-EFAULT
2372: lvx vr0,0,r4
238 li r9,0
2393: beq cr7,4f
240 bl put_vr
241 lvx vr0,r1,r8
2424: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
243 mtlr r0
244 mtmsrd r6
245 isync
246 mr r3,r9
247 addi r1,r1,STKFRM
248 blr
249 extab 2b,3b
250
251/* Store vector reg N to *p. N is in r3, p in r4. */
252_GLOBAL(do_stvx)
253 PPC_STLU r1,-STKFRM(r1)
254 mflr r0
255 PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
256 mfmsr r6
257 oris r7,r6,MSR_VEC@h
258 cmpwi cr7,r3,0
259 li r8,STKFRM-16
260 mtmsrd r7
261 isync
262 beq cr7,1f
263 stvx vr0,r1,r8
264 bl get_vr
2651: li r9,-EFAULT
2662: stvx vr0,0,r4
267 li r9,0
2683: beq cr7,4f
269 lvx vr0,r1,r8
2704: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
271 mtlr r0
272 mtmsrd r6
273 isync
274 mr r3,r9
275 addi r1,r1,STKFRM
276 blr
277 extab 2b,3b
278#endif /* CONFIG_ALTIVEC */
279
280#ifdef CONFIG_VSX
281/* Get the contents of vsrN into vsr0; N is in r3. */
282_GLOBAL(get_vsr)
283 mflr r0
284 rlwinm r3,r3,3,0x1f8
285 bcl 20,31,1f
286 blr /* vsr0 is already in vsr0 */
287 nop
288reg = 1
289 .rept 63
290 XXLOR(0,reg,reg)
291 blr
292reg = reg + 1
293 .endr
2941: mflr r5
295 add r5,r3,r5
296 mtctr r5
297 mtlr r0
298 bctr
299
300/* Put the contents of vsr0 into vsrN; N is in r3. */
301_GLOBAL(put_vsr)
302 mflr r0
303 rlwinm r3,r3,3,0x1f8
304 bcl 20,31,1f
305 blr /* vr0 is already in vr0 */
306 nop
307reg = 1
308 .rept 63
309 XXLOR(reg,0,0)
310 blr
311reg = reg + 1
312 .endr
3131: mflr r5
314 add r5,r3,r5
315 mtctr r5
316 mtlr r0
317 bctr
318
319/* Load VSX reg N from vector doubleword *p. N is in r3, p in r4. */
320_GLOBAL(do_lxvd2x)
321 PPC_STLU r1,-STKFRM(r1)
322 mflr r0
323 PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
324 mfmsr r6
325 oris r7,r6,MSR_VSX@h
326 cmpwi cr7,r3,0
327 li r8,STKFRM-16
328 mtmsrd r7
329 isync
330 beq cr7,1f
331 STXVD2X(0,r1,r8)
3321: li r9,-EFAULT
3332: LXVD2X(0,0,r4)
334 li r9,0
3353: beq cr7,4f
336 bl put_vsr
337 LXVD2X(0,r1,r8)
3384: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
339 mtlr r0
340 mtmsrd r6
341 isync
342 mr r3,r9
343 addi r1,r1,STKFRM
344 blr
345 extab 2b,3b
346
347/* Store VSX reg N to vector doubleword *p. N is in r3, p in r4. */
348_GLOBAL(do_stxvd2x)
349 PPC_STLU r1,-STKFRM(r1)
350 mflr r0
351 PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
352 mfmsr r6
353 oris r7,r6,MSR_VSX@h
354 cmpwi cr7,r3,0
355 li r8,STKFRM-16
356 mtmsrd r7
357 isync
358 beq cr7,1f
359 STXVD2X(0,r1,r8)
360 bl get_vsr
3611: li r9,-EFAULT
3622: STXVD2X(0,0,r4)
363 li r9,0
3643: beq cr7,4f
365 LXVD2X(0,r1,r8)
3664: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
367 mtlr r0
368 mtmsrd r6
369 isync
370 mr r3,r9
371 addi r1,r1,STKFRM
372 blr
373 extab 2b,3b
374
375#endif /* CONFIG_VSX */