diff options
author | Harald Koerfgen <hkoerfg@web.de> | 1999-07-26 19:42:38 +0000 |
---|---|---|
committer | Harald Koerfgen <hkoerfg@web.de> | 1999-07-26 19:42:38 +0000 |
commit | 14ab59aa8aba8687dc957c2186e115ac0b8ab542 (patch) | |
tree | c2eb55db21b6b46ddd983e2d40196fa61f19b64c /arch/mips/kernel/traps.c | |
parent | 552f7f2f262b8ea12edc36f9a260b068bd10f423 (diff) |
The remaining R3000 changes. From now on the CVS will be R3000 aware. R3000 Indigo anyone? :-)
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 153 |
1 files changed, 149 insertions, 4 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 757fbafc2..3cca8acb1 100644 --- a/arch/mips/kernel/traps.c +++ b/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.21 1999/06/23 22:15:57 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 @@ -60,6 +60,15 @@ extern asmlinkage void handle_fpe(void); extern asmlinkage void handle_watch(void); extern asmlinkage void handle_reserved(void); +extern asmlinkage void r4xx0_lazy_fpu_switch(struct task_struct *); +extern asmlinkage void r4xx0_init_fpu(void); +extern asmlinkage void r4xx0_save_fp(struct sigcontext *); +extern asmlinkage void r2300_lazy_fpu_switch(struct task_struct *); +extern asmlinkage void r2300_init_fpu(void); +extern asmlinkage void r2300_save_fp(struct sigcontext *); + +extern asmlinkage void simfp(unsigned int); + static char *cpu_names[] = CPU_NAMES; char watch_available = 0; @@ -69,6 +78,10 @@ char vce_available = 0; void (*ibe_board_handler)(struct pt_regs *regs); void (*dbe_board_handler)(struct pt_regs *regs); +static void (*lazy_fpu_switch)(struct task_struct *); +static void (*init_fpu)(void); +void (*save_fp)(struct sigcontext *); + int kstack_depth_to_print = 24; /* @@ -77,6 +90,23 @@ int kstack_depth_to_print = 24; */ #define MODULE_RANGE (8*1024*1024) +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) +/* + * 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 ... @@ -201,8 +231,10 @@ static void default_be_board_handler(struct pt_regs *regs) /* * 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) @@ -345,6 +377,110 @@ void do_tr(struct pt_regs *regs) force_sig(SIGTRAP, current); } +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) + +/* + * 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,6 +492,8 @@ void do_ri(struct pt_regs *regs) force_sig(SIGILL, current); } +#endif + void do_cpu(struct pt_regs *regs) { unsigned int cpid; @@ -369,10 +507,10 @@ void do_cpu(struct pt_regs *regs) 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; @@ -548,6 +686,9 @@ __initfunc(void trap_init(void)) save_fp_context = r4k_save_fp_context; restore_fp_context = r4k_restore_fp_context; + lazy_fpu_switch = r4xx0_lazy_fpu_switch; + init_fpu = r4xx0_init_fpu; + save_fp = r4xx0_save_fp; resume = r4xx0_resume; set_except_vector(1, r4k_handle_mod); set_except_vector(2, r4k_handle_tlbl); @@ -592,8 +733,12 @@ __initfunc(void trap_init(void)) case CPU_R3000: case CPU_R3000A: memcpy((void *)KSEG0, &except_vec0_r2300, 0x80); + memcpy((void *)(KSEG0 + 0x80), &except_vec3_generic, 0x80); save_fp_context = r2300_save_fp_context; restore_fp_context = r2300_restore_fp_context; + lazy_fpu_switch = r2300_lazy_fpu_switch; + init_fpu = r2300_init_fpu; + save_fp = r2300_save_fp; resume = r2300_resume; set_except_vector(1, r2300_handle_mod); set_except_vector(2, r2300_handle_tlbl); |