| plan 9 kernel history: overview | file list | diff list |
1998/0903/port/sysproc.c (diff list | history)
| port/sysproc.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/0227 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1990/0227 | ||
| 1990/0330 | #include <a.out.h> | |
| 1990/0227 | int shargs(char*, int, char**); long sysr1(ulong *arg) { | |
| 1998/0825 | print("[%s %s %lud] r1 = %lud\n", up->user, up->text, up->pid, arg[0]); | |
| 1990/0227 | return 0; } long | |
| 1991/0807 | sysrfork(ulong *arg) { | |
| 1993/0501 | Proc *p; int n, i; | |
| 1997/1203 | Fgrp *ofg; | |
| 1992/0428 | Pgrp *opg; | |
| 1997/1203 | Rgrp *org; | |
| 1992/0428 | Egrp *oeg; | |
| 1993/0501 | ulong pid, flag; | |
| 1991/0709 | ||
| 1992/1206 | flag = arg[0]; | |
| 1997/1203 | /* 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); | |
| 1992/0501 | if((flag&RFPROC) == 0) { | |
| 1997/1203 | 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); } | |
| 1992/0501 | if(flag & (RFNAMEG|RFCNAMEG)) { | |
| 1993/0501 | opg = up->pgrp; up->pgrp = newpgrp(); | |
| 1992/0501 | if(flag & RFNAMEG) | |
| 1993/0501 | pgrpcpy(up->pgrp, opg); | |
| 1992/0428 | closepgrp(opg); } | |
| 1997/1203 | if(flag & RFREND) { org = up->rgrp; up->rgrp = newrgrp(); closergrp(org); } | |
| 1992/0501 | if(flag & (RFENVG|RFCENVG)) { | |
| 1993/0501 | oeg = up->egrp; up->egrp = smalloc(sizeof(Egrp)); up->egrp->ref = 1; | |
| 1992/0501 | if(flag & RFENVG) | |
| 1993/0501 | envcpy(up->egrp, oeg); | |
| 1992/0428 | closeegrp(oeg); } | |
| 1992/0501 | if(flag & RFNOTEG) | |
| 1993/0501 | up->noteid = incref(¬eidalloc); | |
| 1992/0428 | return 0; } | |
| 1990/0227 | p = newproc(); | |
| 1991/0705 | ||
| 1993/0501 | p->fpsave = up->fpsave; p->scallnr = up->scallnr; p->s = up->s; p->nerrlab = 0; p->slash = up->slash; p->dot = up->dot; | |
| 1998/0512 | incref(p->dot); | |
| 1990/0614 | ||
| 1993/0501 | memmove(p->note, up->note, sizeof(p->note)); p->nnote = up->nnote; p->notified = 0; p->lastnote = up->lastnote; p->notify = up->notify; | |
| 1995/0115 | p->ureg = up->ureg; | |
| 1993/0501 | p->dbgreg = 0; | |
| 1990/0227 | ||
| 1991/0705 | /* Make a new set of memory segments */ | |
| 1992/0501 | n = flag & RFMEM; | |
| 1991/0705 | for(i = 0; i < NSEG; i++) | |
| 1993/0501 | if(up->seg[i]) p->seg[i] = dupseg(up->seg, i, n); | |
| 1991/0705 | ||
| 1992/0428 | /* File descriptors */ | |
| 1992/0501 | if(flag & (RFFDG|RFCFDG)) { if(flag & RFFDG) | |
| 1993/0501 | p->fgrp = dupfgrp(up->fgrp); | |
| 1997/0606 | else p->fgrp = dupfgrp(nil); | |
| 1992/0428 | } else { | |
| 1993/0501 | p->fgrp = up->fgrp; | |
| 1991/0807 | incref(p->fgrp); } | |
| 1991/0705 | ||
| 1992/0428 | /* Process groups */ | |
| 1998/0512 | if(flag & (RFNAMEG|RFCNAMEG)) { | |
| 1992/0928 | p->pgrp = newpgrp(); if(flag & RFNAMEG) | |
| 1993/0501 | pgrpcpy(p->pgrp, up->pgrp); | |
| 1991/0807 | } | |
| 1991/0808 | else { | |
| 1993/0501 | p->pgrp = up->pgrp; | |
| 1991/0808 | incref(p->pgrp); } | |
| 1991/0705 | ||
| 1995/0115 | if(flag & RFREND) p->rgrp = newrgrp(); | |
| 1994/0812 | else { incref(up->rgrp); p->rgrp = up->rgrp; } | |
| 1992/0428 | /* Environment group */ | |
| 1992/0501 | if(flag & (RFENVG|RFCENVG)) { | |
| 1992/0623 | p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; if(flag & RFENVG) | |
| 1993/0501 | envcpy(p->egrp, up->egrp); | |
| 1991/0807 | } | |
| 1991/0808 | else { | |
| 1993/0501 | p->egrp = up->egrp; | |
| 1991/0808 | incref(p->egrp); } | |
| 1993/0501 | p->hang = up->hang; p->procmode = up->procmode; | |
| 1991/1110 | ||
| 1993/0501 | /* 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); | |
| 1998/0512 | ||
| 1993/0501 | p->parent = up; p->parentpid = up->pid; | |
| 1992/0501 | if(flag&RFNOWAIT) | |
| 1992/0430 | p->parentpid = 1; | |
| 1992/0715 | else { | |
| 1993/0501 | lock(&up->exl); up->nchild++; unlock(&up->exl); | |
| 1992/0715 | } | |
| 1992/0501 | if((flag&RFNOTEG) == 0) | |
| 1993/0501 | p->noteid = up->noteid; | |
| 1991/0705 | ||
| 1993/0501 | p->fpstate = up->fpstate; | |
| 1990/0227 | pid = p->pid; memset(p->time, 0, sizeof(p->time)); p->time[TReal] = MACHP(0)->ticks; | |
| 1993/0501 | memmove(p->text, up->text, NAMELEN); memmove(p->user, up->user, NAMELEN); | |
| 1991/0529 | /* * 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. */ | |
| 1990/0227 | flushmmu(); | |
| 1995/0110 | p->priority = up->priority; p->basepri = up->basepri; p->mp = up->mp; | |
| 1995/0102 | if(up->wired) procwired(p); | |
| 1991/0430 | ready(p); | |
| 1995/0324 | sched(); | |
| 1990/0227 | return pid; } | |
| 1991/0723 | static ulong l2be(long l) { uchar *cp; cp = (uchar*)&l; return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3]; } | |
| 1990/0227 | long sysexec(ulong *arg) { | |
| 1991/0705 | Segment *s, *ts; | |
| 1992/0711 | ulong t, d, b; | |
| 1990/0227 | int i; | |
| 1992/0711 | Chan *tc; | |
| 1990/0227 | char **argv, **argp; char *a, *charp, *file; char *progarg[sizeof(Exec)/2+1], elem[NAMELEN]; | |
| 1991/0523 | ulong ssize, spage, nargs, nbytes, n, bssend; | |
| 1990/0227 | int indir; Exec exec; char line[sizeof(Exec)]; | |
| 1991/0705 | Fgrp *f; Image *img; | |
| 1991/0723 | ulong magic, text, entry, data, bss; | |
| 1990/0227 | validaddr(arg[0], 1, 0); file = (char*)arg[0]; indir = 0; | |
| 1994/0812 | for(;;){ tc = namec(file, Aopen, OEXEC, 0); if(waserror()){ | |
| 1997/0327 | cclose(tc); | |
| 1994/0812 | nexterror(); } if(!indir) strcpy(elem, up->elem); | |
| 1998/0512 | ||
| 1997/0327 | n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); | |
| 1994/0812 | if(n < 2) 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) error(Ebadexec); break; /* for binary */ } | |
| 1998/0512 | ||
| 1994/0812 | /* * Process #! /bin/sh args ... */ memmove(line, &exec, sizeof(Exec)); if(indir || line[0]!='#' || line[1]!='!') error(Ebadexec); n = shargs(line, n, progarg); if(n == 0) error(Ebadexec); 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(); | |
| 1997/0327 | cclose(tc); | |
| 1990/0227 | } | |
| 1991/0706 | ||
| 1991/0723 | 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; | |
| 1990/1211 | b = (bssend + (BY2PG-1)) & ~(BY2PG-1); | |
| 1990/0227 | if((t|d|b) & KZERO) | |
| 1990/11211 | error(Ebadexec); | |
| 1990/0227 | /* * Args: pass 1: count */ | |
| 1991/0710 | nbytes = BY2WD; /* hole for profiling clock at top of stack */ | |
| 1990/0227 | 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); | |
| 1993/0227 | nbytes += (vmemchr(a, 0, 0x7FFFFFFF) - a) + 1; | |
| 1990/1226 | nargs++; | |
| 1990/0227 | } ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); | |
| 1992/0923 | ||
| 1992/0802 | /* * 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; | |
| 1990/0227 | spage = (ssize+(BY2PG-1)) >> PGSHIFT; | |
| 1993/0727 | ||
| 1990/0227 | /* * Build the stack segment, putting it in kernel virtual for the moment */ | |
| 1991/0523 | if(spage > TSTKSIZ) | |
| 1992/0114 | error(Enovmem); | |
| 1991/0522 | ||
| 1993/0501 | up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); | |
| 1990/0227 | /* * 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]; | |
| 1991/0705 | ||
| 1990/0227 | for(i=0; i<nargs; i++){ | |
| 1991/0705 | if(indir && *argp==0) { | |
| 1990/0227 | indir = 0; argp = (char**)arg[1]; } *argv++ = charp + (USTKTOP-TSTKTOP); n = strlen(*argp) + 1; | |
| 1991/0318 | memmove(charp, *argp++, n); | |
| 1990/0227 | charp += n; } | |
| 1993/0501 | memmove(up->text, elem, NAMELEN); | |
| 1990/0227 | /* | |
| 1992/1206 | * Committed. * Free old memory. | |
| 1994/0812 | * Special segments are maintained across exec | |
| 1990/0227 | */ | |
| 1991/0709 | for(i = SSEG; i <= BSEG; i++) { | |
| 1993/0501 | putseg(up->seg[i]); | |
| 1994/0106 | /* prevent a second free if we have an error */ up->seg[i] = 0; } for(i = BSEG+1; i < NSEG; i++) { s = up->seg[i]; if(s != 0 && (s->type&SG_CEXEC)) { putseg(s); up->seg[i] = 0; } | |
| 1991/0709 | } | |
| 1990/08141 | /* * Close on exec */ | |
| 1993/0501 | f = up->fgrp; | |
| 1991/0705 | for(i=0; i<=f->maxfd; i++) fdclose(i, CCEXEC); | |
| 1990/0227 | ||
| 1991/0705 | /* Text. Shared. Attaches to cache image if possible */ | |
| 1991/0724 | /* attachimage returns a locked cache image */ | |
| 1991/0705 | img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT); ts = img->s; | |
| 1993/0501 | up->seg[TSEG] = ts; | |
| 1991/0706 | ts->flushme = 1; | |
| 1991/0705 | ts->fstart = 0; | |
| 1991/0723 | ts->flen = sizeof(Exec)+text; | |
| 1991/0724 | unlock(img); | |
| 1990/0227 | ||
| 1991/0705 | /* Data. Shared. */ s = newseg(SG_DATA, t, (d-t)>>PGSHIFT); | |
| 1993/0501 | up->seg[DSEG] = s; | |
| 1990/0227 | ||
| 1991/0705 | /* Attached by hand */ incref(img); s->image = img; s->fstart = ts->fstart+ts->flen; | |
| 1991/0723 | s->flen = data; | |
| 1990/0227 | ||
| 1991/0705 | /* BSS. Zero fill on demand */ | |
| 1993/0501 | up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT); | |
| 1990/1211 | ||
| 1990/0227 | /* * Move the stack */ | |
| 1993/0501 | s = up->seg[ESEG]; up->seg[ESEG] = 0; up->seg[SSEG] = s; | |
| 1991/0705 | s->base = USTKTOP-USTKSIZE; s->top = USTKTOP; | |
| 1993/0502 | relocateseg(s, USTKTOP-TSTKTOP); | |
| 1990/0227 | ||
| 1994/0727 | /* | |
| 1994/0915 | * '/' processes are higher priority (hack to make /ip more responsive). | |
| 1994/0727 | */ | |
| 1997/0408 | if(devtab[tc->type]->dc == L'/') | |
| 1995/0110 | up->basepri = PriRoot; up->priority = up->basepri; | |
| 1994/0812 | poperror(); | |
| 1997/0327 | cclose(tc); | |
| 1991/0705 | ||
| 1991/0529 | /* | |
| 1991/0705 | * At this point, the mmu contains info about the old address | |
| 1991/0529 | * space and needs to be flushed */ | |
| 1990/0227 | flushmmu(); | |
| 1993/0501 | qlock(&up->debug); up->nnote = 0; up->notify = 0; up->notified = 0; procsetup(up); qunlock(&up->debug); if(up->hang) up->procctl = Proc_stopme; | |
| 1991/1110 | ||
| 1991/1214 | return execregs(entry, ssize, nargs); | |
| 1990/0227 | } int shargs(char *s, int n, char **ap) { int i; | |
| 1992/0928 | s += 2; n -= 2; /* skip #! */ | |
| 1990/0227 | for(i=0; s[i]!='\n'; i++) if(i == n-1) return 0; s[i] = 0; *ap = 0; i = 0; | |
| 1993/0501 | for(;;) { | |
| 1990/0227 | 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 | |
| 1995/0804 | return0(void*) | |
| 1990/0227 | { return 0; } long syssleep(ulong *arg) { | |
| 1995/0110 | ||
| 1995/0106 | int n; | |
| 1991/1219 | ||
| 1995/0106 | n = arg[0]; | |
| 1995/0107 | if(n <= 0) { | |
| 1995/0421 | up->priority = 0; | |
| 1995/0106 | sched(); return 0; | |
| 1998/0512 | } | |
| 1995/0107 | if(n < TK2MS(1)) | |
| 1995/0106 | n = TK2MS(1); tsleep(&up->sleep, return0, 0, n); | |
| 1990/0227 | return 0; } | |
| 1991/0513 | long sysalarm(ulong *arg) { | |
| 1998/0512 | return procalarm(arg[0]); | |
| 1991/0513 | } | |
| 1990/0227 | long sysexits(ulong *arg) { char *status; | |
| 1991/0808 | char *inval = "invalid exit string"; | |
| 1995/0329 | char buf[ERRLEN]; | |
| 1990/0227 | status = (char*)arg[0]; if(status){ if(waserror()) | |
| 1991/0808 | status = inval; | |
| 1990/0227 | else{ validaddr((ulong)status, 1, 0); | |
| 1995/0329 | if(vmemchr(status, 0, ERRLEN) == 0){ memmove(buf, status, ERRLEN); buf[ERRLEN-1] = 0; status = buf; } | |
| 1990/0227 | } | |
| 1991/0614 | poperror(); | |
| 1991/0705 | ||
| 1990/0227 | } pexit(status, 1); | |
| 1992/0520 | return 0; /* not reached */ | |
| 1990/0227 | } long syswait(ulong *arg) { if(arg[0]){ validaddr(arg[0], sizeof(Waitmsg), 1); evenaddr(arg[0]); } return pwait((Waitmsg*)arg[0]); } long | |
| 1995/0804 | sysdeath(ulong*) | |
| 1990/0227 | { | |
| 1992/0628 | pprint("deprecated system call\n"); | |
| 1990/11211 | pexit("Suicide", 0); | |
| 1992/0520 | return 0; /* not reached */ | |
| 1990/0227 | } long syserrstr(ulong *arg) { | |
| 1993/0501 | char *e, tmp[ERRLEN]; | |
| 1993/0324 | ||
| 1990/11211 | validaddr(arg[0], ERRLEN, 1); | |
| 1993/0501 | e = (char*)arg[0]; memmove(tmp, e, ERRLEN); memmove(e, up->error, ERRLEN); memmove(up->error, tmp, ERRLEN); | |
| 1990/0227 | return 0; } long sysnotify(ulong *arg) { | |
| 1991/0326 | if(arg[0] != 0) validaddr(arg[0], sizeof(ulong), 0); | |
| 1993/0501 | up->notify = (int(*)(void*, char*))(arg[0]); | |
| 1990/0227 | return 0; } long sysnoted(ulong *arg) { | |
| 1995/0115 | if(arg[0]!=NRSTR && !up->notified) | |
| 1990/11211 | error(Egreg); | |
| 1990/0227 | return 0; } long | |
| 1991/0705 | syssegbrk(ulong *arg) | |
| 1990/0227 | { | |
| 1991/0705 | int i; | |
| 1993/0501 | ulong addr; Segment *s; | |
| 1991/0705 | ||
| 1993/0501 | addr = arg[0]; for(i = 0; i < NSEG; i++) { s = up->seg[i]; if(s == 0 || addr < s->base || addr >= s->top) continue; switch(s->type&SG_TYPE) { case SG_TEXT: case SG_DATA: | |
| 1995/0203 | case SG_STACK: | |
| 1993/0501 | error(Ebadarg); default: return ibrk(arg[1], i); | |
| 1991/0705 | } | |
| 1993/0501 | } | |
| 1991/0705 | ||
| 1992/0114 | error(Ebadarg); | |
| 1992/0520 | return 0; /* not reached */ | |
| 1990/0227 | } | |
| 1991/0606 | ||
| 1991/0605 | long | |
| 1991/0705 | syssegattach(ulong *arg) | |
| 1991/0605 | { | |
| 1993/0501 | return segattach(up, arg[0], (char*)arg[1], arg[2], arg[3]); | |
| 1991/0705 | } long syssegdetach(ulong *arg) { int i; | |
| 1993/0501 | ulong addr; | |
| 1991/0705 | Segment *s; | |
| 1991/0723 | s = 0; | |
| 1993/0501 | addr = arg[0]; | |
| 1991/0705 | for(i = 0; i < NSEG; i++) | |
| 1993/0501 | if(s = up->seg[i]) { | |
| 1991/0705 | qlock(&s->lk); | |
| 1998/0512 | if((addr >= s->base && addr < s->top) || | |
| 1993/0501 | (s->top == s->base && addr == s->base)) | |
| 1991/0705 | goto found; qunlock(&s->lk); } | |
| 1992/0114 | error(Ebadarg); | |
| 1991/0705 | found: | |
| 1993/0501 | /* Check we are not detaching the current stack segment */ | |
| 1991/0705 | if((ulong)arg >= s->base && (ulong)arg < s->top) { qunlock(&s->lk); | |
| 1992/0114 | error(Ebadarg); | |
| 1991/0705 | } | |
| 1993/0501 | up->seg[i] = 0; | |
| 1991/0705 | qunlock(&s->lk); putseg(s); /* Ensure we flush any entries from the lost segment */ flushmmu(); return 0; } long syssegfree(ulong *arg) { Segment *s; | |
| 1991/0712 | ulong from, pages; | |
| 1991/0705 | ||
| 1991/0706 | from = PGROUND(arg[0]); | |
| 1993/0501 | s = seg(up, from, 1); | |
| 1991/0705 | if(s == 0) | |
| 1992/0114 | error(Ebadarg); | |
| 1991/0705 | ||
| 1991/0712 | pages = (arg[1]+BY2PG-1)/BY2PG; | |
| 1991/0705 | ||
| 1991/0712 | if(from+pages*BY2PG > s->top) { | |
| 1991/0705 | qunlock(&s->lk); | |
| 1992/0114 | error(Ebadarg); | |
| 1991/0705 | } | |
| 1991/0712 | mfreeseg(s, from, pages); | |
| 1991/0705 | qunlock(&s->lk); | |
| 1992/1206 | flushmmu(); | |
| 1991/0705 | return 0; } | |
| 1995/0610 | /* For binary compatibility */ | |
| 1991/0705 | long sysbrk_(ulong *arg) { return ibrk(arg[0], BSEG); | |
| 1991/0605 | } | |
| 1991/0806 | long sysrendezvous(ulong *arg) { | |
| 1998/0903 | ulong tag; | |
| 1991/0806 | ulong val; | |
| 1994/0515 | Proc *p, **l; | |
| 1991/0806 | tag = arg[0]; | |
| 1994/0812 | l = &REND(up->rgrp, tag); | |
| 1991/0806 | ||
| 1994/0812 | lock(up->rgrp); | |
| 1991/0806 | for(p = *l; p; p = p->rendhash) { if(p->rendtag == tag) { *l = p->rendhash; val = p->rendval; p->rendval = arg[1]; | |
| 1994/0515 | while(p->mach != 0) | |
| 1991/0807 | ; | |
| 1991/0806 | ready(p); | |
| 1994/0812 | unlock(up->rgrp); | |
| 1998/0512 | return val; | |
| 1991/0806 | } l = &p->rendhash; } /* Going to sleep here */ | |
| 1993/0501 | up->rendtag = tag; up->rendval = arg[1]; up->rendhash = *l; *l = up; up->state = Rendezvous; | |
| 1994/0812 | unlock(up->rgrp); | |
| 1994/0515 | ||
| 1991/0806 | sched(); | |
| 1993/0501 | return up->rendval; | |
| 1991/0806 | } | |