asmlinkage int sys_shmget (key_t key, int size, int shmflg) { struct shmid_kernel *shp; int err, id = 0; down(¤t->mm->mmap_sem); lock_kernel(); if (size < 0 || size > shmmax) { err = -EINVAL; } else if (key == IPC_PRIVATE) { err = newseg(key, shmflg, size); } else if ((id = findkey (key)) == -1) { if (!(shmflg & IPC_CREAT)) err = -ENOENT; else err = newseg(key, shmflg, size); } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) { err = -EEXIST; } else { shp = shm_segs[id]; if (shp->u.shm_perm.mode & SHM_DEST) err = -EIDRM; else if (size > shp->u.shm_segsz) err = -EINVAL; else if (ipcperms (&shp->u.shm_perm, shmflg)) err = -EACCES; else err = (int) shp->u.shm_perm.seq * SHMMNI + id; } unlock_kernel(); up(¤t->mm->mmap_sem); return err; }
void userinit(void) { Proc *p; Segment *s; KMap *k; char **av; Page *pg; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); procsetup(p); /* * Kernel Stack */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->kstack+KSTACK-MAXSYSARG*BY2WD; /* * User Stack, pass input arguments to boot process */ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BY2PG); segpage(s, pg); k = kmap(pg); for(av = (char**)argbuf; *av; av++) *av += (USTKTOP - sizeof(argbuf)) - (ulong)argbuf; memmove((uchar*)VA(k) + BY2PG - sizeof(argbuf), argbuf, sizeof argbuf); kunmap(k); /* * Text */ s = newseg(SG_TEXT, UTZERO, 1); s->flushme++; p->seg[TSEG] = s; pg = newpage(1, 0, UTZERO); pg->txtflush = ~0; segpage(s, pg); k = kmap(s->map[0]->pages[0]); memmove((uchar*)VA(k), initcode, sizeof initcode); kunmap(k); ready(p); }
/* * create the first process */ void userinit(void) { Proc *p; Segment *s; KMap *k; Page *pg; /* no processes yet */ up = nil; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); /* * Kernel Stack */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); /* * User Stack */ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BY2PG); segpage(s, pg); k = kmap(pg); bootargs(VA(k)); kunmap(k); /* * Text */ s = newseg(SG_TEXT, UTZERO, 1); p->seg[TSEG] = s; pg = newpage(1, 0, UTZERO); memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); segpage(s, pg); k = kmap(s->map[0]->pages[0]); memmove((ulong*)VA(k), initcode, sizeof initcode); kunmap(k); ready(p); }
void userinit(void) { Proc *p; Segment *s; KMap *k; Page *pg; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); p->fpstate = FPinit; /* * Stack * * N.B. The -12 for the stack pointer is important. * 4 bytes for gotolabel's return PC */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); /* * User Stack */ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BY2PG); segpage(s, pg); /* * Text */ s = newseg(SG_TEXT, UTZERO, 1); s->flushme++; p->seg[TSEG] = s; pg = newpage(1, 0, UTZERO); memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); segpage(s, pg); k = kmap(s->map[0]->pages[0]); memmove((ulong*)VA(k), initcode, sizeof initcode); kunmap(k); ready(p); }
static Tdir* dirlookup(char *name, int mkit) { Tdir *tl; dprint("dirlookup %s mk=%d\n", name, mkit); lock(&tlck); for(tl = dir; tl != nil; tl = tl->next) if(strcmp(name, tl->name) == 0){ break; } if(tl == nil && !mkit) werrstr("segment not found"); if(tl == nil && mkit){ tl = newseg(name, 0, Tsegsz); if(tl != nil){ strncpy(tl->name, name, sizeof tl->name); tl->end = &tl[1]; tl->avail = Tsegsz; tl->next = dir; dir = tl; } dumpdir("after newseg"); } unlock(&tlck); dprint("dirlookup %s: %#p\n", name, tl); return tl; }
void worm_move(struct monst *mtmp) { struct wseg *wtmp, *whd; int tmp = mtmp->wormno; wtmp = newseg(); wtmp->wx = mtmp->mx; wtmp->wy = mtmp->my; wtmp->nseg = 0; (whd = wheads[tmp])->nseg = wtmp; wheads[tmp] = wtmp; if (cansee(whd->wx, whd->wy)) { unpmon(mtmp); atl(whd->wx, whd->wy, '~'); whd->wdispl = 1; } else whd->wdispl = 0; if (wgrowtime[tmp] <= moves) { if (!wgrowtime[tmp]) wgrowtime[tmp] = moves + rnd(5); else wgrowtime[tmp] += 2 + rnd(15); mtmp->mhpmax += 3; mtmp->mhp += 3; return; } whd = wsegs[tmp]; wsegs[tmp] = whd->nseg; remseg(whd); }
static long segmentwrite(Chan *c, void *a, long n, vlong voff) { Cmdbuf *cb; Globalseg *g; ulong va, len, top; if(c->qid.type == QTDIR) error(Eperm); switch(TYPE(c)){ case Qctl: g = c->aux; cb = parsecmd(a, n); if(strcmp(cb->f[0], "va") == 0){ if(g->s != nil) error("already has a virtual address"); if(cb->nf < 3) error(Ebadarg); va = strtoul(cb->f[1], 0, 0); len = strtoul(cb->f[2], 0, 0); top = PGROUND(va + len); va = va&~(BY2PG-1); len = (top - va) / BY2PG; if(len == 0) error(Ebadarg); g->s = newseg(SG_SHARED, va, len); } else error(Ebadctl); break; case Qdata: g = c->aux; if(voff + n > g->s->top - g->s->base) error(Ebadarg); qlock(&g->l); g->off = voff + g->s->base; g->data = smalloc(n); if(waserror()){ free(g->data); qunlock(&g->l); nexterror(); } g->dlen = n; memmove(g->data, a, g->dlen); docmd(g, Cwrite); free(g->data); qunlock(&g->l); poperror(); return g->dlen; default: panic("segmentwrite"); } return 0; /* not reached */ }
Segment* data2txt(Segment *s) { Segment *ps; ps = newseg(SG_TEXT, s->base, s->size); ps->image = s->image; incref(ps->image); ps->fstart = s->fstart; ps->flen = s->flen; ps->flushme = 1; return ps; }
/* called to initialize a worm unless cut in half */ void initworm(struct monst *mtmp) { struct wseg *wtmp; int tmp = mtmp->wormno; if (!tmp) return; wheads[tmp] = wsegs[tmp] = wtmp = newseg(); wgrowtime[tmp] = 0; wtmp->wx = mtmp->mx; wtmp->wy = mtmp->my; wtmp->nseg = 0; }
void userinit(void) { void *v; Proc *p; Segment *s; Page *pg; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); p->fpstate = FPinit; fpoff(); /* * Kernel Stack * * N.B. make sure there's enough space for syscall to check * for valid args and * 4 bytes for gotolabel's return PC */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); /* * User Stack * * N.B. cannot call newpage() with clear=1, because pc kmap * requires up != nil. use tmpmap instead. */ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); p->seg[SSEG] = s; pg = newpage(0, 0, USTKTOP-BY2PG); v = tmpmap(pg); memset(v, 0, BY2PG); segpage(s, pg); bootargs(v); tmpunmap(v); /* * Text */ s = newseg(SG_TEXT, UTZERO, 1); s->flushme++; p->seg[TSEG] = s; pg = newpage(0, 0, UTZERO); memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); segpage(s, pg); v = tmpmap(pg); memset(v, 0, BY2PG); memmove(v, initcode, sizeof initcode); tmpunmap(v); ready(p); }
Image* attachimage(int type, Chan *c, ulong base, ulong len) { Image *i, **l; lock(&imagealloc); /* * Search the image cache for remains of the text from a previous * or currently running incarnation */ for(i = ihash(c->qid.path); i; i = i->hash) { if(c->qid.path == i->qid.path) { lock(i); if(eqqid(c->qid, i->qid) && eqqid(c->mqid, i->mqid) && c->mchan == i->mchan && c->type == i->type) { goto found; } unlock(i); } } /* * imagereclaim dumps pages from the free list which are cached by image * structures. This should free some image structures. */ while(!(i = imagealloc.free)) { unlock(&imagealloc); imagereclaim(); if(!imagealloc.free){ freebroken(); /* can use the memory */ resrcwait("no image after reclaim"); } lock(&imagealloc); } imagealloc.free = i->next; lock(i); incref(c); c->flag &= ~CCACHE; i->c = c; i->type = c->type; i->qid = c->qid; i->mqid = c->mqid; i->mchan = c->mchan; l = &ihash(c->qid.path); i->hash = *l; *l = i; found: unlock(&imagealloc); if(i->s == 0) { i->ref++; if(waserror()) { unlock(i); putimage(i); nexterror(); } i->s = newseg(type, base, len); i->s->image = i; poperror(); } else incref(i->s); return i; }
Segment* dupseg(Segment **seg, int segno, int share) { int i, size; Pte *pte; Segment *n, *s; SET(n); s = seg[segno]; qlock(&s->lk); if(waserror()){ qunlock(&s->lk); nexterror(); } switch(s->type&SG_TYPE) { case SG_TEXT: /* New segment shares pte set */ case SG_SHARED: case SG_PHYSICAL: goto sameseg; case SG_STACK: n = newseg(s->type, s->base, s->size); break; case SG_BSS: /* Just copy on write */ if(share) goto sameseg; n = newseg(s->type, s->base, s->size); break; case SG_DATA: /* Copy on write plus demand load info */ if(segno == TSEG){ n = data2txt(s); poperror(); qunlock(&s->lk); return n; } if(share) goto sameseg; n = newseg(s->type, s->base, s->size); incref(s->image); n->image = s->image; n->fstart = s->fstart; n->flen = s->flen; break; } size = s->mapsize; for(i = 0; i < size; i++) if(pte = s->map[i]) n->map[i] = ptecpy(pte); n->flushme = s->flushme; if(s->ref > 1) procflushseg(s); poperror(); qunlock(&s->lk); return n; sameseg: incref(s); poperror(); qunlock(&s->lk); return s; }
/* * create the first process */ void userinit(void) { Proc *p; Segment *s; KMap *k; Page *pg; /* no processes yet */ up = nil; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); /* * Kernel Stack */ p->sched.pc = PTR2UINT(init0); p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr)); p->sched.sp = STACKALIGN(p->sched.sp); /* * User Stack * * Technically, newpage can't be called here because it * should only be called when in a user context as it may * try to sleep if there are no pages available, but that * shouldn't be the case here. */ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BY2PG); segpage(s, pg); k = kmap(pg); bootargs(VA(k)); kunmap(k); /* * Text */ s = newseg(SG_TEXT, UTZERO, 1); s->flushme++; p->seg[TSEG] = s; pg = newpage(1, 0, UTZERO); memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); segpage(s, pg); k = kmap(s->map[0]->pages[0]); memmove(UINT2PTR(VA(k)), initcode, sizeof initcode); kunmap(k); ready(p); }
Proc* setupseg(int core) { Mach *m = machp(); Segment *s; uintptr_t ka; Proc *p; static Pgrp *kpgrp; Segment *tseg; int sno; // XXX: we're going to need this for locality domains. USED(core); p = newproc(); p->psstate = 0; p->procmode = 0640; p->kp = 1; p->noswap = 1; p->scallnr = m->externup->scallnr; memmove(p->arg, m->externup->arg, sizeof(m->externup->arg)); p->nerrlab = 0; p->slash = m->externup->slash; p->dot = m->externup->dot; if(p->dot) incref(p->dot); memmove(p->note, m->externup->note, sizeof(p->note)); p->nnote = m->externup->nnote; p->notified = 0; p->lastnote = m->externup->lastnote; p->notify = m->externup->notify; p->ureg = 0; p->dbgreg = 0; kstrdup(&p->user, eve); if(kpgrp == 0) kpgrp = newpgrp(); p->pgrp = kpgrp; incref(kpgrp); memset(p->time, 0, sizeof(p->time)); p->time[TReal] = sys->ticks; procpriority(p, PriKproc, 0); // XXX: kluge 4 pages of address space for this. // how will it expand up? gives us <50 kprocs as is. /* * we create the color and core at allocation time, not execution. This * is probably not the best idea but it's a start. */ sno = 0; // XXX: now that we are asmalloc we are no long proc. /* Stack */ ka = (uintptr_t)KADDR(asmalloc(0, BIGPGSZ, AsmMEMORY, 1)); tseg = newseg(SG_STACK|SG_READ|SG_WRITE, ka, 1); tseg = p->seg[sno++]; ka = (uintptr_t)KADDR(asmalloc(0, BIGPGSZ, AsmMEMORY, 1)); s = newseg(SG_TEXT|SG_READ|SG_EXEC, ka, 1); p->seg[sno++] = s; // s->color = acpicorecolor(core); /* Data. Shared. */ // XXX; Now that the address space is all funky how are we going to handle shared data segments? ka = (uintptr_t)KADDR(asmalloc(0, BIGPGSZ, AsmMEMORY, 2)); s = newseg(SG_DATA|SG_READ|SG_WRITE, ka, 1); p->seg[sno++] = s; s->color = tseg->color; /* BSS. Uses asm from data map. */ p->seg[sno++] = newseg(SG_BSS|SG_READ|SG_WRITE, ka+BIGPGSZ, 1); p->seg[sno++]->color= tseg->color; nixprepage(-1); return p; }
void getlev(int fd, int pid, xchar lev) { struct gold *gold; struct trap *trap; #ifndef NOWORM struct wseg *wtmp; #endif /* NOWORM */ int tmp; long omoves; int hpid; xchar dlvl; /* First some sanity checks */ mread(fd, &hpid, sizeof(hpid)); mread(fd, &dlvl, sizeof(dlvl)); if ((pid && pid != hpid) || (lev && dlvl != lev)) { pline("Strange, this map is not as I remember it."); pline("Somebody is trying some trickery here ..."); pline("This game is void ..."); done("tricked"); } fgold = 0; ftrap = 0; mread(fd, levl, sizeof(levl)); mread(fd, &omoves, sizeof(omoves)); mread(fd, &xupstair, sizeof(xupstair)); mread(fd, &yupstair, sizeof(yupstair)); mread(fd, &xdnstair, sizeof(xdnstair)); mread(fd, &ydnstair, sizeof(ydnstair)); fmon = restmonchn(fd); /* regenerate animals while on another level */ { long tmoves = (moves > omoves) ? moves - omoves : 0; struct monst *mtmp, *mtmp2; for (mtmp = fmon; mtmp; mtmp = mtmp2) { long newhp; /* tmoves may be very large */ mtmp2 = mtmp->nmon; if (strchr(genocided, mtmp->data->mlet)) { mondead(mtmp); continue; } if (mtmp->mtame && tmoves > 250) { mtmp->mtame = 0; mtmp->mpeaceful = 0; } newhp = mtmp->mhp + (strchr(MREGEN, mtmp->data->mlet) ? tmoves : tmoves / 20); if (newhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; else mtmp->mhp = newhp; } } setgd(); gold = newgold(); mread(fd, gold, sizeof(struct gold)); while (gold->gx) { gold->ngold = fgold; fgold = gold; gold = newgold(); mread(fd, gold, sizeof(struct gold)); } free(gold); trap = newtrap(); mread(fd, trap, sizeof(struct trap)); while (trap->tx) { trap->ntrap = ftrap; ftrap = trap; trap = newtrap(); mread(fd, trap, sizeof(struct trap)); } free(trap); fobj = restobjchn(fd); billobjs = restobjchn(fd); rest_engravings(fd); #ifndef QUEST mread(fd, rooms, sizeof(rooms)); mread(fd, doors, sizeof(doors)); #endif /* QUEST */ #ifndef NOWORM mread(fd, wsegs, sizeof(wsegs)); for (tmp = 1; tmp < 32; tmp++) if (wsegs[tmp]) { wheads[tmp] = wsegs[tmp] = wtmp = newseg(); while (1) { mread(fd, wtmp, sizeof(struct wseg)); if (!wtmp->nseg) break; wheads[tmp]->nseg = wtmp = newseg(); wheads[tmp] = wtmp; } } mread(fd, wgrowtime, sizeof(wgrowtime)); #endif /* NOWORM */ }
void userinit(void) { Mach *m = machp(); Proc *p; Segment *s; KMap *k; Page *pg; int sno; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); /* * Kernel Stack * * N.B. make sure there's enough space for syscall to check * for valid args and * space for gotolabel's return PC * AMD64 stack must be quad-aligned. */ p->sched.pc = PTR2UINT(init0); p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(m->externup->arg)-sizeof(uintptr_t)); p->sched.sp = STACKALIGN(p->sched.sp); /* * User Stack * * Technically, newpage can't be called here because it * should only be called when in a user context as it may * try to sleep if there are no pages available, but that * shouldn't be the case here. */ sno = 0; s = newseg(SG_STACK|SG_READ|SG_WRITE, USTKTOP-USTKSIZE, USTKSIZE/ BIGPGSZ); p->seg[sno++] = s; pg = newpage(1, 0, USTKTOP-BIGPGSZ, BIGPGSZ, -1); segpage(s, pg); k = kmap(pg); bootargs(VA(k)); kunmap(k); /* * Text */ s = newseg(SG_TEXT|SG_READ|SG_EXEC, UTZERO, 1); s->flushme++; p->seg[sno++] = s; pg = newpage(1, 0, UTZERO, BIGPGSZ, -1); memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); segpage(s, pg); k = kmap(s->map[0]->pages[0]); /* UTZERO is only needed until we make init not have 2M block of zeros at the front. */ memmove(UINT2PTR(VA(k) + init_code_start - UTZERO), init_code_out, sizeof(init_code_out)); kunmap(k); /* * Data */ s = newseg(SG_DATA|SG_READ|SG_WRITE, UTZERO + BIGPGSZ, 1); s->flushme++; p->seg[sno++] = s; pg = newpage(1, 0, UTZERO + BIGPGSZ, BIGPGSZ, -1); memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); segpage(s, pg); k = kmap(s->map[0]->pages[0]); /* This depends on init having a text segment < 2M. */ memmove(UINT2PTR(VA(k) + init_data_start - (UTZERO + BIGPGSZ)), init_data_out, sizeof(init_data_out)); kunmap(k); ready(p); }
Image* attachimage(int type, Chan *c, int color, uintptr base, usize len) { Image *i, **l; /* reclaim any free channels from reclaimed segments */ if(imagealloc.nfreechan) imagechanreclaim(); lock(&imagealloc); /* * Search the image cache for remains of the text from a previous * or currently running incarnation */ for(i = ihash(c->qid.path); i; i = i->hash) { if(c->qid.path == i->qid.path) { lock(i); if(eqqid(c->qid, i->qid) && eqqid(c->mqid, i->mqid) && c->mchan == i->mchan && c->dev->dc == i->dc) { //subtype goto found; } unlock(i); } } /* * imagereclaim dumps pages from the free list which are cached by image * structures. This should free some image structures. */ while(!(i = lruimage())) { unlock(&imagealloc); imagereclaim(); sched(); lock(&imagealloc); } lock(i); incref(c); i->c = c; i->dc = c->dev->dc; //subtype i->qid = c->qid; i->mqid = c->mqid; i->mchan = c->mchan; i->color = color; l = &ihash(c->qid.path); i->hash = *l; *l = i; found: imageused(i); unlock(&imagealloc); if(i->s == 0) { /* Disaster after commit in exec */ if(waserror()) { unlock(i); pexit(Enovmem, 1); } i->s = newseg(type, base, len); i->s->image = i; i->s->color = color; i->ref++; poperror(); } else incref(i->s); return i; }
static long segmentwrite(Chan *c, void *a, long n, vlong voff) { Cmdbuf *cb; Globalseg *g; uintptr va, len, top; int i; struct{ char *name; int type; }segs[] = { {"kmsg", SG_SHARED|SG_ZIO|SG_KZIO}, {"umsg", SG_SHARED|SG_ZIO}, {"addr", SG_SHARED}, }; if(c->qid.type == QTDIR) error(Eperm); switch(TYPE(c)){ case Qfree: error(Eperm); break; case Qctl: g = c->aux; cb = parsecmd(a, n); for(i = 0; i < nelem(segs); i++) if(strcmp(cb->f[0], segs[i].name) == 0) break; if(i < nelem(segs)){ if(g->s != nil) error("already has a virtual address"); if(cb->nf < 3) cmderror(cb, Ebadarg); va = strtoul(cb->f[1], 0, 0); len = strtoul(cb->f[2], 0, 0); if(va == 0) va = placeseg(len); top = BIGPGROUND(va + len); va = va&~(BIGPGSZ-1); len = (top - va) / BIGPGSZ; if(len == 0) cmderror(cb, "empty segment"); g->s = newseg(segs[i].type, va, len); if(i == 0) newzmap(g->s); else if(i == 1) zgrow(g->s); DBG("newseg %s base %#ullx len %#ullx\n", cb->f[0], va, len*BIGPGSZ); if(i == 0 || i == 1) dumpzseg(g->s); }else if(strcmp(cb->f[0], "heap") == 0){ if(g == nil) error("no globalseg"); if(g->s == nil) error("no segment"); if(heapseg) error("heap already set"); else heapseg = g->s; }else error(Ebadctl); break; case Qdata: g = c->aux; if(voff < 0) error(Enegoff); if(voff + n > g->s->top - g->s->base){ n = g->s->top - voff; if(n <= 0) break; } qlock(&g->l); if(waserror()){ qunlock(&g->l); nexterror(); } g->off = voff + g->s->base; g->data = smalloc(n); if(waserror()){ free(g->data); nexterror(); } g->dlen = n; memmove(g->data, a, g->dlen); docmd(g, Cwrite); poperror(); free(g->data); poperror(); qunlock(&g->l); break; default: panic("segmentwrite"); } return n; }
uintptr sysexec(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(up, 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) { putseg(s); up->seg[i] = nil; } } /* * Close on exec */ if((f = up->fgrp) != nil) { 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; up->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); up->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 */ up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT); /* * Move the stack */ s = up->seg[ESEG]; up->seg[ESEG] = nil; s->base = USTKTOP-USTKSIZE; s->top = USTKTOP; relocateseg(s, USTKTOP-tstk); up->seg[SSEG] = s; qunlock(&up->seglock); poperror(); /* seglock */ /* * '/' 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 */ cclose(tc); poperror(); /* file0 */ free(file0); qlock(&up->debug); free(up->text); up->text = elem; free(up->args); up->args = args; up->nargs = n; up->setargs = 0; up->nnote = 0; up->notify = 0; up->notified = 0; up->privatemem = 0; up->noswap = 0; procsetup(up); qunlock(&up->debug); /* * At this point, the mmu contains info about the old address * space and needs to be flushed */ flushmmu(); if(up->hang) up->procctl = Proc_stopme; return execregs(entry, ssize, nargs); }
long sysexec(ulong *arg) { Segment *s, *ts; ulong t, d, b; int i; Chan *tc; char **argv, **argp; char *a, *charp, *args, *file, *file0; char *progarg[sizeof(Exec)/2+1], *elem, progelem[64]; 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; Tos *tos; indir = 0; elem = nil; validaddr(arg[0], 1, 0); file0 = validnamedup((char*)arg[0], 1); if(waserror()){ free(file0); free(elem); nexterror(); } 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); text = l2be(exec.text); entry = l2be(exec.entry); if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){ if(text >= USTKTOP-UTZERO || entry < UTZERO+sizeof(Exec) || entry >= UTZERO+sizeof(Exec)+text) error(Ebadexec); break; /* for binary */ } /* * 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]; if(strlen(elem) >= sizeof progelem) error(Ebadexec); strcpy(progelem, elem); progarg[0] = progelem; poperror(); cclose(tc); } 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 >= KZERO || d >= KZERO || b >= KZERO) 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){ 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 += ((char*)vmemchr(a, 0, 0x7FFFFFFF) - 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); qlock(&up->seglock); if(waserror()){ qunlock(&up->seglock); nexterror(); } up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); /* * Args: pass 2: assemble; the pages will be faulted in */ tos = (Tos*)(TSTKTOP - sizeof(Tos)); tos->cyclefreq = m->cyclefreq; cycles((uvlong*)&tos->pcycles); tos->pcycles = -tos->pcycles; tos->kcycles = tos->pcycles; tos->clock = 0; argv = (char**)(TSTKTOP - ssize); charp = (char*)(TSTKTOP - nbytes); args = charp; if(indir) argp = progarg; else argp = (char**)arg[1]; for(i=0; i<nargs; i++){ if(indir && *argp==0) { indir = 0; argp = (char**)arg[1]; } *argv++ = charp + (USTKTOP-TSTKTOP); n = strlen(*argp) + 1; memmove(charp, *argp++, n); charp += n; } free(file0); free(up->text); up->text = elem; elem = nil; /* so waserror() won't free elem */ USED(elem); /* copy args; easiest from new process's stack */ n = charp - args; if(n > 128) /* don't waste too much space on huge arg lists */ n = 128; a = up->args; up->args = nil; free(a); up->args = smalloc(n); memmove(up->args, args, n); if(n>0 && up->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(up->args+i, n-i)) break; up->args[i] = 0; n = i+1; } up->nargs = n; /* * 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] = 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; } } /* * Close on exec */ 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 */ img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT); ts = img->s; up->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); up->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 */ up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT); /* * Move the stack */ s = up->seg[ESEG]; up->seg[ESEG] = 0; up->seg[SSEG] = s; qunlock(&up->seglock); poperror(); /* seglock */ poperror(); /* elem */ 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(); cclose(tc); /* * 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, ssize, nargs); }
void userinit(void) { Proc *p; Segment *s; KMap *k; Page *pg; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); /* * Kernel Stack * * N.B. make sure there's enough space for syscall to check * for valid args and * space for gotolabel's return PC * AMD64 stack must be quad-aligned. */ p->sched.pc = PTR2UINT(init0); p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->arg)-sizeof(uintptr)); p->sched.sp = STACKALIGN(p->sched.sp); /* * User Stack * * Technically, newpage can't be called here because it * should only be called when in a user context as it may * try to sleep if there are no pages available, but that * shouldn't be the case here. */ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BIGPGSZ); p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BIGPGSZ, BIGPGSZ, -1); segpage(s, pg); k = kmap(pg); bootargs(VA(k)); kunmap(k); /* * Text */ s = newseg(SG_TEXT, UTZERO, 1); s->flushme++; p->seg[TSEG] = s; pg = newpage(1, 0, UTZERO, BIGPGSZ, -1); memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); segpage(s, pg); k = kmap(s->map[0]->pages[0]); memmove(UINT2PTR(VA(k)), initcode, sizeof initcode); kunmap(k); ready(p); }
Image* attachimage(int type, Chan *c, ulong base, ulong len) { Image *i, **l; /* reclaim any free channels from reclaimed segments */ if(imagealloc.nfreechan) imagechanreclaim(); lock(&imagealloc.lk); /* * Search the image cache for remains of the text from a previous * or currently running incarnation */ for(i = ihash(c->qid.path); i; i = i->hash) { if(c->qid.path == i->qid.path) { lock(&i->ref.lk); if(eqqid(c->qid, i->qid) && eqqid(c->mqid, i->mqid) && c->mchan == i->mchan && c->type == i->type) { goto found; } unlock(&i->ref.lk); } } /* * imagereclaim dumps pages from the free list which are cached by image * structures. This should free some image structures. */ while(!(i = imagealloc.free)) { unlock(&imagealloc.lk); imagereclaim(); sched(); lock(&imagealloc.lk); } imagealloc.free = i->next; lock(&i->ref.lk); incref(&c->ref); i->c = c; i->type = c->type; i->qid = c->qid; i->mqid = c->mqid; i->mchan = c->mchan; l = &ihash(c->qid.path); i->hash = *l; *l = i; found: unlock(&imagealloc.lk); if(i->s == 0) { /* Disaster after commit in exec */ if(waserror()) { unlock(&i->ref.lk); pexit(Enovmem, 1); } i->s = newseg(type, base, len); i->s->image = i; i->ref.ref++; poperror(); } else incref(&i->s->ref); return i; }