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
- Lines: 437
- Date:
Thu Feb 24 22:52:30 2000
- Orig file:
v2.3.47/linux/arch/mips/kernel/traps.c
- Orig date:
Tue Aug 31 17:29:12 1999
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)