Blame view
arch/arm/vfp/vfphw.S
8.24 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
/* * linux/arch/arm/vfp/vfphw.S * * Copyright (C) 2004 ARM Limited. * Written by Deep Blue Solutions Limited. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This code is called from the kernel's undefined instruction trap. * r9 holds the return address for successful handling. * lr holds the return address for unrecognised instructions. * r10 points at the start of the private FP workspace in the thread structure * sp points to a struct pt_regs (as defined in include/asm/proc/ptrace.h) */ #include <asm/thread_info.h> #include <asm/vfpmacros.h> #include "../kernel/entry-header.S" .macro DBGSTR, str #ifdef DEBUG stmfd sp!, {r0-r3, ip, lr} add r0, pc, #4 bl printk b 1f .asciz "<7>VFP: \str " .balign 4 1: ldmfd sp!, {r0-r3, ip, lr} #endif .endm .macro DBGSTR1, str, arg #ifdef DEBUG stmfd sp!, {r0-r3, ip, lr} mov r1, \arg add r0, pc, #4 bl printk b 1f .asciz "<7>VFP: \str " .balign 4 1: ldmfd sp!, {r0-r3, ip, lr} #endif .endm .macro DBGSTR3, str, arg1, arg2, arg3 #ifdef DEBUG stmfd sp!, {r0-r3, ip, lr} mov r3, \arg3 mov r2, \arg2 mov r1, \arg1 add r0, pc, #4 bl printk b 1f .asciz "<7>VFP: \str " .balign 4 1: ldmfd sp!, {r0-r3, ip, lr} #endif .endm @ VFP hardware support entry point. @ @ r0 = faulted instruction @ r2 = faulted PC+4 @ r9 = successful return @ r10 = vfp_state union |
c64284648 [ARM] 4111/1: All... |
71 |
@ r11 = CPU number |
1da177e4c Linux-2.6.12-rc2 |
72 |
@ lr = failure return |
93ed39701 [ARM] 5227/1: Add... |
73 |
ENTRY(vfp_support_entry) |
1da177e4c Linux-2.6.12-rc2 |
74 75 76 77 |
DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 VFPFMRX r1, FPEXC @ Is the VFP enabled? DBGSTR1 "fpexc %08x", r1 |
228adef16 [ARM] vfp: make f... |
78 |
tst r1, #FPEXC_EN |
1da177e4c Linux-2.6.12-rc2 |
79 80 81 |
bne look_for_VFP_exceptions @ VFP is already enabled DBGSTR1 "enable %x", r10 |
af61bdf03 ARM: vfp: rename ... |
82 |
ldr r3, vfp_current_hw_state_address |
228adef16 [ARM] vfp: make f... |
83 |
orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set |
af61bdf03 ARM: vfp: rename ... |
84 |
ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer |
228adef16 [ARM] vfp: make f... |
85 |
bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled |
08409c33d ARM: vfp: rename ... |
86 |
cmp r4, r10 @ this thread owns the hw context? |
f8f2a8522 ARM: vfp: fix a h... |
87 88 89 |
#ifndef CONFIG_SMP @ For UP, checking that this thread owns the hw context is @ sufficient to determine that the hardware state is valid. |
08409c33d ARM: vfp: rename ... |
90 |
beq vfp_hw_state_valid |
1da177e4c Linux-2.6.12-rc2 |
91 |
|
f8f2a8522 ARM: vfp: fix a h... |
92 93 94 |
@ On UP, we lazily save the VFP context. As a different @ thread wants ownership of the VFP hardware, save the old @ state if there was a previous (valid) owner. |
1da177e4c Linux-2.6.12-rc2 |
95 96 97 |
VFPFMXR FPEXC, r5 @ enable VFP, disable any pending @ exceptions, so we can get at the @ rest of it |
1da177e4c Linux-2.6.12-rc2 |
98 |
DBGSTR1 "save old state %p", r4 |
f8f2a8522 ARM: vfp: fix a h... |
99 100 |
cmp r4, #0 @ if the vfp_current_hw_state is NULL beq vfp_reload_hw @ then the hw state needs reloading |
25ebee020 [ARM] 4583/1: ARM... |
101 |
VFPFSTMIA r4, r5 @ save the working registers |
1da177e4c Linux-2.6.12-rc2 |
102 |
VFPFMRX r5, FPSCR @ current status |
85d6943af Fix the VFP handl... |
103 |
#ifndef CONFIG_CPU_FEROCEON |
c98929c07 [ARM] 4582/2: Add... |
104 |
tst r1, #FPEXC_EX @ is there additional state to save? |
24b647a04 ARMv7: Branch ove... |
105 106 107 108 109 110 |
beq 1f VFPFMRX r6, FPINST @ FPINST (only if FPEXC.EX is set) tst r1, #FPEXC_FP2V @ is there an FPINST2 to read? beq 1f VFPFMRX r8, FPINST2 @ FPINST2 if needed (and present) 1: |
85d6943af Fix the VFP handl... |
111 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
112 |
stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 |
f8f2a8522 ARM: vfp: fix a h... |
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
vfp_reload_hw: #else @ For SMP, if this thread does not own the hw context, then we @ need to reload it. No need to save the old state as on SMP, @ we always save the state when we switch away from a thread. bne vfp_reload_hw @ This thread has ownership of the current hardware context. @ However, it may have been migrated to another CPU, in which @ case the saved state is newer than the hardware context. @ Check this by looking at the CPU number which the state was @ last loaded onto. ldr ip, [r10, #VFP_CPU] teq ip, r11 beq vfp_hw_state_valid vfp_reload_hw: @ We're loading this threads state into the VFP hardware. Update @ the CPU number which contains the most up to date VFP context. str r11, [r10, #VFP_CPU] VFPFMXR FPEXC, r5 @ enable VFP, disable any pending @ exceptions, so we can get at the @ rest of it |
c64284648 [ARM] 4111/1: All... |
138 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
139 |
|
1da177e4c Linux-2.6.12-rc2 |
140 |
DBGSTR1 "load state %p", r10 |
af61bdf03 ARM: vfp: rename ... |
141 |
str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer |
1da177e4c Linux-2.6.12-rc2 |
142 |
@ Load the saved state back into the VFP |
25ebee020 [ARM] 4583/1: ARM... |
143 |
VFPFLDMIA r10, r5 @ reload the working registers while |
1da177e4c Linux-2.6.12-rc2 |
144 |
@ FPEXC is in a safe state |
80ed35472 [ARM] 3398/1: Fix... |
145 |
ldmia r10, {r1, r5, r6, r8} @ load FPEXC, FPSCR, FPINST, FPINST2 |
85d6943af Fix the VFP handl... |
146 |
#ifndef CONFIG_CPU_FEROCEON |
c98929c07 [ARM] 4582/2: Add... |
147 |
tst r1, #FPEXC_EX @ is there additional state to restore? |
24b647a04 ARMv7: Branch ove... |
148 149 150 151 152 153 |
beq 1f VFPFMXR FPINST, r6 @ restore FPINST (only if FPEXC.EX is set) tst r1, #FPEXC_FP2V @ is there an FPINST2 to write? beq 1f VFPFMXR FPINST2, r8 @ FPINST2 if needed (and present) 1: |
85d6943af Fix the VFP handl... |
154 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
155 |
VFPFMXR FPSCR, r5 @ restore status |
08409c33d ARM: vfp: rename ... |
156 157 |
@ The context stored in the VFP hardware is up to date with this thread vfp_hw_state_valid: |
228adef16 [ARM] vfp: make f... |
158 |
tst r1, #FPEXC_EX |
1da177e4c Linux-2.6.12-rc2 |
159 160 161 162 163 164 165 |
bne process_exception @ might as well handle the pending @ exception before retrying branch @ out before setting an FPEXC that @ stops us reading stuff VFPFMXR FPEXC, r1 @ restore FPEXC last sub r2, r2, #4 str r2, [sp, #S_PC] @ retry the instruction |
f2255be81 [ARM] 5440/1: Fix... |
166 167 168 169 170 171 |
#ifdef CONFIG_PREEMPT get_thread_info r10 ldr r4, [r10, #TI_PREEMPT] @ get preempt count sub r11, r4, #1 @ decrement it str r11, [r10, #TI_PREEMPT] #endif |
1da177e4c Linux-2.6.12-rc2 |
172 173 174 175 |
mov pc, r9 @ we think we have handled things look_for_VFP_exceptions: |
c98929c07 [ARM] 4582/2: Add... |
176 177 |
@ Check for synchronous or asynchronous exception tst r1, #FPEXC_EX | FPEXC_DEX |
1da177e4c Linux-2.6.12-rc2 |
178 |
bne process_exception |
c98929c07 [ARM] 4582/2: Add... |
179 180 181 |
@ On some implementations of the VFP subarch 1, setting FPSCR.IXE @ causes all the CDP instructions to be bounced synchronously without @ setting the FPEXC.EX bit |
1da177e4c Linux-2.6.12-rc2 |
182 |
VFPFMRX r5, FPSCR |
c98929c07 [ARM] 4582/2: Add... |
183 |
tst r5, #FPSCR_IXE |
1da177e4c Linux-2.6.12-rc2 |
184 185 186 187 188 189 |
bne process_exception @ Fall into hand on to next handler - appropriate coproc instr @ not recognised by VFP DBGSTR "not VFP" |
f2255be81 [ARM] 5440/1: Fix... |
190 191 192 193 194 195 |
#ifdef CONFIG_PREEMPT get_thread_info r10 ldr r4, [r10, #TI_PREEMPT] @ get preempt count sub r11, r4, #1 @ decrement it str r11, [r10, #TI_PREEMPT] #endif |
1da177e4c Linux-2.6.12-rc2 |
196 197 198 199 |
mov pc, lr process_exception: DBGSTR "bounce" |
1da177e4c Linux-2.6.12-rc2 |
200 201 202 203 204 205 206 |
mov r2, sp @ nothing stacked - regdump is at TOS mov lr, r9 @ setup for a return to the user code. @ Now call the C code to package up the bounce to the support code @ r0 holds the trigger instruction @ r1 holds the FPEXC value @ r2 pointer to register dump |
c98929c07 [ARM] 4582/2: Add... |
207 |
b VFP_bounce @ we have handled this - the support |
1da177e4c Linux-2.6.12-rc2 |
208 209 210 |
@ code will raise an exception if @ required. If not, the user code will @ retry the faulted instruction |
93ed39701 [ARM] 5227/1: Add... |
211 |
ENDPROC(vfp_support_entry) |
1da177e4c Linux-2.6.12-rc2 |
212 |
|
93ed39701 [ARM] 5227/1: Add... |
213 |
ENTRY(vfp_save_state) |
c64284648 [ARM] 4111/1: All... |
214 215 216 217 |
@ Save the current VFP state @ r0 - save location @ r1 - FPEXC DBGSTR1 "save VFP state %p", r0 |
25ebee020 [ARM] 4583/1: ARM... |
218 |
VFPFSTMIA r0, r2 @ save the working registers |
c64284648 [ARM] 4111/1: All... |
219 |
VFPFMRX r2, FPSCR @ current status |
c98929c07 [ARM] 4582/2: Add... |
220 |
tst r1, #FPEXC_EX @ is there additional state to save? |
24b647a04 ARMv7: Branch ove... |
221 222 223 224 225 226 |
beq 1f VFPFMRX r3, FPINST @ FPINST (only if FPEXC.EX is set) tst r1, #FPEXC_FP2V @ is there an FPINST2 to read? beq 1f VFPFMRX r12, FPINST2 @ FPINST2 if needed (and present) 1: |
c64284648 [ARM] 4111/1: All... |
227 228 |
stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2 mov pc, lr |
93ed39701 [ARM] 5227/1: Add... |
229 |
ENDPROC(vfp_save_state) |
c64284648 [ARM] 4111/1: All... |
230 |
|
7eb25ebee ARM: 6498/1: vfp:... |
231 |
.align |
af61bdf03 ARM: vfp: rename ... |
232 233 |
vfp_current_hw_state_address: .word vfp_current_hw_state |
1da177e4c Linux-2.6.12-rc2 |
234 |
|
07f33a035 Thumb-2: Implemen... |
235 236 237 238 239 240 241 |
.macro tbl_branch, base, tmp, shift #ifdef CONFIG_THUMB2_KERNEL adr \tmp, 1f add \tmp, \tmp, \base, lsl \shift mov pc, \tmp #else add pc, pc, \base, lsl \shift |
1da177e4c Linux-2.6.12-rc2 |
242 |
mov r0, r0 |
07f33a035 Thumb-2: Implemen... |
243 244 245 246 247 248 |
#endif 1: .endm ENTRY(vfp_get_float) tbl_branch r0, r3, #3 |
1da177e4c Linux-2.6.12-rc2 |
249 |
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 |
07f33a035 Thumb-2: Implemen... |
250 |
1: mrc p10, 0, r0, c\dr, c0, 0 @ fmrs r0, s0 |
1da177e4c Linux-2.6.12-rc2 |
251 |
mov pc, lr |
07f33a035 Thumb-2: Implemen... |
252 253 |
.org 1b + 8 1: mrc p10, 0, r0, c\dr, c0, 4 @ fmrs r0, s1 |
1da177e4c Linux-2.6.12-rc2 |
254 |
mov pc, lr |
07f33a035 Thumb-2: Implemen... |
255 |
.org 1b + 8 |
1da177e4c Linux-2.6.12-rc2 |
256 |
.endr |
93ed39701 [ARM] 5227/1: Add... |
257 |
ENDPROC(vfp_get_float) |
1da177e4c Linux-2.6.12-rc2 |
258 |
|
93ed39701 [ARM] 5227/1: Add... |
259 |
ENTRY(vfp_put_float) |
07f33a035 Thumb-2: Implemen... |
260 |
tbl_branch r1, r3, #3 |
1da177e4c Linux-2.6.12-rc2 |
261 |
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 |
07f33a035 Thumb-2: Implemen... |
262 |
1: mcr p10, 0, r0, c\dr, c0, 0 @ fmsr r0, s0 |
1da177e4c Linux-2.6.12-rc2 |
263 |
mov pc, lr |
07f33a035 Thumb-2: Implemen... |
264 265 |
.org 1b + 8 1: mcr p10, 0, r0, c\dr, c0, 4 @ fmsr r0, s1 |
1da177e4c Linux-2.6.12-rc2 |
266 |
mov pc, lr |
07f33a035 Thumb-2: Implemen... |
267 |
.org 1b + 8 |
1da177e4c Linux-2.6.12-rc2 |
268 |
.endr |
93ed39701 [ARM] 5227/1: Add... |
269 |
ENDPROC(vfp_put_float) |
1da177e4c Linux-2.6.12-rc2 |
270 |
|
93ed39701 [ARM] 5227/1: Add... |
271 |
ENTRY(vfp_get_double) |
07f33a035 Thumb-2: Implemen... |
272 |
tbl_branch r0, r3, #3 |
1da177e4c Linux-2.6.12-rc2 |
273 |
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 |
07f33a035 Thumb-2: Implemen... |
274 |
1: fmrrd r0, r1, d\dr |
1da177e4c Linux-2.6.12-rc2 |
275 |
mov pc, lr |
07f33a035 Thumb-2: Implemen... |
276 |
.org 1b + 8 |
1da177e4c Linux-2.6.12-rc2 |
277 |
.endr |
25ebee020 [ARM] 4583/1: ARM... |
278 279 280 |
#ifdef CONFIG_VFPv3 @ d16 - d31 registers .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 |
07f33a035 Thumb-2: Implemen... |
281 |
1: mrrc p11, 3, r0, r1, c\dr @ fmrrd r0, r1, d\dr |
25ebee020 [ARM] 4583/1: ARM... |
282 |
mov pc, lr |
07f33a035 Thumb-2: Implemen... |
283 |
.org 1b + 8 |
25ebee020 [ARM] 4583/1: ARM... |
284 285 |
.endr #endif |
1da177e4c Linux-2.6.12-rc2 |
286 |
|
25ebee020 [ARM] 4583/1: ARM... |
287 |
@ virtual register 16 (or 32 if VFPv3) for compare with zero |
1da177e4c Linux-2.6.12-rc2 |
288 289 290 |
mov r0, #0 mov r1, #0 mov pc, lr |
93ed39701 [ARM] 5227/1: Add... |
291 |
ENDPROC(vfp_get_double) |
1da177e4c Linux-2.6.12-rc2 |
292 |
|
93ed39701 [ARM] 5227/1: Add... |
293 |
ENTRY(vfp_put_double) |
07f33a035 Thumb-2: Implemen... |
294 |
tbl_branch r2, r3, #3 |
1da177e4c Linux-2.6.12-rc2 |
295 |
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 |
07f33a035 Thumb-2: Implemen... |
296 |
1: fmdrr d\dr, r0, r1 |
1da177e4c Linux-2.6.12-rc2 |
297 |
mov pc, lr |
07f33a035 Thumb-2: Implemen... |
298 |
.org 1b + 8 |
1da177e4c Linux-2.6.12-rc2 |
299 |
.endr |
25ebee020 [ARM] 4583/1: ARM... |
300 301 302 |
#ifdef CONFIG_VFPv3 @ d16 - d31 registers .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 |
138de1c44 ARM: VFP: Fix vfp... |
303 |
1: mcrr p11, 3, r0, r1, c\dr @ fmdrr r0, r1, d\dr |
25ebee020 [ARM] 4583/1: ARM... |
304 |
mov pc, lr |
07f33a035 Thumb-2: Implemen... |
305 |
.org 1b + 8 |
25ebee020 [ARM] 4583/1: ARM... |
306 307 |
.endr #endif |
93ed39701 [ARM] 5227/1: Add... |
308 |
ENDPROC(vfp_put_double) |