patch-1.3.48 linux/arch/mips/kernel/traps.c
Next file: linux/arch/mips/kernel/tyne-c.c
Previous file: linux/arch/mips/kernel/tlb.S
Back to the patch index
Back to the overall index
- Lines: 517
- Date:
Wed Dec 13 12:39:44 1995
- Orig file:
v1.3.47/linux/arch/mips/kernel/traps.c
- Orig date:
Tue Jun 27 14:11:30 1995
diff -u --recursive --new-file v1.3.47/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
@@ -1,7 +1,9 @@
/*
* arch/mips/kernel/traps.c
*
- * Copyright (C) 1991, 1992 Linus Torvalds
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*/
/*
@@ -9,17 +11,23 @@
* state in 'asm.s'. Currently mostly a debugging-aid, will be extended
* to mainly kill the offending process (probably by giving it a signal,
* but possibly by killing it outright if necessary).
+ *
+ * FIXME: This is the place for a fpu emulator.
*/
#include <linux/head.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/string.h>
+#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
-#include <linux/config.h>
#include <linux/timer.h>
+#include <linux/mm.h>
+#include <asm/vector.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
@@ -32,18 +40,15 @@
console_loglevel = 15;
}
-#define get_seg_byte(seg,addr) ({ \
-register unsigned char __res; \
-__res = get_user_byte(addr); \
-__res;})
-
-#define get_seg_long(seg,addr) ({ \
-register unsigned long __res; \
-__res = get_user_word(addr); \
-__res;})
-
-extern asmlinkage void deskstation_tyne_handle_int(void);
+/*
+ * Machine specific interrupt handlers
+ */
extern asmlinkage void acer_pica_61_handle_int(void);
+extern asmlinkage void decstation_handle_int(void);
+extern asmlinkage void deskstation_rpc44_handle_int(void);
+extern asmlinkage void deskstation_tyne_handle_int(void);
+extern asmlinkage void mips_magnum_4000_handle_int(void);
+
extern asmlinkage void handle_mod(void);
extern asmlinkage void handle_tlbl(void);
extern asmlinkage void handle_tlbs(void);
@@ -63,90 +68,60 @@
extern asmlinkage void handle_watch(void);
extern asmlinkage void handle_reserved(void);
-char *cpu_names[] = CPU_NAMES;
+static char *cpu_names[] = CPU_NAMES;
+
+unsigned long page_colour_mask;
int kstack_depth_to_print = 24;
/*
- * These constants are for searching for possible module text
- * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
+ * These constant is for searching for possible module text segments.
+ * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
*/
-#define VMALLOC_OFFSET (8*1024*1024)
#define MODULE_RANGE (8*1024*1024)
void die_if_kernel(char * str, struct pt_regs * regs, long err)
{
- int i;
- unsigned long *sp, *pc;
- unsigned long *stack, addr, module_start, module_end;
- extern char start_kernel, etext;
+ int i;
+ int *stack;
+ u32 *sp, *pc, addr, module_start, module_end;
+ extern char start_kernel, _etext;
if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0)
return;
- sp = (unsigned long *)regs->reg29;
- pc = (unsigned long *)regs->cp0_epc;
+ sp = (u32 *)regs->reg29;
+ pc = (u32 *)regs->cp0_epc;
console_verbose();
printk("%s: %08lx\n", str, err );
- /*
- * Saved main processor registers
- */
- printk("at : %08lx\n", regs->reg1);
- printk("v0 : %08lx %08lx\n", regs->reg2, regs->reg3);
- printk("a0 : %08lx %08lx %08lx %08lx\n",
- regs->reg4, regs->reg5, regs->reg6, regs->reg7);
- printk("t0 : %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg8, regs->reg9, regs->reg10, regs->reg11, regs->reg12);
- printk("t5 : %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg13, regs->reg14, regs->reg15, regs->reg24, regs->reg25);
- printk("s0 : %08lx %08lx %08lx %08lx\n",
- regs->reg16, regs->reg17, regs->reg18, regs->reg19);
- printk("s4 : %08lx %08lx %08lx %08lx\n",
- regs->reg20, regs->reg21, regs->reg22, regs->reg23);
- printk("gp : %08lx\n", regs->reg28);
- printk("sp : %08lx\n", regs->reg29);
- printk("fp/s8: %08lx\n", regs->reg30);
- printk("ra : %08lx\n", regs->reg31);
-
- /*
- * Saved cp0 registers
- */
- printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n",
- regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
-
- /*
- * Some goodies...
- */
- printk("Int : %ld\n", regs->interrupt);
+ show_regs(regs);
/*
* Dump the stack
*/
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
+ if (STACK_MAGIC != *(u32 *)current->kernel_stack_page)
printk("Corrupted stack page\n");
- printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 0xffff & i,
- current->kernel_stack_page);
+ printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
+ current->comm, current->pid, current->kernel_stack_page);
for(i=0;i<5;i++)
- printk("%08lx ", *sp++);
- stack = (unsigned long *) sp;
+ printk("%08x ", *sp++);
+ stack = (int *) sp;
for(i=0; i < kstack_depth_to_print; i++) {
- if (((long) stack & 4095) == 0)
+ if (((u32) stack & (PAGE_SIZE -1)) == 0)
break;
if (i && ((i % 8) == 0))
printk("\n ");
- printk("%08lx ", get_seg_long(ss,stack++));
+ printk("%08lx ", get_user(stack++));
}
printk("\nCall Trace: ");
- stack = (unsigned long *) sp;
+ stack = (int *)sp;
i = 1;
- module_start = ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
+ module_start = VMALLOC_START;
module_end = module_start + MODULE_RANGE;
- while (((long) stack & 4095) != 0) {
- addr = get_seg_long(ss, stack++);
+ while (((u32)stack & (PAGE_SIZE -1)) != 0) {
+ addr = get_user(stack++);
/*
* If the address is either in the text segment of the
* kernel, or in the region which contains vmalloc'ed
@@ -155,103 +130,159 @@
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
- if (((addr >= (unsigned long) &start_kernel) &&
- (addr <= (unsigned long) &etext)) ||
+ if (((addr >= (u32) &start_kernel) &&
+ (addr <= (u32) &_etext)) ||
((addr >= module_start) && (addr <= module_end))) {
if (i && ((i % 8) == 0))
printk("\n ");
- printk("%08lx ", addr);
+ printk("%08x ", addr);
i++;
}
}
printk("\nCode : ");
- for(i=0;i<5;i++)
- printk("%08lx ", *pc++);
- printk("\n");
+ if ((!verify_area(VERIFY_READ, pc, 5 * sizeof(*pc)) ||
+ KSEGX(pc) == KSEG0 ||
+ KSEGX(pc) == KSEG1) &&
+ (((unsigned long) pc & 3) == 0))
+ {
+ for(i=0;i<5;i++)
+ printk("%08x ", *pc++);
+ printk("\n");
+ }
+ else
+ printk("(Bad address in epc)\n");
+while(1);
do_exit(SIGSEGV);
}
+static void
+fix_ade(struct pt_regs *regs, int write)
+{
+ printk("Received address error (ade%c)\n", write ? 's' : 'l');
+ panic("Fixing address errors not implemented yet");
+}
+
void do_adel(struct pt_regs *regs)
{
+ if(current->tss.mflags & MF_FIXADE)
+ {
+ fix_ade(regs, 0);
+ return;
+ }
+ show_regs(regs);
+while(1);
+ dump_tlb_nonwired();
send_sig(SIGSEGV, current, 1);
}
void do_ades(struct pt_regs *regs)
{
+ unsigned long pc = regs->cp0_epc;
+ int i;
+
+ if(current->tss.mflags & MF_FIXADE)
+ {
+ fix_ade(regs, 1);
+ return;
+ }
+while(1);
+ for(i=0; i<NR_TASKS;i++)
+ if(task[i] && task[i]->pid >= 2)
+ {
+ printk("Process %d\n", task[i]->pid);
+ dump_list_process(task[i], pc);
+ }
+ show_regs(regs);
+ dump_tlb_nonwired();
send_sig(SIGSEGV, current, 1);
}
+/*
+ * The ibe/dbe exceptions are signaled by onboard hardware and should get
+ * a board specific handlers to get maximum available information. Bus
+ * errors are always symptom of hardware malfunction or a kernel error.
+ *
+ * FIXME: Linux/68k sends a SIGSEGV for a buserror which seems to be wrong.
+ * This is certainly wrong. Actually, all hardware errors (ades,adel,ibe,dbe)
+ * are bus errors and therefor should send a SIGBUS! (Andy)
+ */
void do_ibe(struct pt_regs *regs)
{
- send_sig(SIGSEGV, current, 1);
+show_regs(regs);
+while(1);
+ send_sig(SIGBUS, current, 1);
}
void do_dbe(struct pt_regs *regs)
{
- send_sig(SIGSEGV, current, 1);
+show_regs(regs);
+while(1);
+ send_sig(SIGBUS, current, 1);
}
void do_ov(struct pt_regs *regs)
{
+show_regs(regs);
+while(1);
send_sig(SIGFPE, current, 1);
}
void do_fpe(struct pt_regs *regs)
{
- /*
- * FIXME: This is the place for a fpu emulator. Not written
- * yet and the demand seems to be quite low.
- */
- printk("Caught FPE exception at %lx.\n", regs->cp0_epc);
+show_regs(regs);
+while(1);
send_sig(SIGFPE, current, 1);
}
void do_bp(struct pt_regs *regs)
{
+show_regs(regs);
+while(1);
send_sig(SIGILL, current, 1);
}
void do_tr(struct pt_regs *regs)
{
+show_regs(regs);
+while(1);
send_sig(SIGILL, current, 1);
}
void do_ri(struct pt_regs *regs)
{
+ int i;
+
+ for(i=0; i<NR_TASKS;i++)
+ if(task[i] && task[i]->pid >= 2)
+ {
+ printk("Process %d\n", task[i]->pid);
+ dump_list_process(task[i], 0x7ffff000);
+ }
+ show_regs(regs);
+while(1);
send_sig(SIGILL, current, 1);
}
void do_cpu(struct pt_regs *regs)
{
- unsigned long pc;
- unsigned int insn;
+ unsigned int cpid;
- /*
- * Check whether this was a cp1 instruction
- */
- pc = regs->cp0_epc;
- if (regs->cp0_cause & (1<<31))
- pc += 4;
- insn = *(unsigned int *)pc;
- insn &= 0xfc000000;
- switch(insn) {
- case 0x44000000:
- case 0xc4000000:
- case 0xe4000000:
- printk("CP1 instruction - enabling cp1.\n");
- regs->cp0_status |= ST0_CU1;
- /*
- * No need to handle branch delay slots
- */
- break;
- default:
- /*
- * This wasn't a cp1 instruction and therefore illegal.
- * Default is to kill the process.
- */
- send_sig(SIGILL, current, 1);
- }
+ cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
+ switch(cpid)
+ {
+ case 1:
+ regs->cp0_status |= ST0_CU1;
+ break;
+ case 0:
+ /*
+ * CPU for cp0 can only happen in user mode
+ */
+ case 2:
+ case 3:
+ send_sig(SIGILL, current, 1);
+ break;
+ }
}
void do_vcei(struct pt_regs *regs)
@@ -274,10 +305,6 @@
void do_watch(struct pt_regs *regs)
{
- /*
- * Only possible on R4[04]00. No way to handle this because
- * I don't have such a cpu.
- */
panic("Caught WATCH exception - can't handle yet\n");
}
@@ -285,7 +312,7 @@
{
/*
* Game over - no way to handle this if it ever occurs.
- * Most probably caused by a new unknown cpu type or a
+ * Most probably caused by a new unknown cpu type or
* after another deadly hard/software error.
*/
panic("Caught reserved exception - can't handle.\n");
@@ -293,12 +320,11 @@
void trap_init(void)
{
- int i;
+ unsigned long i;
+ void watch_set(unsigned long, unsigned long);
- /*
- * FIXME: Mips Magnum R4000 has an EISA bus!
- */
- EISA_bus = 0;
+ if(boot_info.machtype == MACH_MIPS_MAGNUM_4000)
+ EISA_bus = 1;
/*
* Setup default vectors
@@ -310,30 +336,49 @@
* Handling the following exceptions depends mostly of the cpu type
*/
switch(boot_info.cputype) {
+ /*
+ * The R10000 is in most aspects similar to the R4400. It however
+ * should get some special optimizations.
+ */
+ case CPU_R10000:
+ write_32bit_cp0_register(CP0_FRAMEMASK, 0);
+ set_cp0_status(ST0_XX, ST0_XX);
+ page_colour_mask = 0x3000;
+ panic("CPU too expensive - making holiday in the ANDES!");
+ break;
case CPU_R4000MC:
case CPU_R4400MC:
case CPU_R4000SC:
case CPU_R4400SC:
/*
- * Handlers not implemented yet
+ * Handlers not implemented yet. If should ever be used -
+ * otherwise it's a bug in the Linux/MIPS kernel, anyway.
*/
set_except_vector(14, handle_vcei);
set_except_vector(31, handle_vced);
case CPU_R4000PC:
case CPU_R4400PC:
+ case CPU_R4200:
+ /* case CPU_R4300: */
/*
- * Handler not implemented yet
+ * Use watch exception to trap on access to address zero
*/
set_except_vector(23, handle_watch);
- case CPU_R4200:
+ watch_set(KSEG0, 3);
case CPU_R4600:
set_except_vector(1, handle_mod);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);
set_except_vector(4, handle_adel);
set_except_vector(5, handle_ades);
+ /*
+ * The following two are signaled by onboard hardware and
+ * should get board specific handlers to get maximum
+ * available information.
+ */
set_except_vector(6, handle_ibe);
set_except_vector(7, handle_dbe);
+
set_except_vector(8, handle_sys);
set_except_vector(9, handle_bp);
set_except_vector(10, handle_ri);
@@ -341,6 +386,15 @@
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);
set_except_vector(15, handle_fpe);
+
+ /*
+ * Compute mask for page_colour(). This is based on the
+ * size of the data cache. Does the size of the icache
+ * need to be accounted for?
+ */
+ i = read_32bit_cp0_register(CP0_CONFIG);
+ i = (i >> 26) & 7;
+ page_colour_mask = 1 << (12 + i);
break;
case CPU_R2000:
case CPU_R3000:
@@ -353,27 +407,18 @@
case CPU_R6000:
case CPU_R6000A:
case CPU_R8000:
- case CPU_R10000:
printk("Detected unsupported CPU type %s.\n",
- cpu_names[boot_info.cputype]);
+ cpu_names[boot_info.cputype]);
panic("Can't handle CPU\n");
break;
+
case CPU_UNKNOWN:
default:
- panic("Unknown type of CPU");
- }
+ panic("Unknown CPU type");
+ }
/*
- * The interrupt handler depends of both type of the board and cpu
+ * The interrupt handler mostly depends of the board type.
*/
- switch(boot_info.machtype) {
- case MACH_DESKSTATION_TYNE:
- set_except_vector(0, deskstation_tyne_handle_int);
- break;
- case MACH_ACER_PICA_61:
- set_except_vector(0, acer_pica_61_handle_int);
- break;
- default:
- panic("Unknown machine type");
- }
+ set_except_vector(0, feature->handle_int);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this