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