#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include int shargs(char*, int, char**); long sysr1(ulong *arg) { xsummary(); print("[%s %s %d] r1 = %d\n", u->p->user, u->p->text, u->p->pid, arg[0]); return 0; } long sysrfork(ulong *arg) { KMap *k; Pgrp *opg; Egrp *oeg; Fgrp *ofg; int n, i; Proc *p, *parent; ulong upa, pid, flag; /* * used to compute last valid system stack address for copy */ int lastvar; flag = arg[0]; p = u->p; if((flag&RFPROC) == 0) { if(flag & (RFNAMEG|RFCNAMEG)) { if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG)) error(Ebadarg); opg = p->pgrp; p->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(p->pgrp, opg); else *p->pgrp->crypt = *opg->crypt; closepgrp(opg); } if(flag & (RFENVG|RFCENVG)) { if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG)) error(Ebadarg); oeg = p->egrp; p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; if(flag & RFENVG) envcpy(p->egrp, oeg); closeegrp(oeg); } if(flag & RFFDG) { ofg = p->fgrp; p->fgrp = dupfgrp(ofg); closefgrp(ofg); } else if(flag & RFCFDG) { ofg = p->fgrp; p->fgrp = smalloc(sizeof(Fgrp)); p->fgrp->ref = 1; closefgrp(ofg); } if(flag & RFNOTEG) p->noteid = incref(¬eidalloc); if(flag & (RFMEM|RFNOWAIT)) error(Ebadarg); return 0; } /* 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); p = newproc(); parent = u->p; /* Page va of upage used as check in mapstack */ p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF)); k = kmap(p->upage); upa = VA(k); /* Save time: only copy u-> data and useful stack */ memmove((void*)upa, u, sizeof(User)); n = USERADDR+BY2PG - (ulong)&lastvar; n = (n+32) & ~(BY2WD-1); memmove((void*)(upa+BY2PG-n), (void*)(USERADDR+BY2PG-n), n); ((User *)upa)->p = p; kunmap(k); /* Make a new set of memory segments */ n = flag & RFMEM; for(i = 0; i < NSEG; i++) if(parent->seg[i]) p->seg[i] = dupseg(parent->seg[i], n); /* Refs */ incref(u->dot); /* File descriptors */ if(flag & (RFFDG|RFCFDG)) { if(flag & RFFDG) p->fgrp = dupfgrp(parent->fgrp); else { p->fgrp = smalloc(sizeof(Fgrp)); p->fgrp->ref = 1; } } else { p->fgrp = parent->fgrp; incref(p->fgrp); } /* Process groups */ if(flag & (RFNAMEG|RFCNAMEG)) { if(flag & RFNAMEG) { p->pgrp = newpgrp(); pgrpcpy(p->pgrp, parent->pgrp); } else { p->pgrp = newpgrp(); *p->pgrp->crypt = *parent->pgrp->crypt; } } else { p->pgrp = parent->pgrp; incref(p->pgrp); } /* Environment group */ if(flag & (RFENVG|RFCENVG)) { p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; if(flag & RFENVG) envcpy(p->egrp, parent->egrp); } else { p->egrp = parent->egrp; incref(p->egrp); } p->hang = parent->hang; p->procmode = parent->procmode; if(setlabel(&p->sched)){ /* * use u->p instead of p, because we don't trust the compiler, after a * gotolabel, to find the correct contents of a local variable. */ p = u->p; p->state = Running; p->mach = m; m->proc = p; spllo(); return 0; } p->parent = parent; p->parentpid = parent->pid; if(flag&RFNOWAIT) p->parentpid = 1; else { lock(&parent->exl); parent->nchild++; unlock(&parent->exl); } if((flag&RFNOTEG) == 0) p->noteid = parent->noteid; p->fpstate = parent->fpstate; pid = p->pid; memset(p->time, 0, sizeof(p->time)); p->time[TReal] = MACHP(0)->ticks; memmove(p->text, parent->text, NAMELEN); memmove(p->user, parent->user, NAMELEN); /* * 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(); ready(p); return pid; } static ulong l2be(long l) { uchar *cp; cp = (uchar*)&l; return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3]; } long sysexec(ulong *arg) { Proc *p; Segment *s, *ts; ulong t, d, b; int i; Chan *tc; char **argv, **argp; char *a, *charp, *file; char *progarg[sizeof(Exec)/2+1], elem[NAMELEN]; ulong ssize, spage, nargs, nbytes, n, bssend; int indir; Exec exec; char line[sizeof(Exec)]; Fgrp *f; Image *img; ulong magic, text, entry, data, bss; p = u->p; validaddr(arg[0], 1, 0); file = (char*)arg[0]; indir = 0; Header: tc = namec(file, Aopen, OEXEC, 0); if(waserror()){ close(tc); nexterror(); } if(!indir) strcpy(elem, u->elem); n = (*devtab[tc->type].read)(tc, &exec, sizeof(Exec), 0); if(n < 2) Err: error(Ebadexec); magic = l2be(exec.magic); text = l2be(exec.text); entry = l2be(exec.entry); if(n==sizeof(Exec) && magic==AOUT_MAGIC){ if((text&KZERO) || entry < UTZERO+sizeof(Exec) || entry >= UTZERO+sizeof(Exec)+text) goto Err; goto Binary; } /* * Process #! /bin/sh args ... */ memmove(line, &exec, sizeof(Exec)); if(indir || line[0]!='#' || line[1]!='!') goto Err; n = shargs(line, n, progarg); if(n == 0) goto Err; indir = 1; /* * First arg becomes complete file name */ progarg[n++] = file; progarg[n] = 0; validaddr(arg[1], BY2WD, 1); arg[1] += BY2WD; file = progarg[0]; progarg[0] = elem; poperror(); close(tc); goto Header; Binary: poperror(); data = l2be(exec.data); bss = l2be(exec.bss); t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1); d = (t + data + (BY2PG-1)) & ~(BY2PG-1); bssend = t + data + bss; b = (bssend + (BY2PG-1)) & ~(BY2PG-1); if((t|d|b) & KZERO) error(Ebadexec); /* * Args: pass 1: count */ nbytes = BY2WD; /* hole for profiling clock at top of stack */ nargs = 0; if(indir){ argp = progarg; while(*argp){ a = *argp++; nbytes += strlen(a) + 1; nargs++; } } evenaddr(arg[1]); argp = (char**)arg[1]; validaddr((ulong)argp, BY2WD, 0); while(*argp){ a = *argp++; if(((ulong)argp&(BY2PG-1)) < BY2WD) validaddr((ulong)argp, BY2WD, 0); validaddr((ulong)a, 1, 0); nbytes += (vmemchr(a, 0, 0xFFFFFFFF) - a) + 1; 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((ssize+4) & 7) ssize += 4; spage = (ssize+(BY2PG-1)) >> PGSHIFT; /* * Build the stack segment, putting it in kernel virtual for the moment */ if(spage > TSTKSIZ) error(Enovmem); p->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); /* * Args: pass 2: assemble; the pages will be faulted in */ argv = (char**)(TSTKTOP - ssize); charp = (char*)(TSTKTOP - nbytes); if(indir) argp = progarg; else argp = (char**)arg[1]; for(i=0; itext, elem, NAMELEN); /* * Committed. Free old memory. Special segments are maintained accross exec */ for(i = SSEG; i <= BSEG; i++) { putseg(p->seg[i]); p->seg[i] = 0; /* prevent a second free if we have an error */ } /* * Close on exec */ f = u->p->fgrp; for(i=0; i<=f->maxfd; i++) fdclose(i, CCEXEC); /* Text. Shared. Attaches to cache image if possible */ /* attachimage returns a locked cache image */ img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT); ts = img->s; p->seg[TSEG] = ts; ts->flushme = 1; ts->fstart = 0; ts->flen = sizeof(Exec)+text; unlock(img); /* Data. Shared. */ s = newseg(SG_DATA, t, (d-t)>>PGSHIFT); p->seg[DSEG] = s; /* Attached by hand */ incref(img); s->image = img; s->fstart = ts->fstart+ts->flen; s->flen = data; /* BSS. Zero fill on demand */ p->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT); /* * Move the stack */ s = p->seg[ESEG]; p->seg[ESEG] = 0; p->seg[SSEG] = s; s->base = USTKTOP-USTKSIZE; s->top = USTKTOP; relocateseg(s, TSTKTOP-USTKTOP); close(tc); /* * At this point, the mmu contains info about the old address * space and needs to be flushed */ flushmmu(); qlock(&p->debug); u->nnote = 0; u->notify = 0; u->notified = 0; procsetup(p); qunlock(&p->debug); if(p->hang) p->procctl = Proc_stopme; return execregs(entry, ssize, nargs); } int shargs(char *s, int n, char **ap) { int i; s += 2, n -= 2; /* skip #! */ for(i=0; s[i]!='\n'; i++) if(i == n-1) return 0; s[i] = 0; *ap = 0; i = 0; for(;;){ while(*s==' ' || *s=='\t') s++; if(*s == 0) break; i++; *ap++ = s; *ap = 0; while(*s && *s!=' ' && *s!='\t') s++; if(*s == 0) break; else *s++ = 0; } return i; } int return0(void *a) { USED(a); return 0; } long syssleep(ulong *arg) { if(arg[0] == 0) sched(); else tsleep(&u->p->sleep, return0, 0, arg[0]); return 0; } long sysalarm(ulong *arg) { return procalarm(arg[0]); } long sysexits(ulong *arg) { char *status; char *inval = "invalid exit string"; status = (char*)arg[0]; if(status){ if(waserror()) status = inval; else{ validaddr((ulong)status, 1, 0); if(vmemchr(status, 0, ERRLEN) == 0) status = inval; } poperror(); } pexit(status, 1); return 0; /* not reached */ } long syswait(ulong *arg) { if(arg[0]){ validaddr(arg[0], sizeof(Waitmsg), 1); evenaddr(arg[0]); } return pwait((Waitmsg*)arg[0]); } long sysdeath(ulong *arg) { USED(arg); pprint("deprecated system call\n"); pexit("Suicide", 0); return 0; /* not reached */ } long syserrstr(ulong *arg) { validaddr(arg[0], ERRLEN, 1); memmove((char*)arg[0], u->error, ERRLEN); strncpy(u->error, Enoerror, ERRLEN); return 0; } long sysnotify(ulong *arg) { USED(arg); if(arg[0] != 0) validaddr(arg[0], sizeof(ulong), 0); u->notify = (int(*)(void*, char*))(arg[0]); return 0; } long sysnoted(ulong *arg) { USED(arg); if(u->notified == 0) error(Egreg); return 0; } long syssegbrk(ulong *arg) { Segment *s; int i; for(i = 0; i < NSEG; i++) if(s = u->p->seg[i]) { if(arg[0] >= s->base && arg[0] < s->top) { switch(s->type&SG_TYPE) { case SG_TEXT: case SG_DATA: error(Ebadarg); default: return ibrk(arg[1], i); } } } error(Ebadarg); return 0; /* not reached */ } long syssegattach(ulong *arg) { return segattach(u->p, arg[0], (char*)arg[1], arg[2], arg[3]); } long syssegdetach(ulong *arg) { int i; Segment *s; s = 0; for(i = 0; i < NSEG; i++) if(s = u->p->seg[i]) { qlock(&s->lk); if((arg[0] >= s->base && arg[0] < s->top) || (s->top == s->base && arg[0] == s->base)) goto found; qunlock(&s->lk); } error(Ebadarg); found: if((ulong)arg >= s->base && (ulong)arg < s->top) { qunlock(&s->lk); error(Ebadarg); } u->p->seg[i] = 0; qunlock(&s->lk); putseg(s); /* Ensure we flush any entries from the lost segment */ flushmmu(); return 0; } long syssegfree(ulong *arg) { Segment *s; ulong from, pages; from = PGROUND(arg[0]); s = seg(u->p, from, 1); if(s == 0) error(Ebadarg); pages = (arg[1]+BY2PG-1)/BY2PG; if(from+pages*BY2PG > s->top) { qunlock(&s->lk); error(Ebadarg); } mfreeseg(s, from, pages); qunlock(&s->lk); return 0; } /* For binary compatability */ long sysbrk_(ulong *arg) { return ibrk(arg[0], BSEG); } long sysrendezvous(ulong *arg) { Proc *p, **l; int s, tag; ulong val; tag = arg[0]; l = &REND(u->p->pgrp, tag); lock(u->p->pgrp); for(p = *l; p; p = p->rendhash) { if(p->rendtag == tag) { *l = p->rendhash; val = p->rendval; p->rendval = arg[1]; while(p->state != Rendezvous) ; ready(p); unlock(u->p->pgrp); return val; } l = &p->rendhash; } /* Going to sleep here */ p = u->p; p->rendtag = tag; p->rendval = arg[1]; p->rendhash = *l; *l = p; s = splhi(); unlock(p->pgrp); u->p->state = Rendezvous; sched(); splx(s); return u->p->rendval; }