Date: Sat, 29 Mar 2014 14:35:36 +0000 (UTC) From: Andrew Turner <andrew@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r263914 - in head/sys/arm: arm include Message-ID: <201403291435.s2TEZaPR017640@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: andrew Date: Sat Mar 29 14:35:36 2014 New Revision: 263914 URL: http://svnweb.freebsd.org/changeset/base/263914 Log: VFP fixes/cleanups for ARM11: * Save the required VFP registers on context switch. If the exception bit is set we need to save and restore the FPINST register, and if the fp2v bit is also set we need to save and restore FPINST2. * Move saving and restoring the floating point control registers to C. * Clear the fpexc exception and fp2v flags on a floating-point exception. * Signal a SIGFPE if the fpexc exception flag is set on an undefined instruction. This is how the ARM core signals to software there is a floating-point exception. Modified: head/sys/arm/arm/vfp.c head/sys/arm/include/fp.h Modified: head/sys/arm/arm/vfp.c ============================================================================== --- head/sys/arm/arm/vfp.c Sat Mar 29 14:17:04 2014 (r263913) +++ head/sys/arm/arm/vfp.c Sat Mar 29 14:35:36 2014 (r263914) @@ -149,6 +149,7 @@ vfp_bounce(u_int addr, u_int insn, struc { u_int cpu, fpexc; struct pcb *curpcb; + ksiginfo_t ksi; if ((code & FAULT_USER) == 0) panic("undefined floating point instruction in supervisor mode"); @@ -162,9 +163,27 @@ vfp_bounce(u_int addr, u_int insn, struc */ fpexc = fmrx(VFPEXC); if (fpexc & VFPEXC_EN) { + /* Clear any exceptions */ + fmxr(VFPEXC, fpexc & ~(VFPEXC_EX | VFPEXC_FP2V)); + /* kill the process - we do not handle emulation */ critical_exit(); - killproc(curthread->td_proc, "vfp emulation"); + + if (fpexc & VFPEXC_EX) { + /* We have an exception, signal a SIGFPE */ + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = SIGFPE; + if (fpexc & VFPEXC_UFC) + ksi.ksi_code = FPE_FLTUND; + else if (fpexc & VFPEXC_OFC) + ksi.ksi_code = FPE_FLTOVF; + else if (fpexc & VFPEXC_IOC) + ksi.ksi_code = FPE_FLTINV; + ksi.ksi_addr = (void *)addr; + trapsignal(curthread, &ksi); + return 0; + } + return 1; } @@ -192,15 +211,24 @@ vfp_bounce(u_int addr, u_int insn, struc static void vfp_restore(struct vfp_state *vfpsave) { - u_int vfpscr = 0; + uint32_t fpexc; + + /* On VFPv2 we may need to restore FPINST and FPINST2 */ + fpexc = vfpsave->fpexec; + if (fpexc & VFPEXC_EX) { + fmxr(VFPINST, vfpsave->fpinst); + if (fpexc & VFPEXC_FP2V) + fmxr(VFPINST2, vfpsave->fpinst2); + } + fmxr(VFPSCR, vfpsave->fpscr); - __asm __volatile("ldc p10, c0, [%1], #128\n" /* d0-d15 */ - "cmp %2, #0\n" /* -D16 or -D32? */ - LDCLNE "p11, c0, [%1], #128\n" /* d16-d31 */ - "addeq %1, %1, #128\n" /* skip missing regs */ - "ldr %0, [%1]\n" /* set old vfpscr */ - "mcr p10, 7, %0, cr1, c0, 0\n" - : "=&r" (vfpscr) : "r" (vfpsave), "r" (is_d32) : "cc"); + __asm __volatile("ldc p10, c0, [%0], #128\n" /* d0-d15 */ + "cmp %1, #0\n" /* -D16 or -D32? */ + LDCLNE "p11, c0, [%0], #128\n" /* d16-d31 */ + "addeq %0, %0, #128\n" /* skip missing regs */ + : : "r" (vfpsave), "r" (is_d32) : "cc"); + + fmxr(VFPEXC, fpexc); } /* @@ -211,20 +239,30 @@ vfp_restore(struct vfp_state *vfpsave) void vfp_store(struct vfp_state *vfpsave, boolean_t disable_vfp) { - u_int tmp, vfpscr; + uint32_t fpexc; + + fpexc = fmrx(VFPEXC); /* Is the vfp enabled? */ + if (fpexc & VFPEXC_EN) { + vfpsave->fpexec = fpexc; + vfpsave->fpscr = fmrx(VFPSCR); + + /* On VFPv2 we may need to save FPINST and FPINST2 */ + if (fpexc & VFPEXC_EX) { + vfpsave->fpinst = fmrx(VFPINST); + if (fpexc & VFPEXC_FP2V) + vfpsave->fpinst2 = fmrx(VFPINST2); + fpexc &= ~VFPEXC_EX; + } - tmp = fmrx(VFPEXC); /* Is the vfp enabled? */ - if (tmp & VFPEXC_EN) { __asm __volatile( - "stc p11, c0, [%1], #128\n" /* d0-d15 */ - "cmp %2, #0\n" /* -D16 or -D32? */ - STCLNE "p11, c0, [%1], #128\n" /* d16-d31 */ - "addeq %1, %1, #128\n" /* skip missing regs */ - "mrc p10, 7, %0, cr1, c0, 0\n" /* fmxr(VFPSCR) */ - "str %0, [%1]\n" /* save vfpscr */ - : "=&r" (vfpscr) : "r" (vfpsave), "r" (is_d32) : "cc"); + "stc p11, c0, [%0], #128\n" /* d0-d15 */ + "cmp %1, #0\n" /* -D16 or -D32? */ + STCLNE "p11, c0, [%0], #128\n" /* d16-d31 */ + "addeq %0, %0, #128\n" /* skip missing regs */ + : : "r" (vfpsave), "r" (is_d32) : "cc"); + if (disable_vfp) - fmxr(VFPEXC , tmp & ~VFPEXC_EN); + fmxr(VFPEXC , fpexc & ~VFPEXC_EN); } } Modified: head/sys/arm/include/fp.h ============================================================================== --- head/sys/arm/include/fp.h Sat Mar 29 14:17:04 2014 (r263913) +++ head/sys/arm/include/fp.h Sat Mar 29 14:35:36 2014 (r263914) @@ -69,6 +69,9 @@ typedef struct fp_extended_precision fp_ struct vfp_state { u_int64_t reg[32]; u_int32_t fpscr; + u_int32_t fpexec; + u_int32_t fpinst; + u_int32_t fpinst2; }; /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201403291435.s2TEZaPR017640>