plan 9 kernel history: overview | file list | diff list

1992/0111/port/devproc.c (diff list | history)

port/devproc.c on 1990/0227
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1991/1109    
#include	"fcall.h" 
1991/1110    
#include	"ureg.h" 
1990/0227    
 
#include	"devtab.h" 
 
enum{ 
	Qdir, 
	Qctl, 
	Qmem, 
	Qnote, 
1990/1110    
	Qnotepg, 
1990/0227    
	Qproc, 
1991/0705    
	Qsegment, 
1990/0227    
	Qstatus, 
	Qtext, 
}; 
 
1991/0712    
#define	STATSIZE	(2*NAMELEN+12+6*12) 
1990/0227    
Dirtab procdir[]={ 
1991/1109    
	"ctl",		{Qctl},		0,			0000, 
	"mem",		{Qmem},		0,			0000, 
	"note",		{Qnote},	0,			0000, 
1991/1112    
	"notepg",	{Qnotepg},	0,			0000, 
1991/1109    
	"proc",		{Qproc},	sizeof(Proc),		0000, 
1991/1112    
	"segment",	{Qsegment},	0,			0444, 
	"status",	{Qstatus},	STATSIZE,		0444, 
1991/1109    
	"text",		{Qtext},	0,			0000, 
1990/0227    
}; 
 
1991/1109    
/* Segment type from portdat.h */ 
char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys" }; 
1991/0705    
 
1990/0227    
/* 
1990/11211    
 * Qids are, in path: 
1990/0227    
 *	 4 bits of file type (qids above) 
1990/1128    
 *	23 bits of process slot number + 1 
1990/11211    
 *	     in vers, 
 *	32 bits of pid, for consistency checking 
 * If notepg, c->pgrpid.path is pgrp slot, .vers is pgrpid. 
1990/0227    
 */ 
#define	NPROC	(sizeof procdir/sizeof(Dirtab)) 
#define	QSHIFT	4	/* location in qid of proc slot # */ 
1990/11211    
#define	QID(q)	(((q).path&0x0000000F)>>0) 
1990/1128    
#define	SLOT(q)	((((q).path&0x07FFFFFF0)>>QSHIFT)-1) 
1990/11211    
#define	PID(q)	((q).vers) 
1990/0227    
 
1991/1109    
void	procctlreq(Proc*, char*, int); 
int	procctlmemio(Proc*, ulong, int, void*, int); 
1991/1110    
Chan   *procctlnotepg(Chan*, void*, int); 
Chan   *proctext(Chan*, Proc*); 
Segment *txt2data(Proc*, Segment*); 
int	procstopped(void*); 
1991/1109    
 
1990/0227    
int 
procgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) 
{ 
	Proc *p; 
	char buf[NAMELEN]; 
1991/1109    
	ulong pid, path, perm; 
1990/0227    
 
1990/11211    
	if(c->qid.path == CHDIR){ 
1990/0227    
		if(s >= conf.nproc) 
			return -1; 
		p = proctab(s); 
		pid = p->pid; 
		if(pid == 0) 
			return 0; 
		sprint(buf, "%d", pid); 
1991/1112    
		devdir(c, (Qid){CHDIR|((s+1)<<QSHIFT), pid}, buf, 0, p->user, CHDIR|0555, dp); 
1990/0227    
		return 1; 
	} 
	if(s >= NPROC) 
		return -1; 
	if(tab) 
		panic("procgen"); 
	tab = &procdir[s]; 
1991/0705    
	path = c->qid.path&~(CHDIR|((1<<QSHIFT)-1));	/* slot component */ 
1991/1109    
 
	p = proctab(SLOT(c->qid)); 
	perm = tab->perm; 
	if(perm == 0) 
		perm = p->procmode; 
 
	devdir(c, (Qid){path|tab->qid.path, c->qid.vers}, tab->name, tab->length, p->user, perm, dp); 
1990/0227    
	return 1; 
} 
 
void 
procinit(void) 
{ 
	if(conf.nproc >= (1<<(16-QSHIFT))-1) 
		print("warning: too many procs for devproc\n"); 
} 
 
void 
procreset(void) 
{ 
} 
 
Chan* 
procattach(char *spec) 
{ 
	return devattach('p', spec); 
} 
 
Chan* 
procclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int 
procwalk(Chan *c, char *name) 
{ 
1991/1106    
	if(strcmp(name, "..") == 0) { 
1991/1011    
		c->qid.path = Qdir|CHDIR; 
		return 1; 
	} 
 
1990/0227    
	return devwalk(c, name, 0, 0, procgen); 
} 
 
void 
procstat(Chan *c, char *db) 
{ 
	devstat(c, db, 0, 0, procgen); 
} 
 
Chan * 
procopen(Chan *c, int omode) 
{ 
	Proc *p; 
1990/1110    
	Pgrp *pg; 
1991/0705    
	Segment *s; 
1990/0227    
	Chan *tc; 
 
1991/1112    
	if(c->qid.path & CHDIR) 
		return devopen(c, omode, 0, 0, procgen); 
 
1990/0227    
	p = proctab(SLOT(c->qid)); 
1990/1110    
	pg = p->pgrp; 
1990/11211    
	if(p->pid != PID(c->qid)) 
		error(Eprocdied); 
1991/1110    
 
1990/0227    
	omode = openmode(omode); 
 
	switch(QID(c->qid)){ 
	case Qtext: 
1991/1112    
		if(omode != OREAD) 
			error(Eperm); 
1991/1110    
		tc = proctext(c, p); 
1990/0227    
		tc->offset = 0; 
1991/1110    
 
1990/0227    
		return tc; 
1991/1110    
 
1990/0227    
	case Qctl: 
	case Qnote: 
1991/1110    
	case Qmem: 
1991/0705    
	case Qsegment: 
1991/1112    
	case Qproc: 
	case Qstatus: 
1990/0227    
		break; 
1990/1110    
 
	case Qnotepg: 
1990/1115    
		if(omode!=OWRITE || pg->pgrpid==1)	/* easy to do by mistake */ 
1990/11211    
			error(Eperm); 
		c->pgrpid.path = pg->index+1; 
		c->pgrpid.vers = pg->pgrpid; 
1990/1110    
		break; 
1990/0227    
	default: 
		pprint("unknown qid in devopen\n"); 
1990/11211    
		error(Egreg); 
1990/0227    
	} 
1991/1110    
 
	/* Affix pid to qid */ 
1990/0227    
	if(p->state != Dead) 
1990/11211    
		c->qid.vers = p->pid; 
1991/1112    
 
	return devopen(c, omode, 0, 0, procgen); 
; 
1990/0227    
} 
 
void 
proccreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1991/1115    
	USED(c, name, omode, perm); 
1990/11211    
	error(Eperm); 
1990/0227    
} 
 
void 
procremove(Chan *c) 
{ 
1991/1115    
	USED(c); 
1990/11211    
	error(Eperm); 
1990/0227    
} 
 
void 
procwstat(Chan *c, char *db) 
{ 
1991/1109    
	Proc *p; 
	Dir d; 
 
1991/1112    
	if(c->qid.path&CHDIR) 
		error(Eperm); 
 
1991/1109    
	convM2D(db, &d); 
	p = proctab(SLOT(c->qid)); 
	if(p->pid != PID(c->qid)) 
		error(Eprocdied); 
 
	if(strcmp(u->p->user, p->user) != 0 && strcmp(u->p->user, eve) != 0) 
		error(Eperm); 
 
	p->procmode = d.mode&0777; 
1990/0227    
} 
 
void 
procclose(Chan * c) 
{ 
1991/1115    
	USED(c); 
1990/0227    
} 
 
long 
1991/0411    
procread(Chan *c, void *va, long n, ulong offset) 
1990/0227    
{ 
	char *a = va, *b; 
1991/0705    
	char statbuf[NSEG*32]; 
1990/0227    
	Proc *p; 
	Page *pg; 
1990/0614    
	KMap *k; 
1991/0705    
	int i, j; 
1990/0227    
	long l; 
	long pid; 
	User *up; 
1991/0705    
	Segment *sg; 
1990/0227    
 
1990/11211    
	if(c->qid.path & CHDIR) 
1990/0227    
		return devdirread(c, a, n, 0, 0, procgen); 
 
	p = proctab(SLOT(c->qid)); 
1990/11211    
	if(p->pid != PID(c->qid)) 
		error(Eprocdied); 
1990/0227    
 
	switch(QID(c->qid)){ 
	case Qmem: 
1991/1124    
		/* ugly math: USERADDR+BY2PG may be == 0 */ 
		if(offset >= USERADDR && offset <= USERADDR+BY2PG-1) { 
			if(offset+n >= USERADDR+BY2PG-1) 
1991/0411    
				n = USERADDR+BY2PG - offset; 
1990/0227    
			pg = p->upage; 
1990/11211    
			if(pg==0 || p->pid!=PID(c->qid)) 
				error(Eprocdied); 
1990/0614    
			k = kmap(pg); 
			b = (char*)VA(k); 
1991/0411    
			memmove(a, b+(offset-USERADDR), n); 
1990/0614    
			kunmap(k); 
1990/0227    
			return n; 
		} 
 
1991/1110    
		if(offset >= KZERO) { 
			if(offset < KZERO+conf.npage0*BY2PG){ 
				if(offset+n > KZERO+conf.npage0*BY2PG) 
					n = KZERO+conf.npage0*BY2PG - offset; 
				memmove(a, (char*)offset, n); 
				return n; 
			} 
			if(offset < KZERO+conf.base1+conf.npage1*BY2PG){ 
				if(offset+n > KZERO+conf.base1+conf.npage1*BY2PG) 
					n = KZERO+conf.base1+conf.npage1*BY2PG - offset; 
				memmove(a, (char*)offset, n); 
				return n; 
			} 
1990/0227    
		} 
1991/1109    
 
		return procctlmemio(p, offset, n, va, 1); 
 
1990/0227    
	case Qnote: 
1991/1216    
		qlock(&p->debug); 
1990/0227    
		if(waserror()){ 
1991/1216    
			qunlock(&p->debug); 
1990/0227    
			nexterror(); 
		} 
1990/11211    
		if(p->pid != PID(c->qid)) 
			error(Eprocdied); 
1990/0614    
		k = kmap(p->upage); 
		up = (User*)VA(k); 
1990/0227    
		if(up->p != p){ 
1990/0614    
			kunmap(k); 
1990/0227    
			pprint("note read u/p mismatch"); 
1990/11211    
			error(Egreg); 
1990/0227    
		} 
		if(n < ERRLEN) 
1990/11211    
			error(Etoosmall); 
1990/0227    
		if(up->nnote == 0) 
			n = 0; 
		else{ 
1991/0318    
			memmove(va, up->note[0].msg, ERRLEN); 
1990/0227    
			up->nnote--; 
1991/0318    
			memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 
1990/0227    
			n = ERRLEN; 
		} 
1991/1111    
		if(up->nnote == 0) 
			p->notepending = 0; 
1990/0614    
		kunmap(k); 
1991/0614    
		poperror(); 
1991/1216    
		qunlock(&p->debug); 
1990/0227    
		return n; 
 
	case Qproc: 
1991/0411    
		if(offset >= sizeof(Proc)) 
1990/0227    
			return 0; 
1991/0411    
		if(offset+n > sizeof(Proc)) 
			n = sizeof(Proc) - offset; 
		memmove(a, ((char*)p)+offset, n); 
1990/0227    
		return n; 
 
	case Qstatus: 
1991/0712    
		if(offset >= STATSIZE) 
1990/0227    
			return 0; 
1991/0712    
		if(offset+n > STATSIZE) 
			n = STATSIZE - offset; 
		j = sprint(statbuf, "%-27s %-27s %-11s ", 
1991/1105    
			p->text, p->user, p->psstate ? p->psstate : statename[p->state]); 
1990/0227    
		for(i=0; i<6; i++){ 
			l = p->time[i]; 
			if(i == TReal) 
				l = MACHP(0)->ticks - l; 
1990/0614    
			l = TK2MS(l); 
1991/0712    
			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 
1990/0227    
		} 
1991/0411    
		memmove(a, statbuf+offset, n); 
1990/0227    
		return n; 
1991/1110    
 
1991/0705    
	case Qsegment: 
		j = 0; 
		for(i = 0; i < NSEG; i++) 
			if(sg = p->seg[i]) 
				j += sprint(&statbuf[j], "%-6s %c %.8lux %.8lux %4d\n", 
				sname[sg->type&SG_TYPE], sg->type&SG_RONLY ? 'R' : ' ', 
				sg->base, sg->top, sg->ref); 
		if(offset >= j) 
			return 0; 
		if(offset+n > j) 
			n = j-offset; 
1991/1112    
		if(n == 0 && offset == 0) 
			errors("no segments"); 
1991/0705    
		memmove(a, &statbuf[offset], n); 
		return n; 
1990/0227    
	} 
1990/11211    
	error(Egreg); 
1990/0227    
} 
 
 
long 
1991/0411    
procwrite(Chan *c, void *va, long n, ulong offset) 
1990/0227    
{ 
	Proc *p; 
	User *up; 
1990/0614    
	KMap *k; 
1990/0227    
	char buf[ERRLEN]; 
1991/1110    
	Ureg *ur; 
	User *pxu; 
	Page *pg; 
	char *a = va, *b; 
1991/1111    
	ulong hi; 
1990/0227    
 
1990/11211    
	if(c->qid.path & CHDIR) 
		error(Eisdir); 
1990/1110    
 
1990/1126    
	p = proctab(SLOT(c->qid)); 
1991/1109    
 
	/* Use the remembered pgrp id in the channel rather than the process pgrpid */ 
1990/1110    
	if(QID(c->qid) == Qnotepg){ 
1991/1109    
		procctlnotepg(c, va, n); 
1990/1110    
		return n; 
	} 
 
1991/1216    
	qlock(&p->debug); 
1990/0227    
	if(waserror()){ 
1991/1216    
		qunlock(&p->debug); 
1990/0227    
		nexterror(); 
	} 
1990/11211    
	if(p->pid != PID(c->qid)) 
		error(Eprocdied); 
1990/0227    
 
	switch(QID(c->qid)){ 
1991/1109    
	case Qmem: 
1991/1110    
		if(p->state != Stopped) 
			errors("not stopped"); 
 
1991/1124    
		if(offset >= USERADDR && offset <= USERADDR+BY2PG-1) { 
1991/1110    
			pg = p->upage; 
			if(pg==0 || p->pid!=PID(c->qid)) 
				error(Eprocdied); 
			k = kmap(pg); 
			b = (char*)VA(k); 
			pxu = (User*)b; 
1991/1111    
			hi = offset+n; 
			/* Check for floating point registers */ 
			if(offset >= (ulong)&u->fpsave && hi <= (ulong)&u->fpsave+sizeof(FPsave)){ 
				memmove(b+(offset-USERADDR), a, n); 
				break; 
			} 
			/* Check user register set for process at kernel entry */ 
			ur = pxu->dbgreg; 
			if(offset < (ulong)ur || hi > (ulong)ur+sizeof(Ureg)) { 
1991/1110    
				kunmap(k); 
				errors("bad u-area address"); 
			} 
1991/1111    
			ur = (Ureg*)(b+((ulong)ur-USERADDR)); 
			setregisters(ur, b+(offset-USERADDR), a, n); 
1991/1110    
			kunmap(k); 
		} 
1991/1111    
		else	/* Try user memory segments */ 
1991/1110    
			n = procctlmemio(p, offset, n, va, 0); 
		break; 
 
1990/0227    
	case Qctl: 
1991/1109    
		procctlreq(p, va, n); 
1991/1110    
		break; 
 
1990/0227    
	case Qnote: 
1991/1112    
		if(p->kp) 
1991/1116    
			errors("can't note kproc"); 
1990/0614    
		k = kmap(p->upage); 
		up = (User*)VA(k); 
1990/0227    
		if(up->p != p){ 
1990/0614    
			kunmap(k); 
1990/0227    
			pprint("note write u/p mismatch"); 
1990/11211    
			error(Egreg); 
1990/0227    
		} 
1990/0614    
		kunmap(k); 
1990/0227    
		if(n >= ERRLEN-1) 
1990/11211    
			error(Etoobig); 
1991/0318    
		memmove(buf, va, n); 
1990/0227    
		buf[n] = 0; 
		if(!postnote(p, 0, buf, NUser)) 
1990/11211    
			error(Enonote); 
1990/0227    
		break; 
1991/1110    
 
1990/0227    
	default: 
		pprint("unknown qid in procwrite\n"); 
1990/11211    
		error(Egreg); 
1990/0227    
	} 
1991/0614    
	poperror(); 
1991/1216    
	qunlock(&p->debug); 
1991/1109    
	return n; 
} 
 
Chan * 
1991/1110    
proctext(Chan *c, Proc *p) 
{ 
	Chan *tc; 
	Image *i; 
	Segment *s; 
 
	s = p->seg[TSEG]; 
1991/1112    
	if(s == 0) 
		errors("no text segment"); 
	if(p->state==Dead) 
1991/1110    
		error(Eprocdied); 
 
	lock(s); 
	i = s->image; 
	if(i == 0) { 
		unlock(s); 
		error(Eprocdied); 
	} 
	unlock(s); 
 
	lock(i); 
	if(waserror()) { 
		unlock(i); 
		nexterror(); 
	} 
 
	tc = i->c; 
	if(tc == 0) 
		error(Eprocdied); 
 
	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) { 
		close(tc); 
		error(Eprocdied); 
	} 
 
	if(p->pid != PID(c->qid)) 
		error(Eprocdied); 
 
	unlock(i); 
	poperror(); 
 
	return tc; 
} 
 
Chan * 
1991/1109    
procctlnotepg(Chan *c, void *va, int n) 
{ 
	Pgrp *pg; 
 
	pg = pgrptab(c->pgrpid.path-1); 
	qlock(&pg->debug); 
	if(waserror()){ 
		qunlock(&pg->debug); 
		nexterror(); 
	} 
	if(pg->pgrpid != c->pgrpid.vers){ 
		qunlock(&pg->debug); 
		error(Eprocdied); 
	} 
	pgrpnote(pg, va, n, NUser); 
	poperror(); 
	qunlock(&pg->debug); 
} 
 
void 
1991/1110    
procstopwait(Proc *p, int ctl) 
{ 
	int pid; 
 
	if(p->pdbg) 
		errors("debugged already"); 
	if(procstopped(p)) 
		return; 
 
	if(ctl != 0) 
		p->procctl = ctl; 
	p->pdbg = u->p; 
	pid = p->pid; 
1991/1216    
	qunlock(&p->debug); 
1991/1110    
	u->p->psstate = "Stopwait"; 
	if(waserror()) { 
		p->pdbg = 0; 
1991/1216    
		qlock(&p->debug); 
1991/1110    
		nexterror(); 
	} 
	sleep(&u->p->sleep, procstopped, p); 
	poperror(); 
1991/1216    
	qlock(&p->debug); 
1991/1110    
	if(p->pid != pid) 
		error(Eprocdied); 
} 
 
void 
1991/1109    
procctlreq(Proc *p, char *va, int n) 
{ 
1991/1112    
	char buf[NAMELEN]; 
1991/1109    
 
1991/1112    
	if(n > NAMELEN) 
		n = NAMELEN; 
	strncpy(buf, va, n); 
 
1991/1117    
	if(strncmp(buf, "stop", 4) == 0) 
1991/1112    
		procstopwait(p, Proc_stopme); 
	else if(strncmp(buf, "kill", 4) == 0) { 
1991/1117    
		if(p->state == Broken) 
1991/1112    
			ready(p); 
1991/1117    
		else{ 
			if(p->state == Stopped) 
				ready(p); 
			postnote(p, 0, "sys: killed", NExit); 
			p->procctl = Proc_exitme; 
		} 
1991/1112    
	} 
	else if(strncmp(buf, "hang", 4) == 0) 
		p->hang = 1; 
	else if(strncmp(buf, "waitstop", 8) == 0) 
		procstopwait(p, 0); 
	else if(strncmp(buf, "startstop", 9) == 0) { 
1991/1110    
		if(p->state != Stopped) 
			errors("not stopped"); 
		p->procctl = Proc_traceme; 
		ready(p); 
		procstopwait(p, Proc_traceme); 
	} 
1991/1112    
	else if(strncmp(buf, "start", 5) == 0) { 
1991/1109    
		if(p->state != Stopped) 
			errors("not stopped"); 
		ready(p); 
	} 
1991/1112    
	else 
		error(Ebadctl); 
1991/1109    
} 
 
int 
1991/1110    
procstopped(void *a) 
{ 
	Proc *p = a; 
	return p->state == Stopped; 
} 
 
int 
1991/1109    
procctlmemio(Proc *p, ulong offset, int n, void *va, int read) 
{ 
1991/1113    
	Pte *pte; 
1991/1109    
	Page *pg; 
	KMap *k; 
1991/1110    
	Segment *s; 
1991/1109    
	ulong soff; 
	char *a = va, *b; 
 
1991/1113    
	for(;;) { 
		s = seg(p, offset, 1); 
		if(s == 0) 
			errors("not in address space"); 
1991/1109    
 
1991/1113    
		if(offset+n >= s->top) 
			n = s->top-offset; 
1991/1109    
 
1991/1113    
		if((s->type&SG_TYPE) == SG_TEXT) 
			s = txt2data(p, s); 
1991/1109    
 
1991/1113    
		s->steal++; 
		soff = offset-s->base; 
1991/1109    
		if(waserror()) { 
			s->steal--; 
			nexterror(); 
		} 
1991/1113    
		if(fixfault(s, offset, read, 0) == 0) 
			break; 
1991/1109    
		poperror(); 
1991/1113    
		s->steal--; 
1991/1109    
	} 
1991/1113    
	poperror(); 
	pte = s->map[soff/PTEMAPMEM]; 
	if(pte == 0) 
		panic("procctlmemio");  
	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 
	if(pagedout(pg)) 
		panic("procctlmemio1");  
		 
1991/1109    
	k = kmap(pg); 
	b = (char*)VA(k); 
1991/1110    
	if(read == 1) 
		memmove(a, b+(offset&(BY2PG-1)), n); 
	else 
		memmove(b+(offset&(BY2PG-1)), a, n); 
 
1991/1109    
	kunmap(k); 
 
	s->steal--; 
	qunlock(&s->lk); 
1991/1110    
 
	if(read == 0) 
		p->newtlb = 1; 
 
1990/0227    
	return n; 
1991/1110    
} 
 
Segment * 
txt2data(Proc *p, Segment *s) 
{ 
	Segment *ps; 
	int i; 
 
	ps = newseg(SG_DATA, s->base, s->size); 
	ps->image = s->image; 
	incref(ps->image); 
	ps->fstart = s->fstart; 
	ps->flen = s->flen; 
	ps->flushme = 1; 
 
	for(i = 0; i < NSEG; i++) 
		if(p->seg[i] == s) 
			break; 
	if(p->seg[i] != s) 
		panic("segment gone"); 
 
	qunlock(&s->lk); 
	putseg(s); 
	qlock(&ps->lk); 
	p->seg[i] = ps; 
 
	return ps; 
1990/0227    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)