^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * S390 version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright IBM Corp. 1999, 2000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Derived from "arch/i386/kernel/traps.c"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 1991, 1992 Linus Torvalds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * 'Traps.c' handles hardware traps and faults after we have saved some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * state in 'asm.s'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kprobes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/kdebug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/extable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/sched/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/fpu/api.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "entry.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static inline void __user *get_trap_ip(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) unsigned long address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (regs->int_code & 0x200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) address = *(unsigned long *)(current->thread.trap_tdb + 24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) address = regs->psw.addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return (void __user *) (address - (regs->int_code >> 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int is_valid_bugaddr(unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (user_mode(regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) force_sig_fault(si_signo, si_code, get_trap_ip(regs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) report_user_fault(regs, si_signo, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) const struct exception_table_entry *fixup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) fixup = s390_search_extables(regs->psw.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (!fixup || !ex_handle(fixup, regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) die(regs, str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static void do_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (notify_die(DIE_TRAP, str, regs, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) regs->int_code, si_signo) == NOTIFY_STOP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) do_report_trap(regs, si_signo, si_code, str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) NOKPROBE_SYMBOL(do_trap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) void do_per_trap(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (!current->ptrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) force_sig_fault(SIGTRAP, TRAP_HWBKPT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) (void __force __user *) current->thread.per_event.address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) NOKPROBE_SYMBOL(do_per_trap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) void default_trap_handler(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (user_mode(regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) report_user_fault(regs, SIGSEGV, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) do_exit(SIGSEGV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) die(regs, "Unknown program exception");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define DO_ERROR_INFO(name, signr, sicode, str) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) void name(struct pt_regs *regs) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) do_trap(regs, signr, sicode, str); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) "addressing exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) "execute exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) "fixpoint divide exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) "fixpoint overflow exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) "HFP overflow exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) "HFP underflow exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) "HFP significance exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) "HFP divide exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) "HFP square root exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) "operand exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) "privileged operation")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) "special operation exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) "transaction constraint exception")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static inline void do_fp_trap(struct pt_regs *regs, __u32 fpc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) int si_code = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* FPC[2] is Data Exception Code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if ((fpc & 0x00000300) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* bits 6 and 7 of DXC are 0 iff IEEE exception */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (fpc & 0x8000) /* invalid fp operation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) si_code = FPE_FLTINV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) else if (fpc & 0x4000) /* div by 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) si_code = FPE_FLTDIV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) else if (fpc & 0x2000) /* overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) si_code = FPE_FLTOVF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) else if (fpc & 0x1000) /* underflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) si_code = FPE_FLTUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) else if (fpc & 0x0800) /* inexact */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) si_code = FPE_FLTRES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) do_trap(regs, SIGFPE, si_code, "floating point exception");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) void translation_exception(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* May never happen. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) panic("Translation exception");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) void illegal_op(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) __u8 opcode[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) __u16 __user *location;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) int is_uprobe_insn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) int signal = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) location = get_trap_ip(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (user_mode(regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (current->ptrace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) force_sig_fault(SIGTRAP, TRAP_BRKPT, location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) signal = SIGILL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #ifdef CONFIG_UPROBES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) } else if (*((__u16 *) opcode) == UPROBE_SWBP_INSN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) is_uprobe_insn = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) signal = SIGILL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * We got either an illegal op in kernel mode, or user space trapped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * on a uprobes illegal instruction. See if kprobes or uprobes picks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * it up. If not, SIGILL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (is_uprobe_insn || !user_mode(regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (notify_die(DIE_BPT, "bpt", regs, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 3, SIGTRAP) != NOTIFY_STOP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) signal = SIGILL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (signal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) do_trap(regs, signal, ILL_ILLOPC, "illegal operation");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) NOKPROBE_SYMBOL(illegal_op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) "specification exception");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) void vector_exception(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) int si_code, vic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (!MACHINE_HAS_VX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) do_trap(regs, SIGILL, ILL_ILLOPN, "illegal operation");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /* get vector interrupt code from fpc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) save_fpu_regs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) vic = (current->thread.fpu.fpc & 0xf00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) switch (vic) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) case 1: /* invalid vector operation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) si_code = FPE_FLTINV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) case 2: /* division by zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) si_code = FPE_FLTDIV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) case 3: /* overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) si_code = FPE_FLTOVF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) case 4: /* underflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) si_code = FPE_FLTUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) case 5: /* inexact */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) si_code = FPE_FLTRES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) default: /* unknown cause */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) si_code = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) do_trap(regs, SIGFPE, si_code, "vector exception");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) void data_exception(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) save_fpu_regs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (current->thread.fpu.fpc & FPC_DXC_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) do_fp_trap(regs, current->thread.fpu.fpc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) do_trap(regs, SIGILL, ILL_ILLOPN, "data exception");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) void space_switch_exception(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /* Set user psw back to home space mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (user_mode(regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) regs->psw.mask |= PSW_ASC_HOME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) /* Send SIGILL. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) void monitor_event_exception(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) const struct exception_table_entry *fixup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (user_mode(regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) switch (report_bug(regs->psw.addr - (regs->int_code >> 16), regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) case BUG_TRAP_TYPE_NONE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) fixup = s390_search_extables(regs->psw.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (fixup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) ex_handle(fixup, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) case BUG_TRAP_TYPE_WARN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) case BUG_TRAP_TYPE_BUG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) die(regs, "monitor event");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) void kernel_stack_overflow(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) bust_spinlocks(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) printk("Kernel stack overflow.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) show_regs(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) bust_spinlocks(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) panic("Corrupt kernel stack, can't continue.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) NOKPROBE_SYMBOL(kernel_stack_overflow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static void __init test_monitor_call(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) int val = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (!IS_ENABLED(CONFIG_BUG))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) " mc 0,0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) "0: xgr %0,%0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) "1:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) EX_TABLE(0b,1b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) : "+d" (val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (!val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) panic("Monitor call doesn't work!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) void __init trap_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) sort_extable(__start_dma_ex_table, __stop_dma_ex_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) local_mcck_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) test_monitor_call();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }