xref: /plan9-contrib/sys/src/9/port/devsegment.c (revision 4de34a7edde43207e841ec91ecd12e6cf5f5ebe7)
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*
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
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
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
1709a747e4fSDavid du Colombier segmentinit(void)
1719a747e4fSDavid du Colombier {
1729a747e4fSDavid du Colombier 	_globalsegattach = globalsegattach;
1739a747e4fSDavid du Colombier }
1749a747e4fSDavid du Colombier 
1759a747e4fSDavid du Colombier static Chan*
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*
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
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
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*
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
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
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
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");
3309a747e4fSDavid du Colombier 		sprint(buf, "va 0x%lux 0x%lux\n", g->s->base, g->s->top-g->s->base);
3319a747e4fSDavid du Colombier 		return readstr(voff, a, n, buf);
3329a747e4fSDavid du Colombier 	case Qdata:
3339a747e4fSDavid du Colombier 		g = c->aux;
3349a747e4fSDavid du Colombier 		if(voff > g->s->top - g->s->base)
3359a747e4fSDavid du Colombier 			error(Ebadarg);
3369a747e4fSDavid du Colombier 		if(voff + n > g->s->top - g->s->base)
3379a747e4fSDavid du Colombier 			n = g->s->top - g->s->base - voff;
3389a747e4fSDavid du Colombier 		qlock(&g->l);
3399a747e4fSDavid du Colombier 		g->off = voff + g->s->base;
3409a747e4fSDavid du Colombier 		g->data = smalloc(n);
3419a747e4fSDavid du Colombier 		if(waserror()){
3429a747e4fSDavid du Colombier 			free(g->data);
3439a747e4fSDavid du Colombier 			qunlock(&g->l);
3449a747e4fSDavid du Colombier 			nexterror();
3459a747e4fSDavid du Colombier 		}
3469a747e4fSDavid du Colombier 		g->dlen = n;
3479a747e4fSDavid du Colombier 		docmd(g, Cread);
3489a747e4fSDavid du Colombier 		memmove(a, g->data, g->dlen);
3499a747e4fSDavid du Colombier 		free(g->data);
3509a747e4fSDavid du Colombier 		qunlock(&g->l);
3519a747e4fSDavid du Colombier 		poperror();
3529a747e4fSDavid du Colombier 		return g->dlen;
3539a747e4fSDavid du Colombier 	default:
3549a747e4fSDavid du Colombier 		panic("segmentread");
3559a747e4fSDavid du Colombier 	}
3569a747e4fSDavid du Colombier 	return 0;	/* not reached */
3579a747e4fSDavid du Colombier }
3589a747e4fSDavid du Colombier 
3599a747e4fSDavid du Colombier static long
3609a747e4fSDavid du Colombier segmentwrite(Chan *c, void *a, long n, vlong voff)
3619a747e4fSDavid du Colombier {
3629a747e4fSDavid du Colombier 	Cmdbuf *cb;
3639a747e4fSDavid du Colombier 	Globalseg *g;
3649a747e4fSDavid du Colombier 	ulong va, len, top;
3659a747e4fSDavid du Colombier 
3669a747e4fSDavid du Colombier 	if(c->qid.type == QTDIR)
3679a747e4fSDavid du Colombier 		error(Eperm);
3689a747e4fSDavid du Colombier 
3699a747e4fSDavid du Colombier 	switch(TYPE(c)){
3709a747e4fSDavid du Colombier 	case Qctl:
3719a747e4fSDavid du Colombier 		g = c->aux;
3729a747e4fSDavid du Colombier 		cb = parsecmd(a, n);
3739a747e4fSDavid du Colombier 		if(strcmp(cb->f[0], "va") == 0){
3749a747e4fSDavid du Colombier 			if(g->s != nil)
3759a747e4fSDavid du Colombier 				error("already has a virtual address");
3769a747e4fSDavid du Colombier 			if(cb->nf < 3)
3779a747e4fSDavid du Colombier 				error(Ebadarg);
3789a747e4fSDavid du Colombier 			va = strtoul(cb->f[1], 0, 0);
3799a747e4fSDavid du Colombier 			len = strtoul(cb->f[2], 0, 0);
3809a747e4fSDavid du Colombier 			top = PGROUND(va + len);
3819a747e4fSDavid du Colombier 			va = va&~(BY2PG-1);
3829a747e4fSDavid du Colombier 			len = (top - va) / BY2PG;
3839a747e4fSDavid du Colombier 			if(len == 0)
3849a747e4fSDavid du Colombier 				error(Ebadarg);
3859a747e4fSDavid du Colombier 			g->s = newseg(SG_SHARED, va, len);
3869a747e4fSDavid du Colombier 		} else
3879a747e4fSDavid du Colombier 			error(Ebadctl);
3889a747e4fSDavid du Colombier 		break;
3899a747e4fSDavid du Colombier 	case Qdata:
3909a747e4fSDavid du Colombier 		g = c->aux;
3919a747e4fSDavid du Colombier 		if(voff + n > g->s->top - g->s->base)
3929a747e4fSDavid du Colombier 			error(Ebadarg);
3939a747e4fSDavid du Colombier 		qlock(&g->l);
3949a747e4fSDavid du Colombier 		g->off = voff + g->s->base;
3959a747e4fSDavid du Colombier 		g->data = smalloc(n);
3969a747e4fSDavid du Colombier 		if(waserror()){
3979a747e4fSDavid du Colombier 			free(g->data);
3989a747e4fSDavid du Colombier 			qunlock(&g->l);
3999a747e4fSDavid du Colombier 			nexterror();
4009a747e4fSDavid du Colombier 		}
4019a747e4fSDavid du Colombier 		g->dlen = n;
4029a747e4fSDavid du Colombier 		memmove(g->data, a, g->dlen);
4039a747e4fSDavid du Colombier 		docmd(g, Cwrite);
4049a747e4fSDavid du Colombier 		free(g->data);
4059a747e4fSDavid du Colombier 		qunlock(&g->l);
4069a747e4fSDavid du Colombier 		poperror();
4079a747e4fSDavid du Colombier 		return g->dlen;
4089a747e4fSDavid du Colombier 	default:
4099a747e4fSDavid du Colombier 		panic("segmentwrite");
4109a747e4fSDavid du Colombier 	}
4119a747e4fSDavid du Colombier 	return 0;	/* not reached */
4129a747e4fSDavid du Colombier }
4139a747e4fSDavid du Colombier 
4149a747e4fSDavid du Colombier static int
4159a747e4fSDavid du Colombier segmentwstat(Chan *c, uchar *dp, int n)
4169a747e4fSDavid du Colombier {
4179a747e4fSDavid du Colombier 	Globalseg *g;
4189a747e4fSDavid du Colombier 	Dir *d;
4199a747e4fSDavid du Colombier 
4209a747e4fSDavid du Colombier 	if(c->qid.type == QTDIR)
4219a747e4fSDavid du Colombier 		error(Eperm);
4229a747e4fSDavid du Colombier 
4239a747e4fSDavid du Colombier 	g = getgseg(c);
4249a747e4fSDavid du Colombier 	if(waserror()){
4259a747e4fSDavid du Colombier 		putgseg(g);
4269a747e4fSDavid du Colombier 		nexterror();
4279a747e4fSDavid du Colombier 	}
4289a747e4fSDavid du Colombier 
4299a747e4fSDavid du Colombier 	if(strcmp(g->uid, up->user) && !iseve())
4309a747e4fSDavid du Colombier 		error(Eperm);
4319a747e4fSDavid du Colombier 	d = smalloc(sizeof(Dir)+n);
4329a747e4fSDavid du Colombier 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
4339a747e4fSDavid du Colombier 	g->perm = d->mode & 0777;
4349a747e4fSDavid du Colombier 
4359a747e4fSDavid du Colombier 	putgseg(g);
4369a747e4fSDavid du Colombier 	poperror();
4379a747e4fSDavid du Colombier 
4389a747e4fSDavid du Colombier 	free(d);
4399a747e4fSDavid du Colombier 	return n;
4409a747e4fSDavid du Colombier }
4419a747e4fSDavid du Colombier 
4429a747e4fSDavid du Colombier static void
4439a747e4fSDavid du Colombier segmentremove(Chan *c)
4449a747e4fSDavid du Colombier {
4459a747e4fSDavid du Colombier 	Globalseg *g;
4469a747e4fSDavid du Colombier 	int x;
4479a747e4fSDavid du Colombier 
4489a747e4fSDavid du Colombier 	if(TYPE(c) != Qsegdir)
4499a747e4fSDavid du Colombier 		error(Eperm);
4509a747e4fSDavid du Colombier 	lock(&globalseglock);
4519a747e4fSDavid du Colombier 	x = SEG(c);
4529a747e4fSDavid du Colombier 	g = globalseg[x];
4539a747e4fSDavid du Colombier 	globalseg[x] = nil;
4549a747e4fSDavid du Colombier 	unlock(&globalseglock);
4559a747e4fSDavid du Colombier 	if(g != nil)
4569a747e4fSDavid du Colombier 		putgseg(g);
4579a747e4fSDavid du Colombier }
4589a747e4fSDavid du Colombier 
4599a747e4fSDavid du Colombier /*
4609a747e4fSDavid du Colombier  *  called by segattach()
4619a747e4fSDavid du Colombier  */
4629a747e4fSDavid du Colombier static Segment*
4639a747e4fSDavid du Colombier globalsegattach(Proc *p, char *name)
4649a747e4fSDavid du Colombier {
4659a747e4fSDavid du Colombier 	int x;
4669a747e4fSDavid du Colombier 	Globalseg *g;
4679a747e4fSDavid du Colombier 	Segment *s;
4689a747e4fSDavid du Colombier 
4699a747e4fSDavid du Colombier 	g = nil;
4709a747e4fSDavid du Colombier 	if(waserror()){
4719a747e4fSDavid du Colombier 		unlock(&globalseglock);
4729a747e4fSDavid du Colombier 		nexterror();
4739a747e4fSDavid du Colombier 	}
4749a747e4fSDavid du Colombier 	lock(&globalseglock);
4759a747e4fSDavid du Colombier 	for(x = 0; x < nelem(globalseg); x++){
4769a747e4fSDavid du Colombier 		g = globalseg[x];
4779a747e4fSDavid du Colombier 		if(g != nil && strcmp(g->name, name) == 0)
4789a747e4fSDavid du Colombier 			break;
4799a747e4fSDavid du Colombier 	}
4809a747e4fSDavid du Colombier 	if(x == nelem(globalseg)){
4819a747e4fSDavid du Colombier 		unlock(&globalseglock);
4829a747e4fSDavid du Colombier 		poperror();
4839a747e4fSDavid du Colombier 		return nil;
4849a747e4fSDavid du Colombier 	}
4859a747e4fSDavid du Colombier 	devpermcheck(g->uid, g->perm, ORDWR);
4869a747e4fSDavid du Colombier 	s = g->s;
4879a747e4fSDavid du Colombier 	if(s == nil)
4889a747e4fSDavid du Colombier 		error("global segment not assigned a virtual address");
489*4de34a7eSDavid du Colombier 	if(isoverlap(p, s->base, s->top - s->base) != nil)
4909a747e4fSDavid du Colombier 		error("overlaps existing segment");
4919a747e4fSDavid du Colombier 	incref(s);
4929a747e4fSDavid du Colombier 	unlock(&globalseglock);
4939a747e4fSDavid du Colombier 	poperror();
4949a747e4fSDavid du Colombier 	return s;
4959a747e4fSDavid du Colombier }
4969a747e4fSDavid du Colombier 
4979a747e4fSDavid du Colombier static void
4989a747e4fSDavid du Colombier docmd(Globalseg *g, int cmd)
4999a747e4fSDavid du Colombier {
5009a747e4fSDavid du Colombier 	g->err[0] = 0;
5019a747e4fSDavid du Colombier 	g->cmd = cmd;
5029a747e4fSDavid du Colombier 	wakeup(&g->cmdwait);
5039a747e4fSDavid du Colombier 	sleep(&g->replywait, cmddone, g);
5049a747e4fSDavid du Colombier 	if(g->err[0])
5059a747e4fSDavid du Colombier 		error(g->err);
5069a747e4fSDavid du Colombier }
5079a747e4fSDavid du Colombier 
5089a747e4fSDavid du Colombier static int
5099a747e4fSDavid du Colombier cmdready(void *arg)
5109a747e4fSDavid du Colombier {
5119a747e4fSDavid du Colombier 	Globalseg *g = arg;
5129a747e4fSDavid du Colombier 
5139a747e4fSDavid du Colombier 	return g->cmd != Cnone;
5149a747e4fSDavid du Colombier }
5159a747e4fSDavid du Colombier 
5169a747e4fSDavid du Colombier static void
5179a747e4fSDavid du Colombier segmentkproc(void *arg)
5189a747e4fSDavid du Colombier {
5199a747e4fSDavid du Colombier 	Globalseg *g = arg;
5209a747e4fSDavid du Colombier 	int done;
5219a747e4fSDavid du Colombier 	int sno;
5229a747e4fSDavid du Colombier 
5239a747e4fSDavid du Colombier 	for(sno = 0; sno < NSEG; sno++)
5249a747e4fSDavid du Colombier 		if(up->seg[sno] == nil && sno != ESEG)
5259a747e4fSDavid du Colombier 			break;
5269a747e4fSDavid du Colombier 	if(sno == NSEG)
5279a747e4fSDavid du Colombier 		panic("segmentkproc");
5289a747e4fSDavid du Colombier 	g->kproc = up;
5299a747e4fSDavid du Colombier 
5309a747e4fSDavid du Colombier 	incref(g->s);
5319a747e4fSDavid du Colombier 	up->seg[sno] = g->s;
5329a747e4fSDavid du Colombier 
5339a747e4fSDavid du Colombier 	for(done = 0; !done;){
5349a747e4fSDavid du Colombier 		sleep(&g->cmdwait, cmdready, g);
5359a747e4fSDavid du Colombier 		if(waserror()){
5369a747e4fSDavid du Colombier 			strncpy(g->err, up->errstr, sizeof(g->err));
5379a747e4fSDavid du Colombier 		} else {
5389a747e4fSDavid du Colombier 			switch(g->cmd){
5399a747e4fSDavid du Colombier 			case Cstart:
5409a747e4fSDavid du Colombier 				break;
5419a747e4fSDavid du Colombier 			case Cdie:
5429a747e4fSDavid du Colombier 				done = 1;
5439a747e4fSDavid du Colombier 				break;
5449a747e4fSDavid du Colombier 			case Cread:
5459a747e4fSDavid du Colombier 				memmove(g->data, (char*)g->off, g->dlen);
5469a747e4fSDavid du Colombier 				break;
5479a747e4fSDavid du Colombier 			case Cwrite:
5489a747e4fSDavid du Colombier 				memmove((char*)g->off, g->data, g->dlen);
5499a747e4fSDavid du Colombier 				break;
5509a747e4fSDavid du Colombier 			}
5519a747e4fSDavid du Colombier 			poperror();
5529a747e4fSDavid du Colombier 		}
5539a747e4fSDavid du Colombier 		g->cmd = Cnone;
5549a747e4fSDavid du Colombier 		wakeup(&g->replywait);
5559a747e4fSDavid du Colombier 	}
5569a747e4fSDavid du Colombier }
5579a747e4fSDavid du Colombier 
5589a747e4fSDavid du Colombier Dev segmentdevtab = {
5599a747e4fSDavid du Colombier 	'g',
5609a747e4fSDavid du Colombier 	"segment",
5619a747e4fSDavid du Colombier 
5629a747e4fSDavid du Colombier 	devreset,
5639a747e4fSDavid du Colombier 	segmentinit,
5649a747e4fSDavid du Colombier 	devshutdown,
5659a747e4fSDavid du Colombier 	segmentattach,
5669a747e4fSDavid du Colombier 	segmentwalk,
5679a747e4fSDavid du Colombier 	segmentstat,
5689a747e4fSDavid du Colombier 	segmentopen,
5699a747e4fSDavid du Colombier 	segmentcreate,
5709a747e4fSDavid du Colombier 	segmentclose,
5719a747e4fSDavid du Colombier 	segmentread,
5729a747e4fSDavid du Colombier 	devbread,
5739a747e4fSDavid du Colombier 	segmentwrite,
5749a747e4fSDavid du Colombier 	devbwrite,
5759a747e4fSDavid du Colombier 	segmentremove,
5769a747e4fSDavid du Colombier 	segmentwstat,
5779a747e4fSDavid du Colombier };
5789a747e4fSDavid du Colombier 
579