19a747e4fSDavid du Colombier #include "u.h"
29a747e4fSDavid du Colombier #include "../port/lib.h"
39a747e4fSDavid du Colombier #include "mem.h"
49a747e4fSDavid du Colombier #include "dat.h"
59a747e4fSDavid du Colombier #include "fns.h"
69a747e4fSDavid du Colombier #include "../port/error.h"
79a747e4fSDavid du Colombier
89a747e4fSDavid du Colombier enum
99a747e4fSDavid du Colombier {
109a747e4fSDavid du Colombier Qtopdir,
119a747e4fSDavid du Colombier Qsegdir,
129a747e4fSDavid du Colombier Qctl,
139a747e4fSDavid du Colombier Qdata,
149a747e4fSDavid du Colombier
159a747e4fSDavid du Colombier /* commands to kproc */
169a747e4fSDavid du Colombier Cnone=0,
179a747e4fSDavid du Colombier Cread,
189a747e4fSDavid du Colombier Cwrite,
199a747e4fSDavid du Colombier Cstart,
209a747e4fSDavid du Colombier Cdie,
219a747e4fSDavid du Colombier };
229a747e4fSDavid du Colombier
239a747e4fSDavid du Colombier #define TYPE(x) (int)( (c)->qid.path & 0x7 )
249a747e4fSDavid du Colombier #define SEG(x) ( ((c)->qid.path >> 3) & 0x3f )
259a747e4fSDavid du Colombier #define PATH(s, t) ( ((s)<<3) | (t) )
269a747e4fSDavid du Colombier
279a747e4fSDavid du Colombier typedef struct Globalseg Globalseg;
289a747e4fSDavid du Colombier struct Globalseg
299a747e4fSDavid du Colombier {
309a747e4fSDavid du Colombier Ref;
319a747e4fSDavid du Colombier Segment *s;
329a747e4fSDavid du Colombier
339a747e4fSDavid du Colombier char *name;
349a747e4fSDavid du Colombier char *uid;
359a747e4fSDavid du Colombier vlong length;
369a747e4fSDavid du Colombier long perm;
379a747e4fSDavid du Colombier
389a747e4fSDavid du Colombier /* kproc to do reading and writing */
399a747e4fSDavid du Colombier QLock l; /* sync kproc access */
409a747e4fSDavid du Colombier Rendez cmdwait; /* where kproc waits */
419a747e4fSDavid du Colombier Rendez replywait; /* where requestor waits */
429a747e4fSDavid du Colombier Proc *kproc;
439a747e4fSDavid du Colombier char *data;
449a747e4fSDavid du Colombier long off;
459a747e4fSDavid du Colombier int dlen;
469a747e4fSDavid du Colombier int cmd;
479a747e4fSDavid du Colombier char err[64];
489a747e4fSDavid du Colombier };
499a747e4fSDavid du Colombier
509a747e4fSDavid du Colombier static Globalseg *globalseg[100];
519a747e4fSDavid du Colombier static Lock globalseglock;
529a747e4fSDavid du Colombier
539a747e4fSDavid du Colombier
549a747e4fSDavid du Colombier Segment* (*_globalsegattach)(Proc*, char*);
559a747e4fSDavid du Colombier static Segment* globalsegattach(Proc *p, char *name);
569a747e4fSDavid du Colombier static int cmddone(void*);
579a747e4fSDavid du Colombier static void segmentkproc(void*);
589a747e4fSDavid du Colombier static void docmd(Globalseg *g, int cmd);
599a747e4fSDavid du Colombier
609a747e4fSDavid du Colombier /*
619a747e4fSDavid du Colombier * returns with globalseg incref'd
629a747e4fSDavid du Colombier */
639a747e4fSDavid du Colombier static Globalseg*
getgseg(Chan * c)649a747e4fSDavid du Colombier getgseg(Chan *c)
659a747e4fSDavid du Colombier {
669a747e4fSDavid du Colombier int x;
679a747e4fSDavid du Colombier Globalseg *g;
689a747e4fSDavid du Colombier
699a747e4fSDavid du Colombier x = SEG(c);
709a747e4fSDavid du Colombier lock(&globalseglock);
719a747e4fSDavid du Colombier if(x >= nelem(globalseg))
729a747e4fSDavid du Colombier panic("getgseg");
739a747e4fSDavid du Colombier g = globalseg[x];
749a747e4fSDavid du Colombier if(g != nil)
759a747e4fSDavid du Colombier incref(g);
769a747e4fSDavid du Colombier unlock(&globalseglock);
779a747e4fSDavid du Colombier if(g == nil)
789a747e4fSDavid du Colombier error("global segment disappeared");
799a747e4fSDavid du Colombier return g;
809a747e4fSDavid du Colombier }
819a747e4fSDavid du Colombier
829a747e4fSDavid du Colombier static void
putgseg(Globalseg * g)839a747e4fSDavid du Colombier putgseg(Globalseg *g)
849a747e4fSDavid du Colombier {
859a747e4fSDavid du Colombier if(decref(g) > 0)
869a747e4fSDavid du Colombier return;
879a747e4fSDavid du Colombier if(g->s != nil)
889a747e4fSDavid du Colombier putseg(g->s);
899a747e4fSDavid du Colombier if(g->kproc)
909a747e4fSDavid du Colombier docmd(g, Cdie);
919a747e4fSDavid du Colombier free(g->name);
929a747e4fSDavid du Colombier free(g->uid);
939a747e4fSDavid du Colombier free(g);
949a747e4fSDavid du Colombier }
959a747e4fSDavid du Colombier
969a747e4fSDavid du Colombier static int
segmentgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)979a747e4fSDavid du Colombier segmentgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
989a747e4fSDavid du Colombier {
999a747e4fSDavid du Colombier Qid q;
1009a747e4fSDavid du Colombier Globalseg *g;
1019a747e4fSDavid du Colombier ulong size;
1029a747e4fSDavid du Colombier
1039a747e4fSDavid du Colombier switch(TYPE(c)) {
1049a747e4fSDavid du Colombier case Qtopdir:
1059a747e4fSDavid du Colombier if(s == DEVDOTDOT){
1069a747e4fSDavid du Colombier q.vers = 0;
1079a747e4fSDavid du Colombier q.path = PATH(0, Qtopdir);
1089a747e4fSDavid du Colombier q.type = QTDIR;
1099a747e4fSDavid du Colombier devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
1109a747e4fSDavid du Colombier break;
1119a747e4fSDavid du Colombier }
1129a747e4fSDavid du Colombier
1139a747e4fSDavid du Colombier if(s >= nelem(globalseg))
1149a747e4fSDavid du Colombier return -1;
1159a747e4fSDavid du Colombier
1169a747e4fSDavid du Colombier lock(&globalseglock);
1179a747e4fSDavid du Colombier g = globalseg[s];
1189a747e4fSDavid du Colombier if(g == nil){
1199a747e4fSDavid du Colombier unlock(&globalseglock);
1209a747e4fSDavid du Colombier return 0;
1219a747e4fSDavid du Colombier }
1229a747e4fSDavid du Colombier q.vers = 0;
1239a747e4fSDavid du Colombier q.path = PATH(s, Qsegdir);
1249a747e4fSDavid du Colombier q.type = QTDIR;
1259a747e4fSDavid du Colombier devdir(c, q, g->name, 0, g->uid, DMDIR|0777, dp);
1269a747e4fSDavid du Colombier unlock(&globalseglock);
1279a747e4fSDavid du Colombier
1289a747e4fSDavid du Colombier break;
1299a747e4fSDavid du Colombier case Qsegdir:
1309a747e4fSDavid du Colombier if(s == DEVDOTDOT){
1319a747e4fSDavid du Colombier q.vers = 0;
1329a747e4fSDavid du Colombier q.path = PATH(0, Qtopdir);
1339a747e4fSDavid du Colombier q.type = QTDIR;
1349a747e4fSDavid du Colombier devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
1359a747e4fSDavid du Colombier break;
1369a747e4fSDavid du Colombier }
1379a747e4fSDavid du Colombier /* fall through */
1389a747e4fSDavid du Colombier case Qctl:
1399a747e4fSDavid du Colombier case Qdata:
1409a747e4fSDavid du Colombier switch(s){
1419a747e4fSDavid du Colombier case 0:
1429a747e4fSDavid du Colombier g = getgseg(c);
1439a747e4fSDavid du Colombier q.vers = 0;
1449a747e4fSDavid du Colombier q.path = PATH(SEG(c), Qctl);
1459a747e4fSDavid du Colombier q.type = QTFILE;
1469a747e4fSDavid du Colombier devdir(c, q, "ctl", 0, g->uid, g->perm, dp);
1479a747e4fSDavid du Colombier putgseg(g);
1489a747e4fSDavid du Colombier break;
1499a747e4fSDavid du Colombier case 1:
1509a747e4fSDavid du Colombier g = getgseg(c);
1519a747e4fSDavid du Colombier q.vers = 0;
1529a747e4fSDavid du Colombier q.path = PATH(SEG(c), Qdata);
1539a747e4fSDavid du Colombier q.type = QTFILE;
1549a747e4fSDavid du Colombier if(g->s != nil)
1559a747e4fSDavid du Colombier size = g->s->top - g->s->base;
1569a747e4fSDavid du Colombier else
1579a747e4fSDavid du Colombier size = 0;
1589a747e4fSDavid du Colombier devdir(c, q, "data", size, g->uid, g->perm, dp);
1599a747e4fSDavid du Colombier putgseg(g);
1609a747e4fSDavid du Colombier break;
1619a747e4fSDavid du Colombier default:
1629a747e4fSDavid du Colombier return -1;
1639a747e4fSDavid du Colombier }
1649a747e4fSDavid du Colombier break;
1659a747e4fSDavid du Colombier }
1669a747e4fSDavid du Colombier return 1;
1679a747e4fSDavid du Colombier }
1689a747e4fSDavid du Colombier
1699a747e4fSDavid du Colombier static void
segmentinit(void)1709a747e4fSDavid du Colombier segmentinit(void)
1719a747e4fSDavid du Colombier {
1729a747e4fSDavid du Colombier _globalsegattach = globalsegattach;
1739a747e4fSDavid du Colombier }
1749a747e4fSDavid du Colombier
1759a747e4fSDavid du Colombier static Chan*
segmentattach(char * spec)1769a747e4fSDavid du Colombier segmentattach(char *spec)
1779a747e4fSDavid du Colombier {
1789a747e4fSDavid du Colombier return devattach('g', spec);
1799a747e4fSDavid du Colombier }
1809a747e4fSDavid du Colombier
1819a747e4fSDavid du Colombier static Walkqid*
segmentwalk(Chan * c,Chan * nc,char ** name,int nname)1829a747e4fSDavid du Colombier segmentwalk(Chan *c, Chan *nc, char **name, int nname)
1839a747e4fSDavid du Colombier {
1849a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, 0, 0, segmentgen);
1859a747e4fSDavid du Colombier }
1869a747e4fSDavid du Colombier
1879a747e4fSDavid du Colombier static int
segmentstat(Chan * c,uchar * db,int n)1889a747e4fSDavid du Colombier segmentstat(Chan *c, uchar *db, int n)
1899a747e4fSDavid du Colombier {
1909a747e4fSDavid du Colombier return devstat(c, db, n, 0, 0, segmentgen);
1919a747e4fSDavid du Colombier }
1929a747e4fSDavid du Colombier
1939a747e4fSDavid du Colombier static int
cmddone(void * arg)1949a747e4fSDavid du Colombier cmddone(void *arg)
1959a747e4fSDavid du Colombier {
1969a747e4fSDavid du Colombier Globalseg *g = arg;
1979a747e4fSDavid du Colombier
1989a747e4fSDavid du Colombier return g->cmd == Cnone;
1999a747e4fSDavid du Colombier }
2009a747e4fSDavid du Colombier
2019a747e4fSDavid du Colombier static Chan*
segmentopen(Chan * c,int omode)2029a747e4fSDavid du Colombier segmentopen(Chan *c, int omode)
2039a747e4fSDavid du Colombier {
2049a747e4fSDavid du Colombier Globalseg *g;
2059a747e4fSDavid du Colombier
2069a747e4fSDavid du Colombier switch(TYPE(c)){
2079a747e4fSDavid du Colombier case Qtopdir:
2089a747e4fSDavid du Colombier case Qsegdir:
2099a747e4fSDavid du Colombier if(omode != 0)
2109a747e4fSDavid du Colombier error(Eisdir);
2119a747e4fSDavid du Colombier break;
2129a747e4fSDavid du Colombier case Qctl:
2139a747e4fSDavid du Colombier g = getgseg(c);
2149a747e4fSDavid du Colombier if(waserror()){
2159a747e4fSDavid du Colombier putgseg(g);
2169a747e4fSDavid du Colombier nexterror();
2179a747e4fSDavid du Colombier }
2189a747e4fSDavid du Colombier devpermcheck(g->uid, g->perm, omode);
2199a747e4fSDavid du Colombier c->aux = g;
2209a747e4fSDavid du Colombier poperror();
2219a747e4fSDavid du Colombier c->flag |= COPEN;
2229a747e4fSDavid du Colombier break;
2239a747e4fSDavid du Colombier case Qdata:
2249a747e4fSDavid du Colombier g = getgseg(c);
2259a747e4fSDavid du Colombier if(waserror()){
2269a747e4fSDavid du Colombier putgseg(g);
2279a747e4fSDavid du Colombier nexterror();
2289a747e4fSDavid du Colombier }
2299a747e4fSDavid du Colombier devpermcheck(g->uid, g->perm, omode);
2309a747e4fSDavid du Colombier if(g->s == nil)
2319a747e4fSDavid du Colombier error("segment not yet allocated");
2329a747e4fSDavid du Colombier if(g->kproc == nil){
2339a747e4fSDavid du Colombier qlock(&g->l);
2349a747e4fSDavid du Colombier if(waserror()){
2359a747e4fSDavid du Colombier qunlock(&g->l);
2369a747e4fSDavid du Colombier nexterror();
2379a747e4fSDavid du Colombier }
2389a747e4fSDavid du Colombier if(g->kproc == nil){
2399a747e4fSDavid du Colombier g->cmd = Cnone;
2409a747e4fSDavid du Colombier kproc(g->name, segmentkproc, g);
2419a747e4fSDavid du Colombier docmd(g, Cstart);
2429a747e4fSDavid du Colombier }
2439a747e4fSDavid du Colombier qunlock(&g->l);
2449a747e4fSDavid du Colombier poperror();
2459a747e4fSDavid du Colombier }
2469a747e4fSDavid du Colombier c->aux = g;
2479a747e4fSDavid du Colombier poperror();
2489a747e4fSDavid du Colombier c->flag |= COPEN;
2499a747e4fSDavid du Colombier break;
2509a747e4fSDavid du Colombier default:
2519a747e4fSDavid du Colombier panic("segmentopen");
2529a747e4fSDavid du Colombier }
2539a747e4fSDavid du Colombier c->mode = openmode(omode);
2549a747e4fSDavid du Colombier c->offset = 0;
2559a747e4fSDavid du Colombier return c;
2569a747e4fSDavid du Colombier }
2579a747e4fSDavid du Colombier
2589a747e4fSDavid du Colombier static void
segmentclose(Chan * c)2599a747e4fSDavid du Colombier segmentclose(Chan *c)
2609a747e4fSDavid du Colombier {
2619a747e4fSDavid du Colombier if(TYPE(c) == Qtopdir)
2629a747e4fSDavid du Colombier return;
2639a747e4fSDavid du Colombier if(c->flag & COPEN)
2649a747e4fSDavid du Colombier putgseg(c->aux);
2659a747e4fSDavid du Colombier }
2669a747e4fSDavid du Colombier
2679a747e4fSDavid du Colombier static void
segmentcreate(Chan * c,char * name,int omode,ulong perm)2689a747e4fSDavid du Colombier segmentcreate(Chan *c, char *name, int omode, ulong perm)
2699a747e4fSDavid du Colombier {
2709a747e4fSDavid du Colombier int x, xfree;
2719a747e4fSDavid du Colombier Globalseg *g;
2729a747e4fSDavid du Colombier
2739a747e4fSDavid du Colombier if(TYPE(c) != Qtopdir)
2749a747e4fSDavid du Colombier error(Eperm);
2759a747e4fSDavid du Colombier
2769a747e4fSDavid du Colombier if(isphysseg(name))
2779a747e4fSDavid du Colombier error(Eexist);
2789a747e4fSDavid du Colombier
2799a747e4fSDavid du Colombier if((perm & DMDIR) == 0)
2809a747e4fSDavid du Colombier error(Ebadarg);
2819a747e4fSDavid du Colombier
2829a747e4fSDavid du Colombier if(waserror()){
2839a747e4fSDavid du Colombier unlock(&globalseglock);
2849a747e4fSDavid du Colombier nexterror();
2859a747e4fSDavid du Colombier }
2869a747e4fSDavid du Colombier lock(&globalseglock);
2879a747e4fSDavid du Colombier xfree = -1;
2889a747e4fSDavid du Colombier for(x = 0; x < nelem(globalseg); x++){
2899a747e4fSDavid du Colombier g = globalseg[x];
2909a747e4fSDavid du Colombier if(g == nil){
2919a747e4fSDavid du Colombier if(xfree < 0)
2929a747e4fSDavid du Colombier xfree = x;
2939a747e4fSDavid du Colombier } else {
2949a747e4fSDavid du Colombier if(strcmp(g->name, name) == 0)
2959a747e4fSDavid du Colombier error(Eexist);
2969a747e4fSDavid du Colombier }
2979a747e4fSDavid du Colombier }
2989a747e4fSDavid du Colombier if(xfree < 0)
2999a747e4fSDavid du Colombier error("too many global segments");
3009a747e4fSDavid du Colombier g = smalloc(sizeof(Globalseg));
3019a747e4fSDavid du Colombier g->ref = 1;
3029a747e4fSDavid du Colombier kstrdup(&g->name, name);
3039a747e4fSDavid du Colombier kstrdup(&g->uid, up->user);
3049a747e4fSDavid du Colombier g->perm = 0660;
3059a747e4fSDavid du Colombier globalseg[xfree] = g;
3069a747e4fSDavid du Colombier unlock(&globalseglock);
3079a747e4fSDavid du Colombier poperror();
3089a747e4fSDavid du Colombier
3099a747e4fSDavid du Colombier c->qid.path = PATH(x, Qsegdir);
3109a747e4fSDavid du Colombier c->qid.type = QTDIR;
3119a747e4fSDavid du Colombier c->qid.vers = 0;
3129a747e4fSDavid du Colombier c->mode = openmode(omode);
3139a747e4fSDavid du Colombier c->mode = OWRITE;
3149a747e4fSDavid du Colombier }
3159a747e4fSDavid du Colombier
3169a747e4fSDavid du Colombier static long
segmentread(Chan * c,void * a,long n,vlong voff)3179a747e4fSDavid du Colombier segmentread(Chan *c, void *a, long n, vlong voff)
3189a747e4fSDavid du Colombier {
3199a747e4fSDavid du Colombier Globalseg *g;
3209a747e4fSDavid du Colombier char buf[32];
3219a747e4fSDavid du Colombier
3229a747e4fSDavid du Colombier if(c->qid.type == QTDIR)
3239a747e4fSDavid du Colombier return devdirread(c, a, n, (Dirtab *)0, 0L, segmentgen);
3249a747e4fSDavid du Colombier
3259a747e4fSDavid du Colombier switch(TYPE(c)){
3269a747e4fSDavid du Colombier case Qctl:
3279a747e4fSDavid du Colombier g = c->aux;
3289a747e4fSDavid du Colombier if(g->s == nil)
3299a747e4fSDavid du Colombier error("segment not yet allocated");
330*4e3613abSDavid du Colombier snprint(buf, sizeof buf, "va %#lux %#lux\n", g->s->base,
331*4e3613abSDavid du Colombier g->s->top-g->s->base);
3329a747e4fSDavid du Colombier return readstr(voff, a, n, buf);
3339a747e4fSDavid du Colombier case Qdata:
3349a747e4fSDavid du Colombier g = c->aux;
3359a747e4fSDavid du Colombier if(voff > g->s->top - g->s->base)
3369a747e4fSDavid du Colombier error(Ebadarg);
3379a747e4fSDavid du Colombier if(voff + n > g->s->top - g->s->base)
3389a747e4fSDavid du Colombier n = g->s->top - g->s->base - voff;
3399a747e4fSDavid du Colombier qlock(&g->l);
3409a747e4fSDavid du Colombier g->off = voff + g->s->base;
3419a747e4fSDavid du Colombier g->data = smalloc(n);
3429a747e4fSDavid du Colombier if(waserror()){
3439a747e4fSDavid du Colombier free(g->data);
3449a747e4fSDavid du Colombier qunlock(&g->l);
3459a747e4fSDavid du Colombier nexterror();
3469a747e4fSDavid du Colombier }
3479a747e4fSDavid du Colombier g->dlen = n;
3489a747e4fSDavid du Colombier docmd(g, Cread);
3499a747e4fSDavid du Colombier memmove(a, g->data, g->dlen);
3509a747e4fSDavid du Colombier free(g->data);
3519a747e4fSDavid du Colombier qunlock(&g->l);
3529a747e4fSDavid du Colombier poperror();
3539a747e4fSDavid du Colombier return g->dlen;
3549a747e4fSDavid du Colombier default:
3559a747e4fSDavid du Colombier panic("segmentread");
3569a747e4fSDavid du Colombier }
3579a747e4fSDavid du Colombier return 0; /* not reached */
3589a747e4fSDavid du Colombier }
3599a747e4fSDavid du Colombier
3609a747e4fSDavid du Colombier static long
segmentwrite(Chan * c,void * a,long n,vlong voff)3619a747e4fSDavid du Colombier segmentwrite(Chan *c, void *a, long n, vlong voff)
3629a747e4fSDavid du Colombier {
3639a747e4fSDavid du Colombier Cmdbuf *cb;
3649a747e4fSDavid du Colombier Globalseg *g;
3659a747e4fSDavid du Colombier ulong va, len, top;
3669a747e4fSDavid du Colombier
3679a747e4fSDavid du Colombier if(c->qid.type == QTDIR)
3689a747e4fSDavid du Colombier error(Eperm);
3699a747e4fSDavid du Colombier
3709a747e4fSDavid du Colombier switch(TYPE(c)){
3719a747e4fSDavid du Colombier case Qctl:
3729a747e4fSDavid du Colombier g = c->aux;
3739a747e4fSDavid du Colombier cb = parsecmd(a, n);
3749a747e4fSDavid du Colombier if(strcmp(cb->f[0], "va") == 0){
3759a747e4fSDavid du Colombier if(g->s != nil)
3769a747e4fSDavid du Colombier error("already has a virtual address");
3779a747e4fSDavid du Colombier if(cb->nf < 3)
3789a747e4fSDavid du Colombier error(Ebadarg);
3799a747e4fSDavid du Colombier va = strtoul(cb->f[1], 0, 0);
3809a747e4fSDavid du Colombier len = strtoul(cb->f[2], 0, 0);
3819a747e4fSDavid du Colombier top = PGROUND(va + len);
3829a747e4fSDavid du Colombier va = va&~(BY2PG-1);
3839a747e4fSDavid du Colombier len = (top - va) / BY2PG;
3849a747e4fSDavid du Colombier if(len == 0)
3859a747e4fSDavid du Colombier error(Ebadarg);
3869a747e4fSDavid du Colombier g->s = newseg(SG_SHARED, va, len);
3879a747e4fSDavid du Colombier } else
3889a747e4fSDavid du Colombier error(Ebadctl);
3899a747e4fSDavid du Colombier break;
3909a747e4fSDavid du Colombier case Qdata:
3919a747e4fSDavid du Colombier g = c->aux;
3929a747e4fSDavid du Colombier if(voff + n > g->s->top - g->s->base)
3939a747e4fSDavid du Colombier error(Ebadarg);
3949a747e4fSDavid du Colombier qlock(&g->l);
3959a747e4fSDavid du Colombier g->off = voff + g->s->base;
3969a747e4fSDavid du Colombier g->data = smalloc(n);
3979a747e4fSDavid du Colombier if(waserror()){
3989a747e4fSDavid du Colombier free(g->data);
3999a747e4fSDavid du Colombier qunlock(&g->l);
4009a747e4fSDavid du Colombier nexterror();
4019a747e4fSDavid du Colombier }
4029a747e4fSDavid du Colombier g->dlen = n;
4039a747e4fSDavid du Colombier memmove(g->data, a, g->dlen);
4049a747e4fSDavid du Colombier docmd(g, Cwrite);
4059a747e4fSDavid du Colombier free(g->data);
4069a747e4fSDavid du Colombier qunlock(&g->l);
4079a747e4fSDavid du Colombier poperror();
4089a747e4fSDavid du Colombier return g->dlen;
4099a747e4fSDavid du Colombier default:
4109a747e4fSDavid du Colombier panic("segmentwrite");
4119a747e4fSDavid du Colombier }
4129a747e4fSDavid du Colombier return 0; /* not reached */
4139a747e4fSDavid du Colombier }
4149a747e4fSDavid du Colombier
4159a747e4fSDavid du Colombier static int
segmentwstat(Chan * c,uchar * dp,int n)4169a747e4fSDavid du Colombier segmentwstat(Chan *c, uchar *dp, int n)
4179a747e4fSDavid du Colombier {
4189a747e4fSDavid du Colombier Globalseg *g;
4199a747e4fSDavid du Colombier Dir *d;
4209a747e4fSDavid du Colombier
4219a747e4fSDavid du Colombier if(c->qid.type == QTDIR)
4229a747e4fSDavid du Colombier error(Eperm);
4239a747e4fSDavid du Colombier
4249a747e4fSDavid du Colombier g = getgseg(c);
4259a747e4fSDavid du Colombier if(waserror()){
4269a747e4fSDavid du Colombier putgseg(g);
4279a747e4fSDavid du Colombier nexterror();
4289a747e4fSDavid du Colombier }
4299a747e4fSDavid du Colombier
4309a747e4fSDavid du Colombier if(strcmp(g->uid, up->user) && !iseve())
4319a747e4fSDavid du Colombier error(Eperm);
4329a747e4fSDavid du Colombier d = smalloc(sizeof(Dir)+n);
4339a747e4fSDavid du Colombier n = convM2D(dp, n, &d[0], (char*)&d[1]);
4349a747e4fSDavid du Colombier g->perm = d->mode & 0777;
4359a747e4fSDavid du Colombier
4369a747e4fSDavid du Colombier putgseg(g);
4379a747e4fSDavid du Colombier poperror();
4389a747e4fSDavid du Colombier
4399a747e4fSDavid du Colombier free(d);
4409a747e4fSDavid du Colombier return n;
4419a747e4fSDavid du Colombier }
4429a747e4fSDavid du Colombier
4439a747e4fSDavid du Colombier static void
segmentremove(Chan * c)4449a747e4fSDavid du Colombier segmentremove(Chan *c)
4459a747e4fSDavid du Colombier {
4469a747e4fSDavid du Colombier Globalseg *g;
4479a747e4fSDavid du Colombier int x;
4489a747e4fSDavid du Colombier
4499a747e4fSDavid du Colombier if(TYPE(c) != Qsegdir)
4509a747e4fSDavid du Colombier error(Eperm);
4519a747e4fSDavid du Colombier lock(&globalseglock);
4529a747e4fSDavid du Colombier x = SEG(c);
4539a747e4fSDavid du Colombier g = globalseg[x];
4549a747e4fSDavid du Colombier globalseg[x] = nil;
4559a747e4fSDavid du Colombier unlock(&globalseglock);
4569a747e4fSDavid du Colombier if(g != nil)
4579a747e4fSDavid du Colombier putgseg(g);
4589a747e4fSDavid du Colombier }
4599a747e4fSDavid du Colombier
4609a747e4fSDavid du Colombier /*
4619a747e4fSDavid du Colombier * called by segattach()
4629a747e4fSDavid du Colombier */
4639a747e4fSDavid du Colombier static Segment*
globalsegattach(Proc * p,char * name)4649a747e4fSDavid du Colombier globalsegattach(Proc *p, char *name)
4659a747e4fSDavid du Colombier {
4669a747e4fSDavid du Colombier int x;
4679a747e4fSDavid du Colombier Globalseg *g;
4689a747e4fSDavid du Colombier Segment *s;
4699a747e4fSDavid du Colombier
4709a747e4fSDavid du Colombier g = nil;
4719a747e4fSDavid du Colombier if(waserror()){
4729a747e4fSDavid du Colombier unlock(&globalseglock);
4739a747e4fSDavid du Colombier nexterror();
4749a747e4fSDavid du Colombier }
4759a747e4fSDavid du Colombier lock(&globalseglock);
4769a747e4fSDavid du Colombier for(x = 0; x < nelem(globalseg); x++){
4779a747e4fSDavid du Colombier g = globalseg[x];
4789a747e4fSDavid du Colombier if(g != nil && strcmp(g->name, name) == 0)
4799a747e4fSDavid du Colombier break;
4809a747e4fSDavid du Colombier }
4819a747e4fSDavid du Colombier if(x == nelem(globalseg)){
4829a747e4fSDavid du Colombier unlock(&globalseglock);
4839a747e4fSDavid du Colombier poperror();
4849a747e4fSDavid du Colombier return nil;
4859a747e4fSDavid du Colombier }
4869a747e4fSDavid du Colombier devpermcheck(g->uid, g->perm, ORDWR);
4879a747e4fSDavid du Colombier s = g->s;
4889a747e4fSDavid du Colombier if(s == nil)
4899a747e4fSDavid du Colombier error("global segment not assigned a virtual address");
4904de34a7eSDavid du Colombier if(isoverlap(p, s->base, s->top - s->base) != nil)
4919a747e4fSDavid du Colombier error("overlaps existing segment");
4929a747e4fSDavid du Colombier incref(s);
4939a747e4fSDavid du Colombier unlock(&globalseglock);
4949a747e4fSDavid du Colombier poperror();
4959a747e4fSDavid du Colombier return s;
4969a747e4fSDavid du Colombier }
4979a747e4fSDavid du Colombier
4989a747e4fSDavid du Colombier static void
docmd(Globalseg * g,int cmd)4999a747e4fSDavid du Colombier docmd(Globalseg *g, int cmd)
5009a747e4fSDavid du Colombier {
5019a747e4fSDavid du Colombier g->err[0] = 0;
5029a747e4fSDavid du Colombier g->cmd = cmd;
5039a747e4fSDavid du Colombier wakeup(&g->cmdwait);
5049a747e4fSDavid du Colombier sleep(&g->replywait, cmddone, g);
5059a747e4fSDavid du Colombier if(g->err[0])
5069a747e4fSDavid du Colombier error(g->err);
5079a747e4fSDavid du Colombier }
5089a747e4fSDavid du Colombier
5099a747e4fSDavid du Colombier static int
cmdready(void * arg)5109a747e4fSDavid du Colombier cmdready(void *arg)
5119a747e4fSDavid du Colombier {
5129a747e4fSDavid du Colombier Globalseg *g = arg;
5139a747e4fSDavid du Colombier
5149a747e4fSDavid du Colombier return g->cmd != Cnone;
5159a747e4fSDavid du Colombier }
5169a747e4fSDavid du Colombier
5179a747e4fSDavid du Colombier static void
segmentkproc(void * arg)5189a747e4fSDavid du Colombier segmentkproc(void *arg)
5199a747e4fSDavid du Colombier {
5209a747e4fSDavid du Colombier Globalseg *g = arg;
5219a747e4fSDavid du Colombier int done;
5229a747e4fSDavid du Colombier int sno;
5239a747e4fSDavid du Colombier
5249a747e4fSDavid du Colombier for(sno = 0; sno < NSEG; sno++)
5259a747e4fSDavid du Colombier if(up->seg[sno] == nil && sno != ESEG)
5269a747e4fSDavid du Colombier break;
5279a747e4fSDavid du Colombier if(sno == NSEG)
5289a747e4fSDavid du Colombier panic("segmentkproc");
5299a747e4fSDavid du Colombier g->kproc = up;
5309a747e4fSDavid du Colombier
5319a747e4fSDavid du Colombier incref(g->s);
5329a747e4fSDavid du Colombier up->seg[sno] = g->s;
5339a747e4fSDavid du Colombier
5349a747e4fSDavid du Colombier for(done = 0; !done;){
5359a747e4fSDavid du Colombier sleep(&g->cmdwait, cmdready, g);
5369a747e4fSDavid du Colombier if(waserror()){
5379a747e4fSDavid du Colombier strncpy(g->err, up->errstr, sizeof(g->err));
5389a747e4fSDavid du Colombier } else {
5399a747e4fSDavid du Colombier switch(g->cmd){
5409a747e4fSDavid du Colombier case Cstart:
5419a747e4fSDavid du Colombier break;
5429a747e4fSDavid du Colombier case Cdie:
5439a747e4fSDavid du Colombier done = 1;
5449a747e4fSDavid du Colombier break;
5459a747e4fSDavid du Colombier case Cread:
5469a747e4fSDavid du Colombier memmove(g->data, (char*)g->off, g->dlen);
5479a747e4fSDavid du Colombier break;
5489a747e4fSDavid du Colombier case Cwrite:
5499a747e4fSDavid du Colombier memmove((char*)g->off, g->data, g->dlen);
5509a747e4fSDavid du Colombier break;
5519a747e4fSDavid du Colombier }
5529a747e4fSDavid du Colombier poperror();
5539a747e4fSDavid du Colombier }
5549a747e4fSDavid du Colombier g->cmd = Cnone;
5559a747e4fSDavid du Colombier wakeup(&g->replywait);
5569a747e4fSDavid du Colombier }
5579a747e4fSDavid du Colombier }
5589a747e4fSDavid du Colombier
5599a747e4fSDavid du Colombier Dev segmentdevtab = {
5609a747e4fSDavid du Colombier 'g',
5619a747e4fSDavid du Colombier "segment",
5629a747e4fSDavid du Colombier
5639a747e4fSDavid du Colombier devreset,
5649a747e4fSDavid du Colombier segmentinit,
5659a747e4fSDavid du Colombier devshutdown,
5669a747e4fSDavid du Colombier segmentattach,
5679a747e4fSDavid du Colombier segmentwalk,
5689a747e4fSDavid du Colombier segmentstat,
5699a747e4fSDavid du Colombier segmentopen,
5709a747e4fSDavid du Colombier segmentcreate,
5719a747e4fSDavid du Colombier segmentclose,
5729a747e4fSDavid du Colombier segmentread,
5739a747e4fSDavid du Colombier devbread,
5749a747e4fSDavid du Colombier segmentwrite,
5759a747e4fSDavid du Colombier devbwrite,
5769a747e4fSDavid du Colombier segmentremove,
5779a747e4fSDavid du Colombier segmentwstat,
5789a747e4fSDavid du Colombier };
5799a747e4fSDavid du Colombier
580