static void srvcreate(Chan *c, char *name, int omode, ulong perm) { char *sname; Srv *sp; if(openmode(omode) != OWRITE) error(Eperm); if(omode & OCEXEC) /* can't happen */ panic("someone broke namec"); sp = smalloc(sizeof *sp); sname = smalloc(strlen(name)+1); qlock(&srvlk); if(waserror()){ free(sp); free(sname); qunlock(&srvlk); nexterror(); } if(sp == nil || sname == nil) error(Enomem); if(srvlookup(name, -1)) error(Eexist); sp->path = qidpath++; sp->link = srv; strcpy(sname, name); sp->name = sname; c->qid.type = QTFILE; c->qid.path = sp->path; srv = sp; qunlock(&srvlk); poperror(); kstrdup(&sp->owner, up->user); sp->perm = perm&0777; c->flag |= COPEN; c->mode = OWRITE; }
static Chan* consopen(Chan *c, int omode) { c = devopen(c, omode, contab, nelem(contab), devgen); switch((ulong)c->qid.path) { case Qconsctl: incref(&kbd.ctl); break; case Qscancode: qlock(&kbd.gq); if(gkscanq != nil || gkscanid == nil) { qunlock(&kbd.q); c->flag &= ~COPEN; if(gkscanq) error(Einuse); else error("not supported"); } gkscanq = qopen(256, 0, nil, nil); qunlock(&kbd.gq); break; case Qkprint: wlock(&kprintq.l); if(waserror()){ wunlock(&kprintq.l); c->flag &= ~COPEN; nexterror(); } if(kprintq.q != nil) error(Einuse); kprintq.q = qopen(32*1024, Qcoalesce, nil, nil); if(kprintq.q == nil) error(Enomem); qnoblock(kprintq.q, 1); poperror(); wunlock(&kprintq.l); c->iounit = qiomaxatomic; break; } return c; }
/* * write to a queue. only Maxatomic bytes at a time is atomic. */ int qwrite(Queue *q, void *vp, int len) { int n, sofar; Block *b; uchar *p = vp; QDEBUG if(!islo()) print("qwrite hi %#p\n", getcallerpc(&q)); /* stop queue bloat before allocating blocks */ if(q->len/2 >= q->limit && q->noblock == 0 && q->bypass == nil){ while(waserror()){ if(up->procctl == Proc_exitme || up->procctl == Proc_exitbig) error(Egreg); } qflow(q); poperror(); } sofar = 0; do { n = len-sofar; if(n > Maxatomic) n = Maxatomic; b = allocb(n); setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]); if(waserror()){ freeb(b); nexterror(); } memmove(b->wp, p+sofar, n); poperror(); b->wp += n; qbwrite(q, b); sofar += n; } while(sofar < len && (q->state & Qmsg) == 0); return len; }
Block* devbread(Chan *c, int32_t n, int64_t offset) { Mach *m = machp(); if (0) print_func_entry(); Block *bp; bp = allocb(n); if(bp == 0) error(Enomem); if(waserror()) { freeb(bp); nexterror(); } bp->wp += c->dev->read(c, bp->wp, n, offset); poperror(); if (0) print_func_exit(); return bp; }
/* * consume random bytes from a circular buffer */ ulong randomread(void *xp, ulong n) { uchar *e, *p; ulong x; p = xp; if(waserror()){ qunlock(&rb); nexterror(); } qlock(&rb); for(e = p + n; p < e; ){ if(rb.wp == rb.rp){ rb.wakeme = 1; wakeup(&rb.producer); sleep(&rb.consumer, rbnotempty, 0); rb.wakeme = 0; continue; } /* * beating clocks will be precictable if * they are synchronized. Use a cheap pseudo * random number generator to obscure any cycles. */ x = rb.randn*1103515245 ^ *rb.rp; *p++ = rb.randn = x; if(rb.rp+1 == rb.ep) rb.rp = rb.buf; else rb.rp = rb.rp+1; } qunlock(&rb); poperror(); wakeup(&rb.producer); return n; }
void sysremove(Ar0* ar0, ...) { Proc *up = externup(); Chan *c; char *aname; va_list list; va_start(list, ar0); /* * int remove(char* file); */ aname = va_arg(list, char*); c = namec(validaddr(aname, 1, 0), Aremove, 0, 0); va_end(list); /* * Removing mount points is disallowed to avoid surprises * (which should be removed: the mount point or the mounted Chan?). */ if(c->ismtpt){ cclose(c); error(Eismtpt); } if(waserror()){ c->dev = nil; /* see below */ cclose(c); nexterror(); } c->dev->remove(c); /* * Remove clunks the fid, but we need to recover the Chan * so fake it up. rootclose() is known to be a nop. Not sure this dicking around is right for Dev ref counts. */ c->dev = nil; poperror(); cclose(c); ar0->i = 0; }
static long readport(int p, ulong offset, char *buf, long n) { long t; char *b; int v[4], i; IMM *io; io = m->iomem; for(i=0;i<nelem(v); i++) v[i] = 0; switch(p){ case Qporta: v[0] = io->padat; v[1] = io->padir; v[2] = io->papar; break; case Qportb: v[0] = io->pbdat; v[1] = io->pbdir; v[2] = io->pbpar; break; case Qportc: v[0] = io->pcdat; v[1] = io->pcdir; v[2] = io->pcpar; v[3] = io->pcso; break; } b = malloc(READSTR); if(waserror()){ free(b); nexterror(); } t = 0; for(i=0; i<nelem(v); i++) t += snprint(b+t, READSTR-t, " %8.8ux", v[i]); t = readstr(offset, buf, n, b); poperror(); free(b); return t; }
static Chan* call(char *clone, char *dest, DS *ds) { int n; Chan *dchan, *cchan; char name[Maxpath], data[Maxpath], *p; cchan = namec(clone, Aopen, ORDWR, 0); /* get directory name */ if(waserror()){ cclose(cchan); nexterror(); } n = devtab[cchan->type]->read(cchan, name, sizeof(name)-1, 0); name[n] = 0; for(p = name; *p == ' '; p++) ; sprint(name, "%lud", strtoul(p, 0, 0)); p = strrchr(clone, '/'); *p = 0; if(ds->dir) snprint(ds->dir, Maxpath, "%s/%s", clone, name); snprint(data, sizeof(data), "%s/%s/data", clone, name); /* connect */ if(ds->local) snprint(name, sizeof(name), "connect %s %s", dest, ds->local); else snprint(name, sizeof(name), "connect %s", dest); devtab[cchan->type]->write(cchan, name, strlen(name), 0); /* open data connection */ dchan = namec(data, Aopen, ORDWR, 0); if(ds->ctlp) *ds->ctlp = cchan; else cclose(cchan); poperror(); return dchan; }
/* Acquire semaphore or time-out */ static int tsemacquire(Segment *s, long *addr, ulong ms) { int acquired, timedout; ulong t, elms; Sema phore; if(canacquire(addr)) return 1; if(ms == 0) return 0; acquired = timedout = 0; semqueue(s, addr, &phore); for(;;) { phore.waiting = 1; coherence(); if(canacquire(addr)) { acquired = 1; break; } if(waserror()) break; t = m->ticks; tsleep(&phore, semawoke, &phore, ms); elms = TK2MS(m->ticks - t); poperror(); if(elms >= ms) { timedout = 1; break; } ms -= elms; } semdequeue(s, &phore); coherence(); /* not strictly necessary due to lock in semdequeue */ if(!phore.waiting) semwakeup(s, addr, 1); if(timedout) return 0; if(!acquired) nexterror(); return 1; }
static long envwrite(Chan *c, void *a, long n, vlong off) { char *s; ulong len; Egrp *eg; Evalue *e; ulong offset = off; if(n <= 0) return 0; if(offset > Maxenvsize || n > (Maxenvsize - offset)) error(Etoobig); eg = envgrp(c); wlock(eg); if(waserror()){ wunlock(eg); nexterror(); } e = envlookup(eg, nil, c->qid.path); if(e == nil) error(Enonexist); len = offset+n; if(len > e->len) { s = realloc(e->value, len); if(s == nil) error(Enomem); memset(s+offset, 0, n); e->value = s; e->len = len; } memmove(e->value+offset, a, n); e->qid.vers++; eg->vers++; wunlock(eg); poperror(); return n; }
void loopdev(char *name, int mode) { Chan *c; Ctlr *volatile ctlr; SDev *volatile sdev; c = namec(name, Aopen, mode, 0); ctlr = nil; sdev = nil; if(waserror()){ cclose(c); if(ctlr) free(ctlr); if(sdev) free(sdev); nexterror(); } ctlr = smalloc(sizeof *ctlr); sdev = smalloc(sizeof *sdev); sdev->ifc = &sdloopifc; sdev->ctlr = ctlr; sdev->nunit = 1; sdev->idno = '0'; ctlr->sdev = sdev; ctlr->c = c; ctlr->mode = mode; poperror(); lock(&ctlrlock); ctlr->next = nil; ctlr->prev = ctlrtail; ctlrtail = ctlr; if(ctlr->prev) ctlr->prev->next = ctlr; else ctlrhead = ctlr; unlock(&ctlrlock); sdadddevs(sdev); }
/* Initializes a process to run virtual machine contexts, returning the number * initialized, throwing on error. */ int vmm_struct_init(struct proc *p, unsigned int nr_guest_pcores, struct vmm_gpcore_init *u_gpcis, int flags) { ERRSTACK(1); struct vmm *vmm = &p->vmm; struct vmm_gpcore_init gpci; if (flags & ~VMM_ALL_FLAGS) error(EINVAL, "%s: flags is 0x%lx, VMM_ALL_FLAGS is 0x%lx\n", __func__, flags, VMM_ALL_FLAGS); vmm->flags = flags; if (!x86_supports_vmx) error(ENODEV, "This CPU does not support VMX"); qlock(&vmm->qlock); if (waserror()) { qunlock(&vmm->qlock); nexterror(); } /* TODO: just use an atomic test instead of all this locking stuff? */ if (vmm->vmmcp) error(EAGAIN, "We're already running a vmmcp?"); /* Set this early, so cleanup checks the gpc array */ vmm->vmmcp = TRUE; nr_guest_pcores = MIN(nr_guest_pcores, num_cores); vmm->amd = 0; vmm->guest_pcores = kzmalloc(sizeof(void *) * nr_guest_pcores, MEM_WAIT); if (!vmm->guest_pcores) error(ENOMEM, "Allocation of vmm->guest_pcores failed"); for (int i = 0; i < nr_guest_pcores; i++) { if (copy_from_user(&gpci, &u_gpcis[i], sizeof(struct vmm_gpcore_init))) error(EINVAL, "Bad pointer %p for gps", u_gpcis); vmm->guest_pcores[i] = create_guest_pcore(p, &gpci); vmm->nr_guest_pcores = i + 1; } for (int i = 0; i < VMM_VMEXIT_NR_TYPES; i++) vmm->vmexits[i] = 0; qunlock(&vmm->qlock); poperror(); return vmm->nr_guest_pcores; }
static long segmentread(Chan *c, void *a, long n, vlong voff) { Globalseg *g; char buf[32]; if(c->qid.type == QTDIR) return devdirread(c, a, n, (Dirtab *)0, 0L, segmentgen); switch(TYPE(c)){ case Qctl: g = c->aux; if(g->s == nil) error("segment not yet allocated"); sprint(buf, "va %#lux %#lux\n", g->s->base, g->s->top-g->s->base); return readstr(voff, a, n, buf); case Qdata: g = c->aux; if(voff > g->s->top - g->s->base) error(Ebadarg); if(voff + n > g->s->top - g->s->base) n = g->s->top - g->s->base - voff; 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; docmd(g, Cread); memmove(a, g->data, g->dlen); free(g->data); qunlock(&g->l); poperror(); return g->dlen; default: panic("segmentread"); } return 0; /* not reached */ }
/* * if the stream doesn't exist, create it */ static struct chan *pipeopen(struct chan *c, int omode) { ERRSTACK(2); Pipe *p; if (c->qid.type & QTDIR) { if (omode & O_WRITE) error(EINVAL, "Can only open directories O_READ, mode is %o oct", omode); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } openmode(omode); /* check it */ p = c->aux; qlock(&p->qlock); if (waserror()) { qunlock(&p->qlock); nexterror(); } switch (NETTYPE(c->qid.path)) { case Qdata0: devpermcheck(p->user, p->pipedir[1].perm, omode); p->qref[0]++; break; case Qdata1: devpermcheck(p->user, p->pipedir[2].perm, omode); p->qref[1]++; break; } poperror(); qunlock(&p->qlock); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = qiomaxatomic; return c; }
long sysopen(uint32 *arg) { int fd; Chan *c = 0; char *name; openmode(arg[1]); /* error check only */ name = uvalidaddr(arg[0], 1, 0); c = namec(name, Aopen, arg[1], 0); if(waserror()){ cclose(c); nexterror(); } fd = newfd(c); if(fd < 0) error(Enofd); poperror(); return fd; }
static void mmcswitchfunc(SDio *io, int arg) { uchar *buf; int n; u32int r[4]; n = Funcbytes; buf = sdmalloc(n); if(waserror()){ print("mmcswitchfunc error\n"); sdfree(buf); nexterror(); } io->iosetup(0, buf, n, 1); io->cmd(SWITCH_FUNC, arg, r); io->io(0, buf, n); sdfree(buf); poperror(); }
static void aoectl(Ctlr *d, char *s) { Chan *c; c = nil; if(waserror()) { if(c) cclose(c); print("sdaoectl: %s\n", up->errstr); nexterror(); } uprint("%s/ctl", d->path); c = namec(up->genbuf, Aopen, OWRITE, 0); devtab[c->type]->write(c, s, strlen(s), 0); poperror(); cclose(c); }
void netlogopen(Fs *f) { lock(f->alog); if(waserror()){ unlock(f->alog); nexterror(); } if(f->alog->opens == 0){ if(f->alog->buf == nil) f->alog->buf = malloc(Nlog); if(f->alog->buf == nil) error(Enomem); f->alog->rptr = f->alog->buf; f->alog->end = f->alog->buf + Nlog; } f->alog->opens++; unlock(f->alog); poperror(); }
long bindmount(struct chan *c, char *old, int flag, char *spec) { ERRSTACK(1); int ret; struct chan *c1; if (flag > MMASK || (flag & MORDER) == (MBEFORE | MAFTER)) error(EINVAL, ERROR_FIXME); c1 = namec(old, Amount, 0, 0); if (waserror()) { cclose(c1); nexterror(); } ret = cmount(c, c1, flag, spec); poperror(); cclose(c1); return ret; }
/* * if the stream doesn't exist, create it */ static Chan* pipeopen(Chan *c, int omode) { Pipe *p; if(c->qid.type & QTDIR){ if(omode != OREAD) error(Ebadarg); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } openmode(omode); /* check it */ p = c->aux; qlock(&p->l); if(waserror()){ qunlock(&p->l); nexterror(); } switch(NETTYPE(c->qid.path)){ case Qdata0: devpermcheck(p->user, p->pipedir[1].perm, omode); p->qref[0]++; break; case Qdata1: devpermcheck(p->user, p->pipedir[2].perm, omode); p->qref[1]++; break; } poperror(); qunlock(&p->l); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = qiomaxatomic; return c; }
/* * remove a multicast address from an interface, called with c locked */ void ipifcremmulti(struct conv *c, uint8_t * ma, uint8_t * ia) { ERRSTACK(1); struct Ipmulti *multi, **l; struct Iplifc *lifc; struct conv **p; struct Ipifc *ifc; struct Fs *f; f = c->p->f; for (l = &c->multi; *l; l = &(*l)->next) if (ipcmp(ma, (*l)->ma) == 0) if (ipcmp(ia, (*l)->ia) == 0) break; multi = *l; if (multi == NULL) return; /* we don't have it open */ *l = multi->next; for (p = f->ipifc->conv; *p; p++) { if ((*p)->inuse == 0) continue; ifc = (struct Ipifc *)(*p)->ptcl; if (waserror()) { wunlock(&ifc->rwlock); nexterror(); } wlock(&ifc->rwlock); for (lifc = ifc->lifc; lifc; lifc = lifc->next) if (ipcmp(ia, lifc->local) == 0) remselfcache(f, ifc, lifc, ma); wunlock(&ifc->rwlock); poperror(); } kfree(multi); }
void sysstat(Ar0* ar0, ...) { Proc *up = externup(); char *aname; Chan *c; usize n; int r; uint8_t *p; va_list list; va_start(list, ar0); /* * int stat(char* name, uchar* edir, int nedir); * should really be * usize stat(char* name, uchar* edir, usize nedir); * but returning an unsigned is probably too * radical. */ aname = va_arg(list, char*); aname = validaddr(aname, 1, 0); p = va_arg(list, uint8_t*); n = va_arg(list, usize); va_end(list); p = validaddr(p, n, 1); c = namec(aname, Aaccess, 0, 0); if(waserror()){ cclose(c); nexterror(); } r = c->dev->stat(c, p, n); aname = pathlast(c->path); if(aname) r = dirsetname(aname, strlen(aname), p, r, n); poperror(); cclose(c); ar0->i = r; }
/* * remove a multicast address from an interface, called with c->car locked */ void ipifcremmulti(Conv *c, uint8_t *ma, uint8_t *ia) { Proc *up = externup(); Ipmulti *multi, **l; Iplifc *lifc; Conv **p; Ipifc *ifc; Fs *f; f = c->p->f; for(l = &c->multi; *l; l = &(*l)->next) if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0) break; multi = *l; if(multi == nil) return; /* we don't have it open */ *l = multi->next; for(p = f->ipifc->conv; *p; p++){ if((*p)->inuse == 0) continue; ifc = (Ipifc*)(*p)->ptcl; if(waserror()){ wunlock(ifc); nexterror(); } wlock(ifc); for(lifc = ifc->lifc; lifc; lifc = lifc->next) if(ipcmp(ia, lifc->local) == 0) remselfcache(f, ifc, lifc, ma); wunlock(ifc); poperror(); } free(multi); }
static void zmapfree(ZMap* rmap, uintptr_t addr) { Mach *m = machp(); Map *mp, *prev, *next; lock(rmap); if(waserror()){ unlock(rmap); nexterror(); } prev = nil; for(mp = rmap->map; mp != nil; mp = mp->next){ if(mp->addr <= addr) break; prev = mp; } if(mp == nil) panic("zmapfree: no map"); if(mp->free == 1) panic("zmapfree: already free"); if(prev != nil && prev->free && prev->addr + prev->size == addr){ prev->size += mp->size; prev->next = mp->next; free(mp); mp = prev; } next = mp->next; if(next != nil && next->free && mp->addr + mp->size == next->addr){ mp->size += next->size; mp->next = next->next; mp->free = 1; free(next); } poperror(); unlock(rmap); if(DBGFLG > 1){ DBG("zmapfree %#ullx:\n", addr); dumpzmap(rmap); } }
/* * flow control, wait for queue to get below the limit */ static void qflow(Queue *q) { for(;;){ if(q->noblock || qnotfull(q)) break; ilock(q); q->state |= Qflow; iunlock(q); eqlock(&q->wlock); if(waserror()){ qunlock(&q->wlock); nexterror(); } sleep(&q->wr, qnotfull, q); qunlock(&q->wlock); poperror(); } }
static Chan* pointeropen(Chan* c, int omode) { c = devopen(c, omode, pointertab, nelem(pointertab), devgen); if((ulong)c->qid.path == Qpointer){ if(waserror()){ c->flag &= ~COPEN; nexterror(); } if(!canqlock(&mouse.q)) error(Einuse); if(incref(&mouse.ref) != 1){ qunlock(&mouse.q); error(Einuse); } cursorenable(); qunlock(&mouse.q); poperror(); } return c; }
static void waitnotstale(Mach *mp, PmcCtr *p) { Proc *up = externup(); PmcWait *w; p->stale = 1; w = newpmcw(); w->next = p->wq; p->wq = w; incref(&w->r); iunlock(&mp->pmclock); apicipi(mp->apicno); if(waserror()){ pmcwclose(w); nexterror(); } sleep(&w->rend, notstale, p); poperror(); pmcwclose(w); }
long syscreate(uint32 *arg) { int fd; Chan *c = 0; char *name; openmode(arg[1]&~OEXCL); /* error check only; OEXCL okay here */ if(waserror()) { if(c) cclose(c); nexterror(); } name = uvalidaddr(arg[0], 1, 0); c = namec(name, Acreate, arg[1], arg[2]); fd = newfd(c); if(fd < 0) error(Enofd); poperror(); return fd; }
static void pppreader(void *a) { Ipifc *ifc; Block *bp; PPP *ppp; ifc = a; ppp = ifc->arg; ppp->readp = up; /* hide identity under a rock for unbind */ setpri(PriHi); if (waserror()) { netlog(ppp->f, Logppp, "pppreader: %I: %s\n", ppp->local, up->env->errstr); ppp->readp = 0; deadremote(ifc); pexit("hangup", 1); } for (;;) { bp = pppread(ppp); if (bp == nil) error("hungup"); if (!canrlock(ifc)) { freeb(bp); continue; } if (waserror()) { runlock(ifc); nexterror(); } ifc->in++; if (ifc->lifc == nil) freeb(bp); else ipiput(ppp->f, ifc, bp); runlock(ifc); poperror(); } }
/* * Return a copy of configuration environment as a sequence of strings. * The strings alternate between name and value. A zero length name string * indicates the end of the list */ char * getconfenv(void) { Proc *up = externup(); Egrp *eg = &confegrp; Evalue *e; char *p, *q; int i, n; rlock(&eg->rwl); if(waserror()) { runlock(&eg->rwl); nexterror(); } /* determine size */ n = 0; for(i=0; i<eg->nent; i++){ e = eg->ent[i]; n += strlen(e->name) + e->len + 2; } p = malloc(n + 1); if(p == nil) error(Enomem); q = p; for(i=0; i<eg->nent; i++){ e = eg->ent[i]; strcpy(q, e->name); q += strlen(q) + 1; memmove(q, e->value, e->len); q[e->len] = 0; /* move up to the first null */ q += strlen(q) + 1; } *q = 0; poperror(); runlock(&eg->rwl); return p; }