/* * add an address to s's zseg; s is qlocked. * wakeup any reader if it's waiting. */ int zputaddr(Segment *s, uintptr_t va) { Zseg *zs; zs = &s->zseg; if((s->type&SG_ZIO) == 0) return -1; if((s->type&SG_KZIO) != 0){ DBG("zputaddr: zmapfree %#ullx\n", va); zmapfree(s->zseg.map, va); dumpzseg(s); return 0; } if(zs->end == zs->naddr) zgrow(s); zs->addr[zs->end++] = va; if(zs->end == 1) wakeup(&zs->rr); /* in case anyone was waiting */ DBG("zputaddr %#ullx\n", va); dumpzseg(s); return 0; }
/* * Find an address in s's zseg; s is qlocked */ uintptr_t zgetaddr(Segment *s) { Zseg *zs; uintptr_t va; zs = &s->zseg; if(zs->end == 0) return 0ULL; va = zs->addr[0]; zs->end--; if(zs->end > 0) zs->addr[0] = zs->addr[zs->end]; DBG("zgetaddr: %#ullx\n", va); dumpzseg(s); return va; }
/* * Called from putseg, when the segment is being destroyed. */ void freezseg(Segment *s) { Zseg *zs; ZMap *zp; Map *mp; DBG("freezseg: "); dumpzseg(s); zs = &s->zseg; zp = zs->map; if(zp == nil) return; while(zp->map != nil){ mp = zp->map; zp->map = mp->next; free(mp); } free(zp); }
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; }