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