/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1991 by John E. Lloyd.				    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#ifdef VXWORKS_CFG

/* support for handling exceptions in the VxWorks RCI control task */

#include <vxWorks.h>
#include <stdioLib.h>
#include <taskLib.h>
#include <signal.h>
#include <excLib.h>

#include "../h/cdefs.h"
#include "crashinfo.h"

CRASHINFO vxwCrashInfo;
static int crashSig;

extern int rciCtrlTaskId;
extern _rciTaskSuspendHook();

#if 0 

crashHandler(sig, code, ctx)
int sig, code;
SIGCONTEXT *ctx;
{
	extern int rciPlanTaskId;
	EXC_INFO *excInfo;
	CRASHINFO *ci;

#ifdef VXWORKS_V5
	excInfo = &(taskTcb(rciCtrlTaskId)->excInfo);
#else
	excInfo = &(taskTcbX(rciCtrlTaskId)->excInfo);
#endif
	ci = &vxwCrashInfo;

	ci->pc = (int)excInfo->pc;
	ci->npc = 0;
	ci->psr = excInfo->statusReg;
	   
	switch (sig)
	 { case SIGSEGV:
	    { ci->type = CI_MEMFAULT;
	      ci->un.memfault.addr = excInfo->accessAddr;
	      ci->un.memfault.be = 0; /* not available */
	      break;
	    }
	   case SIGBUS:
	    { ci->type = CI_MEMFAULT;
	      ci->un.memfault.addr = excInfo->accessAddr;
	      ci->un.memfault.be = 0; /* not available */
	      break;
	    }
	   case SIGILL:
	    { ci->type = CI_ILLINST;
	      switch (code)
	       { case ILL_PRIVVIO_FAULT:
		    ci->un.subtype = CI_II_PRIV;
		    break;
		 case ILL_ILLINSTR_FAULT:
		    ci->un.subtype = CI_II_UNIMP;
		    break;
		 case ILL_COPROCERR_FAULT:
		    ci->un.subtype = CI_II_COPROT;
		    break;
	       }
	      break;
	    }
	   case SIGFPE:
	    { ci->type = CI_ARITHTRAP; /* NOTE: might be changed below */
	      switch (code)
	       { case FPE_INTDIV_TRAP:
		    ci->un.subtype = CI_AT_IDIVZ;
		    break;
		 case FPE_CHKINST_TRAP:
		    ci->un.subtype = CI_AT_BOUNDS;
		    break;
		 case FPE_TRAPV_TRAP:
		    ci->un.subtype = CI_AT_OVERFTRAP;
		    break;
		 case FPE_FLTBSUN_TRAP:
		    ci->type = CI_ILLINST;
		    ci->un.subtype = CI_II_COPROT;
		    break;
		 case FPE_FLTINEX_TRAP:
		    ci->un.subtype = CI_AT_FINEXACT;
		    break;
		 case FPE_FLTDIV_TRAP:
		    ci->un.subtype = CI_AT_FDIVZ;
		    break;
		 case FPE_FLTUND_TRAP:
		    ci->un.subtype = CI_AT_FUNDERF;
		    break;
		 case FPE_FLTOPERR_TRAP:
		    ci->un.subtype = CI_AT_FOPERAND;
		    break;
		 case FPE_FLTOVF_TRAP:
		    ci->un.subtype = CI_AT_FOVERF;
		    break;
		 case FPE_FLTNAN_TRAP:
		    ci->un.subtype = CI_AT_FNAN;
		    break;
		 case FPE_FPA_ENABLE:
		    ci->un.subtype = CI_AT_FDISABLED;
		    break;
		 case FPE_FPA_ERROR:
		    ci->un.subtype = CI_AT_FERROR;
		    break;
	       }
	      break;
	    }
	   case SIGTRAP:
	    { ci->type = CI_TRACE;
	      ci->un.subtype = 0;
	      break;
	    }
	   case SIGEMT:
	    { ci->type = CI_TRACE;
	      ci->un.subtype = 0;
	      break;
	    }
	   case SIGFMT:
	    { ci->type = CI_FRAMEFAULT;
	      ci->un.subtype = 0;
	      break;
	    }
	 }
	/* still have to get registers, plus the crash frame; will
	   do that inside rciCrashInfo(), will will get called from
	   the planning task by the handler for the crash signal.  */

	fprintf (stderr, "\n control level crash, type %d, pc=0x%x\n", 
			 ci->type, ci->pc);

	ctx->sc_pc = (int)_rciTaskSuspendHook;
	kill (rciPlanTaskId, crashSig);
	return;
/* CC will warn that this statement is not reached; that's OK! */
	asm (".globl __rciTaskSuspendHook");
	asm ("__rciTaskSuspendHook:");
	taskSuspend(0);
}

vxwCrashInit(sig)
int sig;
{
	SIGVEC svec;

	vxwCrashInfo.type = CI_NULL;

	svec.sv_handler = crashHandler;
	svec.sv_mask = 0;
	svec.sv_flags = 0;

	sigvec (SIGSEGV, &svec, NULL);
	sigvec (SIGBUS, &svec, NULL);
	sigvec (SIGILL, &svec, NULL);
	sigvec (SIGFPE, &svec, NULL);
	sigvec (SIGTRAP, &svec, NULL);
	sigvec (SIGEMT, &svec, NULL);
	sigvec (SIGFMT, &svec, NULL);

	crashSig = sig;
}

#else

vxwCrashInit(sig)
int sig;
{
}

#endif

static int crashFrameNum;

putCrashFrame (callAddr, fxnAddr, nargs, args)
INSTR *callAddr;
int fxnAddr;
int nargs;
int *args;
{
	CRASHFRAME *cf;
	int k;

	cf = &(vxwCrashInfo.callstack[crashFrameNum%KAC_MAXCALLS]);
	nargs = MIN(KAC_NARGS, nargs);
	for (k=0; k<nargs; k++)
	 { cf->args[k] = args[k];
	 }
	cf->flags |= CI_CF_VALID;
	cf->pc = (int)callAddr;
	crashFrameNum++;
}

swapCrashFrames (i, j)
int i, j;
{
	CRASHFRAME tmp;

	tmp = vxwCrashInfo.callstack[i];
	vxwCrashInfo.callstack[i] = vxwCrashInfo.callstack[j];
	vxwCrashInfo.callstack[j] = tmp;
}

rciCrashInfo (ci, fdp)
CRASHINFO *ci;
int *fdp;
{
	char *fxnName = "rciCrashInfo()";

	if (vxwCrashInfo.type == CI_NULL)
	 { return (0);
	 }
	if (vxwCrashInfo.type != CI_FRAMEFAULT)
	 { /* a crash has occured and we should get the registers and the
	      stack crash frame. */
	   
	   int dregs[8];
	   int aregs[7];
	   char *sp;
	   unsigned short sr;
	   INSTR *pc;
	   int lastFrameIdx;
	   int k;

	   taskRegsGet (rciCtrlTaskId, dregs, aregs, &sp, &sr, &pc);
	   crashFrameNum=0;
	   trcStack ((int*)aregs[6], (int*)sp, pc, putCrashFrame);
	
	   /* all the crashframes have been read out. Now we have to 
	      put them into the proper order.
	    */

	   if (crashFrameNum > 0)
	    { lastFrameIdx = (crashFrameNum-1)%KAC_MAXCALLS;
	      for (k=0; k<(lastFrameIdx+1)/2; k++)
	       { swapCrashFrames(k,lastFrameIdx-k);
	       }
	      if (crashFrameNum > KAC_MAXCALLS)
	       { for (k=lastFrameIdx+1; k<(KAC_MAXCALLS+lastFrameIdx+1)/2;k++)
		  { swapCrashFrames(k,KAC_MAXCALLS-k+lastFrameIdx);
		  }
	       }
	    }
	 }
	*ci = vxwCrashInfo;
	return (1);
}

#endif
