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) ...@@ -583,12 +583,9 @@ static inline void bus_error030 (struct frame *fp)
unsigned short mmusr; unsigned short mmusr;
unsigned long addr, errorcode; unsigned long addr, errorcode;
unsigned short ssw = fp->un.fmtb.ssw; unsigned short ssw = fp->un.fmtb.ssw;
int user_space_fault = 1;
#if DEBUG #if DEBUG
unsigned long desc; unsigned long desc;
#endif
#if DEBUG
printk ("pid = %x ", current->pid); printk ("pid = %x ", current->pid);
printk ("SSW=%#06x ", ssw); printk ("SSW=%#06x ", ssw);
...@@ -605,62 +602,29 @@ static inline void bus_error030 (struct frame *fp) ...@@ -605,62 +602,29 @@ static inline void bus_error030 (struct frame *fp)
space_names[ssw & DFC], fp->ptregs.pc); space_names[ssw & DFC], fp->ptregs.pc);
#endif #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 /* ++andreas: If a data fault and an instruction fault happen
at the same time map in both pages. */ at the same time map in both pages. */
/* First handle the data fault, if any. */ /* First handle the data fault, if any. */
if (ssw & DF) if (ssw & DF) {
{
addr = fp->un.fmtb.daddr; addr = fp->un.fmtb.daddr;
mmusr = MMU_I;
if (user_space_fault) {
#if DEBUG #if DEBUG
asm volatile ("ptestr #1,%2@,#7,%0\n\t" asm volatile ("ptestr %3,%2@,#7,%0\n\t"
"pmove %/psr,%1@" "pmove %%psr,%1@"
: "=a&" (desc) : "=a&" (desc)
: "a" (&temp), "a" (addr)); : "a" (&temp), "a" (addr), "d" (ssw));
#else #else
asm volatile ("ptestr #1,%1@,#7\n\t" asm volatile ("ptestr %2,%1@,#7\n\t"
"pmove %/psr,%0@" "pmove %%psr,%0@"
: : "a" (&temp), "a" (addr)); : : "a" (&temp), "a" (addr), "d" (ssw));
#endif #endif
mmusr = temp; mmusr = temp;
}
#if DEBUG #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); 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)); __va(desc), *(unsigned long *)__va(desc));
#endif #endif
...@@ -669,12 +633,23 @@ static inline void bus_error030 (struct frame *fp) ...@@ -669,12 +633,23 @@ static inline void bus_error030 (struct frame *fp)
errorcode |= 2; errorcode |= 2;
if (mmusr & (MMU_I | MMU_WP)) { 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 /* Don't try to do anything further if an exception was
handled. */ handled. */
if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
return; 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)) { } 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, !(ssw & RW) ? "write" : "read", addr,
fp->ptregs.pc); fp->ptregs.pc);
die_if_kernel("Oops",&fp->ptregs,mmusr); die_if_kernel("Oops",&fp->ptregs,mmusr);
...@@ -685,25 +660,25 @@ static inline void bus_error030 (struct frame *fp) ...@@ -685,25 +660,25 @@ static inline void bus_error030 (struct frame *fp)
static volatile long tlong; static volatile long tlong;
#endif #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, !(ssw & RW) ? "write" : "read", addr,
fp->ptregs.pc, ssw); fp->ptregs.pc, ssw);
asm volatile ("ptestr #1,%1@,#0\n\t" asm volatile ("ptestr #1,%1@,#0\n\t"
"pmove %/psr,%0@" "pmove %%psr,%0@"
: /* no outputs */ : /* no outputs */
: "a" (&temp), "a" (addr)); : "a" (&temp), "a" (addr));
mmusr = temp; mmusr = temp;
printk ("level 0 mmusr is %#x\n", mmusr); printk ("level 0 mmusr is %#x\n", mmusr);
#if 0 #if 0
asm volatile ("pmove %/tt0,%0@" asm volatile ("pmove %%tt0,%0@"
: /* no outputs */ : /* no outputs */
: "a" (&tlong)); : "a" (&tlong));
printk ("tt0 is %#lx, ", tlong); printk("tt0 is %#lx, ", tlong);
asm volatile ("pmove %/tt1,%0@" asm volatile ("pmove %%tt1,%0@"
: /* no outputs */ : /* no outputs */
: "a" (&tlong)); : "a" (&tlong));
printk ("tt1 is %#lx\n", tlong); printk("tt1 is %#lx\n", tlong);
#endif #endif
#if DEBUG #if DEBUG
printk("Unknown SIGSEGV - 1\n"); printk("Unknown SIGSEGV - 1\n");
...@@ -714,7 +689,7 @@ static inline void bus_error030 (struct frame *fp) ...@@ -714,7 +689,7 @@ static inline void bus_error030 (struct frame *fp)
} }
/* setup an ATC entry for the access about to be retried */ /* 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 */ asm volatile ("ploadw %1,%0@" : /* no outputs */
: "a" (addr), "d" (ssw)); : "a" (addr), "d" (ssw));
else else
...@@ -727,6 +702,16 @@ static inline void bus_error030 (struct frame *fp) ...@@ -727,6 +702,16 @@ static inline void bus_error030 (struct frame *fp)
if (!(ssw & (FC|FB))) if (!(ssw & (FC|FB)))
return; 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 */ /* get the fault address */
if (fp->ptregs.format == 10) if (fp->ptregs.format == 10)
addr = fp->ptregs.pc + 4; addr = fp->ptregs.pc + 4;
...@@ -740,20 +725,17 @@ static inline void bus_error030 (struct frame *fp) ...@@ -740,20 +725,17 @@ static inline void bus_error030 (struct frame *fp)
should still create the ATC entry. */ should still create the ATC entry. */
goto create_atc_entry; goto create_atc_entry;
mmusr = MMU_I;
if (user_space_fault) {
#if DEBUG #if DEBUG
asm volatile ("ptestr #1,%2@,#7,%0\n\t" asm volatile ("ptestr #1,%2@,#7,%0\n\t"
"pmove %/psr,%1@" "pmove %%psr,%1@"
: "=a&" (desc) : "=a&" (desc)
: "a" (&temp), "a" (addr)); : "a" (&temp), "a" (addr));
#else #else
asm volatile ("ptestr #1,%1@,#7\n\t" asm volatile ("ptestr #1,%1@,#7\n\t"
"pmove %/psr,%0@" "pmove %%psr,%0@"
: : "a" (&temp), "a" (addr)); : : "a" (&temp), "a" (addr));
#endif #endif
mmusr = temp; mmusr = temp;
}
#ifdef DEBUG #ifdef DEBUG
printk ("mmusr is %#x for addr %#lx in task %p\n", 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