diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-09-12 01:29:55 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-09-12 01:29:55 +0000 |
commit | 545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch) | |
tree | e9ce4bc598d06374bda906f18365984bf22a526a /arch/ppc/kernel/traps.c | |
parent | 4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (diff) |
Merge with Linux 2.1.55. More bugfixes and goodies from my private
CVS archive.
Diffstat (limited to 'arch/ppc/kernel/traps.c')
-rw-r--r-- | arch/ppc/kernel/traps.c | 109 |
1 files changed, 89 insertions, 20 deletions
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 84ce1c5ca..edfcb4d63 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -1,9 +1,15 @@ /* * linux/arch/ppc/kernel/traps.c * - * Copyright (C) 1995 Gary Thomas - * Adapted for PowerPC by Gary Thomas + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) */ /* @@ -24,9 +30,21 @@ #include <linux/config.h> #include <asm/pgtable.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/system.h> #include <asm/io.h> +#include <asm/processor.h> + +extern int fix_alignment(struct pt_regs *); +extern void bad_page_fault(struct pt_regs *, unsigned long); + +#ifdef CONFIG_XMON +extern int xmon_bpt(struct pt_regs *regs); +extern int xmon_sstep(struct pt_regs *regs); +extern void xmon(struct pt_regs *regs); +extern int xmon_iabr_match(struct pt_regs *regs); +extern void (*xmon_fault_handler)(struct pt_regs *regs); +#endif /* * Trap & Exception support @@ -43,40 +61,53 @@ _exception(int signr, struct pt_regs *regs) if (!user_mode(regs)) { show_regs(regs); - print_backtrace(regs->gpr[1]); - panic("Exception in kernel pc %x signal %d",regs->nip,signr); + print_backtrace((unsigned long *)regs->gpr[1]); +#ifdef CONFIG_XMON + xmon(regs); +#endif + panic("Exception in kernel pc %lx signal %d",regs->nip,signr); } force_sig(signr, current); } +void MachineCheckException(struct pt_regs *regs) { if ( !user_mode(regs) ) { +#ifdef CONFIG_XMON + if (xmon_fault_handler) { + xmon_fault_handler(regs); + return; + } +#endif printk("Machine check in kernel mode.\n"); printk("Caused by (from msr): "); - printk("regs %08x ",regs); + printk("regs %p ",regs); switch( regs->msr & 0x0000F000) { case (1<<12) : printk("Machine check signal - probably due to mm fault\n" "with mmu off\n"); - break; + break; case (1<<13) : printk("Transfer error ack signal\n"); - break; + break; case (1<<14) : printk("Data parity signal\n"); - break; + break; case (1<<15) : printk("Address parity signal\n"); - break; + break; default: printk("Unknown values in msr\n"); } show_regs(regs); - print_backtrace(regs->gpr[1]); - panic(""); + print_backtrace((unsigned long *)regs->gpr[1]); +#ifdef CONFIG_XMON + xmon(regs); +#endif + panic("machine check"); } _exception(SIGSEGV, regs); } @@ -105,33 +136,71 @@ RunModeException(struct pt_regs *regs) _exception(SIGTRAP, regs); } +void ProgramCheckException(struct pt_regs *regs) { - if (current->flags & PF_PTRACED) + if (regs->msr & 0x100000) { + /* IEEE FP exception */ + _exception(SIGFPE, regs); + } else if (regs->msr & 0x20000) { + /* trap exception */ +#ifdef CONFIG_XMON + if (xmon_bpt(regs)) + return; +#endif _exception(SIGTRAP, regs); - else + } else { _exception(SIGILL, regs); + } } +void SingleStepException(struct pt_regs *regs) { regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ +#ifdef CONFIG_XMON + if (xmon_sstep(regs)) + return; +#endif _exception(SIGTRAP, regs); } +void AlignmentException(struct pt_regs *regs) { + int fixed; + + if (last_task_used_math == current) + giveup_fpu(); + fixed = fix_alignment(regs); + if (fixed == 1) { + regs->nip += 4; /* skip over emulated instruction */ + return; + } + if (fixed == -EFAULT) { + /* fixed == -EFAULT means the operand address was bad */ + bad_page_fault(regs, regs->dar); + return; + } _exception(SIGBUS, regs); } +void +PromException(struct pt_regs *regs, int trap) +{ + regs->trap = trap; +#ifdef CONFIG_XMON + xmon(regs); +#endif + printk("Exception %lx in prom at PC: %lx, SR: %lx\n", + regs->trap, regs->nip, regs->msr); + /* probably should turn up the toes here */ +} + +void trace_syscall(struct pt_regs *regs) { - static int count; - printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n", + printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld\n", current, current->pid, regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3]); - if (++count == 20) - { - count = 0; - } } |