
/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION  1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:sys_process.c 12.0$ */
/* $ACIS:sys_process.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/sys/RCS/sys_process.c,v $ */

#if !defined(lint) && !defined(NO_RCS_HDRS)
static char *rcsid = "$Header:sys_process.c 12.0$";
#endif

/*
 * Copyright (c) 1982, 1986 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 */

/*	sys_process.c	6.1	83/07/29	*/

#include "../machine/reg.h"
#ifndef ibm032
#include "../machine/psl.h"
#else ibm032
#include "../machine/scr.h"
#endif ibm032
#include "../machine/pte.h"

#include "param.h"
#include "systm.h"
#include "dir.h"
#include "user.h"
#include "proc.h"
#ifdef VFS
#include "vnode.h"
#else VFS
#include "inode.h"
#endif VFS
#include "text.h"
#include "seg.h"
#include "vm.h"
#include "buf.h"
#include "acct.h"
#ifdef ibm032
#include "ptrace.h"
#endif	/* defined(ibm032) */

/*
 * Priority for tracing
 */
#define	IPCPRI	PZERO

/*
 * Tracing variables.
 * Used to pass trace command from
 * parent to child being traced.
 * This data base cannot be
 * shared and is locked
 * per user.
 */
struct {
	int	ip_lock;
	int	ip_req;
	int	*ip_addr;
	int	ip_data;
#ifdef ibm032
/*
 * IPCBUF uses a buffer to cache IPCBUFSIZ bytes near the last read request
 * so that sequential read accesses to a process do not require a context
 * switch. Any non-read access invalidates the buffer contents.
 */
#define IPCBUFSIZ 1024			/* must be <= NBPG*CLSIZE */
#define IPCOFSET (IPCBUFSIZ-1)
#define btoipc(addr) ((unsigned) (addr) &  ~(IPCBUFSIZ-1))	/* for comparison */
	int	ip_lastreq;		/* last request */
	int	ip_pid;			/* pid of cached data */
	char	ip_buf[IPCBUFSIZ];	/* some cached data */
#endif
} ipc;


/*
 * sys-trace system call.
 */
ptrace()
{
	register struct proc *p;
	register struct a {
		int	req;
		int	pid;
		int	*addr;
		int	data;
	} *uap;

	uap = (struct a *)u.u_ap;
	if (uap->req <= 0) {
		u.u_procp->p_flag |= STRC;
		return;
	}
	p = pfind(uap->pid);
	if (p == 0 || p->p_stat != SSTOP || p->p_ppid != u.u_procp->p_pid ||
	    !(p->p_flag & STRC)) {
		u.u_error = ESRCH;
		return;
	}
	while (ipc.ip_lock)
		sleep((caddr_t)&ipc, IPCPRI);
#ifdef ibm032
	/*
	 * test to see if we have a read request for the same
	 * process as is in the buffer and if the data is there
	 * we return it from the buffer very quickly
	 */
	{
		register int req = uap->req;
		register int addr = (int) uap->addr;

		if (req == ipc.ip_lastreq && uap->pid == ipc.ip_pid &&
			(req==PT_READ_I || req==PT_READ_D || req==PT_READ_U) &&
				(addr&03) == 0 &&
				btoipc(addr) == btoipc(ipc.ip_addr)) {
/*			DEBUGF(svdebug&1, printf("ipcbuf match: pid=%d addr=%x req=%d ip_addr=%x\n",uap->pid,addr,req,ipc.ip_addr));	/* DEBUG */
			u.u_r.r_val1 = * (int *) (ipc.ip_buf + (addr&IPCOFSET));
			return;
		}
	ipc.ip_pid = p->p_pid;		/* remember pid */
	ipc.ip_lastreq = uap->req;	/* remember request */
	}
#endif
	ipc.ip_lock = p->p_pid;
	ipc.ip_data = uap->data;
	ipc.ip_addr = uap->addr;
	ipc.ip_req = uap->req;
	p->p_flag &= ~SWTED;
	while (ipc.ip_req > 0) {
		if (p->p_stat==SSTOP)
			setrun(p);
		sleep((caddr_t)&ipc, IPCPRI);
	}
	u.u_r.r_val1 = ipc.ip_data;
	if (ipc.ip_req < 0) {
		u.u_error = EIO;
#ifdef ibm032
		ipc.ip_lastreq = ipc.ip_req;	/* remember bad request */
#endif
	}
	ipc.ip_lock = 0;
	wakeup((caddr_t)&ipc);
}

#ifdef vax
int ipcreg[] =
	{R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,AP,FP,SP,PC};
#endif vax

#ifdef ibm032
int ipcreg[] =	 /* allow modification of only these u area variables */
	{R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15,IAR,MQ};
#endif ibm032

#ifdef ibm370
int ipcreg[] =
	{R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, 
						FR0, FR2, FR4, FR6, PC};
#endif ibm370

#define	NIPCREG	(sizeof ipcreg/sizeof ipcreg[0])

#ifndef ibm032
#define	PHYSOFF(p, o) \
	((physadr)(p)+((o)/sizeof(((physadr)0)->r[0])))
#else ibm032
#define UAREA_ADDR(o) ((int *)(0x20000000 - UPAGES*NBPG + (int)(o)))
#endif ibm032

#ifdef ibm032
extern char fubyte(), fuibyte();
extern int fuword(), fuiword();
extern int subyte(), suibyte(), suword(), suiword();

#endif ibm032
/*
 * Code that the child process
 * executes to implement the command
 * of the parent process in tracing.
 */
procxmt()
{
	register int i;
	register *p;
	register struct text *xp;
#ifdef ibm032
	register char *cp;
#endif ibm032

	if (ipc.ip_lock != u.u_procp->p_pid)
		return (0);
	u.u_procp->p_slptime = 0;
	i = ipc.ip_req;
#ifdef ibm032
	cp = (char *)ipc.ip_addr;
#endif ibm032
	ipc.ip_req = 0;
	switch (i) {

	case PT_READ_I:			/* read the child's text space */
#ifndef ibm032
		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
			goto error;
		ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
#else ibm032
		if (!useracc(cp, 4, B_READ))
			goto error;
		ipc.ip_data = getubits(cp, fuiword, fuibyte);
		bcopy((caddr_t) ((int) cp & ~IPCOFSET), ipc.ip_buf, IPCBUFSIZ);
#endif ibm032
		break;

	case PT_READ_D:			/* read the child's data space */
#ifndef ibm032
		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
			goto error;
		ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
#else ibm032
		if (!useracc(cp, 4, B_READ))
			goto error;
		ipc.ip_data = getubits(cp, fuword, fubyte);
		bcopy((caddr_t) ((int) cp & ~IPCOFSET), ipc.ip_buf, IPCBUFSIZ);
#endif ibm032
		break;

	case PT_READ_U:			/* read the child's u. */
#ifndef ibm032
		i = (int)ipc.ip_addr;
		if (i<0 || i >= ctob(UPAGES))
			goto error;
		ipc.ip_data = *(int *)PHYSOFF(&u, i);
#else ibm032
		i = (int)cp;
		if (i<0 || i >= ctob(UPAGES) || i&(sizeof(int)-1))
			goto error;
		ipc.ip_data = *UAREA_ADDR(i);
		bcopy((caddr_t) (((int) UAREA_ADDR(i)) & ~IPCOFSET), ipc.ip_buf, IPCBUFSIZ);
#endif ibm032
		break;

	case PT_WRITE_I:		/* write the child's text space */
		/*
		 * If text, must assure exclusive use
		 */
#ifndef VFS
#ifndef ibm032
		if (xp = u.u_procp->p_textp) {
			if (xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX)
#else ibm032
		if (xp = u.u_procp->p_textp ) {
			if ( xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX)
#endif ibm032
				goto error;
			xp->x_flag |= XTRC;
#else !VFS
		if (xp = u.u_procp->p_textp) {
			struct vattr vattr;
			struct vnode *vp;

			vp = xp->x_vptr;
			VOP_GETATTR(vp, &vattr, u.u_cred);

			/* This avoidance of ptrace bug supplied by Wisconsin */
			/* K L U D G E for now... ptrace bug */
#ifdef notdef
			/* removed from kernel as part of AFS fixes */
			/* will take it out completely if it proves to work */
			/* without it. */
			if (u.u_uid && vattr.va_uid != u.u_uid)
				goto error;
#endif notdef
			if (xp->x_count!=1 || (vattr.va_mode & VSVTX))
				goto error;
			vp->v_flag |= VTEXTMOD;
#endif !VFS
		}
#ifndef ibm032
		i = -1;
		if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
			if (chgprot((caddr_t)ipc.ip_addr, RW) &&
			    chgprot((caddr_t)ipc.ip_addr+(sizeof(int)-1), RW))
				i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
			(void) chgprot((caddr_t)ipc.ip_addr, RO);
			(void) chgprot((caddr_t)ipc.ip_addr+(sizeof(int)-1), RO);
#else ibm032
		/* Must set up to allow	writing */
		if ((i = setubits(cp, ipc.ip_data, suiword, suibyte ))) {
			if( chgprot( cp, RW ) && chgprot( cp+3, RW ))
				i = setubits(cp, ipc.ip_data, suiword, suibyte);
			(void) chgprot(cp, RO);
			(void) chgprot(cp+3, RO);
#endif ibm032
		}
		if (i < 0)
			goto error;
		if (xp)
			xp->x_flag |= XWRIT;
		break;

	case PT_WRITE_D:		/* write the child's data space */
#ifndef ibm032
		if (suword((caddr_t)ipc.ip_addr, 0) < 0)
			goto error;
		(void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
#else ibm032
		if (setubits(cp, 0, suword, subyte))
			goto error;
		(void) setubits(cp, ipc.ip_data, suword, subyte);
#endif ibm032
		break;

	case PT_WRITE_U:		/* write the child's u. */
#ifndef ibm032
		i = (int)ipc.ip_addr;
		p = (int *)PHYSOFF(&u, i);
#else ibm032
		i = (int)cp;
		p = UAREA_ADDR(i);
#endif ibm032
		for (i=0; i<NIPCREG; i++)
			if (p == &u.u_ar0[ipcreg[i]])
				goto ok;
#ifndef ibm032
		if (p == &u.u_ar0[PS]) {
			ipc.ip_data |= PSL_USERSET;
			ipc.ip_data &=  ~PSL_USERCLR;
#else ibm032
		if (p == &u.u_ar0[ICSCS]) {
			ipc.ip_data |= ICSCS_USERSET;
			ipc.ip_data &= ~ICSCS_USERCLR;
#endif ibm032
			goto ok;
		}
		goto error;

	ok:
		*p = ipc.ip_data;
		break;

	case PT_STEP:			/* single step the child */
	case PT_CONTINUE:		/* continue the child */
		if ((int)ipc.ip_addr != 1)
#ifndef ibm032
			u.u_ar0[PC] = (int)ipc.ip_addr;
#else ibm032
			u.u_ar0[IAR] = (int)ipc.ip_addr;
#endif ibm032
		if ((unsigned)ipc.ip_data > NSIG)
			goto error;
		u.u_procp->p_cursig = ipc.ip_data;	/* see issig */
		if (i == PT_STEP)
#ifndef ibm032
			u.u_ar0[PS] |= PSL_T;
#else ibm032
			u.u_ar0[ICSCS] |= ICSCS_INSTSTEP;  /* see locore */
#endif ibm032
		wakeup((caddr_t)&ipc);
		return (1);

	case PT_KILL:			/* kill the child process */
		wakeup((caddr_t)&ipc);
		exit(u.u_procp->p_cursig);

#ifdef ibm032
	case PT_READ_F:
		if (float_getreg((int)ipc.ip_addr, &ipc.ip_data))
			goto error;
		break;
	case PT_WRITE_F:
		if (float_putreg((int)ipc.ip_addr, &ipc.ip_data))
			goto error;
		break;
#endif ibm032
	default:
	error:
		ipc.ip_req = -1;
	}
	wakeup((caddr_t)&ipc);
	return (0);
}

#ifdef ibm032

getubits(cp, wsubr, bsubr )
	register char *cp;
	register int (*wsubr)();
	register char (*bsubr)();
{
	register i, fourbytes=0;

	if ((int)cp & 3 ) {
		for (i=0; i<4; ++i) {
			fourbytes <<= 8;
			fourbytes |= (*bsubr)(cp+i);
		}
		return (fourbytes);
	}
	return ((*wsubr)(cp));
}

setubits(cp, bits, wsubr, bsubr)
	register char *cp;
	register int bits;
	register int (*wsubr)();
	register int (*bsubr)();
{
	register i, r;

	if ((int)cp & 3) {
		for (i=3; i>=0; --i) {
			if (r = (*bsubr)(cp+i, bits & 0xFF))
				return (r);
			bits >>= 8;
		}
		return (r);
	}
	return((*wsubr)(cp, bits));
}
#endif ibm032
