Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70d2b595 authored by Chris Metcalf's avatar Chris Metcalf
Browse files

tile: improve illegal translation interrupt handling



First, don't re-enable interrupts blindly in the Linux trap handler.
We already handle page faults this way; synchronous interrupts like
ILL_TRANS will fire even when interrupts are disabled, and we don't
want to re-enable interrupts in that case.

For ILL_TRANS, we now pass the ILL_VA_PC reason into the trap handler
so we can report it properly; this is the address that caused the
illegal translation trap.  We print the address as part of the
pr_alert() message now if it's coming from the kernel.

Signed-off-by: default avatarChris Metcalf <cmetcalf@tilera.com>
parent dadf78bf
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -492,7 +492,7 @@ intvec_\vecname:
	mfspr   r3, SPR_SYSTEM_SAVE_K_2   /* info about page fault */
	.else
	.ifc \vecnum, INT_ILL_TRANS
	mfspr   r2, ILL_TRANS_REASON
	mfspr   r2, ILL_VA_PC
	.else
	.ifc \vecnum, INT_DOUBLE_FAULT
	mfspr   r2, SPR_SYSTEM_SAVE_K_2   /* double fault info from HV */
+15 −10
Original line number Diff line number Diff line
@@ -222,7 +222,8 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
	unsigned long address = 0;
	bundle_bits instr;

	/* Re-enable interrupts. */
	/* Re-enable interrupts, if they were previously enabled. */
	if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
		local_irq_enable();

	/*
@@ -231,7 +232,8 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
	 */
	if (!user_mode(regs)) {
		const char *name;
		if (fixup_exception(regs))  /* only UNALIGN_DATA in practice */
		char buf[100];
		if (fixup_exception(regs))  /* ILL_TRANS or UNALIGN_DATA */
			return;
		if (fault_num >= 0 &&
		    fault_num < sizeof(int_name)/sizeof(int_name[0]) &&
@@ -239,10 +241,16 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
			name = int_name[fault_num];
		else
			name = "Unknown interrupt";
		pr_alert("Kernel took bad trap %d (%s) at PC %#lx\n",
			 fault_num, name, regs->pc);
		if (fault_num == INT_GPV)
			pr_alert("GPV_REASON is %#lx\n", reason);
			snprintf(buf, sizeof(buf), "; GPV_REASON %#lx", reason);
#ifdef __tilegx__
		else if (fault_num == INT_ILL_TRANS)
			snprintf(buf, sizeof(buf), "; address %#lx", reason);
#endif
		else
			buf[0] = '\0';
		pr_alert("Kernel took bad trap %d (%s) at PC %#lx%s\n",
			 fault_num, name, regs->pc, buf);
		show_regs(regs);
		do_exit(SIGKILL);  /* FIXME: implement i386 die() */
		return;
@@ -324,11 +332,8 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
		fill_ra_stack();

		signo = SIGSEGV;
		address = reason;
		code = SEGV_MAPERR;
		if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK)
			address = regs->pc;
		else
			address = 0;  /* FIXME: GX: single-step for address */
		break;
	}
#endif