diff options
Diffstat (limited to 'arch/arm26/nwfpe/entry.S')
-rw-r--r-- | arch/arm26/nwfpe/entry.S | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/arch/arm26/nwfpe/entry.S b/arch/arm26/nwfpe/entry.S new file mode 100644 index 000000000000..7d6dfaad80c2 --- /dev/null +++ b/arch/arm26/nwfpe/entry.S | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | NetWinder Floating Point Emulator | ||
3 | (c) Rebel.COM, 1998 | ||
4 | (c) Philip Blundell 1998-1999 | ||
5 | |||
6 | Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <asm/asm_offsets.h> | ||
24 | |||
25 | /* This is the kernel's entry point into the floating point emulator. | ||
26 | It is called from the kernel with code similar to this: | ||
27 | |||
28 | mov fp, #0 | ||
29 | teqp pc, #PSR_I_BIT | MODE_SVC | ||
30 | ldr r4, .LC2 | ||
31 | ldr pc, [r4] @ Call FP module USR entry point | ||
32 | |||
33 | The kernel expects the emulator to return via one of two possible | ||
34 | points of return it passes to the emulator. The emulator, if | ||
35 | successful in its emulation, jumps to ret_from_exception and the | ||
36 | kernel takes care of returning control from the trap to the user code. | ||
37 | If the emulator is unable to emulate the instruction, it returns to | ||
38 | fpundefinstr and the kernel halts the user program with a core dump. | ||
39 | |||
40 | This routine does four things: | ||
41 | |||
42 | 1) It saves SP into a variable called userRegisters. The kernel has | ||
43 | created a struct pt_regs on the stack and saved the user registers | ||
44 | into it. See /usr/include/asm/proc/ptrace.h for details. The | ||
45 | emulator code uses userRegisters as the base of an array of words from | ||
46 | which the contents of the registers can be extracted. | ||
47 | |||
48 | 2) It locates the FP emulator work area within the TSS structure and | ||
49 | points `fpa11' to it. | ||
50 | |||
51 | 3) It calls EmulateAll to emulate a floating point instruction. | ||
52 | EmulateAll returns 1 if the emulation was successful, or 0 if not. | ||
53 | |||
54 | 4) If an instruction has been emulated successfully, it looks ahead at | ||
55 | the next instruction. If it is a floating point instruction, it | ||
56 | executes the instruction, without returning to user space. In this | ||
57 | way it repeatedly looks ahead and executes floating point instructions | ||
58 | until it encounters a non floating point instruction, at which time it | ||
59 | returns via _fpreturn. | ||
60 | |||
61 | This is done to reduce the effect of the trap overhead on each | ||
62 | floating point instructions. GCC attempts to group floating point | ||
63 | instructions to allow the emulator to spread the cost of the trap over | ||
64 | several floating point instructions. */ | ||
65 | |||
66 | .globl nwfpe_enter | ||
67 | nwfpe_enter: | ||
68 | mov sl, sp | ||
69 | bl FPA11_CheckInit @ check to see if we are initialised | ||
70 | |||
71 | ldr r5, [sp, #60] @ get contents of PC | ||
72 | bic r5, r5, #0xfc000003 | ||
73 | ldr r0, [r5, #-4] @ get actual instruction into r0 | ||
74 | bl EmulateAll @ emulate the instruction | ||
75 | 1: cmp r0, #0 @ was emulation successful | ||
76 | beq fpundefinstr @ no, return failure | ||
77 | |||
78 | next: | ||
79 | .Lx1: ldrt r6, [r5], #4 @ get the next instruction and | ||
80 | @ increment PC | ||
81 | |||
82 | and r2, r6, #0x0F000000 @ test for FP insns | ||
83 | teq r2, #0x0C000000 | ||
84 | teqne r2, #0x0D000000 | ||
85 | teqne r2, #0x0E000000 | ||
86 | bne ret_from_exception @ return ok if not a fp insn | ||
87 | |||
88 | ldr r9, [sp, #60] @ get new condition codes | ||
89 | and r9, r9, #0xfc000003 | ||
90 | orr r7, r5, r9 | ||
91 | str r7, [sp, #60] @ update PC copy in regs | ||
92 | |||
93 | mov r0, r6 @ save a copy | ||
94 | mov r1, r9 @ fetch the condition codes | ||
95 | bl checkCondition @ check the condition | ||
96 | cmp r0, #0 @ r0 = 0 ==> condition failed | ||
97 | |||
98 | @ if condition code failed to match, next insn | ||
99 | beq next @ get the next instruction; | ||
100 | |||
101 | mov r0, r6 @ prepare for EmulateAll() | ||
102 | adr lr, 1b | ||
103 | orr lr, lr, #3 | ||
104 | b EmulateAll @ if r0 != 0, goto EmulateAll | ||
105 | |||
106 | .Lret: b ret_from_exception @ let the user eat segfaults | ||
107 | |||
108 | @ We need to be prepared for the instruction at .Lx1 to fault. | ||
109 | @ Emit the appropriate exception gunk to fix things up. | ||
110 | .section __ex_table,"a" | ||
111 | .align 3 | ||
112 | .long .Lx1 | ||
113 | ldr lr, [lr, $(.Lret - .Lx1)/4] | ||
114 | .previous | ||