static inline void bus_error030()

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));
}