1245 lines · 24.6 KB · C
RawDownload
#include	"u.h"#include	"tos.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"edf.h" #include	<a.out.h> extern void checkpages(void);extern void checkpagerefs(void); uintptrsysr1(va_list){	if(!iseve())		error(Eperm);	checkpagerefs();	return 0;} static voidabortion(void*){	pexit("fork aborted", 1);} uintptrsysrfork(va_list list){	Proc *p;	int n, i;	Fgrp *ofg;	Pgrp *opg;	Rgrp *org;	Egrp *oeg;	ulong pid, flag;	Mach *wm; 	flag = va_arg(list, ulong);	/* Check flags before we commit */	if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))		error(Ebadarg);	if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))		error(Ebadarg);	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))		error(Ebadarg); 	if((flag&RFPROC) == 0) {		if(flag & (RFMEM|RFNOWAIT))			error(Ebadarg);		if(flag & (RFFDG|RFCFDG)) {			ofg = up->fgrp;			if(flag & RFFDG)				up->fgrp = dupfgrp(ofg);			else				up->fgrp = dupfgrp(nil);			closefgrp(ofg);		}		if(flag & (RFNAMEG|RFCNAMEG)) {			opg = up->pgrp;			up->pgrp = newpgrp();			if(flag & RFNAMEG)				pgrpcpy(up->pgrp, opg);			/* inherit noattach */			up->pgrp->noattach = opg->noattach;			closepgrp(opg);		}		if(flag & RFNOMNT)			up->pgrp->noattach = 1;		if(flag & RFREND) {			org = up->rgrp;			up->rgrp = newrgrp();			closergrp(org);		}		if(flag & (RFENVG|RFCENVG)) {			oeg = up->egrp;			up->egrp = smalloc(sizeof(Egrp));			up->egrp->ref = 1;			if(flag & RFENVG)				envcpy(up->egrp, oeg);			closeegrp(oeg);		}		if(flag & RFNOTEG)			up->noteid = pidalloc(0);		return 0;	} 	p = newproc(); 	p->scallnr = up->scallnr;	p->s = up->s;	p->nerrlab = 0;	p->slash = up->slash;	p->dot = up->dot;	incref(p->dot); 	memmove(p->note, up->note, sizeof(p->note));	p->privatemem = up->privatemem;	p->noswap = up->noswap;	p->nnote = up->nnote;	p->notified = 0;	p->lastnote = up->lastnote;	p->notify = up->notify;	p->ureg = up->ureg;	p->dbgreg = 0; 	/* Abort the child process on error */	if(waserror()){		p->kp = 1;		kprocchild(p, abortion, 0);		ready(p);		nexterror();	} 	/* Make a new set of memory segments */	n = flag & RFMEM;	qlock(&p->seglock);	if(waserror()){		qunlock(&p->seglock);		nexterror();	}	for(i = 0; i < NSEG; i++)		if(up->seg[i] != nil)			p->seg[i] = dupseg(up->seg, i, n);	qunlock(&p->seglock);	poperror(); 	/* File descriptors */	if(flag & (RFFDG|RFCFDG)) {		if(flag & RFFDG)			p->fgrp = dupfgrp(up->fgrp);		else			p->fgrp = dupfgrp(nil);	}	else {		p->fgrp = up->fgrp;		incref(p->fgrp);	} 	/* Process groups */	if(flag & (RFNAMEG|RFCNAMEG)) {		p->pgrp = newpgrp();		if(flag & RFNAMEG)			pgrpcpy(p->pgrp, up->pgrp);		/* inherit noattach */		p->pgrp->noattach = up->pgrp->noattach;	}	else {		p->pgrp = up->pgrp;		incref(p->pgrp);	}	if(flag & RFNOMNT)		p->pgrp->noattach = 1; 	if(flag & RFREND)		p->rgrp = newrgrp();	else {		incref(up->rgrp);		p->rgrp = up->rgrp;	} 	/* Environment group */	if(flag & (RFENVG|RFCENVG)) {		p->egrp = smalloc(sizeof(Egrp));		p->egrp->ref = 1;		if(flag & RFENVG)			envcpy(p->egrp, up->egrp);	}	else {		p->egrp = up->egrp;		incref(p->egrp);	}	p->hang = up->hang;	p->procmode = up->procmode;	if(up->procctl == Proc_tracesyscall)		p->procctl = Proc_tracesyscall; 	poperror();	/* abortion */ 	/* Craft a return frame which will cause the child to pop out of	 * the scheduler in user mode with the return register zero	 */	forkchild(p, up->dbgreg); 	p->parent = up;	if((flag&RFNOWAIT) == 0){		p->parentpid = up->pid;		lock(&up->exl);		up->nchild++;		unlock(&up->exl);	}	if((flag&RFNOTEG) == 0)		p->noteid = up->noteid; 	pid = p->pid;	memset(p->time, 0, sizeof(p->time));	p->time[TReal] = MACHP(0)->ticks; 	kstrdup(&p->text, up->text);	kstrdup(&p->user, up->user); 	procfork(p); 	/*	 *  since the bss/data segments are now shareable,	 *  any mmu info about this process is now stale	 *  (i.e. has bad properties) and has to be discarded.	 */	flushmmu();	p->basepri = up->basepri;	p->priority = up->basepri;	p->fixedpri = up->fixedpri;	p->mp = up->mp;	wm = up->wired;	if(wm)		procwired(p, wm->machno);	ready(p);	sched();	return pid;} static intshargs(char *s, int n, char **ap){	int i; 	s += 2;	n -= 2;		/* skip #! */	for(i=0;; i++){		if(i >= n)			return 0;		if(s[i]=='\n')			break;	}	s[i] = 0; 	i = 0;	for(;;) {		while(*s==' ' || *s=='\t')			s++;		if(*s == 0)			break;		ap[i++] = s++;		while(*s && *s!=' ' && *s!='\t')			s++;		if(*s == 0)			break;		*s++ = 0;	}	ap[i] = nil;	return i;} static ulongl2be(long l){	uchar *cp; 	cp = (uchar*)&l;	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];} uintptrsysexec(va_list list){	Segment *s, *ts;	int i;	Chan *tc;	char **argv, **argp, **argp0;	char *a, *e, *charp, *args, *file, *file0;	char *progarg[sizeof(Exec)/2+1], *elem, progelem[64];	ulong magic, ssize, nargs, nbytes, n;	uintptr t, d, b, entry, bssend, text, data, bss, tstk, align;	int indir;	Exec exec;	char line[sizeof(Exec)];	Fgrp *f;	Image *img;	Tos *tos; 	args = elem = nil;	file0 = va_arg(list, char*);	validaddr((uintptr)file0, 1, 0);	argp0 = va_arg(list, char**);	evenaddr((uintptr)argp0);	validaddr((uintptr)argp0, 2*BY2WD, 0);	if(*argp0 == nil)		error(Ebadarg);	file0 = validnamedup(file0, 1);	if(waserror()){		free(file0);		free(elem);		free(args);		/* Disaster after commit */		if(up->seg[SSEG] == nil)			pexit(up->errstr, 1);		s = up->seg[ESEG];		if(s != nil){			putseg(s);			up->seg[ESEG] = nil;		}		nexterror();	}	align = BY2PG;	indir = 0;	file = file0;	for(;;){		tc = namec(file, Aopen, OEXEC, 0);		if(waserror()){			cclose(tc);			nexterror();		}		if(!indir)			kstrdup(&elem, up->genbuf); 		n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);		if(n <= 2)			error(Ebadexec);		magic = l2be(exec.magic);		if(n == sizeof(Exec) && (magic == AOUT_MAGIC)){			entry = l2be(exec.entry);			text = l2be(exec.text);			if(magic & HDR_MAGIC)				text += 8;			switch(magic){			case S_MAGIC:	/* 2MB segment alignment for amd64 */				align = 0x200000;				break;			case V_MAGIC:	/* 16K segment alignment for mips */				align = 0x4000;				break;			}			if(text >= (USTKTOP-USTKSIZE)-(UTZERO+sizeof(Exec))			|| entry < UTZERO+sizeof(Exec)			|| entry >= UTZERO+sizeof(Exec)+text)				error(Ebadexec);			break; /* for binary */		} 		/*		 * Process #! /bin/sh args ...		 */		memmove(line, &exec, n);		if(indir || line[0]!='#' || line[1]!='!')			error(Ebadexec);		n = shargs(line, n, progarg);		if(n < 1)			error(Ebadexec);		indir = 1;		/*		 * First arg becomes complete file name		 */		progarg[n++] = file;		progarg[n] = nil;		argp0++;		file = progarg[0];		if(strlen(elem) >= sizeof progelem)			error(Ebadexec);		strcpy(progelem, elem);		progarg[0] = progelem;		poperror();		cclose(tc);	} 	data = l2be(exec.data);	bss = l2be(exec.bss);	align--;	t = (UTZERO+sizeof(Exec)+text+align) & ~align;	align = BY2PG-1;	d = (t + data + align) & ~align;	bssend = t + data + bss;	b = (bssend + align) & ~align;	if(t >= (USTKTOP-USTKSIZE) || d >= (USTKTOP-USTKSIZE) || b >= (USTKTOP-USTKSIZE))		error(Ebadexec); 	/*	 * Args: pass 1: count	 */	nbytes = sizeof(Tos);		/* hole for profiling clock at top of stack (and more) */	nargs = 0;	if(indir){		argp = progarg;		while(*argp != nil){			a = *argp++;			nbytes += strlen(a) + 1;			nargs++;		}	}	argp = argp0;	while(*argp != nil){		a = *argp++;		if(((uintptr)argp&(BY2PG-1)) < BY2WD)			validaddr((uintptr)argp, BY2WD, 0);		validaddr((uintptr)a, 1, 0);		e = vmemchr(a, 0, USTKSIZE);		if(e == nil)			error(Ebadarg);		nbytes += (e - a) + 1;		if(nbytes >= USTKSIZE)			error(Enovmem);		nargs++;	}	ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); 	/*	 * 8-byte align SP for those (e.g. sparc) that need it.	 * execregs() will subtract another 4 bytes for argc.	 */	if(BY2WD == 4 && (ssize+4) & 7)		ssize += 4; 	if(PGROUND(ssize) >= USTKSIZE)		error(Enovmem); 	/*	 * Build the stack segment, putting it in kernel virtual for the moment	 */	qlock(&up->seglock);	if(waserror()){		qunlock(&up->seglock);		nexterror();	} 	s = up->seg[SSEG];	do {		tstk = s->base;		if(tstk <= USTKSIZE)			error(Enovmem);	} while((s = isoverlap(tstk-USTKSIZE, USTKSIZE)) != nil);	up->seg[ESEG] = newseg(SG_STACK, tstk-USTKSIZE, USTKSIZE/BY2PG); 	/*	 * Args: pass 2: assemble; the pages will be faulted in	 */	tos = (Tos*)(tstk - sizeof(Tos));	tos->cyclefreq = m->cyclefreq;	tos->kcycles = 0;	tos->pcycles = 0;	tos->clock = 0; 	argv = (char**)(tstk - ssize);	charp = (char*)(tstk - nbytes);	if(indir)		argp = progarg;	else		argp = argp0; 	for(i=0; i<nargs; i++){		if(indir && *argp==nil) {			indir = 0;			argp = argp0;		}		*argv++ = charp + (USTKTOP-tstk);		a = *argp++;		if(indir)			e = strchr(a, 0);		else {			validaddr((uintptr)a, 1, 0);			e = vmemchr(a, 0, (char*)tstk - charp);			if(e == nil)				error(Ebadarg);		}		n = (e - a) + 1;		memmove(charp, a, n);		charp += n;	} 	/* copy args; easiest from new process's stack */	a = (char*)(tstk - nbytes);	n = charp - a;	if(n > 128)	/* don't waste too much space on huge arg lists */		n = 128;	args = smalloc(n);	memmove(args, a, n);	if(n>0 && args[n-1]!='\0'){		/* make sure last arg is NUL-terminated */		/* put NUL at UTF-8 character boundary */		for(i=n-1; i>0; --i)			if(fullrune(args+i, n-i))				break;		args[i] = 0;		n = i+1;	} 	/*	 * Committed.	 * Free old memory.	 * Special segments are maintained across exec	 */	for(i = SSEG; i <= BSEG; i++) {		putseg(up->seg[i]);		/* prevent a second free if we have an error */		up->seg[i] = nil;	}	for(i = ESEG+1; i < NSEG; i++) {		s = up->seg[i];		if(s != nil && (s->type&SG_CEXEC) != 0) {

Lines 1–500 of 1245.