diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 3a1f95a8f7307de38ea69336921d8afe7e66876c..ec590d41c383c1f355a6011a5d5fc2150d5fcf8b 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1566,17 +1566,14 @@ void user_instruction_dump (unsigned int *pc)
 	printk("\n");
 }
 
-void show_trace_task(struct task_struct *tsk)
+void show_trace_raw(struct thread_info *tp, unsigned long ksp)
 {
-	unsigned long pc, fp;
-	unsigned long thread_base = (unsigned long) tsk->thread_info;
+	unsigned long pc, fp, thread_base;
 	struct reg_window *rw;
 	int count = 0;
 
-	if (!tsk)
-		return;
-
-	fp = tsk->thread_info->ksp + STACK_BIAS;
+	fp = ksp + STACK_BIAS;
+	thread_base = (unsigned long) tp;
 	do {
 		/* Bogus frame pointer? */
 		if (fp < (thread_base + sizeof(struct thread_info)) ||
@@ -1590,6 +1587,13 @@ void show_trace_task(struct task_struct *tsk)
 	printk("\n");
 }
 
+void show_trace_task(struct task_struct *tsk)
+{
+	if (tsk)
+		show_trace_raw(tsk->thread_info,
+			       tsk->thread_info->ksp);
+}
+
 void die_if_kernel(char *str, struct pt_regs *regs)
 {
 	extern void __show_regs(struct pt_regs * regs);
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 3798f6d6781bbecc2d98c58806becb959943e225..f34184be0c71c1cd13e86b952852a1521abea28d 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -130,8 +130,8 @@ unsigned long __init prom_probe_memory (void)
 	return tally;
 }
 
-void unhandled_fault(unsigned long address, struct task_struct *tsk,
-                     struct pt_regs *regs)
+static void unhandled_fault(unsigned long address, struct task_struct *tsk,
+			    struct pt_regs *regs)
 {
 	if ((unsigned long) address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL "
@@ -148,6 +148,19 @@ void unhandled_fault(unsigned long address, struct task_struct *tsk,
 	die_if_kernel("Oops", regs);
 }
 
+extern void show_trace_raw(struct thread_info *, unsigned long);
+
+static void bad_kernel_pc(struct pt_regs *regs)
+{
+	unsigned long ksp;
+
+	printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n",
+	       regs->tpc);
+	__asm__("mov %%sp, %0" : "=r" (ksp));
+	show_trace_raw(current_thread_info(), ksp);
+	unhandled_fault(regs->tpc, current, regs);
+}
+
 /*
  * We now make sure that mmap_sem is held in all paths that call 
  * this. Additionally, to prevent kswapd from ripping ptes from
@@ -215,7 +228,7 @@ static inline unsigned int get_fault_insn(struct pt_regs *regs, unsigned int ins
 		if (!regs->tpc || (regs->tpc & 0x3))
 			return 0;
 		if (regs->tstate & TSTATE_PRIV) {
-			insn = *(unsigned int *)regs->tpc;
+			insn = *(unsigned int *) regs->tpc;
 		} else {
 			insn = get_user_insn(regs->tpc);
 		}
@@ -306,6 +319,20 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs)
 	    (fault_code & FAULT_CODE_DTLB))
 		BUG();
 
+	if (regs->tstate & TSTATE_PRIV) {
+		unsigned long tpc = regs->tpc;
+		extern unsigned int _etext;
+
+		/* Sanity check the PC. */
+		if ((tpc >= KERNBASE && tpc < (unsigned long) &_etext) ||
+		    (tpc >= MODULES_VADDR && tpc < MODULES_END)) {
+			/* Valid, no problems... */
+		} else {
+			bad_kernel_pc(regs);
+			return;
+		}
+	}
+
 	/*
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
@@ -314,7 +341,8 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs)
 		goto intr_or_no_mm;
 
 	if (test_thread_flag(TIF_32BIT)) {
-		regs->tpc &= 0xffffffff;
+		if (!(regs->tstate & TSTATE_PRIV))
+			regs->tpc &= 0xffffffff;
 		address &= 0xffffffff;
 	}