18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Architecture-specific trap handling. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1998-2003 Hewlett-Packard Co 68c2ecf20Sopenharmony_ci * David Mosberger-Tang <davidm@hpl.hp.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 148c2ecf20Sopenharmony_ci#include <linux/sched/debug.h> 158c2ecf20Sopenharmony_ci#include <linux/tty.h> 168c2ecf20Sopenharmony_ci#include <linux/vt_kern.h> /* For unblank_screen() */ 178c2ecf20Sopenharmony_ci#include <linux/export.h> 188c2ecf20Sopenharmony_ci#include <linux/extable.h> 198c2ecf20Sopenharmony_ci#include <linux/hardirq.h> 208c2ecf20Sopenharmony_ci#include <linux/kprobes.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> /* for ssleep() */ 228c2ecf20Sopenharmony_ci#include <linux/kdebug.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <asm/fpswa.h> 268c2ecf20Sopenharmony_ci#include <asm/intrinsics.h> 278c2ecf20Sopenharmony_ci#include <asm/processor.h> 288c2ecf20Sopenharmony_ci#include <asm/exception.h> 298c2ecf20Sopenharmony_ci#include <asm/setup.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cifpswa_interface_t *fpswa_interface; 328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fpswa_interface); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_civoid __init 358c2ecf20Sopenharmony_citrap_init (void) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci if (ia64_boot_param->fpswa) 388c2ecf20Sopenharmony_ci /* FPSWA fixup: make the interface pointer a kernel virtual address: */ 398c2ecf20Sopenharmony_ci fpswa_interface = __va(ia64_boot_param->fpswa); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ciint 438c2ecf20Sopenharmony_cidie (const char *str, struct pt_regs *regs, long err) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci static struct { 468c2ecf20Sopenharmony_ci spinlock_t lock; 478c2ecf20Sopenharmony_ci u32 lock_owner; 488c2ecf20Sopenharmony_ci int lock_owner_depth; 498c2ecf20Sopenharmony_ci } die = { 508c2ecf20Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(die.lock), 518c2ecf20Sopenharmony_ci .lock_owner = -1, 528c2ecf20Sopenharmony_ci .lock_owner_depth = 0 538c2ecf20Sopenharmony_ci }; 548c2ecf20Sopenharmony_ci static int die_counter; 558c2ecf20Sopenharmony_ci int cpu = get_cpu(); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (die.lock_owner != cpu) { 588c2ecf20Sopenharmony_ci console_verbose(); 598c2ecf20Sopenharmony_ci spin_lock_irq(&die.lock); 608c2ecf20Sopenharmony_ci die.lock_owner = cpu; 618c2ecf20Sopenharmony_ci die.lock_owner_depth = 0; 628c2ecf20Sopenharmony_ci bust_spinlocks(1); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci put_cpu(); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (++die.lock_owner_depth < 3) { 678c2ecf20Sopenharmony_ci printk("%s[%d]: %s %ld [%d]\n", 688c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current), str, err, ++die_counter); 698c2ecf20Sopenharmony_ci if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) 708c2ecf20Sopenharmony_ci != NOTIFY_STOP) 718c2ecf20Sopenharmony_ci show_regs(regs); 728c2ecf20Sopenharmony_ci else 738c2ecf20Sopenharmony_ci regs = NULL; 748c2ecf20Sopenharmony_ci } else 758c2ecf20Sopenharmony_ci printk(KERN_ERR "Recursive die() failure, output suppressed\n"); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci bust_spinlocks(0); 788c2ecf20Sopenharmony_ci die.lock_owner = -1; 798c2ecf20Sopenharmony_ci add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); 808c2ecf20Sopenharmony_ci spin_unlock_irq(&die.lock); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (!regs) 838c2ecf20Sopenharmony_ci return 1; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (panic_on_oops) 868c2ecf20Sopenharmony_ci panic("Fatal exception"); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci make_task_dead(SIGSEGV); 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ciint 938c2ecf20Sopenharmony_cidie_if_kernel (char *str, struct pt_regs *regs, long err) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci if (!user_mode(regs)) 968c2ecf20Sopenharmony_ci return die(str, regs, err); 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_civoid 1018c2ecf20Sopenharmony_ci__kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci int sig, code; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci switch (break_num) { 1068c2ecf20Sopenharmony_ci case 0: /* unknown error (used by GCC for __builtin_abort()) */ 1078c2ecf20Sopenharmony_ci if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP) 1088c2ecf20Sopenharmony_ci == NOTIFY_STOP) 1098c2ecf20Sopenharmony_ci return; 1108c2ecf20Sopenharmony_ci if (die_if_kernel("bugcheck!", regs, break_num)) 1118c2ecf20Sopenharmony_ci return; 1128c2ecf20Sopenharmony_ci sig = SIGILL; code = ILL_ILLOPC; 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci case 1: /* integer divide by zero */ 1168c2ecf20Sopenharmony_ci sig = SIGFPE; code = FPE_INTDIV; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci case 2: /* integer overflow */ 1208c2ecf20Sopenharmony_ci sig = SIGFPE; code = FPE_INTOVF; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci case 3: /* range check/bounds check */ 1248c2ecf20Sopenharmony_ci sig = SIGFPE; code = FPE_FLTSUB; 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci case 4: /* null pointer dereference */ 1288c2ecf20Sopenharmony_ci sig = SIGSEGV; code = SEGV_MAPERR; 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci case 5: /* misaligned data */ 1328c2ecf20Sopenharmony_ci sig = SIGSEGV; code = BUS_ADRALN; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci case 6: /* decimal overflow */ 1368c2ecf20Sopenharmony_ci sig = SIGFPE; code = __FPE_DECOVF; 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci case 7: /* decimal divide by zero */ 1408c2ecf20Sopenharmony_ci sig = SIGFPE; code = __FPE_DECDIV; 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci case 8: /* packed decimal error */ 1448c2ecf20Sopenharmony_ci sig = SIGFPE; code = __FPE_DECERR; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci case 9: /* invalid ASCII digit */ 1488c2ecf20Sopenharmony_ci sig = SIGFPE; code = __FPE_INVASC; 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci case 10: /* invalid decimal digit */ 1528c2ecf20Sopenharmony_ci sig = SIGFPE; code = __FPE_INVDEC; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci case 11: /* paragraph stack overflow */ 1568c2ecf20Sopenharmony_ci sig = SIGSEGV; code = __SEGV_PSTKOVF; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci case 0x3f000 ... 0x3ffff: /* bundle-update in progress */ 1608c2ecf20Sopenharmony_ci sig = SIGILL; code = __ILL_BNDMOD; 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci default: 1648c2ecf20Sopenharmony_ci if ((break_num < 0x40000 || break_num > 0x100000) 1658c2ecf20Sopenharmony_ci && die_if_kernel("Bad break", regs, break_num)) 1668c2ecf20Sopenharmony_ci return; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (break_num < 0x80000) { 1698c2ecf20Sopenharmony_ci sig = SIGILL; code = __ILL_BREAK; 1708c2ecf20Sopenharmony_ci } else { 1718c2ecf20Sopenharmony_ci if (notify_die(DIE_BREAK, "bad break", regs, break_num, TRAP_BRKPT, SIGTRAP) 1728c2ecf20Sopenharmony_ci == NOTIFY_STOP) 1738c2ecf20Sopenharmony_ci return; 1748c2ecf20Sopenharmony_ci sig = SIGTRAP; code = TRAP_BRKPT; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci force_sig_fault(sig, code, 1788c2ecf20Sopenharmony_ci (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), 1798c2ecf20Sopenharmony_ci break_num, 0 /* clear __ISR_VALID */, 0); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * disabled_fph_fault() is called when a user-level process attempts to access f32..f127 1848c2ecf20Sopenharmony_ci * and it doesn't own the fp-high register partition. When this happens, we save the 1858c2ecf20Sopenharmony_ci * current fph partition in the task_struct of the fpu-owner (if necessary) and then load 1868c2ecf20Sopenharmony_ci * the fp-high partition of the current task (if necessary). Note that the kernel has 1878c2ecf20Sopenharmony_ci * access to fph by the time we get here, as the IVT's "Disabled FP-Register" handler takes 1888c2ecf20Sopenharmony_ci * care of clearing psr.dfh. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_cistatic inline void 1918c2ecf20Sopenharmony_cidisabled_fph_fault (struct pt_regs *regs) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct ia64_psr *psr = ia64_psr(regs); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* first, grant user-level access to fph partition: */ 1968c2ecf20Sopenharmony_ci psr->dfh = 0; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * Make sure that no other task gets in on this processor 2008c2ecf20Sopenharmony_ci * while we're claiming the FPU 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci preempt_disable(); 2038c2ecf20Sopenharmony_ci#ifndef CONFIG_SMP 2048c2ecf20Sopenharmony_ci { 2058c2ecf20Sopenharmony_ci struct task_struct *fpu_owner 2068c2ecf20Sopenharmony_ci = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (ia64_is_local_fpu_owner(current)) { 2098c2ecf20Sopenharmony_ci preempt_enable_no_resched(); 2108c2ecf20Sopenharmony_ci return; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (fpu_owner) 2148c2ecf20Sopenharmony_ci ia64_flush_fph(fpu_owner); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci#endif /* !CONFIG_SMP */ 2178c2ecf20Sopenharmony_ci ia64_set_local_fpu_owner(current); 2188c2ecf20Sopenharmony_ci if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { 2198c2ecf20Sopenharmony_ci __ia64_load_fpu(current->thread.fph); 2208c2ecf20Sopenharmony_ci psr->mfh = 0; 2218c2ecf20Sopenharmony_ci } else { 2228c2ecf20Sopenharmony_ci __ia64_init_fpu(); 2238c2ecf20Sopenharmony_ci /* 2248c2ecf20Sopenharmony_ci * Set mfh because the state in thread.fph does not match the state in 2258c2ecf20Sopenharmony_ci * the fph partition. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci psr->mfh = 1; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci preempt_enable_no_resched(); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic inline int 2338c2ecf20Sopenharmony_cifp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs, 2348c2ecf20Sopenharmony_ci struct pt_regs *regs) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci fp_state_t fp_state; 2378c2ecf20Sopenharmony_ci fpswa_ret_t ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (!fpswa_interface) 2408c2ecf20Sopenharmony_ci return -1; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci memset(&fp_state, 0, sizeof(fp_state_t)); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * compute fp_state. only FP registers f6 - f11 are used by the 2468c2ecf20Sopenharmony_ci * kernel, so set those bits in the mask and set the low volatile 2478c2ecf20Sopenharmony_ci * pointer to point to these registers. 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */ 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6; 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * unsigned long (*EFI_FPSWA) ( 2548c2ecf20Sopenharmony_ci * unsigned long trap_type, 2558c2ecf20Sopenharmony_ci * void *Bundle, 2568c2ecf20Sopenharmony_ci * unsigned long *pipsr, 2578c2ecf20Sopenharmony_ci * unsigned long *pfsr, 2588c2ecf20Sopenharmony_ci * unsigned long *pisr, 2598c2ecf20Sopenharmony_ci * unsigned long *ppreds, 2608c2ecf20Sopenharmony_ci * unsigned long *pifs, 2618c2ecf20Sopenharmony_ci * void *fp_state); 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ci ret = (*fpswa_interface->fpswa)((unsigned long) fp_fault, bundle, 2648c2ecf20Sopenharmony_ci (unsigned long *) ipsr, (unsigned long *) fpsr, 2658c2ecf20Sopenharmony_ci (unsigned long *) isr, (unsigned long *) pr, 2668c2ecf20Sopenharmony_ci (unsigned long *) ifs, &fp_state); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return ret.status; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistruct fpu_swa_msg { 2728c2ecf20Sopenharmony_ci unsigned long count; 2738c2ecf20Sopenharmony_ci unsigned long time; 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct fpu_swa_msg, cpulast); 2768c2ecf20Sopenharmony_ciDECLARE_PER_CPU(struct fpu_swa_msg, cpulast); 2778c2ecf20Sopenharmony_cistatic struct fpu_swa_msg last __cacheline_aligned; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/* 2818c2ecf20Sopenharmony_ci * Handle floating-point assist faults and traps. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_cistatic int 2848c2ecf20Sopenharmony_cihandle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci long exception, bundle[2]; 2878c2ecf20Sopenharmony_ci unsigned long fault_ip; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci fault_ip = regs->cr_iip; 2908c2ecf20Sopenharmony_ci if (!fp_fault && (ia64_psr(regs)->ri == 0)) 2918c2ecf20Sopenharmony_ci fault_ip -= 16; 2928c2ecf20Sopenharmony_ci if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle))) 2938c2ecf20Sopenharmony_ci return -1; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (!(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { 2968c2ecf20Sopenharmony_ci unsigned long count, current_jiffies = jiffies; 2978c2ecf20Sopenharmony_ci struct fpu_swa_msg *cp = this_cpu_ptr(&cpulast); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (unlikely(current_jiffies > cp->time)) 3008c2ecf20Sopenharmony_ci cp->count = 0; 3018c2ecf20Sopenharmony_ci if (unlikely(cp->count < 5)) { 3028c2ecf20Sopenharmony_ci cp->count++; 3038c2ecf20Sopenharmony_ci cp->time = current_jiffies + 5 * HZ; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* minimize races by grabbing a copy of count BEFORE checking last.time. */ 3068c2ecf20Sopenharmony_ci count = last.count; 3078c2ecf20Sopenharmony_ci barrier(); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* 3108c2ecf20Sopenharmony_ci * Lower 4 bits are used as a count. Upper bits are a sequence 3118c2ecf20Sopenharmony_ci * number that is updated when count is reset. The cmpxchg will 3128c2ecf20Sopenharmony_ci * fail is seqno has changed. This minimizes mutiple cpus 3138c2ecf20Sopenharmony_ci * resetting the count. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci if (current_jiffies > last.time) 3168c2ecf20Sopenharmony_ci (void) cmpxchg_acq(&last.count, count, 16 + (count & ~15)); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* used fetchadd to atomically update the count */ 3198c2ecf20Sopenharmony_ci if ((last.count & 15) < 5 && (ia64_fetchadd(1, &last.count, acq) & 15) < 5) { 3208c2ecf20Sopenharmony_ci last.time = current_jiffies + 5 * HZ; 3218c2ecf20Sopenharmony_ci printk(KERN_WARNING 3228c2ecf20Sopenharmony_ci "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n", 3238c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current), regs->cr_iip + ia64_psr(regs)->ri, isr); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, 3298c2ecf20Sopenharmony_ci ®s->cr_ifs, regs); 3308c2ecf20Sopenharmony_ci if (fp_fault) { 3318c2ecf20Sopenharmony_ci if (exception == 0) { 3328c2ecf20Sopenharmony_ci /* emulation was successful */ 3338c2ecf20Sopenharmony_ci ia64_increment_ip(regs); 3348c2ecf20Sopenharmony_ci } else if (exception == -1) { 3358c2ecf20Sopenharmony_ci printk(KERN_ERR "handle_fpu_swa: fp_emulate() returned -1\n"); 3368c2ecf20Sopenharmony_ci return -1; 3378c2ecf20Sopenharmony_ci } else { 3388c2ecf20Sopenharmony_ci /* is next instruction a trap? */ 3398c2ecf20Sopenharmony_ci int si_code; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (exception & 2) { 3428c2ecf20Sopenharmony_ci ia64_increment_ip(regs); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci si_code = FPE_FLTUNK; /* default code */ 3458c2ecf20Sopenharmony_ci if (isr & 0x11) { 3468c2ecf20Sopenharmony_ci si_code = FPE_FLTINV; 3478c2ecf20Sopenharmony_ci } else if (isr & 0x22) { 3488c2ecf20Sopenharmony_ci /* denormal operand gets the same si_code as underflow 3498c2ecf20Sopenharmony_ci * see arch/i386/kernel/traps.c:math_error() */ 3508c2ecf20Sopenharmony_ci si_code = FPE_FLTUND; 3518c2ecf20Sopenharmony_ci } else if (isr & 0x44) { 3528c2ecf20Sopenharmony_ci si_code = FPE_FLTDIV; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci force_sig_fault(SIGFPE, si_code, 3558c2ecf20Sopenharmony_ci (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), 3568c2ecf20Sopenharmony_ci 0, __ISR_VALID, isr); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci } else { 3598c2ecf20Sopenharmony_ci if (exception == -1) { 3608c2ecf20Sopenharmony_ci printk(KERN_ERR "handle_fpu_swa: fp_emulate() returned -1\n"); 3618c2ecf20Sopenharmony_ci return -1; 3628c2ecf20Sopenharmony_ci } else if (exception != 0) { 3638c2ecf20Sopenharmony_ci /* raise exception */ 3648c2ecf20Sopenharmony_ci int si_code; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci si_code = FPE_FLTUNK; /* default code */ 3678c2ecf20Sopenharmony_ci if (isr & 0x880) { 3688c2ecf20Sopenharmony_ci si_code = FPE_FLTOVF; 3698c2ecf20Sopenharmony_ci } else if (isr & 0x1100) { 3708c2ecf20Sopenharmony_ci si_code = FPE_FLTUND; 3718c2ecf20Sopenharmony_ci } else if (isr & 0x2200) { 3728c2ecf20Sopenharmony_ci si_code = FPE_FLTRES; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci force_sig_fault(SIGFPE, si_code, 3758c2ecf20Sopenharmony_ci (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), 3768c2ecf20Sopenharmony_ci 0, __ISR_VALID, isr); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistruct illegal_op_return { 3838c2ecf20Sopenharmony_ci unsigned long fkt, arg1, arg2, arg3; 3848c2ecf20Sopenharmony_ci}; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistruct illegal_op_return 3878c2ecf20Sopenharmony_ciia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3, 3888c2ecf20Sopenharmony_ci long arg4, long arg5, long arg6, long arg7, 3898c2ecf20Sopenharmony_ci struct pt_regs regs) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct illegal_op_return rv; 3928c2ecf20Sopenharmony_ci char buf[128]; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci#ifdef CONFIG_IA64_BRL_EMU 3958c2ecf20Sopenharmony_ci { 3968c2ecf20Sopenharmony_ci extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci rv = ia64_emulate_brl(®s, ec); 3998c2ecf20Sopenharmony_ci if (rv.fkt != (unsigned long) -1) 4008c2ecf20Sopenharmony_ci return rv; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci#endif 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci sprintf(buf, "IA-64 Illegal operation fault"); 4058c2ecf20Sopenharmony_ci rv.fkt = 0; 4068c2ecf20Sopenharmony_ci if (die_if_kernel(buf, ®s, 0)) 4078c2ecf20Sopenharmony_ci return rv; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci force_sig_fault(SIGILL, ILL_ILLOPC, 4108c2ecf20Sopenharmony_ci (void __user *) (regs.cr_iip + ia64_psr(®s)->ri), 4118c2ecf20Sopenharmony_ci 0, 0, 0); 4128c2ecf20Sopenharmony_ci return rv; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_civoid __kprobes 4168c2ecf20Sopenharmony_ciia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, 4178c2ecf20Sopenharmony_ci unsigned long iim, unsigned long itir, long arg5, long arg6, 4188c2ecf20Sopenharmony_ci long arg7, struct pt_regs regs) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci unsigned long code, error = isr, iip; 4218c2ecf20Sopenharmony_ci char buf[128]; 4228c2ecf20Sopenharmony_ci int result, sig, si_code; 4238c2ecf20Sopenharmony_ci static const char *reason[] = { 4248c2ecf20Sopenharmony_ci "IA-64 Illegal Operation fault", 4258c2ecf20Sopenharmony_ci "IA-64 Privileged Operation fault", 4268c2ecf20Sopenharmony_ci "IA-64 Privileged Register fault", 4278c2ecf20Sopenharmony_ci "IA-64 Reserved Register/Field fault", 4288c2ecf20Sopenharmony_ci "Disabled Instruction Set Transition fault", 4298c2ecf20Sopenharmony_ci "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", 4308c2ecf20Sopenharmony_ci "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", 4318c2ecf20Sopenharmony_ci "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" 4328c2ecf20Sopenharmony_ci }; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { 4358c2ecf20Sopenharmony_ci /* 4368c2ecf20Sopenharmony_ci * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel 4378c2ecf20Sopenharmony_ci * the lfetch. 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci ia64_psr(®s)->ed = 1; 4408c2ecf20Sopenharmony_ci return; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci iip = regs.cr_iip + ia64_psr(®s)->ri; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci switch (vector) { 4468c2ecf20Sopenharmony_ci case 24: /* General Exception */ 4478c2ecf20Sopenharmony_ci code = (isr >> 4) & 0xf; 4488c2ecf20Sopenharmony_ci sprintf(buf, "General Exception: %s%s", reason[code], 4498c2ecf20Sopenharmony_ci (code == 3) ? ((isr & (1UL << 37)) 4508c2ecf20Sopenharmony_ci ? " (RSE access)" : " (data access)") : ""); 4518c2ecf20Sopenharmony_ci if (code == 8) { 4528c2ecf20Sopenharmony_ci# ifdef CONFIG_IA64_PRINT_HAZARDS 4538c2ecf20Sopenharmony_ci printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n", 4548c2ecf20Sopenharmony_ci current->comm, task_pid_nr(current), 4558c2ecf20Sopenharmony_ci regs.cr_iip + ia64_psr(®s)->ri, regs.pr); 4568c2ecf20Sopenharmony_ci# endif 4578c2ecf20Sopenharmony_ci return; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci case 25: /* Disabled FP-Register */ 4628c2ecf20Sopenharmony_ci if (isr & 2) { 4638c2ecf20Sopenharmony_ci disabled_fph_fault(®s); 4648c2ecf20Sopenharmony_ci return; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci sprintf(buf, "Disabled FPL fault---not supposed to happen!"); 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci case 26: /* NaT Consumption */ 4708c2ecf20Sopenharmony_ci if (user_mode(®s)) { 4718c2ecf20Sopenharmony_ci void __user *addr; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (((isr >> 4) & 0xf) == 2) { 4748c2ecf20Sopenharmony_ci /* NaT page consumption */ 4758c2ecf20Sopenharmony_ci sig = SIGSEGV; 4768c2ecf20Sopenharmony_ci code = SEGV_ACCERR; 4778c2ecf20Sopenharmony_ci addr = (void __user *) ifa; 4788c2ecf20Sopenharmony_ci } else { 4798c2ecf20Sopenharmony_ci /* register NaT consumption */ 4808c2ecf20Sopenharmony_ci sig = SIGILL; 4818c2ecf20Sopenharmony_ci code = ILL_ILLOPN; 4828c2ecf20Sopenharmony_ci addr = (void __user *) (regs.cr_iip 4838c2ecf20Sopenharmony_ci + ia64_psr(®s)->ri); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci force_sig_fault(sig, code, addr, 4868c2ecf20Sopenharmony_ci vector, __ISR_VALID, isr); 4878c2ecf20Sopenharmony_ci return; 4888c2ecf20Sopenharmony_ci } else if (ia64_done_with_exception(®s)) 4898c2ecf20Sopenharmony_ci return; 4908c2ecf20Sopenharmony_ci sprintf(buf, "NaT consumption"); 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci case 31: /* Unsupported Data Reference */ 4948c2ecf20Sopenharmony_ci if (user_mode(®s)) { 4958c2ecf20Sopenharmony_ci force_sig_fault(SIGILL, ILL_ILLOPN, (void __user *) iip, 4968c2ecf20Sopenharmony_ci vector, __ISR_VALID, isr); 4978c2ecf20Sopenharmony_ci return; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci sprintf(buf, "Unsupported data reference"); 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci case 29: /* Debug */ 5038c2ecf20Sopenharmony_ci case 35: /* Taken Branch Trap */ 5048c2ecf20Sopenharmony_ci case 36: /* Single Step Trap */ 5058c2ecf20Sopenharmony_ci if (fsys_mode(current, ®s)) { 5068c2ecf20Sopenharmony_ci extern char __kernel_syscall_via_break[]; 5078c2ecf20Sopenharmony_ci /* 5088c2ecf20Sopenharmony_ci * Got a trap in fsys-mode: Taken Branch Trap 5098c2ecf20Sopenharmony_ci * and Single Step trap need special handling; 5108c2ecf20Sopenharmony_ci * Debug trap is ignored (we disable it here 5118c2ecf20Sopenharmony_ci * and re-enable it in the lower-privilege trap). 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ci if (unlikely(vector == 29)) { 5148c2ecf20Sopenharmony_ci set_thread_flag(TIF_DB_DISABLED); 5158c2ecf20Sopenharmony_ci ia64_psr(®s)->db = 0; 5168c2ecf20Sopenharmony_ci ia64_psr(®s)->lp = 1; 5178c2ecf20Sopenharmony_ci return; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci /* re-do the system call via break 0x100000: */ 5208c2ecf20Sopenharmony_ci regs.cr_iip = (unsigned long) __kernel_syscall_via_break; 5218c2ecf20Sopenharmony_ci ia64_psr(®s)->ri = 0; 5228c2ecf20Sopenharmony_ci ia64_psr(®s)->cpl = 3; 5238c2ecf20Sopenharmony_ci return; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci switch (vector) { 5268c2ecf20Sopenharmony_ci default: 5278c2ecf20Sopenharmony_ci case 29: 5288c2ecf20Sopenharmony_ci si_code = TRAP_HWBKPT; 5298c2ecf20Sopenharmony_ci#ifdef CONFIG_ITANIUM 5308c2ecf20Sopenharmony_ci /* 5318c2ecf20Sopenharmony_ci * Erratum 10 (IFA may contain incorrect address) now has 5328c2ecf20Sopenharmony_ci * "NoFix" status. There are no plans for fixing this. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci if (ia64_psr(®s)->is == 0) 5358c2ecf20Sopenharmony_ci ifa = regs.cr_iip; 5368c2ecf20Sopenharmony_ci#endif 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci case 35: si_code = TRAP_BRANCH; ifa = 0; break; 5398c2ecf20Sopenharmony_ci case 36: si_code = TRAP_TRACE; ifa = 0; break; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci if (notify_die(DIE_FAULT, "ia64_fault", ®s, vector, si_code, SIGTRAP) 5428c2ecf20Sopenharmony_ci == NOTIFY_STOP) 5438c2ecf20Sopenharmony_ci return; 5448c2ecf20Sopenharmony_ci force_sig_fault(SIGTRAP, si_code, (void __user *) ifa, 5458c2ecf20Sopenharmony_ci 0, __ISR_VALID, isr); 5468c2ecf20Sopenharmony_ci return; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci case 32: /* fp fault */ 5498c2ecf20Sopenharmony_ci case 33: /* fp trap */ 5508c2ecf20Sopenharmony_ci result = handle_fpu_swa((vector == 32) ? 1 : 0, ®s, isr); 5518c2ecf20Sopenharmony_ci if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { 5528c2ecf20Sopenharmony_ci force_sig_fault(SIGFPE, FPE_FLTINV, (void __user *) iip, 5538c2ecf20Sopenharmony_ci 0, __ISR_VALID, isr); 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci return; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci case 34: 5588c2ecf20Sopenharmony_ci if (isr & 0x2) { 5598c2ecf20Sopenharmony_ci /* Lower-Privilege Transfer Trap */ 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* If we disabled debug traps during an fsyscall, 5628c2ecf20Sopenharmony_ci * re-enable them here. 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_ci if (test_thread_flag(TIF_DB_DISABLED)) { 5658c2ecf20Sopenharmony_ci clear_thread_flag(TIF_DB_DISABLED); 5668c2ecf20Sopenharmony_ci ia64_psr(®s)->db = 1; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* 5708c2ecf20Sopenharmony_ci * Just clear PSR.lp and then return immediately: 5718c2ecf20Sopenharmony_ci * all the interesting work (e.g., signal delivery) 5728c2ecf20Sopenharmony_ci * is done in the kernel exit path. 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_ci ia64_psr(®s)->lp = 0; 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci } else { 5778c2ecf20Sopenharmony_ci /* Unimplemented Instr. Address Trap */ 5788c2ecf20Sopenharmony_ci if (user_mode(®s)) { 5798c2ecf20Sopenharmony_ci force_sig_fault(SIGILL, ILL_BADIADDR, 5808c2ecf20Sopenharmony_ci (void __user *) iip, 5818c2ecf20Sopenharmony_ci 0, 0, 0); 5828c2ecf20Sopenharmony_ci return; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci sprintf(buf, "Unimplemented Instruction Address fault"); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci case 45: 5898c2ecf20Sopenharmony_ci printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n"); 5908c2ecf20Sopenharmony_ci printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", 5918c2ecf20Sopenharmony_ci iip, ifa, isr); 5928c2ecf20Sopenharmony_ci force_sig(SIGSEGV); 5938c2ecf20Sopenharmony_ci return; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci case 46: 5968c2ecf20Sopenharmony_ci printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n"); 5978c2ecf20Sopenharmony_ci printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n", 5988c2ecf20Sopenharmony_ci iip, ifa, isr, iim); 5998c2ecf20Sopenharmony_ci force_sig(SIGSEGV); 6008c2ecf20Sopenharmony_ci return; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci case 47: 6038c2ecf20Sopenharmony_ci sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16); 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci default: 6078c2ecf20Sopenharmony_ci sprintf(buf, "Fault %lu", vector); 6088c2ecf20Sopenharmony_ci break; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci if (!die_if_kernel(buf, ®s, error)) 6118c2ecf20Sopenharmony_ci force_sig(SIGILL); 6128c2ecf20Sopenharmony_ci} 613