linux/arch/hexagon/kernel/traps.c
<<
>>
Prefs
   1/*
   2 * Kernel traps/events for Hexagon processor
   3 *
   4 * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 and
   8 * only version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18 * 02110-1301, USA.
  19 */
  20
  21#include <linux/init.h>
  22#include <linux/sched/signal.h>
  23#include <linux/sched/debug.h>
  24#include <linux/sched/task_stack.h>
  25#include <linux/module.h>
  26#include <linux/kallsyms.h>
  27#include <linux/kdebug.h>
  28#include <linux/syscalls.h>
  29#include <linux/signal.h>
  30#include <linux/tracehook.h>
  31#include <asm/traps.h>
  32#include <asm/vm_fault.h>
  33#include <asm/syscall.h>
  34#include <asm/registers.h>
  35#include <asm/unistd.h>
  36#include <asm/sections.h>
  37#ifdef CONFIG_KGDB
  38# include <linux/kgdb.h>
  39#endif
  40
  41#define TRAP_SYSCALL    1
  42#define TRAP_DEBUG      0xdb
  43
  44void __init trap_init(void)
  45{
  46}
  47
  48#ifdef CONFIG_GENERIC_BUG
  49/* Maybe should resemble arch/sh/kernel/traps.c ?? */
  50int is_valid_bugaddr(unsigned long addr)
  51{
  52        return 1;
  53}
  54#endif /* CONFIG_GENERIC_BUG */
  55
  56static const char *ex_name(int ex)
  57{
  58        switch (ex) {
  59        case HVM_GE_C_XPROT:
  60        case HVM_GE_C_XUSER:
  61                return "Execute protection fault";
  62        case HVM_GE_C_RPROT:
  63        case HVM_GE_C_RUSER:
  64                return "Read protection fault";
  65        case HVM_GE_C_WPROT:
  66        case HVM_GE_C_WUSER:
  67                return "Write protection fault";
  68        case HVM_GE_C_XMAL:
  69                return "Misaligned instruction";
  70        case HVM_GE_C_WREG:
  71                return "Multiple writes to same register in packet";
  72        case HVM_GE_C_PCAL:
  73                return "Program counter values that are not properly aligned";
  74        case HVM_GE_C_RMAL:
  75                return "Misaligned data load";
  76        case HVM_GE_C_WMAL:
  77                return "Misaligned data store";
  78        case HVM_GE_C_INVI:
  79        case HVM_GE_C_PRIVI:
  80                return "Illegal instruction";
  81        case HVM_GE_C_BUS:
  82                return "Precise bus error";
  83        case HVM_GE_C_CACHE:
  84                return "Cache error";
  85
  86        case 0xdb:
  87                return "Debugger trap";
  88
  89        default:
  90                return "Unrecognized exception";
  91        }
  92}
  93
  94static void do_show_stack(struct task_struct *task, unsigned long *fp,
  95                          unsigned long ip)
  96{
  97        int kstack_depth_to_print = 24;
  98        unsigned long offset, size;
  99        const char *name = NULL;
 100        unsigned long *newfp;
 101        unsigned long low, high;
 102        char tmpstr[128];
 103        char *modname;
 104        int i;
 105
 106        if (task == NULL)
 107                task = current;
 108
 109        printk(KERN_INFO "CPU#%d, %s/%d, Call Trace:\n",
 110               raw_smp_processor_id(), task->comm,
 111               task_pid_nr(task));
 112
 113        if (fp == NULL) {
 114                if (task == current) {
 115                        asm("%0 = r30" : "=r" (fp));
 116                } else {
 117                        fp = (unsigned long *)
 118                             ((struct hexagon_switch_stack *)
 119                             task->thread.switch_sp)->fp;
 120                }
 121        }
 122
 123        if ((((unsigned long) fp) & 0x3) || ((unsigned long) fp < 0x1000)) {
 124                printk(KERN_INFO "-- Corrupt frame pointer %p\n", fp);
 125                return;
 126        }
 127
 128        /* Saved link reg is one word above FP */
 129        if (!ip)
 130                ip = *(fp+1);
 131
 132        /* Expect kernel stack to be in-bounds */
 133        low = (unsigned long)task_stack_page(task);
 134        high = low + THREAD_SIZE - 8;
 135        low += sizeof(struct thread_info);
 136
 137        for (i = 0; i < kstack_depth_to_print; i++) {
 138
 139                name = kallsyms_lookup(ip, &size, &offset, &modname, tmpstr);
 140
 141                printk(KERN_INFO "[%p] 0x%lx: %s + 0x%lx", fp, ip, name,
 142                        offset);
 143                if (((unsigned long) fp < low) || (high < (unsigned long) fp))
 144                        printk(KERN_CONT " (FP out of bounds!)");
 145                if (modname)
 146                        printk(KERN_CONT " [%s] ", modname);
 147                printk(KERN_CONT "\n");
 148
 149                newfp = (unsigned long *) *fp;
 150
 151                if (((unsigned long) newfp) & 0x3) {
 152                        printk(KERN_INFO "-- Corrupt frame pointer %p\n",
 153                                newfp);
 154                        break;
 155                }
 156
 157                /* Attempt to continue past exception. */
 158                if (0 == newfp) {
 159                        struct pt_regs *regs = (struct pt_regs *) (((void *)fp)
 160                                                + 8);
 161
 162                        if (regs->syscall_nr != -1) {
 163                                printk(KERN_INFO "-- trap0 -- syscall_nr: %ld",
 164                                        regs->syscall_nr);
 165                                printk(KERN_CONT "  psp: %lx  elr: %lx\n",
 166                                         pt_psp(regs), pt_elr(regs));
 167                                break;
 168                        } else {
 169                                /* really want to see more ... */
 170                                kstack_depth_to_print += 6;
 171                                printk(KERN_INFO "-- %s (0x%lx)  badva: %lx\n",
 172                                        ex_name(pt_cause(regs)), pt_cause(regs),
 173                                        pt_badva(regs));
 174                        }
 175
 176                        newfp = (unsigned long *) regs->r30;
 177                        ip = pt_elr(regs);
 178                } else {
 179                        ip = *(newfp + 1);
 180                }
 181
 182                /* If link reg is null, we are done. */
 183                if (ip == 0x0)
 184                        break;
 185
 186                /* If newfp isn't larger, we're tracing garbage. */
 187                if (newfp > fp)
 188                        fp = newfp;
 189                else
 190                        break;
 191        }
 192}
 193
 194void show_stack(struct task_struct *task, unsigned long *fp)
 195{
 196        /* Saved link reg is one word above FP */
 197        do_show_stack(task, fp, 0);
 198}
 199
 200int die(const char *str, struct pt_regs *regs, long err)
 201{
 202        static struct {
 203                spinlock_t lock;
 204                int counter;
 205        } die = {
 206                .lock = __SPIN_LOCK_UNLOCKED(die.lock),
 207                .counter = 0
 208        };
 209
 210        console_verbose();
 211        oops_enter();
 212
 213        spin_lock_irq(&die.lock);
 214        bust_spinlocks(1);
 215        printk(KERN_EMERG "Oops: %s[#%d]:\n", str, ++die.counter);
 216
 217        if (notify_die(DIE_OOPS, str, regs, err, pt_cause(regs), SIGSEGV) ==
 218            NOTIFY_STOP)
 219                return 1;
 220
 221        print_modules();
 222        show_regs(regs);
 223        do_show_stack(current, &regs->r30, pt_elr(regs));
 224
 225        bust_spinlocks(0);
 226        add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
 227
 228        spin_unlock_irq(&die.lock);
 229
 230        if (in_interrupt())
 231                panic("Fatal exception in interrupt");
 232
 233        if (panic_on_oops)
 234                panic("Fatal exception");
 235
 236        oops_exit();
 237        do_exit(err);
 238        return 0;
 239}
 240
 241int die_if_kernel(char *str, struct pt_regs *regs, long err)
 242{
 243        if (!user_mode(regs))
 244                return die(str, regs, err);
 245        else
 246                return 0;
 247}
 248
 249/*
 250 * It's not clear that misaligned fetches are ever recoverable.
 251 */
 252static void misaligned_instruction(struct pt_regs *regs)
 253{
 254        die_if_kernel("Misaligned Instruction", regs, 0);
 255        force_sig(SIGBUS, current);
 256}
 257
 258/*
 259 * Misaligned loads and stores, on the other hand, can be
 260 * emulated, and probably should be, some day.  But for now
 261 * they will be considered fatal.
 262 */
 263static void misaligned_data_load(struct pt_regs *regs)
 264{
 265        die_if_kernel("Misaligned Data Load", regs, 0);
 266        force_sig(SIGBUS, current);
 267}
 268
 269static void misaligned_data_store(struct pt_regs *regs)
 270{
 271        die_if_kernel("Misaligned Data Store", regs, 0);
 272        force_sig(SIGBUS, current);
 273}
 274
 275static void illegal_instruction(struct pt_regs *regs)
 276{
 277        die_if_kernel("Illegal Instruction", regs, 0);
 278        force_sig(SIGILL, current);
 279}
 280
 281/*
 282 * Precise bus errors may be recoverable with a a retry,
 283 * but for now, treat them as irrecoverable.
 284 */
 285static void precise_bus_error(struct pt_regs *regs)
 286{
 287        die_if_kernel("Precise Bus Error", regs, 0);
 288        force_sig(SIGBUS, current);
 289}
 290
 291/*
 292 * If anything is to be done here other than panic,
 293 * it will probably be complex and migrate to another
 294 * source module.  For now, just die.
 295 */
 296static void cache_error(struct pt_regs *regs)
 297{
 298        die("Cache Error", regs, 0);
 299}
 300
 301/*
 302 * General exception handler
 303 */
 304void do_genex(struct pt_regs *regs)
 305{
 306        /*
 307         * Decode Cause and Dispatch
 308         */
 309        switch (pt_cause(regs)) {
 310        case HVM_GE_C_XPROT:
 311        case HVM_GE_C_XUSER:
 312                execute_protection_fault(regs);
 313                break;
 314        case HVM_GE_C_RPROT:
 315        case HVM_GE_C_RUSER:
 316                read_protection_fault(regs);
 317                break;
 318        case HVM_GE_C_WPROT:
 319        case HVM_GE_C_WUSER:
 320                write_protection_fault(regs);
 321                break;
 322        case HVM_GE_C_XMAL:
 323                misaligned_instruction(regs);
 324                break;
 325        case HVM_GE_C_WREG:
 326                illegal_instruction(regs);
 327                break;
 328        case HVM_GE_C_PCAL:
 329                misaligned_instruction(regs);
 330                break;
 331        case HVM_GE_C_RMAL:
 332                misaligned_data_load(regs);
 333                break;
 334        case HVM_GE_C_WMAL:
 335                misaligned_data_store(regs);
 336                break;
 337        case HVM_GE_C_INVI:
 338        case HVM_GE_C_PRIVI:
 339                illegal_instruction(regs);
 340                break;
 341        case HVM_GE_C_BUS:
 342                precise_bus_error(regs);
 343                break;
 344        case HVM_GE_C_CACHE:
 345                cache_error(regs);
 346                break;
 347        default:
 348                /* Halt and catch fire */
 349                panic("Unrecognized exception 0x%lx\n", pt_cause(regs));
 350                break;
 351        }
 352}
 353
 354/* Indirect system call dispatch */
 355long sys_syscall(void)
 356{
 357        printk(KERN_ERR "sys_syscall invoked!\n");
 358        return -ENOSYS;
 359}
 360
 361void do_trap0(struct pt_regs *regs)
 362{
 363        syscall_fn syscall;
 364
 365        switch (pt_cause(regs)) {
 366        case TRAP_SYSCALL:
 367                /* System call is trap0 #1 */
 368
 369                /* allow strace to catch syscall args  */
 370                if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE) &&
 371                        tracehook_report_syscall_entry(regs)))
 372                        return;  /*  return -ENOSYS somewhere?  */
 373
 374                /* Interrupts should be re-enabled for syscall processing */
 375                __vmsetie(VM_INT_ENABLE);
 376
 377                /*
 378                 * System call number is in r6, arguments in r0..r5.
 379                 * Fortunately, no Linux syscall has more than 6 arguments,
 380                 * and Hexagon ABI passes first 6 arguments in registers.
 381                 * 64-bit arguments are passed in odd/even register pairs.
 382                 * Fortunately, we have no system calls that take more
 383                 * than three arguments with more than one 64-bit value.
 384                 * Should that change, we'd need to redesign to copy
 385                 * between user and kernel stacks.
 386                 */
 387                regs->syscall_nr = regs->r06;
 388
 389                /*
 390                 * GPR R0 carries the first parameter, and is also used
 391                 * to report the return value.  We need a backup of
 392                 * the user's value in case we need to do a late restart
 393                 * of the system call.
 394                 */
 395                regs->restart_r0 = regs->r00;
 396
 397                if ((unsigned long) regs->syscall_nr >= __NR_syscalls) {
 398                        regs->r00 = -1;
 399                } else {
 400                        syscall = (syscall_fn)
 401                                  (sys_call_table[regs->syscall_nr]);
 402                        regs->r00 = syscall(regs->r00, regs->r01,
 403                                   regs->r02, regs->r03,
 404                                   regs->r04, regs->r05);
 405                }
 406
 407                /* allow strace to get the syscall return state  */
 408                if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE)))
 409                        tracehook_report_syscall_exit(regs, 0);
 410
 411                break;
 412        case TRAP_DEBUG:
 413                /* Trap0 0xdb is debug breakpoint */
 414                if (user_mode(regs)) {
 415                        /*
 416                         * Some architecures add some per-thread state
 417                         * to distinguish between breakpoint traps and
 418                         * trace traps.  We may want to do that, and
 419                         * set the si_code value appropriately, or we
 420                         * may want to use a different trap0 flavor.
 421                         */
 422                        force_sig_fault(SIGTRAP, TRAP_BRKPT,
 423                                        (void __user *) pt_elr(regs), current);
 424                } else {
 425#ifdef CONFIG_KGDB
 426                        kgdb_handle_exception(pt_cause(regs), SIGTRAP,
 427                                              TRAP_BRKPT, regs);
 428#endif
 429                }
 430                break;
 431        }
 432        /* Ignore other trap0 codes for now, especially 0 (Angel calls) */
 433}
 434
 435/*
 436 * Machine check exception handler
 437 */
 438void do_machcheck(struct pt_regs *regs)
 439{
 440        /* Halt and catch fire */
 441        __vmstop();
 442}
 443
 444/*
 445 * Treat this like the old 0xdb trap.
 446 */
 447
 448void do_debug_exception(struct pt_regs *regs)
 449{
 450        regs->hvmer.vmest &= ~HVM_VMEST_CAUSE_MSK;
 451        regs->hvmer.vmest |= (TRAP_DEBUG << HVM_VMEST_CAUSE_SFT);
 452        do_trap0(regs);
 453}
 454