Commit cf9c906f authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] M68k RMW accesses

From: Geert Uytterhoeven <geert@linux-m68k.org>

M68k: Avoid bus fault for certain RMW accesses (from Roman Zippel)
parent db4f1fda
......@@ -583,12 +583,9 @@ static inline void bus_error030 (struct frame *fp)
unsigned short mmusr;
unsigned long addr, errorcode;
unsigned short ssw = fp->un.fmtb.ssw;
int user_space_fault = 1;
#if DEBUG
unsigned long desc;
#endif
#if DEBUG
printk ("pid = %x ", current->pid);
printk ("SSW=%#06x ", ssw);
......@@ -605,62 +602,29 @@ static inline void bus_error030 (struct frame *fp)
space_names[ssw & DFC], fp->ptregs.pc);
#endif
if (fp->ptregs.sr & PS_S) {
/* kernel fault must be a data fault to user space */
if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
/* instruction fault or kernel data fault! */
if (ssw & (FC | FB))
printk ("Instruction fault at %#010lx\n",
fp->ptregs.pc);
if (ssw & DF) {
printk ("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);
}
printk ("BAD KERNEL BUSERR\n");
die_if_kernel("Oops",&fp->ptregs,0);
force_sig(SIGKILL, current);
return;
}
} else {
/* user fault */
if (!(ssw & (FC | FB)) && !(ssw & DF))
/* not an instruction fault or data fault! BAD */
panic ("USER BUSERR w/o instruction or data fault");
user_space_fault = 1;
#if DEBUG
printk("User space bus-error\n");
#endif
}
/* ++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)
{
if (ssw & DF) {
addr = fp->un.fmtb.daddr;
mmusr = MMU_I;
if (user_space_fault) {
#if DEBUG
asm volatile ("ptestr #1,%2@,#7,%0\n\t"
"pmove %/psr,%1@"
asm volatile ("ptestr %3,%2@,#7,%0\n\t"
"pmove %%psr,%1@"
: "=a&" (desc)
: "a" (&temp), "a" (addr));
: "a" (&temp), "a" (addr), "d" (ssw));
#else
asm volatile ("ptestr #1,%1@,#7\n\t"
"pmove %/psr,%0@"
: : "a" (&temp), "a" (addr));
asm volatile ("ptestr %2,%1@,#7\n\t"
"pmove %%psr,%0@"
: : "a" (&temp), "a" (addr), "d" (ssw));
#endif
mmusr = temp;
}
#if DEBUG
printk ("mmusr is %#x for addr %#lx in task %p\n",
printk("mmusr is %#x for addr %#lx in task %p\n",
mmusr, addr, current);
printk ("descriptor address is %#lx, contents %#lx\n",
printk("descriptor address is %#lx, contents %#lx\n",
__va(desc), *(unsigned long *)__va(desc));
#endif
......@@ -669,12 +633,23 @@ static inline void bus_error030 (struct frame *fp)
errorcode |= 2;
if (mmusr & (MMU_I | MMU_WP)) {
if (ssw & 4) {
printk("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)) {
/* propably a 020 cas fault */
if (!(ssw & RM))
printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr);
} else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
printk ("invalid %s access at %#lx from pc %#lx\n",
printk("invalid %s access at %#lx from pc %#lx\n",
!(ssw & RW) ? "write" : "read", addr,
fp->ptregs.pc);
die_if_kernel("Oops",&fp->ptregs,mmusr);
......@@ -685,25 +660,25 @@ static inline void bus_error030 (struct frame *fp)
static volatile long tlong;
#endif
printk ("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
printk("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@"
"pmove %%psr,%0@"
: /* no outputs */
: "a" (&temp), "a" (addr));
mmusr = temp;
printk ("level 0 mmusr is %#x\n", mmusr);
#if 0
asm volatile ("pmove %/tt0,%0@"
asm volatile ("pmove %%tt0,%0@"
: /* no outputs */
: "a" (&tlong));
printk ("tt0 is %#lx, ", tlong);
asm volatile ("pmove %/tt1,%0@"
printk("tt0 is %#lx, ", tlong);
asm volatile ("pmove %%tt1,%0@"
: /* no outputs */
: "a" (&tlong));
printk ("tt1 is %#lx\n", tlong);
printk("tt1 is %#lx\n", tlong);
#endif
#if DEBUG
printk("Unknown SIGSEGV - 1\n");
......@@ -714,7 +689,7 @@ static inline void bus_error030 (struct frame *fp)
}
/* setup an ATC entry for the access about to be retried */
if (!(ssw & RW))
if (!(ssw & RW) || (ssw & RM))
asm volatile ("ploadw %1,%0@" : /* no outputs */
: "a" (addr), "d" (ssw));
else
......@@ -727,6 +702,16 @@ static inline void bus_error030 (struct frame *fp)
if (!(ssw & (FC|FB)))
return;
if (fp->ptregs.sr & PS_S) {
printk("Instruction fault at %#010lx\n",
fp->ptregs.pc);
buserr:
printk ("BAD KERNEL BUSERR\n");
die_if_kernel("Oops",&fp->ptregs,0);
force_sig(SIGKILL, current);
return;
}
/* get the fault address */
if (fp->ptregs.format == 10)
addr = fp->ptregs.pc + 4;
......@@ -740,20 +725,17 @@ static inline void bus_error030 (struct frame *fp)
should still create the ATC entry. */
goto create_atc_entry;
mmusr = MMU_I;
if (user_space_fault) {
#if DEBUG
asm volatile ("ptestr #1,%2@,#7,%0\n\t"
"pmove %/psr,%1@"
"pmove %%psr,%1@"
: "=a&" (desc)
: "a" (&temp), "a" (addr));
#else
asm volatile ("ptestr #1,%1@,#7\n\t"
"pmove %/psr,%0@"
"pmove %%psr,%0@"
: : "a" (&temp), "a" (addr));
#endif
mmusr = temp;
}
#ifdef DEBUG
printk ("mmusr is %#x for addr %#lx in task %p\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment