void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) { u32 fpscr, orig_fpscr, fpsid, exceptions; pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); atomic64_inc(&vfp_bounce_count); fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_DEX|FPEXC_FP2V|FPEXC_VV|FPEXC_TRAP_MASK)); fpsid = fmrx(FPSID); orig_fpscr = fpscr = fmrx(FPSCR); if ((fpsid & FPSID_ARCH_MASK) == (1 << FPSID_ARCH_BIT) && (fpscr & FPSCR_IXE)) { goto emulate; } if (fpexc & FPEXC_EX) { #ifndef CONFIG_CPU_FEROCEON trigger = fmrx(FPINST); regs->ARM_pc -= 4; #endif } else if (!(fpexc & FPEXC_DEX)) { vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs); goto exit; } if (fpexc & (FPEXC_EX | FPEXC_VV)) { u32 len; len = fpexc + (1 << FPEXC_LENGTH_BIT); fpscr &= ~FPSCR_LENGTH_MASK; fpscr |= (len & FPEXC_LENGTH_MASK) << (FPSCR_LENGTH_BIT - FPEXC_LENGTH_BIT); } exceptions = vfp_emulate_instruction(trigger, fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); /* * If there isn't a second FP instruction, exit now. Note that * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1. */ if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V)) goto exit; barrier(); trigger = fmrx(FPINST2); emulate: exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); exit: preempt_enable(); }
unsigned VFPCDP (ARMul_State * state, unsigned type, ARMword instr) { /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ int CoProc = BITS (8, 11); /* 10 or 11 */ int OPC_1 = BITS (20, 23); int CRd = BITS (12, 15); int CRn = BITS (16, 19); int CRm = BITS (0, 3); int OPC_2 = BITS (5, 7); /* TODO check access permission */ /* CRn/opc1 CRm/opc2 */ if (CoProc == 10 || CoProc == 11) { #define VFP_CDP_TRANS #include "core/arm/interpreter/vfp/vfpinstr.cpp" #undef VFP_CDP_TRANS int exceptions = 0; if (CoProc == 10) exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); else exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); return ARMul_DONE; } DEBUG_LOG(ARM11, "Can't identify %x\n", instr); return ARMul_CANT; }
/* * Package up a bounce condition. */ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) { u32 fpscr, orig_fpscr, fpsid, exceptions; pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); /* * At this point, FPEXC can have the following configuration: * * EX DEX IXE * 0 1 x - synchronous exception * 1 x 0 - asynchronous exception * 1 x 1 - sychronous on VFP subarch 1 and asynchronous on later * 0 0 1 - synchronous on VFP9 (non-standard subarch 1 * implementation), undefined otherwise * * Clear various bits and enable access to the VFP so we can * handle the bounce. */ fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_DEX|FPEXC_FP2V|FPEXC_VV|FPEXC_TRAP_MASK)); fpsid = fmrx(FPSID); orig_fpscr = fpscr = fmrx(FPSCR); /* * Check for the special VFP subarch 1 and FPSCR.IXE bit case */ if ((fpsid & FPSID_ARCH_MASK) == (1 << FPSID_ARCH_BIT) && (fpscr & FPSCR_IXE)) { /* * Synchronous exception, emulate the trigger instruction */ goto emulate; } if (fpexc & FPEXC_EX) { #ifndef CONFIG_CPU_FEROCEON /* * Asynchronous exception. The instruction is read from FPINST * and the interrupted instruction has to be restarted. */ trigger = fmrx(FPINST); regs->ARM_pc -= 4; #endif } else if (!(fpexc & FPEXC_DEX)) { /* * Illegal combination of bits. It can be caused by an * unallocated VFP instruction but with FPSCR.IXE set and not * on VFP subarch 1. */ vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs); goto exit; } /* * Modify fpscr to indicate the number of iterations remaining. * If FPEXC.EX is 0, FPEXC.DEX is 1 and the FPEXC.VV bit indicates * whether FPEXC.VECITR or FPSCR.LEN is used. */ if (fpexc & (FPEXC_EX | FPEXC_VV)) { u32 len; len = fpexc + (1 << FPEXC_LENGTH_BIT); fpscr &= ~FPSCR_LENGTH_MASK; fpscr |= (len & FPEXC_LENGTH_MASK) << (FPSCR_LENGTH_BIT - FPEXC_LENGTH_BIT); } /* * Handle the first FP instruction. We used to take note of the * FPEXC bounce reason, but this appears to be unreliable. * Emulate the bounced instruction instead. */ exceptions = vfp_emulate_instruction(trigger, fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); /* * If there isn't a second FP instruction, exit now. Note that * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1. */ if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V)) goto exit; /* * The barrier() here prevents fpinst2 being read * before the condition above. */ barrier(); trigger = fmrx(FPINST2); emulate: exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); exit: preempt_enable(); }
/* * Package up a bounce condition. */ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) { u32 fpscr, orig_fpscr, exceptions, inst; pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); /* * Enable access to the VFP so we can handle the bounce. */ fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_INV|FPEXC_UFC|FPEXC_IOC)); orig_fpscr = fpscr = fmrx(FPSCR); /* * If we are running with inexact exceptions enabled, we need to * emulate the trigger instruction. Note that as we're emulating * the trigger instruction, we need to increment PC. */ if (fpscr & FPSCR_IXE) { regs->ARM_pc += 4; goto emulate; } barrier(); /* * Modify fpscr to indicate the number of iterations remaining */ if (fpexc & FPEXC_EX) { u32 len; len = fpexc + (1 << FPEXC_LENGTH_BIT); fpscr &= ~FPSCR_LENGTH_MASK; fpscr |= (len & FPEXC_LENGTH_MASK) << (FPSCR_LENGTH_BIT - FPEXC_LENGTH_BIT); } /* * Handle the first FP instruction. We used to take note of the * FPEXC bounce reason, but this appears to be unreliable. * Emulate the bounced instruction instead. */ #ifndef CONFIG_VFPv3 inst = fmrx(FPINST); #else inst = trigger; #endif exceptions = vfp_emulate_instruction(inst, fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, inst, orig_fpscr, regs); #ifndef CONFIG_VFPv3 /* * If there isn't a second FP instruction, exit now. */ if (!(fpexc & FPEXC_FPV2)) return; /* * The barrier() here prevents fpinst2 being read * before the condition above. */ barrier(); trigger = fmrx(FPINST2); orig_fpscr = fpscr = fmrx(FPSCR); #else return; #endif emulate: exceptions = vfp_emulate_instruction(trigger, fpscr, regs); if (exceptions) vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); }