mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-20 11:11:24 +00:00
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.
This commit is contained in:
parent
2819cfdf3f
commit
d4f9011c2e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=263914
@ -149,6 +149,7 @@ vfp_bounce(u_int addr, u_int insn, struct trapframe *frame, int code)
|
|||||||
{
|
{
|
||||||
u_int cpu, fpexc;
|
u_int cpu, fpexc;
|
||||||
struct pcb *curpcb;
|
struct pcb *curpcb;
|
||||||
|
ksiginfo_t ksi;
|
||||||
|
|
||||||
if ((code & FAULT_USER) == 0)
|
if ((code & FAULT_USER) == 0)
|
||||||
panic("undefined floating point instruction in supervisor mode");
|
panic("undefined floating point instruction in supervisor mode");
|
||||||
@ -162,9 +163,27 @@ vfp_bounce(u_int addr, u_int insn, struct trapframe *frame, int code)
|
|||||||
*/
|
*/
|
||||||
fpexc = fmrx(VFPEXC);
|
fpexc = fmrx(VFPEXC);
|
||||||
if (fpexc & VFPEXC_EN) {
|
if (fpexc & VFPEXC_EN) {
|
||||||
|
/* Clear any exceptions */
|
||||||
|
fmxr(VFPEXC, fpexc & ~(VFPEXC_EX | VFPEXC_FP2V));
|
||||||
|
|
||||||
/* kill the process - we do not handle emulation */
|
/* kill the process - we do not handle emulation */
|
||||||
critical_exit();
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,15 +211,24 @@ vfp_bounce(u_int addr, u_int insn, struct trapframe *frame, int code)
|
|||||||
static void
|
static void
|
||||||
vfp_restore(struct vfp_state *vfpsave)
|
vfp_restore(struct vfp_state *vfpsave)
|
||||||
{
|
{
|
||||||
u_int vfpscr = 0;
|
uint32_t fpexc;
|
||||||
|
|
||||||
__asm __volatile("ldc p10, c0, [%1], #128\n" /* d0-d15 */
|
/* On VFPv2 we may need to restore FPINST and FPINST2 */
|
||||||
"cmp %2, #0\n" /* -D16 or -D32? */
|
fpexc = vfpsave->fpexec;
|
||||||
LDCLNE "p11, c0, [%1], #128\n" /* d16-d31 */
|
if (fpexc & VFPEXC_EX) {
|
||||||
"addeq %1, %1, #128\n" /* skip missing regs */
|
fmxr(VFPINST, vfpsave->fpinst);
|
||||||
"ldr %0, [%1]\n" /* set old vfpscr */
|
if (fpexc & VFPEXC_FP2V)
|
||||||
"mcr p10, 7, %0, cr1, c0, 0\n"
|
fmxr(VFPINST2, vfpsave->fpinst2);
|
||||||
: "=&r" (vfpscr) : "r" (vfpsave), "r" (is_d32) : "cc");
|
}
|
||||||
|
fmxr(VFPSCR, vfpsave->fpscr);
|
||||||
|
|
||||||
|
__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
|
void
|
||||||
vfp_store(struct vfp_state *vfpsave, boolean_t disable_vfp)
|
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(
|
__asm __volatile(
|
||||||
"stc p11, c0, [%1], #128\n" /* d0-d15 */
|
"stc p11, c0, [%0], #128\n" /* d0-d15 */
|
||||||
"cmp %2, #0\n" /* -D16 or -D32? */
|
"cmp %1, #0\n" /* -D16 or -D32? */
|
||||||
STCLNE "p11, c0, [%1], #128\n" /* d16-d31 */
|
STCLNE "p11, c0, [%0], #128\n" /* d16-d31 */
|
||||||
"addeq %1, %1, #128\n" /* skip missing regs */
|
"addeq %0, %0, #128\n" /* skip missing regs */
|
||||||
"mrc p10, 7, %0, cr1, c0, 0\n" /* fmxr(VFPSCR) */
|
: : "r" (vfpsave), "r" (is_d32) : "cc");
|
||||||
"str %0, [%1]\n" /* save vfpscr */
|
|
||||||
: "=&r" (vfpscr) : "r" (vfpsave), "r" (is_d32) : "cc");
|
|
||||||
if (disable_vfp)
|
if (disable_vfp)
|
||||||
fmxr(VFPEXC , tmp & ~VFPEXC_EN);
|
fmxr(VFPEXC , fpexc & ~VFPEXC_EN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,9 @@ typedef struct fp_extended_precision fp_reg_t;
|
|||||||
struct vfp_state {
|
struct vfp_state {
|
||||||
u_int64_t reg[32];
|
u_int64_t reg[32];
|
||||||
u_int32_t fpscr;
|
u_int32_t fpscr;
|
||||||
|
u_int32_t fpexec;
|
||||||
|
u_int32_t fpinst;
|
||||||
|
u_int32_t fpinst2;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user