linux/arch/tile/kernel/traps.c
<<
>>
Prefs
   1/*
   2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
   3 *
   4 *   This program is free software; you can redistribute it and/or
   5 *   modify it under the terms of the GNU General Public License
   6 *   as published by the Free Software Foundation, version 2.
   7 *
   8 *   This program is distributed in the hope that it will be useful, but
   9 *   WITHOUT ANY WARRANTY; without even the implied warranty of
  10 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11 *   NON INFRINGEMENT.  See the GNU General Public License for
  12 *   more details.
  13 */
  14
  15#include <linux/sched.h>
  16#include <linux/kernel.h>
  17#include <linux/kprobes.h>
  18#include <linux/module.h>
  19#include <linux/reboot.h>
  20#include <linux/uaccess.h>
  21#include <linux/ptrace.h>
  22#include <asm/stack.h>
  23#include <asm/traps.h>
  24#include <asm/setup.h>
  25
  26#include <arch/interrupts.h>
  27#include <arch/spr_def.h>
  28#include <arch/opcode.h>
  29
  30void __init trap_init(void)
  31{
  32        /* Nothing needed here since we link code at .intrpt1 */
  33}
  34
  35int unaligned_fixup = 1;
  36
  37static int __init setup_unaligned_fixup(char *str)
  38{
  39        /*
  40         * Say "=-1" to completely disable it.  If you just do "=0", we
  41         * will still parse the instruction, then fire a SIGBUS with
  42         * the correct address from inside the single_step code.
  43         */
  44        long val;
  45        if (strict_strtol(str, 0, &val) != 0)
  46                return 0;
  47        unaligned_fixup = val;
  48        pr_info("Fixups for unaligned data accesses are %s\n",
  49               unaligned_fixup >= 0 ?
  50               (unaligned_fixup ? "enabled" : "disabled") :
  51               "completely disabled");
  52        return 1;
  53}
  54__setup("unaligned_fixup=", setup_unaligned_fixup);
  55
  56#if CHIP_HAS_TILE_DMA()
  57
  58static int dma_disabled;
  59
  60static int __init nodma(char *str)
  61{
  62        pr_info("User-space DMA is disabled\n");
  63        dma_disabled = 1;
  64        return 1;
  65}
  66__setup("nodma", nodma);
  67
  68/* How to decode SPR_GPV_REASON */
  69#define IRET_ERROR (1U << 31)
  70#define MT_ERROR   (1U << 30)
  71#define MF_ERROR   (1U << 29)
  72#define SPR_INDEX  ((1U << 15) - 1)
  73#define SPR_MPL_SHIFT  9  /* starting bit position for MPL encoded in SPR */
  74
  75/*
  76 * See if this GPV is just to notify the kernel of SPR use and we can
  77 * retry the user instruction after adjusting some MPLs suitably.
  78 */
  79static int retry_gpv(unsigned int gpv_reason)
  80{
  81        int mpl;
  82
  83        if (gpv_reason & IRET_ERROR)
  84                return 0;
  85
  86        BUG_ON((gpv_reason & (MT_ERROR|MF_ERROR)) == 0);
  87        mpl = (gpv_reason & SPR_INDEX) >> SPR_MPL_SHIFT;
  88        if (mpl == INT_DMA_NOTIFY && !dma_disabled) {
  89                /* User is turning on DMA. Allow it and retry. */
  90                printk(KERN_DEBUG "Process %d/%s is now enabled for DMA\n",
  91                       current->pid, current->comm);
  92                BUG_ON(current->thread.tile_dma_state.enabled);
  93                current->thread.tile_dma_state.enabled = 1;
  94                grant_dma_mpls();
  95                return 1;
  96        }
  97
  98        return 0;
  99}
 100
 101#endif /* CHIP_HAS_TILE_DMA() */
 102
 103#ifdef __tilegx__
 104#define bundle_bits tilegx_bundle_bits
 105#else
 106#define bundle_bits tile_bundle_bits
 107#endif
 108
 109extern bundle_bits bpt_code;
 110
 111asm(".pushsection .rodata.bpt_code,\"a\";"
 112    ".align 8;"
 113    "bpt_code: bpt;"
 114    ".size bpt_code,.-bpt_code;"
 115    ".popsection");
 116
 117static int special_ill(bundle_bits bundle, int *sigp, int *codep)
 118{
 119        int sig, code, maxcode;
 120
 121        if (bundle == bpt_code) {
 122                *sigp = SIGTRAP;
 123                *codep = TRAP_BRKPT;
 124                return 1;
 125        }
 126
 127        /* If it's a "raise" bundle, then "ill" must be in pipe X1. */
 128#ifdef __tilegx__
 129        if ((bundle & TILEGX_BUNDLE_MODE_MASK) != 0)
 130                return 0;
 131        if (get_Opcode_X1(bundle) != RRR_0_OPCODE_X1)
 132                return 0;
 133        if (get_RRROpcodeExtension_X1(bundle) != UNARY_RRR_0_OPCODE_X1)
 134                return 0;
 135        if (get_UnaryOpcodeExtension_X1(bundle) != ILL_UNARY_OPCODE_X1)
 136                return 0;
 137#else
 138        if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK)
 139                return 0;
 140        if (get_Opcode_X1(bundle) != SHUN_0_OPCODE_X1)
 141                return 0;
 142        if (get_UnShOpcodeExtension_X1(bundle) != UN_0_SHUN_0_OPCODE_X1)
 143                return 0;
 144        if (get_UnOpcodeExtension_X1(bundle) != ILL_UN_0_SHUN_0_OPCODE_X1)
 145                return 0;
 146#endif
 147
 148        /* Check that the magic distinguishers are set to mean "raise". */
 149        if (get_Dest_X1(bundle) != 29 || get_SrcA_X1(bundle) != 37)
 150                return 0;
 151
 152        /* There must be an "addli zero, zero, VAL" in X0. */
 153        if (get_Opcode_X0(bundle) != ADDLI_OPCODE_X0)
 154                return 0;
 155        if (get_Dest_X0(bundle) != TREG_ZERO)
 156                return 0;
 157        if (get_SrcA_X0(bundle) != TREG_ZERO)
 158                return 0;
 159
 160        /*
 161         * Validate the proposed signal number and si_code value.
 162         * Note that we embed these in the static instruction itself
 163         * so that we perturb the register state as little as possible
 164         * at the time of the actual fault; it's unlikely you'd ever
 165         * need to dynamically choose which kind of fault to raise
 166         * from user space.
 167         */
 168        sig = get_Imm16_X0(bundle) & 0x3f;
 169        switch (sig) {
 170        case SIGILL:
 171                maxcode = NSIGILL;
 172                break;
 173        case SIGFPE:
 174                maxcode = NSIGFPE;
 175                break;
 176        case SIGSEGV:
 177                maxcode = NSIGSEGV;
 178                break;
 179        case SIGBUS:
 180                maxcode = NSIGBUS;
 181                break;
 182        case SIGTRAP:
 183                maxcode = NSIGTRAP;
 184                break;
 185        default:
 186                return 0;
 187        }
 188        code = (get_Imm16_X0(bundle) >> 6) & 0xf;
 189        if (code <= 0 || code > maxcode)
 190                return 0;
 191
 192        /* Make it the requested signal. */
 193        *sigp = sig;
 194        *codep = code | __SI_FAULT;
 195        return 1;
 196}
 197
 198static const char *const int_name[] = {
 199        [INT_MEM_ERROR] = "Memory error",
 200        [INT_ILL] = "Illegal instruction",
 201        [INT_GPV] = "General protection violation",
 202        [INT_UDN_ACCESS] = "UDN access",
 203        [INT_IDN_ACCESS] = "IDN access",
 204#if CHIP_HAS_SN()
 205        [INT_SN_ACCESS] = "SN access",
 206#endif
 207        [INT_SWINT_3] = "Software interrupt 3",
 208        [INT_SWINT_2] = "Software interrupt 2",
 209        [INT_SWINT_0] = "Software interrupt 0",
 210        [INT_UNALIGN_DATA] = "Unaligned data",
 211        [INT_DOUBLE_FAULT] = "Double fault",
 212#ifdef __tilegx__
 213        [INT_ILL_TRANS] = "Illegal virtual address",
 214#endif
 215};
 216
 217void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 218                       unsigned long reason)
 219{
 220        siginfo_t info = { 0 };
 221        int signo, code;
 222        unsigned long address = 0;
 223        bundle_bits instr;
 224
 225        /* Re-enable interrupts. */
 226        local_irq_enable();
 227
 228        /*
 229         * If it hits in kernel mode and we can't fix it up, just exit the
 230         * current process and hope for the best.
 231         */
 232        if (!user_mode(regs)) {
 233                const char *name;
 234                if (fixup_exception(regs))  /* only UNALIGN_DATA in practice */
 235                        return;
 236                if (fault_num >= 0 &&
 237                    fault_num < sizeof(int_name)/sizeof(int_name[0]) &&
 238                    int_name[fault_num] != NULL)
 239                        name = int_name[fault_num];
 240                else
 241                        name = "Unknown interrupt";
 242                pr_alert("Kernel took bad trap %d (%s) at PC %#lx\n",
 243                         fault_num, name, regs->pc);
 244                if (fault_num == INT_GPV)
 245                        pr_alert("GPV_REASON is %#lx\n", reason);
 246                show_regs(regs);
 247                do_exit(SIGKILL);  /* FIXME: implement i386 die() */
 248                return;
 249        }
 250
 251        switch (fault_num) {
 252        case INT_MEM_ERROR:
 253                signo = SIGBUS;
 254                code = BUS_OBJERR;
 255                break;
 256        case INT_ILL:
 257                if (copy_from_user(&instr, (void __user *)regs->pc,
 258                                   sizeof(instr))) {
 259                        pr_err("Unreadable instruction for INT_ILL:"
 260                               " %#lx\n", regs->pc);
 261                        do_exit(SIGKILL);
 262                        return;
 263                }
 264                if (!special_ill(instr, &signo, &code)) {
 265                        signo = SIGILL;
 266                        code = ILL_ILLOPC;
 267                }
 268                address = regs->pc;
 269                break;
 270        case INT_GPV:
 271#if CHIP_HAS_TILE_DMA()
 272                if (retry_gpv(reason))
 273                        return;
 274#endif
 275                /*FALLTHROUGH*/
 276        case INT_UDN_ACCESS:
 277        case INT_IDN_ACCESS:
 278#if CHIP_HAS_SN()
 279        case INT_SN_ACCESS:
 280#endif
 281                signo = SIGILL;
 282                code = ILL_PRVREG;
 283                address = regs->pc;
 284                break;
 285        case INT_SWINT_3:
 286        case INT_SWINT_2:
 287        case INT_SWINT_0:
 288                signo = SIGILL;
 289                code = ILL_ILLTRP;
 290                address = regs->pc;
 291                break;
 292        case INT_UNALIGN_DATA:
 293#ifndef __tilegx__  /* Emulated support for single step debugging */
 294                if (unaligned_fixup >= 0) {
 295                        struct single_step_state *state =
 296                                current_thread_info()->step_state;
 297                        if (!state ||
 298                            (void __user *)(regs->pc) != state->buffer) {
 299                                single_step_once(regs);
 300                                return;
 301                        }
 302                }
 303#endif
 304                signo = SIGBUS;
 305                code = BUS_ADRALN;
 306                address = 0;
 307                break;
 308        case INT_DOUBLE_FAULT:
 309                /*
 310                 * For double fault, "reason" is actually passed as
 311                 * SYSTEM_SAVE_K_2, the hypervisor's double-fault info, so
 312                 * we can provide the original fault number rather than
 313                 * the uninteresting "INT_DOUBLE_FAULT" so the user can
 314                 * learn what actually struck while PL0 ICS was set.
 315                 */
 316                fault_num = reason;
 317                signo = SIGILL;
 318                code = ILL_DBLFLT;
 319                address = regs->pc;
 320                break;
 321#ifdef __tilegx__
 322        case INT_ILL_TRANS: {
 323                /* Avoid a hardware erratum with the return address stack. */
 324                fill_ra_stack();
 325
 326                signo = SIGSEGV;
 327                code = SEGV_MAPERR;
 328                if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK)
 329                        address = regs->pc;
 330                else
 331                        address = 0;  /* FIXME: GX: single-step for address */
 332                break;
 333        }
 334#endif
 335        default:
 336                panic("Unexpected do_trap interrupt number %d", fault_num);
 337                return;
 338        }
 339
 340        info.si_signo = signo;
 341        info.si_code = code;
 342        info.si_addr = (void __user *)address;
 343        if (signo == SIGILL)
 344                info.si_trapno = fault_num;
 345        if (signo != SIGTRAP)
 346                trace_unhandled_signal("trap", regs, address, signo);
 347        force_sig_info(signo, &info, current);
 348}
 349
 350void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
 351{
 352        _dump_stack(dummy, pc, lr, sp, r52);
 353        pr_emerg("Double fault: exiting\n");
 354        machine_halt();
 355}
 356