xref: /kernel/linux/linux-5.10/arch/ia64/kernel/traps.c (revision 8c2ecf20)
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 *) &regs->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, &regs->cr_ipsr, &regs->ar_fpsr, &isr, &regs->pr,
3298c2ecf20Sopenharmony_ci			       &regs->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(&regs, 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, &regs, 0))
4078c2ecf20Sopenharmony_ci		return rv;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	force_sig_fault(SIGILL, ILL_ILLOPC,
4108c2ecf20Sopenharmony_ci			(void __user *) (regs.cr_iip + ia64_psr(&regs)->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(&regs)->ed = 1;
4408c2ecf20Sopenharmony_ci		return;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	iip = regs.cr_iip + ia64_psr(&regs)->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(&regs)->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(&regs);
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(&regs)) {
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(&regs)->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(&regs))
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(&regs)) {
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, &regs)) {
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(&regs)->db = 0;
5168c2ecf20Sopenharmony_ci				ia64_psr(&regs)->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(&regs)->ri = 0;
5228c2ecf20Sopenharmony_ci			ia64_psr(&regs)->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(&regs)->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", &regs, 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, &regs, 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(&regs)->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(&regs)->lp = 0;
5758c2ecf20Sopenharmony_ci			return;
5768c2ecf20Sopenharmony_ci		} else {
5778c2ecf20Sopenharmony_ci			/* Unimplemented Instr. Address Trap */
5788c2ecf20Sopenharmony_ci			if (user_mode(&regs)) {
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, &regs, error))
6118c2ecf20Sopenharmony_ci		force_sig(SIGILL);
6128c2ecf20Sopenharmony_ci}
613