/*
 * This file contains RCI support procedures which are not associated
 *  with any specific interface device.
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/vmmac.h>
#include <sys/map.h>
#include <machine/trap.h>
#include <machine/mmu.h>
#include <machine/pte.h>
#include <rciext/rci.h>
#include <rciext/rciioctl.h>
#include <rciext/kuser_traps.h>
#include <rciext/spl.h>
#include <rciext/procx.h>
#include <sys/time.h>

#include <machine/frame.h> /* for rci_stacktrace */
#include <machine/asm_linkage.h> /* for rci_stacktrace */

#define SPL8(s)		(((s) = spl8()), lockipl())
#define SPLX(s)		(unlockipl(), splx(s))

int rcicrashdebug = 0;

static int didinit;
static int RCItime = 0;
static CRASHINFO *crashinfo;
static struct RCI_bboard *arb_bboard = 0;
static RCIINFO *current_rcii = 0;
static int (*rcisw_fxn)();
static int rcisw_arg;
static int rcisw_rv;
static caddr_t IOpage;
static caddr_t bus;
static struct rcitimeout *pending = 0;
static int recheck_timeouts;
static int inside_tick = 0;
int inside_switch = 0;
int use_hardclock = 1;
int rci_always_hardclock = 0;
int rci_debug_msgs = 0;
int rci_catchup_msgs = 0;
int found_ipl_drop = 0;
static struct timeval (*wallclock)() = 0;

static struct proc *rciProcList[MAX_RCI_PROCS];
static numRciProcs = 0;

static nopFxn();
static int kut_crash();
static sendsig();
static internaltimeout();
static timeout_tick();
static qcirc();
static dropAction();
static dbxcv();

addRciProc(p)
register struct proc *p;
{
	/* add p to the list of RCI processes */
	register int i;

	for (i=0; i<MAX_RCI_PROCS; i++)
	 { if (!rciProcList[i])
	    { rciProcList[i] = p;
	      numRciProcs++;
	      return (1);
	    }
	 }
	return (0);
}

deleteRciProc(p)
register struct proc *p;
{
	/* delete p from the list of RCI processes */
	register int i;

	for (i=0; i<MAX_RCI_PROCS; i++)
	 { if (rciProcList[i] == p)
	    { rciProcList[i] = 0;
	      numRciProcs--;
	      return (1);
	    }
	 }
	return (0);
}

isRciProc(p)
register struct proc *p;
{
	/* return true if p is on the list of RCI processes */
	register int i;

	for (i=0; i<MAX_RCI_PROCS; i++)
	 { if (rciProcList[i] == p)
	    { return (1);
	    }
	 }
	return (0);
}

static RCIINFO *rcii_list;

RCI_setwallclock(fxn)
struct timeval(*fxn)();
{
	printf ("RCI_wallclock set to 0x%x\n", fxn);
	wallclock = fxn;
}

struct timeval RCI_wallclock()
{
	struct timeval tv;

	if (wallclock)
	 { return (*wallclock)();
	 }
	else
	 { struct timeval tv;
	   tv.tv_sec = tv.tv_usec = 0;
	   return (tv);
	 }
}

/* trace functions */

static int (*setFxn)() = 0;
static int (*clearFxn)() = 0;

RCI_setTraceFxns(set, clear)
int (*set)();
int (*clear)();
{
	printf ("RCI trace functions set to 0x%x and 0x%x\n", set, clear);
	setFxn = set;
	clearFxn = clear;
}

RCI_set_trace(c)
int c;
{
	if (setFxn)
	 { return (*setFxn)(c);
	 }
	else
	 { return (-1);
	 }
}

RCI_clear_trace(c)
int c;
{
	if (clearFxn)
	 { return (*clearFxn)(c);
	 }
	else
	 { return (-1);
	 }
}

#define SENDSIG_STACK_SIZE	512
static int sendsigStackp = 0;
static int sendsigStack[SENDSIG_STACK_SIZE];

/*
static int unswitch_sig;
*/

caddr_t kvall();

#define RCITIME (arb_bboard->time_rt[0])

/* Interface */

RCI_init()
{
 int s;
 int abbkmx;
 struct pte *ptep;
 caddr_t getpages();
 u_int pte;
 int a;

 if (didinit)
  { return;
  }
 s = spl8();
 didinit = 1;
 splx(s);
 crashinfo = 0;
 arb_bboard = (struct RCI_bboard *) getpages(1);
 /* page the thing in ... */
 arb_bboard->time_rt[0] = 0;
 s = spl8();
#if 0
 abbkmx = btokmx((struct pte *)arb_bboard);
 ptep = &Usrptmap[abbkmx];
 *(int *)ptep = ((*(int *)ptep) & ~PG_PROT) | PG_UW;
 map_setpgmap((caddr_t)arb_bboard,*(long int *)ptep);
#else
 pte = map_getpgmap((caddr_t)arb_bboard);
 map_setpgmap((caddr_t)arb_bboard,(u_int)((pte & ~PG_PROT) | PG_V | PG_UW));
 pte = map_getpgmap((caddr_t)arb_bboard);
#endif
 arb_bboard->time_rt[0] = 0;
 createBusMaps (&bus, &IOpage);
 rcii_list = 0;
 doKernelPatches();
 /* get u area for process 0 */
 splx(s);
}


RCI_alive()
{
 return(didinit>0);
}

int RCI_use_uprintf = 0;

static nopFxn()
{
}

RCI_get_interface(intf)
struct RCI_interface *intf;
{
 int sendsig();
 extern printf();
 extern uprintf();
 int internaltimeout();
 int useracc();
 int badaddr();
 extern vslock();
 extern vsunlock();
 extern kut_callit();

 intf->time = &RCItime;
 intf->bboards[0] = arb_bboard;
 intf->IOpage = IOpage;
 intf->bus = bus;
 intf->signal = sendsig;
 if (RCI_use_uprintf)
  { intf->printf = uprintf;
  }
 else
  { intf->printf = printf;
  }
 intf->uprintf = uprintf;
 intf->badaddr = badaddr;
 intf->timeout = internaltimeout;
 intf->sigslave = nopFxn;
 intf->useracc = useracc;
 intf->vslock = 0; /*vslock (not used) */
 intf->vsunlock = nopFxn; /*vsunlock*/
 intf->kutcall = kut_callit;
 intf->wallclock = wallclock;
 intf->setTrace = setFxn;
 intf->clearTrace = clearFxn;
 intf->lockReadBuf = nopFxn;
 intf->lockWriteBuf = nopFxn;
}

RCI_tick(n)
int n;
{
 RCItime += n;
 timeout_tick();
}

RCI_setup_timeout(rcii,to)
RCIINFO *rcii;
struct RCI_timeout *to;
{
 RCI_setup_switch(rcii);
 do_timeout(rcii,to->clockno,to->when,to->function,to->argument);
}

RCI_setup_switch(ctx)
RCIINFO *ctx;
{
 kentucky_setup();
 ctx->proc = u.u_procp;
}

RCI_kut_call(fxn,arg,rcii)
int (*fxn)();
int arg;
RCIINFO *rcii;
{
 int s;
 int rv;
 CRASHINFO *crash;
 int kut_doit();

 crash = &rcii->lastcrash;
 s = spl8();
 RCI_setup_switch(rcii);
 rv = RCI_switch(rcii,fxn,arg);
 splx(s);
 return(rv);
}

int RCI_switch(ctx,fxn,arg)
RCIINFO *ctx;
int (*fxn)();
int arg;
{
 int s;
 int kut_crash();
 int rv;
 CRASHINFO *saved_ci;
 int saved_insw;
 int do_rciswitch();

 SPL8(s);
 if (sendsigStackp < SENDSIG_STACK_SIZE-1)
  { sendsigStackp++;
  }
 else
  { printf ("WARNING: RCI sendsig stack overflow\n");
  }
 sendsigStack[sendsigStackp] = 0;
 saved_insw = inside_switch;
 inside_switch = 1;
 saved_ci = crashinfo;
 crashinfo = &ctx->lastcrash;
 rcisw_fxn = fxn;
 rcisw_arg = arg;
 current_rcii = ctx;
 kentucky(ctx->proc,do_rciswitch,0);
/* syncfpu(); done by kentucky code before switchback */
 rv = rcisw_rv;
 if (rv)
  { RCI_cancel (ctx);  /* cancel any pending RCI events for this process */
  }
 current_rcii = 0;
 crashinfo = saved_ci;
 inside_switch = saved_insw;
 if (recheck_timeouts && !inside_switch) timeout_tick();
 if (sendsigStack[sendsigStackp])
  { psignal(ctx->proc,sendsigStack[sendsigStackp]);
  }
 sendsigStackp--;
 SPLX(s);

 return(rv);
}

RCI_signal(pid,sig)
int pid;
int sig;
{
 struct proc *p;

 printf("kill %d with %d:",pid,sig);
 if (!sig)
  { return;
  }
 p = pfind(pid);
 if (p)
  { psignal(p,sig);
  }
}

RCI_heartbeat(rciica)
caddr_t rciica;
{
 RCIINFO *rcii;
 int s;

 s = spl8();
 rcii = (RCIINFO *) rciica;
 if (rcii->hbfxn && RCI_switch(rcii,rcii->hbfxn,rcii->hbarg))
  { RCI_signal(rcii->pid,rcii->crashsig);
  }
 else
  { timeout(RCI_heartbeat,rciica,rcii->hbticks);
  }
 splx(s);
}

RCI_cleari(rcii)
register RCIINFO *rcii;
{
 int s;

 s = spl8();
 rcii->flags = 0;
 rcii->ifxn = 0;
 rcii->pid = 0;
 rcii->crashsig = 0;
 rcii->lastcrash.type = CI_NULL;
 untimeout(RCI_heartbeat,(caddr_t)rcii);
 rcii->hbticks = 0;
 rcii->hbfxn = 0;
 rcii->timeout.info = rcii;
 rcii->timeout.handler = 0;
 rcii->next = 0;
 splx(s);
}

RCI_openi(rcii)
register RCIINFO *rcii;
{
 RCIINFO *ip;
 int s;

 if (!isRciProc(u.u_procp))
  { if (numRciProcs < MAX_RCI_PROCS)
     { addRciProc(u.u_procp);
     }
    else
     { return(0);
     }
  }
 rcii->flags |= (RCI_OPEN|RCI_BUSY);
 rcii->pid = u.u_procp->p_pid;
 s = spl8();
 for (ip=rcii_list; ip; ip = ip->next)
  { if (ip == rcii)
     { panic ("RCI info struct already on list\n");
     }
  }
 LINK_H (rcii_list, rcii);
 splx(s);
 return(1);
}

RCI_closei(rcii)
register RCIINFO *rcii;
{
 int s;

 s = spl8();
 if (rcii->flags & RCI_BUSY)
  { if (rcii->timeout.handler)
     { undo_timeout(rcii);
     }
    UNLINK_H (rcii_list, rcii);
  }
 RCI_cleari(rcii);
 found_ipl_drop = 0;
 splx(s);
}

RCI_cancel(rcii)
RCIINFO *rcii;
{
 /* Cancel all pending RCI functions for the process using the 
    given RCI device. Should be called at spl8() */

    RCIINFO *ip;

    for (ip = rcii_list; ip; ip = ip->next)
     { if (ip->pid == rcii->pid)
	{ ip->ifxn = 0;
	  ip->hbfxn = 0;
	  ip->timeout.handler = 0;
	}
     }
}

RCI_hardclock()
{
 extern int kernel_user_traps;

 if (kernel_user_traps)
  { spl8();
    asm("call _traceback");
    asm("mov %sp,%o0");
    panic ("RCI_hardclock: kernel-user traps set\n");
  }
 if (use_hardclock)
  { if (arb_bboard)
     { arb_bboard->time_rt[0] ++;
     }
    RCI_tick(1);
  }
}

RCI_devclock(n)
int n;
{
 if (! use_hardclock)
  { if (rci_catchup_msgs && (n > 1))
     { printf("catchup: %d\n",n);
     }
    if (arb_bboard)
     { arb_bboard->time_rt[0] += n;
     }
    if (inside_switch)
     { printf ("RCI_devclock: inside switch!\n");
     }
    RCI_tick(n);
  }
}

RCI_use_hardclock(doso)
int doso;
{
 use_hardclock = (!!doso) && (!rci_always_hardclock);
}

/* Implementation */

do_rciswitch()
{
 int rv;
 int saved_kut;
 label_t saved_kuc;
 struct proc *saved_kup;
 int (*saved_kuf)();

 if (!atspl8())
  { spl8();
    printf("do_rciswitch: not at spl8\n");
  }
#if 0
 if (kernel_user_traps)
  { printf("do_rciswitch: kernel-user traps already active\n");
    asm("call _traceback");
    asm("mov %sp,%o0");
    rcisw_rv = 1;
    return;
  }
#endif
 saved_kut = kernel_user_traps;
 saved_kuc = kernel_user_catch;
 saved_kup = kernel_user_proc;
 saved_kuf = kernel_user_fxn;
 kernel_user_proc = 0;
 kernel_user_fxn = kut_crash;
 kernel_user_traps = 1;
 rcisw_rv = 0;
 if (setjmp(&kernel_user_catch) == 0)
  { (*rcisw_fxn)(rcisw_arg);
  }
 else
  { rcisw_rv = 1;
  }
/* syncfpu(); already done by kentucky code before switchback */
 if (!atspl8())
  { panic ("IPL dropped during RCI switch function\n");
  }
 kernel_user_traps = saved_kut;
 kernel_user_catch = saved_kuc;
 kernel_user_proc = saved_kup;
 kernel_user_fxn = saved_kuf;
}

int badaddr(addr,mode)
char *addr;
int mode;
{
 long int trashcan;
 int kut_save;
 int value;
 int s;

 switch (mode)
  { default:
       printf("badaddr(0x%x,%d)\n",addr,mode);
       return (-1);
       break;
    case 1:
       s = spl8();
       kut_save = kernel_user_traps;
       kernel_user_traps = 0;
       value = peekc(addr);
       kernel_user_traps = kut_save;
       splx(s);
       break;
    case 2:
       if (1&(int)addr)
	{ return(1);
	}
       s = spl8();
       kut_save = kernel_user_traps;
       kernel_user_traps = 0;
       value = peek((short int *)addr);
       kernel_user_traps = kut_save;
       splx(s);
       break;
    case 4:
       if (3&(int)addr)
	{ return(1);
	}
       s = spl8();
       kernel_user_traps = 0;
       kut_save = kernel_user_traps;
       value = peekl((long int *)addr,&trashcan);
       kernel_user_traps = kut_save;
       splx(s);
       break;
  }
 return (value == -1);
}

int kut_callit(fxn,arg1,arg2,arg3,arg4)
int (*fxn)();
long int arg1;
long int arg2;
long int arg3;
long int arg4;
{
 int s;
 int rv;
 extern int in_ksw;

 SPL8(s);
 if (in_ksw)
  { printf("kut_callit when kentucky switched\n");
    SPLX(s);
    return;
  }
 if (kernel_user_traps)
  { printf("kut_callit: kernel-user traps already active\n");
    SPLX(s);
    return(-1);
  }
 kernel_user_proc = u.u_procp;
 kernel_user_traps = 1;
 if (setjmp(&kernel_user_catch) == 0)
  { if (! atspl8())
     { printf("kut_callit: not at spl8?\n");
     }
    else
     { rv = (*fxn)(arg1,arg2,arg3,arg4);
     }
  }
 if (!atspl8())
  { printf("kut_callit: not at spl8, afterwards\n");
  }
 kernel_user_traps = 0;
 SPLX(s);
 return(rv);
}

static int kut_crash(type,rp,addr,be)
register unsigned type;
register struct regs *rp;
register unsigned int addr;
register u_char be;
{
 printf("kut_crash: type=%x, pc=%x, npc=%x, psr=%x (crashinfo=%x)\n",
	type,rp->r_pc,rp->r_npc,rp->r_psr,(int)crashinfo);
 crashinfo->pc = rp->r_pc;
 crashinfo->npc = rp->r_npc;
 crashinfo->psr = rp->r_psr;
 switch (type)
  { default:
       printf("bad type %d in RCI kut_crash\n",type);
       panic("kut_crash");
       break;
    case T_DATA_FAULT:
    case T_TEXT_FAULT:
    case T_ALIGNMENT:
       crashinfo->type = CI_MEMFAULT;
       crashinfo->un.memfault.addr = addr;
       crashinfo->un.memfault.be = be;
       break;
    case T_PRIV_INSTR:
       crashinfo->type = CI_ILLINST;
       crashinfo->un.subtype = CI_II_PRIV;
       break;
    case T_UNIMP_INSTR:
       crashinfo->type = CI_ILLINST;
       crashinfo->un.subtype = CI_II_UNIMP;
       break;
    case T_SYSCALL:
       crashinfo->type = CI_ILLINST;
       crashinfo->un.subtype = CI_II_SYSCALL;
       break;
    case T_BREAKPOINT:
    case T_AST:
       crashinfo->type = CI_TRACE;
       break;
    case T_DIV0:
    case T_FP_EXCEPTION:
       crashinfo->type = CI_ARITHTRAP;
       switch (addr)
	{ case FPE_INTDIV_TRAP:
	     crashinfo->un.subtype = CI_AT_IDIVZ;
	     break;
	  case FPE_FLTINEX_TRAP:
	     crashinfo->un.subtype = CI_AT_FINEXACT;
	     break;
	  case FPE_FLTDIV_TRAP:
	     crashinfo->un.subtype = CI_AT_FDIVZ;
	     break;
	  case FPE_FLTUND_TRAP:
	     crashinfo->un.subtype = CI_AT_FUNDERF;
	     break;
	  case FPE_FLTOPERR_TRAP:
	     crashinfo->un.subtype = CI_AT_FOPERAND;
	     break;
	  case FPE_FLTOVF_TRAP:
	     crashinfo->un.subtype = CI_AT_FOVERF;
	     break;
	}
       break;
  }
 bcopy((caddr_t)rp,(caddr_t)crashinfo->registers,sizeof(crashinfo->registers));
 rci_stacktrace(crashinfo,rp->r_sp);
}

rci_stacktrace(ci,sp)
CRASHINFO *ci;
caddr_t sp;
{
 int i;
 int j;
 struct frame *fp;
 CRASHFRAME *cf;

 for (i=0;i<KAC_MAXCALLS;i++)
  { ci->callstack[i].flags = 0;
  }
 if ((int)sp & (STACK_ALIGN-1)) return;
 flush_windows();
 fp = (struct frame *) sp;
 i = 0;
 while (i < KAC_MAXCALLS)
  { cf = &ci->callstack[i++];
    if (peekl(&fp->fr_savpc,&cf->pc) != 0) break;
    for (j=0;j<6;j++)
     { if (peekl(&fp->fr_arg[j],&cf->args[j]) != 0) break;
     }
    if (j != 6) break;
    if (peekl(&fp->fr_savfp,&fp) != 0) break;
    cf->flags = CI_CF_VALID;
    if (! fp) break;
  }
}

static sendsig(cpu,sig)
int cpu;
int sig;
{
 if (cpu == 0)
  { sendsigStack[sendsigStackp] = sig;
  }
}

static internaltimeout(clockno,when,fxn,arg)
int clockno;
int when;
int (*fxn)();
int arg;
{
 do_timeout(current_rcii,clockno,when,fxn,arg);
}

static timeout_tick()
{
 register int curtime;
 int any;
 register struct rcitimeout **tp;
 struct rcitimeout *tofire;
 register struct rcitimeout *t;
 register int n;
 int s;

#define DBG (rci_debug_msgs && !use_hardclock)
 if (DBG)
  { printf("Q"); /* queue in timeout_tick */
    dumptimerqueue(pending);
  }
 s = spl8();
 inside_tick = 1;
 do
  { recheck_timeouts = 0;
    if (! pending)
     { splx(s);
       if (DBG) printf("E"); /* timeout_tick: empty queue */
       break;
     }
    tofire = 0;
    curtime = arb_bboard->time_rt[0];
    n = 0;
    for ( tp = &pending;
	  *tp && ((*tp)->when<=curtime);
	  tp = &(*tp)->link )
     { if (++n > 100)
	{ qcirc(0);
	  tp = &pending;
	  break;
	}
     }
    if (tp != &pending)
     { t = pending;
       pending = *tp;
       *tp = 0;
       tofire = t;
       if (DBG)
	{ printf("F");
	  dumptimerqueue(tofire);
	  printf("R");
	  dumptimerqueue(pending);
	}
       for (t=tofire;t;t=t->link)
	{ t->explink = t->link;
	  t->exphandler = t->handler;
	  t->expargument = t->argument;
	  t->handler = 0;
	}
       for (t=tofire;t;t=t->explink)
	{ if (t->exphandler)
	   { if (RCI_switch(t->info,t->exphandler,t->expargument))
	      { RCI_signal(t->info->pid,t->info->crashsig);
	      }
	   }
	}
     }
    else
     { if (DBG)
	{ printf("N");
	}
     }
  } while (recheck_timeouts);
 inside_tick = 0;
 splx(s);
#undef DBG
}

do_timeout(rcii,clockno,when,function,argument)
RCIINFO *rcii;
int clockno;
int when;
int (*function)();
int argument;
{
 struct rcitimeout *to;
 register struct rcitimeout **tp;
 register int n;
 int s;

 if (rcii == 0)
  { printf("zero RCI context to do_timeout\n");
    return;
  }
 to = &rcii->timeout;
 s = spl8();
 if (clockno != 0)
  { panic("bad clockno to do_timeout");
    /* NOTREACHED */
  }
 if (rci_debug_msgs) printf("@%d:%d.",when,arb_bboard->time_rt[0]); /* at %d now %d */
 if (to->handler)
  { for ( tp = &pending;
	  *tp && (*tp != to);
	  tp = &(*tp)->link )
     { ;
     }
    if (*tp) *tp = to->link;
    to->handler = 0;
  }
 if (function)
  { to->clockno = clockno;
    to->when = when;
    to->handler = function;
    to->argument = argument;
    n = 0;
    for ( tp = &pending;
	  *tp && ((*tp)->when <= when);
	  tp = &(*tp)->link )
     { if (++n > 100)
	{ qcirc(1);
	  /* NOTREACHED */
	}
     }
    to->link = *tp;
    *tp = to;
    if (pending->when <= arb_bboard->time_rt[0])
     { if (inside_tick || inside_switch)
	{ if (rci_debug_msgs) printf("C"); /* recheck later */
	  recheck_timeouts = 1;
	}
       else
	{ if (rci_debug_msgs) printf("X"); /* explicit queue check */
	  timeout_tick();
	}
     }
  }
 splx(s);
}

dumptimerqueue(root)
struct rcitimeout *root;
{
 register struct rcitimeout *to;
 int s;

 s = spl8();
 printf(">%d",arb_bboard->time_rt[0]);
 for (to=root;to;to=to->link)
  { printf("@%d:%x(%x)",to->when,(int)to->handler,to->argument);
  }
 printf("<");
}

undo_timeout(rcii)
RCIINFO *rcii;
{
 int s;
 register struct rcitimeout *to;
 register struct rcitimeout **tp;
 register int n;

 s = spl8();
 to = &rcii->timeout;
 n = 0;
 for ( tp = &pending;
       *tp && (*tp != to);
       tp = &(*tp)->link )
  { if (++n > 100)
     { qcirc(1);
       /* NOTREACHED */
     }
  }
 if (*tp) *tp = to->link;
 to->handler = 0;
 splx(s);
}

static qcirc(crash)
int crash;
{
 register struct rcitimeout *t1;
 register struct rcitimeout *t2;

 printf("More than 100 timeouts on queue\n");
 t1 = pending;
 t2 = t1;
 do
  { printf("%x\n",(int)t1);
    t1 = t1->link;
    t1->handler = 0;
    t2 = t2->link->link;
  } while (t1 != t2);
 printf("Clearing queue%s\n",crash?" and forcing crash":"");
 pending = 0;
 if (crash)
  { *(char *)0xc0000000 = 0;
    /* NOTREACHED */
  }
}

#if 0
/* We take over the IPL set routines since some kernel functions we
   use tend to drop IPL when we are inside a switch */

#define DROP_ACTION(s)	dropAction(s); return (spl8());

static dropAction(s)
{
	if (!found_ipl_drop)
	 { found_ipl_drop = 1;
	 }
}

int splzs_ipl_drop = 0;
splzs()
{
	if (inside_switch)
	 { splzs_ipl_drop++;
	   DROP_ACTION("splzs");
	 }
	return(RCIsplzs());
}

int spl7_ipl_drop = 0;
spl7()
{
	if (inside_switch)
	 { spl7_ipl_drop++;
	   DROP_ACTION("spl7");
	 }
	return(RCIspl7());
}

int spl6_ipl_drop = 0;
spl6()
{
	if (inside_switch)
	 { spl6_ipl_drop++;
	   DROP_ACTION("spl6");
	 }
	return(RCIspl6());
}

int spl5_ipl_drop = 0;
spl5()
{
	if (inside_switch)
	 { spl5_ipl_drop++;
	   DROP_ACTION("spl5");
	 }
	return(RCIspl5());
}

int spl4_ipl_drop = 0;
spl4()
{
	if (inside_switch)
	 { spl4_ipl_drop++;
	   DROP_ACTION("spl4");
	 }
	return(RCIspl4());
}

int spl3_ipl_drop = 0;
spl3()
{
	if (inside_switch)
	 { spl3_ipl_drop++;
	   DROP_ACTION("spl3");
	 }
	return(RCIspl3());
}

int spl2_ipl_drop = 0;
spl2()
{
	if (inside_switch)
	 { spl2_ipl_drop++;
	   DROP_ACTION("spl2");
	 }
	return(RCIspl2());
}

int spl1_ipl_drop = 0;
spl1()
{
	if (inside_switch)
	 { spl1_ipl_drop++;
	   DROP_ACTION("spl1");
	 }
	return(RCIspl1());
}

int splsoftclock_ipl_drop = 0;
splsoftclock()
{
	if (inside_switch)
	 { splsoftclock_ipl_drop++;
	   DROP_ACTION("splsoftclock");
	 }
	return(RCIsplsoftclock());
}

int spl0_ipl_drop = 0;
spl0()
{
	if (inside_switch)
	 { spl0_ipl_drop++;
	   DROP_ACTION("spl0");
	 }
	return(RCIspl0());
}

int splx_ipl_drop = 0;
splx(x)
int x;
{
#if 0
	if (inside_switch)
	 { splx_ipl_drop++;
	   DROP_ACTION("splx");
	 }
#endif
	return(RCIsplx(x));
}

splr(x)
int x;
{
	int new;

	new = RCIsplr(x);
	if (inside_switch && new != 0xf00)
	 { panic ("splr DROPPED ipl inside RCI switch\n");
	 }
	return(new);
}
#endif

#include <vm/hat.h>
#include <vm/as.h>

RCI_exit()
{
	RCIINFO *ip, *next_ip;

	if (isRciProc(u.u_procp))
	 { for (ip = rcii_list; ip; ip = next_ip)
	    { next_ip = ip->next;
	      if (ip->pid == u.u_procp->p_pid)
	       { RCI_closei(ip);
	       }
	    }
	   deleteRciProc(u.u_procp);
	 }
}

swapout_wrapper(p, hardswap)
register struct proc *p;
short hardswap;
{
	if ((p->p_flag & SPROCX) && isRciProc(p))
	 { printf ("WARNING: swapping out RCI process %d\n", p->p_pid);
	 }
	return (wrapped_swapout(p, hardswap));
}


hardclock_wrapper(pc, ps, x0)
caddr_t pc;
int ps;
int x0;
{
	RCI_hardclock();
	return (wrapped_hardclock(pc, ps, x0));
}

static kernelPatchesDone;

doKernelPatches()
{
	if (!kernelPatchesDone)
	 { 
	   extern swapout();
	   extern swapout_wrapper();
	   extern wrapped_swapout();

	   extern hardclock();
	   extern hardclock_wrapper();
	   extern wrapped_hardclock();

	   extern trap();
	   extern trap_wrapper();
	   extern wrapped_trap();

	   extern syscall();
	   extern syscall_wrapper();
	   extern wrapped_syscall();

	   printf ("patching swapout() ...\n");
	   patch_kernel_text ((caddr_t)swapout, (caddr_t)swapout_wrapper, 
					 (caddr_t)wrapped_swapout);

	   printf ("patching hardclock() ...\n");
	   patch_kernel_text ((caddr_t)hardclock, (caddr_t)hardclock_wrapper, 
					 (caddr_t)wrapped_hardclock);
#if 0
	   printf ("patching trap() ...\n");
	   patch_kernel_text ((caddr_t)trap, (caddr_t)trap_wrapper, 
					 (caddr_t)wrapped_trap);

	   printf ("patching syscall() ...\n");
	   patch_kernel_text ((caddr_t)syscall, (caddr_t)syscall_wrapper, 
					 (caddr_t)wrapped_syscall);
#endif
	   kernelPatchesDone = 1;
	 }
}

/* ----- some routines for logging diagnostic information ----- */

#define NMSGS 64
#define MSGSIZE 256

static char dbmsgs[NMSGS][MSGSIZE];
static int dbhand = 0;
int dbdisable = 0;

dbmsg(fmt,na,a0,a1,a2,a3) /* max 6 args */
char *fmt;
int na;
int a0,a1,a2,a3;
{
 register char *bp;

 if (dbdisable) return;
 bp = &dbmsgs[dbhand][0];
 dbhand = (dbhand + 1) % NMSGS;
 strcpy(bp,fmt);
 while (*bp) bp ++;
 if (na > 0)
  { dbxcv(bp,a0);
    while (*bp) bp ++;
  }
 if (na > 1)
  { dbxcv(bp,a1);
    while (*bp) bp ++;
  }
 if (na > 2)
  { dbxcv(bp,a2);
    while (*bp) bp ++;
  }
 if (na > 3)
  { dbxcv(bp,a3);
    while (*bp) bp ++;
  }
}

static dbxcv(bp,a)
register char *bp;
register int a;
{
 register int i;

 *bp++ = ' ';
 for (i=32-4;i>=0;i-=4)
  { *bp++ = "0123456789abcdef"[(a>>i)&0xf];
  }
 *bp = '\0';
}

db_dump_rciilist()
{
 RCIINFO *ip;

 for (ip=rcii_list;ip;ip=ip->next)
  { dbmsg("list el:",1,(int)ip);
  }
}

RCI_kutexec(arg)
int arg;
{
	struct RCI_fxn_arg4 *ap;

	ap = (struct RCI_fxn_arg4*)arg;
	ap->rval = (*ap->fxn)(ap->arg[0],ap->arg[1],ap->arg[2],ap->arg[3]);
}

createBusMaps(busp, IOpagep)
caddr_t *busp;
caddr_t *IOpagep;
{
#ifndef sun4c
 caddr_t bus;
 caddr_t IOpage;
 int a;

 a = (int) rmalloc(kernelmap,(long int)btoc(VME16_SIZE));
 if (a == 0)
  { panic("RCI_init: out of kernel vm (IOpage)");
  }
 IOpage = (caddr_t) kmxtob(a);
 mapin( &Usrptmap[a],
	btop(IOpage),
	PGT_VME_D16 | btop(VME16_BASE),
	btoc(VME16_SIZE),
	PG_V | PG_UW );
 a = (int) rmalloc(kernelmap,(long int)btoc(0x200000));
 if (a == 0)
  { panic("RCI_init: out of kernel vm (bus)");
  }
 bus = (caddr_t) kmxtob(a);
 mapin( &Usrptmap[a],
	btop(bus),
	PGT_VME_D16 | btop(VME24_BASE+0x800000),
	btoc(0x200000),
	PG_V | PG_UW );
#else
 IOpage = 0;
 bus = 0;
#endif
 *IOpagep = IOpage;
 *busp = bus;
}
