linux/arch/openrisc/kernel/traps.c
<<
>>
Prefs
   1/*
   2 * OpenRISC traps.c
   3 *
   4 * Linux architectural port borrowing liberally from similar works of
   5 * others.  All original copyrights apply as per the original source
   6 * declaration.
   7 *
   8 * Modifications for the OpenRISC architecture:
   9 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
  10 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
  11 *
  12 *      This program is free software; you can redistribute it and/or
  13 *      modify it under the terms of the GNU General Public License
  14 *      as published by the Free Software Foundation; either version
  15 *      2 of the License, or (at your option) any later version.
  16 *
  17 *  Here we handle the break vectors not used by the system call
  18 *  mechanism, as well as some general stack/register dumping
  19 *  things.
  20 *
  21 */
  22
  23#include <linux/init.h>
  24#include <linux/sched.h>
  25#include <linux/sched/debug.h>
  26#include <linux/sched/task_stack.h>
  27#include <linux/kernel.h>
  28#include <linux/extable.h>
  29#include <linux/kmod.h>
  30#include <linux/string.h>
  31#include <linux/errno.h>
  32#include <linux/ptrace.h>
  33#include <linux/timer.h>
  34#include <linux/mm.h>
  35#include <linux/kallsyms.h>
  36#include <linux/uaccess.h>
  37
  38#include <asm/segment.h>
  39#include <asm/io.h>
  40#include <asm/pgtable.h>
  41#include <asm/unwinder.h>
  42#include <asm/sections.h>
  43
  44int kstack_depth_to_print = 0x180;
  45int lwa_flag;
  46unsigned long __user *lwa_addr;
  47
  48void print_trace(void *data, unsigned long addr, int reliable)
  49{
  50        pr_emerg("[<%p>] %s%pS\n", (void *) addr, reliable ? "" : "? ",
  51               (void *) addr);
  52}
  53
  54/* displays a short stack trace */
  55void show_stack(struct task_struct *task, unsigned long *esp)
  56{
  57        if (esp == NULL)
  58                esp = (unsigned long *)&esp;
  59
  60        pr_emerg("Call trace:\n");
  61        unwind_stack(NULL, esp, print_trace);
  62}
  63
  64void show_trace_task(struct task_struct *tsk)
  65{
  66        /*
  67         * TODO: SysRq-T trace dump...
  68         */
  69}
  70
  71void show_registers(struct pt_regs *regs)
  72{
  73        int i;
  74        int in_kernel = 1;
  75        unsigned long esp;
  76
  77        esp = (unsigned long)(regs->sp);
  78        if (user_mode(regs))
  79                in_kernel = 0;
  80
  81        printk("CPU #: %d\n"
  82               "   PC: %08lx    SR: %08lx    SP: %08lx\n",
  83               smp_processor_id(), regs->pc, regs->sr, regs->sp);
  84        printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
  85               0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
  86        printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
  87               regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]);
  88        printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n",
  89               regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]);
  90        printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n",
  91               regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]);
  92        printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n",
  93               regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]);
  94        printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n",
  95               regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]);
  96        printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n",
  97               regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
  98        printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
  99               regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
 100        printk("  RES: %08lx oGPR11: %08lx\n",
 101               regs->gpr[11], regs->orig_gpr11);
 102
 103        printk("Process %s (pid: %d, stackpage=%08lx)\n",
 104               current->comm, current->pid, (unsigned long)current);
 105        /*
 106         * When in-kernel, we also print out the stack and code at the
 107         * time of the fault..
 108         */
 109        if (in_kernel) {
 110
 111                printk("\nStack: ");
 112                show_stack(NULL, (unsigned long *)esp);
 113
 114                printk("\nCode: ");
 115                if (regs->pc < PAGE_OFFSET)
 116                        goto bad;
 117
 118                for (i = -24; i < 24; i++) {
 119                        unsigned char c;
 120                        if (__get_user(c, &((unsigned char *)regs->pc)[i])) {
 121bad:
 122                                printk(" Bad PC value.");
 123                                break;
 124                        }
 125
 126                        if (i == 0)
 127                                printk("(%02x) ", c);
 128                        else
 129                                printk("%02x ", c);
 130                }
 131        }
 132        printk("\n");
 133}
 134
 135void nommu_dump_state(struct pt_regs *regs,
 136                      unsigned long ea, unsigned long vector)
 137{
 138        int i;
 139        unsigned long addr, stack = regs->sp;
 140
 141        printk("\n\r[nommu_dump_state] :: ea %lx, vector %lx\n\r", ea, vector);
 142
 143        printk("CPU #: %d\n"
 144               "   PC: %08lx    SR: %08lx    SP: %08lx\n",
 145               0, regs->pc, regs->sr, regs->sp);
 146        printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
 147               0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
 148        printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
 149               regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]);
 150        printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n",
 151               regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]);
 152        printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n",
 153               regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]);
 154        printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n",
 155               regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]);
 156        printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n",
 157               regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]);
 158        printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n",
 159               regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
 160        printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
 161               regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
 162        printk("  RES: %08lx oGPR11: %08lx\n",
 163               regs->gpr[11], regs->orig_gpr11);
 164
 165        printk("Process %s (pid: %d, stackpage=%08lx)\n",
 166               ((struct task_struct *)(__pa(current)))->comm,
 167               ((struct task_struct *)(__pa(current)))->pid,
 168               (unsigned long)current);
 169
 170        printk("\nStack: ");
 171        printk("Stack dump [0x%08lx]:\n", (unsigned long)stack);
 172        for (i = 0; i < kstack_depth_to_print; i++) {
 173                if (((long)stack & (THREAD_SIZE - 1)) == 0)
 174                        break;
 175                stack++;
 176
 177                printk("%lx :: sp + %02d: 0x%08lx\n", stack, i * 4,
 178                       *((unsigned long *)(__pa(stack))));
 179        }
 180        printk("\n");
 181
 182        printk("Call Trace:   ");
 183        i = 1;
 184        while (((long)stack & (THREAD_SIZE - 1)) != 0) {
 185                addr = *((unsigned long *)__pa(stack));
 186                stack++;
 187
 188                if (kernel_text_address(addr)) {
 189                        if (i && ((i % 6) == 0))
 190                                printk("\n ");
 191                        printk(" [<%08lx>]", addr);
 192                        i++;
 193                }
 194        }
 195        printk("\n");
 196
 197        printk("\nCode: ");
 198
 199        for (i = -24; i < 24; i++) {
 200                unsigned char c;
 201                c = ((unsigned char *)(__pa(regs->pc)))[i];
 202
 203                if (i == 0)
 204                        printk("(%02x) ", c);
 205                else
 206                        printk("%02x ", c);
 207        }
 208        printk("\n");
 209}
 210
 211/* This is normally the 'Oops' routine */
 212void die(const char *str, struct pt_regs *regs, long err)
 213{
 214
 215        console_verbose();
 216        printk("\n%s#: %04lx\n", str, err & 0xffff);
 217        show_registers(regs);
 218#ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION
 219        printk("\n\nUNHANDLED_EXCEPTION: entering infinite loop\n");
 220
 221        /* shut down interrupts */
 222        local_irq_disable();
 223
 224        __asm__ __volatile__("l.nop   1");
 225        do {} while (1);
 226#endif
 227        do_exit(SIGSEGV);
 228}
 229
 230/* This is normally the 'Oops' routine */
 231void die_if_kernel(const char *str, struct pt_regs *regs, long err)
 232{
 233        if (user_mode(regs))
 234                return;
 235
 236        die(str, regs, err);
 237}
 238
 239void unhandled_exception(struct pt_regs *regs, int ea, int vector)
 240{
 241        printk("Unable to handle exception at EA =0x%x, vector 0x%x",
 242               ea, vector);
 243        die("Oops", regs, 9);
 244}
 245
 246void __init trap_init(void)
 247{
 248        /* Nothing needs to be done */
 249}
 250
 251asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
 252{
 253        siginfo_t info;
 254        memset(&info, 0, sizeof(info));
 255        info.si_signo = SIGTRAP;
 256        info.si_code = TRAP_TRACE;
 257        info.si_addr = (void *)address;
 258        force_sig_info(SIGTRAP, &info, current);
 259
 260        regs->pc += 4;
 261}
 262
 263asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
 264{
 265        siginfo_t info;
 266
 267        if (user_mode(regs)) {
 268                /* Send a SIGBUS */
 269                info.si_signo = SIGBUS;
 270                info.si_errno = 0;
 271                info.si_code = BUS_ADRALN;
 272                info.si_addr = (void __user *)address;
 273                force_sig_info(SIGBUS, &info, current);
 274        } else {
 275                printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
 276                show_registers(regs);
 277                die("Die:", regs, address);
 278        }
 279
 280}
 281
 282asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address)
 283{
 284        siginfo_t info;
 285
 286        if (user_mode(regs)) {
 287                /* Send a SIGBUS */
 288                info.si_signo = SIGBUS;
 289                info.si_errno = 0;
 290                info.si_code = BUS_ADRERR;
 291                info.si_addr = (void *)address;
 292                force_sig_info(SIGBUS, &info, current);
 293        } else {                /* Kernel mode */
 294                printk("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address);
 295                show_registers(regs);
 296                die("Die:", regs, address);
 297        }
 298}
 299
 300static inline int in_delay_slot(struct pt_regs *regs)
 301{
 302#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX
 303        /* No delay slot flag, do the old way */
 304        unsigned int op, insn;
 305
 306        insn = *((unsigned int *)regs->pc);
 307        op = insn >> 26;
 308        switch (op) {
 309        case 0x00: /* l.j */
 310        case 0x01: /* l.jal */
 311        case 0x03: /* l.bnf */
 312        case 0x04: /* l.bf */
 313        case 0x11: /* l.jr */
 314        case 0x12: /* l.jalr */
 315                return 1;
 316        default:
 317                return 0;
 318        }
 319#else
 320        return regs->sr & SPR_SR_DSX;
 321#endif
 322}
 323
 324static inline void adjust_pc(struct pt_regs *regs, unsigned long address)
 325{
 326        int displacement;
 327        unsigned int rb, op, jmp;
 328
 329        if (unlikely(in_delay_slot(regs))) {
 330                /* In delay slot, instruction at pc is a branch, simulate it */
 331                jmp = *((unsigned int *)regs->pc);
 332
 333                displacement = sign_extend32(((jmp) & 0x3ffffff) << 2, 27);
 334                rb = (jmp & 0x0000ffff) >> 11;
 335                op = jmp >> 26;
 336
 337                switch (op) {
 338                case 0x00: /* l.j */
 339                        regs->pc += displacement;
 340                        return;
 341                case 0x01: /* l.jal */
 342                        regs->pc += displacement;
 343                        regs->gpr[9] = regs->pc + 8;
 344                        return;
 345                case 0x03: /* l.bnf */
 346                        if (regs->sr & SPR_SR_F)
 347                                regs->pc += 8;
 348                        else
 349                                regs->pc += displacement;
 350                        return;
 351                case 0x04: /* l.bf */
 352                        if (regs->sr & SPR_SR_F)
 353                                regs->pc += displacement;
 354                        else
 355                                regs->pc += 8;
 356                        return;
 357                case 0x11: /* l.jr */
 358                        regs->pc = regs->gpr[rb];
 359                        return;
 360                case 0x12: /* l.jalr */
 361                        regs->pc = regs->gpr[rb];
 362                        regs->gpr[9] = regs->pc + 8;
 363                        return;
 364                default:
 365                        break;
 366                }
 367        } else {
 368                regs->pc += 4;
 369        }
 370}
 371
 372static inline void simulate_lwa(struct pt_regs *regs, unsigned long address,
 373                                unsigned int insn)
 374{
 375        unsigned int ra, rd;
 376        unsigned long value;
 377        unsigned long orig_pc;
 378        long imm;
 379
 380        const struct exception_table_entry *entry;
 381
 382        orig_pc = regs->pc;
 383        adjust_pc(regs, address);
 384
 385        ra = (insn >> 16) & 0x1f;
 386        rd = (insn >> 21) & 0x1f;
 387        imm = (short)insn;
 388        lwa_addr = (unsigned long __user *)(regs->gpr[ra] + imm);
 389
 390        if ((unsigned long)lwa_addr & 0x3) {
 391                do_unaligned_access(regs, address);
 392                return;
 393        }
 394
 395        if (get_user(value, lwa_addr)) {
 396                if (user_mode(regs)) {
 397                        force_sig(SIGSEGV, current);
 398                        return;
 399                }
 400
 401                if ((entry = search_exception_tables(orig_pc))) {
 402                        regs->pc = entry->fixup;
 403                        return;
 404                }
 405
 406                /* kernel access in kernel space, load it directly */
 407                value = *((unsigned long *)lwa_addr);
 408        }
 409
 410        lwa_flag = 1;
 411        regs->gpr[rd] = value;
 412}
 413
 414static inline void simulate_swa(struct pt_regs *regs, unsigned long address,
 415                                unsigned int insn)
 416{
 417        unsigned long __user *vaddr;
 418        unsigned long orig_pc;
 419        unsigned int ra, rb;
 420        long imm;
 421
 422        const struct exception_table_entry *entry;
 423
 424        orig_pc = regs->pc;
 425        adjust_pc(regs, address);
 426
 427        ra = (insn >> 16) & 0x1f;
 428        rb = (insn >> 11) & 0x1f;
 429        imm = (short)(((insn & 0x2200000) >> 10) | (insn & 0x7ff));
 430        vaddr = (unsigned long __user *)(regs->gpr[ra] + imm);
 431
 432        if (!lwa_flag || vaddr != lwa_addr) {
 433                regs->sr &= ~SPR_SR_F;
 434                return;
 435        }
 436
 437        if ((unsigned long)vaddr & 0x3) {
 438                do_unaligned_access(regs, address);
 439                return;
 440        }
 441
 442        if (put_user(regs->gpr[rb], vaddr)) {
 443                if (user_mode(regs)) {
 444                        force_sig(SIGSEGV, current);
 445                        return;
 446                }
 447
 448                if ((entry = search_exception_tables(orig_pc))) {
 449                        regs->pc = entry->fixup;
 450                        return;
 451                }
 452
 453                /* kernel access in kernel space, store it directly */
 454                *((unsigned long *)vaddr) = regs->gpr[rb];
 455        }
 456
 457        lwa_flag = 0;
 458        regs->sr |= SPR_SR_F;
 459}
 460
 461#define INSN_LWA        0x1b
 462#define INSN_SWA        0x33
 463
 464asmlinkage void do_illegal_instruction(struct pt_regs *regs,
 465                                       unsigned long address)
 466{
 467        siginfo_t info;
 468        unsigned int op;
 469        unsigned int insn = *((unsigned int *)address);
 470
 471        op = insn >> 26;
 472
 473        switch (op) {
 474        case INSN_LWA:
 475                simulate_lwa(regs, address, insn);
 476                return;
 477
 478        case INSN_SWA:
 479                simulate_swa(regs, address, insn);
 480                return;
 481
 482        default:
 483                break;
 484        }
 485
 486        if (user_mode(regs)) {
 487                /* Send a SIGILL */
 488                info.si_signo = SIGILL;
 489                info.si_errno = 0;
 490                info.si_code = ILL_ILLOPC;
 491                info.si_addr = (void *)address;
 492                force_sig_info(SIGBUS, &info, current);
 493        } else {                /* Kernel mode */
 494                printk("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n",
 495                       address);
 496                show_registers(regs);
 497                die("Die:", regs, address);
 498        }
 499}
 500