static inline void bus_error030()

in kernel/traps.c [370:492]


static inline void bus_error030 (struct frame *fp)
{
	unsigned char buserr_type = sun3_get_buserr ();
	unsigned long addr, errorcode;
	unsigned short ssw = fp->un.fmtb.ssw;
	extern unsigned long _sun3_map_test_start, _sun3_map_test_end;

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

	/*
	 * Check if this page should be demand-mapped. This needs to go before
	 * the testing for a bad kernel-space access (demand-mapping applies
	 * to kernel accesses too).
	 */

	if ((ssw & DF)
	    && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
		if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
			return;
	}

	/* Check for kernel-space pagefault (BAD). */
	if (fp->ptregs.sr & PS_S) {
		/* kernel fault must be a data fault to user space */
		if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
		     // try checking the kernel mappings before surrender
		     if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
			  return;
			/* instruction fault or kernel data fault! */
			if (ssw & (FC | FB))
				pr_err("Instruction fault at %#010lx\n",
					fp->ptregs.pc);
			if (ssw & DF) {
				/* was this fault incurred testing bus mappings? */
				if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) &&
				   (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) {
					send_fault_sig(&fp->ptregs);
					return;
				}

				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);
			}
			pr_err("BAD KERNEL BUSERR\n");

			die_if_kernel("Oops", &fp->ptregs,0);
			force_sig(SIGKILL);
			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");
	}


	/* First handle the data fault, if any.  */
	if (ssw & DF) {
		addr = fp->un.fmtb.daddr;

// errorcode bit 0:	0 -> no page		1 -> protection fault
// errorcode bit 1:	0 -> read fault		1 -> write fault

// (buserr_type & SUN3_BUSERR_PROTERR)	-> protection fault
// (buserr_type & SUN3_BUSERR_INVALID)	-> invalid page fault

		if (buserr_type & SUN3_BUSERR_PROTERR)
			errorcode = 0x01;
		else if (buserr_type & SUN3_BUSERR_INVALID)
			errorcode = 0x00;
		else {
			pr_debug("*** unexpected busfault type=%#04x\n",
				 buserr_type);
			pr_debug("invalid %s access at %#lx from pc %#lx\n",
				 !(ssw & RW) ? "write" : "read", addr,
				 fp->ptregs.pc);
			die_if_kernel ("Oops", &fp->ptregs, buserr_type);
			force_sig (SIGBUS);
			return;
		}

//todo: wtf is RM bit? --m
		if (!(ssw & RW) || ssw & RM)
			errorcode |= 0x02;

		/* Handle page fault. */
		do_page_fault (&fp->ptregs, addr, errorcode);

		/* Retry the data fault now. */
		return;
	}

	/* Now handle the instruction fault. */

	/* Get the fault address. */
	if (fp->ptregs.format == 0xA)
		addr = fp->ptregs.pc + 4;
	else
		addr = fp->un.fmtb.baddr;
	if (ssw & FC)
		addr -= 2;

	if (buserr_type & SUN3_BUSERR_INVALID) {
		if (!mmu_emu_handle_fault(addr, 1, 0))
			do_page_fault (&fp->ptregs, addr, 0);
       } else {
		pr_debug("protection fault on insn access (segv).\n");
		force_sig (SIGSEGV);
       }
}