#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" enum{ Qtopdir, Qsegdir, Qctl, Qdata, /* commands to kproc */ Cnone=0, Cread, Cwrite, Cstart, Cdie,}; #define TYPE(x) (int)( (c)->qid.path & 0x7 )#define SEG(x) ( ((c)->qid.path >> 3) & 0x3f )#define PATH(s, t) ( ((s)<<3) | (t) ) typedef struct Globalseg Globalseg;struct Globalseg{ Ref; Segment *s; char *name; char *uid; vlong length; long perm; /* kproc to do reading and writing */ QLock l; /* sync kproc access */ Rendez cmdwait; /* where kproc waits */ Rendez replywait; /* where requestor waits */ Proc *kproc; char *data; long off; int dlen; int cmd; char err[64];}; static Globalseg *globalseg[100];static Lock globalseglock; Segment* (*_globalsegattach)(Proc*, char*);static Segment* globalsegattach(Proc *p, char *name);static int cmddone(void*);static void segmentkproc(void*);static void docmd(Globalseg *g, int cmd); /* the megabyte map used for P==V in cnk program heap */u32int mbmap[4096];struct Physseg cnkmbseg = { .attr = 0, .size = 0, .pa = 0, .name = "P==V segment"}; voidcnkmbinit(int basemb, int sizemb){ cnkmbseg.pa = basemb * MiB; cnkmbseg.size = (MiB*sizemb)/BY2PG; cnkmbseg.attr = SG_PHYSICAL;print("cnkbase %#lx pages %ld \n", cnkmbseg.pa, cnkmbseg.size);}voidcnkmbfree(u32int addr){ mbmap[addr>>20] = 1;} /* find a physically contiguous bunch of mb. For now, just do 1 */void *cnkmbmalloc(int){ extern u32int cnkbase; int i; for(i = cnkbase; mbmap[i] && i < sys->tom; i++) ; if (i < sys->tom) return (void *) (i <<20); return nil;} /* * returns with globalseg incref'd */static Globalseg*getgseg(Chan *c){ int x; Globalseg *g; x = SEG(c); lock(&globalseglock); if(x >= nelem(globalseg)) panic("getgseg"); g = globalseg[x]; if(g != nil) incref(g); unlock(&globalseglock); if(g == nil) error("global segment disappeared"); return g;} static voidputgseg(Globalseg *g){ up->heapseg = nil; if(decref(g) > 0) return; if(g->s != nil) putseg(g->s); if(g->kproc) docmd(g, Cdie); free(g->name); free(g->uid); free(g);} static intsegmentgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp){ Qid q; Globalseg *g; ulong size; switch(TYPE(c)) { case Qtopdir: if(s == DEVDOTDOT){ q.vers = 0; q.path = PATH(0, Qtopdir); q.type = QTDIR; devdir(c, q, "#g", 0, eve, DMDIR|0777, dp); break; } if(s >= nelem(globalseg)) return -1; lock(&globalseglock); g = globalseg[s]; if(g == nil){ unlock(&globalseglock); return 0; } q.vers = 0; q.path = PATH(s, Qsegdir); q.type = QTDIR; devdir(c, q, g->name, 0, g->uid, DMDIR|0777, dp); unlock(&globalseglock); break; case Qsegdir: if(s == DEVDOTDOT){ q.vers = 0; q.path = PATH(0, Qtopdir); q.type = QTDIR; devdir(c, q, "#g", 0, eve, DMDIR|0777, dp); break; } /* fall through */ case Qctl: case Qdata: switch(s){ case 0: g = getgseg(c); q.vers = 0; q.path = PATH(SEG(c), Qctl); q.type = QTFILE; devdir(c, q, "ctl", 0, g->uid, g->perm, dp); putgseg(g); break; case 1: g = getgseg(c); q.vers = 0; q.path = PATH(SEG(c), Qdata); q.type = QTFILE; if(g->s != nil) size = g->s->top - g->s->base; else size = 0; devdir(c, q, "data", size, g->uid, g->perm, dp); putgseg(g); break; default: return -1; } break; } return 1;} static voidsegmentinit(void){ _globalsegattach = globalsegattach;} static Chan*segmentattach(char *spec){ return devattach('g', spec);} static Walkqid*segmentwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, segmentgen);} static longsegmentstat(Chan *c, uchar *db, long n){ return devstat(c, db, n, 0, 0, segmentgen);} static intcmddone(void *arg){ Globalseg *g = arg; return g->cmd == Cnone;} static Chan*segmentopen(Chan *c, int omode){ Globalseg *g; switch(TYPE(c)){ case Qtopdir: case Qsegdir: if(omode != 0) error(Eisdir); break; case Qctl: g = getgseg(c); if(waserror()){ putgseg(g); nexterror(); } devpermcheck(g->uid, g->perm, omode); c->aux = g; poperror(); c->flag |= COPEN; break; case Qdata: g = getgseg(c); if(waserror()){ putgseg(g); nexterror(); } devpermcheck(g->uid, g->perm, omode); if(g->s == nil) error("segment not yet allocated"); if(g->kproc == nil){ qlock(&g->l); if(waserror()){ qunlock(&g->l); nexterror(); } if(g->kproc == nil){ g->cmd = Cnone; kproc(g->name, segmentkproc, g); docmd(g, Cstart); } qunlock(&g->l); poperror(); } c->aux = g; poperror(); c->flag |= COPEN; break; default: panic("segmentopen"); } c->mode = openmode(omode); c->offset = 0; return c;} static voidsegmentclose(Chan *c){ if(TYPE(c) == Qtopdir) return; if(c->flag & COPEN) putgseg(c->aux);} /* cnk programs really like numbers. So we require that the name be a number. * we don't enforce it. */static voidsegmentcreate(Chan *c, char *name, int omode, int perm){ unsigned int segno; Globalseg *g; if(TYPE(c) != Qtopdir) error(Eperm); if(isphysseg(name)) error(Eexist); if((perm & DMDIR) == 0) error("DMDIR not set"); if(waserror()){ unlock(&globalseglock); nexterror(); } segno = strtoul(name, 0, 0); lock(&globalseglock); g = globalseg[segno]; if(g) error("Segment already in use"); g = smalloc(sizeof(Globalseg)); g->ref = 1; kstrdup(&g->name, name); kstrdup(&g->uid, up->user); g->perm = 0660; globalseg[segno] = g; unlock(&globalseglock); poperror(); c->qid.path = PATH(segno, Qsegdir); c->qid.type = QTDIR; c->qid.vers = 0; c->mode = openmode(omode); c->mode = OWRITE;} static longsegmentread(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("voff > g->s->top - g->s->base"); 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 */} static longsegmentwrite(Chan *c, void *a, long n, vlong voff){ Cmdbuf *cb; Globalseg *g; ulong va, len, top; extern u32int cnkbase; 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("usage: start va len"); 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("len is zero"); /* if this segment is in the P==V range, make it SG_PHYSICAL, otherwise, not */ if (cnkbase && va >= cnkbase*MiB){ g->s = newseg(SG_PHYSICAL, va, len); g->s->nozfod = 1; g->s->pseg = &cnkmbseg; } else g->s = newseg(SG_SHARED, va, len); } else if(strcmp(cb->f[0], "heap") == 0){ int i; /* CNK mode: no errstr. So print these too, they're critical and you need to know. */ if (!g){ print("%d: no globalseg\n", up->pid); error("no globalseg"); } if (!g->s){ print("%d: no segment\n", up->pid); error("no segment"); } if (up->heapseg){ print("%d: heap already set\n", up->pid); error("heap already set"); } up->heapseg = g->s; /* pre-fault the pages in */ if (! cnkbase) for(i = 0; i < g->s->size; i++) { print("Pre-fault %#ulx\n", g->s->base + i*BY2PG); fault(g->s->base + i*BY2PG, 0); } } else error(Ebadctl); break; case Qdata: g = c->aux; if(voff + n > g->s->top - g->s->base) error("voff + n > g->s->top - g->s->base"); 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 */} static longsegmentwstat(Chan *c, uchar *dp, long n){ Globalseg *g; Dir *d; if(c->qid.type == QTDIR) error(Eperm); g = getgseg(c); if(waserror()){ putgseg(g); nexterror(); } if(strcmp(g->uid, up->user) && !iseve()) error(Eperm); d = smalloc(sizeof(Dir)+n); n = convM2D(dp, n, &d[0], (char*)&d[1]); g->perm = d->mode & 0777; putgseg(g); poperror(); free(d); return n;} Lines 1–500 of 639. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" enum { Qtopdir, Qsegdir, Qctl, Qdata, /* commands to kproc */ Cnone=0, Cread, Cwrite, Cstart, Cdie, }; #define TYPE(x) (int)( (c)->qid.path & 0x7 ) #define SEG(x) ( ((c)->qid.path >> 3) & 0x3f ) #define PATH(s, t) ( ((s)<<3) | (t) ) typedef struct Globalseg Globalseg; struct Globalseg { Ref; Segment *s; char *name; char *uid; vlong length; long perm; /* kproc to do reading and writing */ QLock l; /* sync kproc access */ Rendez cmdwait; /* where kproc waits */ Rendez replywait; /* where requestor waits */ Proc *kproc; char *data; long off; int dlen; int cmd; char err[64]; }; static Globalseg *globalseg[100]; static Lock globalseglock; Segment* (*_globalsegattach)(Proc*, char*); static Segment* globalsegattach(Proc *p, char *name); static int cmddone(void*); static void segmentkproc(void*); static void docmd(Globalseg *g, int cmd); /* the megabyte map used for P==V in cnk program heap */ u32int mbmap[4096]; struct Physseg cnkmbseg = { .attr = 0, .size = 0, .pa = 0, .name = "P==V segment" }; void cnkmbinit(int basemb, int sizemb) { cnkmbseg.pa = basemb * MiB; cnkmbseg.size = (MiB*sizemb)/BY2PG; cnkmbseg.attr = SG_PHYSICAL; print("cnkbase %#lx pages %ld \n", cnkmbseg.pa, cnkmbseg.size); } void cnkmbfree(u32int addr) { mbmap[addr>>20] = 1; } /* find a physically contiguous bunch of mb. For now, just do 1 */ void * cnkmbmalloc(int){ extern u32int cnkbase; int i; for(i = cnkbase; mbmap[i] && i < sys->tom; i++) ; if (i < sys->tom) return (void *) (i <<20); return nil; } /* * returns with globalseg incref'd */ static Globalseg* getgseg(Chan *c) { int x; Globalseg *g; x = SEG(c); lock(&globalseglock); if(x >= nelem(globalseg)) panic("getgseg"); g = globalseg[x]; if(g != nil) incref(g); unlock(&globalseglock); if(g == nil) error("global segment disappeared"); return g; } static void putgseg(Globalseg *g) { up->heapseg = nil; if(decref(g) > 0) return; if(g->s != nil) putseg(g->s); if(g->kproc) docmd(g, Cdie); free(g->name); free(g->uid); free(g); } static int segmentgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp) { Qid q; Globalseg *g; ulong size; switch(TYPE(c)) { case Qtopdir: if(s == DEVDOTDOT){ q.vers = 0; q.path = PATH(0, Qtopdir); q.type = QTDIR; devdir(c, q, "#g", 0, eve, DMDIR|0777, dp); break; } if(s >= nelem(globalseg)) return -1; lock(&globalseglock); g = globalseg[s]; if(g == nil){ unlock(&globalseglock); return 0; } q.vers = 0; q.path = PATH(s, Qsegdir); q.type = QTDIR; devdir(c, q, g->name, 0, g->uid, DMDIR|0777, dp); unlock(&globalseglock); break; case Qsegdir: if(s == DEVDOTDOT){ q.vers = 0; q.path = PATH(0, Qtopdir); q.type = QTDIR; devdir(c, q, "#g", 0, eve, DMDIR|0777, dp); break; } /* fall through */ case Qctl: case Qdata: switch(s){ case 0: g = getgseg(c); q.vers = 0; q.path = PATH(SEG(c), Qctl); q.type = QTFILE; devdir(c, q, "ctl", 0, g->uid, g->perm, dp); putgseg(g); break; case 1: g = getgseg(c); q.vers = 0; q.path = PATH(SEG(c), Qdata); q.type = QTFILE; if(g->s != nil) size = g->s->top - g->s->base; else size = 0; devdir(c, q, "data", size, g->uid, g->perm, dp); putgseg(g); break; default: return -1; } break; } return 1; } static void segmentinit(void) { _globalsegattach = globalsegattach; } static Chan* segmentattach(char *spec) { return devattach('g', spec); } static Walkqid* segmentwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, segmentgen); } static long segmentstat(Chan *c, uchar *db, long n) { return devstat(c, db, n, 0, 0, segmentgen); } static int cmddone(void *arg) { Globalseg *g = arg; return g->cmd == Cnone; } static Chan* segmentopen(Chan *c, int omode) { Globalseg *g; switch(TYPE(c)){ case Qtopdir: case Qsegdir: if(omode != 0) error(Eisdir); break; case Qctl: g = getgseg(c); if(waserror()){ putgseg(g); nexterror(); } devpermcheck(g->uid, g->perm, omode); c->aux = g; poperror(); c->flag |= COPEN; break; case Qdata: g = getgseg(c); if(waserror()){ putgseg(g); nexterror(); } devpermcheck(g->uid, g->perm, omode); if(g->s == nil) error("segment not yet allocated"); if(g->kproc == nil){ qlock(&g->l); if(waserror()){ qunlock(&g->l); nexterror(); } if(g->kproc == nil){ g->cmd = Cnone; kproc(g->name, segmentkproc, g); docmd(g, Cstart); } qunlock(&g->l); poperror(); } c->aux = g; poperror(); c->flag |= COPEN; break; default: panic("segmentopen"); } c->mode = openmode(omode); c->offset = 0; return c; } static void segmentclose(Chan *c) { if(TYPE(c) == Qtopdir) return; if(c->flag & COPEN) putgseg(c->aux); } /* cnk programs really like numbers. So we require that the name be a number. * we don't enforce it. */ static void segmentcreate(Chan *c, char *name, int omode, int perm) { unsigned int segno; Globalseg *g; if(TYPE(c) != Qtopdir) error(Eperm); if(isphysseg(name)) error(Eexist); if((perm & DMDIR) == 0) error("DMDIR not set"); if(waserror()){ unlock(&globalseglock); nexterror(); } segno = strtoul(name, 0, 0); lock(&globalseglock); g = globalseg[segno]; if(g) error("Segment already in use"); g = smalloc(sizeof(Globalseg)); g->ref = 1; kstrdup(&g->name, name); kstrdup(&g->uid, up->user); g->perm = 0660; globalseg[segno] = g; unlock(&globalseglock); poperror(); c->qid.path = PATH(segno, Qsegdir); c->qid.type = QTDIR; c->qid.vers = 0; c->mode = openmode(omode); c->mode = OWRITE; } 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("voff > g->s->top - g->s->base"); 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 */ } static long segmentwrite(Chan *c, void *a, long n, vlong voff) { Cmdbuf *cb; Globalseg *g; ulong va, len, top; extern u32int cnkbase; 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("usage: start va len"); 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("len is zero"); /* if this segment is in the P==V range, make it SG_PHYSICAL, otherwise, not */ if (cnkbase && va >= cnkbase*MiB){ g->s = newseg(SG_PHYSICAL, va, len); g->s->nozfod = 1; g->s->pseg = &cnkmbseg; } else g->s = newseg(SG_SHARED, va, len); } else if(strcmp(cb->f[0], "heap") == 0){ int i; /* CNK mode: no errstr. So print these too, they're critical and you need to know. */ if (!g){ print("%d: no globalseg\n", up->pid); error("no globalseg"); } if (!g->s){ print("%d: no segment\n", up->pid); error("no segment"); } if (up->heapseg){ print("%d: heap already set\n", up->pid); error("heap already set"); } up->heapseg = g->s; /* pre-fault the pages in */ if (! cnkbase) for(i = 0; i < g->s->size; i++) { print("Pre-fault %#ulx\n", g->s->base + i*BY2PG); fault(g->s->base + i*BY2PG, 0); } } else error(Ebadctl); break; case Qdata: g = c->aux; if(voff + n > g->s->top - g->s->base) error("voff + n > g->s->top - g->s->base"); 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 */ } static long segmentwstat(Chan *c, uchar *dp, long n) { Globalseg *g; Dir *d; if(c->qid.type == QTDIR) error(Eperm); g = getgseg(c); if(waserror()){ putgseg(g); nexterror(); } if(strcmp(g->uid, up->user) && !iseve()) error(Eperm); d = smalloc(sizeof(Dir)+n); n = convM2D(dp, n, &d[0], (char*)&d[1]); g->perm = d->mode & 0777; putgseg(g); poperror(); free(d); return n; }