linux/arch/sh/kernel/traps_32.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * 'traps.c' handles hardware traps and faults after we have saved some
   4 * state in 'entry.S'.
   5 *
   6 *  SuperH version: Copyright (C) 1999 Niibe Yutaka
   7 *                  Copyright (C) 2000 Philipp Rumpf
   8 *                  Copyright (C) 2000 David Howells
   9 *                  Copyright (C) 2002 - 2010 Paul Mundt
  10 */
  11#include <linux/kernel.h>
  12#include <linux/ptrace.h>
  13#include <linux/hardirq.h>
  14#include <linux/init.h>
  15#include <linux/spinlock.h>
  16#include <linux/kallsyms.h>
  17#include <linux/io.h>
  18#include <linux/bug.h>
  19#include <linux/debug_locks.h>
  20#include <linux/kdebug.h>
  21#include <linux/limits.h>
  22#include <linux/sysfs.h>
  23#include <linux/uaccess.h>
  24#include <linux/perf_event.h>
  25#include <linux/sched/task_stack.h>
  26
  27#include <asm/alignment.h>
  28#include <asm/fpu.h>
  29#include <asm/kprobes.h>
  30#include <asm/traps.h>
  31#include <asm/bl_bit.h>
  32
  33#ifdef CONFIG_CPU_SH2
  34# define TRAP_RESERVED_INST     4
  35# define TRAP_ILLEGAL_SLOT_INST 6
  36# define TRAP_ADDRESS_ERROR     9
  37# ifdef CONFIG_CPU_SH2A
  38#  define TRAP_UBC              12
  39#  define TRAP_FPU_ERROR        13
  40#  define TRAP_DIVZERO_ERROR    17
  41#  define TRAP_DIVOVF_ERROR     18
  42# endif
  43#else
  44#define TRAP_RESERVED_INST      12
  45#define TRAP_ILLEGAL_SLOT_INST  13
  46#endif
  47
  48static inline void sign_extend(unsigned int count, unsigned char *dst)
  49{
  50#ifdef __LITTLE_ENDIAN__
  51        if ((count == 1) && dst[0] & 0x80) {
  52                dst[1] = 0xff;
  53                dst[2] = 0xff;
  54                dst[3] = 0xff;
  55        }
  56        if ((count == 2) && dst[1] & 0x80) {
  57                dst[2] = 0xff;
  58                dst[3] = 0xff;
  59        }
  60#else
  61        if ((count == 1) && dst[3] & 0x80) {
  62                dst[2] = 0xff;
  63                dst[1] = 0xff;
  64                dst[0] = 0xff;
  65        }
  66        if ((count == 2) && dst[2] & 0x80) {
  67                dst[1] = 0xff;
  68                dst[0] = 0xff;
  69        }
  70#endif
  71}
  72
  73static struct mem_access user_mem_access = {
  74        copy_from_user,
  75        copy_to_user,
  76};
  77
  78/*
  79 * handle an instruction that does an unaligned memory access by emulating the
  80 * desired behaviour
  81 * - note that PC _may not_ point to the faulting instruction
  82 *   (if that instruction is in a branch delay slot)
  83 * - return 0 if emulation okay, -EFAULT on existential error
  84 */
  85static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs,
  86                                struct mem_access *ma)
  87{
  88        int ret, index, count;
  89        unsigned long *rm, *rn;
  90        unsigned char *src, *dst;
  91        unsigned char __user *srcu, *dstu;
  92
  93        index = (instruction>>8)&15;    /* 0x0F00 */
  94        rn = &regs->regs[index];
  95
  96        index = (instruction>>4)&15;    /* 0x00F0 */
  97        rm = &regs->regs[index];
  98
  99        count = 1<<(instruction&3);
 100
 101        switch (count) {
 102        case 1: inc_unaligned_byte_access(); break;
 103        case 2: inc_unaligned_word_access(); break;
 104        case 4: inc_unaligned_dword_access(); break;
 105        case 8: inc_unaligned_multi_access(); break;
 106        }
 107
 108        ret = -EFAULT;
 109        switch (instruction>>12) {
 110        case 0: /* mov.[bwl] to/from memory via r0+rn */
 111                if (instruction & 8) {
 112                        /* from memory */
 113                        srcu = (unsigned char __user *)*rm;
 114                        srcu += regs->regs[0];
 115                        dst = (unsigned char *)rn;
 116                        *(unsigned long *)dst = 0;
 117
 118#if !defined(__LITTLE_ENDIAN__)
 119                        dst += 4-count;
 120#endif
 121                        if (ma->from(dst, srcu, count))
 122                                goto fetch_fault;
 123
 124                        sign_extend(count, dst);
 125                } else {
 126                        /* to memory */
 127                        src = (unsigned char *)rm;
 128#if !defined(__LITTLE_ENDIAN__)
 129                        src += 4-count;
 130#endif
 131                        dstu = (unsigned char __user *)*rn;
 132                        dstu += regs->regs[0];
 133
 134                        if (ma->to(dstu, src, count))
 135                                goto fetch_fault;
 136                }
 137                ret = 0;
 138                break;
 139
 140        case 1: /* mov.l Rm,@(disp,Rn) */
 141                src = (unsigned char*) rm;
 142                dstu = (unsigned char __user *)*rn;
 143                dstu += (instruction&0x000F)<<2;
 144
 145                if (ma->to(dstu, src, 4))
 146                        goto fetch_fault;
 147                ret = 0;
 148                break;
 149
 150        case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
 151                if (instruction & 4)
 152                        *rn -= count;
 153                src = (unsigned char*) rm;
 154                dstu = (unsigned char __user *)*rn;
 155#if !defined(__LITTLE_ENDIAN__)
 156                src += 4-count;
 157#endif
 158                if (ma->to(dstu, src, count))
 159                        goto fetch_fault;
 160                ret = 0;
 161                break;
 162
 163        case 5: /* mov.l @(disp,Rm),Rn */
 164                srcu = (unsigned char __user *)*rm;
 165                srcu += (instruction & 0x000F) << 2;
 166                dst = (unsigned char *)rn;
 167                *(unsigned long *)dst = 0;
 168
 169                if (ma->from(dst, srcu, 4))
 170                        goto fetch_fault;
 171                ret = 0;
 172                break;
 173
 174        case 6: /* mov.[bwl] from memory, possibly with post-increment */
 175                srcu = (unsigned char __user *)*rm;
 176                if (instruction & 4)
 177                        *rm += count;
 178                dst = (unsigned char*) rn;
 179                *(unsigned long*)dst = 0;
 180
 181#if !defined(__LITTLE_ENDIAN__)
 182                dst += 4-count;
 183#endif
 184                if (ma->from(dst, srcu, count))
 185                        goto fetch_fault;
 186                sign_extend(count, dst);
 187                ret = 0;
 188                break;
 189
 190        case 8:
 191                switch ((instruction&0xFF00)>>8) {
 192                case 0x81: /* mov.w R0,@(disp,Rn) */
 193                        src = (unsigned char *) &regs->regs[0];
 194#if !defined(__LITTLE_ENDIAN__)
 195                        src += 2;
 196#endif
 197                        dstu = (unsigned char __user *)*rm; /* called Rn in the spec */
 198                        dstu += (instruction & 0x000F) << 1;
 199
 200                        if (ma->to(dstu, src, 2))
 201                                goto fetch_fault;
 202                        ret = 0;
 203                        break;
 204
 205                case 0x85: /* mov.w @(disp,Rm),R0 */
 206                        srcu = (unsigned char __user *)*rm;
 207                        srcu += (instruction & 0x000F) << 1;
 208                        dst = (unsigned char *) &regs->regs[0];
 209                        *(unsigned long *)dst = 0;
 210
 211#if !defined(__LITTLE_ENDIAN__)
 212                        dst += 2;
 213#endif
 214                        if (ma->from(dst, srcu, 2))
 215                                goto fetch_fault;
 216                        sign_extend(2, dst);
 217                        ret = 0;
 218                        break;
 219                }
 220                break;
 221
 222        case 9: /* mov.w @(disp,PC),Rn */
 223                srcu = (unsigned char __user *)regs->pc;
 224                srcu += 4;
 225                srcu += (instruction & 0x00FF) << 1;
 226                dst = (unsigned char *)rn;
 227                *(unsigned long *)dst = 0;
 228
 229#if !defined(__LITTLE_ENDIAN__)
 230                dst += 2;
 231#endif
 232
 233                if (ma->from(dst, srcu, 2))
 234                        goto fetch_fault;
 235                sign_extend(2, dst);
 236                ret = 0;
 237                break;
 238
 239        case 0xd: /* mov.l @(disp,PC),Rn */
 240                srcu = (unsigned char __user *)(regs->pc & ~0x3);
 241                srcu += 4;
 242                srcu += (instruction & 0x00FF) << 2;
 243                dst = (unsigned char *)rn;
 244                *(unsigned long *)dst = 0;
 245
 246                if (ma->from(dst, srcu, 4))
 247                        goto fetch_fault;
 248                ret = 0;
 249                break;
 250        }
 251        return ret;
 252
 253 fetch_fault:
 254        /* Argh. Address not only misaligned but also non-existent.
 255         * Raise an EFAULT and see if it's trapped
 256         */
 257        die_if_no_fixup("Fault in unaligned fixup", regs, 0);
 258        return -EFAULT;
 259}
 260
 261/*
 262 * emulate the instruction in the delay slot
 263 * - fetches the instruction from PC+2
 264 */
 265static inline int handle_delayslot(struct pt_regs *regs,
 266                                   insn_size_t old_instruction,
 267                                   struct mem_access *ma)
 268{
 269        insn_size_t instruction;
 270        void __user *addr = (void __user *)(regs->pc +
 271                instruction_size(old_instruction));
 272
 273        if (copy_from_user(&instruction, addr, sizeof(instruction))) {
 274                /* the instruction-fetch faulted */
 275                if (user_mode(regs))
 276                        return -EFAULT;
 277
 278                /* kernel */
 279                die("delay-slot-insn faulting in handle_unaligned_delayslot",
 280                    regs, 0);
 281        }
 282
 283        return handle_unaligned_ins(instruction, regs, ma);
 284}
 285
 286/*
 287 * handle an instruction that does an unaligned memory access
 288 * - have to be careful of branch delay-slot instructions that fault
 289 *  SH3:
 290 *   - if the branch would be taken PC points to the branch
 291 *   - if the branch would not be taken, PC points to delay-slot
 292 *  SH4:
 293 *   - PC always points to delayed branch
 294 * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
 295 */
 296
 297/* Macros to determine offset from current PC for branch instructions */
 298/* Explicit type coercion is used to force sign extension where needed */
 299#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
 300#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
 301
 302int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
 303                            struct mem_access *ma, int expected,
 304                            unsigned long address)
 305{
 306        u_int rm;
 307        int ret, index;
 308
 309        /*
 310         * XXX: We can't handle mixed 16/32-bit instructions yet
 311         */
 312        if (instruction_size(instruction) != 2)
 313                return -EINVAL;
 314
 315        index = (instruction>>8)&15;    /* 0x0F00 */
 316        rm = regs->regs[index];
 317
 318        /*
 319         * Log the unexpected fixups, and then pass them on to perf.
 320         *
 321         * We intentionally don't report the expected cases to perf as
 322         * otherwise the trapped I/O case will skew the results too much
 323         * to be useful.
 324         */
 325        if (!expected) {
 326                unaligned_fixups_notify(current, instruction, regs);
 327                perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1,
 328                              regs, address);
 329        }
 330
 331        ret = -EFAULT;
 332        switch (instruction&0xF000) {
 333        case 0x0000:
 334                if (instruction==0x000B) {
 335                        /* rts */
 336                        ret = handle_delayslot(regs, instruction, ma);
 337                        if (ret==0)
 338                                regs->pc = regs->pr;
 339                }
 340                else if ((instruction&0x00FF)==0x0023) {
 341                        /* braf @Rm */
 342                        ret = handle_delayslot(regs, instruction, ma);
 343                        if (ret==0)
 344                                regs->pc += rm + 4;
 345                }
 346                else if ((instruction&0x00FF)==0x0003) {
 347                        /* bsrf @Rm */
 348                        ret = handle_delayslot(regs, instruction, ma);
 349                        if (ret==0) {
 350                                regs->pr = regs->pc + 4;
 351                                regs->pc += rm + 4;
 352                        }
 353                }
 354                else {
 355                        /* mov.[bwl] to/from memory via r0+rn */
 356                        goto simple;
 357                }
 358                break;
 359
 360        case 0x1000: /* mov.l Rm,@(disp,Rn) */
 361                goto simple;
 362
 363        case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
 364                goto simple;
 365
 366        case 0x4000:
 367                if ((instruction&0x00FF)==0x002B) {
 368                        /* jmp @Rm */
 369                        ret = handle_delayslot(regs, instruction, ma);
 370                        if (ret==0)
 371                                regs->pc = rm;
 372                }
 373                else if ((instruction&0x00FF)==0x000B) {
 374                        /* jsr @Rm */
 375                        ret = handle_delayslot(regs, instruction, ma);
 376                        if (ret==0) {
 377                                regs->pr = regs->pc + 4;
 378                                regs->pc = rm;
 379                        }
 380                }
 381                else {
 382                        /* mov.[bwl] to/from memory via r0+rn */
 383                        goto simple;
 384                }
 385                break;
 386
 387        case 0x5000: /* mov.l @(disp,Rm),Rn */
 388                goto simple;
 389
 390        case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
 391                goto simple;
 392
 393        case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
 394                switch (instruction&0x0F00) {
 395                case 0x0100: /* mov.w R0,@(disp,Rm) */
 396                        goto simple;
 397                case 0x0500: /* mov.w @(disp,Rm),R0 */
 398                        goto simple;
 399                case 0x0B00: /* bf   lab - no delayslot*/
 400                        ret = 0;
 401                        break;
 402                case 0x0F00: /* bf/s lab */
 403                        ret = handle_delayslot(regs, instruction, ma);
 404                        if (ret==0) {
 405#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
 406                                if ((regs->sr & 0x00000001) != 0)
 407                                        regs->pc += 4; /* next after slot */
 408                                else
 409#endif
 410                                        regs->pc += SH_PC_8BIT_OFFSET(instruction);
 411                        }
 412                        break;
 413                case 0x0900: /* bt   lab - no delayslot */
 414                        ret = 0;
 415                        break;
 416                case 0x0D00: /* bt/s lab */
 417                        ret = handle_delayslot(regs, instruction, ma);
 418                        if (ret==0) {
 419#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
 420                                if ((regs->sr & 0x00000001) == 0)
 421                                        regs->pc += 4; /* next after slot */
 422                                else
 423#endif
 424                                        regs->pc += SH_PC_8BIT_OFFSET(instruction);
 425                        }
 426                        break;
 427                }
 428                break;
 429
 430        case 0x9000: /* mov.w @(disp,Rm),Rn */
 431                goto simple;
 432
 433        case 0xA000: /* bra label */
 434                ret = handle_delayslot(regs, instruction, ma);
 435                if (ret==0)
 436                        regs->pc += SH_PC_12BIT_OFFSET(instruction);
 437                break;
 438
 439        case 0xB000: /* bsr label */
 440                ret = handle_delayslot(regs, instruction, ma);
 441                if (ret==0) {
 442                        regs->pr = regs->pc + 4;
 443                        regs->pc += SH_PC_12BIT_OFFSET(instruction);
 444                }
 445                break;
 446
 447        case 0xD000: /* mov.l @(disp,Rm),Rn */
 448                goto simple;
 449        }
 450        return ret;
 451
 452        /* handle non-delay-slot instruction */
 453 simple:
 454        ret = handle_unaligned_ins(instruction, regs, ma);
 455        if (ret==0)
 456                regs->pc += instruction_size(instruction);
 457        return ret;
 458}
 459
 460/*
 461 * Handle various address error exceptions:
 462 *  - instruction address error:
 463 *       misaligned PC
 464 *       PC >= 0x80000000 in user mode
 465 *  - data address error (read and write)
 466 *       misaligned data access
 467 *       access to >= 0x80000000 is user mode
 468 * Unfortuntaly we can't distinguish between instruction address error
 469 * and data address errors caused by read accesses.
 470 */
 471asmlinkage void do_address_error(struct pt_regs *regs,
 472                                 unsigned long writeaccess,
 473                                 unsigned long address)
 474{
 475        unsigned long error_code = 0;
 476        mm_segment_t oldfs;
 477        insn_size_t instruction;
 478        int tmp;
 479
 480        /* Intentional ifdef */
 481#ifdef CONFIG_CPU_HAS_SR_RB
 482        error_code = lookup_exception_vector();
 483#endif
 484
 485        if (user_mode(regs)) {
 486                int si_code = BUS_ADRERR;
 487                unsigned int user_action;
 488
 489                local_irq_enable();
 490                inc_unaligned_user_access();
 491
 492                oldfs = force_uaccess_begin();
 493                if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1),
 494                                   sizeof(instruction))) {
 495                        force_uaccess_end(oldfs);
 496                        goto uspace_segv;
 497                }
 498                force_uaccess_end(oldfs);
 499
 500                /* shout about userspace fixups */
 501                unaligned_fixups_notify(current, instruction, regs);
 502
 503                user_action = unaligned_user_action();
 504                if (user_action & UM_FIXUP)
 505                        goto fixup;
 506                if (user_action & UM_SIGNAL)
 507                        goto uspace_segv;
 508                else {
 509                        /* ignore */
 510                        regs->pc += instruction_size(instruction);
 511                        return;
 512                }
 513
 514fixup:
 515                /* bad PC is not something we can fix */
 516                if (regs->pc & 1) {
 517                        si_code = BUS_ADRALN;
 518                        goto uspace_segv;
 519                }
 520
 521                oldfs = force_uaccess_begin();
 522                tmp = handle_unaligned_access(instruction, regs,
 523                                              &user_mem_access, 0,
 524                                              address);
 525                force_uaccess_end(oldfs);
 526
 527                if (tmp == 0)
 528                        return; /* sorted */
 529uspace_segv:
 530                printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
 531                       "access (PC %lx PR %lx)\n", current->comm, regs->pc,
 532                       regs->pr);
 533
 534                force_sig_fault(SIGBUS, si_code, (void __user *)address);
 535        } else {
 536                inc_unaligned_kernel_access();
 537
 538                if (regs->pc & 1)
 539                        die("unaligned program counter", regs, error_code);
 540
 541                set_fs(KERNEL_DS);
 542                if (copy_from_user(&instruction, (void __user *)(regs->pc),
 543                                   sizeof(instruction))) {
 544                        /* Argh. Fault on the instruction itself.
 545                           This should never happen non-SMP
 546                        */
 547                        set_fs(oldfs);
 548                        die("insn faulting in do_address_error", regs, 0);
 549                }
 550
 551                unaligned_fixups_notify(current, instruction, regs);
 552
 553                handle_unaligned_access(instruction, regs, &user_mem_access,
 554                                        0, address);
 555                set_fs(oldfs);
 556        }
 557}
 558
 559#ifdef CONFIG_SH_DSP
 560/*
 561 *      SH-DSP support gerg@snapgear.com.
 562 */
 563int is_dsp_inst(struct pt_regs *regs)
 564{
 565        unsigned short inst = 0;
 566
 567        /*
 568         * Safe guard if DSP mode is already enabled or we're lacking
 569         * the DSP altogether.
 570         */
 571        if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
 572                return 0;
 573
 574        get_user(inst, ((unsigned short *) regs->pc));
 575
 576        inst &= 0xf000;
 577
 578        /* Check for any type of DSP or support instruction */
 579        if ((inst == 0xf000) || (inst == 0x4000))
 580                return 1;
 581
 582        return 0;
 583}
 584#else
 585#define is_dsp_inst(regs)       (0)
 586#endif /* CONFIG_SH_DSP */
 587
 588#ifdef CONFIG_CPU_SH2A
 589asmlinkage void do_divide_error(unsigned long r4)
 590{
 591        int code;
 592
 593        switch (r4) {
 594        case TRAP_DIVZERO_ERROR:
 595                code = FPE_INTDIV;
 596                break;
 597        case TRAP_DIVOVF_ERROR:
 598                code = FPE_INTOVF;
 599                break;
 600        default:
 601                /* Let gcc know unhandled cases don't make it past here */
 602                return;
 603        }
 604        force_sig_fault(SIGFPE, code, NULL);
 605}
 606#endif
 607
 608asmlinkage void do_reserved_inst(void)
 609{
 610        struct pt_regs *regs = current_pt_regs();
 611        unsigned long error_code;
 612
 613#ifdef CONFIG_SH_FPU_EMU
 614        unsigned short inst = 0;
 615        int err;
 616
 617        get_user(inst, (unsigned short*)regs->pc);
 618
 619        err = do_fpu_inst(inst, regs);
 620        if (!err) {
 621                regs->pc += instruction_size(inst);
 622                return;
 623        }
 624        /* not a FPU inst. */
 625#endif
 626
 627#ifdef CONFIG_SH_DSP
 628        /* Check if it's a DSP instruction */
 629        if (is_dsp_inst(regs)) {
 630                /* Enable DSP mode, and restart instruction. */
 631                regs->sr |= SR_DSP;
 632                /* Save DSP mode */
 633                current->thread.dsp_status.status |= SR_DSP;
 634                return;
 635        }
 636#endif
 637
 638        error_code = lookup_exception_vector();
 639
 640        local_irq_enable();
 641        force_sig(SIGILL);
 642        die_if_no_fixup("reserved instruction", regs, error_code);
 643}
 644
 645#ifdef CONFIG_SH_FPU_EMU
 646static int emulate_branch(unsigned short inst, struct pt_regs *regs)
 647{
 648        /*
 649         * bfs: 8fxx: PC+=d*2+4;
 650         * bts: 8dxx: PC+=d*2+4;
 651         * bra: axxx: PC+=D*2+4;
 652         * bsr: bxxx: PC+=D*2+4  after PR=PC+4;
 653         * braf:0x23: PC+=Rn*2+4;
 654         * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
 655         * jmp: 4x2b: PC=Rn;
 656         * jsr: 4x0b: PC=Rn      after PR=PC+4;
 657         * rts: 000b: PC=PR;
 658         */
 659        if (((inst & 0xf000) == 0xb000)  ||     /* bsr */
 660            ((inst & 0xf0ff) == 0x0003)  ||     /* bsrf */
 661            ((inst & 0xf0ff) == 0x400b))        /* jsr */
 662                regs->pr = regs->pc + 4;
 663
 664        if ((inst & 0xfd00) == 0x8d00) {        /* bfs, bts */
 665                regs->pc += SH_PC_8BIT_OFFSET(inst);
 666                return 0;
 667        }
 668
 669        if ((inst & 0xe000) == 0xa000) {        /* bra, bsr */
 670                regs->pc += SH_PC_12BIT_OFFSET(inst);
 671                return 0;
 672        }
 673
 674        if ((inst & 0xf0df) == 0x0003) {        /* braf, bsrf */
 675                regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
 676                return 0;
 677        }
 678
 679        if ((inst & 0xf0df) == 0x400b) {        /* jmp, jsr */
 680                regs->pc = regs->regs[(inst & 0x0f00) >> 8];
 681                return 0;
 682        }
 683
 684        if ((inst & 0xffff) == 0x000b) {        /* rts */
 685                regs->pc = regs->pr;
 686                return 0;
 687        }
 688
 689        return 1;
 690}
 691#endif
 692
 693asmlinkage void do_illegal_slot_inst(void)
 694{
 695        struct pt_regs *regs = current_pt_regs();
 696        unsigned long inst;
 697
 698        if (kprobe_handle_illslot(regs->pc) == 0)
 699                return;
 700
 701#ifdef CONFIG_SH_FPU_EMU
 702        get_user(inst, (unsigned short *)regs->pc + 1);
 703        if (!do_fpu_inst(inst, regs)) {
 704                get_user(inst, (unsigned short *)regs->pc);
 705                if (!emulate_branch(inst, regs))
 706                        return;
 707                /* fault in branch.*/
 708        }
 709        /* not a FPU inst. */
 710#endif
 711
 712        inst = lookup_exception_vector();
 713
 714        local_irq_enable();
 715        force_sig(SIGILL);
 716        die_if_no_fixup("illegal slot instruction", regs, inst);
 717}
 718
 719asmlinkage void do_exception_error(void)
 720{
 721        long ex;
 722
 723        ex = lookup_exception_vector();
 724        die_if_kernel("exception", current_pt_regs(), ex);
 725}
 726
 727void per_cpu_trap_init(void)
 728{
 729        extern void *vbr_base;
 730
 731        /* NOTE: The VBR value should be at P1
 732           (or P2, virtural "fixed" address space).
 733           It's definitely should not in physical address.  */
 734
 735        asm volatile("ldc       %0, vbr"
 736                     : /* no output */
 737                     : "r" (&vbr_base)
 738                     : "memory");
 739
 740        /* disable exception blocking now when the vbr has been setup */
 741        clear_bl_bit();
 742}
 743
 744void *set_exception_table_vec(unsigned int vec, void *handler)
 745{
 746        extern void *exception_handling_table[];
 747        void *old_handler;
 748
 749        old_handler = exception_handling_table[vec];
 750        exception_handling_table[vec] = handler;
 751        return old_handler;
 752}
 753
 754void __init trap_init(void)
 755{
 756        set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
 757        set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
 758
 759#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
 760    defined(CONFIG_SH_FPU_EMU)
 761        /*
 762         * For SH-4 lacking an FPU, treat floating point instructions as
 763         * reserved. They'll be handled in the math-emu case, or faulted on
 764         * otherwise.
 765         */
 766        set_exception_table_evt(0x800, do_reserved_inst);
 767        set_exception_table_evt(0x820, do_illegal_slot_inst);
 768#elif defined(CONFIG_SH_FPU)
 769        set_exception_table_evt(0x800, fpu_state_restore_trap_handler);
 770        set_exception_table_evt(0x820, fpu_state_restore_trap_handler);
 771#endif
 772
 773#ifdef CONFIG_CPU_SH2
 774        set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler);
 775#endif
 776#ifdef CONFIG_CPU_SH2A
 777        set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
 778        set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
 779#ifdef CONFIG_SH_FPU
 780        set_exception_table_vec(TRAP_FPU_ERROR, fpu_error_trap_handler);
 781#endif
 782#endif
 783
 784#ifdef TRAP_UBC
 785        set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler);
 786#endif
 787}
 788