^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0-or-later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) NetWinder Floating Point Emulator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) (c) Rebel.COM, 1998
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) (c) 1998, 1999 Philip Blundell
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/assembler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/opcodes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /* This is the kernel's entry point into the floating point emulator.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) It is called from the kernel with code similar to this:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) sub r4, r5, #4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) ldrt r0, [r4] @ r0 = instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) adrsvc al, r9, ret_from_exception @ r9 = normal FP return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) adrsvc al, lr, fpundefinstr @ lr = undefined instr return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) get_current_task r10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) mov r8, #1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) strb r8, [r10, #TSK_USED_MATH] @ set current->used_math
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) add r10, r10, #TSS_FPESAVE @ r10 = workspace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) ldr r4, .LC2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) ldr pc, [r4] @ Call FP emulator entry point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) The kernel expects the emulator to return via one of two possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) points of return it passes to the emulator. The emulator, if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) successful in its emulation, jumps to ret_from_exception (passed in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) r9) and the kernel takes care of returning control from the trap to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) the user code. If the emulator is unable to emulate the instruction,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) it returns via _fpundefinstr (passed via lr) and the kernel halts the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) user program with a core dump.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) On entry to the emulator r10 points to an area of private FP workspace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) reserved in the thread structure for this process. This is where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) emulator saves its registers across calls. The first word of this area
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) is used as a flag to detect the first time a process uses floating point,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) so that the emulator startup cost can be avoided for tasks that don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) want it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) This routine does three things:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) 1) The kernel has created a struct pt_regs on the stack and saved the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) user registers into it. See /usr/include/asm/proc/ptrace.h for details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) 2) It calls EmulateAll to emulate a floating point instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) EmulateAll returns 1 if the emulation was successful, or 0 if not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) 3) If an instruction has been emulated successfully, it looks ahead at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) the next instruction. If it is a floating point instruction, it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) executes the instruction, without returning to user space. In this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) way it repeatedly looks ahead and executes floating point instructions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) until it encounters a non floating point instruction, at which time it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) returns via _fpreturn.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) This is done to reduce the effect of the trap overhead on each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) floating point instructions. GCC attempts to group floating point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) instructions to allow the emulator to spread the cost of the trap over
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) several floating point instructions. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #include <asm/asm-offsets.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .globl nwfpe_enter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) nwfpe_enter:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) mov r4, lr @ save the failure-return addresses
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) mov sl, sp @ we access the registers via 'sl'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ldr r5, [sp, #S_PC] @ get contents of PC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) mov r6, r0 @ save the opcode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) emulate:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ldr r1, [sp, #S_PSR] @ fetch the PSR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) bl arm_check_condition @ check the condition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) cmp r0, #ARM_OPCODE_CONDTEST_PASS @ condition passed?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) @ if condition code failed to match, next insn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) bne next @ get the next instruction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) mov r0, r6 @ prepare for EmulateAll()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) bl EmulateAll @ emulate the instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) cmp r0, #0 @ was emulation successful
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) reteq r4 @ no, return failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) next:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) uaccess_enable r3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .Lx1: ldrt r6, [r5], #4 @ get the next instruction and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) @ increment PC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) uaccess_disable r3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) and r2, r6, #0x0F000000 @ test for FP insns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) teq r2, #0x0C000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) teqne r2, #0x0D000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) teqne r2, #0x0E000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) retne r9 @ return ok if not a fp insn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) str r5, [sp, #S_PC] @ update PC copy in regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) mov r0, r6 @ save a copy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) b emulate @ check condition and emulate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) @ We need to be prepared for the instructions at .Lx1 and .Lx2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) @ to fault. Emit the appropriate exception gunk to fix things up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) @ ??? For some reason, faults can happen at .Lx2 even with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) @ plain LDR instruction. Weird, but it seems harmless.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .pushsection .text.fixup,"ax"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .align 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .Lfix: ret r9 @ let the user eat segfaults
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .popsection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .pushsection __ex_table,"a"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .align 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .long .Lx1, .Lfix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .popsection