in kernel/traps.c [495:665]
static inline void bus_error030 (struct frame *fp)
{
volatile unsigned short temp;
unsigned short mmusr;
unsigned long addr, errorcode;
unsigned short ssw = fp->un.fmtb.ssw;
#ifdef DEBUG
unsigned long desc;
#endif
pr_debug("pid = %x ", current->pid);
pr_debug("SSW=%#06x ", ssw);
if (ssw & (FC | FB))
pr_debug("Instruction fault at %#010lx\n",
ssw & FC ?
fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
:
fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
if (ssw & DF)
pr_debug("Data %s fault at %#010lx in %s (pc=%#lx)\n",
ssw & RW ? "read" : "write",
fp->un.fmtb.daddr,
space_names[ssw & DFC], fp->ptregs.pc);
/* ++andreas: If a data fault and an instruction fault happen
at the same time map in both pages. */
/* First handle the data fault, if any. */
if (ssw & DF) {
addr = fp->un.fmtb.daddr;
#ifdef DEBUG
asm volatile ("ptestr %3,%2@,#7,%0\n\t"
"pmove %%psr,%1"
: "=a&" (desc), "=m" (temp)
: "a" (addr), "d" (ssw));
pr_debug("mmusr is %#x for addr %#lx in task %p\n",
temp, addr, current);
pr_debug("descriptor address is 0x%p, contents %#lx\n",
__va(desc), *(unsigned long *)__va(desc));
#else
asm volatile ("ptestr %2,%1@,#7\n\t"
"pmove %%psr,%0"
: "=m" (temp) : "a" (addr), "d" (ssw));
#endif
mmusr = temp;
errorcode = (mmusr & MMU_I) ? 0 : 1;
if (!(ssw & RW) || (ssw & RM))
errorcode |= 2;
if (mmusr & (MMU_I | MMU_WP)) {
if (ssw & 4) {
pr_err("Data %s fault at %#010lx in %s (pc=%#lx)\n",
ssw & RW ? "read" : "write",
fp->un.fmtb.daddr,
space_names[ssw & DFC], fp->ptregs.pc);
goto buserr;
}
/* Don't try to do anything further if an exception was
handled. */
if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
return;
} else if (!(mmusr & MMU_I)) {
/* probably a 020 cas fault */
if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0)
pr_err("unexpected bus error (%#x,%#x)\n", ssw,
mmusr);
} else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
pr_err("invalid %s access at %#lx from pc %#lx\n",
!(ssw & RW) ? "write" : "read", addr,
fp->ptregs.pc);
die_if_kernel("Oops",&fp->ptregs,mmusr);
force_sig(SIGSEGV);
return;
} else {
#if 0
static volatile long tlong;
#endif
pr_err("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
!(ssw & RW) ? "write" : "read", addr,
fp->ptregs.pc, ssw);
asm volatile ("ptestr #1,%1@,#0\n\t"
"pmove %%psr,%0"
: "=m" (temp)
: "a" (addr));
mmusr = temp;
pr_err("level 0 mmusr is %#x\n", mmusr);
#if 0
asm volatile ("pmove %%tt0,%0"
: "=m" (tlong));
pr_debug("tt0 is %#lx, ", tlong);
asm volatile ("pmove %%tt1,%0"
: "=m" (tlong));
pr_debug("tt1 is %#lx\n", tlong);
#endif
pr_debug("Unknown SIGSEGV - 1\n");
die_if_kernel("Oops",&fp->ptregs,mmusr);
force_sig(SIGSEGV);
return;
}
/* setup an ATC entry for the access about to be retried */
if (!(ssw & RW) || (ssw & RM))
asm volatile ("ploadw %1,%0@" : /* no outputs */
: "a" (addr), "d" (ssw));
else
asm volatile ("ploadr %1,%0@" : /* no outputs */
: "a" (addr), "d" (ssw));
}
/* Now handle the instruction fault. */
if (!(ssw & (FC|FB)))
return;
if (fp->ptregs.sr & PS_S) {
pr_err("Instruction fault at %#010lx\n", fp->ptregs.pc);
buserr:
pr_err("BAD KERNEL BUSERR\n");
die_if_kernel("Oops",&fp->ptregs,0);
force_sig(SIGKILL);
return;
}
/* get the fault address */
if (fp->ptregs.format == 10)
addr = fp->ptregs.pc + 4;
else
addr = fp->un.fmtb.baddr;
if (ssw & FC)
addr -= 2;
if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
/* Insn fault on same page as data fault. But we
should still create the ATC entry. */
goto create_atc_entry;
#ifdef DEBUG
asm volatile ("ptestr #1,%2@,#7,%0\n\t"
"pmove %%psr,%1"
: "=a&" (desc), "=m" (temp)
: "a" (addr));
pr_debug("mmusr is %#x for addr %#lx in task %p\n",
temp, addr, current);
pr_debug("descriptor address is 0x%p, contents %#lx\n",
__va(desc), *(unsigned long *)__va(desc));
#else
asm volatile ("ptestr #1,%1@,#7\n\t"
"pmove %%psr,%0"
: "=m" (temp) : "a" (addr));
#endif
mmusr = temp;
if (mmusr & MMU_I)
do_page_fault (&fp->ptregs, addr, 0);
else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
pr_err("invalid insn access at %#lx from pc %#lx\n",
addr, fp->ptregs.pc);
pr_debug("Unknown SIGSEGV - 2\n");
die_if_kernel("Oops",&fp->ptregs,mmusr);
force_sig(SIGSEGV);
return;
}
create_atc_entry:
/* setup an ATC entry for the access about to be retried */
asm volatile ("ploadr #2,%0@" : /* no outputs */
: "a" (addr));
}