/* random local syscalls, primarily for development and testing */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <machine/mmu.h>
#include <sun4/pte.h>

#include <rciext/spl.h>
#include <rciext/kuser_traps.h>
#include <rciext/rciioctl.h>

cmkrnl()
{
 struct a {
   int (*fxn)();
   int arg;
   } *uap = (struct a *) u.u_ap;

#ifndef RCI 
 if (! suser())
  { u.u_error = EPERM;
    return;
  }
#endif

 u.u_r.r_val1 = (*uap->fxn)(uap->arg);
}

local_sys1() /* dump mmu */
{
 struct a {
   unsigned short int *segmap; /* array [65536] */
   unsigned int *pagemap; /* array [16384] */
   } *uap = (struct a *) u.u_ap;
 int s;
 static unsigned short int segmap[65536];
 static unsigned int pagemap[16384];

 if ( !useracc((caddr_t)uap->segmap,65536*sizeof(*segmap),B_WRITE) ||
      !useracc((caddr_t)uap->pagemap,16384*sizeof(*pagemap),B_WRITE) )
  { u.u_error = EFAULT;
    return;
  }
 s = splhigh();
 local_sys1_s(segmap,pagemap);
 splx(s);
 copyout((caddr_t)segmap,(caddr_t)uap->segmap,65536*sizeof(segmap[0]));
 copyout((caddr_t)pagemap,(caddr_t)uap->pagemap,16384*sizeof(pagemap[0]));
}

local_sys2()
{
 struct a {
   struct RCI_interface *intf;
   } *uap = (struct a *) u.u_ap;
 struct RCI_interface kintf;

 if (!useracc((caddr_t)uap->intf,sizeof(kintf),B_WRITE))
  { u.u_error = EFAULT;
    return;
  }
 RCI_init();
 RCI_get_interface(&kintf);
 copyout((caddr_t)&kintf,(caddr_t)uap->intf,sizeof(kintf));
}

int sys3_busy = 0;
int (*sys3_fxn)();
int sys3_arg;
int sys3_rv;
struct proc *sys3_proc;

sys3_aux()
{
 int s;

 s = splhigh();
 kernel_user_proc = sys3_proc;
 if (setjmp(&kernel_user_catch))
  { sys3_rv = -1;
  }
 else
  { kernel_user_traps = 1;
    sys3_rv = kentucky(sys3_proc,sys3_fxn,sys3_arg);
  }
 kernel_user_traps = 0;
 sys3_fxn = 0;
 wakeup((caddr_t)&sys3_fxn);
 splx(s);
}

local_sys3()
{
 struct a {
   int (*fxn)();
   int arg;
   } *uap = (struct a *) u.u_ap;
 int s;

 if (! suser())
  { u.u_error = EPERM;
    return;
  }
 s = splhigh();
 while (sys3_busy)
  { splx(s);
    sleep((caddr_t)&sys3_busy,PZERO+1);
    s = splhigh();
  }
 kentucky_setup();
 sys3_fxn = uap->fxn;
 sys3_arg = uap->arg;
 sys3_proc = u.u_procp;
 timeout(sys3_aux,(caddr_t)0,10);
 while (sys3_fxn)
  { sleep((caddr_t)&sys3_fxn,PZERO);
  }
 u.u_r.r_val1 = sys3_rv;
 sys3_busy = 0;
 wakeup((caddr_t)&sys3_busy);
 splx(s);
}

local_sys4()
{
 struct a {
   int foo;
   } *uap = (struct a *) u.u_ap;
}

local_sys5()
{
 struct a {
   int foo;
   } *uap = (struct a *) u.u_ap;
}


write_text_long (addr, value)
caddr_t addr;
u_long value;
{
	/* code to write an unsigned long value into the kernel text
	   segment. Used by 'patch_kernel_text', below.
	 */
	register int s;
	register u_int savepte;
	extern u_int map_getpgmap();
	extern map_setpgmap();

	s = spl8();
	savepte = map_getpgmap(addr);
	map_setpgmap(addr, (u_int)(PG_V | PG_KW | savepte & PG_PFNUM));
/*	vac_flush (addr, sizeof(u_long)); */
	*(u_long*)addr = value;
	vac_flush (addr, sizeof(u_long));
	(void) map_setpgmap(addr, savepte);
/*	vac_flush (addr, sizeof(u_long)); */
	(void) splx(s);
}

patch_kernel_text (src, target, dest)
caddr_t src, target, dest;
{
	/* inserts an unconditional branch (annulled) from 'src' to 'target',
	   and places the original instruction at 'dest' */

#define BA_CODE		0x30800000
#define BA_OFFSET	0x003fffff

	int offset, s;

	s = spl8();

	offset = ((u_int)target-(u_int)src)/4;

	if (((int)dest & 0x3) || ((int)src & 0x3))
	 { panic ("patch_kernel_text -- bad alignment");
	 }
	write_text_long (dest, *(u_long*)src);
	write_text_long (src, BA_CODE | (offset & BA_OFFSET) );	

	splx(s);
}
