linux/arch/s390/kernel/traps.c
<<
>>
Prefs
   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/randomize_kstack.h>
  21#include <linux/extable.h>
  22#include <linux/ptrace.h>
  23#include <linux/sched.h>
  24#include <linux/sched/debug.h>
  25#include <linux/mm.h>
  26#include <linux/slab.h>
  27#include <linux/uaccess.h>
  28#include <linux/cpu.h>
  29#include <linux/entry-common.h>
  30#include <asm/asm-extable.h>
  31#include <asm/fpu/api.h>
  32#include <asm/vtime.h>
  33#include "entry.h"
  34
  35static inline void __user *get_trap_ip(struct pt_regs *regs)
  36{
  37        unsigned long address;
  38
  39        if (regs->int_code & 0x200)
  40                address = current->thread.trap_tdb.data[3];
  41        else
  42                address = regs->psw.addr;
  43        return (void __user *) (address - (regs->int_code >> 16));
  44}
  45
  46int is_valid_bugaddr(unsigned long addr)
  47{
  48        return 1;
  49}
  50
  51void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
  52{
  53        if (user_mode(regs)) {
  54                force_sig_fault(si_signo, si_code, get_trap_ip(regs));
  55                report_user_fault(regs, si_signo, 0);
  56        } else {
  57                if (!fixup_exception(regs))
  58                        die(regs, str);
  59        }
  60}
  61
  62static 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}
  69NOKPROBE_SYMBOL(do_trap);
  70
  71void 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}
  80NOKPROBE_SYMBOL(do_per_trap);
  81
  82static void default_trap_handler(struct pt_regs *regs)
  83{
  84        if (user_mode(regs)) {
  85                report_user_fault(regs, SIGSEGV, 0);
  86                force_exit_sig(SIGSEGV);
  87        } else
  88                die(regs, "Unknown program exception");
  89}
  90
  91#define DO_ERROR_INFO(name, signr, sicode, str) \
  92static void name(struct pt_regs *regs)          \
  93{                                               \
  94        do_trap(regs, signr, sicode, str);      \
  95}
  96
  97DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
  98              "addressing exception")
  99DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
 100              "execute exception")
 101DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
 102              "fixpoint divide exception")
 103DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
 104              "fixpoint overflow exception")
 105DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
 106              "HFP overflow exception")
 107DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
 108              "HFP underflow exception")
 109DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
 110              "HFP significance exception")
 111DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
 112              "HFP divide exception")
 113DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
 114              "HFP square root exception")
 115DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
 116              "operand exception")
 117DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
 118              "privileged operation")
 119DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
 120              "special operation exception")
 121DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN,
 122              "transaction constraint exception")
 123
 124static 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
 144static void translation_specification_exception(struct pt_regs *regs)
 145{
 146        /* May never happen. */
 147        panic("Translation-Specification Exception");
 148}
 149
 150static 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}
 187NOKPROBE_SYMBOL(illegal_op);
 188
 189DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
 190              "specification exception");
 191
 192static 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
 226static 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
 235static 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
 244static void monitor_event_exception(struct pt_regs *regs)
 245{
 246        if (user_mode(regs))
 247                return;
 248
 249        switch (report_bug(regs->psw.addr - (regs->int_code >> 16), regs)) {
 250        case BUG_TRAP_TYPE_NONE:
 251                fixup_exception(regs);
 252                break;
 253        case BUG_TRAP_TYPE_WARN:
 254                break;
 255        case BUG_TRAP_TYPE_BUG:
 256                die(regs, "monitor event");
 257                break;
 258        }
 259}
 260
 261void kernel_stack_overflow(struct pt_regs *regs)
 262{
 263        bust_spinlocks(1);
 264        printk("Kernel stack overflow.\n");
 265        show_regs(regs);
 266        bust_spinlocks(0);
 267        panic("Corrupt kernel stack, can't continue.");
 268}
 269NOKPROBE_SYMBOL(kernel_stack_overflow);
 270
 271static void __init test_monitor_call(void)
 272{
 273        int val = 1;
 274
 275        if (!IS_ENABLED(CONFIG_BUG))
 276                return;
 277        asm volatile(
 278                "       mc      0,0\n"
 279                "0:     xgr     %0,%0\n"
 280                "1:\n"
 281                EX_TABLE(0b,1b)
 282                : "+d" (val));
 283        if (!val)
 284                panic("Monitor call doesn't work!\n");
 285}
 286
 287void __init trap_init(void)
 288{
 289        local_mcck_enable();
 290        test_monitor_call();
 291}
 292
 293static void (*pgm_check_table[128])(struct pt_regs *regs);
 294
 295void noinstr __do_pgm_check(struct pt_regs *regs)
 296{
 297        unsigned int trapnr;
 298        irqentry_state_t state;
 299
 300        regs->int_code = S390_lowcore.pgm_int_code;
 301        regs->int_parm_long = S390_lowcore.trans_exc_code;
 302
 303        state = irqentry_enter(regs);
 304
 305        if (user_mode(regs)) {
 306                update_timer_sys();
 307                if (!static_branch_likely(&cpu_has_bear)) {
 308                        if (regs->last_break < 4096)
 309                                regs->last_break = 1;
 310                }
 311                current->thread.last_break = regs->last_break;
 312        }
 313
 314        if (S390_lowcore.pgm_code & 0x0200) {
 315                /* transaction abort */
 316                current->thread.trap_tdb = S390_lowcore.pgm_tdb;
 317        }
 318
 319        if (S390_lowcore.pgm_code & PGM_INT_CODE_PER) {
 320                if (user_mode(regs)) {
 321                        struct per_event *ev = &current->thread.per_event;
 322
 323                        set_thread_flag(TIF_PER_TRAP);
 324                        ev->address = S390_lowcore.per_address;
 325                        ev->cause = S390_lowcore.per_code_combined;
 326                        ev->paid = S390_lowcore.per_access_id;
 327                } else {
 328                        /* PER event in kernel is kprobes */
 329                        __arch_local_irq_ssm(regs->psw.mask & ~PSW_MASK_PER);
 330                        do_per_trap(regs);
 331                        goto out;
 332                }
 333        }
 334
 335        if (!irqs_disabled_flags(regs->psw.mask))
 336                trace_hardirqs_on();
 337        __arch_local_irq_ssm(regs->psw.mask & ~PSW_MASK_PER);
 338
 339        trapnr = regs->int_code & PGM_INT_CODE_MASK;
 340        if (trapnr)
 341                pgm_check_table[trapnr](regs);
 342out:
 343        local_irq_disable();
 344        irqentry_exit(regs, state);
 345}
 346
 347/*
 348 * The program check table contains exactly 128 (0x00-0x7f) entries. Each
 349 * line defines the function to be called corresponding to the program check
 350 * interruption code.
 351 */
 352static void (*pgm_check_table[128])(struct pt_regs *regs) = {
 353        [0x00]          = default_trap_handler,
 354        [0x01]          = illegal_op,
 355        [0x02]          = privileged_op,
 356        [0x03]          = execute_exception,
 357        [0x04]          = do_protection_exception,
 358        [0x05]          = addressing_exception,
 359        [0x06]          = specification_exception,
 360        [0x07]          = data_exception,
 361        [0x08]          = overflow_exception,
 362        [0x09]          = divide_exception,
 363        [0x0a]          = overflow_exception,
 364        [0x0b]          = divide_exception,
 365        [0x0c]          = hfp_overflow_exception,
 366        [0x0d]          = hfp_underflow_exception,
 367        [0x0e]          = hfp_significance_exception,
 368        [0x0f]          = hfp_divide_exception,
 369        [0x10]          = do_dat_exception,
 370        [0x11]          = do_dat_exception,
 371        [0x12]          = translation_specification_exception,
 372        [0x13]          = special_op_exception,
 373        [0x14]          = default_trap_handler,
 374        [0x15]          = operand_exception,
 375        [0x16]          = default_trap_handler,
 376        [0x17]          = default_trap_handler,
 377        [0x18]          = transaction_exception,
 378        [0x19]          = default_trap_handler,
 379        [0x1a]          = default_trap_handler,
 380        [0x1b]          = vector_exception,
 381        [0x1c]          = space_switch_exception,
 382        [0x1d]          = hfp_sqrt_exception,
 383        [0x1e ... 0x37] = default_trap_handler,
 384        [0x38]          = do_dat_exception,
 385        [0x39]          = do_dat_exception,
 386        [0x3a]          = do_dat_exception,
 387        [0x3b]          = do_dat_exception,
 388        [0x3c]          = default_trap_handler,
 389        [0x3d]          = do_secure_storage_access,
 390        [0x3e]          = do_non_secure_storage_access,
 391        [0x3f]          = do_secure_storage_violation,
 392        [0x40]          = monitor_event_exception,
 393        [0x41 ... 0x7f] = default_trap_handler,
 394};
 395
 396#define COND_TRAP(x) asm(                       \
 397        ".weak " __stringify(x) "\n\t"          \
 398        ".set  " __stringify(x) ","             \
 399        __stringify(default_trap_handler))
 400
 401COND_TRAP(do_secure_storage_access);
 402COND_TRAP(do_non_secure_storage_access);
 403COND_TRAP(do_secure_storage_violation);
 404