/*
***************************************************************************
*
* Datei:
*	  RSysSignalTrap.c
*
* Inhalt:
*
*      --- Globale Routinen ---
*
*    void HandleTrap ( int signal );
*    void InstallTrapHandlers ( void );
*    void RemoveTrapHandlers ( void );
*    void _traphandler ( long sig );
*
*      --- Lokale  Routinen ---
*
*    static void ( *_sigfuncs [_NUMSIG ]);
*    static void convert ( ULONG state , char *str );
*
* Bemerkungen:
*	  Verwaltung eines Traphandlers, um RSys wirklich (?) absturzsicher
*	  zu machen.
*
* Erstellungsdatum:
*	  07-Jul-93 	Rolf Böhme
*
* Änderungen:
*	  07-Jul-93 	Rolf Böhme	  Erstellung
*
***************************************************************************
*/

#include "RSys.h"

/*
#define SIG_BEGINSSP 		0
#define SIG_BEGINPC			1
#define SIG_BUSERROR 		2
#define SIG_ADDRERROR		3
#define SIG_ILLCOMM			4
#define SIG_DIVZERO			5
#define SIG_CHKERROR 		6
#define SIG_TRAPV 			7
#define SIG_VIOLPRIV 		8
#define SIG_TRACE 			9
#define SIG_LINEAEMUL		10
#define SIG_LINEFEMUL		11
#define SIG_NOTDEF			12
#define SIG_COPROPROT		13
#define SIG_FORMATERR		14
#define SIG_INTRFAIL 		15

#define SIG_MC_ILLCOND		48
#define SIG_MC_ILLRESULT	49
#define SIG_MC_DIVZERO		50
#define SIG_MC_UNDERFLOW	51
#define SIG_MC_OPERROR		52
#define SIG_MC_OVERFLOW 	53
#define SIG_MC_NANSIG		54
#define SIG_MC_NOTDEF		55
*/

static void (*_sigfuncs[_NUMSIG])(int);
int _trapexception(void);
int _initfpu(void);
void *_oldtrap, **_trapaddr;

static struct Task *tp;

char *TrapCPUMsg[] =
{
	"Begin of SSP (ISP by 680x0)",
	"Begin of PC",
	"Bus error",
	"Address error",
	"Illegal or unknown instruction",
	"Division by zero or arithmetic fault",
	"CHK and CHK2 affected",
	"TRAP or TRAPV reached",
	"Priviledge violation",
	"Trace error",
	"Line A Emulator, illegal Opcode by MC68000",
	"Line F Emulator, illegal Opcode by MC68000",
	"Error is reserved",
	"Coprocessor protocol error",
	"Format error by MC680x0",
	"Uninitialized Interrupt"
};

	/*
	 * convert() konvertiert eine 32Bit-Zahl in einen
	 * "Binärstring", also in einen String, der nur aus '0'
	 * und '1' besteht
	 */
static void
convert(ULONG state,char *str)
{
	register int bit;

	for( bit = 0; bit < 32; bit++ ) str[31-bit] = ((state & (1L<<bit)) ? '1' : '0');

	str[32] = STRINGEND;

   return;
}

	/*
	 * HandleTrap() ist die Funktion, die im Falle eines
	 * System traps aktiviert wird. Diese Routine ruft
	 * entweder den System debugger ROMWack auf, oder
	 * verursacht einen Kaltstart des Rechners, falls dies
	 * gewünscht wird. Installiert wird diese Routine
	 * mit der ANSI-Routine signal() des
	 * Aztec-C-Compilers
	 */
void
HandleTrap(int signal)
{
	int action;
	char exceptstr[33],signalstr[33],statestr[33];
	UBYTE *fmt = (UBYTE *)"Error signal: %s (%ld)\n"
								  "Exception   : %s (0x%08lX)\n"
								  "Task signal : %s (0x%08lX)\n"
								  "CPU Status  : %s (0x%08lX)\n"
								 "Trap data   : %08lX\n"
								 "Except data : %08lX\n";
	ULONG exc,sig,sta;
	APTR UserStack;

	UserStack = SuperState();

	exc = SetExcept(0L,0L);
	sig = SetSignal(0L,0L);
	sta = SetSR(0L,0L);

	UserState(UserStack);

	convert(exc,exceptstr);
	convert(sig,signalstr);
	convert(sta,statestr);

	if(IntuitionBase != NULL)
		 action = MyEasyRequest(NULL,
							(UBYTE *)NAME " *** Emergency trap failure message ***",
							(UBYTE *)"Continue|Terminate RSys|Call system debugger|Reboot system",
							fmt, TrapCPUMsg[signal], signal,
							exceptstr,exc,signalstr,sig,statestr,sta,
                     tp->tc_TrapData, tp->tc_ExceptData);
	else
	{
		action = -1;
      Printf(fmt,(ULONG)TrapCPUMsg[signal],signal,
						exceptstr,exc,signalstr,sig,statestr,sta,
					  tp->tc_TrapData, tp->tc_ExceptData);
	}

	switch(action)
	{
      case -1:
         exit(0);
         break;

		case 0:
			ColdReboot();
			break;

		case 1:
			break;

		case 2:
			CloseAll();
			break;

		case 3:
			Debug(0L);
			CloseAll();
			break;
	}

	return;
}

	/*
	 * InstallTrapHandlers() installiert einen Traphandler,
	 * der auf verschiedene Traps reagieren kann
	 */
void
InstallTrapHandlers(void)
{
	register int i;
	extern struct ExecBase *SysBase;

	tp = FindTask(NULL);

   Forbid();

	_trapaddr = (void *)&tp->tc_TrapCode;
	_oldtrap= tp->tc_TrapCode;

	tp->tc_TrapCode = (APTR)&_trapexception;

	if (SysBase->AttnFlags & AFF_68881) _initfpu();

	for(i = _FSTSIG; i <= _NUMSIG; i++) _sigfuncs[i] = HandleTrap;

   Permit();

	return;
}

void
RemoveTrapHandlers(void)
{
	register int i;

	Forbid();

	if (_trapaddr) *_trapaddr = _oldtrap;

	for(i = _FSTSIG; i <= _NUMSIG; i++) _sigfuncs[i] = NULL;

	Permit();

	return;
}

void
_traphandler(long sig)
{
	register void (*handler)(int);

	if ((handler = _sigfuncs[sig]) != NULL) (*handler)(sig);

	return;
}

