|
|
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);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.