xref: /plan9-contrib/sys/src/9/port/devsegment.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include	"u.h"
2*9a747e4fSDavid du Colombier #include	"../port/lib.h"
3*9a747e4fSDavid du Colombier #include	"mem.h"
4*9a747e4fSDavid du Colombier #include	"dat.h"
5*9a747e4fSDavid du Colombier #include	"fns.h"
6*9a747e4fSDavid du Colombier #include	"../port/error.h"
7*9a747e4fSDavid du Colombier 
8*9a747e4fSDavid du Colombier enum
9*9a747e4fSDavid du Colombier {
10*9a747e4fSDavid du Colombier 	Qtopdir,
11*9a747e4fSDavid du Colombier 	Qsegdir,
12*9a747e4fSDavid du Colombier 	Qctl,
13*9a747e4fSDavid du Colombier 	Qdata,
14*9a747e4fSDavid du Colombier 
15*9a747e4fSDavid du Colombier 	/* commands to kproc */
16*9a747e4fSDavid du Colombier 	Cnone=0,
17*9a747e4fSDavid du Colombier 	Cread,
18*9a747e4fSDavid du Colombier 	Cwrite,
19*9a747e4fSDavid du Colombier 	Cstart,
20*9a747e4fSDavid du Colombier 	Cdie,
21*9a747e4fSDavid du Colombier };
22*9a747e4fSDavid du Colombier 
23*9a747e4fSDavid du Colombier #define TYPE(x) 	(int)( (c)->qid.path & 0x7 )
24*9a747e4fSDavid du Colombier #define SEG(x)	 	( ((c)->qid.path >> 3) & 0x3f )
25*9a747e4fSDavid du Colombier #define PATH(s, t) 	( ((s)<<3) | (t) )
26*9a747e4fSDavid du Colombier 
27*9a747e4fSDavid du Colombier typedef struct Globalseg Globalseg;
28*9a747e4fSDavid du Colombier struct Globalseg
29*9a747e4fSDavid du Colombier {
30*9a747e4fSDavid du Colombier 	Ref;
31*9a747e4fSDavid du Colombier 	Segment	*s;
32*9a747e4fSDavid du Colombier 
33*9a747e4fSDavid du Colombier 	char	*name;
34*9a747e4fSDavid du Colombier 	char	*uid;
35*9a747e4fSDavid du Colombier 	vlong	length;
36*9a747e4fSDavid du Colombier 	long	perm;
37*9a747e4fSDavid du Colombier 
38*9a747e4fSDavid du Colombier 	/* kproc to do reading and writing */
39*9a747e4fSDavid du Colombier 	QLock	l;		/* sync kproc access */
40*9a747e4fSDavid du Colombier 	Rendez	cmdwait;	/* where kproc waits */
41*9a747e4fSDavid du Colombier 	Rendez	replywait;	/* where requestor waits */
42*9a747e4fSDavid du Colombier 	Proc	*kproc;
43*9a747e4fSDavid du Colombier 	char	*data;
44*9a747e4fSDavid du Colombier 	long	off;
45*9a747e4fSDavid du Colombier 	int	dlen;
46*9a747e4fSDavid du Colombier 	int	cmd;
47*9a747e4fSDavid du Colombier 	char	err[64];
48*9a747e4fSDavid du Colombier };
49*9a747e4fSDavid du Colombier 
50*9a747e4fSDavid du Colombier static Globalseg *globalseg[100];
51*9a747e4fSDavid du Colombier static Lock globalseglock;
52*9a747e4fSDavid du Colombier 
53*9a747e4fSDavid du Colombier 
54*9a747e4fSDavid du Colombier 	Segment* (*_globalsegattach)(Proc*, char*);
55*9a747e4fSDavid du Colombier static	Segment* globalsegattach(Proc *p, char *name);
56*9a747e4fSDavid du Colombier static	int	cmddone(void*);
57*9a747e4fSDavid du Colombier static	void	segmentkproc(void*);
58*9a747e4fSDavid du Colombier static	void	docmd(Globalseg *g, int cmd);
59*9a747e4fSDavid du Colombier 
60*9a747e4fSDavid du Colombier /*
61*9a747e4fSDavid du Colombier  *  returns with globalseg incref'd
62*9a747e4fSDavid du Colombier  */
63*9a747e4fSDavid du Colombier static Globalseg*
64*9a747e4fSDavid du Colombier getgseg(Chan *c)
65*9a747e4fSDavid du Colombier {
66*9a747e4fSDavid du Colombier 	int x;
67*9a747e4fSDavid du Colombier 	Globalseg *g;
68*9a747e4fSDavid du Colombier 
69*9a747e4fSDavid du Colombier 	x = SEG(c);
70*9a747e4fSDavid du Colombier 	lock(&globalseglock);
71*9a747e4fSDavid du Colombier 	if(x >= nelem(globalseg))
72*9a747e4fSDavid du Colombier 		panic("getgseg");
73*9a747e4fSDavid du Colombier 	g = globalseg[x];
74*9a747e4fSDavid du Colombier 	if(g != nil)
75*9a747e4fSDavid du Colombier 		incref(g);
76*9a747e4fSDavid du Colombier 	unlock(&globalseglock);
77*9a747e4fSDavid du Colombier 	if(g == nil)
78*9a747e4fSDavid du Colombier 		error("global segment disappeared");
79*9a747e4fSDavid du Colombier 	return g;
80*9a747e4fSDavid du Colombier }
81*9a747e4fSDavid du Colombier 
82*9a747e4fSDavid du Colombier static void
83*9a747e4fSDavid du Colombier putgseg(Globalseg *g)
84*9a747e4fSDavid du Colombier {
85*9a747e4fSDavid du Colombier 	if(decref(g) > 0)
86*9a747e4fSDavid du Colombier 		return;
87*9a747e4fSDavid du Colombier 	if(g->s != nil)
88*9a747e4fSDavid du Colombier 		putseg(g->s);
89*9a747e4fSDavid du Colombier 	if(g->kproc)
90*9a747e4fSDavid du Colombier 		docmd(g, Cdie);
91*9a747e4fSDavid du Colombier 	free(g->name);
92*9a747e4fSDavid du Colombier 	free(g->uid);
93*9a747e4fSDavid du Colombier 	free(g);
94*9a747e4fSDavid du Colombier }
95*9a747e4fSDavid du Colombier 
96*9a747e4fSDavid du Colombier static int
97*9a747e4fSDavid du Colombier segmentgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
98*9a747e4fSDavid du Colombier {
99*9a747e4fSDavid du Colombier 	Qid q;
100*9a747e4fSDavid du Colombier 	Globalseg *g;
101*9a747e4fSDavid du Colombier 	ulong size;
102*9a747e4fSDavid du Colombier 
103*9a747e4fSDavid du Colombier 	switch(TYPE(c)) {
104*9a747e4fSDavid du Colombier 	case Qtopdir:
105*9a747e4fSDavid du Colombier 		if(s == DEVDOTDOT){
106*9a747e4fSDavid du Colombier 			q.vers = 0;
107*9a747e4fSDavid du Colombier 			q.path = PATH(0, Qtopdir);
108*9a747e4fSDavid du Colombier 			q.type = QTDIR;
109*9a747e4fSDavid du Colombier 			devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
110*9a747e4fSDavid du Colombier 			break;
111*9a747e4fSDavid du Colombier 		}
112*9a747e4fSDavid du Colombier 
113*9a747e4fSDavid du Colombier 		if(s >= nelem(globalseg))
114*9a747e4fSDavid du Colombier 			return -1;
115*9a747e4fSDavid du Colombier 
116*9a747e4fSDavid du Colombier 		lock(&globalseglock);
117*9a747e4fSDavid du Colombier 		g = globalseg[s];
118*9a747e4fSDavid du Colombier 		if(g == nil){
119*9a747e4fSDavid du Colombier 			unlock(&globalseglock);
120*9a747e4fSDavid du Colombier 			return 0;
121*9a747e4fSDavid du Colombier 		}
122*9a747e4fSDavid du Colombier 		q.vers = 0;
123*9a747e4fSDavid du Colombier 		q.path = PATH(s, Qsegdir);
124*9a747e4fSDavid du Colombier 		q.type = QTDIR;
125*9a747e4fSDavid du Colombier 		devdir(c, q, g->name, 0, g->uid, DMDIR|0777, dp);
126*9a747e4fSDavid du Colombier 		unlock(&globalseglock);
127*9a747e4fSDavid du Colombier 
128*9a747e4fSDavid du Colombier 		break;
129*9a747e4fSDavid du Colombier 	case Qsegdir:
130*9a747e4fSDavid du Colombier 		if(s == DEVDOTDOT){
131*9a747e4fSDavid du Colombier 			q.vers = 0;
132*9a747e4fSDavid du Colombier 			q.path = PATH(0, Qtopdir);
133*9a747e4fSDavid du Colombier 			q.type = QTDIR;
134*9a747e4fSDavid du Colombier 			devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
135*9a747e4fSDavid du Colombier 			break;
136*9a747e4fSDavid du Colombier 		}
137*9a747e4fSDavid du Colombier 		/* fall through */
138*9a747e4fSDavid du Colombier 	case Qctl:
139*9a747e4fSDavid du Colombier 	case Qdata:
140*9a747e4fSDavid du Colombier 		switch(s){
141*9a747e4fSDavid du Colombier 		case 0:
142*9a747e4fSDavid du Colombier 			g = getgseg(c);
143*9a747e4fSDavid du Colombier 			q.vers = 0;
144*9a747e4fSDavid du Colombier 			q.path = PATH(SEG(c), Qctl);
145*9a747e4fSDavid du Colombier 			q.type = QTFILE;
146*9a747e4fSDavid du Colombier 			devdir(c, q, "ctl", 0, g->uid, g->perm, dp);
147*9a747e4fSDavid du Colombier 			putgseg(g);
148*9a747e4fSDavid du Colombier 			break;
149*9a747e4fSDavid du Colombier 		case 1:
150*9a747e4fSDavid du Colombier 			g = getgseg(c);
151*9a747e4fSDavid du Colombier 			q.vers = 0;
152*9a747e4fSDavid du Colombier 			q.path = PATH(SEG(c), Qdata);
153*9a747e4fSDavid du Colombier 			q.type = QTFILE;
154*9a747e4fSDavid du Colombier 			if(g->s != nil)
155*9a747e4fSDavid du Colombier 				size = g->s->top - g->s->base;
156*9a747e4fSDavid du Colombier 			else
157*9a747e4fSDavid du Colombier 				size = 0;
158*9a747e4fSDavid du Colombier 			devdir(c, q, "data", size, g->uid, g->perm, dp);
159*9a747e4fSDavid du Colombier 			putgseg(g);
160*9a747e4fSDavid du Colombier 			break;
161*9a747e4fSDavid du Colombier 		default:
162*9a747e4fSDavid du Colombier 			return -1;
163*9a747e4fSDavid du Colombier 		}
164*9a747e4fSDavid du Colombier 		break;
165*9a747e4fSDavid du Colombier 	}
166*9a747e4fSDavid du Colombier 	return 1;
167*9a747e4fSDavid du Colombier }
168*9a747e4fSDavid du Colombier 
169*9a747e4fSDavid du Colombier static void
170*9a747e4fSDavid du Colombier segmentinit(void)
171*9a747e4fSDavid du Colombier {
172*9a747e4fSDavid du Colombier 	_globalsegattach = globalsegattach;
173*9a747e4fSDavid du Colombier }
174*9a747e4fSDavid du Colombier 
175*9a747e4fSDavid du Colombier static Chan*
176*9a747e4fSDavid du Colombier segmentattach(char *spec)
177*9a747e4fSDavid du Colombier {
178*9a747e4fSDavid du Colombier 	return devattach('g', spec);
179*9a747e4fSDavid du Colombier }
180*9a747e4fSDavid du Colombier 
181*9a747e4fSDavid du Colombier static Walkqid*
182*9a747e4fSDavid du Colombier segmentwalk(Chan *c, Chan *nc, char **name, int nname)
183*9a747e4fSDavid du Colombier {
184*9a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, segmentgen);
185*9a747e4fSDavid du Colombier }
186*9a747e4fSDavid du Colombier 
187*9a747e4fSDavid du Colombier static int
188*9a747e4fSDavid du Colombier segmentstat(Chan *c, uchar *db, int n)
189*9a747e4fSDavid du Colombier {
190*9a747e4fSDavid du Colombier 	return devstat(c, db, n, 0, 0, segmentgen);
191*9a747e4fSDavid du Colombier }
192*9a747e4fSDavid du Colombier 
193*9a747e4fSDavid du Colombier static int
194*9a747e4fSDavid du Colombier cmddone(void *arg)
195*9a747e4fSDavid du Colombier {
196*9a747e4fSDavid du Colombier 	Globalseg *g = arg;
197*9a747e4fSDavid du Colombier 
198*9a747e4fSDavid du Colombier 	return g->cmd == Cnone;
199*9a747e4fSDavid du Colombier }
200*9a747e4fSDavid du Colombier 
201*9a747e4fSDavid du Colombier static Chan*
202*9a747e4fSDavid du Colombier segmentopen(Chan *c, int omode)
203*9a747e4fSDavid du Colombier {
204*9a747e4fSDavid du Colombier 	Globalseg *g;
205*9a747e4fSDavid du Colombier 
206*9a747e4fSDavid du Colombier 	switch(TYPE(c)){
207*9a747e4fSDavid du Colombier 	case Qtopdir:
208*9a747e4fSDavid du Colombier 	case Qsegdir:
209*9a747e4fSDavid du Colombier 		if(omode != 0)
210*9a747e4fSDavid du Colombier 			error(Eisdir);
211*9a747e4fSDavid du Colombier 		break;
212*9a747e4fSDavid du Colombier 	case Qctl:
213*9a747e4fSDavid du Colombier 		g = getgseg(c);
214*9a747e4fSDavid du Colombier 		if(waserror()){
215*9a747e4fSDavid du Colombier 			putgseg(g);
216*9a747e4fSDavid du Colombier 			nexterror();
217*9a747e4fSDavid du Colombier 		}
218*9a747e4fSDavid du Colombier 		devpermcheck(g->uid, g->perm, omode);
219*9a747e4fSDavid du Colombier 		c->aux = g;
220*9a747e4fSDavid du Colombier 		poperror();
221*9a747e4fSDavid du Colombier 		c->flag |= COPEN;
222*9a747e4fSDavid du Colombier 		break;
223*9a747e4fSDavid du Colombier 	case Qdata:
224*9a747e4fSDavid du Colombier 		g = getgseg(c);
225*9a747e4fSDavid du Colombier 		if(waserror()){
226*9a747e4fSDavid du Colombier 			putgseg(g);
227*9a747e4fSDavid du Colombier 			nexterror();
228*9a747e4fSDavid du Colombier 		}
229*9a747e4fSDavid du Colombier 		devpermcheck(g->uid, g->perm, omode);
230*9a747e4fSDavid du Colombier 		if(g->s == nil)
231*9a747e4fSDavid du Colombier 			error("segment not yet allocated");
232*9a747e4fSDavid du Colombier 		if(g->kproc == nil){
233*9a747e4fSDavid du Colombier 			qlock(&g->l);
234*9a747e4fSDavid du Colombier 			if(waserror()){
235*9a747e4fSDavid du Colombier 				qunlock(&g->l);
236*9a747e4fSDavid du Colombier 				nexterror();
237*9a747e4fSDavid du Colombier 			}
238*9a747e4fSDavid du Colombier 			if(g->kproc == nil){
239*9a747e4fSDavid du Colombier 				g->cmd = Cnone;
240*9a747e4fSDavid du Colombier 				kproc(g->name, segmentkproc, g);
241*9a747e4fSDavid du Colombier 				docmd(g, Cstart);
242*9a747e4fSDavid du Colombier 			}
243*9a747e4fSDavid du Colombier 			qunlock(&g->l);
244*9a747e4fSDavid du Colombier 			poperror();
245*9a747e4fSDavid du Colombier 		}
246*9a747e4fSDavid du Colombier 		c->aux = g;
247*9a747e4fSDavid du Colombier 		poperror();
248*9a747e4fSDavid du Colombier 		c->flag |= COPEN;
249*9a747e4fSDavid du Colombier 		break;
250*9a747e4fSDavid du Colombier 	default:
251*9a747e4fSDavid du Colombier 		panic("segmentopen");
252*9a747e4fSDavid du Colombier 	}
253*9a747e4fSDavid du Colombier 	c->mode = openmode(omode);
254*9a747e4fSDavid du Colombier 	c->offset = 0;
255*9a747e4fSDavid du Colombier 	return c;
256*9a747e4fSDavid du Colombier }
257*9a747e4fSDavid du Colombier 
258*9a747e4fSDavid du Colombier static void
259*9a747e4fSDavid du Colombier segmentclose(Chan *c)
260*9a747e4fSDavid du Colombier {
261*9a747e4fSDavid du Colombier 	if(TYPE(c) == Qtopdir)
262*9a747e4fSDavid du Colombier 		return;
263*9a747e4fSDavid du Colombier 	if(c->flag & COPEN)
264*9a747e4fSDavid du Colombier 		putgseg(c->aux);
265*9a747e4fSDavid du Colombier }
266*9a747e4fSDavid du Colombier 
267*9a747e4fSDavid du Colombier static void
268*9a747e4fSDavid du Colombier segmentcreate(Chan *c, char *name, int omode, ulong perm)
269*9a747e4fSDavid du Colombier {
270*9a747e4fSDavid du Colombier 	int x, xfree;
271*9a747e4fSDavid du Colombier 	Globalseg *g;
272*9a747e4fSDavid du Colombier 
273*9a747e4fSDavid du Colombier 	if(TYPE(c) != Qtopdir)
274*9a747e4fSDavid du Colombier 		error(Eperm);
275*9a747e4fSDavid du Colombier 
276*9a747e4fSDavid du Colombier 	if(isphysseg(name))
277*9a747e4fSDavid du Colombier 		error(Eexist);
278*9a747e4fSDavid du Colombier 
279*9a747e4fSDavid du Colombier 	if((perm & DMDIR) == 0)
280*9a747e4fSDavid du Colombier 		error(Ebadarg);
281*9a747e4fSDavid du Colombier 
282*9a747e4fSDavid du Colombier 	if(waserror()){
283*9a747e4fSDavid du Colombier 		unlock(&globalseglock);
284*9a747e4fSDavid du Colombier 		nexterror();
285*9a747e4fSDavid du Colombier 	}
286*9a747e4fSDavid du Colombier 	lock(&globalseglock);
287*9a747e4fSDavid du Colombier 	xfree = -1;
288*9a747e4fSDavid du Colombier 	for(x = 0; x < nelem(globalseg); x++){
289*9a747e4fSDavid du Colombier 		g = globalseg[x];
290*9a747e4fSDavid du Colombier 		if(g == nil){
291*9a747e4fSDavid du Colombier 			if(xfree < 0)
292*9a747e4fSDavid du Colombier 				xfree = x;
293*9a747e4fSDavid du Colombier 		} else {
294*9a747e4fSDavid du Colombier 			if(strcmp(g->name, name) == 0)
295*9a747e4fSDavid du Colombier 				error(Eexist);
296*9a747e4fSDavid du Colombier 		}
297*9a747e4fSDavid du Colombier 	}
298*9a747e4fSDavid du Colombier 	if(xfree < 0)
299*9a747e4fSDavid du Colombier 		error("too many global segments");
300*9a747e4fSDavid du Colombier 	g = smalloc(sizeof(Globalseg));
301*9a747e4fSDavid du Colombier 	g->ref = 1;
302*9a747e4fSDavid du Colombier 	kstrdup(&g->name, name);
303*9a747e4fSDavid du Colombier 	kstrdup(&g->uid, up->user);
304*9a747e4fSDavid du Colombier 	g->perm = 0660;
305*9a747e4fSDavid du Colombier 	globalseg[xfree] = g;
306*9a747e4fSDavid du Colombier 	unlock(&globalseglock);
307*9a747e4fSDavid du Colombier 	poperror();
308*9a747e4fSDavid du Colombier 
309*9a747e4fSDavid du Colombier 	c->qid.path = PATH(x, Qsegdir);
310*9a747e4fSDavid du Colombier 	c->qid.type = QTDIR;
311*9a747e4fSDavid du Colombier 	c->qid.vers = 0;
312*9a747e4fSDavid du Colombier 	c->mode = openmode(omode);
313*9a747e4fSDavid du Colombier 	c->mode = OWRITE;
314*9a747e4fSDavid du Colombier }
315*9a747e4fSDavid du Colombier 
316*9a747e4fSDavid du Colombier static long
317*9a747e4fSDavid du Colombier segmentread(Chan *c, void *a, long n, vlong voff)
318*9a747e4fSDavid du Colombier {
319*9a747e4fSDavid du Colombier 	Globalseg *g;
320*9a747e4fSDavid du Colombier 	char buf[32];
321*9a747e4fSDavid du Colombier 
322*9a747e4fSDavid du Colombier 	if(c->qid.type == QTDIR)
323*9a747e4fSDavid du Colombier 		return devdirread(c, a, n, (Dirtab *)0, 0L, segmentgen);
324*9a747e4fSDavid du Colombier 
325*9a747e4fSDavid du Colombier 	switch(TYPE(c)){
326*9a747e4fSDavid du Colombier 	case Qctl:
327*9a747e4fSDavid du Colombier 		g = c->aux;
328*9a747e4fSDavid du Colombier 		if(g->s == nil)
329*9a747e4fSDavid du Colombier 			error("segment not yet allocated");
330*9a747e4fSDavid du Colombier 		sprint(buf, "va 0x%lux 0x%lux\n", g->s->base, g->s->top-g->s->base);
331*9a747e4fSDavid du Colombier 		return readstr(voff, a, n, buf);
332*9a747e4fSDavid du Colombier 	case Qdata:
333*9a747e4fSDavid du Colombier 		g = c->aux;
334*9a747e4fSDavid du Colombier 		if(voff > g->s->top - g->s->base)
335*9a747e4fSDavid du Colombier 			error(Ebadarg);
336*9a747e4fSDavid du Colombier 		if(voff + n > g->s->top - g->s->base)
337*9a747e4fSDavid du Colombier 			n = g->s->top - g->s->base - voff;
338*9a747e4fSDavid du Colombier 		qlock(&g->l);
339*9a747e4fSDavid du Colombier 		g->off = voff + g->s->base;
340*9a747e4fSDavid du Colombier 		g->data = smalloc(n);
341*9a747e4fSDavid du Colombier 		if(waserror()){
342*9a747e4fSDavid du Colombier 			free(g->data);
343*9a747e4fSDavid du Colombier 			qunlock(&g->l);
344*9a747e4fSDavid du Colombier 			nexterror();
345*9a747e4fSDavid du Colombier 		}
346*9a747e4fSDavid du Colombier 		g->dlen = n;
347*9a747e4fSDavid du Colombier 		docmd(g, Cread);
348*9a747e4fSDavid du Colombier 		memmove(a, g->data, g->dlen);
349*9a747e4fSDavid du Colombier 		free(g->data);
350*9a747e4fSDavid du Colombier 		qunlock(&g->l);
351*9a747e4fSDavid du Colombier 		poperror();
352*9a747e4fSDavid du Colombier 		return g->dlen;
353*9a747e4fSDavid du Colombier 	default:
354*9a747e4fSDavid du Colombier 		panic("segmentread");
355*9a747e4fSDavid du Colombier 	}
356*9a747e4fSDavid du Colombier 	return 0;	/* not reached */
357*9a747e4fSDavid du Colombier }
358*9a747e4fSDavid du Colombier 
359*9a747e4fSDavid du Colombier static long
360*9a747e4fSDavid du Colombier segmentwrite(Chan *c, void *a, long n, vlong voff)
361*9a747e4fSDavid du Colombier {
362*9a747e4fSDavid du Colombier 	Cmdbuf *cb;
363*9a747e4fSDavid du Colombier 	Globalseg *g;
364*9a747e4fSDavid du Colombier 	ulong va, len, top;
365*9a747e4fSDavid du Colombier 
366*9a747e4fSDavid du Colombier 	if(c->qid.type == QTDIR)
367*9a747e4fSDavid du Colombier 		error(Eperm);
368*9a747e4fSDavid du Colombier 
369*9a747e4fSDavid du Colombier 	switch(TYPE(c)){
370*9a747e4fSDavid du Colombier 	case Qctl:
371*9a747e4fSDavid du Colombier 		g = c->aux;
372*9a747e4fSDavid du Colombier 		cb = parsecmd(a, n);
373*9a747e4fSDavid du Colombier 		if(strcmp(cb->f[0], "va") == 0){
374*9a747e4fSDavid du Colombier 			if(g->s != nil)
375*9a747e4fSDavid du Colombier 				error("already has a virtual address");
376*9a747e4fSDavid du Colombier 			if(cb->nf < 3)
377*9a747e4fSDavid du Colombier 				error(Ebadarg);
378*9a747e4fSDavid du Colombier 			va = strtoul(cb->f[1], 0, 0);
379*9a747e4fSDavid du Colombier 			len = strtoul(cb->f[2], 0, 0);
380*9a747e4fSDavid du Colombier 			top = PGROUND(va + len);
381*9a747e4fSDavid du Colombier 			va = va&~(BY2PG-1);
382*9a747e4fSDavid du Colombier 			len = (top - va) / BY2PG;
383*9a747e4fSDavid du Colombier 			if(len == 0)
384*9a747e4fSDavid du Colombier 				error(Ebadarg);
385*9a747e4fSDavid du Colombier 			g->s = newseg(SG_SHARED, va, len);
386*9a747e4fSDavid du Colombier 		} else
387*9a747e4fSDavid du Colombier 			error(Ebadctl);
388*9a747e4fSDavid du Colombier 		break;
389*9a747e4fSDavid du Colombier 	case Qdata:
390*9a747e4fSDavid du Colombier 		g = c->aux;
391*9a747e4fSDavid du Colombier 		if(voff + n > g->s->top - g->s->base)
392*9a747e4fSDavid du Colombier 			error(Ebadarg);
393*9a747e4fSDavid du Colombier 		qlock(&g->l);
394*9a747e4fSDavid du Colombier 		g->off = voff + g->s->base;
395*9a747e4fSDavid du Colombier 		g->data = smalloc(n);
396*9a747e4fSDavid du Colombier 		if(waserror()){
397*9a747e4fSDavid du Colombier 			free(g->data);
398*9a747e4fSDavid du Colombier 			qunlock(&g->l);
399*9a747e4fSDavid du Colombier 			nexterror();
400*9a747e4fSDavid du Colombier 		}
401*9a747e4fSDavid du Colombier 		g->dlen = n;
402*9a747e4fSDavid du Colombier 		memmove(g->data, a, g->dlen);
403*9a747e4fSDavid du Colombier 		docmd(g, Cwrite);
404*9a747e4fSDavid du Colombier 		free(g->data);
405*9a747e4fSDavid du Colombier 		qunlock(&g->l);
406*9a747e4fSDavid du Colombier 		poperror();
407*9a747e4fSDavid du Colombier 		return g->dlen;
408*9a747e4fSDavid du Colombier 	default:
409*9a747e4fSDavid du Colombier 		panic("segmentwrite");
410*9a747e4fSDavid du Colombier 	}
411*9a747e4fSDavid du Colombier 	return 0;	/* not reached */
412*9a747e4fSDavid du Colombier }
413*9a747e4fSDavid du Colombier 
414*9a747e4fSDavid du Colombier static int
415*9a747e4fSDavid du Colombier segmentwstat(Chan *c, uchar *dp, int n)
416*9a747e4fSDavid du Colombier {
417*9a747e4fSDavid du Colombier 	Globalseg *g;
418*9a747e4fSDavid du Colombier 	Dir *d;
419*9a747e4fSDavid du Colombier 
420*9a747e4fSDavid du Colombier 	if(c->qid.type == QTDIR)
421*9a747e4fSDavid du Colombier 		error(Eperm);
422*9a747e4fSDavid du Colombier 
423*9a747e4fSDavid du Colombier 	g = getgseg(c);
424*9a747e4fSDavid du Colombier 	if(waserror()){
425*9a747e4fSDavid du Colombier 		putgseg(g);
426*9a747e4fSDavid du Colombier 		nexterror();
427*9a747e4fSDavid du Colombier 	}
428*9a747e4fSDavid du Colombier 
429*9a747e4fSDavid du Colombier 	if(strcmp(g->uid, up->user) && !iseve())
430*9a747e4fSDavid du Colombier 		error(Eperm);
431*9a747e4fSDavid du Colombier 	d = smalloc(sizeof(Dir)+n);
432*9a747e4fSDavid du Colombier 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
433*9a747e4fSDavid du Colombier 	g->perm = d->mode & 0777;
434*9a747e4fSDavid du Colombier 
435*9a747e4fSDavid du Colombier 	putgseg(g);
436*9a747e4fSDavid du Colombier 	poperror();
437*9a747e4fSDavid du Colombier 
438*9a747e4fSDavid du Colombier 	free(d);
439*9a747e4fSDavid du Colombier 	return n;
440*9a747e4fSDavid du Colombier }
441*9a747e4fSDavid du Colombier 
442*9a747e4fSDavid du Colombier static void
443*9a747e4fSDavid du Colombier segmentremove(Chan *c)
444*9a747e4fSDavid du Colombier {
445*9a747e4fSDavid du Colombier 	Globalseg *g;
446*9a747e4fSDavid du Colombier 	int x;
447*9a747e4fSDavid du Colombier 
448*9a747e4fSDavid du Colombier 	if(TYPE(c) != Qsegdir)
449*9a747e4fSDavid du Colombier 		error(Eperm);
450*9a747e4fSDavid du Colombier 	lock(&globalseglock);
451*9a747e4fSDavid du Colombier 	x = SEG(c);
452*9a747e4fSDavid du Colombier 	g = globalseg[x];
453*9a747e4fSDavid du Colombier 	globalseg[x] = nil;
454*9a747e4fSDavid du Colombier 	unlock(&globalseglock);
455*9a747e4fSDavid du Colombier 	if(g != nil)
456*9a747e4fSDavid du Colombier 		putgseg(g);
457*9a747e4fSDavid du Colombier }
458*9a747e4fSDavid du Colombier 
459*9a747e4fSDavid du Colombier /*
460*9a747e4fSDavid du Colombier  *  called by segattach()
461*9a747e4fSDavid du Colombier  */
462*9a747e4fSDavid du Colombier static Segment*
463*9a747e4fSDavid du Colombier globalsegattach(Proc *p, char *name)
464*9a747e4fSDavid du Colombier {
465*9a747e4fSDavid du Colombier 	int x;
466*9a747e4fSDavid du Colombier 	Globalseg *g;
467*9a747e4fSDavid du Colombier 	Segment *s;
468*9a747e4fSDavid du Colombier 
469*9a747e4fSDavid du Colombier 	g = nil;
470*9a747e4fSDavid du Colombier 	if(waserror()){
471*9a747e4fSDavid du Colombier 		unlock(&globalseglock);
472*9a747e4fSDavid du Colombier 		nexterror();
473*9a747e4fSDavid du Colombier 	}
474*9a747e4fSDavid du Colombier 	lock(&globalseglock);
475*9a747e4fSDavid du Colombier 	for(x = 0; x < nelem(globalseg); x++){
476*9a747e4fSDavid du Colombier 		g = globalseg[x];
477*9a747e4fSDavid du Colombier 		if(g != nil && strcmp(g->name, name) == 0)
478*9a747e4fSDavid du Colombier 			break;
479*9a747e4fSDavid du Colombier 	}
480*9a747e4fSDavid du Colombier 	if(x == nelem(globalseg)){
481*9a747e4fSDavid du Colombier 		unlock(&globalseglock);
482*9a747e4fSDavid du Colombier 		poperror();
483*9a747e4fSDavid du Colombier 		return nil;
484*9a747e4fSDavid du Colombier 	}
485*9a747e4fSDavid du Colombier 	devpermcheck(g->uid, g->perm, ORDWR);
486*9a747e4fSDavid du Colombier 	s = g->s;
487*9a747e4fSDavid du Colombier 	if(s == nil)
488*9a747e4fSDavid du Colombier 		error("global segment not assigned a virtual address");
489*9a747e4fSDavid du Colombier 	if(isoverlap(p, s->base, s->top) != nil)
490*9a747e4fSDavid du Colombier 		error("overlaps existing segment");
491*9a747e4fSDavid du Colombier 	incref(s);
492*9a747e4fSDavid du Colombier 	unlock(&globalseglock);
493*9a747e4fSDavid du Colombier 	poperror();
494*9a747e4fSDavid du Colombier 	return s;
495*9a747e4fSDavid du Colombier }
496*9a747e4fSDavid du Colombier 
497*9a747e4fSDavid du Colombier static void
498*9a747e4fSDavid du Colombier docmd(Globalseg *g, int cmd)
499*9a747e4fSDavid du Colombier {
500*9a747e4fSDavid du Colombier 	g->err[0] = 0;
501*9a747e4fSDavid du Colombier 	g->cmd = cmd;
502*9a747e4fSDavid du Colombier 	wakeup(&g->cmdwait);
503*9a747e4fSDavid du Colombier 	sleep(&g->replywait, cmddone, g);
504*9a747e4fSDavid du Colombier 	if(g->err[0])
505*9a747e4fSDavid du Colombier 		error(g->err);
506*9a747e4fSDavid du Colombier }
507*9a747e4fSDavid du Colombier 
508*9a747e4fSDavid du Colombier static int
509*9a747e4fSDavid du Colombier cmdready(void *arg)
510*9a747e4fSDavid du Colombier {
511*9a747e4fSDavid du Colombier 	Globalseg *g = arg;
512*9a747e4fSDavid du Colombier 
513*9a747e4fSDavid du Colombier 	return g->cmd != Cnone;
514*9a747e4fSDavid du Colombier }
515*9a747e4fSDavid du Colombier 
516*9a747e4fSDavid du Colombier static void
517*9a747e4fSDavid du Colombier segmentkproc(void *arg)
518*9a747e4fSDavid du Colombier {
519*9a747e4fSDavid du Colombier 	Globalseg *g = arg;
520*9a747e4fSDavid du Colombier 	int done;
521*9a747e4fSDavid du Colombier 	int sno;
522*9a747e4fSDavid du Colombier 
523*9a747e4fSDavid du Colombier 	for(sno = 0; sno < NSEG; sno++)
524*9a747e4fSDavid du Colombier 		if(up->seg[sno] == nil && sno != ESEG)
525*9a747e4fSDavid du Colombier 			break;
526*9a747e4fSDavid du Colombier 	if(sno == NSEG)
527*9a747e4fSDavid du Colombier 		panic("segmentkproc");
528*9a747e4fSDavid du Colombier 	g->kproc = up;
529*9a747e4fSDavid du Colombier 
530*9a747e4fSDavid du Colombier 	incref(g->s);
531*9a747e4fSDavid du Colombier 	up->seg[sno] = g->s;
532*9a747e4fSDavid du Colombier 
533*9a747e4fSDavid du Colombier 	for(done = 0; !done;){
534*9a747e4fSDavid du Colombier 		sleep(&g->cmdwait, cmdready, g);
535*9a747e4fSDavid du Colombier 		if(waserror()){
536*9a747e4fSDavid du Colombier 			strncpy(g->err, up->errstr, sizeof(g->err));
537*9a747e4fSDavid du Colombier 		} else {
538*9a747e4fSDavid du Colombier 			switch(g->cmd){
539*9a747e4fSDavid du Colombier 			case Cstart:
540*9a747e4fSDavid du Colombier 				break;
541*9a747e4fSDavid du Colombier 			case Cdie:
542*9a747e4fSDavid du Colombier 				done = 1;
543*9a747e4fSDavid du Colombier 				break;
544*9a747e4fSDavid du Colombier 			case Cread:
545*9a747e4fSDavid du Colombier 				memmove(g->data, (char*)g->off, g->dlen);
546*9a747e4fSDavid du Colombier 				break;
547*9a747e4fSDavid du Colombier 			case Cwrite:
548*9a747e4fSDavid du Colombier 				memmove((char*)g->off, g->data, g->dlen);
549*9a747e4fSDavid du Colombier 				break;
550*9a747e4fSDavid du Colombier 			}
551*9a747e4fSDavid du Colombier 			poperror();
552*9a747e4fSDavid du Colombier 		}
553*9a747e4fSDavid du Colombier 		g->cmd = Cnone;
554*9a747e4fSDavid du Colombier 		wakeup(&g->replywait);
555*9a747e4fSDavid du Colombier 	}
556*9a747e4fSDavid du Colombier }
557*9a747e4fSDavid du Colombier 
558*9a747e4fSDavid du Colombier Dev segmentdevtab = {
559*9a747e4fSDavid du Colombier 	'g',
560*9a747e4fSDavid du Colombier 	"segment",
561*9a747e4fSDavid du Colombier 
562*9a747e4fSDavid du Colombier 	devreset,
563*9a747e4fSDavid du Colombier 	segmentinit,
564*9a747e4fSDavid du Colombier 	devshutdown,
565*9a747e4fSDavid du Colombier 	segmentattach,
566*9a747e4fSDavid du Colombier 	segmentwalk,
567*9a747e4fSDavid du Colombier 	segmentstat,
568*9a747e4fSDavid du Colombier 	segmentopen,
569*9a747e4fSDavid du Colombier 	segmentcreate,
570*9a747e4fSDavid du Colombier 	segmentclose,
571*9a747e4fSDavid du Colombier 	segmentread,
572*9a747e4fSDavid du Colombier 	devbread,
573*9a747e4fSDavid du Colombier 	segmentwrite,
574*9a747e4fSDavid du Colombier 	devbwrite,
575*9a747e4fSDavid du Colombier 	segmentremove,
576*9a747e4fSDavid du Colombier 	segmentwstat,
577*9a747e4fSDavid du Colombier };
578*9a747e4fSDavid du Colombier 
579