File:  [MW Coherent from dump] / coherent / d / PS2_KERNEL / coh.386 / 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

/* (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.
 *
 *	Intel 386 port and extensions (16/32 bit compatibility)
 *	Copyright (c) Ciaran O'Donnell, Bievres (FRANCE), 1991
 *
 * $Log: exec.c,v $
 * Revision 1.1.1.1  2019/05/29 04:56:39  root
 * coherent
 *
 * Revision 1.10  92/07/16  16:33:31  hal
 * Kernel #58
 * 
 * Revision 1.9  92/06/11  21:39:19  root
 * Add close on exec.
 * 
 * Revision 1.8  92/06/10  12:51:09  hal
 * Do click roundup on call to salloc for eveinit.
 * Assorted cosmetic changes.
 * 
 * Revision 1.6  92/02/11  10:09:57  hal
 * Execute shared l.out's now
 * 
 * Revision 1.5  92/02/10  18:11:27  hal
 * Ignore SHR bit in l.out's for now.
 * 
 * Revision 1.4  92/01/23  18:15:28  hal
 * Add "double sfree" fix from Ciaran.
 * 
 * Revision 1.3  92/01/15  11:11:26  hal
 * Remove exlock temporary fix.
 * 
 * Revision 1.2  92/01/06  11:58:57  hal
 * Compile with cc.mwc.
 * 
 *
 -lgl) */
#include <sys/coherent.h>
#include <acct.h>
#include <sys/buf.h>
#include <canon.h>
#include <sys/con.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/filsys.h>
#include <sys/ino.h>
#include <sys/inode.h>
#include <a.out.h>
#include <l.out.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/seg.h>
#include <signal.h>
#include <sys/reg.h>
#include <sys/stat.h>
#include <sys/fd.h>

/*
 * 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[];
{
	struct xechdr	head;
	register INODE	*ip;			/* Load file INODE */
	register PROC	*pp;			/* A cheap copy of SELF */
 	register SEG    *segp;
	SEG	*ssegp;
	register int	i;			/* For looping over segments*/
	register BUF *bp;
	int roundup;
	int shrdsize;

	pp = SELF;
	kclear(&head, sizeof(head)); 
	if ((ip=exlopen(&head, np, &shrdsize)) == NULL)
		goto done;
	roundup = (shrdsize) & 0xf;
	ssegp = exstack(&head,argp, envp, wdsize());

	if (!ssegp) {
		idetach(ip);
		goto done;
	}

	/*
	 * 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);
		}
	}
	pp->p_segp[SISTACK] = ssegp;

	/*
	 * Read in the loadable segments.
	 */
	switch (head.magic) {
	case XMAGIC(	I286MAGIC,I_MAGIC	):
		u.u_regl[CS] = SEG_286_UII | R_USR;
		u.u_regl[DS] = SEG_286_UD  | R_USR;
		segp = pp->p_segp[SISTEXT] = ssalloc(ip,SFTEXT,
		  head.segs[SISTEXT].size);
		if (!exsread(segp, ip, &head.segs[SISTEXT], 0)) {
			goto out;
		}
		segp = ssalloc(ip,0,roundup+
		  head.segs[SIPDATA].size+head.segs[SIBSS].size);
		pp->p_segp[SIPDATA] = segp;
		if (!exsread(segp,ip,&head.segs[SIPDATA],shrdsize)) {
			goto out;
		}
		head.segs[SIPDATA].size += roundup;
		break;
	case XMAGIC(	I386MAGIC,Z_MAGIC	):
		u.u_regl[CS] = SEG_386_UI | R_USR;
		u.u_regl[DS] = SEG_386_UD | R_USR;
		segp = pp->p_segp[SISTEXT] = ssalloc(ip,SFTEXT|SFSHRX,
				head.segs[SISTEXT].size);
		if (segp->s_ip==0) {
			if (!exsread(segp, ip, &head.segs[SISTEXT], 0)) {
				goto out;
			}
			segp->s_ip = ip;
			ip->i_refc++;
		}
		segp = ssalloc(ip,0,
		  head.segs[SIPDATA].size+head.segs[SIBSS].size);
		pp->p_segp[SIPDATA] = segp;
		if (segp->s_ip==0 &&
		    !exsread(segp, ip, &head.segs[SIPDATA], 0)) {
			goto out;
		}
		break;
	default:
		panic("pexece");
	}

	u.u_regl[SS] = u.u_regl[ES] = u.u_regl[DS];
	if (sproto(&head) == 0) {
		goto out;
	}

	/*
	 * 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;
	}

	/*
	 * Norm says Frank says we need to drop this for db to work.
	 */
	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 < NUFILE; i++) {
		if (u.u_filep[i]!=NULL && (u.u_filep[i]->f_flag2&FD_CLOEXEC))  {
			fdclose(i);	/* close fd on exec bit set */
		}
	}
	/*
	 * Default every signal that is not ignored.
	 */
	for (i=0; i<NSIG; ++i) {
		if (u.u_sfunc[i] != SIG_IGN) {
			u.u_sfunc[i] = SIG_DFL;
			pp->p_dfsig |= ((sig_t) 1) << (i - 1);
		}
	}
	if ((pp->p_flags&PFTRAC) != 0)	/* Being traced */
		sendsig(SIGTRAP, pp);
	idetach(ip);
	msetusr(head.entry, head.initsp);

	segload();
	goto done;

	/*
	 * 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);

done:
	return 0;	
}

/*
 * Open an l.out, make sure it is an l.out and executable and return the
 * appropriate information.
 */
INODE *
exlopen(xhp, np, shrds) 
register struct xechdr *xhp;
char *np;
int *shrds;
{
	register INODE *ip;
	int	i, nscn, diff, hdrsize;
	register BUF *bp;
	unsigned short magic;
	struct ldheader head;
	struct filehdr fhead;
	struct aouthdr ahead;	
	struct scnhdr scnhdr;

	/*
	 * 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)
		goto bad;
	/*
	 * Copy everything we need from the l.out header and check magic
	 * number and machine type.
	 */
	*shrds = 0;  /* set return arg shrds nonzero only for shared l.out */
	kkcopy(bp->b_vaddr, &magic, sizeof(magic));
	canint(magic);
	switch (magic) {
	case L_MAGIC:		/* Coherent 286 format */
		kkcopy(bp->b_vaddr, &head, sizeof(struct ldheader));
		canint(head.l_machine);
		if (head.l_machine!=M_8086)
			goto bad;
		for (i=0; i<NXSEG; i++) {
			cansize(head.l_ssize[i]);
		}	
		canint(head.l_flag);
		canvaddr(head.l_entry);

		/*
		 * 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.
		 */
		head.l_flag &= LF_SHR|LF_SEP|LF_KER;

		if ((head.l_flag&LF_SEP==0) || (head.l_flag &LF_KER)
		  || head.l_ssize[L_PRVI] || head.l_ssize[L_BSSI]) {
			goto bad;
		}
		xhp->magic = XMAGIC(	I286MAGIC,I_MAGIC	);
		xhp->entry = head.l_entry;

		xhp->segs[SISTEXT].fbase = sizeof(struct ldheader);
		xhp->segs[SISTEXT].mbase = NBPS;
		xhp->segs[SISTEXT].size = head.l_ssize[L_SHRI];

		xhp->segs[SIPDATA].fbase = sizeof(struct ldheader) +
			xhp->segs[SISTEXT].size;
		xhp->segs[SIPDATA].mbase = 0;
		xhp->segs[SIPDATA].size = head.l_ssize[L_SHRD] +
			head.l_ssize[L_PRVD];
		if (head.l_flag & LF_SHR)
			*shrds = head.l_ssize[L_SHRD];

		xhp->segs[SIBSS].fbase = 0;
		xhp->segs[SIBSS].mbase = xhp->segs[SIPDATA].size;
		xhp->segs[SIBSS].size = head.l_ssize[L_BSSD];

		xhp->segs[SISTACK].mbase = ISP_286;	/* size 0, fbase 0 */
		brelease(bp);
		return ip;

	case I386MAGIC:		/* ... COFF */
		kkcopy(bp->b_vaddr, &fhead, sizeof(struct filehdr));
		hdrsize = sizeof(ahead)+sizeof(fhead);
		if(fhead.f_opthdr!=sizeof (ahead) || !(fhead.f_flags&F_EXEC)||
		fhead.f_nscns*sizeof(scnhdr) > BSIZE)
			goto bad;

		kkcopy(bp->b_vaddr+sizeof(fhead), &ahead, sizeof(ahead));
		if ((/*ahead.magic!=O_MAGIC && ahead.magic!=N_MAGIC && */
		     ahead.magic!=Z_MAGIC))
			goto bad;

		xhp->magic = XMAGIC(	I386MAGIC,ahead.magic	);
		xhp->entry = ahead.entry;

		for (i=0; i<fhead.f_nscns; i++) {
			kkcopy(bp->b_vaddr + hdrsize + sizeof(scnhdr)*i,
				&scnhdr, sizeof(scnhdr));
			switch ((int)(scnhdr.s_flags)) {
			case STYP_INFO:
				continue;
			case STYP_BSS:
				nscn = SIBSS;
				break;
			case STYP_TEXT:
				nscn = SISTEXT;	goto common;
			case STYP_DATA:
				nscn = SIPDATA;
			common:
				diff = scnhdr.s_scnptr & (NBPC-1);
				scnhdr.s_vaddr -= diff;
				scnhdr.s_scnptr -= diff;
				scnhdr.s_size += diff;
				break;
			default:
				goto bad;
			}

			if (xhp->segs[nscn].size!=0
			||  (unsigned)scnhdr.s_vaddr >= ISP_386)
				goto bad;

			xhp->segs[nscn].mbase = scnhdr.s_vaddr;
			xhp->segs[nscn].fbase = scnhdr.s_scnptr;
			xhp->segs[nscn].size = scnhdr.s_size;
		}

		if (!xhp->segs[SISTEXT].size || !xhp->segs[SIPDATA].size)
			goto bad;

		xhp->entry = ahead.entry;
		if (xhp->entry >= xhp->segs[SISTEXT].size)
			goto bad;

		xhp->segs[SISTACK].mbase = ISP_386;	/* size 0, fbase 0 */
		xhp->magic = XMAGIC(	I386MAGIC,ahead.magic	);
		brelease(bp);	
		return ip;
	default:
	bad:		
		brelease(bp);
		u.u_error = ENOEXEC;
		idetach(ip);
		return NULL;
	}
}

/*
 * Given a segment `sp', read `ss' bytes from the inode `ip' starting
 * at seek address `sa' into offset `so' in the segment.
 *
 * Argument "first" is nonzero only when loading data for l.out -
 * need this because *shared* l.out's need PRVD to be aligned on the next
 * 16 byte boundary after the end of SHRD.  So we need to leave a hole
 * between SHRD and PRVD in this case.
 */
static SEG *
exsread(sp, ip, xsp, first)
register SEG *sp;
INODE *ip;
struct xecseg *xsp;
int first;
{
	register int ss, sa, so, did;
	int overshoot;

	sa = xsp->fbase;
	so = 0;

	for (ss = first ? first : xsp->size;; ss -= did) {
		if (!ss) {	/* we finished a hunk */
			/* is there more to read */
			if (!first || (!(ss = xsp->size - first)))
				break;
			so = (so + 15) & ~15; /* round up */
			first = 0;	/* don't go again */
		}
		u.u_io.io_seg = IOPHY;
		u.u_io.io_seek = sa;
		u.u_io.io.pbase = MAPIO(sp->s_vmem, so);
		u.u_io.io_flag = 0;
		/*
		 * "did" is how many bytes to read in with this request.
		 */
		if (ss >= 4096)
			did = u.u_io.io_ioc = 4096;
		else
			did = u.u_io.io_ioc = ss;
		/*
		 * Don't allow incoming data to straddle a 4k segment.
		 */
		overshoot = did + (so & 4095) - 4096;
		if (overshoot > 0)
			did -= overshoot;
		sp->s_lrefc++;
		iread(ip, &u.u_io);
		sp->s_lrefc--;
		if (nondsig()) {
			u.u_error = EINTR;
			break;
		}
		sa += did;
		so += did;
	}
	if (u.u_error == 0)
		return (sp);
	return (NULL);
}

struct adata {		/* Storage for arg and env data */
	int	np;		/* Number of pointers in vector */
	int	nc;		/* Number of characters in strings */
};

/*
 * 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(xhp, argp, envp, wdin)
register struct xechdr *xhp;
vaddr_t	argp, envp;
{
	register SEG *sp;		/* Stack segment pointer */
	struct sdata {		/* To keep segment pointers */
		vaddr_t	vp;		/* Argv[i], envp[i] pointer */
		vaddr_t	cp;		/* Argv[i][j], envp[i][j] pointer */
	} stk;
	struct adata arg, env;
	int	chrsz, vecsz, stksz, wdmask, wdout, stkoff, stktop;
	int	stkenvp;
	register int i;

	/* Validate and evaluate size of args and envs */
	if (!excount(argp, &arg, wdin) || !excount(envp, &env, wdin))
		return NULL;

	/* Calculate stack size and allocate it */
	chrsz = roundu(arg.nc + env.nc, sizeof(int));
	vecsz = (arg.np+1 + env.np+1) * sizeof(long);
	stksz = roundu(vecsz+chrsz+ISTSIZE, NBPC);
	if (stksz > MADSIZE || !(sp = salloc(stksz, SFDOWN))) {
		u.u_error = E2BIG;
		return NULL;
	}

	/* Set up target stack */
	stktop = xhp->segs[SISTACK].mbase;
	stk.cp = stktop - chrsz;
	stk.vp = stktop - chrsz - vecsz;
	stkoff = MAPIO(sp->s_vmem, stksz - stktop);
	u.u_argc = arg.np;
	u.u_argp = stk.vp;
	wdmask = -1;
	if (wdin==sizeof(short))
		wdmask = (unsigned short)wdmask;

	switch (stktop) {

	case ISP_386:
		wdout = sizeof(long);
		xhp->initsp = stk.vp - sizeof(long);
		dmaout(sizeof(long), xhp->initsp+stkoff, &arg.np);
		break;

	case ISP_286:
		wdout = sizeof(short);
		xhp->initsp = stk.vp - 3*sizeof(short);
		stkenvp = stk.vp + (arg.np+1) * sizeof(short);
		dmaout(sizeof(short), xhp->initsp+stkoff, &arg.np);
		dmaout(sizeof(short), xhp->initsp+sizeof(short)+stkoff,
			&stk.vp);
		dmaout(sizeof(short), xhp->initsp+2*sizeof(short)+stkoff,
			&stkenvp);
		break;

	default:
		panic("exstack");

	}

	/* Arguments */
	for (i = 0; i<arg.np; i++, argp += wdin, stk.vp += wdout) {
		dmaout(wdout, stk.vp+stkoff, &stk.cp);
		stk.cp += exarg(stk.cp+stkoff, getupd(argp) & wdmask);
	}

	/* skip null word after arguments */
	stk.vp += wdout;

	/* Environments */
	for (i = 0; i<env.np; i++, envp += wdin, stk.vp += wdout) {
		dmaout(wdout, stk.vp+stkoff, &stk.cp);
		stk.cp += exarg(stk.cp+stkoff, getupd(envp) & wdmask);
	}

	return sp;
}

exarg(out, in)
vaddr_t	in, out;
{
	char 	c;
	vaddr_t	init_in;

	init_in = in;
	do {
		c = getubd(in++);
		dmaout(sizeof(char), out++, &c);
	} while (c);
	return in - init_in;
}


/*
 * Given a pointer to a list of arguments, a pointer to an argument count
 * and a pointer to a byte count, count the #characters/#strigns
 * in the arguments
 */
excount(usrvp, adp, wdin)
register vaddr_t usrvp;
struct adata *adp;
{
	register vaddr_t	usrcp;
	register int c;
	register unsigned nb;
	register unsigned na;
	int	wdmask;

	wdmask = -1;
	if (wdin==sizeof(short))
		wdmask = (unsigned short)wdmask;
	na = nb = 0;
	if (usrvp != NULL) {
		for (;;) {
			usrcp = getupd(usrvp) & wdmask;
			usrvp += wdin;
			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;
			}
		}
	}
	adp->np = na;
	adp->nc = nb;
	return (1);
}

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

pload( np )
char * np;
{
	return -1;

}
/*
 * Set up the first process, a small programme which will exec
 * the init programme.
 */
eveinit()
{
	SEG *sp;
	register PROC *pp;
	SELF = pp = eprocp;
/*	static struct xechdr xecinit[NUSEG+1] = { {0},{0},{0},{ISP_386}}; */ 

	/*
	 * Allocate, record, initialize code segment, make it executable.
	 */
	if ((sp = salloc(roundu(icodes, NBPC), 0)) == NULL)
		panic("eveinit(code)");
	pp->p_segp[SIPDATA] = sp;

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

/*
 * 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);
}


unix.superglobalmegacorp.com

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