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

Lines 1–500 of 639.