xref: /plan9/sys/src/9/port/devsegment.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
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