xref: /plan9-contrib/sys/src/9/port/devproc.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 #include	"ureg.h"
8 
9 #include	"devtab.h"
10 
11 enum{
12 	Qdir,
13 	Qctl,
14 	Qmem,
15 	Qnote,
16 	Qnoteid,
17 	Qnotepg,
18 	Qproc,
19 	Qsegment,
20 	Qstatus,
21 	Qtext,
22 	Qwait,
23 };
24 
25 #define	STATSIZE	(2*NAMELEN+12+7*12)
26 Dirtab procdir[] =
27 {
28 	"ctl",		{Qctl},		0,			0000,
29 	"mem",		{Qmem},		0,			0000,
30 	"note",		{Qnote},	0,			0000,
31 	"noteid",	{Qnoteid},	0,			0666,
32 	"notepg",	{Qnotepg},	0,			0000,
33 	"proc",		{Qproc},	sizeof(Proc),		0444,
34 	"segment",	{Qsegment},	0,			0444,
35 	"status",	{Qstatus},	STATSIZE,		0444,
36 	"text",		{Qtext},	0,			0000,
37 	"wait",		{Qwait},	0,			0400,
38 };
39 
40 /* Segment type from portdat.h */
41 char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Shdata" };
42 
43 /*
44  * Qids are, in path:
45  *	 4 bits of file type (qids above)
46  *	23 bits of process slot number + 1
47  *	     in vers,
48  *	32 bits of pid, for consistency checking
49  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
50  */
51 #define	NPROC	(sizeof procdir/sizeof(Dirtab))
52 #define	QSHIFT	4	/* location in qid of proc slot # */
53 
54 #define	QID(q)		(((q).path&0x0000000F)>>0)
55 #define	SLOT(q)		((((q).path&0x07FFFFFF0)>>QSHIFT)-1)
56 #define	PID(q)		((q).vers)
57 #define	NOTEID(q)	((q).vers)
58 
59 void	procctlreq(Proc*, char*, int);
60 int	procctlmemio(Proc*, ulong, int, void*, int);
61 Chan*	proctext(Chan*, Proc*);
62 Segment* txt2data(Proc*, Segment*);
63 int	procstopped(void*);
64 
65 int
66 procgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
67 {
68 	Qid qid;
69 	Proc *p;
70 	char buf[NAMELEN];
71 	ulong pid, path, perm, len;
72 
73 	USED(ntab);
74 	if(c->qid.path == CHDIR){
75 		if(s >= conf.nproc)
76 			return -1;
77 		p = proctab(s);
78 		pid = p->pid;
79 		if(pid == 0)
80 			return 0;
81 		sprint(buf, "%d", pid);
82 		qid = (Qid){CHDIR|((s+1)<<QSHIFT), pid};
83 		devdir(c, qid, buf, 0, p->user, CHDIR|0555, dp);
84 		return 1;
85 	}
86 	if(s >= NPROC)
87 		return -1;
88 	if(tab)
89 		panic("procgen");
90 
91 	tab = &procdir[s];
92 	path = c->qid.path&~(CHDIR|((1<<QSHIFT)-1));	/* slot component */
93 
94 	p = proctab(SLOT(c->qid));
95 	perm = tab->perm;
96 	if(perm == 0)
97 		perm = p->procmode;
98 
99 	len = tab->length;
100 	if(QID(c->qid) == Qwait)
101 		len = p->nwait * sizeof(Waitmsg);
102 
103 	qid = (Qid){path|tab->qid.path, c->qid.vers};
104 	devdir(c, qid, tab->name, len, p->user, perm, dp);
105 	return 1;
106 }
107 
108 void
109 procinit(void)
110 {
111 	if(conf.nproc >= (1<<(16-QSHIFT))-1)
112 		print("warning: too many procs for devproc\n");
113 }
114 
115 void
116 procreset(void)
117 {
118 }
119 
120 Chan*
121 procattach(char *spec)
122 {
123 	return devattach('p', spec);
124 }
125 
126 Chan*
127 procclone(Chan *c, Chan *nc)
128 {
129 	return devclone(c, nc);
130 }
131 
132 int
133 procwalk(Chan *c, char *name)
134 {
135 	if(strcmp(name, "..") == 0) {
136 		c->qid.path = Qdir|CHDIR;
137 		return 1;
138 	}
139 
140 	return devwalk(c, name, 0, 0, procgen);
141 }
142 
143 void
144 procstat(Chan *c, char *db)
145 {
146 	devstat(c, db, 0, 0, procgen);
147 }
148 
149 Chan *
150 procopen(Chan *c, int omode)
151 {
152 	Proc *p;
153 	Pgrp *pg;
154 	Chan *tc;
155 
156 	if(c->qid.path & CHDIR)
157 		return devopen(c, omode, 0, 0, procgen);
158 
159 	p = proctab(SLOT(c->qid));
160 	pg = p->pgrp;
161 	if(p->pid != PID(c->qid))
162 		error(Eprocdied);
163 
164 	omode = openmode(omode);
165 
166 	switch(QID(c->qid)){
167 	case Qtext:
168 		tc = proctext(c, p);
169 		tc->offset = 0;
170 		return tc;
171 
172 	case Qctl:
173 	case Qnote:
174 	case Qnoteid:
175 	case Qmem:
176 	case Qsegment:
177 	case Qproc:
178 	case Qstatus:
179 	case Qwait:
180 		break;
181 
182 	case Qnotepg:
183 		if(omode!=OWRITE || pg->pgrpid == 1)
184 			error(Eperm);
185 		c->pgrpid.path = pg->pgrpid+1;
186 		c->pgrpid.vers = p->noteid;
187 		break;
188 
189 	default:
190 		pprint("procopen %lux\n", c->qid);
191 		error(Egreg);
192 	}
193 
194 	/* Affix pid to qid */
195 	if(p->state != Dead)
196 		c->qid.vers = p->pid;
197 
198 	return devopen(c, omode, 0, 0, procgen);
199 }
200 
201 void
202 proccreate(Chan *c, char *name, int omode, ulong perm)
203 {
204 	USED(c, name, omode, perm);
205 	error(Eperm);
206 }
207 
208 void
209 procremove(Chan *c)
210 {
211 	USED(c);
212 	error(Eperm);
213 }
214 
215 void
216 procwstat(Chan *c, char *db)
217 {
218 	Proc *p;
219 	Dir d;
220 
221 	if(c->qid.path&CHDIR)
222 		error(Eperm);
223 
224 	convM2D(db, &d);
225 	p = proctab(SLOT(c->qid));
226 	if(p->pid != PID(c->qid))
227 		error(Eprocdied);
228 
229 	if(strcmp(u->p->user, p->user) != 0 && strcmp(u->p->user, eve) != 0)
230 		error(Eperm);
231 
232 	p->procmode = d.mode&0777;
233 }
234 
235 void
236 procclose(Chan * c)
237 {
238 	USED(c);
239 }
240 
241 long
242 procread(Chan *c, void *va, long n, ulong offset)
243 {
244 	Proc *p;
245 	Page *pg;
246 	KMap *k;
247 	Segment *s;
248 	int i, j;
249 	long l;
250 	User *up;
251 	Segment *sg;
252 	Waitq *wq;
253 	char statbuf[NSEG*32];
254 	char *a = va, *b, *sps;
255 
256 	if(c->qid.path & CHDIR)
257 		return devdirread(c, a, n, 0, 0, procgen);
258 
259 	p = proctab(SLOT(c->qid));
260 	if(p->pid != PID(c->qid))
261 		error(Eprocdied);
262 
263 	switch(QID(c->qid)){
264 	case Qmem:
265 		/* ugly math: USERADDR+BY2PG may be == 0 */
266 		if(offset >= USERADDR && offset <= USERADDR+BY2PG-1) {
267 			if(offset+n >= USERADDR+BY2PG-1)
268 				n = USERADDR+BY2PG - offset;
269 			pg = p->upage;
270 			if(pg==0 || p->pid!=PID(c->qid))
271 				error(Eprocdied);
272 			k = kmap(pg);
273 			b = (char*)VA(k);
274 			memmove(a, b+(offset-USERADDR), n);
275 			kunmap(k);
276 			return n;
277 		}
278 
279 		if(offset >= KZERO) {
280 			/* Protect crypt key memory */
281 			if(offset < palloc.cmemtop && offset+n > palloc.cmembase)
282 				error(Eperm);
283 
284 			/* validate physical kernel addresses */
285 			if(offset < (ulong)end) {
286 				if(offset+n > (ulong)end)
287 					n = (ulong)end - offset;
288 				memmove(a, (char*)offset, n);
289 				return n;
290 			}
291 			if(offset >= conf.base0 && offset < conf.npage0){
292 				if(offset+n > conf.npage0)
293 					n = conf.npage0 - offset;
294 				memmove(a, (char*)offset, n);
295 				return n;
296 			}
297 			if(offset >= conf.base1 && offset < conf.npage1){
298 				if(offset+n > conf.npage1)
299 					n = conf.npage1 - offset;
300 				memmove(a, (char*)offset, n);
301 				return n;
302 			}
303 		}
304 
305 		return procctlmemio(p, offset, n, va, 1);
306 
307 	case Qnote:
308 		qlock(&p->debug);
309 		if(waserror()){
310 			qunlock(&p->debug);
311 			nexterror();
312 		}
313 		if(p->pid != PID(c->qid))
314 			error(Eprocdied);
315 		k = kmap(p->upage);
316 		up = (User*)VA(k);
317 		if(up->p != p){
318 			kunmap(k);
319 			pprint("note read u/p mismatch");
320 			error(Egreg);
321 		}
322 		if(n < ERRLEN)
323 			error(Etoosmall);
324 		if(up->nnote == 0)
325 			n = 0;
326 		else{
327 			memmove(va, up->note[0].msg, ERRLEN);
328 			up->nnote--;
329 			memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
330 			n = ERRLEN;
331 		}
332 		if(up->nnote == 0)
333 			p->notepending = 0;
334 		kunmap(k);
335 		poperror();
336 		qunlock(&p->debug);
337 		return n;
338 
339 	case Qproc:
340 		if(offset >= sizeof(Proc))
341 			return 0;
342 		if(offset+n > sizeof(Proc))
343 			n = sizeof(Proc) - offset;
344 		memmove(a, ((char*)p)+offset, n);
345 		return n;
346 
347 	case Qstatus:
348 		if(offset >= STATSIZE)
349 			return 0;
350 		if(offset+n > STATSIZE)
351 			n = STATSIZE - offset;
352 
353 		sps = p->psstate;
354 		if(sps == 0)
355 			sps = statename[p->state];
356 		memset(statbuf, ' ', sizeof statbuf);
357 		memmove(statbuf+0*NAMELEN, p->text, strlen(p->text));
358 		memmove(statbuf+1*NAMELEN, p->user, strlen(p->user));
359 		memmove(statbuf+2*NAMELEN, sps, strlen(sps));
360 		j = 2*NAMELEN + 12;
361 
362 		for(i = 0; i < 6; i++) {
363 			l = p->time[i];
364 			if(i == TReal)
365 				l = MACHP(0)->ticks - l;
366 			l = TK2MS(l);
367 			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
368 		}
369 		/* ignore stack, which is mostly non-existent */
370 		l = 0;
371 		for(i=1; i<NSEG; i++){
372 			s = p->seg[i];
373 			if(s)
374 				l += s->top - s->base;
375 		}
376 		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
377 		memmove(a, statbuf+offset, n);
378 		return n;
379 
380 	case Qsegment:
381 		j = 0;
382 		for(i = 0; i < NSEG; i++)
383 			if(sg = p->seg[i])
384 				j += sprint(&statbuf[j], "%-6s %c %.8lux %.8lux %4d\n",
385 				sname[sg->type&SG_TYPE], sg->type&SG_RONLY ? 'R' : ' ',
386 				sg->base, sg->top, sg->ref);
387 		if(offset >= j)
388 			return 0;
389 		if(offset+n > j)
390 			n = j-offset;
391 		if(n == 0 && offset == 0)
392 			exhausted("segments");
393 		memmove(a, &statbuf[offset], n);
394 		return n;
395 
396 	case Qwait:
397 		if(n < sizeof(Waitmsg))
398 			error(Etoosmall);
399 
400 		if(!canqlock(&p->qwaitr))
401 			error(Einuse);
402 
403 		if(waserror()) {
404 			qunlock(&p->qwaitr);
405 			nexterror();
406 		}
407 
408 		lock(&p->exl);
409 		if(u->p == p && p->nchild == 0 && p->waitq == 0) {
410 			unlock(&p->exl);
411 			error(Enochild);
412 		}
413 		while(p->waitq == 0) {
414 			unlock(&p->exl);
415 			sleep(&p->waitr, haswaitq, p);
416 			lock(&p->exl);
417 		}
418 		wq = p->waitq;
419 		p->waitq = wq->next;
420 		p->nwait--;
421 		unlock(&p->exl);
422 
423 		qunlock(&p->qwaitr);
424 		poperror();
425 		memmove(a, &wq->w, sizeof(Waitmsg));
426 		free(wq);
427 		return sizeof(Waitmsg);
428 	case Qnoteid:
429 		return readnum(offset, va, n, p->noteid, NUMSIZE);
430 	}
431 	error(Egreg);
432 	return 0;		/* not reached */
433 }
434 
435 
436 long
437 procwrite(Chan *c, void *va, long n, ulong offset)
438 {
439 	int id;
440 	User *up;
441 	KMap *k;
442 	Ureg *ur;
443 	User *pxu;
444 	Page *pg;
445 	ulong hi;
446 	char *a, *b;
447 	char buf[ERRLEN];
448 	Proc *p, *t, *et;
449 
450 	if(c->qid.path & CHDIR)
451 		error(Eisdir);
452 
453 	a = va;
454 	p = proctab(SLOT(c->qid));
455 
456 	/* Use the remembered noteid in the channel
457 	 * rather than the process pgrpid
458 	 */
459 	if(QID(c->qid) == Qnotepg) {
460 		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
461 		return n;
462 	}
463 
464 	qlock(&p->debug);
465 	if(waserror()){
466 		qunlock(&p->debug);
467 		nexterror();
468 	}
469 	if(p->pid != PID(c->qid))
470 		error(Eprocdied);
471 
472 	switch(QID(c->qid)){
473 	case Qmem:
474 		if(p->state != Stopped)
475 			error(Ebadctl);
476 
477 		if(offset >= USERADDR && offset <= USERADDR+BY2PG-1) {
478 			pg = p->upage;
479 			if(pg==0 || p->pid!=PID(c->qid))
480 				error(Eprocdied);
481 			k = kmap(pg);
482 			b = (char*)VA(k);
483 			pxu = (User*)b;
484 			hi = offset+n;
485 			/* Check for floating point registers */
486 			if(offset >= (ulong)&u->fpsave &&
487 			   hi <= (ulong)&u->fpsave+sizeof(FPsave)){
488 				memmove(b+(offset-USERADDR), a, n);
489 				break;
490 			}
491 			/* Check user register set for process at kernel entry */
492 			ur = pxu->dbgreg;
493 			if(offset < (ulong)ur || hi > (ulong)ur+sizeof(Ureg)) {
494 				kunmap(k);
495 				error(Ebadarg);
496 			}
497 			ur = (Ureg*)(b+((ulong)ur-USERADDR));
498 			setregisters(ur, b+(offset-USERADDR), a, n);
499 			kunmap(k);
500 		}
501 		else	/* Try user memory segments */
502 			n = procctlmemio(p, offset, n, va, 0);
503 		break;
504 
505 	case Qctl:
506 		procctlreq(p, va, n);
507 		break;
508 
509 	case Qnote:
510 		if(p->kp)
511 			error(Eperm);
512 		k = kmap(p->upage);
513 		up = (User*)VA(k);
514 		if(up->p != p){
515 			kunmap(k);
516 			pprint("note write u/p mismatch");
517 			error(Egreg);
518 		}
519 		kunmap(k);
520 		if(n >= ERRLEN-1)
521 			error(Etoobig);
522 		memmove(buf, va, n);
523 		buf[n] = 0;
524 		if(!postnote(p, 0, buf, NUser))
525 			error("note not posted");
526 		break;
527 	case Qnoteid:
528 		id = atoi(a);
529 		if(id == p->pid) {
530 			p->noteid = id;
531 			break;
532 		}
533 		t = proctab(0);
534 		for(et = t+conf.nproc; t < et; t++) {
535 			if(id == t->noteid) {
536 				if(strcmp(p->user, t->user) != 0)
537 					error(Eperm);
538 				p->noteid = id;
539 				break;
540 			}
541 		}
542 		if(p->noteid != id)
543 			error(Ebadarg);
544 		break;
545 	default:
546 		pprint("unknown qid in procwrite\n");
547 		error(Egreg);
548 	}
549 	poperror();
550 	qunlock(&p->debug);
551 	return n;
552 }
553 
554 Chan *
555 proctext(Chan *c, Proc *p)
556 {
557 	Chan *tc;
558 	Image *i;
559 	Segment *s;
560 
561 	s = p->seg[TSEG];
562 	if(s == 0)
563 		error(Enonexist);
564 	if(p->state==Dead)
565 		error(Eprocdied);
566 
567 	lock(s);
568 	i = s->image;
569 	if(i == 0) {
570 		unlock(s);
571 		error(Eprocdied);
572 	}
573 	unlock(s);
574 
575 	lock(i);
576 	if(waserror()) {
577 		unlock(i);
578 		nexterror();
579 	}
580 
581 	tc = i->c;
582 	if(tc == 0)
583 		error(Eprocdied);
584 
585 	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
586 		close(tc);
587 		error(Eprocdied);
588 	}
589 
590 	if(p->pid != PID(c->qid))
591 		error(Eprocdied);
592 
593 	unlock(i);
594 	poperror();
595 
596 	return tc;
597 }
598 
599 void
600 procstopwait(Proc *p, int ctl)
601 {
602 	int pid;
603 
604 	if(p->pdbg)
605 		error(Einuse);
606 	if(procstopped(p))
607 		return;
608 
609 	if(ctl != 0)
610 		p->procctl = ctl;
611 	p->pdbg = u->p;
612 	pid = p->pid;
613 	qunlock(&p->debug);
614 	u->p->psstate = "Stopwait";
615 	if(waserror()) {
616 		p->pdbg = 0;
617 		qlock(&p->debug);
618 		nexterror();
619 	}
620 	sleep(&u->p->sleep, procstopped, p);
621 	poperror();
622 	qlock(&p->debug);
623 	if(p->pid != pid)
624 		error(Eprocdied);
625 }
626 
627 void
628 procctlreq(Proc *p, char *va, int n)
629 {
630 	int i;
631 	char buf[NAMELEN+1];
632 
633 	if(n > NAMELEN)
634 		n = NAMELEN;
635 	strncpy(buf, va, n);
636 	buf[NAMELEN] = '\0';
637 
638 	if(strncmp(buf, "stop", 4) == 0)
639 		procstopwait(p, Proc_stopme);
640 	else if(strncmp(buf, "kill", 4) == 0) {
641 		switch(p->state) {
642 		case Broken:
643 			unbreak(p);
644 			break;
645 		case Stopped:
646 			postnote(p, 0, "sys: killed", NExit);
647 			p->procctl = Proc_exitme;
648 			ready(p);
649 			break;
650 		default:
651 			postnote(p, 0, "sys: killed", NExit);
652 			p->procctl = Proc_exitme;
653 		}
654 	}
655 	else if(strncmp(buf, "hang", 4) == 0)
656 		p->hang = 1;
657 	else if(strncmp(buf, "nohang", 6) == 0)
658 		p->hang = 0;
659 	else if(strncmp(buf, "waitstop", 8) == 0)
660 		procstopwait(p, 0);
661 	else if(strncmp(buf, "startstop", 9) == 0) {
662 		if(p->state != Stopped)
663 			error(Ebadctl);
664 		p->procctl = Proc_traceme;
665 		ready(p);
666 		procstopwait(p, Proc_traceme);
667 	}
668 	else if(strncmp(buf, "start", 5) == 0) {
669 		if(p->state != Stopped)
670 			error(Ebadctl);
671 		ready(p);
672 	}
673 	else if(strncmp(buf, "pri", 3) == 0){
674 		if(n < 4)
675 			error(Ebadctl);
676 		i = atoi(buf+4);
677 		if(i < 0)
678 			i = 0;
679 		if(i >= Nrq)
680 			i = Nrq - 1;
681 		if(i < p->basepri && !iseve())
682 			error(Eperm);
683 		p->basepri = i;
684 	}
685 	else
686 		error(Ebadctl);
687 }
688 
689 int
690 procstopped(void *a)
691 {
692 	Proc *p = a;
693 	return p->state == Stopped;
694 }
695 
696 int
697 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
698 {
699 	KMap *k;
700 	Pte *pte;
701 	Page *pg;
702 	Segment *s;
703 	ulong soff, l;
704 	char *a = va, *b;
705 
706 	for(;;) {
707 		s = seg(p, offset, 1);
708 		if(s == 0)
709 			error(Ebadarg);
710 
711 		if(offset+n >= s->top)
712 			n = s->top-offset;
713 
714 		if(read == 0 && (s->type&SG_TYPE) == SG_TEXT)
715 			s = txt2data(p, s);
716 
717 		s->steal++;
718 		soff = offset-s->base;
719 		if(waserror()) {
720 			s->steal--;
721 			nexterror();
722 		}
723 		if(fixfault(s, offset, read, 0) == 0)
724 			break;
725 		poperror();
726 		s->steal--;
727 	}
728 	poperror();
729 	pte = s->map[soff/PTEMAPMEM];
730 	if(pte == 0)
731 		panic("procctlmemio");
732 	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
733 	if(pagedout(pg))
734 		panic("procctlmemio1");
735 
736 	l = BY2PG - (offset&(BY2PG-1));
737 	if(n > l)
738 		n = l;
739 
740 	k = kmap(pg);
741 	b = (char*)VA(k);
742 	if(read == 1)
743 		memmove(a, b+(offset&(BY2PG-1)), n);
744 	else
745 		memmove(b+(offset&(BY2PG-1)), a, n);
746 
747 	kunmap(k);
748 
749 	s->steal--;
750 	qunlock(&s->lk);
751 
752 	if(read == 0)
753 		p->newtlb = 1;
754 
755 	return n;
756 }
757 
758 Segment*
759 txt2data(Proc *p, Segment *s)
760 {
761 	int i;
762 	Segment *ps;
763 
764 	ps = newseg(SG_DATA, s->base, s->size);
765 	ps->image = s->image;
766 	incref(ps->image);
767 	ps->fstart = s->fstart;
768 	ps->flen = s->flen;
769 	ps->flushme = 1;
770 
771 	for(i = 0; i < NSEG; i++)
772 		if(p->seg[i] == s)
773 			break;
774 	if(p->seg[i] != s)
775 		panic("segment gone");
776 
777 	qunlock(&s->lk);
778 	putseg(s);
779 	qlock(&ps->lk);
780 	p->seg[i] = ps;
781 
782 	return ps;
783 }
784 
785 Segment*
786 data2txt(Segment *s)
787 {
788 	Segment *ps;
789 
790 	ps = newseg(SG_TEXT, s->base, s->size);
791 	ps->image = s->image;
792 	incref(ps->image);
793 	ps->fstart = s->fstart;
794 	ps->flen = s->flen;
795 	ps->flushme = 1;
796 
797 	return ps;
798 }
799