xref: /linux/arch/arm/nwfpe/entry.S (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
174ba9207SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */
21da177e4SLinus Torvalds/*
31da177e4SLinus Torvalds    NetWinder Floating Point Emulator
41da177e4SLinus Torvalds    (c) Rebel.COM, 1998
51da177e4SLinus Torvalds    (c) 1998, 1999 Philip Blundell
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds*/
10*47ba5f39SArd Biesheuvel#include <linux/linkage.h>
116ebbf2ceSRussell King#include <asm/assembler.h>
12e7f626dbSLeif Lindholm#include <asm/opcodes.h>
13e7f626dbSLeif Lindholm
141da177e4SLinus Torvalds/* This is the kernel's entry point into the floating point emulator.
151da177e4SLinus TorvaldsIt is called from the kernel with code similar to this:
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds	sub	r4, r5, #4
181da177e4SLinus Torvalds	ldrt	r0, [r4]			@ r0  = instruction
191da177e4SLinus Torvalds	adrsvc	al, r9, ret_from_exception	@ r9  = normal FP return
201da177e4SLinus Torvalds	adrsvc	al, lr, fpundefinstr		@ lr  = undefined instr return
211da177e4SLinus Torvalds
221da177e4SLinus Torvalds	get_current_task r10
231da177e4SLinus Torvalds	mov	r8, #1
241da177e4SLinus Torvalds	strb	r8, [r10, #TSK_USED_MATH]	@ set current->used_math
251da177e4SLinus Torvalds	add	r10, r10, #TSS_FPESAVE		@ r10 = workspace
261da177e4SLinus Torvalds	ldr	r4, .LC2
271da177e4SLinus Torvalds	ldr	pc, [r4]			@ Call FP emulator entry point
281da177e4SLinus Torvalds
291da177e4SLinus TorvaldsThe kernel expects the emulator to return via one of two possible
301da177e4SLinus Torvaldspoints of return it passes to the emulator.  The emulator, if
311da177e4SLinus Torvaldssuccessful in its emulation, jumps to ret_from_exception (passed in
321da177e4SLinus Torvaldsr9) and the kernel takes care of returning control from the trap to
331da177e4SLinus Torvaldsthe user code.  If the emulator is unable to emulate the instruction,
341da177e4SLinus Torvaldsit returns via _fpundefinstr (passed via lr) and the kernel halts the
351da177e4SLinus Torvaldsuser program with a core dump.
361da177e4SLinus Torvalds
371da177e4SLinus TorvaldsOn entry to the emulator r10 points to an area of private FP workspace
381da177e4SLinus Torvaldsreserved in the thread structure for this process.  This is where the
391da177e4SLinus Torvaldsemulator saves its registers across calls.  The first word of this area
401da177e4SLinus Torvaldsis used as a flag to detect the first time a process uses floating point,
411da177e4SLinus Torvaldsso that the emulator startup cost can be avoided for tasks that don't
421da177e4SLinus Torvaldswant it.
431da177e4SLinus Torvalds
441da177e4SLinus TorvaldsThis routine does three things:
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds1) The kernel has created a struct pt_regs on the stack and saved the
471da177e4SLinus Torvaldsuser registers into it.  See /usr/include/asm/proc/ptrace.h for details.
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds2) It calls EmulateAll to emulate a floating point instruction.
501da177e4SLinus TorvaldsEmulateAll returns 1 if the emulation was successful, or 0 if not.
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds3) If an instruction has been emulated successfully, it looks ahead at
531da177e4SLinus Torvaldsthe next instruction.  If it is a floating point instruction, it
541da177e4SLinus Torvaldsexecutes the instruction, without returning to user space.  In this
551da177e4SLinus Torvaldsway it repeatedly looks ahead and executes floating point instructions
561da177e4SLinus Torvaldsuntil it encounters a non floating point instruction, at which time it
571da177e4SLinus Torvaldsreturns via _fpreturn.
581da177e4SLinus Torvalds
591da177e4SLinus TorvaldsThis is done to reduce the effect of the trap overhead on each
601da177e4SLinus Torvaldsfloating point instructions.  GCC attempts to group floating point
611da177e4SLinus Torvaldsinstructions to allow the emulator to spread the cost of the trap over
621da177e4SLinus Torvaldsseveral floating point instructions.  */
631da177e4SLinus Torvalds
64c1f438f5SCatalin Marinas#include <asm/asm-offsets.h>
65c1f438f5SCatalin Marinas
661da177e4SLinus Torvalds	.globl	nwfpe_enter
671da177e4SLinus Torvaldsnwfpe_enter:
681da177e4SLinus Torvalds	mov	r4, lr			@ save the failure-return addresses
691da177e4SLinus Torvalds	mov	sl, sp			@ we access the registers via 'sl'
701da177e4SLinus Torvalds
71c1f438f5SCatalin Marinas	ldr	r5, [sp, #S_PC]		@ get contents of PC;
72c1f438f5SCatalin Marinas	mov	r6, r0			@ save the opcode
731da177e4SLinus Torvaldsemulate:
74c1f438f5SCatalin Marinas	ldr	r1, [sp, #S_PSR]	@ fetch the PSR
75e7f626dbSLeif Lindholm	bl	arm_check_condition	@ check the condition
76e7f626dbSLeif Lindholm	cmp	r0, #ARM_OPCODE_CONDTEST_PASS	@ condition passed?
77c1f438f5SCatalin Marinas
78c1f438f5SCatalin Marinas	@ if condition code failed to match, next insn
79e7f626dbSLeif Lindholm	bne	next			@ get the next instruction;
80c1f438f5SCatalin Marinas
81c1f438f5SCatalin Marinas	mov	r0, r6			@ prepare for EmulateAll()
821da177e4SLinus Torvalds	bl	EmulateAll		@ emulate the instruction
831da177e4SLinus Torvalds	cmp	r0, #0			@ was emulation successful
846ebbf2ceSRussell King	reteq	r4			@ no, return failure
851da177e4SLinus Torvalds
861da177e4SLinus Torvaldsnext:
8739dc53deSRussell King	uaccess_enable r3
881da177e4SLinus Torvalds.Lx1:	ldrt	r6, [r5], #4		@ get the next instruction and
891da177e4SLinus Torvalds					@ increment PC
9039dc53deSRussell King	uaccess_disable r3
911da177e4SLinus Torvalds	and	r2, r6, #0x0F000000	@ test for FP insns
921da177e4SLinus Torvalds	teq	r2, #0x0C000000
931da177e4SLinus Torvalds	teqne	r2, #0x0D000000
941da177e4SLinus Torvalds	teqne	r2, #0x0E000000
956ebbf2ceSRussell King	retne	r9			@ return ok if not a fp insn
961da177e4SLinus Torvalds
97c1f438f5SCatalin Marinas	str	r5, [sp, #S_PC]		@ update PC copy in regs
981da177e4SLinus Torvalds
991da177e4SLinus Torvalds	mov	r0, r6			@ save a copy
100c1f438f5SCatalin Marinas	b	emulate			@ check condition and emulate
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds	@ We need to be prepared for the instructions at .Lx1 and .Lx2
1031da177e4SLinus Torvalds	@ to fault.  Emit the appropriate exception gunk to fix things up.
1041da177e4SLinus Torvalds	@ ??? For some reason, faults can happen at .Lx2 even with a
1051da177e4SLinus Torvalds	@ plain LDR instruction.  Weird, but it seems harmless.
106c4a84ae3SArd Biesheuvel	.pushsection .text.fixup,"ax"
1071da177e4SLinus Torvalds	.align	2
108*47ba5f39SArd Biesheuvel.Lrep:	str     r4, [sp, #S_PC]		@ retry current instruction
1096ebbf2ceSRussell King.Lfix:	ret	r9			@ let the user eat segfaults
1104260415fSRussell King	.popsection
1111da177e4SLinus Torvalds
1124260415fSRussell King	.pushsection __ex_table,"a"
1131da177e4SLinus Torvalds	.align	3
1141da177e4SLinus Torvalds	.long	.Lx1, .Lfix
1154260415fSRussell King	.popsection
116*47ba5f39SArd Biesheuvel
117*47ba5f39SArd Biesheuvel	@
118*47ba5f39SArd Biesheuvel	@ Check whether the instruction is a co-processor instruction.
119*47ba5f39SArd Biesheuvel	@ If yes, we need to call the relevant co-processor handler.
120*47ba5f39SArd Biesheuvel	@ Only FPE instructions are dispatched here, everything else
121*47ba5f39SArd Biesheuvel	@ is handled by undef hooks.
122*47ba5f39SArd Biesheuvel	@
123*47ba5f39SArd Biesheuvel	@ Emulators may wish to make use of the following registers:
124*47ba5f39SArd Biesheuvel	@  r4  = PC value to resume execution after successful emulation
125*47ba5f39SArd Biesheuvel	@  r9  = normal "successful" return address
126*47ba5f39SArd Biesheuvel	@  lr  = unrecognised instruction return address
127*47ba5f39SArd Biesheuvel	@ IRQs enabled, FIQs enabled.
128*47ba5f39SArd Biesheuvel	@
129*47ba5f39SArd BiesheuvelENTRY(call_fpe)
130*47ba5f39SArd Biesheuvel	mov	r2, r4
131*47ba5f39SArd Biesheuvel	sub	r4, r4, #4			@ ARM instruction at user PC - 4
132*47ba5f39SArd BiesheuvelUSERL(	.Lrep,	ldrt r0, [r4])			@ load opcode from user space
133*47ba5f39SArd BiesheuvelARM_BE8(rev	r0, r0)				@ little endian instruction
134*47ba5f39SArd Biesheuvel
135*47ba5f39SArd Biesheuvel	uaccess_disable ip
136*47ba5f39SArd Biesheuvel
137*47ba5f39SArd Biesheuvel	get_thread_info r10			@ get current thread
138*47ba5f39SArd Biesheuvel	tst	r0, #0x08000000			@ only CDP/CPRT/LDC/STC have bit 27
139*47ba5f39SArd Biesheuvel	reteq	lr
140*47ba5f39SArd Biesheuvel	and	r8, r0, #0x00000f00		@ mask out CP number
141*47ba5f39SArd Biesheuvel#ifdef CONFIG_IWMMXT
142*47ba5f39SArd Biesheuvel	@ Test if we need to give access to iWMMXt coprocessors
143*47ba5f39SArd Biesheuvel	ldr	r5, [r10, #TI_FLAGS]
144*47ba5f39SArd Biesheuvel	rsbs	r7, r8, #(1 << 8)		@ CP 0 or 1 only
145*47ba5f39SArd Biesheuvel	movscs	r7, r5, lsr #(TIF_USING_IWMMXT + 1)
146*47ba5f39SArd Biesheuvel	movcs	r0, sp				@ pass struct pt_regs
147*47ba5f39SArd Biesheuvel	bcs	iwmmxt_task_enable
148*47ba5f39SArd Biesheuvel#endif
149*47ba5f39SArd Biesheuvel	add	pc, pc, r8, lsr #6
150*47ba5f39SArd Biesheuvel	nop
151*47ba5f39SArd Biesheuvel
152*47ba5f39SArd Biesheuvel	ret	lr				@ CP#0
153*47ba5f39SArd Biesheuvel	b	do_fpe				@ CP#1 (FPE)
154*47ba5f39SArd Biesheuvel	b	do_fpe				@ CP#2 (FPE)
155*47ba5f39SArd Biesheuvel	ret	lr				@ CP#3
156*47ba5f39SArd Biesheuvel	ret	lr				@ CP#4
157*47ba5f39SArd Biesheuvel	ret	lr				@ CP#5
158*47ba5f39SArd Biesheuvel	ret	lr				@ CP#6
159*47ba5f39SArd Biesheuvel	ret	lr				@ CP#7
160*47ba5f39SArd Biesheuvel	ret	lr				@ CP#8
161*47ba5f39SArd Biesheuvel	ret	lr				@ CP#9
162*47ba5f39SArd Biesheuvel	ret	lr				@ CP#10 (VFP)
163*47ba5f39SArd Biesheuvel	ret	lr				@ CP#11 (VFP)
164*47ba5f39SArd Biesheuvel	ret	lr				@ CP#12
165*47ba5f39SArd Biesheuvel	ret	lr				@ CP#13
166*47ba5f39SArd Biesheuvel	ret	lr				@ CP#14 (Debug)
167*47ba5f39SArd Biesheuvel	ret	lr				@ CP#15 (Control)
168*47ba5f39SArd Biesheuvel
169*47ba5f39SArd Biesheuveldo_fpe:
170*47ba5f39SArd Biesheuvel	add	r10, r10, #TI_FPSTATE		@ r10 = workspace
171*47ba5f39SArd Biesheuvel	ldr_va	pc, fp_enter, tmp=r4		@ Call FP module USR entry point
172*47ba5f39SArd Biesheuvel
173*47ba5f39SArd Biesheuvel	@
174*47ba5f39SArd Biesheuvel	@ The FP module is called with these registers set:
175*47ba5f39SArd Biesheuvel	@  r0  = instruction
176*47ba5f39SArd Biesheuvel	@  r2  = PC+4
177*47ba5f39SArd Biesheuvel	@  r9  = normal "successful" return address
178*47ba5f39SArd Biesheuvel	@  r10 = FP workspace
179*47ba5f39SArd Biesheuvel	@  lr  = unrecognised FP instruction return address
180*47ba5f39SArd Biesheuvel	@
181*47ba5f39SArd Biesheuvel
182*47ba5f39SArd Biesheuvel	.pushsection .data
183*47ba5f39SArd Biesheuvel	.align	2
184*47ba5f39SArd BiesheuvelENTRY(fp_enter)
185*47ba5f39SArd Biesheuvel	.word	no_fp
186*47ba5f39SArd Biesheuvel	.popsection
187*47ba5f39SArd Biesheuvel
188*47ba5f39SArd Biesheuvelno_fp:
189*47ba5f39SArd Biesheuvel	ret	lr
190*47ba5f39SArd BiesheuvelENDPROC(no_fp)
191