📄 sysproc.c
字号:
#define WANT_M#include "u.h"#include "tos.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "error.h"#include "a.out.h"int shargs(char*, int, char**);extern void checkpages(void);extern void checkpagerefs(void);longsysr1(ulong *x){ vx32sysr1(); return 0;}longsysrfork(ulong *arg){ Proc *p; int n, i; Fgrp *ofg; Pgrp *opg; Rgrp *org; Egrp *oeg; ulong pid, flag; Mach *wm; flag = arg[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); 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.ref = 1; if(flag & RFENVG) envcpy(up->egrp, oeg); closeegrp(oeg); } if(flag & RFNOTEG) up->noteid = incref(¬eidalloc); return 0; } p = newproc(); p->fpsave = up->fpsave; p->scallnr = up->scallnr; p->s = up->s; p->nerrlab = 0; p->slash = up->slash; p->dot = up->dot; incref(&p->dot->ref); 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; /* 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]) 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->ref); } /* 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->ref); } if(flag & RFNOMNT) up->pgrp->noattach = 1; if(flag & RFREND) p->rgrp = newrgrp(); else { incref(&up->rgrp->ref); p->rgrp = up->rgrp; } /* Environment group */ if(flag & (RFENVG|RFCENVG)) { p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref.ref = 1; if(flag & RFENVG) envcpy(p->egrp, up->egrp); } else { p->egrp = up->egrp; incref(&p->egrp->ref); } p->hang = up->hang; p->procmode = up->procmode; /* 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; p->parentpid = up->pid; if(flag&RFNOWAIT) p->parentpid = 0; else { lock(&up->exl); up->nchild++; unlock(&up->exl); } if((flag&RFNOTEG) == 0) p->noteid = up->noteid; p->fpstate = up->fpstate; pid = p->pid; memset(p->time, 0, sizeof(p->time)); p->time[TReal] = msec(); kstrdup(&p->text, up->text); kstrdup(&p->user, up->user); /* * 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 ulongl2be(long l){ uchar *cp; cp = (uchar*)&l; return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];}static char Echanged[] = "exec arguments changed underfoot";longsysexec(ulong *arg){ char *volatile elem, *volatile file, *ufile; Chan *volatile tc; /* * Open the file, remembering the final element and the full name. */ file = nil; elem = nil; tc = nil; if(waserror()){ if(file) free(file); if(elem) free(elem); if(tc) cclose(tc); nexterror(); } ufile = uvalidaddr(arg[0], 1, 0); file = validnamedup(ufile, 1); tc = namec(file, Aopen, OEXEC, 0); kstrdup((char**)&elem, up->genbuf); /* * Read the header. If it's a #!, fill in progarg[] with info and repeat. */ int i, n, nprogarg; char *progarg[sizeof(Exec)/2+1]; char *prog, *p; char line[sizeof(Exec)+1]; Exec exec; nprogarg = 0; n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); if(n < 2) error(Ebadexec); p = (char*)&exec; if(p[0] == '#' && p[1] == '!'){ memmove(line, p, n); nprogarg = shargs(line, n, progarg); if(nprogarg == 0) error(Ebadexec); /* The original file becomes an extra arg after #! line */ progarg[nprogarg++] = file; /* * Take the #! $0 as a file to open, and replace * $0 with the original path's name. */ prog = progarg[0]; progarg[0] = elem; cclose(tc); tc = nil; /* in case namec errors out */ tc = namec(prog, Aopen, OEXEC, 0); n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); if(n < 2) error(Ebadexec); } /* * #! has had its chance, now we need a real binary */ ulong magic, entry, text, etext, data, edata, bss, ebss; magic = l2be(exec.magic); if(n != sizeof(Exec) || l2be(exec.magic) != AOUT_MAGIC) error(Ebadexec); entry = l2be(exec.entry); text = l2be(exec.text); data = l2be(exec.data); bss = l2be(exec.bss); etext = ROUND(UTZERO+sizeof(Exec)+text, BY2PG); edata = ROUND(etext + data, BY2PG); ebss = ROUND(etext + data + bss, BY2PG); //iprint("entry %#lux text %#lux data %#lux bss %#lux\n", entry, text, data, bss);//iprint("etext %#lux edata %#lux ebss %#lux\n", etext, edata, ebss); if(entry < UTZERO+sizeof(Exec) || entry >= UTZERO+sizeof(Exec)+text) error(Ebadexec); /* many overflow possibilities */ if(text >= USTKTOP || data >= USTKTOP || bss >= USTKTOP || etext >= USTKTOP || edata >= USTKTOP || ebss >= USTKTOP || etext >= USTKTOP || edata < etext || ebss < edata) error(Ebadexec); /* * Copy argv into new stack segment temporarily mapped elsewhere. * Be careful: multithreaded program could be changing argv during this. * Pass 1: count number of arguments, string bytes. */ int nargv, strbytes; ulong argp, ssize, spage; strbytes = 0; for(i=0; i<nprogarg; i++) strbytes += strlen(progarg[i]) + 1; argp = arg[1]; for(nargv=0;; nargv++, argp += BY2WD){ ulong a; char *str; a = *(ulong*)uvalidaddr(argp, BY2WD, 0); if(a == 0) break; str = uvalidaddr(a, 1, 0); n = ((char*)vmemchr(str, 0, 0x7FFFFFFF) - str) + 1; if(nprogarg > 0 && nargv == 0) continue; /* going to skip argv[0] on #! */ strbytes += n; } if(nargv == 0) error("exec missing argv"); /* * Skip over argv[0] if using #!. Waited until now so that * string would still be checked for validity during loop. */ if(nprogarg > 0){ nargv--; arg[1] += BY2WD; } ssize = BY2WD*((nprogarg+nargv)+1) + ROUND(strbytes, BY2WD) + sizeof(Tos); /* * 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; /* * Pass 2: build the stack segment, being careful not to assume * that the counts from pass 1 are still valid. */ if(spage > TSTKSIZ) error(Enovmem); qlock(&up->seglock); if(waserror()){ if(up->seg[ESEG]){ putseg(up->seg[ESEG]); up->seg[ESEG] = nil; } qunlock(&up->seglock); nexterror(); } up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); flushmmu(); // Needed for Plan 9 VX XXX really? /* * Top-of-stack structure. */ Tos *tos; ulong utos; utos = USTKTOP - sizeof(Tos); tos = (Tos*)(uzero + utos + TSTKTOP - USTKTOP); tos->cyclefreq = m->cyclefreq; cycles((uvlong*)&tos->pcycles); tos->pcycles = -tos->pcycles; tos->kcycles = tos->pcycles; tos->clock = 0; /* * Argument pointers and strings, together. */ char *bp, *ep; ulong *targp; ulong ustrp, uargp; ustrp = utos - ROUND(strbytes, BY2WD); uargp = ustrp - BY2WD*((nprogarg+nargv)+1); bp = (char*)(uzero + ustrp + TSTKTOP - USTKTOP); ep = bp + strbytes; p = bp; targp = (ulong*)(uzero + uargp + TSTKTOP - USTKTOP); /* #! args are trusted */ for(i=0; i<nprogarg; i++){ n = strlen(progarg[i]) + 1; if(n > ep - p) error(Echanged); memmove(p, progarg[i], n); p += n; *targp++ = ustrp; ustrp += n; } /* the rest are not */ argp = arg[1]; for(i=0; i<nargv; i++){ ulong a; char *str; a = *(ulong*)uvalidaddr(argp, BY2WD, 0); argp += BY2WD; str = uvalidaddr(a, 1, 0); n = ((char*)vmemchr(str, 0, 0x7FFFFFFF) - str) + 1; if(n > ep - p) error(Echanged); memmove(p, str, n); p += n; *targp++ = ustrp; ustrp += n; } if(*(ulong*)uvalidaddr(argp, BY2WD, 0) != 0) error(Echanged); *targp = 0; /* * But wait, there's more: prepare an arg copy for up->args * using the copy we just made in the temporary segment. */ char *args; int nargs; n = p - bp; /* includes NUL on last arg, so must be > 0 */ if(n <= 0) /* nprogarg+nargv > 0; checked above */ error(Egreg); if(n > 128) n = 128; args = smalloc(n); if(waserror()){ free(args); nexterror(); } memmove(args, bp, n); for(i=0; i<n; i++) /* NULs -> spaces */ if(args[i] == '\0') args[i] = ' '; /* find beginning of UTF character boundary to place final NUL */ while(n > 0 && (args[n-1]&0xC0) == 0x80) n--; args[n-1] = '\0'; nargs = n; /* * Now we're ready to commit. */ free(up->text); up->text = elem; free(up->args); up->args = args; up->nargs = n; elem = nil; poperror(); /* args */ /* * Free old memory. Special segments maintained across exec. */ Segment *s; for(i = SSEG; i <= BSEG; i++) { putseg(up->seg[i]); up->seg[i] = nil; /* in case of error */ } for(i = BSEG+1; i< NSEG; i++) { s = up->seg[i]; if(s && (s->type&SG_CEXEC)) { putseg(s); up->seg[i] = nil; } } /* * Close on exec */ Fgrp *f; f = up->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 */ Image *img; Segment *ts; img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (etext-UTZERO)>>PGSHIFT); ts = img->s; up->seg[TSEG] = ts; ts->flushme = 1; ts->fstart = 0; ts->flen = sizeof(Exec)+text; unlock(&img->ref.lk); /* Data. Shared. */ s = newseg(SG_DATA, etext, (edata-etext)>>PGSHIFT); up->seg[DSEG] = s; /* Attached by hand */ incref(&img->ref); s->image = img; s->fstart = ts->fstart+ts->flen; s->flen = data; /* BSS. Zero fill on demand */ up->seg[BSEG] = newseg(SG_BSS, edata, (ebss-edata)>>PGSHIFT); /* * Move the stack */ s = up->seg[ESEG]; up->seg[ESEG] = 0; up->seg[SSEG] = s; qunlock(&up->seglock); poperror(); /* seglock */ s->base = USTKTOP-USTKSIZE; s->top = USTKTOP; relocateseg(s, USTKTOP-TSTKTOP); /* * '/' processes are higher priority (hack to make /ip more responsive). */ if(devtab[tc->type]->dc == L'/') up->basepri = PriRoot; up->priority = up->basepri; poperror(); /* tc, elem, file */ cclose(tc); free(file); // elem is now up->text /* * At this point, the mmu contains info about the old address * space and needs to be flushed */ flushmmu(); qlock(&up->debug); up->nnote = 0; up->notify = 0; up->notified = 0; up->privatemem = 0; procsetup(up); qunlock(&up->debug); if(up->hang) up->procctl = Proc_stopme; return execregs(entry, USTKTOP - uargp, nprogarg+nargv);}intshargs(char *s, int n, char **ap)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -