File:  [MW Coherent from dump] / coherent / d / PS2_KERNEL / i286 / exec.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/* $Header: /var/lib/cvsd/repos/coherent/coherent/d/PS2_KERNEL/i286/exec.c,v 1.1.1.1 2019/05/29 04:56:39 root Exp $ */
/* (lgl-
 *	The information contained herein is a trade secret of Mark Williams
 *	Company, and  is confidential information.  It is provided  under a
 *	license agreement,  and may be  copied or disclosed  only under the
 *	terms of  that agreement.  Any  reproduction or disclosure  of this
 *	material without the express written authorization of Mark Williams
 *	Company or persuant to the license agreement is unlawful.
 *
 *	COHERENT Version 2.3.37
 *	Copyright (c) 1982, 1983, 1984.
 *	An unpublished work by Mark Williams Company, Chicago.
 *	All rights reserved.
 -lgl) */
/*
 * This file contains a special version
 * of "sys exec" for the i8086. This version has
 * no driver load code in it (save space) and has
 * special load code so that the text of a shared
 * and separated image can be shared.
 * Loadable kernel processes are partially supported:
 * the process text and data must be ld'ed with the system
 * and the l.out executed must have no loadable or allocateable
 * segments.
 *
 * $Log: exec.c,v $
 * Revision 1.1.1.1  2019/05/29 04:56:39  root
 * coherent
 *
 * Revision 1.1  92/07/17  15:21:27  bin
 * Initial revision
 * 
 * Revision 1.1	88/03/24  17:39:26	src
 * Initial revision
 * 
 * 88/01/21	Allan Cornish		/usr/src/sys/i8086/src/exec.c
 * Segments are now de-associated from processes before freeing the segment.
 *
 * 87/12/03	Allan Cornish		/usr/src/sys/i8086/src/exec.c
 * ld_start() now reverts to kernel mode [depth=0] from user mode [depth=1].
 *
 * 87/11/25	Allan Cornish		/usr/src/sys/i8086/src/exec.c
 * vaddr_t bp->b_vaddr --> faddr_t bp->b_faddr.
 *
 * 87/11/14	Allan Cornish		/usr/src/sys/i8086/src/exec.c
 * Init code+data now split into icodep/icodes and idatap/idatas.
 *
 * 87/11/05	Allan Cornish		/usr/src/sys/i8086/src/exec.c
 * New seg struct now used to allow extended addressing.
 *
 * 87/10/09	Allan Cornish		/usr/src/sys/i8086/src/exec.c
 * pload() now handles new format [separate code] loadable device drivers.
 *
 * 87/10/08	Allan Cornish		/usr/src/sys/i8086/src/exec.c
 * Exsread() initializes the (IO).io_flag field to 0.
 */
#include <sys/coherent.h>
#include <acct.h>
#include <sys/buf.h>
#include <canon.h>
#include <sys/con.h>
#include <errno.h>
#include <sys/filsys.h>
#include <sys/ino.h>
#include <sys/inode.h>
#include <l.out.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/seg.h>
#include <signal.h>
#include <sys/i8086.h>

/*
 * Sizes.
 */
#define	sh	((fsize_t)sizeof(struct ldheader))
#define si	lssize[L_SHRI]
#define pi	lssize[L_PRVI]
#define bi	lssize[L_BSSI]
#define sd	lssize[L_SHRD]
#define pd	lssize[L_PRVD]
#define bd	lssize[L_BSSD]

/*
 * Segments.
 */
#define upsp	pp->p_segp[SIUSERP]
#define sssp	pp->p_segp[SISTACK]
#define	sisp	pp->p_segp[SISTEXT]
#define pisp	pp->p_segp[SIPTEXT]
#define pdsp	pp->p_segp[SIPDATA]

/*
 * Loadable driver initiation point.
 */
static
ld_start()
{
	register SEG * sp;
	register int ret;

	/*
	 * Kernel processes start by default at user level.
	 * Revert to kernel level.
	 */
	if ( depth == 1 )
		depth--;

	/*
	 * Initialize memory references.
	 */
	u.u_btime = timer.t_time;
	sproto();
	segload();


	/*
	 * Invoke the driver if it has a shared or private code segment.
	 */
	ret = 100;
	if ( (sp = SELF->p_segp[SISTEXT]) || (sp = SELF->p_segp[SIPTEXT]) ) {
		ret = ld_xcall( sp->s_faddr );
	}

	uexit( ret );
}

/*
 * Set up the first process, a small programme which will exec
 * the init programme.
 */
eveinit(sp)
SEG *sp;
{
	register PROC *pp;
	SELF = pp = eprocp;

	/*
	 * Record user area.
	 */
	pp->p_segp[SIUSERP] = sp;

	/*
	 * Allocate, record, initialize code segment, make it executable.
	 */
	if ((sp=salloc((fsize_t)icodes, 0)) == NULL)
		panic("eveinit(code)");
	pp->p_segp[SIPTEXT] = sp;
	kfcopy( icodep, sp->s_faddr, icodes );
	sp->s_flags |= SFTEXT;
	vremap(sp);

	/*
	 * Allocate, record, and initialize data segment.
	 */
	if ((sp=salloc((fsize_t)idatas, 0)) == NULL)
		panic("eveinit(data)");
	pp->p_segp[SIPDATA] = sp;
	kfcopy( idatap, sp->s_faddr, idatas );

	/*
	 * Allocate and record stack segment.
	 */
	if ((sp=salloc((fsize_t)UPASIZE, SFDOWN)) == NULL)
		panic("eveinit()");
	pp->p_segp[SISTACK] = sp;

	/*
	 * Start process.
	 */
	u.u_argp = 0;
	if (sproto() == 0)
		panic("eveinit()");
	segload();
}

/*
 * Load a driver which has already been linked into the system image.
 */
pload( np )
char * np;
{
	register INODE * ip;
	register PROC  * cpp;
	struct seg     * sp;
	fsize_t		lssize[NUSEG];		/* Segment sizes */
	int		lflag;			/* l_flags from l.out */
	vaddr_t		pc;			/* l_entry from l.out */
	int		r;			/* Flag for "exload" */
	int		s;
	extern char	end[];


	if (super() == 0) {
		return( -1 );
	}

	/*
	 * Coalesce memory BEFORE loading driver, since it can't be moved.
	 */
	krunch(10000);

	if ((ip=exlopen(np, lssize, &lflag, &pc)) == NULL) {
		return( -1 );
	}

	/*
	 * New format loadable drivers must have separate code/data.
	 * It must have executable code, but no initialized data.
	 * Uninitialized data must match the kernel data size.
	 */
	if ( ((lflag & (LF_KER|LF_SHR|LF_SEP)) != (LF_SEP|LF_KER))
	  || (si==0) || (sd!=0) || (pd!=0) || (bd != (int)end) ) {
		u.u_error = EBADFMT;
		idetach(ip);
		return( -1 );
	}

	/*
	 * Allocate and initialize driver code segment.
	 * NOTE: Must be system segment to prevent relocation.
	 */
	sp = ssalloc(&r, ip, SFTEXT|SFHIGH|SFNSWP|SFSYST, si+pi+bi, sh, si+pi);

	/*
	 * Release driver object file.
	 */
	idetach(ip);

	if ( r < 0 ) {
		u.u_error = ENOMEM;
		return( -1 );
	}

	/*
	 * Spawn kernel process to service driver.
	 */
	if ((cpp = process(ld_start)) == NULL ) {
		u.u_error = ENOMEM;
		sfree(sp);
		return( -1 );
	}

	/*
	 * Record the basename of the loaded driver.
	 */
	kscopy( u.u_direct.d_name, cpp->p_segp[SIUSERP],
		offset(uproc,u_comm[0]), sizeof(u.u_comm) );

	/*
	 * Record the driver code segment in the process's private code.
	 */
	cpp->p_segp[SIPTEXT] = sp;
	cpp->p_cval = CVCHILD;
	cpp->p_sval = SVCHILD;
	cpp->p_rval = RVCHILD;
	cpp->p_ppid = 1;

	/*
	 * Make the process executable.
	 */
	s = sphi();
	setrun( cpp );
	spl( s );

	/*
	 * Return driver process id.
	 */
	return( cpp->p_pid );
}

/*
 * Given a major number, undo the previous function.
 */
puload(m)
int m;
{
	register CON *cp;
	register DRV *dp;

	dp = &drvl[m];
	lock(dp->d_gate);
	if (m>=drvn || (cp=dp->d_conp)==NULL) {
		u.u_error = ENXIO;
		goto ret;
	}
	(*cp->c_uload)();
	if ( ! u.u_error)
		dp->d_conp = NULL;
ret:
	unlock(dp->d_gate);
	return (0);
}

/*
 * Pass control to an image in a file.
 * Make sure the format is acceptable. Release
 * the old segments. Read in the new ones. Some special
 * care is taken so that shared and (more important) shared
 * and separated images can be run on the 8086.
 */
pexece(np, argp, envp)
char	*np;
char	*argp[];
char	*envp[];
{
	register INODE	*ip;			/* Load file INODE */
	register PROC	*pp;			/* A cheap copy of SELF */
	register SEG	*ssp;			/* New stack segment */
 	register SEG    *segp;
	register fsize_t	ss;			/* Segment size temp. */
	register int	i;			/* For looping over segments */
	int		r;			/* Flag for "exload" */
	int		lflag;			/* l_flags from l.out */
	vaddr_t		pc;			/* l_entry from l.out */
	vaddr_t		sp;			/* Initial stack pointer */
	fsize_t		lssize[NUSEG];		/* Segment sizes */
	fsize_t		codsize;		/* Total if CS segment	*/
	fsize_t		datsize;		/* Total of DS segment	*/
	extern fsize_t	exround();		/* Paragraph rounder */

	pp = SELF;
	if ((ip=exlopen(np, lssize, &lflag, &pc)) == NULL) {
		return;
	}

	if ( (lflag & LF_SEP) == 0 ) {
		u.u_error = EBADFMT;
		idetach(ip);
		return;
	}

	/*
	 * Kernel processes are now supported through the sload() system call.
	 * 87/10/09	Allan Cornish.
	 */
	if ((lflag&LF_KER) != 0) {
		u.u_error = EBADFMT;
		idetach(ip);
		return;
	}

	/*
	 * If a shared and separated image
 	 * has stuff in segments that makes it impossible
	 * to share, give an error immediately so that we don't
	 * lose the parent.
	 */
	lflag &= LF_SHR|LF_SEP;

	if (lflag==(LF_SHR|LF_SEP) && (pi!=0 || bi!=0)) {
		u.u_error = EBADFMT;
		idetach(ip);
		return;
	}

	if ((ssp=exstack(&sp, argp, envp)) == NULL) {
		idetach(ip);
		return;
	}

	switch (lflag) {
	case LF_SEP:
		codsize = si+pi+bi;
		datsize = ssp->s_size+sd+pd+bd;
		break;
	case LF_SHR|LF_SEP:
		codsize = si;
		datsize = ssp->s_size+exround(sd)+pd+bd;
		break;
	}
	codsize = (codsize+(BSIZE-1)) & ~(BSIZE-1);
	datsize = (datsize+(BSIZE-1)) & ~(BSIZE-1);
	if ( (codsize >= MAXU) || (datsize >= MAXU) ) {
		u.u_error = E2BIG;
		idetach(ip);
		return;
	}

	/*
	 * At this point the file has been
	 * validated as an object module, and the
	 * argument list has been built. Release all of
	 * the original segments. At this point we have
	 * committed to the new image. A "sys exec" that
	 * gets an I/O error is doomed.
 	 * NOTE: User-area segment is NOT released.
 	 *	 Segment pointer in proc is erased BEFORE invoking sfree().
	 */
	for ( i = 1; i < NUSEG; ++i ) {
 		if ((segp = pp->p_segp[i]) != NULL) {
			pp->p_segp[i] = NULL;
			sfree(segp);
		}
	}

	/*
	 * Read in the loadable segments.
	 */
	sssp = ssp;
	switch (lflag) {
	case 0:
		ss = si+pi+sd+pd;
		pdsp = ssalloc(&r, ip, 0, ss+bi+bd, sh, ss);
		if (r < 0)
			goto out;
		break;

	case LF_SHR:
		ss = exround(si+sd);
		pdsp = ssalloc(&r, ip, 0, ss+pi+pd+bi+bd, sh, si);
		if (r < 0)
			goto out;
		if (exsread(pdsp, ip, sd, sh+si+pi, si) == NULL)
			goto out;
		if (exsread(pdsp, ip, pi, sh+si, ss) == NULL)
			goto out;
		if (exsread(pdsp, ip, pd, sh+si+pi+sd, ss+pi) == NULL)
			goto out;
		break;

	case LF_SEP:
		pisp = ssalloc(&r, ip, SFTEXT, si+pi+bi, sh, si+pi);
		if (r < 0)
			goto out;
		pdsp = ssalloc(&r, ip, 0, sd+pd+bd, sh+si+pi, sd+pd);
		if (r < 0)
			goto out;
		break;

	case LF_SHR|LF_SEP:
		/* pi=0, bi=0 */
		sisp = ssalloc(&r, ip, SFSHRX|SFTEXT, si, sh, si);
		if (r < 0)
			goto out;
		ss = exround(sd);
		pdsp = ssalloc(&r, ip, 0, ss+pd+bd, sh+si, sd);
		if (r<0 || exsread(pdsp, ip, pd, sh+si+sd, ss) == NULL)
			goto out;
	}
	if (sproto() == 0)
		 goto out;
#if 0
	if ( (datsize != pdsp->s_size) ||
	     ( (lflag==LF_SEP) && (codsize != pisp->s_size) ) ||
	     ( (lflag==(LF_SEP|LF_SHR)) && (codsize != sisp->s_size) ) ) {
		printf("\nExec ERROR:  codsize: 0x%X  datsize: 0x%X\n", 
					codsize, datsize);
		printf(
		"pdsp->s_size: 0x%X  pisp->s_size: 0x%X  sisp->s_size: 0x%X\n",
			pdsp->s_size, pisp->s_size, sisp->s_size);
	}
#endif
	/*
	 * The new image is read in
	 * and mapped. Perform the final grunge
	 * (set-uid stuff, accounting, loading up
	 * registers, etc).
	 */
	u.u_flag &= ~AFORK;
	kkcopy(u.u_direct.d_name, u.u_comm, sizeof(u.u_comm));
	if (iaccess(ip, IPR) == 0) {	/* Can't read ? no dump or trace */
		pp->p_flags |= PFNDMP;
		pp->p_flags &= ~PFTRAC;
	}
	if (iaccess(ip, IPW) == 0)	/* Can't write ? no trace */
		pp->p_flags &= ~PFTRAC;
	if ((ip->i_mode&ISUID) != 0) {	/* Set user id ? no trace */
		pp->p_uid = u.u_uid = ip->i_uid;
		pp->p_flags &= ~PFTRAC;
	}
	if ((ip->i_mode&ISGID) != 0) {	/* Set group id ? no trace */
		u.u_gid = ip->i_gid;
		pp->p_flags &= ~PFTRAC;
	}
	for (i=0; i<NSIG; ++i)
		if (u.u_sfunc[i] != SIG_IGN)
			u.u_sfunc[i] = SIG_DFL;
	if ((pp->p_flags&PFTRAC) != 0)	/* Being traced */
		sendsig(SIGTRAP, pp);
	idetach(ip);
	msetusr(pc, sp);
	segload();
	return (0);

	/*
	 * We did not make it.
	 * Release the INODE for the load
	 * file, and return through the "sys exit"
	 * code with a "SIGSYS", or with the signal actually received
	 * if we are aborting due to interrupted exec.
	 */
out:
	idetach(ip);
	if (u.u_error == EINTR)
		pexit(nondsig());
	pexit(SIGSYS);
}

/*
 * Open an l.out, make sure it is an l.out and executable and return the
 * appropriate information.
 */
INODE *
exlopen(np, ssizep, flagp, pcp)
char *np;
fsize_t *ssizep;
int *flagp;
vaddr_t *pcp;
{
	register INODE *ip;
	register struct ldheader *ldp;
	register int n;
	register BUF *bp;
	int m;

	/*
	 * Make sure the file is really an executable l.out and read the
	 * header in.
	 */
	if (ftoi(np, 'r') != 0)
		return (NULL);
	ip = u.u_cdiri;
	if (iaccess(ip, IPE) == 0) {
		idetach(ip);
		return (NULL);
	}
	if ((ip->i_mode&(IPE|IPE<<3|IPE<<6))==0 || (ip->i_mode&IFMT)!=IFREG) {
		u.u_error = EACCES;
		idetach(ip);
		return (NULL);
	}
	if ((bp=vread(ip, (daddr_t)0)) == NULL) {
		u.u_error = EBADFMT;
		idetach(ip);
		return (NULL);
	}

	/*
	 * Copy everything we need from the l.out header and check magic
	 * number and machine type.
	 */
	ldp = FP_OFF(bp->b_faddr);
	m = ldp->l_magic;
	canint(m);
	if (m != L_MAGIC) {
		u.u_error = ENOEXEC;
		brelease(bp);
		idetach(ip);
		return (NULL);
	}
	m = ldp->l_machine;
	canint(m);
	if (m != mactype) {
		u.u_error = EBADFMT;
		brelease(bp);
		idetach(ip);
		return (NULL);
	}
	kkcopy(ldp->l_ssize, ssizep, NXSEG*sizeof(fsize_t));
	for (n=0; n<NXSEG; n++)
		cansize(ssizep[n]);
	*flagp = ldp->l_flag;
	canint(*flagp);
	*pcp = ldp->l_entry;
	canvaddr(*pcp);
	brelease(bp);
	return (ip);
}

/*
 * Given a segment `sp', read `ss' bytes from the inode `ip' starting
 * at seek address `sa' into offset `so' in the segment.
 */
SEG *
exsread(sp, ip, ss, sa, so)
register SEG *sp;
INODE *ip;
fsize_t ss;
fsize_t sa;
fsize_t so;
{
	while (ss > 0) {
		u.u_io.io_seg = IOPHY;
		u.u_io.io_seek = sa;
		u.u_io.io_phys = sp->s_paddr + so;
		u.u_io.io_flag = 0;
		if (ss >= 4096) {
			u.u_io.io_ioc = 4096;
			ss -= 4096;
		} else {
			u.u_io.io_ioc = ss;
			ss = 0;
		}
		sp->s_lrefc++;
		iread(ip, &u.u_io);
		sp->s_lrefc--;
		if (nondsig()) {
			u.u_error = EINTR;
			break;
		}
		sa += 4096;
		so += 4096;
	}
	if (u.u_error == 0)
		return (sp);
	return (NULL);
}

/*
 * Given a pointer to a list of arguments and a pointer to a list of
 * environments, return a stack with the arguments and environments on it.
 */
SEG *
exstack(iusp, argp, envp)
char **iusp;		/* Back patch sp value */
char *argp[];		/* Arguments for new process */
char *envp[];		/* Environments for new process */
{
	SEG *sp;		/* Stack segment pointer */
	struct adata {		/* Storage for arg and env data */
		char	**up;		/* User vector pointer */
		int	np;		/* Number of pointers in vector */
		int	nc;		/* Number of characters in strings */
	} arg, env;
	struct sdata {		/* To keep segment pointers */
		vaddr_t	base;		/* Top of segment virtual */
		vaddr_t	ap;		/* Argc, argv, envp pointer */
		vaddr_t	vp;		/* Argv[i], envp[i] pointer */
		vaddr_t	cp;		/* Argv[i][j], envp[i][j] pointer */
	} aux, stk;
	aold_t aold;			/* Auxiliary map storage */
	register char **usrvp;		/* Vector pointer into user seg */
	register char *usrcp;		/* Character pointer into user seg */
	register int c;			/* Character fetched from user */
	register int chrsz;		/* Size of strings */
	register struct adata *adp;	/* Arg and env scanner */
	register int vecsz;		/* Size of vectors */
	register int stksz;		/* Size of stack argument region */

	/* Validate and evaluate size of args and envs */
	arg.up = argp;
	env.up = envp;
	chrsz = 0;
	vecsz = 0;
	for (adp = &arg; ; adp = &env) {
		adp->np = 0;
		adp->nc = 0;
		if (excount(adp->up, &adp->np, &adp->nc) == 0)
			return (NULL);
		chrsz += adp->nc * sizeof(char);
		vecsz += adp->np * sizeof(char *);
		if (adp == &env)
			break;
	}

	/* Calculate stack size and allocate it */
	chrsz = roundu(chrsz, sizeof(int));
	stksz = sizeof(int)		/* argc */
		+ sizeof(char **)	/* argv */
		+ sizeof(char **)	/* envp */
		+ vecsz			/* argv[i] and envp[i] */
		+ chrsz			/* *argv[i] and *envp[i] */
		+ sizeof(int)		/* Mystery zero word */
		+ sizeof(char *)	/* Splimit for z8000 */
		+ sizeof(int);		/* errno */
	stksz += ISTSIZE;
	if (stksz > MADSIZE) {
		u.u_error = E2BIG;
		return (NULL);
	}
	if ((sp=salloc((fsize_t)stksz, SFDOWN)) == NULL)
		return (NULL);
	stksz -= ISTSIZE;

	/*
	 * Initialize segment data.
	 */
	asave(aold);

	abase(FP_SEL(sp->s_faddr));
	aux.base = sp->s_size;
	aux.ap = aux.base - stksz;
	aux.vp = aux.ap + sizeof(int) + 2*sizeof(char **);
	aux.cp = aux.vp + vecsz;

	stk.base = ISTVIRT;
	stk.ap = stk.base - stksz;
	stk.vp = stk.ap + sizeof(int) + 2*sizeof(char **);
	stk.cp = stk.vp + vecsz;

	/*
	 * Write argc.
	 */
	aputi((int *)aux.ap, arg.np-1);
	aux.ap += sizeof(int);

	/*
	 * Arguments and environments.
	 */
	for (adp = &arg; ; adp = &env) {

		/* Write argv or envp */
		aputp((char ***)aux.ap, (char **)stk.vp);
		aux.ap += sizeof(char **);
		if ((usrvp = adp->up) != NULL) {

			/* Write argv[i] or envp[i] */
			while ((usrcp = getupd(usrvp++)) != NULL) {
				aputp((char **)aux.vp, (char *)stk.cp);
				aux.vp += sizeof(char *);
				stk.vp += sizeof(char *);

				/* Write argv[i][j] or envp[i][j] */
				do {
					c = getubd(usrcp++);
					aputc((char *)aux.cp, c);
					aux.cp += sizeof(char);
					stk.cp += sizeof(char);
				} while (c != '\0');
			}
		}

		/* Write argv[argc] or envp[envc] */
		aputp((char **)aux.vp, NULL);
		aux.vp += sizeof(char *);
		stk.vp += sizeof(char *);
		if (adp == &env)
			break;
	}

	/*
	 * Clear out the slop.
	 */
	aux.base -= sizeof(int);
	aputi((int *) aux.base, 0);		/* errno */
	aux.base -= sizeof(char *);
	aputp((char **) aux.base, (char *)stk.base - sp->s_size + SOVSIZE);
	aux.base -= sizeof(int);
	aputi((int *) aux.base, 0);		/* mystery word */

	arest(aold);

	/*
	 * Patch some values and return.
	 */
	*iusp = stk.ap;		/* Patch initial usp */
	u.u_argc = arg.np-1;
	u.u_argp = stk.vp;	/* Points after NULL of envs */
	return (sp);
}

/*
 * Given a pointer to a list of arguments, a pointer to an argument count
 * and a pointer to a byte count, update incrementally the argument count
 * and the byte count.
 */
excount(usrvp, nap, nbp)
register char **usrvp;
int *nap;
int *nbp;
{
	register char *usrcp;
	register int c;
	register unsigned nb;
	register unsigned na;

	na = 1;
	nb = 0;
	if (usrvp != NULL) {
		for (;;) {
			usrcp = getupd(usrvp++);
			if (u.u_error)
				return (0);
			if (usrcp == NULL)
				break;
			na++;
			for (;;) {
				c = getubd(usrcp++);
				if (u.u_error)
					return (0);
				nb++;
				if (c == '\0')
					break;
			}
		}
	}
	*nap += na;
	*nbp += nb;
	return (1);
}

/*
 * Round up a size to a paragraph
 * (mod 16) boundry.
 * This is really mod 512 to make swapping work
 */
fsize_t
exround(s)
fsize_t	s;
{
	return ((s+15)&~0x0F);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.