18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/parisc/traps.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 68c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * 'Traps.c' handles hardware traps and faults after we have saved some 118c2ecf20Sopenharmony_ci * state in 'asm.s'. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/sched.h> 158c2ecf20Sopenharmony_ci#include <linux/sched/debug.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/errno.h> 198c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 208c2ecf20Sopenharmony_ci#include <linux/timer.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/mm.h> 238c2ecf20Sopenharmony_ci#include <linux/module.h> 248c2ecf20Sopenharmony_ci#include <linux/smp.h> 258c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 268c2ecf20Sopenharmony_ci#include <linux/init.h> 278c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 288c2ecf20Sopenharmony_ci#include <linux/console.h> 298c2ecf20Sopenharmony_ci#include <linux/bug.h> 308c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 318c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 328c2ecf20Sopenharmony_ci#include <linux/kdebug.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <asm/assembly.h> 358c2ecf20Sopenharmony_ci#include <asm/io.h> 368c2ecf20Sopenharmony_ci#include <asm/irq.h> 378c2ecf20Sopenharmony_ci#include <asm/traps.h> 388c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 398c2ecf20Sopenharmony_ci#include <linux/atomic.h> 408c2ecf20Sopenharmony_ci#include <asm/smp.h> 418c2ecf20Sopenharmony_ci#include <asm/pdc.h> 428c2ecf20Sopenharmony_ci#include <asm/pdc_chassis.h> 438c2ecf20Sopenharmony_ci#include <asm/unwind.h> 448c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 458c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 468c2ecf20Sopenharmony_ci#include <linux/kgdb.h> 478c2ecf20Sopenharmony_ci#include <linux/kprobes.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include "../math-emu/math-emu.h" /* for handle_fpe() */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void parisc_show_stack(struct task_struct *task, 528c2ecf20Sopenharmony_ci struct pt_regs *regs, const char *loglvl); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int printbinary(char *buf, unsigned long x, int nbits) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci unsigned long mask = 1UL << (nbits - 1); 578c2ecf20Sopenharmony_ci while (mask != 0) { 588c2ecf20Sopenharmony_ci *buf++ = (mask & x ? '1' : '0'); 598c2ecf20Sopenharmony_ci mask >>= 1; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci *buf = '\0'; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return nbits; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 678c2ecf20Sopenharmony_ci#define RFMT "%016lx" 688c2ecf20Sopenharmony_ci#else 698c2ecf20Sopenharmony_ci#define RFMT "%08lx" 708c2ecf20Sopenharmony_ci#endif 718c2ecf20Sopenharmony_ci#define FFMT "%016llx" /* fpregs are 64-bit always */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define PRINTREGS(lvl,r,f,fmt,x) \ 748c2ecf20Sopenharmony_ci printk("%s%s%02d-%02d " fmt " " fmt " " fmt " " fmt "\n", \ 758c2ecf20Sopenharmony_ci lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1], \ 768c2ecf20Sopenharmony_ci (r)[(x)+2], (r)[(x)+3]) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic void print_gr(const char *level, struct pt_regs *regs) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int i; 818c2ecf20Sopenharmony_ci char buf[64]; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci printk("%s\n", level); 848c2ecf20Sopenharmony_ci printk("%s YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level); 858c2ecf20Sopenharmony_ci printbinary(buf, regs->gr[0], 32); 868c2ecf20Sopenharmony_ci printk("%sPSW: %s %s\n", level, buf, print_tainted()); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci for (i = 0; i < 32; i += 4) 898c2ecf20Sopenharmony_ci PRINTREGS(level, regs->gr, "r", RFMT, i); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic void print_fr(const char *level, struct pt_regs *regs) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int i; 958c2ecf20Sopenharmony_ci char buf[64]; 968c2ecf20Sopenharmony_ci struct { u32 sw[2]; } s; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* FR are 64bit everywhere. Need to use asm to get the content 998c2ecf20Sopenharmony_ci * of fpsr/fper1, and we assume that we won't have a FP Identify 1008c2ecf20Sopenharmony_ci * in our way, otherwise we're screwed. 1018c2ecf20Sopenharmony_ci * The fldd is used to restore the T-bit if there was one, as the 1028c2ecf20Sopenharmony_ci * store clears it anyway. 1038c2ecf20Sopenharmony_ci * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */ 1048c2ecf20Sopenharmony_ci asm volatile ("fstd %%fr0,0(%1) \n\t" 1058c2ecf20Sopenharmony_ci "fldd 0(%1),%%fr0 \n\t" 1068c2ecf20Sopenharmony_ci : "=m" (s) : "r" (&s) : "r0"); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci printk("%s\n", level); 1098c2ecf20Sopenharmony_ci printk("%s VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level); 1108c2ecf20Sopenharmony_ci printbinary(buf, s.sw[0], 32); 1118c2ecf20Sopenharmony_ci printk("%sFPSR: %s\n", level, buf); 1128c2ecf20Sopenharmony_ci printk("%sFPER1: %08x\n", level, s.sw[1]); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* here we'll print fr0 again, tho it'll be meaningless */ 1158c2ecf20Sopenharmony_ci for (i = 0; i < 32; i += 4) 1168c2ecf20Sopenharmony_ci PRINTREGS(level, regs->fr, "fr", FFMT, i); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid show_regs(struct pt_regs *regs) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci int i, user; 1228c2ecf20Sopenharmony_ci const char *level; 1238c2ecf20Sopenharmony_ci unsigned long cr30, cr31; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci user = user_mode(regs); 1268c2ecf20Sopenharmony_ci level = user ? KERN_DEBUG : KERN_CRIT; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci show_regs_print_info(level); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci print_gr(level, regs); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci for (i = 0; i < 8; i += 4) 1338c2ecf20Sopenharmony_ci PRINTREGS(level, regs->sr, "sr", RFMT, i); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (user) 1368c2ecf20Sopenharmony_ci print_fr(level, regs); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci cr30 = mfctl(30); 1398c2ecf20Sopenharmony_ci cr31 = mfctl(31); 1408c2ecf20Sopenharmony_ci printk("%s\n", level); 1418c2ecf20Sopenharmony_ci printk("%sIASQ: " RFMT " " RFMT " IAOQ: " RFMT " " RFMT "\n", 1428c2ecf20Sopenharmony_ci level, regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]); 1438c2ecf20Sopenharmony_ci printk("%s IIR: %08lx ISR: " RFMT " IOR: " RFMT "\n", 1448c2ecf20Sopenharmony_ci level, regs->iir, regs->isr, regs->ior); 1458c2ecf20Sopenharmony_ci printk("%s CPU: %8d CR30: " RFMT " CR31: " RFMT "\n", 1468c2ecf20Sopenharmony_ci level, current_thread_info()->cpu, cr30, cr31); 1478c2ecf20Sopenharmony_ci printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (user) { 1508c2ecf20Sopenharmony_ci printk("%s IAOQ[0]: " RFMT "\n", level, regs->iaoq[0]); 1518c2ecf20Sopenharmony_ci printk("%s IAOQ[1]: " RFMT "\n", level, regs->iaoq[1]); 1528c2ecf20Sopenharmony_ci printk("%s RP(r2): " RFMT "\n", level, regs->gr[2]); 1538c2ecf20Sopenharmony_ci } else { 1548c2ecf20Sopenharmony_ci printk("%s IAOQ[0]: %pS\n", level, (void *) regs->iaoq[0]); 1558c2ecf20Sopenharmony_ci printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]); 1568c2ecf20Sopenharmony_ci printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci parisc_show_stack(current, regs, KERN_DEFAULT); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic DEFINE_RATELIMIT_STATE(_hppa_rs, 1638c2ecf20Sopenharmony_ci DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define parisc_printk_ratelimited(critical, regs, fmt, ...) { \ 1668c2ecf20Sopenharmony_ci if ((critical || show_unhandled_signals) && __ratelimit(&_hppa_rs)) { \ 1678c2ecf20Sopenharmony_ci printk(fmt, ##__VA_ARGS__); \ 1688c2ecf20Sopenharmony_ci show_regs(regs); \ 1698c2ecf20Sopenharmony_ci } \ 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void do_show_stack(struct unwind_frame_info *info, const char *loglvl) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci int i = 1; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci printk("%sBacktrace:\n", loglvl); 1788c2ecf20Sopenharmony_ci while (i <= MAX_UNWIND_ENTRIES) { 1798c2ecf20Sopenharmony_ci if (unwind_once(info) < 0 || info->ip == 0) 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (__kernel_text_address(info->ip)) { 1838c2ecf20Sopenharmony_ci printk("%s [<" RFMT ">] %pS\n", 1848c2ecf20Sopenharmony_ci loglvl, info->ip, (void *) info->ip); 1858c2ecf20Sopenharmony_ci i++; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci printk("%s\n", loglvl); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic void parisc_show_stack(struct task_struct *task, 1928c2ecf20Sopenharmony_ci struct pt_regs *regs, const char *loglvl) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct unwind_frame_info info; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci unwind_frame_init_task(&info, task, regs); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci do_show_stack(&info, loglvl); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_civoid show_stack(struct task_struct *t, unsigned long *sp, const char *loglvl) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci parisc_show_stack(t, NULL, loglvl); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ciint is_valid_bugaddr(unsigned long iaoq) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci return 1; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_civoid die_if_kernel(char *str, struct pt_regs *regs, long err) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci if (user_mode(regs)) { 2148c2ecf20Sopenharmony_ci if (err == 0) 2158c2ecf20Sopenharmony_ci return; /* STFU */ 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci parisc_printk_ratelimited(1, regs, 2188c2ecf20Sopenharmony_ci KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n", 2198c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current), str, err, regs->iaoq[0]); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci bust_spinlocks(1); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci oops_enter(); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Amuse the user in a SPARC fashion */ 2298c2ecf20Sopenharmony_ci if (err) printk(KERN_CRIT 2308c2ecf20Sopenharmony_ci " _______________________________ \n" 2318c2ecf20Sopenharmony_ci " < Your System ate a SPARC! Gah! >\n" 2328c2ecf20Sopenharmony_ci " ------------------------------- \n" 2338c2ecf20Sopenharmony_ci " \\ ^__^\n" 2348c2ecf20Sopenharmony_ci " (__)\\ )\\/\\\n" 2358c2ecf20Sopenharmony_ci " U ||----w |\n" 2368c2ecf20Sopenharmony_ci " || ||\n"); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* unlock the pdc lock if necessary */ 2398c2ecf20Sopenharmony_ci pdc_emergency_unlock(); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* maybe the kernel hasn't booted very far yet and hasn't been able 2428c2ecf20Sopenharmony_ci * to initialize the serial or STI console. In that case we should 2438c2ecf20Sopenharmony_ci * re-enable the pdc console, so that the user will be able to 2448c2ecf20Sopenharmony_ci * identify the problem. */ 2458c2ecf20Sopenharmony_ci if (!console_drivers) 2468c2ecf20Sopenharmony_ci pdc_console_restart(); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (err) 2498c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", 2508c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current), str, err); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Wot's wrong wif bein' racy? */ 2538c2ecf20Sopenharmony_ci if (current->thread.flags & PARISC_KERNEL_DEATH) { 2548c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s() recursion detected.\n", __func__); 2558c2ecf20Sopenharmony_ci local_irq_enable(); 2568c2ecf20Sopenharmony_ci while (1); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci current->thread.flags |= PARISC_KERNEL_DEATH; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci show_regs(regs); 2618c2ecf20Sopenharmony_ci dump_stack(); 2628c2ecf20Sopenharmony_ci add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (in_interrupt()) 2658c2ecf20Sopenharmony_ci panic("Fatal exception in interrupt"); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (panic_on_oops) 2688c2ecf20Sopenharmony_ci panic("Fatal exception"); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci oops_exit(); 2718c2ecf20Sopenharmony_ci make_task_dead(SIGSEGV); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/* gdb uses break 4,8 */ 2758c2ecf20Sopenharmony_ci#define GDB_BREAK_INSN 0x10004 2768c2ecf20Sopenharmony_cistatic void handle_gdb_break(struct pt_regs *regs, int wot) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci force_sig_fault(SIGTRAP, wot, 2798c2ecf20Sopenharmony_ci (void __user *) (regs->iaoq[0] & ~3)); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void handle_break(struct pt_regs *regs) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci unsigned iir = regs->iir; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) { 2878c2ecf20Sopenharmony_ci /* check if a BUG() or WARN() trapped here. */ 2888c2ecf20Sopenharmony_ci enum bug_trap_type tt; 2898c2ecf20Sopenharmony_ci tt = report_bug(regs->iaoq[0] & ~3, regs); 2908c2ecf20Sopenharmony_ci if (tt == BUG_TRAP_TYPE_WARN) { 2918c2ecf20Sopenharmony_ci regs->iaoq[0] += 4; 2928c2ecf20Sopenharmony_ci regs->iaoq[1] += 4; 2938c2ecf20Sopenharmony_ci return; /* return to next instruction when WARN_ON(). */ 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci die_if_kernel("Unknown kernel breakpoint", regs, 2968c2ecf20Sopenharmony_ci (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci#ifdef CONFIG_KPROBES 3008c2ecf20Sopenharmony_ci if (unlikely(iir == PARISC_KPROBES_BREAK_INSN)) { 3018c2ecf20Sopenharmony_ci parisc_kprobe_break_handler(regs); 3028c2ecf20Sopenharmony_ci return; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci#endif 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci#ifdef CONFIG_KGDB 3088c2ecf20Sopenharmony_ci if (unlikely((iir == PARISC_KGDB_COMPILED_BREAK_INSN || 3098c2ecf20Sopenharmony_ci iir == PARISC_KGDB_BREAK_INSN)) && !user_mode(regs)) { 3108c2ecf20Sopenharmony_ci kgdb_handle_exception(9, SIGTRAP, 0, regs); 3118c2ecf20Sopenharmony_ci return; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci#endif 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (unlikely(iir != GDB_BREAK_INSN)) 3168c2ecf20Sopenharmony_ci parisc_printk_ratelimited(0, regs, 3178c2ecf20Sopenharmony_ci KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", 3188c2ecf20Sopenharmony_ci iir & 31, (iir>>13) & ((1<<13)-1), 3198c2ecf20Sopenharmony_ci task_pid_nr(current), current->comm); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* send standard GDB signal */ 3228c2ecf20Sopenharmony_ci handle_gdb_break(regs, TRAP_BRKPT); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic void default_trap(int code, struct pt_regs *regs) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci printk(KERN_ERR "Trap %d on CPU %d\n", code, smp_processor_id()); 3288c2ecf20Sopenharmony_ci show_regs(regs); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_civoid (*cpu_lpmc) (int code, struct pt_regs *regs) __read_mostly = default_trap; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_civoid transfer_pim_to_trap_frame(struct pt_regs *regs) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci register int i; 3378c2ecf20Sopenharmony_ci extern unsigned int hpmc_pim_data[]; 3388c2ecf20Sopenharmony_ci struct pdc_hpmc_pim_11 *pim_narrow; 3398c2ecf20Sopenharmony_ci struct pdc_hpmc_pim_20 *pim_wide; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (boot_cpu_data.cpu_type >= pcxu) { 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* 3468c2ecf20Sopenharmony_ci * Note: The following code will probably generate a 3478c2ecf20Sopenharmony_ci * bunch of truncation error warnings from the compiler. 3488c2ecf20Sopenharmony_ci * Could be handled with an ifdef, but perhaps there 3498c2ecf20Sopenharmony_ci * is a better way. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci regs->gr[0] = pim_wide->cr[22]; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci for (i = 1; i < 32; i++) 3558c2ecf20Sopenharmony_ci regs->gr[i] = pim_wide->gr[i]; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) 3588c2ecf20Sopenharmony_ci regs->fr[i] = pim_wide->fr[i]; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 3618c2ecf20Sopenharmony_ci regs->sr[i] = pim_wide->sr[i]; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci regs->iasq[0] = pim_wide->cr[17]; 3648c2ecf20Sopenharmony_ci regs->iasq[1] = pim_wide->iasq_back; 3658c2ecf20Sopenharmony_ci regs->iaoq[0] = pim_wide->cr[18]; 3668c2ecf20Sopenharmony_ci regs->iaoq[1] = pim_wide->iaoq_back; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci regs->sar = pim_wide->cr[11]; 3698c2ecf20Sopenharmony_ci regs->iir = pim_wide->cr[19]; 3708c2ecf20Sopenharmony_ci regs->isr = pim_wide->cr[20]; 3718c2ecf20Sopenharmony_ci regs->ior = pim_wide->cr[21]; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci else { 3748c2ecf20Sopenharmony_ci pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci regs->gr[0] = pim_narrow->cr[22]; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci for (i = 1; i < 32; i++) 3798c2ecf20Sopenharmony_ci regs->gr[i] = pim_narrow->gr[i]; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) 3828c2ecf20Sopenharmony_ci regs->fr[i] = pim_narrow->fr[i]; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 3858c2ecf20Sopenharmony_ci regs->sr[i] = pim_narrow->sr[i]; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci regs->iasq[0] = pim_narrow->cr[17]; 3888c2ecf20Sopenharmony_ci regs->iasq[1] = pim_narrow->iasq_back; 3898c2ecf20Sopenharmony_ci regs->iaoq[0] = pim_narrow->cr[18]; 3908c2ecf20Sopenharmony_ci regs->iaoq[1] = pim_narrow->iaoq_back; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci regs->sar = pim_narrow->cr[11]; 3938c2ecf20Sopenharmony_ci regs->iir = pim_narrow->cr[19]; 3948c2ecf20Sopenharmony_ci regs->isr = pim_narrow->cr[20]; 3958c2ecf20Sopenharmony_ci regs->ior = pim_narrow->cr[21]; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * The following fields only have meaning if we came through 4008c2ecf20Sopenharmony_ci * another path. So just zero them here. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci regs->ksp = 0; 4048c2ecf20Sopenharmony_ci regs->kpc = 0; 4058c2ecf20Sopenharmony_ci regs->orig_r28 = 0; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* 4108c2ecf20Sopenharmony_ci * This routine is called as a last resort when everything else 4118c2ecf20Sopenharmony_ci * has gone clearly wrong. We get called for faults in kernel space, 4128c2ecf20Sopenharmony_ci * and HPMC's. 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_civoid parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci static DEFINE_SPINLOCK(terminate_lock); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci (void)notify_die(DIE_OOPS, msg, regs, 0, code, SIGTRAP); 4198c2ecf20Sopenharmony_ci bust_spinlocks(1); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci set_eiem(0); 4228c2ecf20Sopenharmony_ci local_irq_disable(); 4238c2ecf20Sopenharmony_ci spin_lock(&terminate_lock); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* unlock the pdc lock if necessary */ 4268c2ecf20Sopenharmony_ci pdc_emergency_unlock(); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* restart pdc console if necessary */ 4298c2ecf20Sopenharmony_ci if (!console_drivers) 4308c2ecf20Sopenharmony_ci pdc_console_restart(); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* Not all paths will gutter the processor... */ 4338c2ecf20Sopenharmony_ci switch(code){ 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci case 1: 4368c2ecf20Sopenharmony_ci transfer_pim_to_trap_frame(regs); 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci default: 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci { 4458c2ecf20Sopenharmony_ci /* show_stack(NULL, (unsigned long *)regs->gr[30]); */ 4468c2ecf20Sopenharmony_ci struct unwind_frame_info info; 4478c2ecf20Sopenharmony_ci unwind_frame_init(&info, current, regs); 4488c2ecf20Sopenharmony_ci do_show_stack(&info, KERN_CRIT); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci printk("\n"); 4528c2ecf20Sopenharmony_ci pr_crit("%s: Code=%d (%s) at addr " RFMT "\n", 4538c2ecf20Sopenharmony_ci msg, code, trap_name(code), offset); 4548c2ecf20Sopenharmony_ci show_regs(regs); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci spin_unlock(&terminate_lock); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* put soft power button back under hardware control; 4598c2ecf20Sopenharmony_ci * if the user had pressed it once at any time, the 4608c2ecf20Sopenharmony_ci * system will shut down immediately right here. */ 4618c2ecf20Sopenharmony_ci pdc_soft_power_button(0); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* Call kernel panic() so reboot timeouts work properly 4648c2ecf20Sopenharmony_ci * FIXME: This function should be on the list of 4658c2ecf20Sopenharmony_ci * panic notifiers, and we should call panic 4668c2ecf20Sopenharmony_ci * directly from the location that we wish. 4678c2ecf20Sopenharmony_ci * e.g. We should not call panic from 4688c2ecf20Sopenharmony_ci * parisc_terminate, but rather the oter way around. 4698c2ecf20Sopenharmony_ci * This hack works, prints the panic message twice, 4708c2ecf20Sopenharmony_ci * and it enables reboot timers! 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci panic(msg); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_civoid notrace handle_interruption(int code, struct pt_regs *regs) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci unsigned long fault_address = 0; 4788c2ecf20Sopenharmony_ci unsigned long fault_space = 0; 4798c2ecf20Sopenharmony_ci int si_code; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (code == 1) 4828c2ecf20Sopenharmony_ci pdc_console_restart(); /* switch back to pdc if HPMC */ 4838c2ecf20Sopenharmony_ci else 4848c2ecf20Sopenharmony_ci local_irq_enable(); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* Security check: 4878c2ecf20Sopenharmony_ci * If the priority level is still user, and the 4888c2ecf20Sopenharmony_ci * faulting space is not equal to the active space 4898c2ecf20Sopenharmony_ci * then the user is attempting something in a space 4908c2ecf20Sopenharmony_ci * that does not belong to them. Kill the process. 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * This is normally the situation when the user 4938c2ecf20Sopenharmony_ci * attempts to jump into the kernel space at the 4948c2ecf20Sopenharmony_ci * wrong offset, be it at the gateway page or a 4958c2ecf20Sopenharmony_ci * random location. 4968c2ecf20Sopenharmony_ci * 4978c2ecf20Sopenharmony_ci * We cannot normally signal the process because it 4988c2ecf20Sopenharmony_ci * could *be* on the gateway page, and processes 4998c2ecf20Sopenharmony_ci * executing on the gateway page can't have signals 5008c2ecf20Sopenharmony_ci * delivered. 5018c2ecf20Sopenharmony_ci * 5028c2ecf20Sopenharmony_ci * We merely readjust the address into the users 5038c2ecf20Sopenharmony_ci * space, at a destination address of zero, and 5048c2ecf20Sopenharmony_ci * allow processing to continue. 5058c2ecf20Sopenharmony_ci */ 5068c2ecf20Sopenharmony_ci if (((unsigned long)regs->iaoq[0] & 3) && 5078c2ecf20Sopenharmony_ci ((unsigned long)regs->iasq[0] != (unsigned long)regs->sr[7])) { 5088c2ecf20Sopenharmony_ci /* Kill the user process later */ 5098c2ecf20Sopenharmony_ci regs->iaoq[0] = 0 | 3; 5108c2ecf20Sopenharmony_ci regs->iaoq[1] = regs->iaoq[0] + 4; 5118c2ecf20Sopenharmony_ci regs->iasq[0] = regs->iasq[1] = regs->sr[7]; 5128c2ecf20Sopenharmony_ci regs->gr[0] &= ~PSW_B; 5138c2ecf20Sopenharmony_ci return; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci#if 0 5178c2ecf20Sopenharmony_ci printk(KERN_CRIT "Interruption # %d\n", code); 5188c2ecf20Sopenharmony_ci#endif 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci switch(code) { 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci case 1: 5238c2ecf20Sopenharmony_ci /* High-priority machine check (HPMC) */ 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* set up a new led state on systems shipped with a LED State panel */ 5268c2ecf20Sopenharmony_ci pdc_chassis_send_status(PDC_CHASSIS_DIRECT_HPMC); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci parisc_terminate("High Priority Machine Check (HPMC)", 5298c2ecf20Sopenharmony_ci regs, code, 0); 5308c2ecf20Sopenharmony_ci /* NOT REACHED */ 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci case 2: 5338c2ecf20Sopenharmony_ci /* Power failure interrupt */ 5348c2ecf20Sopenharmony_ci printk(KERN_CRIT "Power failure interrupt !\n"); 5358c2ecf20Sopenharmony_ci return; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci case 3: 5388c2ecf20Sopenharmony_ci /* Recovery counter trap */ 5398c2ecf20Sopenharmony_ci regs->gr[0] &= ~PSW_R; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci#ifdef CONFIG_KPROBES 5428c2ecf20Sopenharmony_ci if (parisc_kprobe_ss_handler(regs)) 5438c2ecf20Sopenharmony_ci return; 5448c2ecf20Sopenharmony_ci#endif 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci#ifdef CONFIG_KGDB 5478c2ecf20Sopenharmony_ci if (kgdb_single_step) { 5488c2ecf20Sopenharmony_ci kgdb_handle_exception(0, SIGTRAP, 0, regs); 5498c2ecf20Sopenharmony_ci return; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci#endif 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (user_space(regs)) 5548c2ecf20Sopenharmony_ci handle_gdb_break(regs, TRAP_TRACE); 5558c2ecf20Sopenharmony_ci /* else this must be the start of a syscall - just let it run */ 5568c2ecf20Sopenharmony_ci return; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci case 5: 5598c2ecf20Sopenharmony_ci /* Low-priority machine check */ 5608c2ecf20Sopenharmony_ci pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci flush_cache_all(); 5638c2ecf20Sopenharmony_ci flush_tlb_all(); 5648c2ecf20Sopenharmony_ci cpu_lpmc(5, regs); 5658c2ecf20Sopenharmony_ci return; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci case PARISC_ITLB_TRAP: 5688c2ecf20Sopenharmony_ci /* Instruction TLB miss fault/Instruction page fault */ 5698c2ecf20Sopenharmony_ci fault_address = regs->iaoq[0]; 5708c2ecf20Sopenharmony_ci fault_space = regs->iasq[0]; 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci case 8: 5748c2ecf20Sopenharmony_ci /* Illegal instruction trap */ 5758c2ecf20Sopenharmony_ci die_if_kernel("Illegal instruction", regs, code); 5768c2ecf20Sopenharmony_ci si_code = ILL_ILLOPC; 5778c2ecf20Sopenharmony_ci goto give_sigill; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci case 9: 5808c2ecf20Sopenharmony_ci /* Break instruction trap */ 5818c2ecf20Sopenharmony_ci handle_break(regs); 5828c2ecf20Sopenharmony_ci return; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci case 10: 5858c2ecf20Sopenharmony_ci /* Privileged operation trap */ 5868c2ecf20Sopenharmony_ci die_if_kernel("Privileged operation", regs, code); 5878c2ecf20Sopenharmony_ci si_code = ILL_PRVOPC; 5888c2ecf20Sopenharmony_ci goto give_sigill; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci case 11: 5918c2ecf20Sopenharmony_ci /* Privileged register trap */ 5928c2ecf20Sopenharmony_ci if ((regs->iir & 0xffdfffe0) == 0x034008a0) { 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* This is a MFCTL cr26/cr27 to gr instruction. 5958c2ecf20Sopenharmony_ci * PCXS traps on this, so we need to emulate it. 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (regs->iir & 0x00200000) 5998c2ecf20Sopenharmony_ci regs->gr[regs->iir & 0x1f] = mfctl(27); 6008c2ecf20Sopenharmony_ci else 6018c2ecf20Sopenharmony_ci regs->gr[regs->iir & 0x1f] = mfctl(26); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci regs->iaoq[0] = regs->iaoq[1]; 6048c2ecf20Sopenharmony_ci regs->iaoq[1] += 4; 6058c2ecf20Sopenharmony_ci regs->iasq[0] = regs->iasq[1]; 6068c2ecf20Sopenharmony_ci return; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci die_if_kernel("Privileged register usage", regs, code); 6108c2ecf20Sopenharmony_ci si_code = ILL_PRVREG; 6118c2ecf20Sopenharmony_ci give_sigill: 6128c2ecf20Sopenharmony_ci force_sig_fault(SIGILL, si_code, 6138c2ecf20Sopenharmony_ci (void __user *) regs->iaoq[0]); 6148c2ecf20Sopenharmony_ci return; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci case 12: 6178c2ecf20Sopenharmony_ci /* Overflow Trap, let the userland signal handler do the cleanup */ 6188c2ecf20Sopenharmony_ci force_sig_fault(SIGFPE, FPE_INTOVF, 6198c2ecf20Sopenharmony_ci (void __user *) regs->iaoq[0]); 6208c2ecf20Sopenharmony_ci return; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci case 13: 6238c2ecf20Sopenharmony_ci /* Conditional Trap 6248c2ecf20Sopenharmony_ci The condition succeeds in an instruction which traps 6258c2ecf20Sopenharmony_ci on condition */ 6268c2ecf20Sopenharmony_ci if(user_mode(regs)){ 6278c2ecf20Sopenharmony_ci /* Let userspace app figure it out from the insn pointed 6288c2ecf20Sopenharmony_ci * to by si_addr. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci force_sig_fault(SIGFPE, FPE_CONDTRAP, 6318c2ecf20Sopenharmony_ci (void __user *) regs->iaoq[0]); 6328c2ecf20Sopenharmony_ci return; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci /* The kernel doesn't want to handle condition codes */ 6358c2ecf20Sopenharmony_ci break; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci case 14: 6388c2ecf20Sopenharmony_ci /* Assist Exception Trap, i.e. floating point exception. */ 6398c2ecf20Sopenharmony_ci die_if_kernel("Floating point exception", regs, 0); /* quiet */ 6408c2ecf20Sopenharmony_ci __inc_irq_stat(irq_fpassist_count); 6418c2ecf20Sopenharmony_ci handle_fpe(regs); 6428c2ecf20Sopenharmony_ci return; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci case 15: 6458c2ecf20Sopenharmony_ci /* Data TLB miss fault/Data page fault */ 6468c2ecf20Sopenharmony_ci fallthrough; 6478c2ecf20Sopenharmony_ci case 16: 6488c2ecf20Sopenharmony_ci /* Non-access instruction TLB miss fault */ 6498c2ecf20Sopenharmony_ci /* The instruction TLB entry needed for the target address of the FIC 6508c2ecf20Sopenharmony_ci is absent, and hardware can't find it, so we get to cleanup */ 6518c2ecf20Sopenharmony_ci fallthrough; 6528c2ecf20Sopenharmony_ci case 17: 6538c2ecf20Sopenharmony_ci /* Non-access data TLB miss fault/Non-access data page fault */ 6548c2ecf20Sopenharmony_ci /* FIXME: 6558c2ecf20Sopenharmony_ci Still need to add slow path emulation code here! 6568c2ecf20Sopenharmony_ci If the insn used a non-shadow register, then the tlb 6578c2ecf20Sopenharmony_ci handlers could not have their side-effect (e.g. probe 6588c2ecf20Sopenharmony_ci writing to a target register) emulated since rfir would 6598c2ecf20Sopenharmony_ci erase the changes to said register. Instead we have to 6608c2ecf20Sopenharmony_ci setup everything, call this function we are in, and emulate 6618c2ecf20Sopenharmony_ci by hand. Technically we need to emulate: 6628c2ecf20Sopenharmony_ci fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw 6638c2ecf20Sopenharmony_ci */ 6648c2ecf20Sopenharmony_ci if (code == 17 && handle_nadtlb_fault(regs)) 6658c2ecf20Sopenharmony_ci return; 6668c2ecf20Sopenharmony_ci fault_address = regs->ior; 6678c2ecf20Sopenharmony_ci fault_space = regs->isr; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci case 18: 6718c2ecf20Sopenharmony_ci /* PCXS only -- later cpu's split this into types 26,27 & 28 */ 6728c2ecf20Sopenharmony_ci /* Check for unaligned access */ 6738c2ecf20Sopenharmony_ci if (check_unaligned(regs)) { 6748c2ecf20Sopenharmony_ci handle_unaligned(regs); 6758c2ecf20Sopenharmony_ci return; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci fallthrough; 6788c2ecf20Sopenharmony_ci case 26: 6798c2ecf20Sopenharmony_ci /* PCXL: Data memory access rights trap */ 6808c2ecf20Sopenharmony_ci fault_address = regs->ior; 6818c2ecf20Sopenharmony_ci fault_space = regs->isr; 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci case 19: 6858c2ecf20Sopenharmony_ci /* Data memory break trap */ 6868c2ecf20Sopenharmony_ci regs->gr[0] |= PSW_X; /* So we can single-step over the trap */ 6878c2ecf20Sopenharmony_ci fallthrough; 6888c2ecf20Sopenharmony_ci case 21: 6898c2ecf20Sopenharmony_ci /* Page reference trap */ 6908c2ecf20Sopenharmony_ci handle_gdb_break(regs, TRAP_HWBKPT); 6918c2ecf20Sopenharmony_ci return; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci case 25: 6948c2ecf20Sopenharmony_ci /* Taken branch trap */ 6958c2ecf20Sopenharmony_ci regs->gr[0] &= ~PSW_T; 6968c2ecf20Sopenharmony_ci if (user_space(regs)) 6978c2ecf20Sopenharmony_ci handle_gdb_break(regs, TRAP_BRANCH); 6988c2ecf20Sopenharmony_ci /* else this must be the start of a syscall - just let it 6998c2ecf20Sopenharmony_ci * run. 7008c2ecf20Sopenharmony_ci */ 7018c2ecf20Sopenharmony_ci return; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci case 7: 7048c2ecf20Sopenharmony_ci /* Instruction access rights */ 7058c2ecf20Sopenharmony_ci /* PCXL: Instruction memory protection trap */ 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* 7088c2ecf20Sopenharmony_ci * This could be caused by either: 1) a process attempting 7098c2ecf20Sopenharmony_ci * to execute within a vma that does not have execute 7108c2ecf20Sopenharmony_ci * permission, or 2) an access rights violation caused by a 7118c2ecf20Sopenharmony_ci * flush only translation set up by ptep_get_and_clear(). 7128c2ecf20Sopenharmony_ci * So we check the vma permissions to differentiate the two. 7138c2ecf20Sopenharmony_ci * If the vma indicates we have execute permission, then 7148c2ecf20Sopenharmony_ci * the cause is the latter one. In this case, we need to 7158c2ecf20Sopenharmony_ci * call do_page_fault() to fix the problem. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (user_mode(regs)) { 7198c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci mmap_read_lock(current->mm); 7228c2ecf20Sopenharmony_ci vma = find_vma(current->mm,regs->iaoq[0]); 7238c2ecf20Sopenharmony_ci if (vma && (regs->iaoq[0] >= vma->vm_start) 7248c2ecf20Sopenharmony_ci && (vma->vm_flags & VM_EXEC)) { 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci fault_address = regs->iaoq[0]; 7278c2ecf20Sopenharmony_ci fault_space = regs->iasq[0]; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 7308c2ecf20Sopenharmony_ci break; /* call do_page_fault() */ 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci /* CPU could not fetch instruction, so clear stale IIR value. */ 7358c2ecf20Sopenharmony_ci regs->iir = 0xbaadf00d; 7368c2ecf20Sopenharmony_ci fallthrough; 7378c2ecf20Sopenharmony_ci case 27: 7388c2ecf20Sopenharmony_ci /* Data memory protection ID trap */ 7398c2ecf20Sopenharmony_ci if (code == 27 && !user_mode(regs) && 7408c2ecf20Sopenharmony_ci fixup_exception(regs)) 7418c2ecf20Sopenharmony_ci return; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci die_if_kernel("Protection id trap", regs, code); 7448c2ecf20Sopenharmony_ci force_sig_fault(SIGSEGV, SEGV_MAPERR, 7458c2ecf20Sopenharmony_ci (code == 7)? 7468c2ecf20Sopenharmony_ci ((void __user *) regs->iaoq[0]) : 7478c2ecf20Sopenharmony_ci ((void __user *) regs->ior)); 7488c2ecf20Sopenharmony_ci return; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci case 28: 7518c2ecf20Sopenharmony_ci /* Unaligned data reference trap */ 7528c2ecf20Sopenharmony_ci handle_unaligned(regs); 7538c2ecf20Sopenharmony_ci return; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci default: 7568c2ecf20Sopenharmony_ci if (user_mode(regs)) { 7578c2ecf20Sopenharmony_ci parisc_printk_ratelimited(0, regs, KERN_DEBUG 7588c2ecf20Sopenharmony_ci "handle_interruption() pid=%d command='%s'\n", 7598c2ecf20Sopenharmony_ci task_pid_nr(current), current->comm); 7608c2ecf20Sopenharmony_ci /* SIGBUS, for lack of a better one. */ 7618c2ecf20Sopenharmony_ci force_sig_fault(SIGBUS, BUS_OBJERR, 7628c2ecf20Sopenharmony_ci (void __user *)regs->ior); 7638c2ecf20Sopenharmony_ci return; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci parisc_terminate("Unexpected interruption", regs, code, 0); 7688c2ecf20Sopenharmony_ci /* NOT REACHED */ 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (user_mode(regs)) { 7728c2ecf20Sopenharmony_ci if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) { 7738c2ecf20Sopenharmony_ci parisc_printk_ratelimited(0, regs, KERN_DEBUG 7748c2ecf20Sopenharmony_ci "User fault %d on space 0x%08lx, pid=%d command='%s'\n", 7758c2ecf20Sopenharmony_ci code, fault_space, 7768c2ecf20Sopenharmony_ci task_pid_nr(current), current->comm); 7778c2ecf20Sopenharmony_ci force_sig_fault(SIGSEGV, SEGV_MAPERR, 7788c2ecf20Sopenharmony_ci (void __user *)regs->ior); 7798c2ecf20Sopenharmony_ci return; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci else { 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* 7858c2ecf20Sopenharmony_ci * The kernel should never fault on its own address space, 7868c2ecf20Sopenharmony_ci * unless pagefault_disable() was called before. 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (faulthandler_disabled() || fault_space == 0) 7908c2ecf20Sopenharmony_ci { 7918c2ecf20Sopenharmony_ci /* Clean up and return if in exception table. */ 7928c2ecf20Sopenharmony_ci if (fixup_exception(regs)) 7938c2ecf20Sopenharmony_ci return; 7948c2ecf20Sopenharmony_ci pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC); 7958c2ecf20Sopenharmony_ci parisc_terminate("Kernel Fault", regs, code, fault_address); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci do_page_fault(regs, code, fault_address); 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_civoid __init initialize_ivt(const void *iva) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci extern u32 os_hpmc_size; 8068c2ecf20Sopenharmony_ci extern const u32 os_hpmc[]; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci int i; 8098c2ecf20Sopenharmony_ci u32 check = 0; 8108c2ecf20Sopenharmony_ci u32 *ivap; 8118c2ecf20Sopenharmony_ci u32 *hpmcp; 8128c2ecf20Sopenharmony_ci u32 length, instr; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (strcmp((const char *)iva, "cows can fly")) 8158c2ecf20Sopenharmony_ci panic("IVT invalid"); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci ivap = (u32 *)iva; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 8208c2ecf20Sopenharmony_ci *ivap++ = 0; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* 8238c2ecf20Sopenharmony_ci * Use PDC_INSTR firmware function to get instruction that invokes 8248c2ecf20Sopenharmony_ci * PDCE_CHECK in HPMC handler. See programming note at page 1-31 of 8258c2ecf20Sopenharmony_ci * the PA 1.1 Firmware Architecture document. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci if (pdc_instr(&instr) == PDC_OK) 8288c2ecf20Sopenharmony_ci ivap[0] = instr; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* 8318c2ecf20Sopenharmony_ci * Rules for the checksum of the HPMC handler: 8328c2ecf20Sopenharmony_ci * 1. The IVA does not point to PDC/PDH space (ie: the OS has installed 8338c2ecf20Sopenharmony_ci * its own IVA). 8348c2ecf20Sopenharmony_ci * 2. The word at IVA + 32 is nonzero. 8358c2ecf20Sopenharmony_ci * 3. If Length (IVA + 60) is not zero, then Length (IVA + 60) and 8368c2ecf20Sopenharmony_ci * Address (IVA + 56) are word-aligned. 8378c2ecf20Sopenharmony_ci * 4. The checksum of the 8 words starting at IVA + 32 plus the sum of 8388c2ecf20Sopenharmony_ci * the Length/4 words starting at Address is zero. 8398c2ecf20Sopenharmony_ci */ 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* Setup IVA and compute checksum for HPMC handler */ 8428c2ecf20Sopenharmony_ci ivap[6] = (u32)__pa(os_hpmc); 8438c2ecf20Sopenharmony_ci length = os_hpmc_size; 8448c2ecf20Sopenharmony_ci ivap[7] = length; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci hpmcp = (u32 *)os_hpmc; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci for (i=0; i<length/4; i++) 8498c2ecf20Sopenharmony_ci check += *hpmcp++; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci for (i=0; i<8; i++) 8528c2ecf20Sopenharmony_ci check += ivap[i]; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci ivap[5] = -check; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci/* early_trap_init() is called before we set up kernel mappings and 8598c2ecf20Sopenharmony_ci * write-protect the kernel */ 8608c2ecf20Sopenharmony_civoid __init early_trap_init(void) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci extern const void fault_vector_20; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci#ifndef CONFIG_64BIT 8658c2ecf20Sopenharmony_ci extern const void fault_vector_11; 8668c2ecf20Sopenharmony_ci initialize_ivt(&fault_vector_11); 8678c2ecf20Sopenharmony_ci#endif 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci initialize_ivt(&fault_vector_20); 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_civoid __init trap_init(void) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci} 875