162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Architecture-specific trap handling. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1998-2003 Hewlett-Packard Co 662306a36Sopenharmony_ci * David Mosberger-Tang <davidm@hpl.hp.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/sched/signal.h> 1462306a36Sopenharmony_ci#include <linux/sched/debug.h> 1562306a36Sopenharmony_ci#include <linux/tty.h> 1662306a36Sopenharmony_ci#include <linux/vt_kern.h> /* For unblank_screen() */ 1762306a36Sopenharmony_ci#include <linux/export.h> 1862306a36Sopenharmony_ci#include <linux/extable.h> 1962306a36Sopenharmony_ci#include <linux/hardirq.h> 2062306a36Sopenharmony_ci#include <linux/kprobes.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> /* for ssleep() */ 2262306a36Sopenharmony_ci#include <linux/kdebug.h> 2362306a36Sopenharmony_ci#include <linux/uaccess.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <asm/fpswa.h> 2662306a36Sopenharmony_ci#include <asm/intrinsics.h> 2762306a36Sopenharmony_ci#include <asm/processor.h> 2862306a36Sopenharmony_ci#include <asm/exception.h> 2962306a36Sopenharmony_ci#include <asm/setup.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cifpswa_interface_t *fpswa_interface; 3262306a36Sopenharmony_ciEXPORT_SYMBOL(fpswa_interface); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_civoid __init 3562306a36Sopenharmony_citrap_init (void) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci if (ia64_boot_param->fpswa) 3862306a36Sopenharmony_ci /* FPSWA fixup: make the interface pointer a kernel virtual address: */ 3962306a36Sopenharmony_ci fpswa_interface = __va(ia64_boot_param->fpswa); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciint 4362306a36Sopenharmony_cidie (const char *str, struct pt_regs *regs, long err) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci static struct { 4662306a36Sopenharmony_ci spinlock_t lock; 4762306a36Sopenharmony_ci u32 lock_owner; 4862306a36Sopenharmony_ci int lock_owner_depth; 4962306a36Sopenharmony_ci } die = { 5062306a36Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(die.lock), 5162306a36Sopenharmony_ci .lock_owner = -1, 5262306a36Sopenharmony_ci .lock_owner_depth = 0 5362306a36Sopenharmony_ci }; 5462306a36Sopenharmony_ci static int die_counter; 5562306a36Sopenharmony_ci int cpu = get_cpu(); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (die.lock_owner != cpu) { 5862306a36Sopenharmony_ci console_verbose(); 5962306a36Sopenharmony_ci spin_lock_irq(&die.lock); 6062306a36Sopenharmony_ci die.lock_owner = cpu; 6162306a36Sopenharmony_ci die.lock_owner_depth = 0; 6262306a36Sopenharmony_ci bust_spinlocks(1); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci put_cpu(); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (++die.lock_owner_depth < 3) { 6762306a36Sopenharmony_ci printk("%s[%d]: %s %ld [%d]\n", 6862306a36Sopenharmony_ci current->comm, task_pid_nr(current), str, err, ++die_counter); 6962306a36Sopenharmony_ci if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) 7062306a36Sopenharmony_ci != NOTIFY_STOP) 7162306a36Sopenharmony_ci show_regs(regs); 7262306a36Sopenharmony_ci else 7362306a36Sopenharmony_ci regs = NULL; 7462306a36Sopenharmony_ci } else 7562306a36Sopenharmony_ci printk(KERN_ERR "Recursive die() failure, output suppressed\n"); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci bust_spinlocks(0); 7862306a36Sopenharmony_ci die.lock_owner = -1; 7962306a36Sopenharmony_ci add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); 8062306a36Sopenharmony_ci spin_unlock_irq(&die.lock); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (!regs) 8362306a36Sopenharmony_ci return 1; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (panic_on_oops) 8662306a36Sopenharmony_ci panic("Fatal exception"); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci make_task_dead(SIGSEGV); 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciint 9362306a36Sopenharmony_cidie_if_kernel (char *str, struct pt_regs *regs, long err) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci if (!user_mode(regs)) 9662306a36Sopenharmony_ci return die(str, regs, err); 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_civoid 10162306a36Sopenharmony_ci__kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int sig, code; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci switch (break_num) { 10662306a36Sopenharmony_ci case 0: /* unknown error (used by GCC for __builtin_abort()) */ 10762306a36Sopenharmony_ci if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP) 10862306a36Sopenharmony_ci == NOTIFY_STOP) 10962306a36Sopenharmony_ci return; 11062306a36Sopenharmony_ci if (die_if_kernel("bugcheck!", regs, break_num)) 11162306a36Sopenharmony_ci return; 11262306a36Sopenharmony_ci sig = SIGILL; code = ILL_ILLOPC; 11362306a36Sopenharmony_ci break; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci case 1: /* integer divide by zero */ 11662306a36Sopenharmony_ci sig = SIGFPE; code = FPE_INTDIV; 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci case 2: /* integer overflow */ 12062306a36Sopenharmony_ci sig = SIGFPE; code = FPE_INTOVF; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci case 3: /* range check/bounds check */ 12462306a36Sopenharmony_ci sig = SIGFPE; code = FPE_FLTSUB; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci case 4: /* null pointer dereference */ 12862306a36Sopenharmony_ci sig = SIGSEGV; code = SEGV_MAPERR; 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci case 5: /* misaligned data */ 13262306a36Sopenharmony_ci sig = SIGSEGV; code = BUS_ADRALN; 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci case 6: /* decimal overflow */ 13662306a36Sopenharmony_ci sig = SIGFPE; code = __FPE_DECOVF; 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci case 7: /* decimal divide by zero */ 14062306a36Sopenharmony_ci sig = SIGFPE; code = __FPE_DECDIV; 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci case 8: /* packed decimal error */ 14462306a36Sopenharmony_ci sig = SIGFPE; code = __FPE_DECERR; 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci case 9: /* invalid ASCII digit */ 14862306a36Sopenharmony_ci sig = SIGFPE; code = __FPE_INVASC; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci case 10: /* invalid decimal digit */ 15262306a36Sopenharmony_ci sig = SIGFPE; code = __FPE_INVDEC; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci case 11: /* paragraph stack overflow */ 15662306a36Sopenharmony_ci sig = SIGSEGV; code = __SEGV_PSTKOVF; 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci case 0x3f000 ... 0x3ffff: /* bundle-update in progress */ 16062306a36Sopenharmony_ci sig = SIGILL; code = __ILL_BNDMOD; 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci default: 16462306a36Sopenharmony_ci if ((break_num < 0x40000 || break_num > 0x100000) 16562306a36Sopenharmony_ci && die_if_kernel("Bad break", regs, break_num)) 16662306a36Sopenharmony_ci return; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (break_num < 0x80000) { 16962306a36Sopenharmony_ci sig = SIGILL; code = __ILL_BREAK; 17062306a36Sopenharmony_ci } else { 17162306a36Sopenharmony_ci if (notify_die(DIE_BREAK, "bad break", regs, break_num, TRAP_BRKPT, SIGTRAP) 17262306a36Sopenharmony_ci == NOTIFY_STOP) 17362306a36Sopenharmony_ci return; 17462306a36Sopenharmony_ci sig = SIGTRAP; code = TRAP_BRKPT; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci force_sig_fault(sig, code, 17862306a36Sopenharmony_ci (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), 17962306a36Sopenharmony_ci break_num, 0 /* clear __ISR_VALID */, 0); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* 18362306a36Sopenharmony_ci * disabled_fph_fault() is called when a user-level process attempts to access f32..f127 18462306a36Sopenharmony_ci * and it doesn't own the fp-high register partition. When this happens, we save the 18562306a36Sopenharmony_ci * current fph partition in the task_struct of the fpu-owner (if necessary) and then load 18662306a36Sopenharmony_ci * the fp-high partition of the current task (if necessary). Note that the kernel has 18762306a36Sopenharmony_ci * access to fph by the time we get here, as the IVT's "Disabled FP-Register" handler takes 18862306a36Sopenharmony_ci * care of clearing psr.dfh. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_cistatic inline void 19162306a36Sopenharmony_cidisabled_fph_fault (struct pt_regs *regs) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct ia64_psr *psr = ia64_psr(regs); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* first, grant user-level access to fph partition: */ 19662306a36Sopenharmony_ci psr->dfh = 0; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci * Make sure that no other task gets in on this processor 20062306a36Sopenharmony_ci * while we're claiming the FPU 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci preempt_disable(); 20362306a36Sopenharmony_ci#ifndef CONFIG_SMP 20462306a36Sopenharmony_ci { 20562306a36Sopenharmony_ci struct task_struct *fpu_owner 20662306a36Sopenharmony_ci = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (ia64_is_local_fpu_owner(current)) { 20962306a36Sopenharmony_ci preempt_enable_no_resched(); 21062306a36Sopenharmony_ci return; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (fpu_owner) 21462306a36Sopenharmony_ci ia64_flush_fph(fpu_owner); 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci#endif /* !CONFIG_SMP */ 21762306a36Sopenharmony_ci ia64_set_local_fpu_owner(current); 21862306a36Sopenharmony_ci if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { 21962306a36Sopenharmony_ci __ia64_load_fpu(current->thread.fph); 22062306a36Sopenharmony_ci psr->mfh = 0; 22162306a36Sopenharmony_ci } else { 22262306a36Sopenharmony_ci __ia64_init_fpu(); 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * Set mfh because the state in thread.fph does not match the state in 22562306a36Sopenharmony_ci * the fph partition. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci psr->mfh = 1; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci preempt_enable_no_resched(); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic inline int 23362306a36Sopenharmony_cifp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs, 23462306a36Sopenharmony_ci struct pt_regs *regs) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci fp_state_t fp_state; 23762306a36Sopenharmony_ci fpswa_ret_t ret; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (!fpswa_interface) 24062306a36Sopenharmony_ci return -1; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci memset(&fp_state, 0, sizeof(fp_state_t)); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* 24562306a36Sopenharmony_ci * compute fp_state. only FP registers f6 - f11 are used by the 24662306a36Sopenharmony_ci * kernel, so set those bits in the mask and set the low volatile 24762306a36Sopenharmony_ci * pointer to point to these registers. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6; 25262306a36Sopenharmony_ci /* 25362306a36Sopenharmony_ci * unsigned long (*EFI_FPSWA) ( 25462306a36Sopenharmony_ci * unsigned long trap_type, 25562306a36Sopenharmony_ci * void *Bundle, 25662306a36Sopenharmony_ci * unsigned long *pipsr, 25762306a36Sopenharmony_ci * unsigned long *pfsr, 25862306a36Sopenharmony_ci * unsigned long *pisr, 25962306a36Sopenharmony_ci * unsigned long *ppreds, 26062306a36Sopenharmony_ci * unsigned long *pifs, 26162306a36Sopenharmony_ci * void *fp_state); 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci ret = (*fpswa_interface->fpswa)((unsigned long) fp_fault, bundle, 26462306a36Sopenharmony_ci (unsigned long *) ipsr, (unsigned long *) fpsr, 26562306a36Sopenharmony_ci (unsigned long *) isr, (unsigned long *) pr, 26662306a36Sopenharmony_ci (unsigned long *) ifs, &fp_state); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return ret.status; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistruct fpu_swa_msg { 27262306a36Sopenharmony_ci unsigned long count; 27362306a36Sopenharmony_ci unsigned long time; 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct fpu_swa_msg, cpulast); 27662306a36Sopenharmony_ciDECLARE_PER_CPU(struct fpu_swa_msg, cpulast); 27762306a36Sopenharmony_cistatic struct fpu_swa_msg last __cacheline_aligned; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* 28162306a36Sopenharmony_ci * Handle floating-point assist faults and traps. 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_cistatic int 28462306a36Sopenharmony_cihandle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci long exception, bundle[2]; 28762306a36Sopenharmony_ci unsigned long fault_ip; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci fault_ip = regs->cr_iip; 29062306a36Sopenharmony_ci if (!fp_fault && (ia64_psr(regs)->ri == 0)) 29162306a36Sopenharmony_ci fault_ip -= 16; 29262306a36Sopenharmony_ci if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle))) 29362306a36Sopenharmony_ci return -1; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { 29662306a36Sopenharmony_ci unsigned long count, current_jiffies = jiffies; 29762306a36Sopenharmony_ci struct fpu_swa_msg *cp = this_cpu_ptr(&cpulast); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (unlikely(current_jiffies > cp->time)) 30062306a36Sopenharmony_ci cp->count = 0; 30162306a36Sopenharmony_ci if (unlikely(cp->count < 5)) { 30262306a36Sopenharmony_ci cp->count++; 30362306a36Sopenharmony_ci cp->time = current_jiffies + 5 * HZ; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* minimize races by grabbing a copy of count BEFORE checking last.time. */ 30662306a36Sopenharmony_ci count = last.count; 30762306a36Sopenharmony_ci barrier(); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* 31062306a36Sopenharmony_ci * Lower 4 bits are used as a count. Upper bits are a sequence 31162306a36Sopenharmony_ci * number that is updated when count is reset. The cmpxchg will 31262306a36Sopenharmony_ci * fail is seqno has changed. This minimizes multiple cpus 31362306a36Sopenharmony_ci * resetting the count. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci if (current_jiffies > last.time) 31662306a36Sopenharmony_ci (void) cmpxchg_acq(&last.count, count, 16 + (count & ~15)); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* used fetchadd to atomically update the count */ 31962306a36Sopenharmony_ci if ((last.count & 15) < 5 && (ia64_fetchadd(1, &last.count, acq) & 15) < 5) { 32062306a36Sopenharmony_ci last.time = current_jiffies + 5 * HZ; 32162306a36Sopenharmony_ci printk(KERN_WARNING 32262306a36Sopenharmony_ci "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n", 32362306a36Sopenharmony_ci current->comm, task_pid_nr(current), regs->cr_iip + ia64_psr(regs)->ri, isr); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, 32962306a36Sopenharmony_ci ®s->cr_ifs, regs); 33062306a36Sopenharmony_ci if (fp_fault) { 33162306a36Sopenharmony_ci if (exception == 0) { 33262306a36Sopenharmony_ci /* emulation was successful */ 33362306a36Sopenharmony_ci ia64_increment_ip(regs); 33462306a36Sopenharmony_ci } else if (exception == -1) { 33562306a36Sopenharmony_ci printk(KERN_ERR "handle_fpu_swa: fp_emulate() returned -1\n"); 33662306a36Sopenharmony_ci return -1; 33762306a36Sopenharmony_ci } else { 33862306a36Sopenharmony_ci /* is next instruction a trap? */ 33962306a36Sopenharmony_ci int si_code; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (exception & 2) { 34262306a36Sopenharmony_ci ia64_increment_ip(regs); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci si_code = FPE_FLTUNK; /* default code */ 34562306a36Sopenharmony_ci if (isr & 0x11) { 34662306a36Sopenharmony_ci si_code = FPE_FLTINV; 34762306a36Sopenharmony_ci } else if (isr & 0x22) { 34862306a36Sopenharmony_ci /* denormal operand gets the same si_code as underflow 34962306a36Sopenharmony_ci * see arch/i386/kernel/traps.c:math_error() */ 35062306a36Sopenharmony_ci si_code = FPE_FLTUND; 35162306a36Sopenharmony_ci } else if (isr & 0x44) { 35262306a36Sopenharmony_ci si_code = FPE_FLTDIV; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci force_sig_fault(SIGFPE, si_code, 35562306a36Sopenharmony_ci (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), 35662306a36Sopenharmony_ci 0, __ISR_VALID, isr); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci } else { 35962306a36Sopenharmony_ci if (exception == -1) { 36062306a36Sopenharmony_ci printk(KERN_ERR "handle_fpu_swa: fp_emulate() returned -1\n"); 36162306a36Sopenharmony_ci return -1; 36262306a36Sopenharmony_ci } else if (exception != 0) { 36362306a36Sopenharmony_ci /* raise exception */ 36462306a36Sopenharmony_ci int si_code; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci si_code = FPE_FLTUNK; /* default code */ 36762306a36Sopenharmony_ci if (isr & 0x880) { 36862306a36Sopenharmony_ci si_code = FPE_FLTOVF; 36962306a36Sopenharmony_ci } else if (isr & 0x1100) { 37062306a36Sopenharmony_ci si_code = FPE_FLTUND; 37162306a36Sopenharmony_ci } else if (isr & 0x2200) { 37262306a36Sopenharmony_ci si_code = FPE_FLTRES; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci force_sig_fault(SIGFPE, si_code, 37562306a36Sopenharmony_ci (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), 37662306a36Sopenharmony_ci 0, __ISR_VALID, isr); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistruct illegal_op_return { 38362306a36Sopenharmony_ci unsigned long fkt, arg1, arg2, arg3; 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistruct illegal_op_return 38762306a36Sopenharmony_ciia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3, 38862306a36Sopenharmony_ci long arg4, long arg5, long arg6, long arg7, 38962306a36Sopenharmony_ci struct pt_regs regs) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct illegal_op_return rv; 39262306a36Sopenharmony_ci char buf[128]; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci#ifdef CONFIG_IA64_BRL_EMU 39562306a36Sopenharmony_ci { 39662306a36Sopenharmony_ci extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci rv = ia64_emulate_brl(®s, ec); 39962306a36Sopenharmony_ci if (rv.fkt != (unsigned long) -1) 40062306a36Sopenharmony_ci return rv; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci#endif 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci sprintf(buf, "IA-64 Illegal operation fault"); 40562306a36Sopenharmony_ci rv.fkt = 0; 40662306a36Sopenharmony_ci if (die_if_kernel(buf, ®s, 0)) 40762306a36Sopenharmony_ci return rv; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci force_sig_fault(SIGILL, ILL_ILLOPC, 41062306a36Sopenharmony_ci (void __user *) (regs.cr_iip + ia64_psr(®s)->ri), 41162306a36Sopenharmony_ci 0, 0, 0); 41262306a36Sopenharmony_ci return rv; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_civoid __kprobes 41662306a36Sopenharmony_ciia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, 41762306a36Sopenharmony_ci unsigned long iim, unsigned long itir, long arg5, long arg6, 41862306a36Sopenharmony_ci long arg7, struct pt_regs regs) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci unsigned long code, error = isr, iip; 42162306a36Sopenharmony_ci char buf[128]; 42262306a36Sopenharmony_ci int result, sig, si_code; 42362306a36Sopenharmony_ci static const char *reason[] = { 42462306a36Sopenharmony_ci "IA-64 Illegal Operation fault", 42562306a36Sopenharmony_ci "IA-64 Privileged Operation fault", 42662306a36Sopenharmony_ci "IA-64 Privileged Register fault", 42762306a36Sopenharmony_ci "IA-64 Reserved Register/Field fault", 42862306a36Sopenharmony_ci "Disabled Instruction Set Transition fault", 42962306a36Sopenharmony_ci "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", 43062306a36Sopenharmony_ci "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", 43162306a36Sopenharmony_ci "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" 43262306a36Sopenharmony_ci }; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel 43762306a36Sopenharmony_ci * the lfetch. 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_ci ia64_psr(®s)->ed = 1; 44062306a36Sopenharmony_ci return; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci iip = regs.cr_iip + ia64_psr(®s)->ri; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci switch (vector) { 44662306a36Sopenharmony_ci case 24: /* General Exception */ 44762306a36Sopenharmony_ci code = (isr >> 4) & 0xf; 44862306a36Sopenharmony_ci sprintf(buf, "General Exception: %s%s", reason[code], 44962306a36Sopenharmony_ci (code == 3) ? ((isr & (1UL << 37)) 45062306a36Sopenharmony_ci ? " (RSE access)" : " (data access)") : ""); 45162306a36Sopenharmony_ci if (code == 8) { 45262306a36Sopenharmony_ci# ifdef CONFIG_IA64_PRINT_HAZARDS 45362306a36Sopenharmony_ci printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n", 45462306a36Sopenharmony_ci current->comm, task_pid_nr(current), 45562306a36Sopenharmony_ci regs.cr_iip + ia64_psr(®s)->ri, regs.pr); 45662306a36Sopenharmony_ci# endif 45762306a36Sopenharmony_ci return; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci case 25: /* Disabled FP-Register */ 46262306a36Sopenharmony_ci if (isr & 2) { 46362306a36Sopenharmony_ci disabled_fph_fault(®s); 46462306a36Sopenharmony_ci return; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci sprintf(buf, "Disabled FPL fault---not supposed to happen!"); 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci case 26: /* NaT Consumption */ 47062306a36Sopenharmony_ci if (user_mode(®s)) { 47162306a36Sopenharmony_ci void __user *addr; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (((isr >> 4) & 0xf) == 2) { 47462306a36Sopenharmony_ci /* NaT page consumption */ 47562306a36Sopenharmony_ci sig = SIGSEGV; 47662306a36Sopenharmony_ci code = SEGV_ACCERR; 47762306a36Sopenharmony_ci addr = (void __user *) ifa; 47862306a36Sopenharmony_ci } else { 47962306a36Sopenharmony_ci /* register NaT consumption */ 48062306a36Sopenharmony_ci sig = SIGILL; 48162306a36Sopenharmony_ci code = ILL_ILLOPN; 48262306a36Sopenharmony_ci addr = (void __user *) (regs.cr_iip 48362306a36Sopenharmony_ci + ia64_psr(®s)->ri); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci force_sig_fault(sig, code, addr, 48662306a36Sopenharmony_ci vector, __ISR_VALID, isr); 48762306a36Sopenharmony_ci return; 48862306a36Sopenharmony_ci } else if (ia64_done_with_exception(®s)) 48962306a36Sopenharmony_ci return; 49062306a36Sopenharmony_ci sprintf(buf, "NaT consumption"); 49162306a36Sopenharmony_ci break; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci case 31: /* Unsupported Data Reference */ 49462306a36Sopenharmony_ci if (user_mode(®s)) { 49562306a36Sopenharmony_ci force_sig_fault(SIGILL, ILL_ILLOPN, (void __user *) iip, 49662306a36Sopenharmony_ci vector, __ISR_VALID, isr); 49762306a36Sopenharmony_ci return; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci sprintf(buf, "Unsupported data reference"); 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci case 29: /* Debug */ 50362306a36Sopenharmony_ci case 35: /* Taken Branch Trap */ 50462306a36Sopenharmony_ci case 36: /* Single Step Trap */ 50562306a36Sopenharmony_ci if (fsys_mode(current, ®s)) { 50662306a36Sopenharmony_ci extern char __kernel_syscall_via_break[]; 50762306a36Sopenharmony_ci /* 50862306a36Sopenharmony_ci * Got a trap in fsys-mode: Taken Branch Trap 50962306a36Sopenharmony_ci * and Single Step trap need special handling; 51062306a36Sopenharmony_ci * Debug trap is ignored (we disable it here 51162306a36Sopenharmony_ci * and re-enable it in the lower-privilege trap). 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci if (unlikely(vector == 29)) { 51462306a36Sopenharmony_ci set_thread_flag(TIF_DB_DISABLED); 51562306a36Sopenharmony_ci ia64_psr(®s)->db = 0; 51662306a36Sopenharmony_ci ia64_psr(®s)->lp = 1; 51762306a36Sopenharmony_ci return; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci /* re-do the system call via break 0x100000: */ 52062306a36Sopenharmony_ci regs.cr_iip = (unsigned long) __kernel_syscall_via_break; 52162306a36Sopenharmony_ci ia64_psr(®s)->ri = 0; 52262306a36Sopenharmony_ci ia64_psr(®s)->cpl = 3; 52362306a36Sopenharmony_ci return; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci switch (vector) { 52662306a36Sopenharmony_ci default: 52762306a36Sopenharmony_ci case 29: 52862306a36Sopenharmony_ci si_code = TRAP_HWBKPT; 52962306a36Sopenharmony_ci#ifdef CONFIG_ITANIUM 53062306a36Sopenharmony_ci /* 53162306a36Sopenharmony_ci * Erratum 10 (IFA may contain incorrect address) now has 53262306a36Sopenharmony_ci * "NoFix" status. There are no plans for fixing this. 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_ci if (ia64_psr(®s)->is == 0) 53562306a36Sopenharmony_ci ifa = regs.cr_iip; 53662306a36Sopenharmony_ci#endif 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case 35: si_code = TRAP_BRANCH; ifa = 0; break; 53962306a36Sopenharmony_ci case 36: si_code = TRAP_TRACE; ifa = 0; break; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci if (notify_die(DIE_FAULT, "ia64_fault", ®s, vector, si_code, SIGTRAP) 54262306a36Sopenharmony_ci == NOTIFY_STOP) 54362306a36Sopenharmony_ci return; 54462306a36Sopenharmony_ci force_sig_fault(SIGTRAP, si_code, (void __user *) ifa, 54562306a36Sopenharmony_ci 0, __ISR_VALID, isr); 54662306a36Sopenharmony_ci return; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci case 32: /* fp fault */ 54962306a36Sopenharmony_ci case 33: /* fp trap */ 55062306a36Sopenharmony_ci result = handle_fpu_swa((vector == 32) ? 1 : 0, ®s, isr); 55162306a36Sopenharmony_ci if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { 55262306a36Sopenharmony_ci force_sig_fault(SIGFPE, FPE_FLTINV, (void __user *) iip, 55362306a36Sopenharmony_ci 0, __ISR_VALID, isr); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci return; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci case 34: 55862306a36Sopenharmony_ci if (isr & 0x2) { 55962306a36Sopenharmony_ci /* Lower-Privilege Transfer Trap */ 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* If we disabled debug traps during an fsyscall, 56262306a36Sopenharmony_ci * re-enable them here. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_ci if (test_thread_flag(TIF_DB_DISABLED)) { 56562306a36Sopenharmony_ci clear_thread_flag(TIF_DB_DISABLED); 56662306a36Sopenharmony_ci ia64_psr(®s)->db = 1; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* 57062306a36Sopenharmony_ci * Just clear PSR.lp and then return immediately: 57162306a36Sopenharmony_ci * all the interesting work (e.g., signal delivery) 57262306a36Sopenharmony_ci * is done in the kernel exit path. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_ci ia64_psr(®s)->lp = 0; 57562306a36Sopenharmony_ci return; 57662306a36Sopenharmony_ci } else { 57762306a36Sopenharmony_ci /* Unimplemented Instr. Address Trap */ 57862306a36Sopenharmony_ci if (user_mode(®s)) { 57962306a36Sopenharmony_ci force_sig_fault(SIGILL, ILL_BADIADDR, 58062306a36Sopenharmony_ci (void __user *) iip, 58162306a36Sopenharmony_ci 0, 0, 0); 58262306a36Sopenharmony_ci return; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci sprintf(buf, "Unimplemented Instruction Address fault"); 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci case 45: 58962306a36Sopenharmony_ci printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n"); 59062306a36Sopenharmony_ci printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", 59162306a36Sopenharmony_ci iip, ifa, isr); 59262306a36Sopenharmony_ci force_sig(SIGSEGV); 59362306a36Sopenharmony_ci return; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci case 46: 59662306a36Sopenharmony_ci printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n"); 59762306a36Sopenharmony_ci printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n", 59862306a36Sopenharmony_ci iip, ifa, isr, iim); 59962306a36Sopenharmony_ci force_sig(SIGSEGV); 60062306a36Sopenharmony_ci return; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci case 47: 60362306a36Sopenharmony_ci sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16); 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci default: 60762306a36Sopenharmony_ci sprintf(buf, "Fault %lu", vector); 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci if (!die_if_kernel(buf, ®s, error)) 61162306a36Sopenharmony_ci force_sig(SIGILL); 61262306a36Sopenharmony_ci} 613