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 *) ((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 *) ((epcr0 & EPCR0_PC) ? (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 *
 106 */
 107asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
 108{
 109        siginfo_t info;
 110
 111        die_if_kernel("-- Media Exception --\n"
 112                      "MSR0 : %08lx\n"
 113                      "MSR1 : %08lx\n",
 114                      msr0, msr1);
 115
 116        info.si_signo   = SIGFPE;
 117        info.si_code    = FPE_MDAOVF;
 118        info.si_errno   = 0;
 119        info.si_addr    = (void *) __frame->pc;
 120
 121        force_sig_info(info.si_signo, &info, current);
 122} /* end media_exception() */
 123
 124/*****************************************************************************/
 125/*
 126 * instruction or data access exception
 127 */
 128asmlinkage void memory_access_exception(unsigned long esr0,
 129                                        unsigned long ear0,
 130                                        unsigned long epcr0)
 131{
 132        siginfo_t info;
 133
 134#ifdef CONFIG_MMU
 135        unsigned long fixup;
 136
 137        if ((esr0 & ESRx_EC) == ESRx_EC_DATA_ACCESS)
 138                if (handle_misalignment(esr0, ear0, epcr0) == 0)
 139                        return;
 140
 141        if ((fixup = search_exception_table(__frame->pc)) != 0) {
 142                __frame->pc = fixup;
 143                return;
 144        }
 145#endif
 146
 147        die_if_kernel("-- Memory Access Exception --\n"
 148                      "ESR0  : %08lx\n"
 149                      "EAR0  : %08lx\n"
 150                      "EPCR0 : %08lx\n",
 151                      esr0, ear0, epcr0);
 152
 153        info.si_signo   = SIGSEGV;
 154        info.si_code    = SEGV_ACCERR;
 155        info.si_errno   = 0;
 156        info.si_addr    = NULL;
 157
 158        if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
 159                info.si_addr = (void *) ear0;
 160
 161        force_sig_info(info.si_signo, &info, current);
 162
 163} /* end memory_access_exception() */
 164
 165/*****************************************************************************/
 166/*
 167 * data access error
 168 * - double-word data load from CPU control area (0xFExxxxxx)
 169 * - read performed on inactive or self-refreshing SDRAM
 170 * - error notification from slave device
 171 * - misaligned address
 172 * - access to out of bounds memory region
 173 * - user mode accessing privileged memory region
 174 * - write to R/O memory region
 175 */
 176asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15)
 177{
 178        siginfo_t info;
 179
 180        die_if_kernel("-- Data Access Error --\n"
 181                      "ESR15 : %08lx\n"
 182                      "EAR15 : %08lx\n",
 183                      esr15, ear15);
 184
 185        info.si_signo   = SIGSEGV;
 186        info.si_code    = SEGV_ACCERR;
 187        info.si_errno   = 0;
 188        info.si_addr    = (void *)
 189                (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
 190
 191        force_sig_info(info.si_signo, &info, current);
 192} /* end data_access_error() */
 193
 194/*****************************************************************************/
 195/*
 196 * data store error - should only happen if accessing inactive or self-refreshing SDRAM
 197 */
 198asmlinkage void data_store_error(unsigned long esfr1, unsigned long esr15)
 199{
 200        die_if_kernel("-- Data Store Error --\n"
 201                      "ESR15 : %08lx\n",
 202                      esr15);
 203        BUG();
 204} /* end data_store_error() */
 205
 206/*****************************************************************************/
 207/*
 208 *
 209 */
 210asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr)
 211{
 212        siginfo_t info;
 213
 214        die_if_kernel("-- Division Exception --\n"
 215                      "ESR0 : %08lx\n"
 216                      "ISR  : %08lx\n",
 217                      esr0, isr);
 218
 219        info.si_signo   = SIGFPE;
 220        info.si_code    = FPE_INTDIV;
 221        info.si_errno   = 0;
 222        info.si_addr    = (void *) __frame->pc;
 223
 224        force_sig_info(info.si_signo, &info, current);
 225} /* end division_exception() */
 226
 227/*****************************************************************************/
 228/*
 229 *
 230 */
 231asmlinkage void compound_exception(unsigned long esfr1,
 232                                   unsigned long esr0, unsigned long esr14, unsigned long esr15,
 233                                   unsigned long msr0, unsigned long msr1)
 234{
 235        die_if_kernel("-- Compound Exception --\n"
 236                      "ESR0  : %08lx\n"
 237                      "ESR15 : %08lx\n"
 238                      "ESR15 : %08lx\n"
 239                      "MSR0  : %08lx\n"
 240                      "MSR1  : %08lx\n",
 241                      esr0, esr14, esr15, msr0, msr1);
 242        BUG();
 243} /* end compound_exception() */
 244
 245/*****************************************************************************/
 246/*
 247 * The architecture-independent backtrace generator
 248 */
 249void dump_stack(void)
 250{
 251        show_stack(NULL, NULL);
 252}
 253
 254EXPORT_SYMBOL(dump_stack);
 255
 256void show_stack(struct task_struct *task, unsigned long *sp)
 257{
 258}
 259
 260void show_trace_task(struct task_struct *tsk)
 261{
 262        printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n",
 263               tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr);
 264}
 265
 266static const char *regnames[] = {
 267        "PSR ", "ISR ", "CCR ", "CCCR",
 268        "LR  ", "LCR ", "PC  ", "_stt",
 269        "sys ", "GR8*", "GNE0", "GNE1",
 270        "IACH", "IACL",
 271        "TBR ", "SP  ", "FP  ", "GR3 ",
 272        "GR4 ", "GR5 ", "GR6 ", "GR7 ",
 273        "GR8 ", "GR9 ", "GR10", "GR11",
 274        "GR12", "GR13", "GR14", "GR15",
 275        "GR16", "GR17", "GR18", "GR19",
 276        "GR20", "GR21", "GR22", "GR23",
 277        "GR24", "GR25", "GR26", "GR27",
 278        "EFRM", "CURR", "GR30", "BFRM"
 279};
 280
 281void show_regs(struct pt_regs *regs)
 282{
 283        unsigned long *reg;
 284        int loop;
 285
 286        printk("\n");
 287
 288        printk("Frame: @%08lx [%s]\n",
 289               (unsigned long) regs,
 290               regs->psr & PSR_S ? "kernel" : "user");
 291
 292        reg = (unsigned long *) regs;
 293        for (loop = 0; loop < NR_PT_REGS; loop++) {
 294                printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
 295
 296                if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
 297                        printk("\n");
 298                else
 299                        printk(" | ");
 300        }
 301
 302        printk("Process %s (pid: %d)\n", current->comm, current->pid);
 303}
 304
 305void die_if_kernel(const char *str, ...)
 306{
 307        char buffer[256];
 308        va_list va;
 309
 310        if (user_mode(__frame))
 311                return;
 312
 313        va_start(va, str);
 314        vsprintf(buffer, str, va);
 315        va_end(va);
 316
 317        console_verbose();
 318        printk("\n===================================\n");
 319        printk("%s\n", buffer);
 320        show_backtrace(__frame, 0);
 321
 322        __break_hijack_kernel_event();
 323        do_exit(SIGSEGV);
 324}
 325
 326/*****************************************************************************/
 327/*
 328 * dump the contents of an exception frame
 329 */
 330static void show_backtrace_regs(struct pt_regs *frame)
 331{
 332        unsigned long *reg;
 333        int loop;
 334
 335        /* print the registers for this frame */
 336        printk("<-- %s Frame: @%p -->\n",
 337               frame->psr & PSR_S ? "Kernel Mode" : "User Mode",
 338               frame);
 339
 340        reg = (unsigned long *) frame;
 341        for (loop = 0; loop < NR_PT_REGS; loop++) {
 342                printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
 343
 344                if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
 345                        printk("\n");
 346                else
 347                        printk(" | ");
 348        }
 349
 350        printk("--------\n");
 351} /* end show_backtrace_regs() */
 352
 353/*****************************************************************************/
 354/*
 355 * generate a backtrace of the kernel stack
 356 */
 357void show_backtrace(struct pt_regs *frame, unsigned long sp)
 358{
 359        struct pt_regs *frame0;
 360        unsigned long tos = 0, stop = 0, base;
 361        int format;
 362
 363        base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context);
 364        frame0 = (struct pt_regs *) base;
 365
 366        if (sp) {
 367                tos = sp;
 368                stop = (unsigned long) frame;
 369        }
 370
 371        printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid);
 372
 373        for (;;) {
 374                /* dump stack segment between frames */
 375                //printk("%08lx -> %08lx\n", tos, stop);
 376                format = 0;
 377                while (tos < stop) {
 378                        if (format == 0)
 379                                printk(" %04lx :", tos & 0xffff);
 380
 381                        printk(" %08lx", *(unsigned long *) tos);
 382
 383                        tos += 4;
 384                        format++;
 385                        if (format == 8) {
 386                                printk("\n");
 387                                format = 0;
 388                        }
 389                }
 390
 391                if (format > 0)
 392                        printk("\n");
 393
 394                /* dump frame 0 outside of the loop */
 395                if (frame == frame0)
 396                        break;
 397
 398                tos = frame->sp;
 399                if (((unsigned long) frame) + sizeof(*frame) != tos) {
 400                        printk("-- TOS %08lx does not follow frame %p --\n",
 401                               tos, frame);
 402                        break;
 403                }
 404
 405                show_backtrace_regs(frame);
 406
 407                /* dump the stack between this frame and the next */
 408                stop = (unsigned long) frame->next_frame;
 409                if (stop != base &&
 410                    (stop < tos ||
 411                     stop > base ||
 412                     (stop < base && stop + sizeof(*frame) > base) ||
 413                     stop & 3)) {
 414                        printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n",
 415                               stop, tos, base);
 416                        break;
 417                }
 418
 419                /* move to next frame */
 420                frame = frame->next_frame;
 421        }
 422
 423        /* we can always dump frame 0, even if the rest of the stack is corrupt */
 424        show_backtrace_regs(frame0);
 425
 426} /* end show_backtrace() */
 427
 428/*****************************************************************************/
 429/*
 430 * initialise traps
 431 */
 432void __init trap_init (void)
 433{
 434} /* end trap_init() */
 435
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.