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