|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.