OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [armnommu/] [kernel/] [traps.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 *  linux/arch/arm/kernel/traps.c
 *  linux/arch/arm/kernel/traps.c
 *
 *
 *  Copyright (C) 1995, 1996 Russell King
 *  Copyright (C) 1995, 1996 Russell King
 *  Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
 *  Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
 */
 */
 
 
/*
/*
 * 'traps.c' handles hardware exceptions after we have saved some state in
 * 'traps.c' handles hardware exceptions after we have saved some state in
 * 'linux/arch/arm/lib/traps.S'.  Mostly a debugging aid, but will probably
 * 'linux/arch/arm/lib/traps.S'.  Mostly a debugging aid, but will probably
 * kill the offending process.
 * kill the offending process.
 */
 */
#include <linux/config.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/mm.h>
 
 
extern void fpe_save(struct fp_soft_struct *);
extern void fpe_save(struct fp_soft_struct *);
extern void fpe_restore(struct fp_soft_struct *);
extern void fpe_restore(struct fp_soft_struct *);
extern void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret);
extern void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret);
extern void c_backtrace (unsigned long fp, int pmode);
extern void c_backtrace (unsigned long fp, int pmode);
extern int ptrace_cancel_bpt (struct task_struct *);
extern int ptrace_cancel_bpt (struct task_struct *);
 
 
char *processor_modes[]=
char *processor_modes[]=
{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
  "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
  "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
  "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
  "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
  "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
  "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
};
};
 
 
static char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
static char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
 
 
static inline void console_verbose(void)
static inline void console_verbose(void)
{
{
        extern int console_loglevel;
        extern int console_loglevel;
        console_loglevel = 15;
        console_loglevel = 15;
}
}
 
 
int kstack_depth_to_print = 200;
int kstack_depth_to_print = 200;
 
 
static int verify_stack_pointer (unsigned long stackptr, int size)
static int verify_stack_pointer (unsigned long stackptr, int size)
{
{
#if defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3)
#if defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3)
        if (stackptr < 0x02048000 || stackptr + size > 0x03000000)
        if (stackptr < 0x02048000 || stackptr + size > 0x03000000)
                return -EFAULT;
                return -EFAULT;
#else
#else
        if (stackptr < 0xc0000000 || stackptr + size > high_memory)
        if (stackptr < 0xc0000000 || stackptr + size > high_memory)
                return -EFAULT;
                return -EFAULT;
#endif
#endif
                return 0;
                return 0;
}
}
 
 
static void dump_stack (unsigned long *start, unsigned long *end, int offset, int max)
static void dump_stack (unsigned long *start, unsigned long *end, int offset, int max)
{
{
        unsigned long *p;
        unsigned long *p;
        int i;
        int i;
 
 
        for (p = start + offset, i = 0; i < max && p < end; i++, p++) {
        for (p = start + offset, i = 0; i < max && p < end; i++, p++) {
                if (i && (i & 7) == 0)
                if (i && (i & 7) == 0)
                        printk ("\n       ");
                        printk ("\n       ");
                printk ("%08lx ", *p);
                printk ("%08lx ", *p);
        }
        }
        printk ("\n");
        printk ("\n");
}
}
 
 
/*
/*
 * These constants are for searching for possible module text
 * These constants are for searching for possible module text
 * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
 * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
 * a guess of how much space is likely to be vmalloced.
 * a guess of how much space is likely to be vmalloced.
 */
 */
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_OFFSET (8*1024*1024)
#define MODULE_RANGE (8*1024*1024)
#define MODULE_RANGE (8*1024*1024)
 
 
static void dump_instr (unsigned long pc)
static void dump_instr (unsigned long pc)
{
{
        unsigned long module_start, module_end;
        unsigned long module_start, module_end;
        int pmin = -2, pmax = 3, ok = 0;
        int pmin = -2, pmax = 3, ok = 0;
        extern char start_kernel, _etext;
        extern char start_kernel, _etext;
 
 
        module_start = ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
        module_start = ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
        module_end   = module_start + MODULE_RANGE;
        module_end   = module_start + MODULE_RANGE;
 
 
        if ((pc >= (unsigned long) &start_kernel) &&
        if ((pc >= (unsigned long) &start_kernel) &&
            (pc <= (unsigned long) &_etext)) {
            (pc <= (unsigned long) &_etext)) {
                if (pc + pmin < (unsigned long) &start_kernel)
                if (pc + pmin < (unsigned long) &start_kernel)
                        pmin = ((unsigned long) &start_kernel) - pc;
                        pmin = ((unsigned long) &start_kernel) - pc;
                if (pc + pmax > (unsigned long) &_etext)
                if (pc + pmax > (unsigned long) &_etext)
                        pmax = ((unsigned long) &_etext) - pc;
                        pmax = ((unsigned long) &_etext) - pc;
                ok = 1;
                ok = 1;
        } else if (pc >= module_start && pc <= module_end) {
        } else if (pc >= module_start && pc <= module_end) {
                if (pc + pmin < module_start)
                if (pc + pmin < module_start)
                        pmin = module_start - pc;
                        pmin = module_start - pc;
                if (pc + pmax > module_end)
                if (pc + pmax > module_end)
                        pmax = module_end - pc;
                        pmax = module_end - pc;
                ok = 1;
                ok = 1;
        }
        }
        printk ("Code: ");
        printk ("Code: ");
        if (ok) {
        if (ok) {
                int i;
                int i;
                for (i = pmin; i < pmax; i++)
                for (i = pmin; i < pmax; i++)
                        printk("%08lx ", ((unsigned long *)pc)[i]);
                        printk("%08lx ", ((unsigned long *)pc)[i]);
                printk ("\n");
                printk ("\n");
        } else
        } else
                printk ("pc not in code space\n");
                printk ("pc not in code space\n");
}
}
 
 
/*
/*
 * This function is protected against kernel-mode re-entrancy.  If it
 * This function is protected against kernel-mode re-entrancy.  If it
 * is re-entered it will hang the system since we can't guarantee in
 * is re-entered it will hang the system since we can't guarantee in
 * this case that any of the functions that it calls are safe any more.
 * this case that any of the functions that it calls are safe any more.
 * Even the panic function could be a problem, but we'll give it a go.
 * Even the panic function could be a problem, but we'll give it a go.
 */
 */
void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret)
void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret)
{
{
        static int died = 0;
        static int died = 0;
        unsigned long cstack, sstack, frameptr;
        unsigned long cstack, sstack, frameptr;
 
 
        if (user_mode(regs))
        if (user_mode(regs))
                return;
                return;
 
 
        switch (died) {
        switch (died) {
        case 2:
        case 2:
                while (1);
                while (1);
        case 1:
        case 1:
                died ++;
                died ++;
                panic ("die_if_kernel re-entered.  Major kernel corruption.  Please reboot me!");
                panic ("die_if_kernel re-entered.  Major kernel corruption.  Please reboot me!");
                break;
                break;
        case 0:
        case 0:
                died ++;
                died ++;
                break;
                break;
        }
        }
 
 
        console_verbose ();
        console_verbose ();
        printk ("Internal error: %s: %x\n", str, err);
        printk ("Internal error: %s: %x\n", str, err);
        printk ("CPU: %d", smp_processor_id());
        printk ("CPU: %d", smp_processor_id());
        show_regs (regs);
        show_regs (regs);
        printk ("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
        printk ("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
                current->comm, current->pid, current->kernel_stack_page);
                current->comm, current->pid, current->kernel_stack_page);
 
 
        cstack = (unsigned long)(regs + 1);
        cstack = (unsigned long)(regs + 1);
        sstack = (unsigned long)current->kernel_stack_page;
        sstack = (unsigned long)current->kernel_stack_page;
 
 
        if (*(unsigned long *)sstack != STACK_MAGIC)
        if (*(unsigned long *)sstack != STACK_MAGIC)
                printk ("*** corrupted stack page\n       ");
                printk ("*** corrupted stack page\n       ");
 
 
        if (verify_stack_pointer (cstack, 4))
        if (verify_stack_pointer (cstack, 4))
                printk ("%08lx invalid kernel stack pointer\n", cstack);
                printk ("%08lx invalid kernel stack pointer\n", cstack);
        else if(cstack > sstack + 4096)
        else if(cstack > sstack + 4096)
                printk("(sp overflow)\n");
                printk("(sp overflow)\n");
        else if(cstack < sstack)
        else if(cstack < sstack)
                printk("(sp underflow)\n");
                printk("(sp underflow)\n");
        else
        else
                dump_stack ((unsigned long *)sstack, (unsigned long *)sstack + 1024,
                dump_stack ((unsigned long *)sstack, (unsigned long *)sstack + 1024,
                        cstack - sstack, kstack_depth_to_print);
                        cstack - sstack, kstack_depth_to_print);
 
 
        frameptr = regs->ARM_fp;
        frameptr = regs->ARM_fp;
        if (frameptr) {
        if (frameptr) {
                if (verify_stack_pointer (frameptr, 4))
                if (verify_stack_pointer (frameptr, 4))
                        printk ("Backtrace: invalid frame pointer\n");
                        printk ("Backtrace: invalid frame pointer\n");
                else {
                else {
                        printk("Backtrace: \n");
                        printk("Backtrace: \n");
                        c_backtrace (frameptr, processor_mode(regs));
                        c_backtrace (frameptr, processor_mode(regs));
                }
                }
        }
        }
 
 
        dump_instr (instruction_pointer(regs));
        dump_instr (instruction_pointer(regs));
        died = 0;
        died = 0;
        if (ret != -1)
        if (ret != -1)
                do_exit (ret);
                do_exit (ret);
        else {
        else {
                cli ();
                cli ();
                while (1);
                while (1);
        }
        }
}
}
 
 
void bad_user_access_alignment (const void *ptr)
void bad_user_access_alignment (const void *ptr)
{
{
        void *pc;
        void *pc;
        __asm__("mov %0, lr\n": "=r" (pc));
        __asm__("mov %0, lr\n": "=r" (pc));
        printk ("bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr, pc);
        printk ("bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr, pc);
        current->tss.error_code = 0;
        current->tss.error_code = 0;
        current->tss.trap_no = 11;
        current->tss.trap_no = 11;
        force_sig (SIGBUS, current);
        force_sig (SIGBUS, current);
/*      die_if_kernel("Oops - bad user access alignment", regs, mode, SIGBUS);*/
/*      die_if_kernel("Oops - bad user access alignment", regs, mode, SIGBUS);*/
}
}
 
 
asmlinkage void do_undefinstr (int address, struct pt_regs *regs, int mode)
asmlinkage void do_undefinstr (int address, struct pt_regs *regs, int mode)
{
{
        current->tss.error_code = 0;
        current->tss.error_code = 0;
        current->tss.trap_no = 6;
        current->tss.trap_no = 6;
        force_sig (SIGILL, current);
        force_sig (SIGILL, current);
        die_if_kernel("Oops - undefined instruction", regs, mode, SIGILL);
        die_if_kernel("Oops - undefined instruction", regs, mode, SIGILL);
}
}
 
 
asmlinkage void do_excpt (int address, struct pt_regs *regs, int mode)
asmlinkage void do_excpt (int address, struct pt_regs *regs, int mode)
{
{
        current->tss.error_code = 0;
        current->tss.error_code = 0;
        current->tss.trap_no = 11;
        current->tss.trap_no = 11;
        force_sig (SIGBUS, current);
        force_sig (SIGBUS, current);
        die_if_kernel("Oops - address exception", regs, mode, SIGBUS);
        die_if_kernel("Oops - address exception", regs, mode, SIGBUS);
}
}
 
 
asmlinkage void do_unexp_fiq (struct pt_regs *regs)
asmlinkage void do_unexp_fiq (struct pt_regs *regs)
{
{
#ifndef CONFIG_IGNORE_FIQ
#ifndef CONFIG_IGNORE_FIQ
        printk ("Hmm.  Unexpected FIQ received, but trying to continue\n");
        printk ("Hmm.  Unexpected FIQ received, but trying to continue\n");
        printk ("You may have a hardware problem...\n");
        printk ("You may have a hardware problem...\n");
#endif
#endif
}
}
 
 
asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
{
{
        printk ("Bad mode in %s handler detected: mode %s\n",
        printk ("Bad mode in %s handler detected: mode %s\n",
                handler[reason],
                handler[reason],
                processor_modes[proc_mode]);
                processor_modes[proc_mode]);
        die_if_kernel ("Oops", regs, 0, -1);
        die_if_kernel ("Oops", regs, 0, -1);
}
}
 
 
/*
/*
 * 'math_state_restore()' saves the current math information in the
 * 'math_state_restore()' saves the current math information in the
 * old math state array, and gets the new ones from the current task.
 * old math state array, and gets the new ones from the current task.
 *
 *
 * We no longer save/restore the math state on every context switch
 * We no longer save/restore the math state on every context switch
 * any more.  We only do this now if it actually gets used.
 * any more.  We only do this now if it actually gets used.
 */
 */
asmlinkage void math_state_restore (void)
asmlinkage void math_state_restore (void)
{
{
        if (last_task_used_math == current)
        if (last_task_used_math == current)
                return;
                return;
        if (last_task_used_math)
        if (last_task_used_math)
                /*
                /*
                 * Save current fp state into last_task_used_math->tss.fpe_save
                 * Save current fp state into last_task_used_math->tss.fpe_save
                 */
                 */
                fpe_save (&last_task_used_math->tss.fpstate.soft);
                fpe_save (&last_task_used_math->tss.fpstate.soft);
        last_task_used_math = current;
        last_task_used_math = current;
        if (current->used_math) {
        if (current->used_math) {
                /*
                /*
                 * Restore current fp state from current->tss.fpe_save
                 * Restore current fp state from current->tss.fpe_save
                 */
                 */
                fpe_restore (&current->tss.fpstate.soft);
                fpe_restore (&current->tss.fpstate.soft);
        } else {
        } else {
                /*
                /*
                 * initialise fp state
                 * initialise fp state
                 */
                 */
                fpe_restore (&init_task.tss.fpstate.soft);
                fpe_restore (&init_task.tss.fpstate.soft);
                current->used_math = 1;
                current->used_math = 1;
        }
        }
}
}
 
 
asmlinkage void arm_syscall (int no, struct pt_regs *regs)
asmlinkage void arm_syscall (int no, struct pt_regs *regs)
{
{
        switch (no) {
        switch (no) {
        case 0: /* branch through 0 */
        case 0: /* branch through 0 */
                printk ("[%d] %s: branch through zero\n", current->pid, current->comm);
                printk ("[%d] %s: branch through zero\n", current->pid, current->comm);
                force_sig (SIGILL, current);
                force_sig (SIGILL, current);
                if (user_mode(regs)) {
                if (user_mode(regs)) {
                        show_regs (regs);
                        show_regs (regs);
                        c_backtrace (regs->ARM_fp, processor_mode(regs));
                        c_backtrace (regs->ARM_fp, processor_mode(regs));
                }
                }
                die_if_kernel ("Oops", regs, 0, SIGILL);
                die_if_kernel ("Oops", regs, 0, SIGILL);
                break;
                break;
 
 
        case 1: /* SWI_BREAK_POINT */
        case 1: /* SWI_BREAK_POINT */
                regs->ARM_pc -= 4; /* Decrement PC by one instruction */
                regs->ARM_pc -= 4; /* Decrement PC by one instruction */
                ptrace_cancel_bpt (current);
                ptrace_cancel_bpt (current);
                force_sig (SIGTRAP, current);
                force_sig (SIGTRAP, current);
                break;
                break;
 
 
        default:
        default:
                printk ("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
                printk ("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
                force_sig (SIGILL, current);
                force_sig (SIGILL, current);
                if (user_mode(regs)) {
                if (user_mode(regs)) {
                        show_regs (regs);
                        show_regs (regs);
                        c_backtrace (regs->ARM_fp, processor_mode(regs));
                        c_backtrace (regs->ARM_fp, processor_mode(regs));
                }
                }
                die_if_kernel ("Oops", regs, no, SIGILL);
                die_if_kernel ("Oops", regs, no, SIGILL);
                break;
                break;
        }
        }
}
}
 
 
asmlinkage void deferred(int n, struct pt_regs *regs)
asmlinkage void deferred(int n, struct pt_regs *regs)
{
{
        printk ("[%d] %s: old system call %X\n", current->pid, current->comm, n);
        printk ("[%d] %s: old system call %X\n", current->pid, current->comm, n);
        show_regs (regs);
        show_regs (regs);
        force_sig (SIGILL, current);
        force_sig (SIGILL, current);
}
}
 
 
asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr)
asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr)
{
{
        printk ("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc);
        printk ("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc);
}
}
 
 
asmlinkage void arm_invalidptr (const char *function, int size)
asmlinkage void arm_invalidptr (const char *function, int size)
{
{
        printk ("Invalid pointer size in %s (PC=%p) size %d\n",
        printk ("Invalid pointer size in %s (PC=%p) size %d\n",
                function, __builtin_return_address(0), size);
                function, __builtin_return_address(0), size);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.