patch-2.3.48 linux/arch/mips/kernel/traps.c

Next file: linux/arch/mips/kernel/unaligned.c
Previous file: linux/arch/mips/kernel/time.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.20 1999/06/13 16:30:34 ralf Exp $
+/* $Id: traps.c,v 1.27 2000/01/16 01:29:05 ralf Exp $
  *
  * 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
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/spinlock.h>
 
 #include <asm/branch.h>
 #include <asm/cachectl.h>
@@ -24,11 +25,19 @@
 #include <asm/watch.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/mmu_context.h>
+
+extern int console_loglevel;
+
+static inline void console_silent(void)
+{
+	console_loglevel = 0;
+}
 
 static inline void console_verbose(void)
 {
-	extern int console_loglevel;
-	console_loglevel = 15;
+	if (console_loglevel)
+		console_loglevel = 15;
 }
 
 /*
@@ -40,12 +49,9 @@
 extern asmlinkage void deskstation_tyne_handle_int(void);
 extern asmlinkage void mips_magnum_4000_handle_int(void);
 
-extern asmlinkage void r4k_handle_mod(void);
-extern asmlinkage void r2300_handle_mod(void);
-extern asmlinkage void r4k_handle_tlbl(void);
-extern asmlinkage void r2300_handle_tlbl(void);
-extern asmlinkage void r4k_handle_tlbs(void);
-extern asmlinkage void r2300_handle_tlbs(void);
+extern asmlinkage void handle_mod(void);
+extern asmlinkage void handle_tlbl(void);
+extern asmlinkage void handle_tlbs(void);
 extern asmlinkage void handle_adel(void);
 extern asmlinkage void handle_ades(void);
 extern asmlinkage void handle_ibe(void);
@@ -77,6 +83,23 @@
  */
 #define MODULE_RANGE (8*1024*1024)
 
+#if !defined(CONFIG_CPU_HAS_LLSC)
+/*
+ * This stuff is needed for the userland ll-sc emulation for R2300
+ */
+void simulate_ll(struct pt_regs *regs, unsigned int opcode);
+void simulate_sc(struct pt_regs *regs, unsigned int opcode);
+
+#define OPCODE 0xfc000000
+#define BASE   0x03e00000
+#define RT     0x001f0000
+#define OFFSET 0x0000ffff
+#define LL     0xc0000000
+#define SC     0xd0000000
+
+#define DEBUG_LLSC
+#endif
+
 /*
  * This routine abuses get_user()/put_user() to reference pointers
  * with at least a bit of error checking ...
@@ -173,13 +196,17 @@
 	}
 }
 
-void die(const char * str, struct pt_regs * regs, unsigned long err)
-{
-	if (user_mode(regs))	/* Just return if in user mode.  */
-		return;
+spinlock_t die_lock;
 
+extern void __die(const char * str, struct pt_regs * regs, const char *where,
+                  unsigned long line)
+{
 	console_verbose();
-	printk("%s: %04lx\n", str, err & 0xffff);
+	spin_lock_irq(&die_lock);
+	printk("%s", str);
+	if (where)
+		printk(" in %s, line %ld", where, line);
+	printk(":\n");
 	show_regs(regs);
 	printk("Process %s (pid: %ld, stackpage=%08lx)\n",
 		current->comm, current->pid, (unsigned long) current);
@@ -187,13 +214,16 @@
 	show_trace((unsigned int *) regs->regs[29]);
 	show_code((unsigned int *) regs->cp0_epc);
 	printk("\n");
+while(1);
+	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
 }
 
-void die_if_kernel(const char * str, struct pt_regs * regs, unsigned long err)
+void __die_if_kernel(const char * str, struct pt_regs * regs, const char *where,
+	unsigned long line)
 {
 	if (!user_mode(regs))
-		die(str, regs, err);
+		__die(str, regs, where, line);
 }
 
 static void default_be_board_handler(struct pt_regs *regs)
@@ -201,8 +231,10 @@
 	/*
 	 * Assume it would be too dangerous to continue ...
 	 */
-	force_sig(SIGBUS, current);
+/* XXX */
+printk("Got Bus Error at %08x\n", (unsigned int)regs->cp0_epc);
 show_regs(regs); while(1);
+	force_sig(SIGBUS, current);
 }
 
 void do_ibe(struct pt_regs *regs)
@@ -249,6 +281,7 @@
 {
 	unsigned long pc;
 	unsigned int insn;
+	extern void simfp(void*);
 
 #ifdef CONFIG_MIPS_FPE_MODULE
 	if (fpe_handler != NULL) {
@@ -307,7 +340,6 @@
 	return 0;
 }
 
-
 void do_bp(struct pt_regs *regs)
 {
 	unsigned int opcode, bcode;
@@ -340,11 +372,115 @@
 	/*
 	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break
 	 * insns, even for break codes that indicate arithmetic failures.
-	 * Wiered ...)
+	 * Weird ...)
 	 */
 	force_sig(SIGTRAP, current);
 }
 
+#if !defined(CONFIG_CPU_HAS_LLSC)
+
+/*
+ * userland emulation for R2300 CPUs
+ * needed for the multithreading part of glibc
+ */
+void do_ri(struct pt_regs *regs)
+{
+	unsigned int opcode;
+
+	lock_kernel();
+	if (!get_insn_opcode(regs, &opcode)) {
+		if ((opcode & OPCODE) == LL)
+			simulate_ll(regs, opcode);
+		if ((opcode & OPCODE) == SC)
+			simulate_sc(regs, opcode);
+	} else {
+	printk("[%s:%ld] Illegal instruction at %08lx ra=%08lx\n",
+	       current->comm, current->pid, regs->cp0_epc, regs->regs[31]);
+	}
+	unlock_kernel();
+	if (compute_return_epc(regs))
+		return;
+	force_sig(SIGILL, current);
+}
+
+/*
+ * the ll_bit will be cleared by r2300_switch.S
+ */
+unsigned long ll_bit, *lladdr;
+ 
+void simulate_ll(struct pt_regs *regp, unsigned int opcode)
+{
+	unsigned long *addr, *vaddr;
+	long offset;
+ 
+	/*
+	 * analyse the ll instruction that just caused a ri exception
+	 * and put the referenced address to addr.
+	 */
+	/* sign extend offset */
+	offset = opcode & OFFSET;
+	if (offset & 0x00008000)
+		offset = -(offset & 0x00007fff);
+	else
+		offset = (offset & 0x00007fff);
+
+	vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset);
+
+#ifdef DEBUG_LLSC
+	printk("ll: vaddr = 0x%08x, reg = %d\n", (unsigned int)vaddr, (opcode & RT) >> 16);
+#endif
+
+	/*
+	 * TODO: compute physical address from vaddr
+	 */
+	panic("ll: emulation not yet finished!");
+
+	lladdr = addr;
+	ll_bit = 1;
+	regp->regs[(opcode & RT) >> 16] = *addr;
+}
+ 
+void simulate_sc(struct pt_regs *regp, unsigned int opcode)
+{
+	unsigned long *addr, *vaddr, reg;
+	long offset;
+
+	/*
+	 * analyse the sc instruction that just caused a ri exception
+	 * and put the referenced address to addr.
+	 */
+	/* sign extend offset */
+	offset = opcode & OFFSET;
+	if (offset & 0x00008000)
+		offset = -(offset & 0x00007fff);
+	else
+		offset = (offset & 0x00007fff);
+
+	vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset);
+	reg = (opcode & RT) >> 16;
+
+#ifdef DEBUG_LLSC
+	printk("sc: vaddr = 0x%08x, reg = %d\n", (unsigned int)vaddr, (unsigned int)reg);
+#endif
+
+	/*
+	 * TODO: compute physical address from vaddr
+	 */
+	panic("sc: emulation not yet finished!");
+
+	lladdr = addr;
+
+	if (ll_bit == 0) {
+		regp->regs[reg] = 0;
+		return;
+	}
+
+	*addr = regp->regs[reg];
+	regp->regs[reg] = 1;
+}
+
+#else /* MIPS 2 or higher */
+
 void do_ri(struct pt_regs *regs)
 {
 	lock_kernel();
@@ -356,9 +492,13 @@
 	force_sig(SIGILL, current);
 }
 
+#endif
+
 void do_cpu(struct pt_regs *regs)
 {
 	unsigned int cpid;
+	extern void lazy_fpu_switch(void*);
+	extern void init_fpu(void);
 
 	cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
 	if (cpid != 1)
@@ -369,10 +509,10 @@
 		return;
 
 	if (current->used_math) {		/* Using the FPU again.  */
-		r4xx0_lazy_fpu_switch(last_task_used_math);
+		lazy_fpu_switch(last_task_used_math);
 	} else {				/* First time FPU user.  */
 
-		r4xx0_init_fpu();
+		init_fpu();
 		current->used_math = 1;
 	}
 	last_task_used_math = current;
@@ -454,19 +594,6 @@
 	}
 }
 
-asmlinkage void (*save_fp_context)(struct sigcontext *sc);
-extern asmlinkage void r4k_save_fp_context(struct sigcontext *sc);
-extern asmlinkage void r2300_save_fp_context(struct sigcontext *sc);
-extern asmlinkage void r6000_save_fp_context(struct sigcontext *sc);
-
-asmlinkage void (*restore_fp_context)(struct sigcontext *sc);
-extern asmlinkage void r4k_restore_fp_context(struct sigcontext *sc);
-extern asmlinkage void r2300_restore_fp_context(struct sigcontext *sc);
-extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc);
-
-extern asmlinkage void *r4xx0_resume(void *last, void *next);
-extern asmlinkage void *r2300_resume(void *last, void *next);
-
 void __init trap_init(void)
 {
 	extern char except_vec0_nevada, except_vec0_r4000;
@@ -479,6 +606,9 @@
 	   mips_machtype == MACH_SNI_RM200_PCI)
 		EISA_bus = 1;
 
+	/* Some firmware leaves the BEV flag set, clear it.  */
+	set_cp0_status(ST0_BEV, 0);
+
 	/* Copy the generic exception handler code to it's final destination. */
 	memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80);
 	memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);
@@ -497,6 +627,29 @@
 	watch_init(mips_cputype);
 	setup_dedicated_int();
 
+	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 Data Bus Error/ Instruction Bus Errors are signaled
+	 * by external hardware.  Therefore these two expection have
+	 * board specific handlers.
+	 */
+	set_except_vector(6, handle_ibe);
+	set_except_vector(7, handle_dbe);
+	ibe_board_handler = default_be_board_handler;
+	dbe_board_handler = default_be_board_handler;
+
+	set_except_vector(8, handle_sys);
+	set_except_vector(9, handle_bp);
+	set_except_vector(10, handle_ri);
+	set_except_vector(11, handle_cpu);
+	set_except_vector(12, handle_ov);
+	set_except_vector(13, handle_tr);
+	set_except_vector(15, handle_fpe);
+
 	/*
 	 * Handling the following exceptions depends mostly of the cpu type
 	 */
@@ -540,42 +693,16 @@
 
 		if (vce_available) {
 			memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000,
-			       0x180);
+			       0x80);
 		} else {
 			memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic,
-			       0x100);
+			       0x80);
 		}
 
-		save_fp_context = r4k_save_fp_context;
-		restore_fp_context = r4k_restore_fp_context;
-		resume = r4xx0_resume;
-		set_except_vector(1, r4k_handle_mod);
-		set_except_vector(2, r4k_handle_tlbl);
-		set_except_vector(3, r4k_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);
-		set_except_vector(11, handle_cpu);
-		set_except_vector(12, handle_ov);
-		set_except_vector(13, handle_tr);
-		set_except_vector(15, handle_fpe);
 		break;
 
 	case CPU_R6000:
 	case CPU_R6000A:
-		save_fp_context = r6000_save_fp_context;
-		restore_fp_context = r6000_restore_fp_context;
 #if 0
 		/*
 		 * The R6000 is the only R-series CPU that features a machine
@@ -592,31 +719,7 @@
 	case CPU_R3000:
 	case CPU_R3000A:
 		memcpy((void *)KSEG0, &except_vec0_r2300, 0x80);
-		save_fp_context = r2300_save_fp_context;
-		restore_fp_context = r2300_restore_fp_context;
-		resume = r2300_resume;
-		set_except_vector(1, r2300_handle_mod);
-		set_except_vector(2, r2300_handle_tlbl);
-		set_except_vector(3, r2300_handle_tlbs);
-		set_except_vector(4, handle_adel);
-		set_except_vector(5, handle_ades);
-		/*
-		 * The Data Bus Error/ Instruction Bus Errors are signaled
-		 * by external hardware.  Therefore these two expection have
-		 * board specific handlers.
-		 */
-		set_except_vector(6, handle_ibe);
-		set_except_vector(7, handle_dbe);
-		ibe_board_handler = default_be_board_handler;
-		dbe_board_handler = default_be_board_handler;
-
-		set_except_vector(8, handle_sys);
-		set_except_vector(9, handle_bp);
-		set_except_vector(10, handle_ri);
-		set_except_vector(11, handle_cpu);
-		set_except_vector(12, handle_ov);
-		set_except_vector(13, handle_tr);
-		set_except_vector(15, handle_fpe);
+		memcpy((void *)(KSEG0 + 0x80), &except_vec3_generic, 0x80);
 		break;
 	case CPU_R3041:
 	case CPU_R3051:
@@ -634,4 +737,8 @@
 		panic("Unknown CPU type");
 	}
 	flush_icache_range(KSEG0, KSEG0 + 0x200);
+
+	atomic_inc(&init_mm.mm_count);	/* XXX  UP?  */
+	current->active_mm = &init_mm;
+	current_pgd = init_mm.pgd;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)