Blame view

arch/arm/vfp/vfphw.S 8.24 KB
1da177e4c   Linus Torvalds   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   Catalin Marinas   [ARM] 4111/1: All...
71
  @  r11 = CPU number
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  @  lr  = failure return
93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
73
  ENTRY(vfp_support_entry)
1da177e4c   Linus Torvalds   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   Russell King   [ARM] vfp: make f...
78
  	tst	r1, #FPEXC_EN
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
  	bne	look_for_VFP_exceptions	@ VFP is already enabled
  
  	DBGSTR1 "enable %x", r10
af61bdf03   Russell King   ARM: vfp: rename ...
82
  	ldr	r3, vfp_current_hw_state_address
228adef16   Russell King   [ARM] vfp: make f...
83
  	orr	r1, r1, #FPEXC_EN	@ user FPEXC has the enable bit set
af61bdf03   Russell King   ARM: vfp: rename ...
84
  	ldr	r4, [r3, r11, lsl #2]	@ vfp_current_hw_state pointer
228adef16   Russell King   [ARM] vfp: make f...
85
  	bic	r5, r1, #FPEXC_EX	@ make sure exceptions are disabled
08409c33d   Russell King   ARM: vfp: rename ...
86
  	cmp	r4, r10			@ this thread owns the hw context?
f8f2a8522   Russell King   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   Russell King   ARM: vfp: rename ...
90
  	beq	vfp_hw_state_valid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91

f8f2a8522   Russell King   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   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
98
  	DBGSTR1	"save old state %p", r4
f8f2a8522   Russell King   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   Catalin Marinas   [ARM] 4583/1: ARM...
101
  	VFPFSTMIA r4, r5		@ save the working registers
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  	VFPFMRX	r5, FPSCR		@ current status
85d6943af   Catalin Marinas   Fix the VFP handl...
103
  #ifndef CONFIG_CPU_FEROCEON
c98929c07   Catalin Marinas   [ARM] 4582/2: Add...
104
  	tst	r1, #FPEXC_EX		@ is there additional state to save?
24b647a04   Catalin Marinas   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   Catalin Marinas   Fix the VFP handl...
111
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  	stmia	r4, {r1, r5, r6, r8}	@ save FPEXC, FPSCR, FPINST, FPINST2
f8f2a8522   Russell King   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   Catalin Marinas   [ARM] 4111/1: All...
138
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  	DBGSTR1	"load state %p", r10
af61bdf03   Russell King   ARM: vfp: rename ...
141
  	str	r10, [r3, r11, lsl #2]	@ update the vfp_current_hw_state pointer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  					@ Load the saved state back into the VFP
25ebee020   Catalin Marinas   [ARM] 4583/1: ARM...
143
  	VFPFLDMIA r10, r5		@ reload the working registers while
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  					@ FPEXC is in a safe state
80ed35472   Catalin Marinas   [ARM] 3398/1: Fix...
145
  	ldmia	r10, {r1, r5, r6, r8}	@ load FPEXC, FPSCR, FPINST, FPINST2
85d6943af   Catalin Marinas   Fix the VFP handl...
146
  #ifndef CONFIG_CPU_FEROCEON
c98929c07   Catalin Marinas   [ARM] 4582/2: Add...
147
  	tst	r1, #FPEXC_EX		@ is there additional state to restore?
24b647a04   Catalin Marinas   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   Catalin Marinas   Fix the VFP handl...
154
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  	VFPFMXR	FPSCR, r5		@ restore status
08409c33d   Russell King   ARM: vfp: rename ...
156
157
  @ The context stored in the VFP hardware is up to date with this thread
  vfp_hw_state_valid:
228adef16   Russell King   [ARM] vfp: make f...
158
  	tst	r1, #FPEXC_EX
1da177e4c   Linus Torvalds   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   George G. Davis   [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   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
  	mov	pc, r9			@ we think we have handled things
  
  
  look_for_VFP_exceptions:
c98929c07   Catalin Marinas   [ARM] 4582/2: Add...
176
177
  	@ Check for synchronous or asynchronous exception
  	tst	r1, #FPEXC_EX | FPEXC_DEX
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  	bne	process_exception
c98929c07   Catalin Marinas   [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   Linus Torvalds   Linux-2.6.12-rc2
182
  	VFPFMRX	r5, FPSCR
c98929c07   Catalin Marinas   [ARM] 4582/2: Add...
183
  	tst	r5, #FPSCR_IXE
1da177e4c   Linus Torvalds   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   George G. Davis   [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   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
  	mov	pc, lr
  
  process_exception:
  	DBGSTR	"bounce"
1da177e4c   Linus Torvalds   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   Catalin Marinas   [ARM] 4582/2: Add...
207
  	b	VFP_bounce		@ we have handled this - the support
1da177e4c   Linus Torvalds   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   Catalin Marinas   [ARM] 5227/1: Add...
211
  ENDPROC(vfp_support_entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212

93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
213
  ENTRY(vfp_save_state)
c64284648   Catalin Marinas   [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   Catalin Marinas   [ARM] 4583/1: ARM...
218
  	VFPFSTMIA r0, r2		@ save the working registers
c64284648   Catalin Marinas   [ARM] 4111/1: All...
219
  	VFPFMRX	r2, FPSCR		@ current status
c98929c07   Catalin Marinas   [ARM] 4582/2: Add...
220
  	tst	r1, #FPEXC_EX		@ is there additional state to save?
24b647a04   Catalin Marinas   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   Catalin Marinas   [ARM] 4111/1: All...
227
228
  	stmia	r0, {r1, r2, r3, r12}	@ save FPEXC, FPSCR, FPINST, FPINST2
  	mov	pc, lr
93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
229
  ENDPROC(vfp_save_state)
c64284648   Catalin Marinas   [ARM] 4111/1: All...
230

7eb25ebee   Dave Martin   ARM: 6498/1: vfp:...
231
  	.align
af61bdf03   Russell King   ARM: vfp: rename ...
232
233
  vfp_current_hw_state_address:
  	.word	vfp_current_hw_state
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

07f33a035   Catalin Marinas   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   Linus Torvalds   Linux-2.6.12-rc2
242
  	mov	r0, r0
07f33a035   Catalin Marinas   Thumb-2: Implemen...
243
244
245
246
247
248
  #endif
  1:
  	.endm
  
  ENTRY(vfp_get_float)
  	tbl_branch r0, r3, #3
1da177e4c   Linus Torvalds   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   Catalin Marinas   Thumb-2: Implemen...
250
  1:	mrc	p10, 0, r0, c\dr, c0, 0	@ fmrs	r0, s0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  	mov	pc, lr
07f33a035   Catalin Marinas   Thumb-2: Implemen...
252
253
  	.org	1b + 8
  1:	mrc	p10, 0, r0, c\dr, c0, 4	@ fmrs	r0, s1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  	mov	pc, lr
07f33a035   Catalin Marinas   Thumb-2: Implemen...
255
  	.org	1b + 8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  	.endr
93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
257
  ENDPROC(vfp_get_float)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258

93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
259
  ENTRY(vfp_put_float)
07f33a035   Catalin Marinas   Thumb-2: Implemen...
260
  	tbl_branch r1, r3, #3
1da177e4c   Linus Torvalds   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   Catalin Marinas   Thumb-2: Implemen...
262
  1:	mcr	p10, 0, r0, c\dr, c0, 0	@ fmsr	r0, s0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  	mov	pc, lr
07f33a035   Catalin Marinas   Thumb-2: Implemen...
264
265
  	.org	1b + 8
  1:	mcr	p10, 0, r0, c\dr, c0, 4	@ fmsr	r0, s1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  	mov	pc, lr
07f33a035   Catalin Marinas   Thumb-2: Implemen...
267
  	.org	1b + 8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  	.endr
93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
269
  ENDPROC(vfp_put_float)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270

93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
271
  ENTRY(vfp_get_double)
07f33a035   Catalin Marinas   Thumb-2: Implemen...
272
  	tbl_branch r0, r3, #3
1da177e4c   Linus Torvalds   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   Catalin Marinas   Thumb-2: Implemen...
274
  1:	fmrrd	r0, r1, d\dr
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
  	mov	pc, lr
07f33a035   Catalin Marinas   Thumb-2: Implemen...
276
  	.org	1b + 8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  	.endr
25ebee020   Catalin Marinas   [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   Catalin Marinas   Thumb-2: Implemen...
281
  1:	mrrc	p11, 3, r0, r1, c\dr	@ fmrrd	r0, r1, d\dr
25ebee020   Catalin Marinas   [ARM] 4583/1: ARM...
282
  	mov	pc, lr
07f33a035   Catalin Marinas   Thumb-2: Implemen...
283
  	.org	1b + 8
25ebee020   Catalin Marinas   [ARM] 4583/1: ARM...
284
285
  	.endr
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286

25ebee020   Catalin Marinas   [ARM] 4583/1: ARM...
287
  	@ virtual register 16 (or 32 if VFPv3) for compare with zero
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
  	mov	r0, #0
  	mov	r1, #0
  	mov	pc, lr
93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
291
  ENDPROC(vfp_get_double)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292

93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
293
  ENTRY(vfp_put_double)
07f33a035   Catalin Marinas   Thumb-2: Implemen...
294
  	tbl_branch r2, r3, #3
1da177e4c   Linus Torvalds   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   Catalin Marinas   Thumb-2: Implemen...
296
  1:	fmdrr	d\dr, r0, r1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	mov	pc, lr
07f33a035   Catalin Marinas   Thumb-2: Implemen...
298
  	.org	1b + 8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  	.endr
25ebee020   Catalin Marinas   [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   Russell King   ARM: VFP: Fix vfp...
303
  1:	mcrr	p11, 3, r0, r1, c\dr	@ fmdrr	r0, r1, d\dr
25ebee020   Catalin Marinas   [ARM] 4583/1: ARM...
304
  	mov	pc, lr
07f33a035   Catalin Marinas   Thumb-2: Implemen...
305
  	.org	1b + 8
25ebee020   Catalin Marinas   [ARM] 4583/1: ARM...
306
307
  	.endr
  #endif
93ed39701   Catalin Marinas   [ARM] 5227/1: Add...
308
  ENDPROC(vfp_put_double)