#include <asm/mmu_context.h>
#include <asm/watch.h>
#include <asm/types.h>
+#include <asm/stacktrace.h>
extern asmlinkage void handle_int(void);
extern asmlinkage void handle_tlbm(void);
extern asmlinkage void handle_sys(void);
extern asmlinkage void handle_bp(void);
extern asmlinkage void handle_ri(void);
+extern asmlinkage void handle_ri_rdhwr_vivt(void);
+extern asmlinkage void handle_ri_rdhwr(void);
extern asmlinkage void handle_cpu(void);
extern asmlinkage void handle_ov(void);
extern asmlinkage void handle_tr(void);
extern asmlinkage void handle_reserved(void);
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
- struct mips_fpu_struct *ctx);
+ struct mips_fpu_struct *ctx, int has_fpu);
void (*board_be_init)(void);
int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
}
#ifdef CONFIG_KALLSYMS
-static int raw_show_trace;
+int raw_show_trace;
static int __init set_raw_show_trace(char *str)
{
raw_show_trace = 1;
return 1;
}
__setup("raw_show_trace", set_raw_show_trace);
-
-extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
- unsigned long pc, unsigned long ra);
+#endif
static void show_backtrace(struct task_struct *task, struct pt_regs *regs)
{
printk("Call Trace:\n");
do {
print_ip_sym(pc);
- pc = unwind_stack(task, &sp, pc, ra);
- ra = 0;
+ pc = unwind_stack(task, &sp, pc, &ra);
} while (pc);
printk("\n");
}
-#else
-#define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]);
-#endif
/*
* This routine abuses get_user()/put_user() to reference pointers
show_backtrace(task, regs);
}
-static __always_inline void prepare_frametrace(struct pt_regs *regs)
-{
- __asm__ __volatile__(
- ".set push\n\t"
- ".set noat\n\t"
-#ifdef CONFIG_64BIT
- "1: dla $1, 1b\n\t"
- "sd $1, %0\n\t"
- "sd $29, %1\n\t"
- "sd $31, %2\n\t"
-#else
- "1: la $1, 1b\n\t"
- "sw $1, %0\n\t"
- "sw $29, %1\n\t"
- "sw $31, %2\n\t"
-#endif
- ".set pop\n\t"
- : "=m" (regs->cp0_epc),
- "=m" (regs->regs[29]), "=m" (regs->regs[31])
- : : "memory");
-}
-
void show_stack(struct task_struct *task, unsigned long *sp)
{
struct pt_regs regs;
{
struct pt_regs regs;
- /*
- * Remove any garbage that may be in regs (specially func
- * addresses) to avoid show_raw_backtrace() to report them
- */
- memset(®s, 0, sizeof(regs));
prepare_frametrace(®s);
show_backtrace(current, ®s);
}
force_sig(SIGBUS, current);
}
-static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
-{
- unsigned int __user *epc;
-
- epc = (unsigned int __user *) regs->cp0_epc +
- ((regs->cp0_cause & CAUSEF_BD) != 0);
- if (!get_user(*opcode, epc))
- return 0;
-
- force_sig(SIGSEGV, current);
- return 1;
-}
-
/*
* ll/sc emulation
*/
{
unsigned int opcode;
- if (unlikely(get_insn_opcode(regs, &opcode)))
- return -EFAULT;
+ if (get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+ goto out_sigsegv;
if ((opcode & OPCODE) == LL) {
simulate_ll(regs, opcode);
}
return -EFAULT; /* Strange things going on ... */
+
+out_sigsegv:
+ force_sig(SIGSEGV, current);
+ return -EFAULT;
}
/*
struct thread_info *ti = task_thread_info(current);
unsigned int opcode;
- if (unlikely(get_insn_opcode(regs, &opcode)))
- return -EFAULT;
+ if (get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+ goto out_sigsegv;
if (unlikely(compute_return_epc(regs)))
return -EFAULT;
/* Not ours. */
return -EFAULT;
+
+out_sigsegv:
+ force_sig(SIGSEGV, current);
+ return -EFAULT;
}
asmlinkage void do_ov(struct pt_regs *regs)
preempt_enable();
/* Run the emulator */
- sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu);
+ sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1);
preempt_disable();
unsigned int opcode, bcode;
siginfo_t info;
- die_if_kernel("Break instruction in kernel code", regs);
-
- if (get_insn_opcode(regs, &opcode))
- return;
+ if (get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+ goto out_sigsegv;
/*
* There is the ancient bug in the MIPS assemblers that the break
switch (bcode) {
case BRK_OVERFLOW << 10:
case BRK_DIVZERO << 10:
+ die_if_kernel("Break instruction in kernel code", regs);
if (bcode == (BRK_DIVZERO << 10))
info.si_code = FPE_INTDIV;
else
info.si_addr = (void __user *) regs->cp0_epc;
force_sig_info(SIGFPE, &info, current);
break;
+ case BRK_BUG:
+ die("Kernel bug detected", regs);
+ break;
default:
+ die_if_kernel("Break instruction in kernel code", regs);
force_sig(SIGTRAP, current);
}
+
+out_sigsegv:
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_tr(struct pt_regs *regs)
unsigned int opcode, tcode = 0;
siginfo_t info;
- die_if_kernel("Trap instruction in kernel code", regs);
-
- if (get_insn_opcode(regs, &opcode))
- return;
+ if (get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+ goto out_sigsegv;
/* Immediate versions don't provide a code. */
if (!(opcode & OPCODE))
switch (tcode) {
case BRK_OVERFLOW:
case BRK_DIVZERO:
+ die_if_kernel("Trap instruction in kernel code", regs);
if (tcode == BRK_DIVZERO)
info.si_code = FPE_INTDIV;
else
info.si_addr = (void __user *) regs->cp0_epc;
force_sig_info(SIGFPE, &info, current);
break;
+ case BRK_BUG:
+ die("Kernel bug detected", regs);
+ break;
default:
+ die_if_kernel("Trap instruction in kernel code", regs);
force_sig(SIGTRAP, current);
}
+
+out_sigsegv:
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_ri(struct pt_regs *regs)
set_used_math();
}
- preempt_enable();
-
- if (!cpu_has_fpu) {
- int sig = fpu_emulator_cop1Handler(regs,
- ¤t->thread.fpu);
+ if (cpu_has_fpu) {
+ preempt_enable();
+ } else {
+ int sig;
+ preempt_enable();
+ sig = fpu_emulator_cop1Handler(regs,
+ ¤t->thread.fpu, 0);
if (sig)
force_sig(sig, current);
#ifdef CONFIG_MIPS_MT_FPAFF
static void mips_srs_init(void)
{
shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
- printk(KERN_INFO "%d MIPSR2 register sets available\n",
+ printk(KERN_INFO "%ld MIPSR2 register sets available\n",
shadow_registers.sr_supported);
shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */
}
memcpy((void *)(uncached_ebase + offset), addr, size);
}
+static int __initdata rdhwr_noopt;
+static int __init set_rdhwr_noopt(char *str)
+{
+ rdhwr_noopt = 1;
+ return 1;
+}
+
+__setup("rdhwr_noopt", set_rdhwr_noopt);
+
void __init trap_init(void)
{
extern char except_vec3_generic, except_vec3_r4000;
set_except_vector(8, handle_sys);
set_except_vector(9, handle_bp);
- set_except_vector(10, handle_ri);
+ set_except_vector(10, rdhwr_noopt ? handle_ri :
+ (cpu_has_vtag_icache ?
+ handle_ri_rdhwr_vivt : handle_ri_rdhwr));
set_except_vector(11, handle_cpu);
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);