1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * S390 version
4a53c8fabSHeiko Carstens * Copyright IBM Corp. 1999, 2000
51da177e4SLinus Torvalds * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
61da177e4SLinus Torvalds * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * Derived from "arch/i386/kernel/traps.c"
91da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds /*
131da177e4SLinus Torvalds * 'Traps.c' handles hardware traps and faults after we have saved some
141da177e4SLinus Torvalds * state in 'asm.s'.
151da177e4SLinus Torvalds */
1656e62a73SSven Schnelle #include "asm/irqflags.h"
1756e62a73SSven Schnelle #include "asm/ptrace.h"
184ba069b8SMichael Grundy #include <linux/kprobes.h>
191bca09f7SHeiko Carstens #include <linux/kdebug.h>
20bae1cd36SSven Schnelle #include <linux/randomize_kstack.h>
21dcc096c5SPaul Gortmaker #include <linux/extable.h>
221bca09f7SHeiko Carstens #include <linux/ptrace.h>
231bca09f7SHeiko Carstens #include <linux/sched.h>
24b17b0153SIngo Molnar #include <linux/sched/debug.h>
251bca09f7SHeiko Carstens #include <linux/mm.h>
2680703617SMartin Schwidefsky #include <linux/slab.h>
277c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
2892acfb74SHeiko Carstens #include <linux/cpu.h>
2956e62a73SSven Schnelle #include <linux/entry-common.h>
30d09a307fSHeiko Carstens #include <asm/asm-extable.h>
31b0753902SHendrik Brueckner #include <asm/fpu/api.h>
3256e62a73SSven Schnelle #include <asm/vtime.h>
33a806170eSHeiko Carstens #include "entry.h"
341da177e4SLinus Torvalds
get_trap_ip(struct pt_regs * regs)35d35339a4SMartin Schwidefsky static inline void __user *get_trap_ip(struct pt_regs *regs)
36d35339a4SMartin Schwidefsky {
37d35339a4SMartin Schwidefsky unsigned long address;
38d35339a4SMartin Schwidefsky
39d35339a4SMartin Schwidefsky if (regs->int_code & 0x200)
40755112b3SSven Schnelle address = current->thread.trap_tdb.data[3];
41d35339a4SMartin Schwidefsky else
42d35339a4SMartin Schwidefsky address = regs->psw.addr;
439cb1ccecSHeiko Carstens return (void __user *) (address - (regs->int_code >> 16));
44d35339a4SMartin Schwidefsky }
45d35339a4SMartin Schwidefsky
is_valid_bugaddr(unsigned long addr)46c0007f1aSHeiko Carstens int is_valid_bugaddr(unsigned long addr)
47c0007f1aSHeiko Carstens {
48c0007f1aSHeiko Carstens return 1;
49c0007f1aSHeiko Carstens }
50c0007f1aSHeiko Carstens
do_report_trap(struct pt_regs * regs,int si_signo,int si_code,char * str)512a0a5b22SJan Willeke void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
52aa33c8cbSMartin Schwidefsky {
537d256175SHeiko Carstens if (user_mode(regs)) {
542e1661d2SEric W. Biederman force_sig_fault(si_signo, si_code, get_trap_ip(regs));
555d7eccecSHeiko Carstens report_user_fault(regs, si_signo, 0);
561da177e4SLinus Torvalds } else {
5746fee16fSHeiko Carstens if (!fixup_exception(regs))
58aa33c8cbSMartin Schwidefsky die(regs, str);
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds
do_trap(struct pt_regs * regs,int si_signo,int si_code,char * str)627a5388deSHeiko Carstens static void do_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
632a0a5b22SJan Willeke {
642a0a5b22SJan Willeke if (notify_die(DIE_TRAP, str, regs, 0,
652a0a5b22SJan Willeke regs->int_code, si_signo) == NOTIFY_STOP)
662a0a5b22SJan Willeke return;
672a0a5b22SJan Willeke do_report_trap(regs, si_signo, si_code, str);
682a0a5b22SJan Willeke }
697a5388deSHeiko Carstens NOKPROBE_SYMBOL(do_trap);
702a0a5b22SJan Willeke
do_per_trap(struct pt_regs * regs)717a5388deSHeiko Carstens void do_per_trap(struct pt_regs *regs)
721da177e4SLinus Torvalds {
735e9a2692SMartin Schwidefsky if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
744ba069b8SMichael Grundy return;
7573b7d40fSMartin Schwidefsky if (!current->ptrace)
7673b7d40fSMartin Schwidefsky return;
779507a5d0SEric W. Biederman force_sig_fault(SIGTRAP, TRAP_HWBKPT,
782e1661d2SEric W. Biederman (void __force __user *) current->thread.per_event.address);
791da177e4SLinus Torvalds }
807a5388deSHeiko Carstens NOKPROBE_SYMBOL(do_per_trap);
811da177e4SLinus Torvalds
default_trap_handler(struct pt_regs * regs)8217a363dcSHeiko Carstens static void default_trap_handler(struct pt_regs *regs)
831da177e4SLinus Torvalds {
847d256175SHeiko Carstens if (user_mode(regs)) {
855d7eccecSHeiko Carstens report_user_fault(regs, SIGSEGV, 0);
86fcb116bcSEric W. Biederman force_exit_sig(SIGSEGV);
871da177e4SLinus Torvalds } else
88aa33c8cbSMartin Schwidefsky die(regs, "Unknown program exception");
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds
911e54622eSMartin Schwidefsky #define DO_ERROR_INFO(name, signr, sicode, str) \
926f8daa29SHeiko Carstens static void name(struct pt_regs *regs) \
931da177e4SLinus Torvalds { \
94aa33c8cbSMartin Schwidefsky do_trap(regs, signr, sicode, str); \
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds
971e54622eSMartin Schwidefsky DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
981e54622eSMartin Schwidefsky "addressing exception")
991e54622eSMartin Schwidefsky DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
1001e54622eSMartin Schwidefsky "execute exception")
1011e54622eSMartin Schwidefsky DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
1021e54622eSMartin Schwidefsky "fixpoint divide exception")
1031e54622eSMartin Schwidefsky DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
1041e54622eSMartin Schwidefsky "fixpoint overflow exception")
1051e54622eSMartin Schwidefsky DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
1061e54622eSMartin Schwidefsky "HFP overflow exception")
1071e54622eSMartin Schwidefsky DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
1081e54622eSMartin Schwidefsky "HFP underflow exception")
1091e54622eSMartin Schwidefsky DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
1101e54622eSMartin Schwidefsky "HFP significance exception")
1111e54622eSMartin Schwidefsky DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
1121e54622eSMartin Schwidefsky "HFP divide exception")
1131e54622eSMartin Schwidefsky DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
1141e54622eSMartin Schwidefsky "HFP square root exception")
1151e54622eSMartin Schwidefsky DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
1161e54622eSMartin Schwidefsky "operand exception")
1171e54622eSMartin Schwidefsky DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
1181e54622eSMartin Schwidefsky "privileged operation")
1191e54622eSMartin Schwidefsky DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
1201e54622eSMartin Schwidefsky "special operation exception")
121d35339a4SMartin Schwidefsky DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN,
122d35339a4SMartin Schwidefsky "transaction constraint exception")
123d35339a4SMartin Schwidefsky
do_fp_trap(struct pt_regs * regs,__u32 fpc)1249977e886SHendrik Brueckner static inline void do_fp_trap(struct pt_regs *regs, __u32 fpc)
1251da177e4SLinus Torvalds {
126aa33c8cbSMartin Schwidefsky int si_code = 0;
1271da177e4SLinus Torvalds /* FPC[2] is Data Exception Code */
1281da177e4SLinus Torvalds if ((fpc & 0x00000300) == 0) {
1291da177e4SLinus Torvalds /* bits 6 and 7 of DXC are 0 iff IEEE exception */
1301da177e4SLinus Torvalds if (fpc & 0x8000) /* invalid fp operation */
131aa33c8cbSMartin Schwidefsky si_code = FPE_FLTINV;
1321da177e4SLinus Torvalds else if (fpc & 0x4000) /* div by 0 */
133aa33c8cbSMartin Schwidefsky si_code = FPE_FLTDIV;
1341da177e4SLinus Torvalds else if (fpc & 0x2000) /* overflow */
135aa33c8cbSMartin Schwidefsky si_code = FPE_FLTOVF;
1361da177e4SLinus Torvalds else if (fpc & 0x1000) /* underflow */
137aa33c8cbSMartin Schwidefsky si_code = FPE_FLTUND;
1381da177e4SLinus Torvalds else if (fpc & 0x0800) /* inexact */
139aa33c8cbSMartin Schwidefsky si_code = FPE_FLTRES;
1401da177e4SLinus Torvalds }
141aa33c8cbSMartin Schwidefsky do_trap(regs, SIGFPE, si_code, "floating point exception");
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds
translation_specification_exception(struct pt_regs * regs)144f09354ffSHeiko Carstens static void translation_specification_exception(struct pt_regs *regs)
145e56da345SHeiko Carstens {
146e56da345SHeiko Carstens /* May never happen. */
147f09354ffSHeiko Carstens panic("Translation-Specification Exception");
148e56da345SHeiko Carstens }
149e56da345SHeiko Carstens
illegal_op(struct pt_regs * regs)1506f8daa29SHeiko Carstens static void illegal_op(struct pt_regs *regs)
1511da177e4SLinus Torvalds {
1521da177e4SLinus Torvalds __u8 opcode[6];
153d2c993d8SHeiko Carstens __u16 __user *location;
1542a0a5b22SJan Willeke int is_uprobe_insn = 0;
1551da177e4SLinus Torvalds int signal = 0;
1561da177e4SLinus Torvalds
157d35339a4SMartin Schwidefsky location = get_trap_ip(regs);
1581da177e4SLinus Torvalds
1597d256175SHeiko Carstens if (user_mode(regs)) {
16012bae235SHeiko Carstens if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
16112bae235SHeiko Carstens return;
1621da177e4SLinus Torvalds if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
1639507a5d0SEric W. Biederman if (current->ptrace)
1642e1661d2SEric W. Biederman force_sig_fault(SIGTRAP, TRAP_BRKPT, location);
1659507a5d0SEric W. Biederman else
1661da177e4SLinus Torvalds signal = SIGILL;
1672a0a5b22SJan Willeke #ifdef CONFIG_UPROBES
1682a0a5b22SJan Willeke } else if (*((__u16 *) opcode) == UPROBE_SWBP_INSN) {
1692a0a5b22SJan Willeke is_uprobe_insn = 1;
1702a0a5b22SJan Willeke #endif
1711da177e4SLinus Torvalds } else
1721da177e4SLinus Torvalds signal = SIGILL;
1732a0a5b22SJan Willeke }
17435df8d53SHeiko Carstens /*
1752a0a5b22SJan Willeke * We got either an illegal op in kernel mode, or user space trapped
1762a0a5b22SJan Willeke * on a uprobes illegal instruction. See if kprobes or uprobes picks
1772a0a5b22SJan Willeke * it up. If not, SIGILL.
17835df8d53SHeiko Carstens */
1792a0a5b22SJan Willeke if (is_uprobe_insn || !user_mode(regs)) {
180aa33c8cbSMartin Schwidefsky if (notify_die(DIE_BPT, "bpt", regs, 0,
18135df8d53SHeiko Carstens 3, SIGTRAP) != NOTIFY_STOP)
1821da177e4SLinus Torvalds signal = SIGILL;
18335df8d53SHeiko Carstens }
184aa33c8cbSMartin Schwidefsky if (signal)
185aa33c8cbSMartin Schwidefsky do_trap(regs, signal, ILL_ILLOPC, "illegal operation");
1861da177e4SLinus Torvalds }
1877a5388deSHeiko Carstens NOKPROBE_SYMBOL(illegal_op);
1881da177e4SLinus Torvalds
1891e54622eSMartin Schwidefsky DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
1901e54622eSMartin Schwidefsky "specification exception");
1911da177e4SLinus Torvalds
vector_exception(struct pt_regs * regs)1926f8daa29SHeiko Carstens static void vector_exception(struct pt_regs *regs)
19380703617SMartin Schwidefsky {
19480703617SMartin Schwidefsky int si_code, vic;
19580703617SMartin Schwidefsky
19680703617SMartin Schwidefsky if (!MACHINE_HAS_VX) {
19780703617SMartin Schwidefsky do_trap(regs, SIGILL, ILL_ILLOPN, "illegal operation");
19880703617SMartin Schwidefsky return;
19980703617SMartin Schwidefsky }
20080703617SMartin Schwidefsky
20180703617SMartin Schwidefsky /* get vector interrupt code from fpc */
202d0164ee2SHendrik Brueckner save_fpu_regs();
203904818e2SHendrik Brueckner vic = (current->thread.fpu.fpc & 0xf00) >> 8;
20480703617SMartin Schwidefsky switch (vic) {
20580703617SMartin Schwidefsky case 1: /* invalid vector operation */
20680703617SMartin Schwidefsky si_code = FPE_FLTINV;
20780703617SMartin Schwidefsky break;
20880703617SMartin Schwidefsky case 2: /* division by zero */
20980703617SMartin Schwidefsky si_code = FPE_FLTDIV;
21080703617SMartin Schwidefsky break;
21180703617SMartin Schwidefsky case 3: /* overflow */
21280703617SMartin Schwidefsky si_code = FPE_FLTOVF;
21380703617SMartin Schwidefsky break;
21480703617SMartin Schwidefsky case 4: /* underflow */
21580703617SMartin Schwidefsky si_code = FPE_FLTUND;
21680703617SMartin Schwidefsky break;
21780703617SMartin Schwidefsky case 5: /* inexact */
21880703617SMartin Schwidefsky si_code = FPE_FLTRES;
21980703617SMartin Schwidefsky break;
22080703617SMartin Schwidefsky default: /* unknown cause */
22180703617SMartin Schwidefsky si_code = 0;
22280703617SMartin Schwidefsky }
22380703617SMartin Schwidefsky do_trap(regs, SIGFPE, si_code, "vector exception");
22480703617SMartin Schwidefsky }
22580703617SMartin Schwidefsky
data_exception(struct pt_regs * regs)2266f8daa29SHeiko Carstens static void data_exception(struct pt_regs *regs)
2271da177e4SLinus Torvalds {
228d0164ee2SHendrik Brueckner save_fpu_regs();
229904818e2SHendrik Brueckner if (current->thread.fpu.fpc & FPC_DXC_MASK)
230904818e2SHendrik Brueckner do_fp_trap(regs, current->thread.fpu.fpc);
231b4e3133bSVasily Gorbik else
232b4e3133bSVasily Gorbik do_trap(regs, SIGILL, ILL_ILLOPN, "data exception");
2331da177e4SLinus Torvalds }
2341da177e4SLinus Torvalds
space_switch_exception(struct pt_regs * regs)2356f8daa29SHeiko Carstens static void space_switch_exception(struct pt_regs *regs)
2361da177e4SLinus Torvalds {
2371da177e4SLinus Torvalds /* Set user psw back to home space mode. */
2387d256175SHeiko Carstens if (user_mode(regs))
2391da177e4SLinus Torvalds regs->psw.mask |= PSW_ASC_HOME;
2401da177e4SLinus Torvalds /* Send SIGILL. */
241aa33c8cbSMartin Schwidefsky do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds
monitor_event_exception(struct pt_regs * regs)2446f8daa29SHeiko Carstens static void monitor_event_exception(struct pt_regs *regs)
24517248ea0SSven Schnelle {
24617248ea0SSven Schnelle if (user_mode(regs))
24717248ea0SSven Schnelle return;
24817248ea0SSven Schnelle
24917248ea0SSven Schnelle switch (report_bug(regs->psw.addr - (regs->int_code >> 16), regs)) {
25017248ea0SSven Schnelle case BUG_TRAP_TYPE_NONE:
25146fee16fSHeiko Carstens fixup_exception(regs);
25217248ea0SSven Schnelle break;
25317248ea0SSven Schnelle case BUG_TRAP_TYPE_WARN:
25417248ea0SSven Schnelle break;
25517248ea0SSven Schnelle case BUG_TRAP_TYPE_BUG:
25617248ea0SSven Schnelle die(regs, "monitor event");
25717248ea0SSven Schnelle break;
25817248ea0SSven Schnelle }
25917248ea0SSven Schnelle }
26017248ea0SSven Schnelle
kernel_stack_overflow(struct pt_regs * regs)2617a5388deSHeiko Carstens void kernel_stack_overflow(struct pt_regs *regs)
2621da177e4SLinus Torvalds {
26377eb65cbSHeiko Carstens bust_spinlocks(1);
26477eb65cbSHeiko Carstens printk("Kernel stack overflow.\n");
26577eb65cbSHeiko Carstens show_regs(regs);
26677eb65cbSHeiko Carstens bust_spinlocks(0);
2671da177e4SLinus Torvalds panic("Corrupt kernel stack, can't continue.");
2681da177e4SLinus Torvalds }
2697a5388deSHeiko Carstens NOKPROBE_SYMBOL(kernel_stack_overflow);
2701da177e4SLinus Torvalds
test_monitor_call(void)2711d49688dSHeiko Carstens static void __init test_monitor_call(void)
27217248ea0SSven Schnelle {
27317248ea0SSven Schnelle int val = 1;
27417248ea0SSven Schnelle
275b8e9cc20SIlya Leoshkevich if (!IS_ENABLED(CONFIG_BUG))
276b8e9cc20SIlya Leoshkevich return;
27717248ea0SSven Schnelle asm volatile(
27817248ea0SSven Schnelle " mc 0,0\n"
279*272abd47SHeiko Carstens "0: lhi %[val],0\n"
28017248ea0SSven Schnelle "1:\n"
28117248ea0SSven Schnelle EX_TABLE(0b, 1b)
282*272abd47SHeiko Carstens : [val] "+d" (val));
28317248ea0SSven Schnelle if (!val)
28417248ea0SSven Schnelle panic("Monitor call doesn't work!\n");
28517248ea0SSven Schnelle }
28617248ea0SSven Schnelle
trap_init(void)2871da177e4SLinus Torvalds void __init trap_init(void)
2881da177e4SLinus Torvalds {
289f3e1a273SHeiko Carstens local_mcck_enable();
29017248ea0SSven Schnelle test_monitor_call();
2911da177e4SLinus Torvalds }
29256e62a73SSven Schnelle
2936f8daa29SHeiko Carstens static void (*pgm_check_table[128])(struct pt_regs *regs);
2946f8daa29SHeiko Carstens
__do_pgm_check(struct pt_regs * regs)29556e62a73SSven Schnelle void noinstr __do_pgm_check(struct pt_regs *regs)
29656e62a73SSven Schnelle {
297fbf50f47SSven Schnelle unsigned int trapnr;
29856e62a73SSven Schnelle irqentry_state_t state;
29956e62a73SSven Schnelle
30052b739e2SHeiko Carstens regs->int_code = S390_lowcore.pgm_int_code;
30156e62a73SSven Schnelle regs->int_parm_long = S390_lowcore.trans_exc_code;
30256e62a73SSven Schnelle
30356e62a73SSven Schnelle state = irqentry_enter(regs);
30456e62a73SSven Schnelle
30556e62a73SSven Schnelle if (user_mode(regs)) {
30656e62a73SSven Schnelle update_timer_sys();
3073b051e89SSven Schnelle if (!static_branch_likely(&cpu_has_bear)) {
3083b051e89SSven Schnelle if (regs->last_break < 4096)
3093b051e89SSven Schnelle regs->last_break = 1;
3103b051e89SSven Schnelle }
3113b051e89SSven Schnelle current->thread.last_break = regs->last_break;
31256e62a73SSven Schnelle }
31356e62a73SSven Schnelle
31456e62a73SSven Schnelle if (S390_lowcore.pgm_code & 0x0200) {
31556e62a73SSven Schnelle /* transaction abort */
316755112b3SSven Schnelle current->thread.trap_tdb = S390_lowcore.pgm_tdb;
31756e62a73SSven Schnelle }
31856e62a73SSven Schnelle
31956e62a73SSven Schnelle if (S390_lowcore.pgm_code & PGM_INT_CODE_PER) {
32056e62a73SSven Schnelle if (user_mode(regs)) {
32156e62a73SSven Schnelle struct per_event *ev = ¤t->thread.per_event;
32256e62a73SSven Schnelle
32356e62a73SSven Schnelle set_thread_flag(TIF_PER_TRAP);
32456e62a73SSven Schnelle ev->address = S390_lowcore.per_address;
325998e7800SHeiko Carstens ev->cause = S390_lowcore.per_code_combined;
32656e62a73SSven Schnelle ev->paid = S390_lowcore.per_access_id;
32756e62a73SSven Schnelle } else {
32856e62a73SSven Schnelle /* PER event in kernel is kprobes */
32956e62a73SSven Schnelle __arch_local_irq_ssm(regs->psw.mask & ~PSW_MASK_PER);
33056e62a73SSven Schnelle do_per_trap(regs);
33156e62a73SSven Schnelle goto out;
33256e62a73SSven Schnelle }
33356e62a73SSven Schnelle }
33456e62a73SSven Schnelle
33556e62a73SSven Schnelle if (!irqs_disabled_flags(regs->psw.mask))
33656e62a73SSven Schnelle trace_hardirqs_on();
33756e62a73SSven Schnelle __arch_local_irq_ssm(regs->psw.mask & ~PSW_MASK_PER);
33856e62a73SSven Schnelle
33956e62a73SSven Schnelle trapnr = regs->int_code & PGM_INT_CODE_MASK;
34056e62a73SSven Schnelle if (trapnr)
34156e62a73SSven Schnelle pgm_check_table[trapnr](regs);
34256e62a73SSven Schnelle out:
34356e62a73SSven Schnelle local_irq_disable();
34456e62a73SSven Schnelle irqentry_exit(regs, state);
34556e62a73SSven Schnelle }
3466f8daa29SHeiko Carstens
3476f8daa29SHeiko Carstens /*
3486f8daa29SHeiko Carstens * The program check table contains exactly 128 (0x00-0x7f) entries. Each
3496f8daa29SHeiko Carstens * line defines the function to be called corresponding to the program check
3506f8daa29SHeiko Carstens * interruption code.
3516f8daa29SHeiko Carstens */
3526f8daa29SHeiko Carstens static void (*pgm_check_table[128])(struct pt_regs *regs) = {
3536f8daa29SHeiko Carstens [0x00] = default_trap_handler,
3546f8daa29SHeiko Carstens [0x01] = illegal_op,
3556f8daa29SHeiko Carstens [0x02] = privileged_op,
3566f8daa29SHeiko Carstens [0x03] = execute_exception,
3576f8daa29SHeiko Carstens [0x04] = do_protection_exception,
3586f8daa29SHeiko Carstens [0x05] = addressing_exception,
3596f8daa29SHeiko Carstens [0x06] = specification_exception,
3606f8daa29SHeiko Carstens [0x07] = data_exception,
3616f8daa29SHeiko Carstens [0x08] = overflow_exception,
3626f8daa29SHeiko Carstens [0x09] = divide_exception,
3636f8daa29SHeiko Carstens [0x0a] = overflow_exception,
3646f8daa29SHeiko Carstens [0x0b] = divide_exception,
3656f8daa29SHeiko Carstens [0x0c] = hfp_overflow_exception,
3666f8daa29SHeiko Carstens [0x0d] = hfp_underflow_exception,
3676f8daa29SHeiko Carstens [0x0e] = hfp_significance_exception,
3686f8daa29SHeiko Carstens [0x0f] = hfp_divide_exception,
3696f8daa29SHeiko Carstens [0x10] = do_dat_exception,
3706f8daa29SHeiko Carstens [0x11] = do_dat_exception,
371f09354ffSHeiko Carstens [0x12] = translation_specification_exception,
3726f8daa29SHeiko Carstens [0x13] = special_op_exception,
3736f8daa29SHeiko Carstens [0x14] = default_trap_handler,
3746f8daa29SHeiko Carstens [0x15] = operand_exception,
3756f8daa29SHeiko Carstens [0x16] = default_trap_handler,
3766f8daa29SHeiko Carstens [0x17] = default_trap_handler,
3776f8daa29SHeiko Carstens [0x18] = transaction_exception,
3786f8daa29SHeiko Carstens [0x19] = default_trap_handler,
3796f8daa29SHeiko Carstens [0x1a] = default_trap_handler,
3806f8daa29SHeiko Carstens [0x1b] = vector_exception,
3816f8daa29SHeiko Carstens [0x1c] = space_switch_exception,
3826f8daa29SHeiko Carstens [0x1d] = hfp_sqrt_exception,
3836f8daa29SHeiko Carstens [0x1e ... 0x37] = default_trap_handler,
3846f8daa29SHeiko Carstens [0x38] = do_dat_exception,
3856f8daa29SHeiko Carstens [0x39] = do_dat_exception,
3866f8daa29SHeiko Carstens [0x3a] = do_dat_exception,
3876f8daa29SHeiko Carstens [0x3b] = do_dat_exception,
3886f8daa29SHeiko Carstens [0x3c] = default_trap_handler,
3896f8daa29SHeiko Carstens [0x3d] = do_secure_storage_access,
3906f8daa29SHeiko Carstens [0x3e] = do_non_secure_storage_access,
3916f8daa29SHeiko Carstens [0x3f] = do_secure_storage_violation,
3926f8daa29SHeiko Carstens [0x40] = monitor_event_exception,
3936f8daa29SHeiko Carstens [0x41 ... 0x7f] = default_trap_handler,
3946f8daa29SHeiko Carstens };
39517a363dcSHeiko Carstens
39617a363dcSHeiko Carstens #define COND_TRAP(x) asm( \
39717a363dcSHeiko Carstens ".weak " __stringify(x) "\n\t" \
39817a363dcSHeiko Carstens ".set " __stringify(x) "," \
39917a363dcSHeiko Carstens __stringify(default_trap_handler))
40017a363dcSHeiko Carstens
40117a363dcSHeiko Carstens COND_TRAP(do_secure_storage_access);
40217a363dcSHeiko Carstens COND_TRAP(do_non_secure_storage_access);
40317a363dcSHeiko Carstens COND_TRAP(do_secure_storage_violation);
404