/*
|
/*
|
* linux/arch/m68knommu/kernel/traps.c
|
* linux/arch/m68knommu/kernel/traps.c
|
*
|
*
|
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
|
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
|
* Kenneth Albanowski <kjahds@kjahds.com>
|
* Kenneth Albanowski <kjahds@kjahds.com>
|
* The Silver Hammer Group, Ltd.
|
* The Silver Hammer Group, Ltd.
|
*
|
*
|
* (Blame me for the icky bits -- kja)
|
* (Blame me for the icky bits -- kja)
|
*
|
*
|
* 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
|
*
|
*
|
* 68040 fixes by Michael Rausch
|
* 68040 fixes by Michael Rausch
|
* 68040 fixes by Martin Apel
|
* 68040 fixes by Martin Apel
|
* 68060 fixes by Roman Hodek
|
* 68060 fixes by Roman Hodek
|
* 68060 fixes by Jesper Skov
|
* 68060 fixes by Jesper Skov
|
*
|
*
|
* 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.
|
*
|
*
|
* Feb/1999 - Greg Ungerer (gerg@moreton.com.au) changes to support ColdFire.
|
* Feb/1999 - Greg Ungerer (gerg@moreton.com.au) changes to support ColdFire.
|
*/
|
*/
|
|
|
/*
|
/*
|
* 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/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>
|
|
|
|
|
void trap_init (void)
|
void trap_init (void)
|
{
|
{
|
if (mach_trap_init)
|
if (mach_trap_init)
|
mach_trap_init();
|
mach_trap_init();
|
}
|
}
|
|
|
static inline void console_verbose(void)
|
static inline void console_verbose(void)
|
{
|
{
|
extern int console_loglevel;
|
extern int console_loglevel;
|
console_loglevel = 15;
|
console_loglevel = 15;
|
if (mach_debug_init)
|
if (mach_debug_init)
|
mach_debug_init();
|
mach_debug_init();
|
}
|
}
|
|
|
|
|
extern void die_if_kernel(char *,struct pt_regs *,int);
|
extern void die_if_kernel(char *,struct pt_regs *,int);
|
asmlinkage void trap_c(int vector, struct frame *fp);
|
asmlinkage void trap_c(int vector, struct frame *fp);
|
|
|
asmlinkage void buserr_c(struct frame *fp)
|
asmlinkage void buserr_c(struct frame *fp)
|
{
|
{
|
#if 1
|
#if 1
|
extern void dump(struct pt_regs *fp);
|
extern void dump(struct pt_regs *fp);
|
printk("%s(%d): BUSS ERROR TRAP\n", __FILE__, __LINE__);
|
printk("%s(%d): BUSS ERROR TRAP\n", __FILE__, __LINE__);
|
dump((struct pt_regs *) fp);
|
dump((struct pt_regs *) fp);
|
#endif
|
#endif
|
|
|
/* Only set esp0 if coming from user mode */
|
/* Only set esp0 if coming from user mode */
|
if (user_mode(&fp->ptregs)) {
|
if (user_mode(&fp->ptregs)) {
|
current->tss.esp0 = (unsigned long) fp;
|
current->tss.esp0 = (unsigned long) fp;
|
} else {
|
} else {
|
die_if_kernel("Kernel mode BUS error",(struct pt_regs *)fp,0);
|
die_if_kernel("Kernel mode BUS error",(struct pt_regs *)fp,0);
|
}
|
}
|
|
|
/* insert handler here */
|
/* insert handler here */
|
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
}
|
}
|
|
|
|
|
static int bad_super_trap_count = 0;
|
static int bad_super_trap_count = 0;
|
|
|
void bad_super_trap (int vector, struct frame *fp)
|
void bad_super_trap (int vector, struct frame *fp)
|
{
|
{
|
extern void dump(struct pt_regs *fp);
|
extern void dump(struct pt_regs *fp);
|
|
|
if (bad_super_trap_count++) {
|
if (bad_super_trap_count++) {
|
while(1);
|
while(1);
|
}
|
}
|
|
|
printk ("KERNEL: Bad trap from supervisor state, vector=%d\n", vector);
|
printk ("KERNEL: Bad trap from supervisor state, vector=%d\n", vector);
|
dump((struct pt_regs *) fp);
|
dump((struct pt_regs *) fp);
|
panic ("Trap from supervisor state");
|
panic ("Trap from supervisor state");
|
}
|
}
|
|
|
asmlinkage void trap_c(int vector, struct frame *fp)
|
asmlinkage void trap_c(int vector, struct frame *fp)
|
{
|
{
|
int sig;
|
int sig;
|
#if 0
|
#if 0
|
if ((fp->ptregs.sr & PS_S)
|
if ((fp->ptregs.sr & PS_S)
|
&& ((fp->ptregs.vector) >> 2) == VEC_TRACE
|
&& ((fp->ptregs.vector) >> 2) == VEC_TRACE
|
&& !(fp->ptregs.sr & PS_T)) {
|
&& !(fp->ptregs.sr & PS_T)) {
|
/* traced a trapping instruction */
|
/* traced a trapping instruction */
|
unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4;
|
unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4;
|
current->flags |= PF_DTRACE;
|
current->flags |= PF_DTRACE;
|
/* clear the trace bit */
|
/* clear the trace bit */
|
(*(unsigned short *)lp) &= ~PS_T;
|
(*(unsigned short *)lp) &= ~PS_T;
|
return;
|
return;
|
} else if (fp->ptregs.sr & PS_S) {
|
} else if (fp->ptregs.sr & PS_S) {
|
bad_super_trap(vector, fp);
|
bad_super_trap(vector, fp);
|
return;
|
return;
|
}
|
}
|
|
|
/* send the appropriate signal to the user program */
|
/* send the appropriate signal to the user program */
|
switch (vector) {
|
switch (vector) {
|
case VEC_ADDRERR:
|
case VEC_ADDRERR:
|
sig = SIGBUS;
|
sig = SIGBUS;
|
break;
|
break;
|
case VEC_BUSERR:
|
case VEC_BUSERR:
|
sig = SIGSEGV;
|
sig = SIGSEGV;
|
break;
|
break;
|
case VEC_ILLEGAL:
|
case VEC_ILLEGAL:
|
case VEC_PRIV:
|
case VEC_PRIV:
|
case VEC_LINE10:
|
case VEC_LINE10:
|
case VEC_LINE11:
|
case VEC_LINE11:
|
case VEC_COPROC:
|
case VEC_COPROC:
|
case VEC_TRAP2:
|
case VEC_TRAP2:
|
case VEC_TRAP3:
|
case VEC_TRAP3:
|
case VEC_TRAP4:
|
case VEC_TRAP4:
|
case VEC_TRAP5:
|
case VEC_TRAP5:
|
case VEC_TRAP6:
|
case VEC_TRAP6:
|
case VEC_TRAP7:
|
case VEC_TRAP7:
|
case VEC_TRAP8:
|
case VEC_TRAP8:
|
case VEC_TRAP9:
|
case VEC_TRAP9:
|
case VEC_TRAP10:
|
case VEC_TRAP10:
|
case VEC_TRAP11:
|
case VEC_TRAP11:
|
case VEC_TRAP12:
|
case VEC_TRAP12:
|
case VEC_TRAP13:
|
case VEC_TRAP13:
|
case VEC_TRAP14:
|
case VEC_TRAP14:
|
sig = SIGILL;
|
sig = SIGILL;
|
break;
|
break;
|
#ifndef NO_FPU
|
#ifndef NO_FPU
|
case VEC_FPBRUC:
|
case VEC_FPBRUC:
|
case VEC_FPIR:
|
case VEC_FPIR:
|
case VEC_FPDIVZ:
|
case VEC_FPDIVZ:
|
case VEC_FPUNDER:
|
case VEC_FPUNDER:
|
case VEC_FPOE:
|
case VEC_FPOE:
|
case VEC_FPOVER:
|
case VEC_FPOVER:
|
case VEC_FPNAN:
|
case VEC_FPNAN:
|
{
|
{
|
unsigned char fstate[216];
|
unsigned char fstate[216];
|
|
|
__asm__ __volatile__ ("fsave %0@" : : "a" (fstate) : "memory");
|
__asm__ __volatile__ ("fsave %0@" : : "a" (fstate) : "memory");
|
/* Set the exception pending bit in the 68882 idle frame */
|
/* Set the exception pending bit in the 68882 idle frame */
|
if (*(unsigned short *) fstate == 0x1f38)
|
if (*(unsigned short *) fstate == 0x1f38)
|
{
|
{
|
fstate[fstate[1]] |= 1 << 3;
|
fstate[fstate[1]] |= 1 << 3;
|
__asm__ __volatile__ ("frestore %0@" : : "a" (fstate));
|
__asm__ __volatile__ ("frestore %0@" : : "a" (fstate));
|
}
|
}
|
}
|
}
|
/* fall through */
|
/* fall through */
|
#endif
|
#endif
|
case VEC_ZERODIV:
|
case VEC_ZERODIV:
|
case VEC_TRAP:
|
case VEC_TRAP:
|
sig = SIGFPE;
|
sig = SIGFPE;
|
break;
|
break;
|
case VEC_TRACE: /* ptrace single step */
|
case VEC_TRACE: /* ptrace single step */
|
fp->ptregs.sr &= ~PS_T;
|
fp->ptregs.sr &= ~PS_T;
|
case VEC_TRAP15: /* breakpoint */
|
case VEC_TRAP15: /* breakpoint */
|
sig = SIGTRAP;
|
sig = SIGTRAP;
|
break;
|
break;
|
case VEC_TRAP1: /* gdbserver breakpoint */
|
case VEC_TRAP1: /* gdbserver breakpoint */
|
/* kwonsk: is this right? */
|
/* kwonsk: is this right? */
|
fp->ptregs.pc -= 2;
|
fp->ptregs.pc -= 2;
|
sig = SIGTRAP;
|
sig = SIGTRAP;
|
break;
|
break;
|
default:
|
default:
|
sig = SIGILL;
|
sig = SIGILL;
|
break;
|
break;
|
}
|
}
|
|
|
send_sig (sig, current, 1);
|
send_sig (sig, current, 1);
|
#endif
|
#endif
|
}
|
}
|
|
|
asmlinkage void set_esp0 (unsigned long ssp)
|
asmlinkage void set_esp0 (unsigned long ssp)
|
{
|
{
|
current->tss.esp0 = ssp;
|
current->tss.esp0 = ssp;
|
}
|
}
|
|
|
void die_if_kernel (char *str, struct pt_regs *fp, int nr)
|
void die_if_kernel (char *str, struct pt_regs *fp, int nr)
|
{
|
{
|
extern void dump(struct pt_regs *fp);
|
extern void dump(struct pt_regs *fp);
|
|
|
if (!(fp->sr & PS_S))
|
if (!(fp->sr & PS_S))
|
return;
|
return;
|
|
|
console_verbose();
|
console_verbose();
|
dump(fp);
|
dump(fp);
|
|
|
do_exit(SIGSEGV);
|
do_exit(SIGSEGV);
|
}
|
}
|
|
|