/*
|
/*
|
* linux/arch/i960/kernel/traps.c
|
* linux/arch/i960/kernel/traps.c
|
*
|
*
|
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu>
|
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu>
|
* Oregon Graduate Institute
|
* Oregon Graduate Institute
|
*
|
*
|
* Based on:
|
* Based on:
|
*
|
*
|
* linux/arch/m68k/kernel/traps.c
|
* linux/arch/m68k/kernel/traps.c
|
*
|
*
|
* Copyright (C) 1993, 1994 by Hamish Macdonald
|
* Copyright (C) 1993, 1994 by Hamish Macdonald
|
*
|
*
|
* This file is subject to the terms and conditions of the GNU General Public
|
* 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
|
* License. See the file COPYING in the main directory of this archive
|
* for more details.
|
* for more details.
|
*/
|
*/
|
|
|
/*
|
/*
|
* Sets up all exception vectors
|
* Sets up all exception vectors
|
*/
|
*/
|
|
|
#include <linux/config.h>
|
#include <linux/config.h>
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/signal.h>
|
#include <linux/signal.h>
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/mm.h>
|
#include <linux/mm.h>
|
#include <linux/types.h>
|
#include <linux/types.h>
|
#include <linux/a.out.h>
|
#include <linux/a.out.h>
|
#include <linux/user.h>
|
#include <linux/user.h>
|
#include <linux/string.h>
|
#include <linux/string.h>
|
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
|
|
#include <asm/setup.h>
|
#include <asm/setup.h>
|
#include <asm/system.h>
|
#include <asm/system.h>
|
#include <asm/segment.h>
|
#include <asm/segment.h>
|
#include <asm/traps.h>
|
#include <asm/traps.h>
|
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
#include <asm/machdep.h>
|
#include <asm/machdep.h>
|
#include <asm/i960jx.h>
|
#include <asm/i960jx.h>
|
#include <asm/mon960.h>
|
#include <asm/mon960.h>
|
|
|
/* set fault handlers in fault table, syscall table */
|
/* set fault handlers in fault table, syscall table */
|
void trap_init (void)
|
void trap_init (void)
|
{
|
{
|
int ii;
|
int ii;
|
unsigned long** prcb = (unsigned long**) get_prcbptr();
|
unsigned long** prcb = (unsigned long**) get_prcbptr();
|
unsigned long* syscall_tab = prcb[5];
|
unsigned long* syscall_tab = prcb[5];
|
unsigned long* fault_tab = prcb[0];
|
unsigned long* fault_tab = prcb[0];
|
extern void fault(void);
|
extern void fault(void);
|
|
|
/* faults use syscall table entry 1 (0 is for syscalls) */
|
/* faults use syscall table entry 1 (0 is for syscalls) */
|
syscall_tab[13] = ((unsigned long) fault) | 0x2;
|
syscall_tab[13] = ((unsigned long) fault) | 0x2;
|
for (ii=0; ii < 20; ii += 2) {
|
for (ii=0; ii < 20; ii += 2) {
|
/* leave trace trap to mon960; don't mess with reserved
|
/* leave trace trap to mon960; don't mess with reserved
|
* fields. */
|
* fields. */
|
if (ii == 2 || ii == 8 || ii == 12 || ii == 16 || ii == 18)
|
if (ii == 2 || ii == 8 || ii == 12 || ii == 16 || ii == 18)
|
continue;
|
continue;
|
|
|
fault_tab[ii] = (1 << 2) | 2; /* use syscall #1 */
|
fault_tab[ii] = (1 << 2) | 2; /* use syscall #1 */
|
fault_tab[ii+1] = 0x27f; /* magic number */
|
fault_tab[ii+1] = 0x27f; /* magic number */
|
}
|
}
|
}
|
}
|
|
|
void cfault(unsigned long* fault_rec, struct pt_regs* regs)
|
void cfault(unsigned long* fault_rec, struct pt_regs* regs)
|
{
|
{
|
int ii;
|
int ii;
|
unsigned long wd = fault_rec[2];
|
unsigned long wd = fault_rec[2];
|
unsigned char type = (wd >> 16);
|
unsigned char type = (wd >> 16);
|
unsigned char subtype = (unsigned char)(wd);
|
unsigned char subtype = (unsigned char)(wd);
|
char* nm = "<no fault>";
|
char* nm = "<no fault>";
|
int sig = 0;
|
int sig = 0;
|
|
|
switch(type) {
|
switch(type) {
|
case 3:
|
case 3:
|
/* arithmetic fault */
|
/* arithmetic fault */
|
nm = "arithmetic error";
|
nm = "arithmetic error";
|
sig = SIGFPE;
|
sig = SIGFPE;
|
break;
|
break;
|
case 5:
|
case 5:
|
/* constraint error? */
|
/* constraint error? */
|
nm = "constraint error";
|
nm = "constraint error";
|
break;
|
break;
|
case 2:
|
case 2:
|
switch(subtype) {
|
switch(subtype) {
|
case 1:
|
case 1:
|
nm = "illegal instruction";
|
nm = "illegal instruction";
|
sig = SIGILL;
|
sig = SIGILL;
|
break;
|
break;
|
case 2:
|
case 2:
|
nm = "accessed bad address";
|
nm = "accessed bad address";
|
sig = SIGSEGV;
|
sig = SIGSEGV;
|
break;
|
break;
|
case 3:
|
case 3:
|
nm = "unaligned";
|
nm = "unaligned";
|
sig = SIGBUS;
|
sig = SIGBUS;
|
break;
|
break;
|
case 4:
|
case 4:
|
nm = "invalid operand";
|
nm = "invalid operand";
|
sig = SIGILL;
|
sig = SIGILL;
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
case 7:
|
case 7:
|
nm = "protection fault";
|
nm = "protection fault";
|
sig = SIGILL;
|
sig = SIGILL;
|
break;
|
break;
|
case 1:
|
case 1:
|
nm = "trace fault";
|
nm = "trace fault";
|
/* bugger: we need to do better tracing */
|
/* bugger: we need to do better tracing */
|
break;
|
break;
|
|
|
case 0xa:
|
case 0xa:
|
nm = "type.mismatch";
|
nm = "type.mismatch";
|
sig = SIGILL;
|
sig = SIGILL;
|
break;
|
break;
|
}
|
}
|
|
|
if (user_mode(regs)) {
|
if (user_mode(regs)) {
|
extern void leave_kernel(struct pt_regs* regs);
|
extern void leave_kernel(struct pt_regs* regs);
|
if (sig) {
|
if (sig) {
|
current-> signal |= (1 << (sig -1));
|
current-> signal |= (1 << (sig -1));
|
}
|
}
|
leave_kernel(regs);
|
leave_kernel(regs);
|
return;
|
return;
|
}
|
}
|
|
|
cli();
|
cli();
|
/* Amuse the user. */
|
/* Amuse the user. */
|
printk("\n"
|
printk("\n"
|
" \\|/ ____ \\|/\n"
|
" \\|/ ____ \\|/\n"
|
" \"@'/ ,. \\`@\"\n"
|
" \"@'/ ,. \\`@\"\n"
|
" /_| \\__/ |_\\\n"
|
" /_| \\__/ |_\\\n"
|
" \\__U_/\n");
|
" \\__U_/\n");
|
|
|
printk("kernel fault: %s\n", nm);
|
printk("kernel fault: %s\n", nm);
|
for (ii=0; ii < 4; ii++)
|
for (ii=0; ii < 4; ii++)
|
printk("fault_rec: 0x%8x\n", fault_rec[ii]);
|
printk("fault_rec: 0x%8x\n", fault_rec[ii]);
|
|
|
show_regs(regs);
|
show_regs(regs);
|
stack_trace();
|
stack_trace();
|
|
|
#ifdef CONFIG_MON960
|
#ifdef CONFIG_MON960
|
system_break();
|
system_break();
|
#else
|
#else
|
for (;;) ;
|
for (;;) ;
|
#endif
|
#endif
|
}
|
}
|
|
|
void die_if_kernel(char* msg, struct pt_regs* regs, long err)
|
void die_if_kernel(char* msg, struct pt_regs* regs, long err)
|
{
|
{
|
if (user_mode(regs))
|
if (user_mode(regs))
|
return;
|
return;
|
|
|
/* Amuse the user. */
|
/* Amuse the user. */
|
printk(
|
printk(
|
" \\|/ ____ \\|/\n"
|
" \\|/ ____ \\|/\n"
|
" \"@'/ ,. \\`@\"\n"
|
" \"@'/ ,. \\`@\"\n"
|
" /_| \\__/ |_\\\n"
|
" /_| \\__/ |_\\\n"
|
" \\__U_/\n");
|
" \\__U_/\n");
|
|
|
printk("%s: %04lx\n", msg, err & 0xffff);
|
printk("%s: %04lx\n", msg, err & 0xffff);
|
show_regs(regs);
|
show_regs(regs);
|
stack_trace();
|
stack_trace();
|
|
|
cli();
|
cli();
|
for (;;) ;
|
for (;;) ;
|
}
|
}
|
|
|
/*
|
/*
|
* Print a quick n' dirty stack trace
|
* Print a quick n' dirty stack trace
|
*/
|
*/
|
struct frameo {
|
struct frameo {
|
struct frameo* pfp;
|
struct frameo* pfp;
|
unsigned long sp;
|
unsigned long sp;
|
void* rip;
|
void* rip;
|
};
|
};
|
|
|
void stack_trace(void)
|
void stack_trace(void)
|
{
|
{
|
unsigned long fp;
|
unsigned long fp;
|
|
|
__asm__ __volatile__ ("flushreg; mov pfp, %0" : "=r"(fp));
|
__asm__ __volatile__ ("flushreg; mov pfp, %0" : "=r"(fp));
|
stack_trace_from(fp);
|
stack_trace_from(fp);
|
}
|
}
|
|
|
void stack_trace_from(unsigned long ulfp)
|
void stack_trace_from(unsigned long ulfp)
|
{
|
{
|
int ii;
|
int ii;
|
long flags;
|
long flags;
|
struct frameo* fp = (struct frameo*) ulfp;
|
struct frameo* fp = (struct frameo*) ulfp;
|
|
|
save_flags(flags);
|
save_flags(flags);
|
cli();
|
cli();
|
printk("trace: fp == %p\n", fp);
|
printk("trace: fp == %p\n", fp);
|
for (ii=1; fp && (ii < 50); ii++, fp=fp->pfp) {
|
for (ii=1; fp && (ii < 50); ii++, fp=fp->pfp) {
|
unsigned long type = ((unsigned long)fp) & 0xf;
|
unsigned long type = ((unsigned long)fp) & 0xf;
|
fp = ((unsigned long)fp) & ~0xf;
|
fp = ((unsigned long)fp) & ~0xf;
|
|
|
switch(type) {
|
switch(type) {
|
case 1:
|
case 1:
|
printk("<f>");
|
printk("<f>");
|
break;
|
break;
|
|
|
case 2:
|
case 2:
|
case 3:
|
case 3:
|
printk("<s>");
|
printk("<s>");
|
break;
|
break;
|
case 7:
|
case 7:
|
printk("<i>");
|
printk("<i>");
|
}
|
}
|
printk("\t%8x", fp->rip);
|
printk("\t%8x", fp->rip);
|
if (! (ii & 0x3))
|
if (! (ii & 0x3))
|
printk("\n");
|
printk("\n");
|
}
|
}
|
|
|
if (!fp) {
|
if (!fp) {
|
printk("<bottom of stack>\n");
|
printk("<bottom of stack>\n");
|
}
|
}
|
|
|
printk("\n");
|
printk("\n");
|
restore_flags(flags);
|
restore_flags(flags);
|
}
|
}
|
|
|
void ckpt(int num, unsigned long val)
|
void ckpt(int num, unsigned long val)
|
{
|
{
|
|
|
printk("--------reached ckpt: %d\tval:0x%8x\n", num, val);
|
printk("--------reached ckpt: %d\tval:0x%8x\n", num, val);
|
#if 0
|
#if 0
|
struct pt_regs* regs;
|
struct pt_regs* regs;
|
asm("flushreg; subo 16, fp, %0" : "=r"(regs));
|
asm("flushreg; subo 16, fp, %0" : "=r"(regs));
|
|
|
show_regs(regs);
|
show_regs(regs);
|
#endif
|
#endif
|
printk("current stack trace:\n");
|
printk("current stack trace:\n");
|
stack_trace();
|
stack_trace();
|
printk("new stack strace:\n");
|
printk("new stack strace:\n");
|
stack_trace_from(val);
|
stack_trace_from(val);
|
printk("offset of ksp: 0x%8x\n",
|
printk("offset of ksp: 0x%8x\n",
|
&(((struct task_struct*)0)->kernel_stack_page));
|
&(((struct task_struct*)0)->kernel_stack_page));
|
printk("current ksp: 0x%8x\n", current->kernel_stack_page);
|
printk("current ksp: 0x%8x\n", current->kernel_stack_page);
|
}
|
}
|
|
|
void system_break(void)
|
void system_break(void)
|
{
|
{
|
long flags;
|
long flags;
|
|
|
save_flags(flags);
|
save_flags(flags);
|
cli();
|
cli();
|
mon_entry();
|
mon_entry();
|
restore_flags(flags);
|
restore_flags(flags);
|
}
|
}
|
|
|