patch-2.4.21 linux-2.4.21/arch/parisc/kernel/traps.c
Next file: linux-2.4.21/arch/parisc/kernel/unaligned.c
Previous file: linux-2.4.21/arch/parisc/kernel/syscall.S
Back to the patch index
Back to the overall index
- Lines: 499
- Date:
2003-06-13 07:51:31.000000000 -0700
- Orig file:
linux-2.4.20/arch/parisc/kernel/traps.c
- Orig date:
2002-11-28 15:53:10.000000000 -0800
diff -urN linux-2.4.20/arch/parisc/kernel/traps.c linux-2.4.21/arch/parisc/kernel/traps.c
@@ -18,6 +18,7 @@
#include <linux/ptrace.h>
#include <linux/timer.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
@@ -34,17 +35,10 @@
#include <asm/atomic.h>
#include <asm/smp.h>
#include <asm/pdc.h>
+#include <asm/pdc_chassis.h>
#include "../math-emu/math-emu.h" /* for handle_fpe() */
-#ifdef CONFIG_KWDB
-#include <kdb/break.h> /* for BI2_KGDB_GDB */
-#include <kdb/kgdb_types.h> /* for __() */
-#include <kdb/save_state.h> /* for struct save_state */
-#include <kdb/kgdb_machine.h> /* for pt_regs_to_ssp and ssp_to_pt_regs */
-#include <kdb/trap.h> /* for I_BRK_INST */
-#endif /* CONFIG_KWDB */
-
#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
/* dumped to the console via printk) */
@@ -66,6 +60,99 @@
#define RFMT "%08lx"
#endif
+static int kstack_depth_to_print = 24;
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+#ifdef CONFIG_MODULES
+ int retval = 0;
+ struct module *mod;
+#endif
+ extern char _stext, _etext;
+
+ if (addr >= (unsigned long) &_stext &&
+ addr <= (unsigned long) &_etext)
+ return 1;
+
+#ifdef CONFIG_MODULES
+ for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+ /* mod_bound tests for addr being inside the vmalloc'ed
+ * module area. Of course it'd be better to test only
+ * for the .text subset... */
+ if (mod_bound(addr, 0, mod)) {
+ retval = 1;
+ break;
+ }
+ }
+ return retval;
+#endif
+}
+
+
+void show_trace(unsigned long * stack)
+{
+ unsigned long *startstack;
+ unsigned long addr;
+ int i;
+
+ startstack = (unsigned long *)((unsigned long)stack & ~(THREAD_SIZE - 1));
+ i = 1;
+ printk("Kernel addresses on the stack:\n");
+ while (stack >= startstack) {
+ addr = *stack--;
+ if (kernel_text_address(addr)) {
+ printk(" [<" RFMT ">] ", addr);
+ if ((i & 0x03) == 0)
+ printk("\n");
+ i++;
+ }
+ }
+ printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+ show_trace((unsigned long *)tsk->thread.regs.ksp);
+}
+
+void show_stack(unsigned long * sp)
+{
+ unsigned long *stack;
+ int i;
+
+ /*
+ * debugging aid: "show_stack(NULL);" prints the
+ * back trace for this cpu.
+ */
+ if (sp==NULL)
+ sp = (unsigned long*)&sp;
+
+ stack = sp;
+ printk("\n" KERN_CRIT "Stack Dump:\n");
+ printk(KERN_CRIT " " RFMT ": ", (unsigned long) stack);
+ for (i=0; i < kstack_depth_to_print; i++) {
+ if (((long) stack & (THREAD_SIZE-1)) == 0)
+ break;
+ if (i && ((i & 0x03) == 0))
+ printk("\n" KERN_CRIT " " RFMT ": ",
+ (unsigned long) stack);
+ printk(RFMT " ", *stack--);
+ }
+ printk("\n" KERN_CRIT "\n");
+ show_trace(sp);
+}
+
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+ show_stack(0);
+}
+
+
void show_regs(struct pt_regs *regs)
{
int i;
@@ -121,84 +208,6 @@
}
-static void dump_stack(unsigned long from, unsigned long to, int istackflag)
-{
- unsigned int *fromptr;
- unsigned int *toptr;
-
- fromptr = (unsigned int *)from;
- toptr = (unsigned int *)to;
-
- printk("\n");
- printk(KERN_CRIT "Dumping %sStack from 0x%p to 0x%p:\n",
- istackflag ? "Interrupt " : "",
- fromptr, toptr);
-
- while (fromptr < toptr) {
- printk(KERN_CRIT "%04lx %08x %08x %08x %08x %08x %08x %08x %08x\n",
- ((unsigned long)fromptr) & 0xffff,
- fromptr[0], fromptr[1], fromptr[2], fromptr[3],
- fromptr[4], fromptr[5], fromptr[6], fromptr[7]);
- fromptr += 8;
- }
-}
-
-
-void show_stack(struct pt_regs *regs)
-{
-#if 1
- /* If regs->sr[7] == 0, we are on a kernel stack */
- if (regs->sr[7] == 0) {
-
- unsigned long sp = regs->gr[30];
- unsigned long cr30;
- unsigned long cr31;
- unsigned long stack_start;
- struct pt_regs *int_regs;
-
- cr30 = mfctl(30);
- cr31 = mfctl(31);
- stack_start = sp & ~(ISTACK_SIZE - 1);
- if (stack_start == cr31) {
- /*
- * We are on the interrupt stack, get the stack
- * pointer from the first pt_regs structure on
- * the interrupt stack, so we can dump the task
- * stack first.
- */
-
- int_regs = (struct pt_regs *)cr31;
- sp = int_regs->gr[30];
- stack_start = sp & ~(INIT_TASK_SIZE - 1);
- if (stack_start != cr30) {
- printk(KERN_CRIT "WARNING! Interrupt-Stack pointer and cr30 do not correspond!\n");
- printk(KERN_CRIT "Dumping virtual address stack instead\n");
- dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
- } else {
- dump_stack(stack_start, sp, 0);
- };
-
- printk("\n\n" KERN_DEBUG "Registers at Interrupt:\n");
- show_regs(int_regs);
-
- /* Now dump the interrupt stack */
-
- sp = regs->gr[30];
- stack_start = sp & ~(ISTACK_SIZE - 1);
- dump_stack(stack_start,sp,1);
- }
- else
- {
- /* Stack Dump! */
- printk(KERN_CRIT "WARNING! Stack pointer and cr30 do not correspond!\n");
- printk(KERN_CRIT "Dumping virtual address stack instead\n");
- dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
- }
- }
-#endif
-}
-
-
void die_if_kernel(char *str, struct pt_regs *regs, long err)
{
if (user_mode(regs)) {
@@ -260,9 +269,6 @@
void handle_break(unsigned iir, struct pt_regs *regs)
{
struct siginfo si;
-#ifdef CONFIG_KWDB
- struct save_state ssp;
-#endif /* CONFIG_KWDB */
switch(iir) {
case 0x00:
@@ -285,26 +291,6 @@
handle_gdb_break(regs, TRAP_BRKPT);
break;
-#ifdef CONFIG_KWDB
- case KGDB_BREAK_INSN:
- mtctl(0, 15);
- pt_regs_to_ssp(regs, &ssp);
- kgdb_trap(I_BRK_INST, &ssp, 1);
- ssp_to_pt_regs(&ssp, regs);
- break;
-
- case KGDB_INIT_BREAK_INSN:
- mtctl(0, 15);
- pt_regs_to_ssp(regs, &ssp);
- kgdb_trap(I_BRK_INST, &ssp, 1);
- ssp_to_pt_regs(&ssp, regs);
-
- /* Advance pcoq to skip break */
- regs->iaoq[0] = regs->iaoq[1];
- regs->iaoq[1] += 4;
- break;
-#endif /* CONFIG_KWDB */
-
default:
#ifdef PRINT_USER_FAULTS
printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n",
@@ -335,20 +321,6 @@
void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
-#ifdef CONFIG_KWDB
-int debug_call (void)
-{
- printk (KERN_DEBUG "Debug call.\n");
- return 0;
-}
-
-int debug_call_leaf (void)
-{
- return 0;
-}
-#endif /* CONFIG_KWDB */
-
-
void transfer_pim_to_trap_frame(struct pt_regs *regs)
{
register int i;
@@ -425,7 +397,7 @@
/*
- * This routine handles page faults. It determines the address,
+ * This routine handles various exception codes. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
*/
@@ -444,10 +416,20 @@
if (!console_drivers)
pdc_console_restart();
- if (code == 1)
- transfer_pim_to_trap_frame(regs);
- show_stack(regs);
+ /* Not all switch paths will gutter the processor... */
+ switch(code){
+
+ case 1:
+ transfer_pim_to_trap_frame(regs);
+ break;
+
+ default:
+ /* Fall through */
+ break;
+ }
+
+ show_stack((unsigned long *)regs->gr[30]);
printk("\n");
printk(KERN_CRIT "%s: Code=%d regs=%p (Addr=" RFMT ")\n",
@@ -461,32 +443,34 @@
* system will shut down immediately right here. */
pdc_soft_power_button(0);
+ /* Gutter the processor... */
for(;;)
;
}
+
void handle_interruption(int code, struct pt_regs *regs)
{
unsigned long fault_address = 0;
unsigned long fault_space = 0;
struct siginfo si;
-#ifdef CONFIG_KWDB
- struct save_state ssp;
-#endif /* CONFIG_KWDB */
-
- if (code == 1)
- pdc_console_restart(); /* switch back to pdc if HPMC */
- else
- sti();
-#if 0
- printk(KERN_CRIT "Interruption # %d\n", code);
-#endif
+ /* HACK! jsm is going to fix this.
+ * entry.S will manage I-bit - only enable I-bit if it was
+ * enabled before we took the "trap".
+ */
+ if (code != 1)
+ local_irq_enable();
switch(code) {
case 1:
/* High-priority machine check (HPMC) */
+ pdc_console_restart(); /* switch back to pdc if HPMC */
+
+ /* set up a new led state on systems shipped with a LED State panel */
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_HPMC);
+
parisc_terminate("High Priority Machine Check (HPMC)",
regs, code, 0);
/* NOT REACHED */
@@ -506,6 +490,9 @@
case 5:
/* Low-priority machine check */
+
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC);
+
flush_all_caches();
cpu_lpmc(5, regs);
return;
@@ -554,6 +541,7 @@
die_if_kernel("Privileged register usage", regs, code);
si.si_code = ILL_PRVREG;
+ /* Fall thru */
give_sigill:
si.si_signo = SIGILL;
si.si_errno = 0;
@@ -561,17 +549,47 @@
force_sig_info(SIGILL, &si, current);
return;
+ case 12:
+ /* Overflow Trap, let the userland signal handler do the cleanup */
+ si.si_signo = SIGFPE;
+ si.si_code = FPE_INTOVF;
+ si.si_addr = (void *) regs->iaoq[0];
+ force_sig_info(SIGFPE, &si, current);
+ return;
+
+ case 13:
+ /* Conditional Trap
+ The condition succees in an instruction which traps on condition */
+ si.si_signo = SIGFPE;
+ /* Set to zero, and let the userspace app figure it out from
+ the insn pointed to by si_addr */
+ si.si_code = 0;
+ si.si_addr = (void *) regs->iaoq[0];
+ force_sig_info(SIGFPE, &si, current);
+ return;
+
case 14:
/* Assist Exception Trap, i.e. floating point exception. */
die_if_kernel("Floating point exception", regs, 0); /* quiet */
handle_fpe(regs);
return;
+ case 15:
+ /* Data TLB miss fault/Data page fault */
+ /* Fall thru */
+ case 16:
+ /* Non-access instruction TLB miss fault */
+ /* The instruction TLB entry needed for the target address of the FIC
+ is absent, and hardware can't find it, so we get to cleanup */
+ /* Fall thru */
case 17:
/* Non-access data TLB miss fault/Non-access data page fault */
/* TODO: Still need to add slow path emulation code here */
+ /* TODO: Understand what is meant by the TODO listed
+ above this one. (Carlos) */
fault_address = regs->ior;
- parisc_terminate("Non access data tlb fault!",regs,code,fault_address);
+ fault_space = regs->isr;
+ break;
case 18:
/* PCXS only -- later cpu's split this into types 26,27 & 28 */
@@ -581,9 +599,8 @@
return;
}
/* Fall Through */
-
- case 15: /* Data TLB miss fault/Data page fault */
- case 26: /* PCXL: Data memory access rights trap */
+ case 26:
+ /* PCXL: Data memory access rights trap */
fault_address = regs->ior;
fault_space = regs->isr;
break;
@@ -599,7 +616,6 @@
case 25:
/* Taken branch trap */
-#ifndef CONFIG_KWDB
regs->gr[0] &= ~PSW_T;
if (regs->iasq[0])
handle_gdb_break(regs, TRAP_BRANCH);
@@ -607,14 +623,6 @@
* run.
*/
return;
-#else
- /* Kernel debugger: */
- mtctl(0, 15);
- pt_regs_to_ssp(regs, &ssp);
- kgdb_trap(I_TAKEN_BR, &ssp, 1);
- ssp_to_pt_regs(&ssp, regs);
- break;
-#endif /* CONFIG_KWDB */
case 7:
/* Instruction access rights */
@@ -648,7 +656,6 @@
up_read(¤t->mm->mmap_sem);
}
/* Fall Through */
-
case 27:
/* Data memory protection ID trap */
die_if_kernel("Protection id trap", regs, code);
@@ -682,6 +689,9 @@
force_sig_info(SIGBUS, &si, current);
return;
}
+
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+
parisc_terminate("Unexpected interruption", regs, code, 0);
/* NOT REACHED */
}
@@ -710,24 +720,17 @@
* The kernel should never fault on its own address space.
*/
- if (fault_space == 0)
- parisc_terminate("Kernel Fault", regs, code, fault_address);
+ if (fault_space == 0) {
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+ parisc_terminate("Kernel Fault", regs, code, fault_address);
+ /** NOT REACHED **/
+ }
}
-#ifdef CONFIG_KWDB
- debug_call_leaf ();
-#endif /* CONFIG_KWDB */
-
do_page_fault(regs, code, fault_address);
}
-void show_trace_task(struct task_struct *tsk)
-{
- BUG();
-}
-
-
int __init check_ivt(void *iva)
{
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)