linux/arch/frv/kernel/traps.c
<<
>>
Prefs
   1/* traps.c: high-level exception handler for FR-V
   2 *
   3 * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#include <linux/sched.h>
  13#include <linux/signal.h>
  14#include <linux/kernel.h>
  15#include <linux/mm.h>
  16#include <linux/types.h>
  17#include <linux/user.h>
  18#include <linux/string.h>
  19#include <linux/linkage.h>
  20#include <linux/init.h>
  21#include <linux/module.h>
  22
  23#include <asm/asm-offsets.h>
  24#include <asm/setup.h>
  25#include <asm/fpu.h>
  26#include <asm/uaccess.h>
  27#include <asm/pgtable.h>
  28#include <asm/siginfo.h>
  29#include <asm/unaligned.h>
  30
  31void show_backtrace(struct pt_regs *, unsigned long);
  32
  33extern asmlinkage void __break_hijack_kernel_event(void);
  34
  35/*****************************************************************************/
  36/*
  37 * instruction access error
  38 */
  39asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
  40{
  41        siginfo_t info;
  42
  43        die_if_kernel("-- Insn Access Error --\n"
  44                      "EPCR0 : %08lx\n"
  45                      "ESR0  : %08lx\n",
  46                      epcr0, esr0);
  47
  48        info.si_signo   = SIGSEGV;
  49        info.si_code    = SEGV_ACCERR;
  50        info.si_errno   = 0;
  51        info.si_addr    = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
  52
  53        force_sig_info(info.si_signo, &info, current);
  54} /* end insn_access_error() */
  55
  56/*****************************************************************************/
  57/*
  58 * handler for:
  59 * - illegal instruction
  60 * - privileged instruction
  61 * - unsupported trap
  62 * - debug exceptions
  63 */
  64asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
  65{
  66        siginfo_t info;
  67
  68        die_if_kernel("-- Illegal Instruction --\n"
  69                      "EPCR0 : %08lx\n"
  70                      "ESR0  : %08lx\n"
  71                      "ESFR1 : %08lx\n",
  72                      epcr0, esr0, esfr1);
  73
  74        info.si_errno   = 0;
  75        info.si_addr    = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
  76
  77        switch (__frame->tbr & TBR_TT) {
  78        case TBR_TT_ILLEGAL_INSTR:
  79                info.si_signo   = SIGILL;
  80                info.si_code    = ILL_ILLOPC;
  81                break;
  82        case TBR_TT_PRIV_INSTR:
  83                info.si_signo   = SIGILL;
  84                info.si_code    = ILL_PRVOPC;
  85                break;
  86        case TBR_TT_TRAP2 ... TBR_TT_TRAP126:
  87                info.si_signo   = SIGILL;
  88                info.si_code    = ILL_ILLTRP;
  89                break;
  90        /* GDB uses "tira gr0, #1" as a breakpoint instruction.  */
  91        case TBR_TT_TRAP1:
  92        case TBR_TT_BREAK:
  93                info.si_signo   = SIGTRAP;
  94                info.si_code    =
  95                        (__frame->__status & REG__STATUS_STEPPED) ? TRAP_TRACE : TRAP_BRKPT;
  96                break;
  97        }
  98
  99        force_sig_info(info.si_signo, &info, current);
 100} /* end illegal_instruction() */
 101
 102/*****************************************************************************/
 103/*
 104 * handle atomic operations with errors
 105 * - arguments in gr8, gr9, gr10
 106 * - original memory value placed in gr5
 107 * - replacement memory value placed in gr9
 108 */
 109asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
 110                                 unsigned long esr0)
 111{
 112        static DEFINE_SPINLOCK(atomic_op_lock);
 113        unsigned long x, y, z;
 114        unsigned long __user *p;
 115        mm_segment_t oldfs;
 116        siginfo_t info;
 117        int ret;
 118
 119        y = 0;
 120        z = 0;
 121
 122        oldfs = get_fs();
 123        if (!user_mode(__frame))
 124                set_fs(KERNEL_DS);
 125
 126        switch (__frame->tbr & TBR_TT) {
 127                /* TIRA gr0,#120
 128                 * u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new)
 129                 */
 130        case TBR_TT_ATOMIC_CMPXCHG32:
 131                p = (unsigned long __user *) __frame->gr8;
 132                x = __frame->gr9;
 133                y = __frame->gr10;
 134
 135                for (;;) {
 136                        ret = get_user(z, p);
 137                        if (ret < 0)
 138                                goto error;
 139
 140                        if (z != x)
 141                                goto done;
 142
 143                        spin_lock_irq(&atomic_op_lock);
 144
 145                        if (__get_user(z, p) == 0) {
 146                                if (z != x)
 147                                        goto done2;
 148
 149                                if (__put_user(y, p) == 0)
 150                                        goto done2;
 151                                goto error2;
 152                        }
 153
 154                        spin_unlock_irq(&atomic_op_lock);
 155                }
 156
 157                /* TIRA gr0,#121
 158                 * u32 __atomic_kernel_xchg32(void *v, u32 new)
 159                 */
 160        case TBR_TT_ATOMIC_XCHG32:
 161                p = (unsigned long __user *) __frame->gr8;
 162                y = __frame->gr9;
 163
 164                for (;;) {
 165                        ret = get_user(z, p);
 166                        if (ret < 0)
 167                                goto error;
 168
 169                        spin_lock_irq(&atomic_op_lock);
 170
 171                        if (__get_user(z, p) == 0) {
 172                                if (__put_user(y, p) == 0)
 173                                        goto done2;
 174                                goto error2;
 175                        }
 176
 177                        spin_unlock_irq(&atomic_op_lock);
 178                }
 179
 180                /* TIRA gr0,#122
 181                 * ulong __atomic_kernel_XOR_return(ulong i, ulong *v)
 182                 */
 183        case TBR_TT_ATOMIC_XOR:
 184                p = (unsigned long __user *) __frame->gr8;
 185                x = __frame->gr9;
 186
 187                for (;;) {
 188                        ret = get_user(z, p);
 189                        if (ret < 0)
 190                                goto error;
 191
 192                        spin_lock_irq(&atomic_op_lock);
 193
 194                        if (__get_user(z, p) == 0) {
 195                                y = x ^ z;
 196                                if (__put_user(y, p) == 0)
 197                                        goto done2;
 198                                goto error2;
 199                        }
 200
 201                        spin_unlock_irq(&atomic_op_lock);
 202                }
 203
 204                /* TIRA gr0,#123
 205                 * ulong __atomic_kernel_OR_return(ulong i, ulong *v)
 206                 */
 207        case TBR_TT_ATOMIC_OR:
 208                p = (unsigned long __user *) __frame->gr8;
 209                x = __frame->gr9;
 210
 211                for (;;) {
 212                        ret = get_user(z, p);
 213                        if (ret < 0)
 214                                goto error;
 215
 216                        spin_lock_irq(&atomic_op_lock);
 217
 218                        if (__get_user(z, p) == 0) {
 219                                y = x ^ z;
 220                                if (__put_user(y, p) == 0)
 221                                        goto done2;
 222                                goto error2;
 223                        }
 224
 225                        spin_unlock_irq(&atomic_op_lock);
 226                }
 227
 228                /* TIRA gr0,#124
 229                 * ulong __atomic_kernel_AND_return(ulong i, ulong *v)
 230                 */
 231        case TBR_TT_ATOMIC_AND:
 232                p = (unsigned long __user *) __frame->gr8;
 233                x = __frame->gr9;
 234
 235                for (;;) {
 236                        ret = get_user(z, p);
 237                        if (ret < 0)
 238                                goto error;
 239
 240                        spin_lock_irq(&atomic_op_lock);
 241
 242                        if (__get_user(z, p) == 0) {
 243                                y = x & z;
 244                                if (__put_user(y, p) == 0)
 245                                        goto done2;
 246                                goto error2;
 247                        }
 248
 249                        spin_unlock_irq(&atomic_op_lock);
 250                }
 251
 252                /* TIRA gr0,#125
 253                 * int __atomic_user_sub_return(atomic_t *v, int i)
 254                 */
 255        case TBR_TT_ATOMIC_SUB:
 256                p = (unsigned long __user *) __frame->gr8;
 257                x = __frame->gr9;
 258
 259                for (;;) {
 260                        ret = get_user(z, p);
 261                        if (ret < 0)
 262                                goto error;
 263
 264                        spin_lock_irq(&atomic_op_lock);
 265
 266                        if (__get_user(z, p) == 0) {
 267                                y = z - x;
 268                                if (__put_user(y, p) == 0)
 269                                        goto done2;
 270                                goto error2;
 271                        }
 272
 273                        spin_unlock_irq(&atomic_op_lock);
 274                }
 275
 276                /* TIRA gr0,#126
 277                 * int __atomic_user_add_return(atomic_t *v, int i)
 278                 */
 279        case TBR_TT_ATOMIC_ADD:
 280                p = (unsigned long __user *) __frame->gr8;
 281                x = __frame->gr9;
 282
 283                for (;;) {
 284                        ret = get_user(z, p);
 285                        if (ret < 0)
 286                                goto error;
 287
 288                        spin_lock_irq(&atomic_op_lock);
 289
 290                        if (__get_user(z, p) == 0) {
 291                                y = z + x;
 292                                if (__put_user(y, p) == 0)
 293                                        goto done2;
 294                                goto error2;
 295                        }
 296
 297                        spin_unlock_irq(&atomic_op_lock);
 298                }
 299
 300        default:
 301                BUG();
 302        }
 303
 304done2:
 305        spin_unlock_irq(&atomic_op_lock);
 306done:
 307        if (!user_mode(__frame))
 308                set_fs(oldfs);
 309        __frame->gr5 = z;
 310        __frame->gr9 = y;
 311        return;
 312
 313error2:
 314        spin_unlock_irq(&atomic_op_lock);
 315error:
 316        if (!user_mode(__frame))
 317                set_fs(oldfs);
 318        __frame->pc -= 4;
 319
 320        die_if_kernel("-- Atomic Op Error --\n");
 321
 322        info.si_signo   = SIGSEGV;
 323        info.si_code    = SEGV_ACCERR;
 324        info.si_errno   = 0;
 325        info.si_addr    = (void __user *) __frame->pc;
 326
 327        force_sig_info(info.si_signo, &info, current);
 328}
 329
 330/*****************************************************************************/
 331/*
 332 *
 333 */
 334asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
 335{
 336        siginfo_t info;
 337
 338        die_if_kernel("-- Media Exception --\n"
 339                      "MSR0 : %08lx\n"
 340                      "MSR1 : %08lx\n",
 341                      msr0, msr1);
 342
 343        info.si_signo   = SIGFPE;
 344        info.si_code    = FPE_MDAOVF;
 345        info.si_errno   = 0;
 346        info.si_addr    = (void __user *) __frame->pc;
 347
 348        force_sig_info(info.si_signo, &info, current);
 349} /* end media_exception() */
 350
 351/*****************************************************************************/
 352/*
 353 * instruction or data access exception
 354 */
 355asmlinkage void memory_access_exception(unsigned long esr0,
 356                                        unsigned long ear0,
 357                                        unsigned long epcr0)
 358{
 359        siginfo_t info;
 360
 361#ifdef CONFIG_MMU
 362        unsigned long fixup;
 363
 364        fixup = search_exception_table(__frame->pc);
 365        if (fixup) {
 366                __frame->pc = fixup;
 367                return;
 368        }
 369#endif
 370
 371        die_if_kernel("-- Memory Access Exception --\n"
 372                      "ESR0  : %08lx\n"
 373                      "EAR0  : %08lx\n"
 374                      "EPCR0 : %08lx\n",
 375                      esr0, ear0, epcr0);
 376
 377        info.si_signo   = SIGSEGV;
 378        info.si_code    = SEGV_ACCERR;
 379        info.si_errno   = 0;
 380        info.si_addr    = NULL;
 381
 382        if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
 383                info.si_addr = (void __user *) ear0;
 384
 385        force_sig_info(info.si_signo, &info, current);
 386
 387} /* end memory_access_exception() */
 388
 389/*****************************************************************************/
 390/*
 391 * data access error
 392 * - double-word data load from CPU control area (0xFExxxxxx)
 393 * - read performed on inactive or self-refreshing SDRAM
 394 * - error notification from slave device
 395 * - misaligned address
 396 * - access to out of bounds memory region
 397 * - user mode accessing privileged memory region
 398 * - write to R/O memory region
 399 */
 400asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15)
 401{
 402        siginfo_t info;
 403
 404        die_if_kernel("-- Data Access Error --\n"
 405                      "ESR15 : %08lx\n"
 406                      "EAR15 : %08lx\n",
 407                      esr15, ear15);
 408
 409        info.si_signo   = SIGSEGV;
 410        info.si_code    = SEGV_ACCERR;
 411        info.si_errno   = 0;
 412        info.si_addr    = (void __user *)
 413                (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
 414
 415        force_sig_info(info.si_signo, &info, current);
 416} /* end data_access_error() */
 417
 418/*****************************************************************************/
 419/*
 420 * data store error - should only happen if accessing inactive or self-refreshing SDRAM
 421 */
 422asmlinkage void data_store_error(unsigned long esfr1, unsigned long esr15)
 423{
 424        die_if_kernel("-- Data Store Error --\n"
 425                      "ESR15 : %08lx\n",
 426                      esr15);
 427        BUG();
 428} /* end data_store_error() */
 429
 430/*****************************************************************************/
 431/*
 432 *
 433 */
 434asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr)
 435{
 436        siginfo_t info;
 437
 438        die_if_kernel("-- Division Exception --\n"
 439                      "ESR0 : %08lx\n"
 440                      "ISR  : %08lx\n",
 441                      esr0, isr);
 442
 443        info.si_signo   = SIGFPE;
 444        info.si_code    = FPE_INTDIV;
 445        info.si_errno   = 0;
 446        info.si_addr    = (void __user *) __frame->pc;
 447
 448        force_sig_info(info.si_signo, &info, current);
 449} /* end division_exception() */
 450
 451/*****************************************************************************/
 452/*
 453 *
 454 */
 455asmlinkage void compound_exception(unsigned long esfr1,
 456                                   unsigned long esr0, unsigned long esr14, unsigned long esr15,
 457                                   unsigned long msr0, unsigned long msr1)
 458{
 459        die_if_kernel("-- Compound Exception --\n"
 460                      "ESR0  : %08lx\n"
 461                      "ESR15 : %08lx\n"
 462                      "ESR15 : %08lx\n"
 463                      "MSR0  : %08lx\n"
 464                      "MSR1  : %08lx\n",
 465                      esr0, esr14, esr15, msr0, msr1);
 466        BUG();
 467} /* end compound_exception() */
 468
 469void show_stack(struct task_struct *task, unsigned long *sp)
 470{
 471}
 472
 473void show_trace_task(struct task_struct *tsk)
 474{
 475        printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n",
 476               tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr);
 477}
 478
 479static const char *regnames[] = {
 480        "PSR ", "ISR ", "CCR ", "CCCR",
 481        "LR  ", "LCR ", "PC  ", "_stt",
 482        "sys ", "GR8*", "GNE0", "GNE1",
 483        "IACH", "IACL",
 484        "TBR ", "SP  ", "FP  ", "GR3 ",
 485        "GR4 ", "GR5 ", "GR6 ", "GR7 ",
 486        "GR8 ", "GR9 ", "GR10", "GR11",
 487        "GR12", "GR13", "GR14", "GR15",
 488        "GR16", "GR17", "GR18", "GR19",
 489        "GR20", "GR21", "GR22", "GR23",
 490        "GR24", "GR25", "GR26", "GR27",
 491        "EFRM", "CURR", "GR30", "BFRM"
 492};
 493
 494void show_regs(struct pt_regs *regs)
 495{
 496        unsigned long *reg;
 497        int loop;
 498
 499        printk("\n");
 500        show_regs_print_info(KERN_DEFAULT);
 501
 502        printk("Frame: @%08lx [%s]\n",
 503               (unsigned long) regs,
 504               regs->psr & PSR_S ? "kernel" : "user");
 505
 506        reg = (unsigned long *) regs;
 507        for (loop = 0; loop < NR_PT_REGS; loop++) {
 508                printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
 509
 510                if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
 511                        printk("\n");
 512                else
 513                        printk(" | ");
 514        }
 515}
 516
 517void die_if_kernel(const char *str, ...)
 518{
 519        char buffer[256];
 520        va_list va;
 521
 522        if (user_mode(__frame))
 523                return;
 524
 525        va_start(va, str);
 526        vsnprintf(buffer, sizeof(buffer), str, va);
 527        va_end(va);
 528
 529        console_verbose();
 530        printk("\n===================================\n");
 531        printk("%s\n", buffer);
 532        show_backtrace(__frame, 0);
 533
 534        __break_hijack_kernel_event();
 535        do_exit(SIGSEGV);
 536}
 537
 538/*****************************************************************************/
 539/*
 540 * dump the contents of an exception frame
 541 */
 542static void show_backtrace_regs(struct pt_regs *frame)
 543{
 544        unsigned long *reg;
 545        int loop;
 546
 547        /* print the registers for this frame */
 548        printk("<-- %s Frame: @%p -->\n",
 549               frame->psr & PSR_S ? "Kernel Mode" : "User Mode",
 550               frame);
 551
 552        reg = (unsigned long *) frame;
 553        for (loop = 0; loop < NR_PT_REGS; loop++) {
 554                printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
 555
 556                if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
 557                        printk("\n");
 558                else
 559                        printk(" | ");
 560        }
 561
 562        printk("--------\n");
 563} /* end show_backtrace_regs() */
 564
 565/*****************************************************************************/
 566/*
 567 * generate a backtrace of the kernel stack
 568 */
 569void show_backtrace(struct pt_regs *frame, unsigned long sp)
 570{
 571        struct pt_regs *frame0;
 572        unsigned long tos = 0, stop = 0, base;
 573        int format;
 574
 575        base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context);
 576        frame0 = (struct pt_regs *) base;
 577
 578        if (sp) {
 579                tos = sp;
 580                stop = (unsigned long) frame;
 581        }
 582
 583        printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid);
 584
 585        for (;;) {
 586                /* dump stack segment between frames */
 587                //printk("%08lx -> %08lx\n", tos, stop);
 588                format = 0;
 589                while (tos < stop) {
 590                        if (format == 0)
 591                                printk(" %04lx :", tos & 0xffff);
 592
 593                        printk(" %08lx", *(unsigned long *) tos);
 594
 595                        tos += 4;
 596                        format++;
 597                        if (format == 8) {
 598                                printk("\n");
 599                                format = 0;
 600                        }
 601                }
 602
 603                if (format > 0)
 604                        printk("\n");
 605
 606                /* dump frame 0 outside of the loop */
 607                if (frame == frame0)
 608                        break;
 609
 610                tos = frame->sp;
 611                if (((unsigned long) frame) + sizeof(*frame) != tos) {
 612                        printk("-- TOS %08lx does not follow frame %p --\n",
 613                               tos, frame);
 614                        break;
 615                }
 616
 617                show_backtrace_regs(frame);
 618
 619                /* dump the stack between this frame and the next */
 620                stop = (unsigned long) frame->next_frame;
 621                if (stop != base &&
 622                    (stop < tos ||
 623                     stop > base ||
 624                     (stop < base && stop + sizeof(*frame) > base) ||
 625                     stop & 3)) {
 626                        printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n",
 627                               stop, tos, base);
 628                        break;
 629                }
 630
 631                /* move to next frame */
 632                frame = frame->next_frame;
 633        }
 634
 635        /* we can always dump frame 0, even if the rest of the stack is corrupt */
 636        show_backtrace_regs(frame0);
 637
 638} /* end show_backtrace() */
 639
 640/*****************************************************************************/
 641/*
 642 * initialise traps
 643 */
 644void __init trap_init (void)
 645{
 646} /* end trap_init() */
 647