powerpc: Sync icache on SIGILL, in case of cache issues

The update of jemalloc to 5.1.0 exposed a cache syncing issue on a Freescale
e500 base system.  There was already code in the FPU emulator to address
this, but it was limited to a single static variable, and did not attempt to
sync the cache.  This pulls that out to the higher level program exception
handler, and syncs the cache.

If a SIGILL is hit a second time at the same address, it will be treated as
a real illegal instruction, and handled accordingly.
This commit is contained in:
Justin Hibbits 2018-11-19 23:54:49 +00:00
parent 06cf1308e4
commit fe5e88fabf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=340653
3 changed files with 14 additions and 10 deletions

View File

@ -189,7 +189,6 @@ fpu_emulate(struct trapframe *frame, struct fpu *fpf)
{
union instr insn;
struct fpemu fe;
static int lastill = 0;
int sig;
/* initialize insn.is_datasize to tell it is *not* initialized */
@ -243,17 +242,11 @@ fpu_emulate(struct trapframe *frame, struct fpu *fpf)
opc_disasm(frame->srr0, insn.i_int);
}
#endif
/*
* XXXX retry an illegal insn once due to cache issues.
*/
if (lastill == frame->srr0) {
sig = SIGILL;
sig = SIGILL;
#ifdef DEBUG
if (fpe_debug & FPE_EX)
kdb_enter(KDB_WHY_UNSET, "illegal instruction");
if (fpe_debug & FPE_EX)
kdb_enter(KDB_WHY_UNSET, "illegal instruction");
#endif
}
lastill = frame->srr0;
break;
}

View File

@ -89,6 +89,7 @@ struct pcb {
register_t dbcr0;
} booke;
} pcb_cpu;
vm_offset_t pcb_lastill; /* Last illegal instruction */
};
#endif

View File

@ -94,6 +94,8 @@ __FBSDID("$FreeBSD$");
#include <machine/trap.h>
#include <machine/vmparam.h>
#include <vm/pmap.h>
#ifdef FPU_EMU
#include <powerpc/fpu/fpu_extern.h>
#endif
@ -1099,6 +1101,14 @@ ppc_instr_emulate(struct trapframe *frame, struct pcb *pcb)
}
sig = fpu_emulate(frame, &pcb->pcb_fpu);
#endif
if (sig == SIGILL) {
if (pcb->pcb_lastill != frame->srr0) {
/* Allow a second chance, in case of cache sync issues. */
sig = 0;
pmap_sync_icache(PCPU_GET(curpmap), frame->srr0, 4);
pcb->pcb_lastill = frame->srr0;
}
}
return (sig);
}