xref: /openbmc/linux/arch/parisc/kernel/traps.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/arch/parisc/traps.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992  Linus Torvalds
61da177e4SLinus Torvalds  *  Copyright (C) 1999, 2000  Philipp Rumpf <prumpf@tux.org>
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds /*
101da177e4SLinus Torvalds  * 'Traps.c' handles hardware traps and faults after we have saved some
111da177e4SLinus Torvalds  * state in 'asm.s'.
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/sched.h>
15b17b0153SIngo Molnar #include <linux/sched/debug.h>
161da177e4SLinus Torvalds #include <linux/kernel.h>
171da177e4SLinus Torvalds #include <linux/string.h>
181da177e4SLinus Torvalds #include <linux/errno.h>
191da177e4SLinus Torvalds #include <linux/ptrace.h>
201da177e4SLinus Torvalds #include <linux/timer.h>
2122fced88SHelge Deller #include <linux/delay.h>
221da177e4SLinus Torvalds #include <linux/mm.h>
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds #include <linux/smp.h>
251da177e4SLinus Torvalds #include <linux/spinlock.h>
261da177e4SLinus Torvalds #include <linux/init.h>
271da177e4SLinus Torvalds #include <linux/interrupt.h>
281da177e4SLinus Torvalds #include <linux/console.h>
296891f8a1SHelge Deller #include <linux/bug.h>
30fef47e2aSHelge Deller #include <linux/ratelimit.h>
3170ffdb93SDavid Hildenbrand #include <linux/uaccess.h>
32ec4d396bSSven Schnelle #include <linux/kdebug.h>
33ec5c1150SHelge Deller #include <linux/kfence.h>
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds #include <asm/assembly.h>
361da177e4SLinus Torvalds #include <asm/io.h>
371da177e4SLinus Torvalds #include <asm/irq.h>
381da177e4SLinus Torvalds #include <asm/traps.h>
391da177e4SLinus Torvalds #include <asm/unaligned.h>
4060063497SArun Sharma #include <linux/atomic.h>
411da177e4SLinus Torvalds #include <asm/smp.h>
421da177e4SLinus Torvalds #include <asm/pdc.h>
431da177e4SLinus Torvalds #include <asm/pdc_chassis.h>
441da177e4SLinus Torvalds #include <asm/unwind.h>
45d6ce8626SRandolph Chung #include <asm/tlbflush.h>
46d6ce8626SRandolph Chung #include <asm/cacheflush.h>
47eacbfce1SSven Schnelle #include <linux/kgdb.h>
488858ac8eSSven Schnelle #include <linux/kprobes.h>
491da177e4SLinus Torvalds 
5015e64ef6SHelge Deller #if defined(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK)
5115e64ef6SHelge Deller #include <asm/spinlock.h>
5215e64ef6SHelge Deller #endif
5315e64ef6SHelge Deller 
541da177e4SLinus Torvalds #include "../math-emu/math-emu.h"	/* for handle_fpe() */
551da177e4SLinus Torvalds 
569e0d5c45SHelge Deller static void parisc_show_stack(struct task_struct *task,
573481d31bSDmitry Safonov 	struct pt_regs *regs, const char *loglvl);
58dc39455eSKyle McMartin 
printbinary(char * buf,unsigned long x,int nbits)596891f8a1SHelge Deller static int printbinary(char *buf, unsigned long x, int nbits)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds 	unsigned long mask = 1UL << (nbits - 1);
621da177e4SLinus Torvalds 	while (mask != 0) {
631da177e4SLinus Torvalds 		*buf++ = (mask & x ? '1' : '0');
641da177e4SLinus Torvalds 		mask >>= 1;
651da177e4SLinus Torvalds 	}
661da177e4SLinus Torvalds 	*buf = '\0';
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	return nbits;
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
71a8f44e38SHelge Deller #ifdef CONFIG_64BIT
721da177e4SLinus Torvalds #define RFMT "%016lx"
731da177e4SLinus Torvalds #else
741da177e4SLinus Torvalds #define RFMT "%08lx"
751da177e4SLinus Torvalds #endif
761c63b4b8SKyle McMartin #define FFMT "%016llx"	/* fpregs are 64-bit always */
771da177e4SLinus Torvalds 
781c63b4b8SKyle McMartin #define PRINTREGS(lvl,r,f,fmt,x)	\
791c63b4b8SKyle McMartin 	printk("%s%s%02d-%02d  " fmt " " fmt " " fmt " " fmt "\n",	\
801c63b4b8SKyle McMartin 		lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1],		\
811c63b4b8SKyle McMartin 		(r)[(x)+2], (r)[(x)+3])
821c63b4b8SKyle McMartin 
print_gr(const char * level,struct pt_regs * regs)83e2693ec1SRolf Eike Beer static void print_gr(const char *level, struct pt_regs *regs)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds 	int i;
861c63b4b8SKyle McMartin 	char buf[64];
871da177e4SLinus Torvalds 
881c63b4b8SKyle McMartin 	printk("%s\n", level);
891da177e4SLinus Torvalds 	printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
901da177e4SLinus Torvalds 	printbinary(buf, regs->gr[0], 32);
911da177e4SLinus Torvalds 	printk("%sPSW: %s %s\n", level, buf, print_tainted());
921da177e4SLinus Torvalds 
931c63b4b8SKyle McMartin 	for (i = 0; i < 32; i += 4)
941c63b4b8SKyle McMartin 		PRINTREGS(level, regs->gr, "r", RFMT, i);
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds 
print_fr(const char * level,struct pt_regs * regs)97e2693ec1SRolf Eike Beer static void print_fr(const char *level, struct pt_regs *regs)
981c63b4b8SKyle McMartin {
991c63b4b8SKyle McMartin 	int i;
1001c63b4b8SKyle McMartin 	char buf[64];
1011c63b4b8SKyle McMartin 	struct { u32 sw[2]; } s;
1021da177e4SLinus Torvalds 
103eba91727SThibaut Varene 	/* FR are 64bit everywhere. Need to use asm to get the content
104eba91727SThibaut Varene 	 * of fpsr/fper1, and we assume that we won't have a FP Identify
105eba91727SThibaut Varene 	 * in our way, otherwise we're screwed.
106eba91727SThibaut Varene 	 * The fldd is used to restore the T-bit if there was one, as the
107eba91727SThibaut Varene 	 * store clears it anyway.
1081c63b4b8SKyle McMartin 	 * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */
1091c63b4b8SKyle McMartin 	asm volatile ("fstd %%fr0,0(%1)	\n\t"
110eba91727SThibaut Varene 		      "fldd 0(%1),%%fr0	\n\t"
1111c63b4b8SKyle McMartin 		      : "=m" (s) : "r" (&s) : "r0");
112eba91727SThibaut Varene 
113eba91727SThibaut Varene 	printk("%s\n", level);
114eba91727SThibaut Varene 	printk("%s      VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level);
115eba91727SThibaut Varene 	printbinary(buf, s.sw[0], 32);
116eba91727SThibaut Varene 	printk("%sFPSR: %s\n", level, buf);
117eba91727SThibaut Varene 	printk("%sFPER1: %08x\n", level, s.sw[1]);
118eba91727SThibaut Varene 
119eba91727SThibaut Varene 	/* here we'll print fr0 again, tho it'll be meaningless */
1201c63b4b8SKyle McMartin 	for (i = 0; i < 32; i += 4)
1211c63b4b8SKyle McMartin 		PRINTREGS(level, regs->fr, "fr", FFMT, i);
122eba91727SThibaut Varene }
1231da177e4SLinus Torvalds 
show_regs(struct pt_regs * regs)1241c63b4b8SKyle McMartin void show_regs(struct pt_regs *regs)
1251c63b4b8SKyle McMartin {
1267a3f5134SHelge Deller 	int i, user;
127e2693ec1SRolf Eike Beer 	const char *level;
1281c63b4b8SKyle McMartin 	unsigned long cr30, cr31;
1291c63b4b8SKyle McMartin 
1307a3f5134SHelge Deller 	user = user_mode(regs);
1317a3f5134SHelge Deller 	level = user ? KERN_DEBUG : KERN_CRIT;
1321c63b4b8SKyle McMartin 
133a43cb95dSTejun Heo 	show_regs_print_info(level);
134a43cb95dSTejun Heo 
1351c63b4b8SKyle McMartin 	print_gr(level, regs);
1361c63b4b8SKyle McMartin 
1371c63b4b8SKyle McMartin 	for (i = 0; i < 8; i += 4)
1381c63b4b8SKyle McMartin 		PRINTREGS(level, regs->sr, "sr", RFMT, i);
1391c63b4b8SKyle McMartin 
1407a3f5134SHelge Deller 	if (user)
1411c63b4b8SKyle McMartin 		print_fr(level, regs);
1421c63b4b8SKyle McMartin 
1431da177e4SLinus Torvalds 	cr30 = mfctl(30);
1441da177e4SLinus Torvalds 	cr31 = mfctl(31);
1451da177e4SLinus Torvalds 	printk("%s\n", level);
1461da177e4SLinus Torvalds 	printk("%sIASQ: " RFMT " " RFMT " IAOQ: " RFMT " " RFMT "\n",
1471da177e4SLinus Torvalds 	       level, regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
1481da177e4SLinus Torvalds 	printk("%s IIR: %08lx    ISR: " RFMT "  IOR: " RFMT "\n",
1491da177e4SLinus Torvalds 	       level, regs->iir, regs->isr, regs->ior);
1501da177e4SLinus Torvalds 	printk("%s CPU: %8d   CR30: " RFMT " CR31: " RFMT "\n",
1512214c0e7SHelge Deller 	       level, task_cpu(current), cr30, cr31);
1521da177e4SLinus Torvalds 	printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
1537a3f5134SHelge Deller 
1547a3f5134SHelge Deller 	if (user) {
1557a3f5134SHelge Deller 		printk("%s IAOQ[0]: " RFMT "\n", level, regs->iaoq[0]);
1567a3f5134SHelge Deller 		printk("%s IAOQ[1]: " RFMT "\n", level, regs->iaoq[1]);
1577a3f5134SHelge Deller 		printk("%s RP(r2): " RFMT "\n", level, regs->gr[2]);
1587a3f5134SHelge Deller 	} else {
1597a3f5134SHelge Deller 		printk("%s IAOQ[0]: %pS\n", level, (void *) regs->iaoq[0]);
1607a3f5134SHelge Deller 		printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]);
1617a3f5134SHelge Deller 		printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]);
162d0347b49SKyle McMartin 
1633481d31bSDmitry Safonov 		parisc_show_stack(current, regs, KERN_DEFAULT);
1641da177e4SLinus Torvalds 	}
1657a3f5134SHelge Deller }
1661da177e4SLinus Torvalds 
167fef47e2aSHelge Deller static DEFINE_RATELIMIT_STATE(_hppa_rs,
168fef47e2aSHelge Deller 	DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
169fef47e2aSHelge Deller 
170fef47e2aSHelge Deller #define parisc_printk_ratelimited(critical, regs, fmt, ...)	{	      \
171fef47e2aSHelge Deller 	if ((critical || show_unhandled_signals) && __ratelimit(&_hppa_rs)) { \
172fef47e2aSHelge Deller 		printk(fmt, ##__VA_ARGS__);				      \
173fef47e2aSHelge Deller 		show_regs(regs);					      \
174fef47e2aSHelge Deller 	}								      \
175fef47e2aSHelge Deller }
176fef47e2aSHelge Deller 
177fef47e2aSHelge Deller 
do_show_stack(struct unwind_frame_info * info,const char * loglvl)1783481d31bSDmitry Safonov static void do_show_stack(struct unwind_frame_info *info, const char *loglvl)
1791da177e4SLinus Torvalds {
1801da177e4SLinus Torvalds 	int i = 1;
1811da177e4SLinus Torvalds 
1823481d31bSDmitry Safonov 	printk("%sBacktrace:\n", loglvl);
183c8921d72SHelge Deller 	while (i <= MAX_UNWIND_ENTRIES) {
1841da177e4SLinus Torvalds 		if (unwind_once(info) < 0 || info->ip == 0)
1851da177e4SLinus Torvalds 			break;
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 		if (__kernel_text_address(info->ip)) {
1883481d31bSDmitry Safonov 			printk("%s [<" RFMT ">] %pS\n",
1893481d31bSDmitry Safonov 				loglvl, info->ip, (void *) info->ip);
1901da177e4SLinus Torvalds 			i++;
1911da177e4SLinus Torvalds 		}
1921da177e4SLinus Torvalds 	}
1933481d31bSDmitry Safonov 	printk("%s\n", loglvl);
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds 
parisc_show_stack(struct task_struct * task,struct pt_regs * regs,const char * loglvl)1969e0d5c45SHelge Deller static void parisc_show_stack(struct task_struct *task,
1973481d31bSDmitry Safonov 	struct pt_regs *regs, const char *loglvl)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds 	struct unwind_frame_info info;
2001da177e4SLinus Torvalds 
2019e0d5c45SHelge Deller 	unwind_frame_init_task(&info, task, regs);
202dc39455eSKyle McMartin 
2033481d31bSDmitry Safonov 	do_show_stack(&info, loglvl);
2043481d31bSDmitry Safonov }
2053481d31bSDmitry Safonov 
show_stack(struct task_struct * t,unsigned long * sp,const char * loglvl)2069cb8f069SDmitry Safonov void show_stack(struct task_struct *t, unsigned long *sp, const char *loglvl)
2073481d31bSDmitry Safonov {
2083481d31bSDmitry Safonov 	parisc_show_stack(t, NULL, loglvl);
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds 
is_valid_bugaddr(unsigned long iaoq)2116891f8a1SHelge Deller int is_valid_bugaddr(unsigned long iaoq)
2126891f8a1SHelge Deller {
2136891f8a1SHelge Deller 	return 1;
2146891f8a1SHelge Deller }
2156891f8a1SHelge Deller 
die_if_kernel(char * str,struct pt_regs * regs,long err)2161da177e4SLinus Torvalds void die_if_kernel(char *str, struct pt_regs *regs, long err)
2171da177e4SLinus Torvalds {
2181da177e4SLinus Torvalds 	if (user_mode(regs)) {
2191da177e4SLinus Torvalds 		if (err == 0)
2201da177e4SLinus Torvalds 			return; /* STFU */
2211da177e4SLinus Torvalds 
222fef47e2aSHelge Deller 		parisc_printk_ratelimited(1, regs,
223fef47e2aSHelge Deller 			KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n",
22419c5870cSAlexey Dobriyan 			current->comm, task_pid_nr(current), str, err, regs->iaoq[0]);
225fef47e2aSHelge Deller 
2261da177e4SLinus Torvalds 		return;
2271da177e4SLinus Torvalds 	}
2281da177e4SLinus Torvalds 
229c288ac97SSergey Senozhatsky 	bust_spinlocks(1);
2301da177e4SLinus Torvalds 
231c48faf86SHelge Deller 	oops_enter();
232c48faf86SHelge Deller 
2331da177e4SLinus Torvalds 	/* Amuse the user in a SPARC fashion */
234ad361c98SJoe Perches 	if (err) printk(KERN_CRIT
235ad361c98SJoe Perches 			"      _______________________________ \n"
236ad361c98SJoe Perches 			"     < Your System ate a SPARC! Gah! >\n"
237ad361c98SJoe Perches 			"      ------------------------------- \n"
238ad361c98SJoe Perches 			"             \\   ^__^\n"
239ad361c98SJoe Perches 			"                 (__)\\       )\\/\\\n"
240ad361c98SJoe Perches 			"                  U  ||----w |\n"
241ad361c98SJoe Perches 			"                     ||     ||\n");
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 	/* unlock the pdc lock if necessary */
2441da177e4SLinus Torvalds 	pdc_emergency_unlock();
2451da177e4SLinus Torvalds 
2466891f8a1SHelge Deller 	if (err)
2471da177e4SLinus Torvalds 		printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
24819c5870cSAlexey Dobriyan 			current->comm, task_pid_nr(current), str, err);
249bd83bcffSHelge Deller 
2500bbdac08SHelge Deller 	/* Wot's wrong wif bein' racy? */
2510bbdac08SHelge Deller 	if (current->thread.flags & PARISC_KERNEL_DEATH) {
25291bae23cSHarvey Harrison 		printk(KERN_CRIT "%s() recursion detected.\n", __func__);
2530bbdac08SHelge Deller 		local_irq_enable();
2540bbdac08SHelge Deller 		while (1);
2550bbdac08SHelge Deller 	}
2560bbdac08SHelge Deller 	current->thread.flags |= PARISC_KERNEL_DEATH;
2570bbdac08SHelge Deller 
2581da177e4SLinus Torvalds 	show_regs(regs);
2590bbdac08SHelge Deller 	dump_stack();
260373d4d09SRusty Russell 	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
2611da177e4SLinus Torvalds 
26222fced88SHelge Deller 	if (in_interrupt())
26322fced88SHelge Deller 		panic("Fatal exception in interrupt");
26422fced88SHelge Deller 
265c95a23daSAaro Koskinen 	if (panic_on_oops)
26622fced88SHelge Deller 		panic("Fatal exception");
26722fced88SHelge Deller 
268c48faf86SHelge Deller 	oops_exit();
2690e25498fSEric W. Biederman 	make_task_dead(SIGSEGV);
2701da177e4SLinus Torvalds }
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds /* gdb uses break 4,8 */
2731da177e4SLinus Torvalds #define GDB_BREAK_INSN 0x10004
handle_gdb_break(struct pt_regs * regs,int wot)2746891f8a1SHelge Deller static void handle_gdb_break(struct pt_regs *regs, int wot)
2751da177e4SLinus Torvalds {
276ccf75290SEric W. Biederman 	force_sig_fault(SIGTRAP, wot,
2772e1661d2SEric W. Biederman 			(void __user *) (regs->iaoq[0] & ~3));
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds 
handle_break(struct pt_regs * regs)2806891f8a1SHelge Deller static void handle_break(struct pt_regs *regs)
2811da177e4SLinus Torvalds {
2826891f8a1SHelge Deller 	unsigned iir = regs->iir;
2831da177e4SLinus Torvalds 
2846891f8a1SHelge Deller 	if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) {
2856891f8a1SHelge Deller 		/* check if a BUG() or WARN() trapped here.  */
2866891f8a1SHelge Deller 		enum bug_trap_type tt;
287608e2619SHeiko Carstens 		tt = report_bug(regs->iaoq[0] & ~3, regs);
2886891f8a1SHelge Deller 		if (tt == BUG_TRAP_TYPE_WARN) {
2896891f8a1SHelge Deller 			regs->iaoq[0] += 4;
2906891f8a1SHelge Deller 			regs->iaoq[1] += 4;
2916891f8a1SHelge Deller 			return; /* return to next instruction when WARN_ON().  */
2926891f8a1SHelge Deller 		}
2936891f8a1SHelge Deller 		die_if_kernel("Unknown kernel breakpoint", regs,
2946891f8a1SHelge Deller 			(tt == BUG_TRAP_TYPE_NONE) ? 9 : 0);
2956891f8a1SHelge Deller 	}
2966891f8a1SHelge Deller 
2978858ac8eSSven Schnelle #ifdef CONFIG_KPROBES
298df419492SHelge Deller 	if (unlikely(iir == PARISC_KPROBES_BREAK_INSN && !user_mode(regs))) {
2998858ac8eSSven Schnelle 		parisc_kprobe_break_handler(regs);
3008858ac8eSSven Schnelle 		return;
3018858ac8eSSven Schnelle 	}
302df419492SHelge Deller 	if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2 && !user_mode(regs))) {
3039b046d02SHelge Deller 		parisc_kprobe_ss_handler(regs);
3049b046d02SHelge Deller 		return;
3059b046d02SHelge Deller 	}
3068858ac8eSSven Schnelle #endif
3078858ac8eSSven Schnelle 
308eacbfce1SSven Schnelle #ifdef CONFIG_KGDB
3096888ff04SHelge Deller 	if (unlikely((iir == PARISC_KGDB_COMPILED_BREAK_INSN ||
3106888ff04SHelge Deller 		iir == PARISC_KGDB_BREAK_INSN)) && !user_mode(regs)) {
311eacbfce1SSven Schnelle 		kgdb_handle_exception(9, SIGTRAP, 0, regs);
312eacbfce1SSven Schnelle 		return;
313eacbfce1SSven Schnelle 	}
314eacbfce1SSven Schnelle #endif
315eacbfce1SSven Schnelle 
31615e64ef6SHelge Deller #ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK
31715e64ef6SHelge Deller         if ((iir == SPINLOCK_BREAK_INSN) && !user_mode(regs)) {
31815e64ef6SHelge Deller 		die_if_kernel("Spinlock was trashed", regs, 1);
31915e64ef6SHelge Deller 	}
32015e64ef6SHelge Deller #endif
32115e64ef6SHelge Deller 
322fef47e2aSHelge Deller 	if (unlikely(iir != GDB_BREAK_INSN))
323fef47e2aSHelge Deller 		parisc_printk_ratelimited(0, regs,
324fef47e2aSHelge Deller 			KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
325df47b438SHelge Deller 			iir & 31, (iir>>13) & ((1<<13)-1),
32619c5870cSAlexey Dobriyan 			task_pid_nr(current), current->comm);
3271da177e4SLinus Torvalds 
3286891f8a1SHelge Deller 	/* send standard GDB signal */
3291da177e4SLinus Torvalds 	handle_gdb_break(regs, TRAP_BRKPT);
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
default_trap(int code,struct pt_regs * regs)3321da177e4SLinus Torvalds static void default_trap(int code, struct pt_regs *regs)
3331da177e4SLinus Torvalds {
3341da177e4SLinus Torvalds 	printk(KERN_ERR "Trap %d on CPU %d\n", code, smp_processor_id());
3351da177e4SLinus Torvalds 	show_regs(regs);
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds 
transfer_pim_to_trap_frame(struct pt_regs * regs)3387def4239SHelge Deller static void transfer_pim_to_trap_frame(struct pt_regs *regs)
3391da177e4SLinus Torvalds {
3401da177e4SLinus Torvalds     register int i;
3411da177e4SLinus Torvalds     extern unsigned int hpmc_pim_data[];
3421da177e4SLinus Torvalds     struct pdc_hpmc_pim_11 *pim_narrow;
3431da177e4SLinus Torvalds     struct pdc_hpmc_pim_20 *pim_wide;
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds     if (boot_cpu_data.cpu_type >= pcxu) {
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 	pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	/*
3501da177e4SLinus Torvalds 	 * Note: The following code will probably generate a
3511da177e4SLinus Torvalds 	 * bunch of truncation error warnings from the compiler.
3521da177e4SLinus Torvalds 	 * Could be handled with an ifdef, but perhaps there
3531da177e4SLinus Torvalds 	 * is a better way.
3541da177e4SLinus Torvalds 	 */
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds 	regs->gr[0] = pim_wide->cr[22];
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	for (i = 1; i < 32; i++)
3591da177e4SLinus Torvalds 	    regs->gr[i] = pim_wide->gr[i];
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 	for (i = 0; i < 32; i++)
3621da177e4SLinus Torvalds 	    regs->fr[i] = pim_wide->fr[i];
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds 	for (i = 0; i < 8; i++)
3651da177e4SLinus Torvalds 	    regs->sr[i] = pim_wide->sr[i];
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds 	regs->iasq[0] = pim_wide->cr[17];
3681da177e4SLinus Torvalds 	regs->iasq[1] = pim_wide->iasq_back;
3691da177e4SLinus Torvalds 	regs->iaoq[0] = pim_wide->cr[18];
3701da177e4SLinus Torvalds 	regs->iaoq[1] = pim_wide->iaoq_back;
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	regs->sar  = pim_wide->cr[11];
3731da177e4SLinus Torvalds 	regs->iir  = pim_wide->cr[19];
3741da177e4SLinus Torvalds 	regs->isr  = pim_wide->cr[20];
3751da177e4SLinus Torvalds 	regs->ior  = pim_wide->cr[21];
3761da177e4SLinus Torvalds     }
3771da177e4SLinus Torvalds     else {
3781da177e4SLinus Torvalds 	pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	regs->gr[0] = pim_narrow->cr[22];
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	for (i = 1; i < 32; i++)
3831da177e4SLinus Torvalds 	    regs->gr[i] = pim_narrow->gr[i];
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	for (i = 0; i < 32; i++)
3861da177e4SLinus Torvalds 	    regs->fr[i] = pim_narrow->fr[i];
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	for (i = 0; i < 8; i++)
3891da177e4SLinus Torvalds 	    regs->sr[i] = pim_narrow->sr[i];
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	regs->iasq[0] = pim_narrow->cr[17];
3921da177e4SLinus Torvalds 	regs->iasq[1] = pim_narrow->iasq_back;
3931da177e4SLinus Torvalds 	regs->iaoq[0] = pim_narrow->cr[18];
3941da177e4SLinus Torvalds 	regs->iaoq[1] = pim_narrow->iaoq_back;
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	regs->sar  = pim_narrow->cr[11];
3971da177e4SLinus Torvalds 	regs->iir  = pim_narrow->cr[19];
3981da177e4SLinus Torvalds 	regs->isr  = pim_narrow->cr[20];
3991da177e4SLinus Torvalds 	regs->ior  = pim_narrow->cr[21];
4001da177e4SLinus Torvalds     }
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds     /*
4031da177e4SLinus Torvalds      * The following fields only have meaning if we came through
4041da177e4SLinus Torvalds      * another path. So just zero them here.
4051da177e4SLinus Torvalds      */
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds     regs->ksp = 0;
4081da177e4SLinus Torvalds     regs->kpc = 0;
4091da177e4SLinus Torvalds     regs->orig_r28 = 0;
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds /*
4141da177e4SLinus Torvalds  * This routine is called as a last resort when everything else
4151da177e4SLinus Torvalds  * has gone clearly wrong. We get called for faults in kernel space,
4161da177e4SLinus Torvalds  * and HPMC's.
4171da177e4SLinus Torvalds  */
parisc_terminate(char * msg,struct pt_regs * regs,int code,unsigned long offset)4181da177e4SLinus Torvalds void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
4191da177e4SLinus Torvalds {
4201da177e4SLinus Torvalds 	static DEFINE_SPINLOCK(terminate_lock);
4211da177e4SLinus Torvalds 
422ec4d396bSSven Schnelle 	(void)notify_die(DIE_OOPS, msg, regs, 0, code, SIGTRAP);
423c288ac97SSergey Senozhatsky 	bust_spinlocks(1);
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	set_eiem(0);
4261da177e4SLinus Torvalds 	local_irq_disable();
4271da177e4SLinus Torvalds 	spin_lock(&terminate_lock);
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 	/* unlock the pdc lock if necessary */
4301da177e4SLinus Torvalds 	pdc_emergency_unlock();
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 	/* Not all paths will gutter the processor... */
4331da177e4SLinus Torvalds 	switch(code){
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds 	case 1:
4361da177e4SLinus Torvalds 		transfer_pim_to_trap_frame(regs);
4371da177e4SLinus Torvalds 		break;
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 	default:
4401da177e4SLinus Torvalds 		break;
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds 	}
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	{
4451da177e4SLinus Torvalds 		/* show_stack(NULL, (unsigned long *)regs->gr[30]); */
4461da177e4SLinus Torvalds 		struct unwind_frame_info info;
4471da177e4SLinus Torvalds 		unwind_frame_init(&info, current, regs);
4483481d31bSDmitry Safonov 		do_show_stack(&info, KERN_CRIT);
4491da177e4SLinus Torvalds 	}
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	printk("\n");
452e98bc5eeSHelge Deller 	pr_crit("%s: Code=%d (%s) at addr " RFMT "\n",
453e98bc5eeSHelge Deller 		msg, code, trap_name(code), offset);
4541da177e4SLinus Torvalds 	show_regs(regs);
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 	spin_unlock(&terminate_lock);
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 	/* put soft power button back under hardware control;
4591da177e4SLinus Torvalds 	 * if the user had pressed it once at any time, the
4601da177e4SLinus Torvalds 	 * system will shut down immediately right here. */
4611da177e4SLinus Torvalds 	pdc_soft_power_button(0);
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	/* Call kernel panic() so reboot timeouts work properly
4641da177e4SLinus Torvalds 	 * FIXME: This function should be on the list of
4651da177e4SLinus Torvalds 	 * panic notifiers, and we should call panic
4661da177e4SLinus Torvalds 	 * directly from the location that we wish.
4671da177e4SLinus Torvalds 	 * e.g. We should not call panic from
468a65bcad5SJulia Lawall 	 * parisc_terminate, but rather the other way around.
4691da177e4SLinus Torvalds 	 * This hack works, prints the panic message twice,
4701da177e4SLinus Torvalds 	 * and it enables reboot timers!
4711da177e4SLinus Torvalds 	 */
4721da177e4SLinus Torvalds 	panic(msg);
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds 
handle_interruption(int code,struct pt_regs * regs)475d75f054aSHelge Deller void notrace handle_interruption(int code, struct pt_regs *regs)
4761da177e4SLinus Torvalds {
4771da177e4SLinus Torvalds 	unsigned long fault_address = 0;
4781da177e4SLinus Torvalds 	unsigned long fault_space = 0;
479ccf75290SEric W. Biederman 	int si_code;
4801da177e4SLinus Torvalds 
481027c3d34SHelge Deller 	if (!irqs_disabled_flags(regs->gr[0]))
4821da177e4SLinus Torvalds 	    local_irq_enable();
4831da177e4SLinus Torvalds 
4841da177e4SLinus Torvalds 	/* Security check:
4851da177e4SLinus Torvalds 	 * If the priority level is still user, and the
4861da177e4SLinus Torvalds 	 * faulting space is not equal to the active space
4871da177e4SLinus Torvalds 	 * then the user is attempting something in a space
4881da177e4SLinus Torvalds 	 * that does not belong to them. Kill the process.
4891da177e4SLinus Torvalds 	 *
4901da177e4SLinus Torvalds 	 * This is normally the situation when the user
4911da177e4SLinus Torvalds 	 * attempts to jump into the kernel space at the
4921da177e4SLinus Torvalds 	 * wrong offset, be it at the gateway page or a
4931da177e4SLinus Torvalds 	 * random location.
4941da177e4SLinus Torvalds 	 *
4951da177e4SLinus Torvalds 	 * We cannot normally signal the process because it
4961da177e4SLinus Torvalds 	 * could *be* on the gateway page, and processes
4971da177e4SLinus Torvalds 	 * executing on the gateway page can't have signals
4981da177e4SLinus Torvalds 	 * delivered.
4991da177e4SLinus Torvalds 	 *
5001da177e4SLinus Torvalds 	 * We merely readjust the address into the users
5011da177e4SLinus Torvalds 	 * space, at a destination address of zero, and
5021da177e4SLinus Torvalds 	 * allow processing to continue.
5031da177e4SLinus Torvalds 	 */
5041da177e4SLinus Torvalds 	if (((unsigned long)regs->iaoq[0] & 3) &&
5051da177e4SLinus Torvalds 	    ((unsigned long)regs->iasq[0] != (unsigned long)regs->sr[7])) {
5061da177e4SLinus Torvalds 		/* Kill the user process later */
5071da177e4SLinus Torvalds 		regs->iaoq[0] = 0 | 3;
5081da177e4SLinus Torvalds 		regs->iaoq[1] = regs->iaoq[0] + 4;
509825e1e23SGrant Grundler 		regs->iasq[0] = regs->iasq[1] = regs->sr[7];
5101da177e4SLinus Torvalds 		regs->gr[0] &= ~PSW_B;
5111da177e4SLinus Torvalds 		return;
5121da177e4SLinus Torvalds 	}
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds #if 0
5151da177e4SLinus Torvalds 	printk(KERN_CRIT "Interruption # %d\n", code);
5161da177e4SLinus Torvalds #endif
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	switch(code) {
5191da177e4SLinus Torvalds 
5201da177e4SLinus Torvalds 	case  1:
5211da177e4SLinus Torvalds 		/* High-priority machine check (HPMC) */
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 		/* set up a new led state on systems shipped with a LED State panel */
5241da177e4SLinus Torvalds 		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_HPMC);
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 		parisc_terminate("High Priority Machine Check (HPMC)",
5271da177e4SLinus Torvalds 				regs, code, 0);
5281da177e4SLinus Torvalds 		/* NOT REACHED */
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 	case  2:
5311da177e4SLinus Torvalds 		/* Power failure interrupt */
5321da177e4SLinus Torvalds 		printk(KERN_CRIT "Power failure interrupt !\n");
5331da177e4SLinus Torvalds 		return;
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 	case  3:
5361da177e4SLinus Torvalds 		/* Recovery counter trap */
5371da177e4SLinus Torvalds 		regs->gr[0] &= ~PSW_R;
538eacbfce1SSven Schnelle 
539eacbfce1SSven Schnelle #ifdef CONFIG_KGDB
540eacbfce1SSven Schnelle 		if (kgdb_single_step) {
541eacbfce1SSven Schnelle 			kgdb_handle_exception(0, SIGTRAP, 0, regs);
542eacbfce1SSven Schnelle 			return;
543eacbfce1SSven Schnelle 		}
544eacbfce1SSven Schnelle #endif
545eacbfce1SSven Schnelle 
5461da177e4SLinus Torvalds 		if (user_space(regs))
5471da177e4SLinus Torvalds 			handle_gdb_break(regs, TRAP_TRACE);
5481da177e4SLinus Torvalds 		/* else this must be the start of a syscall - just let it run */
5491da177e4SLinus Torvalds 		return;
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds 	case  5:
5521da177e4SLinus Torvalds 		/* Low-priority machine check */
5531da177e4SLinus Torvalds 		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC);
5541da177e4SLinus Torvalds 
555d6ce8626SRandolph Chung 		flush_cache_all();
556d6ce8626SRandolph Chung 		flush_tlb_all();
557*75c6d083SHelge Deller 		default_trap(code, regs);
5581da177e4SLinus Torvalds 		return;
5591da177e4SLinus Torvalds 
5605b00ca0bSHelge Deller 	case  PARISC_ITLB_TRAP:
5611da177e4SLinus Torvalds 		/* Instruction TLB miss fault/Instruction page fault */
5621da177e4SLinus Torvalds 		fault_address = regs->iaoq[0];
5631da177e4SLinus Torvalds 		fault_space   = regs->iasq[0];
5641da177e4SLinus Torvalds 		break;
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds 	case  8:
5671da177e4SLinus Torvalds 		/* Illegal instruction trap */
5681da177e4SLinus Torvalds 		die_if_kernel("Illegal instruction", regs, code);
569ccf75290SEric W. Biederman 		si_code = ILL_ILLOPC;
5701da177e4SLinus Torvalds 		goto give_sigill;
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds 	case  9:
5731da177e4SLinus Torvalds 		/* Break instruction trap */
5746891f8a1SHelge Deller 		handle_break(regs);
5751da177e4SLinus Torvalds 		return;
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds 	case 10:
5781da177e4SLinus Torvalds 		/* Privileged operation trap */
5791da177e4SLinus Torvalds 		die_if_kernel("Privileged operation", regs, code);
580ccf75290SEric W. Biederman 		si_code = ILL_PRVOPC;
5811da177e4SLinus Torvalds 		goto give_sigill;
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds 	case 11:
5841da177e4SLinus Torvalds 		/* Privileged register trap */
5851da177e4SLinus Torvalds 		if ((regs->iir & 0xffdfffe0) == 0x034008a0) {
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds 			/* This is a MFCTL cr26/cr27 to gr instruction.
5881da177e4SLinus Torvalds 			 * PCXS traps on this, so we need to emulate it.
5891da177e4SLinus Torvalds 			 */
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 			if (regs->iir & 0x00200000)
5921da177e4SLinus Torvalds 				regs->gr[regs->iir & 0x1f] = mfctl(27);
5931da177e4SLinus Torvalds 			else
5941da177e4SLinus Torvalds 				regs->gr[regs->iir & 0x1f] = mfctl(26);
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 			regs->iaoq[0] = regs->iaoq[1];
5971da177e4SLinus Torvalds 			regs->iaoq[1] += 4;
5981da177e4SLinus Torvalds 			regs->iasq[0] = regs->iasq[1];
5991da177e4SLinus Torvalds 			return;
6001da177e4SLinus Torvalds 		}
6011da177e4SLinus Torvalds 
6021da177e4SLinus Torvalds 		die_if_kernel("Privileged register usage", regs, code);
603ccf75290SEric W. Biederman 		si_code = ILL_PRVREG;
6041da177e4SLinus Torvalds 	give_sigill:
605ccf75290SEric W. Biederman 		force_sig_fault(SIGILL, si_code,
6062e1661d2SEric W. Biederman 				(void __user *) regs->iaoq[0]);
6071da177e4SLinus Torvalds 		return;
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds 	case 12:
6101da177e4SLinus Torvalds 		/* Overflow Trap, let the userland signal handler do the cleanup */
611ccf75290SEric W. Biederman 		force_sig_fault(SIGFPE, FPE_INTOVF,
6122e1661d2SEric W. Biederman 				(void __user *) regs->iaoq[0]);
6131da177e4SLinus Torvalds 		return;
6141da177e4SLinus Torvalds 
6151da177e4SLinus Torvalds 	case 13:
6161da177e4SLinus Torvalds 		/* Conditional Trap
6177022672eSSimon Arlott 		   The condition succeeds in an instruction which traps
6181da177e4SLinus Torvalds 		   on condition  */
6191da177e4SLinus Torvalds 		if(user_mode(regs)){
62075abf642SHelge Deller 			/* Let userspace app figure it out from the insn pointed
62175abf642SHelge Deller 			 * to by si_addr.
62275abf642SHelge Deller 			 */
623ccf75290SEric W. Biederman 			force_sig_fault(SIGFPE, FPE_CONDTRAP,
6242e1661d2SEric W. Biederman 					(void __user *) regs->iaoq[0]);
6251da177e4SLinus Torvalds 			return;
6261da177e4SLinus Torvalds 		}
6271da177e4SLinus Torvalds 		/* The kernel doesn't want to handle condition codes */
6281da177e4SLinus Torvalds 		break;
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds 	case 14:
6311da177e4SLinus Torvalds 		/* Assist Exception Trap, i.e. floating point exception. */
6321da177e4SLinus Torvalds 		die_if_kernel("Floating point exception", regs, 0); /* quiet */
633d0c3be80SHelge Deller 		__inc_irq_stat(irq_fpassist_count);
6341da177e4SLinus Torvalds 		handle_fpe(regs);
6351da177e4SLinus Torvalds 		return;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	case 15:
6381da177e4SLinus Torvalds 		/* Data TLB miss fault/Data page fault */
639df561f66SGustavo A. R. Silva 		fallthrough;
6401da177e4SLinus Torvalds 	case 16:
6411da177e4SLinus Torvalds 		/* Non-access instruction TLB miss fault */
6421da177e4SLinus Torvalds 		/* The instruction TLB entry needed for the target address of the FIC
6431da177e4SLinus Torvalds 		   is absent, and hardware can't find it, so we get to cleanup */
644df561f66SGustavo A. R. Silva 		fallthrough;
6451da177e4SLinus Torvalds 	case 17:
6461da177e4SLinus Torvalds 		/* Non-access data TLB miss fault/Non-access data page fault */
6471da177e4SLinus Torvalds 		/* FIXME:
6481da177e4SLinus Torvalds 			 Still need to add slow path emulation code here!
6491da177e4SLinus Torvalds 			 If the insn used a non-shadow register, then the tlb
6501da177e4SLinus Torvalds 			 handlers could not have their side-effect (e.g. probe
6511da177e4SLinus Torvalds 			 writing to a target register) emulated since rfir would
6521da177e4SLinus Torvalds 			 erase the changes to said register. Instead we have to
6531da177e4SLinus Torvalds 			 setup everything, call this function we are in, and emulate
6541da177e4SLinus Torvalds 			 by hand. Technically we need to emulate:
6551da177e4SLinus Torvalds 			 fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw
6561da177e4SLinus Torvalds 		*/
657e00b0a2aSJohn David Anglin 		if (code == 17 && handle_nadtlb_fault(regs))
658e00b0a2aSJohn David Anglin 			return;
6591da177e4SLinus Torvalds 		fault_address = regs->ior;
6601da177e4SLinus Torvalds 		fault_space = regs->isr;
6611da177e4SLinus Torvalds 		break;
6621da177e4SLinus Torvalds 
6631da177e4SLinus Torvalds 	case 18:
6641da177e4SLinus Torvalds 		/* PCXS only -- later cpu's split this into types 26,27 & 28 */
6651da177e4SLinus Torvalds 		/* Check for unaligned access */
6661da177e4SLinus Torvalds 		if (check_unaligned(regs)) {
6671da177e4SLinus Torvalds 			handle_unaligned(regs);
6681da177e4SLinus Torvalds 			return;
6691da177e4SLinus Torvalds 		}
670df561f66SGustavo A. R. Silva 		fallthrough;
6711da177e4SLinus Torvalds 	case 26:
6721da177e4SLinus Torvalds 		/* PCXL: Data memory access rights trap */
6731da177e4SLinus Torvalds 		fault_address = regs->ior;
6741da177e4SLinus Torvalds 		fault_space   = regs->isr;
6751da177e4SLinus Torvalds 		break;
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	case 19:
6781da177e4SLinus Torvalds 		/* Data memory break trap */
6791da177e4SLinus Torvalds 		regs->gr[0] |= PSW_X; /* So we can single-step over the trap */
680df561f66SGustavo A. R. Silva 		fallthrough;
6811da177e4SLinus Torvalds 	case 21:
6821da177e4SLinus Torvalds 		/* Page reference trap */
6831da177e4SLinus Torvalds 		handle_gdb_break(regs, TRAP_HWBKPT);
6841da177e4SLinus Torvalds 		return;
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	case 25:
6871da177e4SLinus Torvalds 		/* Taken branch trap */
6881da177e4SLinus Torvalds 		regs->gr[0] &= ~PSW_T;
6891da177e4SLinus Torvalds 		if (user_space(regs))
6901da177e4SLinus Torvalds 			handle_gdb_break(regs, TRAP_BRANCH);
6911da177e4SLinus Torvalds 		/* else this must be the start of a syscall - just let it
6921da177e4SLinus Torvalds 		 * run.
6931da177e4SLinus Torvalds 		 */
6941da177e4SLinus Torvalds 		return;
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	case  7:
6971da177e4SLinus Torvalds 		/* Instruction access rights */
6981da177e4SLinus Torvalds 		/* PCXL: Instruction memory protection trap */
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 		/*
7011da177e4SLinus Torvalds 		 * This could be caused by either: 1) a process attempting
7021da177e4SLinus Torvalds 		 * to execute within a vma that does not have execute
7031da177e4SLinus Torvalds 		 * permission, or 2) an access rights violation caused by a
7041da177e4SLinus Torvalds 		 * flush only translation set up by ptep_get_and_clear().
7051da177e4SLinus Torvalds 		 * So we check the vma permissions to differentiate the two.
7061da177e4SLinus Torvalds 		 * If the vma indicates we have execute permission, then
7071da177e4SLinus Torvalds 		 * the cause is the latter one. In this case, we need to
7081da177e4SLinus Torvalds 		 * call do_page_fault() to fix the problem.
7091da177e4SLinus Torvalds 		 */
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 		if (user_mode(regs)) {
7121da177e4SLinus Torvalds 			struct vm_area_struct *vma;
7131da177e4SLinus Torvalds 
714d8ed45c5SMichel Lespinasse 			mmap_read_lock(current->mm);
7151da177e4SLinus Torvalds 			vma = find_vma(current->mm,regs->iaoq[0]);
7161da177e4SLinus Torvalds 			if (vma && (regs->iaoq[0] >= vma->vm_start)
7171da177e4SLinus Torvalds 				&& (vma->vm_flags & VM_EXEC)) {
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds 				fault_address = regs->iaoq[0];
7201da177e4SLinus Torvalds 				fault_space = regs->iasq[0];
7211da177e4SLinus Torvalds 
722d8ed45c5SMichel Lespinasse 				mmap_read_unlock(current->mm);
7231da177e4SLinus Torvalds 				break; /* call do_page_fault() */
7241da177e4SLinus Torvalds 			}
725d8ed45c5SMichel Lespinasse 			mmap_read_unlock(current->mm);
7261da177e4SLinus Torvalds 		}
727484730e5SHelge Deller 		/* CPU could not fetch instruction, so clear stale IIR value. */
728484730e5SHelge Deller 		regs->iir = 0xbaadf00d;
729df561f66SGustavo A. R. Silva 		fallthrough;
7301da177e4SLinus Torvalds 	case 27:
7311da177e4SLinus Torvalds 		/* Data memory protection ID trap */
732c61c25ebSKyle McMartin 		if (code == 27 && !user_mode(regs) &&
733c61c25ebSKyle McMartin 			fixup_exception(regs))
734c61c25ebSKyle McMartin 			return;
735c61c25ebSKyle McMartin 
7361da177e4SLinus Torvalds 		die_if_kernel("Protection id trap", regs, code);
737ccf75290SEric W. Biederman 		force_sig_fault(SIGSEGV, SEGV_MAPERR,
738ccf75290SEric W. Biederman 				(code == 7)?
739ccf75290SEric W. Biederman 				((void __user *) regs->iaoq[0]) :
7402e1661d2SEric W. Biederman 				((void __user *) regs->ior));
7411da177e4SLinus Torvalds 		return;
7421da177e4SLinus Torvalds 
7431da177e4SLinus Torvalds 	case 28:
7441da177e4SLinus Torvalds 		/* Unaligned data reference trap */
7451da177e4SLinus Torvalds 		handle_unaligned(regs);
7461da177e4SLinus Torvalds 		return;
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 	default:
7491da177e4SLinus Torvalds 		if (user_mode(regs)) {
750fef47e2aSHelge Deller 			parisc_printk_ratelimited(0, regs, KERN_DEBUG
751fef47e2aSHelge Deller 				"handle_interruption() pid=%d command='%s'\n",
75219c5870cSAlexey Dobriyan 				task_pid_nr(current), current->comm);
7531da177e4SLinus Torvalds 			/* SIGBUS, for lack of a better one. */
754ccf75290SEric W. Biederman 			force_sig_fault(SIGBUS, BUS_OBJERR,
7552e1661d2SEric W. Biederman 					(void __user *)regs->ior);
7561da177e4SLinus Torvalds 			return;
7571da177e4SLinus Torvalds 		}
7581da177e4SLinus Torvalds 		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds 		parisc_terminate("Unexpected interruption", regs, code, 0);
7611da177e4SLinus Torvalds 		/* NOT REACHED */
7621da177e4SLinus Torvalds 	}
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	if (user_mode(regs)) {
7651da177e4SLinus Torvalds 	    if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) {
766fef47e2aSHelge Deller 		parisc_printk_ratelimited(0, regs, KERN_DEBUG
767fef47e2aSHelge Deller 				"User fault %d on space 0x%08lx, pid=%d command='%s'\n",
768fef47e2aSHelge Deller 				code, fault_space,
769ad361c98SJoe Perches 				task_pid_nr(current), current->comm);
770ccf75290SEric W. Biederman 		force_sig_fault(SIGSEGV, SEGV_MAPERR,
7712e1661d2SEric W. Biederman 				(void __user *)regs->ior);
7721da177e4SLinus Torvalds 		return;
7731da177e4SLinus Torvalds 	    }
7741da177e4SLinus Torvalds 	}
7751da177e4SLinus Torvalds 	else {
7761da177e4SLinus Torvalds 
7771da177e4SLinus Torvalds 	    /*
77859b33f14SHelge Deller 	     * The kernel should never fault on its own address space,
77959b33f14SHelge Deller 	     * unless pagefault_disable() was called before.
7801da177e4SLinus Torvalds 	     */
7811da177e4SLinus Torvalds 
7829e9d4b46SJohn David Anglin 	    if (faulthandler_disabled() || fault_space == 0)
7831da177e4SLinus Torvalds 	    {
784ef72f311SHelge Deller 		/* Clean up and return if in exception table. */
785ef72f311SHelge Deller 		if (fixup_exception(regs))
786ef72f311SHelge Deller 			return;
787ec5c1150SHelge Deller 		/* Clean up and return if handled by kfence. */
788ec5c1150SHelge Deller 		if (kfence_handle_page_fault(fault_address,
789ec5c1150SHelge Deller 			parisc_acctyp(code, regs->iir) == VM_WRITE, regs))
790ec5c1150SHelge Deller 			return;
7911da177e4SLinus Torvalds 		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
7921da177e4SLinus Torvalds 		parisc_terminate("Kernel Fault", regs, code, fault_address);
7931da177e4SLinus Torvalds 	    }
7941da177e4SLinus Torvalds 	}
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 	do_page_fault(regs, code, fault_address);
7971da177e4SLinus Torvalds }
7981da177e4SLinus Torvalds 
7991da177e4SLinus Torvalds 
initialize_ivt(const void * iva)8007def4239SHelge Deller static void __init initialize_ivt(const void *iva)
8011da177e4SLinus Torvalds {
802c3d4ed4eSKyle McMartin 	extern const u32 os_hpmc[];
803c3d4ed4eSKyle McMartin 
8041da177e4SLinus Torvalds 	int i;
8051da177e4SLinus Torvalds 	u32 check = 0;
8061da177e4SLinus Torvalds 	u32 *ivap;
807c70919bdSSven Schnelle 	u32 instr;
8081da177e4SLinus Torvalds 
8094182d0cdSHelge Deller 	if (strcmp((const char *)iva, "cows can fly"))
8104182d0cdSHelge Deller 		panic("IVT invalid");
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds 	ivap = (u32 *)iva;
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds 	for (i = 0; i < 8; i++)
8151da177e4SLinus Torvalds 	    *ivap++ = 0;
8161da177e4SLinus Torvalds 
8178d771b14SHelge Deller 	/*
8188d771b14SHelge Deller 	 * Use PDC_INSTR firmware function to get instruction that invokes
8198d771b14SHelge Deller 	 * PDCE_CHECK in HPMC handler.  See programming note at page 1-31 of
8208d771b14SHelge Deller 	 * the PA 1.1 Firmware Architecture document.
8218d771b14SHelge Deller 	 */
8228d771b14SHelge Deller 	if (pdc_instr(&instr) == PDC_OK)
8238d771b14SHelge Deller 		ivap[0] = instr;
8248d771b14SHelge Deller 
82541dbee81SHelge Deller 	/*
82641dbee81SHelge Deller 	 * Rules for the checksum of the HPMC handler:
82741dbee81SHelge Deller 	 * 1. The IVA does not point to PDC/PDH space (ie: the OS has installed
82841dbee81SHelge Deller 	 *    its own IVA).
82941dbee81SHelge Deller 	 * 2. The word at IVA + 32 is nonzero.
83041dbee81SHelge Deller 	 * 3. If Length (IVA + 60) is not zero, then Length (IVA + 60) and
83141dbee81SHelge Deller 	 *    Address (IVA + 56) are word-aligned.
83241dbee81SHelge Deller 	 * 4. The checksum of the 8 words starting at IVA + 32 plus the sum of
83341dbee81SHelge Deller 	 *    the Length/4 words starting at Address is zero.
83441dbee81SHelge Deller 	 */
83541dbee81SHelge Deller 
8361138b671SJohn David Anglin 	/* Setup IVA and compute checksum for HPMC handler */
8371138b671SJohn David Anglin 	ivap[6] = (u32)__pa(os_hpmc);
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	for (i=0; i<8; i++)
8401da177e4SLinus Torvalds 	    check += ivap[i];
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	ivap[5] = -check;
843c70919bdSSven Schnelle 	pr_debug("initialize_ivt: IVA[6] = 0x%08x\n", ivap[6]);
8441da177e4SLinus Torvalds }
8451da177e4SLinus Torvalds 
8464182d0cdSHelge Deller 
8474182d0cdSHelge Deller /* early_trap_init() is called before we set up kernel mappings and
8484182d0cdSHelge Deller  * write-protect the kernel */
early_trap_init(void)8494182d0cdSHelge Deller void  __init early_trap_init(void)
8504182d0cdSHelge Deller {
8514182d0cdSHelge Deller 	extern const void fault_vector_20;
8524182d0cdSHelge Deller 
853a8f44e38SHelge Deller #ifndef CONFIG_64BIT
8541da177e4SLinus Torvalds 	extern const void fault_vector_11;
8554182d0cdSHelge Deller 	initialize_ivt(&fault_vector_11);
8561da177e4SLinus Torvalds #endif
8574182d0cdSHelge Deller 
8584182d0cdSHelge Deller 	initialize_ivt(&fault_vector_20);
8594182d0cdSHelge Deller }
860