Root/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c

1/*
2 * arch/ubicom32/kernel/traps.c
3 * Ubicom32 architecture trap handling support.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 *
7 * This file is part of the Ubicom32 Linux Kernel Port.
8 *
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
22 *
23 * Ubicom32 implementation derived from (with many thanks):
24 * arch/m68knommu
25 * arch/blackfin
26 * arch/parisc
27 */
28
29/*
30 * Sets up all exception vectors
31 */
32#include <linux/sched.h>
33#include <linux/signal.h>
34#include <linux/kernel.h>
35#include <linux/mm.h>
36#include <linux/module.h>
37#include <linux/types.h>
38#include <linux/a.out.h>
39#include <linux/user.h>
40#include <linux/string.h>
41#include <linux/linkage.h>
42#include <linux/init.h>
43#include <linux/ptrace.h>
44#include <linux/kallsyms.h>
45#include <linux/compiler.h>
46#include <linux/stacktrace.h>
47#include <linux/personality.h>
48
49#include <asm/uaccess.h>
50#include <asm/stacktrace.h>
51#include <asm/devtree.h>
52#include <asm/setup.h>
53#include <asm/fpu.h>
54#include <asm/system.h>
55#include <asm/traps.h>
56#include <asm/pgtable.h>
57#include <asm/processor.h>
58#include <asm/machdep.h>
59#include <asm/siginfo.h>
60#include <asm/ip5000.h>
61#include <asm/thread.h>
62
63#define TRAP_MAX_STACK_DEPTH 20
64
65/*
66 * These symbols are filled in by the linker.
67 */
68extern unsigned long _stext;
69extern unsigned long _etext;
70
71extern unsigned long __ocm_text_run_begin;
72extern unsigned long __data_begin;
73
74extern void show_vmas(struct task_struct *task);
75
76const char *trap_cause_strings[] = {
77    /*0*/ "inst address decode error",
78    /*1*/ "inst sync error",
79    /*2*/ "inst illegal",
80    /*3*/ "src1 address decode error",
81    /*4*/ "dst address decode error",
82    /*5*/ "src1 alignment error",
83    /*6*/ "dst alignment error",
84    /*7*/ "src1 sync error",
85    /*8*/ "dst sync error",
86    /*9*/ "DCAPT error",
87    /*10*/ "inst range error",
88    /*11*/ "src1 range error",
89    /*12*/ "dst range error",
90};
91
92/*
93 * The device tree trap node definition.
94 */
95struct trapnode {
96    struct devtree_node dn;
97    unsigned int intthread;
98};
99
100static struct trapnode *tn;;
101
102/*
103 * trap_interrupt_handler()
104 * Software Interrupt to ensure that a trap is serviced.
105 */
106static irqreturn_t trap_interrupt_handler(int irq, void *dummy)
107{
108    /* Do Nothing */
109    return IRQ_HANDLED;
110}
111
112/*
113 * Data used by setup_irq for the timer.
114 */
115static struct irqaction trap_irq = {
116    .name = "trap",
117    .flags = IRQF_DISABLED,
118    .handler = trap_interrupt_handler,
119};
120
121/*
122 * trap_cause_to_str()
123 * Convert a trap_cause into a series of printk
124 */
125static void trap_cause_to_str(long status)
126{
127    int bit;
128
129    if ((status & ((1 << TRAP_CAUSE_TOTAL) - 1)) == 0) {
130        printk(KERN_NOTICE "decode: UNKNOWN CAUSES\n");
131        return;
132    }
133
134    for (bit = 0; bit < TRAP_CAUSE_TOTAL; bit++) {
135        if (status & (1 << bit)) {
136            printk(KERN_NOTICE "\tdecode: %08x %s\n",
137                   1 << bit, trap_cause_strings[bit]);
138        }
139    }
140}
141
142/*
143 * trap_print_information()
144 * Print the cause of the trap and additional info.
145 */
146static void trap_print_information(const char *str, struct pt_regs *regs)
147{
148    printk(KERN_WARNING "\n");
149
150    if (current) {
151        printk(KERN_WARNING "Process %s (pid: %d)\n",
152            current->comm, current->pid);
153    }
154
155    if (current && current->mm) {
156        printk(KERN_NOTICE "text = 0x%p-0x%p data = 0x%p-0x%p\n"
157            KERN_NOTICE "bss = 0x%p-0x%p user-stack = 0x%p\n"
158            KERN_NOTICE "\n",
159            (void *)current->mm->start_code,
160            (void *)current->mm->end_code,
161            (void *)current->mm->start_data,
162            (void *)current->mm->end_data,
163            (void *)current->mm->end_data,
164            (void *)current->mm->brk,
165            (void *)current->mm->start_stack);
166    }
167
168    printk(KERN_WARNING "%s: Causes: 0x%08x\n", str,
169            (unsigned int)regs->trap_cause);
170    trap_cause_to_str(regs->trap_cause);
171    show_regs(regs);
172    show_stack(NULL, (unsigned long *)regs->an[7]);
173    printk(KERN_NOTICE "--- End Trap --- \n");
174}
175
176/*
177 * dump_stack()
178 * Dump the stack of the current task.
179 */
180void dump_stack(void)
181{
182    show_stack(NULL, NULL);
183}
184EXPORT_SYMBOL(dump_stack);
185
186/*
187 * show_stack()
188 * Print out information from the current stack.
189 */
190void show_stack(struct task_struct *task, unsigned long *sp)
191{
192    /*
193     * Allocate just enough entries on the stack.
194     */
195    unsigned int calls[TRAP_MAX_STACK_DEPTH];
196    unsigned long code_start;
197    unsigned long code_end;
198    unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin;
199    unsigned long ocm_code_end = (unsigned long)&__data_begin;
200    unsigned long stack_end = (unsigned long)(current->stack + THREAD_SIZE - 8);
201    unsigned long stack = (unsigned long)sp;
202    int kernel_stack = 1;
203
204    processor_dram(&code_start, &code_end);
205
206    /*
207     * Which task are we talking about.
208     */
209    if (!task) {
210        task = current;
211    }
212
213    /*
214     * Find the stack for the task if one was not specified. Otherwise
215     * use the specified stack.
216     */
217    if (!stack) {
218        if (task != current) {
219            stack = task->thread.sp;
220            stack_end = (unsigned long)task->stack + THREAD_SIZE - 8;
221        } else {
222            asm volatile (
223                "move.4 %0, SP \n\t"
224                : "=r" (stack)
225            );
226        }
227    }
228
229    printk(KERN_NOTICE "Starting backtrace: PID %d '%s'\n",
230            task->pid, task->comm);
231
232    /*
233     * We do 2 passes the first pass is Kernel stack is the second
234     * User stack.
235     */
236    while (kernel_stack) {
237        unsigned long *handle;
238        unsigned int i, idx = 0;
239        struct pt_regs *pt = task_pt_regs(task);
240
241        /*
242         * If the task is in user mode, reset the start
243         * and end values for text.
244         */
245        if (__user_mode(stack)) {
246            if (!(task->personality & FDPIC_FUNCPTRS)) {
247                printk(KERN_NOTICE " User Stack:\n");
248                code_start = task->mm->start_code;
249                code_end = task->mm->end_code;
250            } else {
251                printk(KERN_NOTICE " User Stack (fdpic):\n");
252                show_vmas(task);
253            }
254            stack_end = task->mm->start_stack;
255            ocm_code_end = ocm_code_start = 0;
256            kernel_stack = 0;
257        } else {
258            printk(KERN_NOTICE " Kernel Stack:\n");
259        }
260
261        /*
262         * Collect the stack back trace information.
263         */
264        printk(" code[0x%lx-0x%lx]", code_start, code_end);
265        if (ocm_code_start) {
266            printk(" ocm_code[0x%lx-0x%lx]",
267                   ocm_code_start, ocm_code_end);
268        }
269        printk("\n stack[0x%lx-0x%lx]\n", stack, stack_end);
270
271        handle = (unsigned long*)stack;
272        while (idx < TRAP_MAX_STACK_DEPTH) {
273            calls[idx] = stacktrace_iterate(&handle,
274                    code_start, code_end,
275                    ocm_code_start, ocm_code_end,
276                    (unsigned long)stack, stack_end);
277            if (calls[idx] == 0) {
278                break;
279            }
280            idx++;
281        }
282
283        /*
284         * Now print out the data.
285         */
286        printk(KERN_NOTICE " CALL && CALLI on stack:");
287        for (i = 0; i < idx; i++) {
288            printk("%s0x%x, ", (i & 0x3) == 0 ? "\n " : "",
289                    calls[i]);
290        }
291        printk(idx == TRAP_MAX_STACK_DEPTH ? "...\n" : "\n");
292
293        /*
294         * If we are doing user stack we are done
295         */
296        if (!kernel_stack) {
297            break;
298        }
299
300        /*
301         * Does this kernel stack have a mm (i.e. is it user)
302         */
303        if (!task->mm) {
304            printk("No mm for userspace stack.\n");
305            break;
306        }
307        /*
308         * Get the user-mode stack (if any)
309         */
310        stack = pt->an[7];
311        printk(KERN_NOTICE "Userspace stack at 0x%lx frame type %d\n",
312                stack, (int)pt->frame_type);
313        if (!__user_mode(stack)) {
314            break;
315        }
316    }
317}
318
319/*
320 * die_if_kernel()
321 * Determine if we are in kernel mode and if so print stuff out and die.
322 */
323void die_if_kernel(char *str, struct pt_regs *regs, long trap_cause)
324{
325    unsigned int s3value;
326
327    if (user_mode(regs)) {
328        return;
329    }
330
331    console_verbose();
332    trap_print_information(str, regs);
333
334    /*
335     * If the debugger is attached via the hardware mailbox protocol,
336     * go into an infinite loop and the debugger will figure things out.
337     */
338    asm volatile (
339          "move.4 %0, scratchpad3"
340          : "=r" (s3value)
341    );
342    if (s3value) {
343        asm volatile("1: jmpt.t 1b");
344    }
345
346    /*
347     * Set the debug taint value.
348     */
349    add_taint(TAINT_DIE);
350    do_exit(SIGSEGV);
351}
352
353/*
354 * trap_handler()
355 * Handle traps.
356 *
357 * Traps are treated as interrupts and registered with the LDSR. When
358 * the LDSR takes the interrupt, it will determine if a trap has occurred
359 * and service the trap prior to servicing the interrupt.
360 *
361 * This function is directly called by the LDSR.
362 */
363void trap_handler(int irq, struct pt_regs *regs)
364{
365    int sig = SIGSEGV;
366    siginfo_t info;
367    unsigned int trap_cause = regs->trap_cause;
368
369    BUG_ON(!irqs_disabled());
370
371    /*
372     * test if in kernel and die.
373     */
374    die_if_kernel("Kernel Trap", regs, trap_cause);
375
376    /*
377     * User process problem, setup a signal for this process
378     */
379    if ((trap_cause & (1 << TRAP_CAUSE_DST_RANGE_ERR)) ||
380        (trap_cause & (1 << TRAP_CAUSE_SRC1_RANGE_ERR)) ||
381        (trap_cause & (1 << TRAP_CAUSE_I_RANGE_ERR))) {
382        sig = SIGSEGV;
383        info.si_code = SEGV_MAPERR;
384    } else if ((trap_cause & (1 << TRAP_CAUSE_DST_MISALIGNED)) ||
385           (trap_cause & (1 << TRAP_CAUSE_SRC1_MISALIGNED))) {
386        sig = SIGBUS;
387        info.si_code = BUS_ADRALN;
388    } else if ((trap_cause & (1 << TRAP_CAUSE_DST_DECODE_ERR)) ||
389           (trap_cause & (1 << TRAP_CAUSE_SRC1_DECODE_ERR))) {
390        sig = SIGILL;
391        info.si_code = ILL_ILLOPN;
392    } else if ((trap_cause & (1 << TRAP_CAUSE_ILLEGAL_INST))) {
393        /*
394         * Check for software break point and if found signal trap
395         * not illegal instruction.
396         */
397        unsigned long instruction;
398        if (between(regs->pc, KERNELSTART, memory_end) &&
399            (regs->pc & 3) == 0 &&
400            get_user(instruction, (unsigned long *)regs->pc) == 0) {
401
402            /*
403             * This used to be 0xaabbccdd but it turns out
404             * that is now valid in ubicom32v4 isa so we
405             * have switched to 0xfabbccdd
406             */
407            if ((instruction == 0xfabbccdd) ||
408                (instruction == 0xaabbccdd)) {
409                sig = SIGTRAP;
410                info.si_code = TRAP_BRKPT;
411                goto send_signal;
412            }
413        }
414        sig = SIGILL;
415        info.si_code = ILL_ILLOPC;
416    } else if ((trap_cause & (1 << TRAP_CAUSE_I_DECODE_ERR))) {
417        sig = SIGILL;
418        info.si_code = ILL_ILLOPC;
419    } else if ((trap_cause & (1 << TRAP_CAUSE_DCAPT))) {
420        sig = SIGTRAP;
421        info.si_code = TRAP_TRACE;
422    }
423
424    /*
425     * Print a trap information block to the console, do not
426     * print this above the case because we don't want it
427     * printed for software break points.
428     */
429    trap_print_information("User Trap", regs);
430
431send_signal:
432
433    force_sig_info(sig, &info, current);
434
435    /*
436     * Interrupts are disabled, re-enable them now.
437     */
438    if (!irqs_disabled()) {
439        printk(KERN_EMERG "interrupts enabled on exit, irq=%d, regs=%p",
440                irq, regs);
441        BUG();
442    }
443}
444
445/*
446 * trap_init_interrupt()
447 * We need a 2nd trap handling init that will occur after init_IRQ().
448 */
449void __init trap_init_interrupt(void)
450{
451    int err;
452    unsigned char tirq;
453    struct devtree_node *dn = (struct devtree_node *)tn;
454
455    /*
456     * Now setup the Software IRQ so that if a trap occurs the LDSR
457     * is started. The irq is there just to "force" the LDSR to run.
458     */
459    if (!tn) {
460        printk(KERN_WARNING "trap_init_interrupt skipped.\n");
461        return;
462    }
463
464    err = devtree_irq(dn, NULL, &tirq);
465    if (err) {
466        printk(KERN_WARNING "error obtaining trap irq value: %d\n",
467            err);
468        return;
469    }
470
471    if (tirq == DEVTREE_IRQ_NONE) {
472        printk(KERN_WARNING "trap irq not available: %d\n", tirq);
473        return;
474    }
475
476    err = setup_irq(tirq, &trap_irq);
477    if (err) {
478        printk(KERN_WARNING "trap irq setup failed: %d\n", err);
479        return;
480    }
481
482    /*
483     * Let ultra know which thread is handling the traps and
484     * what the interrupt to use is.
485     */
486    tn->intthread = ldsr_get_threadid();
487
488    /*
489     * Tell the LDSR about our IRQ so that it will unsuspend
490     * if one occurs while waiting for the per thread lock.
491     */
492    ldsr_set_trap_irq(tirq);
493}
494
495/*
496 * trap_init()
497 * init trap handling
498 *
499 * Trap handling is done through the ldsr. Every time an interrupt
500 * occurs, the LDSR looks for threads that are listed in the TRAP
501 * register and forces a call to the trap handler.
502 */
503void __init trap_init(void)
504{
505    /*
506     * If we do not have a trap node in the device tree, we leave the fault
507     * handling to the underlying hardware.
508     */
509    tn = (struct trapnode *)devtree_find_node("traps");
510    if (!tn) {
511        printk(KERN_WARNING "traps are not handled by linux\n");
512        return;
513    }
514}
515

Archive Download this file



interactive