Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003     NetWinder Floating Point Emulator
0004     (c) Rebel.COM, 1998
0005     (c) 1998, 1999 Philip Blundell
0006 
0007     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
0008 
0009 */
0010 #include <asm/assembler.h>
0011 #include <asm/opcodes.h>
0012 
0013 /* This is the kernel's entry point into the floating point emulator.
0014 It is called from the kernel with code similar to this:
0015 
0016     sub r4, r5, #4
0017     ldrt    r0, [r4]            @ r0  = instruction
0018     adrsvc  al, r9, ret_from_exception  @ r9  = normal FP return
0019     adrsvc  al, lr, fpundefinstr        @ lr  = undefined instr return
0020 
0021     get_current_task r10
0022     mov r8, #1
0023     strb    r8, [r10, #TSK_USED_MATH]   @ set current->used_math
0024     add r10, r10, #TSS_FPESAVE      @ r10 = workspace
0025     ldr r4, .LC2
0026     ldr pc, [r4]            @ Call FP emulator entry point
0027 
0028 The kernel expects the emulator to return via one of two possible
0029 points of return it passes to the emulator.  The emulator, if
0030 successful in its emulation, jumps to ret_from_exception (passed in
0031 r9) and the kernel takes care of returning control from the trap to
0032 the user code.  If the emulator is unable to emulate the instruction,
0033 it returns via _fpundefinstr (passed via lr) and the kernel halts the
0034 user program with a core dump.
0035 
0036 On entry to the emulator r10 points to an area of private FP workspace
0037 reserved in the thread structure for this process.  This is where the
0038 emulator saves its registers across calls.  The first word of this area
0039 is used as a flag to detect the first time a process uses floating point,
0040 so that the emulator startup cost can be avoided for tasks that don't
0041 want it.
0042 
0043 This routine does three things:
0044 
0045 1) The kernel has created a struct pt_regs on the stack and saved the
0046 user registers into it.  See /usr/include/asm/proc/ptrace.h for details.
0047 
0048 2) It calls EmulateAll to emulate a floating point instruction.
0049 EmulateAll returns 1 if the emulation was successful, or 0 if not.
0050 
0051 3) If an instruction has been emulated successfully, it looks ahead at
0052 the next instruction.  If it is a floating point instruction, it
0053 executes the instruction, without returning to user space.  In this
0054 way it repeatedly looks ahead and executes floating point instructions
0055 until it encounters a non floating point instruction, at which time it
0056 returns via _fpreturn.
0057 
0058 This is done to reduce the effect of the trap overhead on each
0059 floating point instructions.  GCC attempts to group floating point
0060 instructions to allow the emulator to spread the cost of the trap over
0061 several floating point instructions.  */
0062 
0063 #include <asm/asm-offsets.h>
0064 
0065     .globl  nwfpe_enter
0066 nwfpe_enter:
0067     mov r4, lr          @ save the failure-return addresses
0068     mov sl, sp          @ we access the registers via 'sl'
0069 
0070     ldr r5, [sp, #S_PC]     @ get contents of PC;
0071     mov r6, r0          @ save the opcode
0072 emulate:
0073     ldr r1, [sp, #S_PSR]    @ fetch the PSR
0074     bl  arm_check_condition @ check the condition
0075     cmp r0, #ARM_OPCODE_CONDTEST_PASS   @ condition passed?
0076 
0077     @ if condition code failed to match, next insn
0078     bne next            @ get the next instruction;
0079 
0080     mov r0, r6          @ prepare for EmulateAll()
0081     bl  EmulateAll      @ emulate the instruction
0082     cmp r0, #0          @ was emulation successful
0083     reteq   r4          @ no, return failure
0084 
0085 next:
0086     uaccess_enable r3
0087 .Lx1:   ldrt    r6, [r5], #4        @ get the next instruction and
0088                     @ increment PC
0089     uaccess_disable r3
0090     and r2, r6, #0x0F000000 @ test for FP insns
0091     teq r2, #0x0C000000
0092     teqne   r2, #0x0D000000
0093     teqne   r2, #0x0E000000
0094     retne   r9          @ return ok if not a fp insn
0095 
0096     str r5, [sp, #S_PC]     @ update PC copy in regs
0097 
0098     mov r0, r6          @ save a copy
0099     b   emulate         @ check condition and emulate
0100 
0101     @ We need to be prepared for the instructions at .Lx1 and .Lx2 
0102     @ to fault.  Emit the appropriate exception gunk to fix things up.
0103     @ ??? For some reason, faults can happen at .Lx2 even with a
0104     @ plain LDR instruction.  Weird, but it seems harmless.
0105     .pushsection .text.fixup,"ax"
0106     .align  2
0107 .Lfix:  ret r9          @ let the user eat segfaults
0108     .popsection
0109 
0110     .pushsection __ex_table,"a"
0111     .align  3
0112     .long   .Lx1, .Lfix
0113     .popsection