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