devcons.c (23243B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 8 #include "authsrv.h" 9 10 void (*consdebug)(void) = nil; 11 void (*screenputs)(char*, int) = nil; 12 13 Queue* kbdq; /* unprocessed console input */ 14 Queue* lineq; /* processed console input */ 15 Queue* kprintoq; /* console output, for /dev/kprint */ 16 ulong kprintinuse; /* test and set whether /dev/kprint is open */ 17 int iprintscreenputs = 1; 18 19 int panicking; 20 21 static struct 22 { 23 QLock lk; 24 25 int raw; /* true if we shouldn't process input */ 26 Ref ctl; /* number of opens to the control file */ 27 int x; /* index into line */ 28 char line[1024]; /* current input line */ 29 30 int count; 31 int ctlpoff; 32 33 /* a place to save up characters at interrupt time before dumping them in the queue */ 34 Lock lockputc; 35 char istage[1024]; 36 char *iw; 37 char *ir; 38 char *ie; 39 } kbd = { 40 .iw = kbd.istage, 41 .ir = kbd.istage, 42 .ie = kbd.istage + sizeof(kbd.istage), 43 }; 44 45 char *sysname; 46 vlong fasthz = 1000000000ULL; // Plan 9 VX = nsecs 47 48 static void seedrand(void); 49 static int readtime(ulong, char*, int); 50 static int readbintime(char*, int); 51 static int writetime(char*, int); 52 static int writebintime(char*, int); 53 54 enum 55 { 56 CMhalt, 57 CMreboot, 58 CMpanic, 59 }; 60 61 Cmdtab rebootmsg[] = 62 { 63 CMhalt, "halt", 1, 64 CMreboot, "reboot", 0, 65 CMpanic, "panic", 0, 66 }; 67 68 void 69 printinit(void) 70 { 71 lineq = qopen(2*1024, 0, nil, nil); 72 if(lineq == nil) 73 panic("printinit"); 74 qnoblock(lineq, 1); 75 } 76 77 #if 0 // Plan 9 VX 78 int 79 consactive(void) 80 { 81 if(serialoq) 82 return qlen(serialoq) > 0; 83 return 0; 84 } 85 #endif 86 87 #if 0 // Plan 9 VX 88 void 89 prflush(void) 90 { 91 ulong now; 92 93 now = m->ticks; 94 while(consactive()) 95 if(m->ticks - now >= HZ) 96 break; 97 } 98 #endif 99 100 /* 101 * Log console output so it can be retrieved via /dev/kmesg. 102 * This is good for catching boot-time messages after the fact. 103 */ 104 struct { 105 Lock lk; 106 char buf[16384]; 107 uint n; 108 } kmesg; 109 110 static void 111 kmesgputs(char *str, int n) 112 { 113 uint nn, d; 114 115 ilock(&kmesg.lk); 116 /* take the tail of huge writes */ 117 if(n > sizeof kmesg.buf){ 118 d = n - sizeof kmesg.buf; 119 str += d; 120 n -= d; 121 } 122 123 /* slide the buffer down to make room */ 124 nn = kmesg.n; 125 if(nn + n >= sizeof kmesg.buf){ 126 d = nn + n - sizeof kmesg.buf; 127 if(d) 128 memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d); 129 nn -= d; 130 } 131 132 /* copy the data in */ 133 memmove(kmesg.buf+nn, str, n); 134 nn += n; 135 kmesg.n = nn; 136 iunlock(&kmesg.lk); 137 } 138 139 /* 140 * Print a string on the console. Convert \n to \r\n for serial 141 * line consoles. Locking of the queues is left up to the screen 142 * or uart code. Multi-line messages to serial consoles may get 143 * interspersed with other messages. 144 */ 145 static void 146 putstrn0(char *str, int n, int usewrite) 147 { 148 149 if(!islo()) 150 usewrite = 0; 151 152 /* 153 * how many different output devices do we need? 154 */ 155 kmesgputs(str, n); 156 157 /* 158 * if someone is reading /dev/kprint, 159 * put the message there. 160 * if not and there's an attached bit mapped display, 161 * put the message there. 162 * 163 * if there's a serial line being used as a console, 164 * put the message there. 165 */ 166 if(kprintoq != nil && !qisclosed(kprintoq)){ 167 if(usewrite) 168 qwrite(kprintoq, str, n); 169 else 170 qiwrite(kprintoq, str, n); 171 }else if(screenputs != nil) 172 screenputs(str, n); 173 174 uartputs(str, n); 175 #if 0 // Plan 9 VX 176 if(serialoq == nil){ 177 uartputs(str, n); 178 return; 179 } 180 181 while(n > 0) { 182 t = memchr(str, '\n', n); 183 if(t && !kbd.raw) { 184 m = t-str; 185 if(usewrite){ 186 qwrite(serialoq, str, m); 187 qwrite(serialoq, "\r\n", 2); 188 } else { 189 qiwrite(serialoq, str, m); 190 qiwrite(serialoq, "\r\n", 2); 191 } 192 n -= m+1; 193 str = t+1; 194 } else { 195 if(usewrite) 196 qwrite(serialoq, str, n); 197 else 198 qiwrite(serialoq, str, n); 199 break; 200 } 201 } 202 #endif 203 } 204 205 void 206 putstrn(char *str, int n) 207 { 208 putstrn0(str, n, 0); 209 } 210 211 int noprint; 212 213 int 214 print(char *fmt, ...) 215 { 216 int n; 217 va_list arg; 218 char buf[PRINTSIZE]; 219 220 if(noprint) 221 return -1; 222 223 va_start(arg, fmt); 224 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; 225 va_end(arg); 226 putstrn(buf, n); 227 228 return n; 229 } 230 231 /* 232 * Want to interlock iprints to avoid interlaced output on 233 * multiprocessor, but don't want to deadlock if one processor 234 * dies during print and another has something important to say. 235 * Make a good faith effort. 236 */ 237 #if 0 // Plan 9 VX 238 static Lock iprintlock; 239 static int 240 iprintcanlock(Lock *l) 241 { 242 int i; 243 244 for(i=0; i<1000; i++){ 245 if(canlock(l)) 246 return 1; 247 if(l->m == MACHP(m->machno)) 248 return 0; 249 microdelay(100); 250 } 251 return 0; 252 } 253 254 int 255 iprint(char *fmt, ...) 256 { 257 int n, s, locked; 258 va_list arg; 259 char buf[PRINTSIZE]; 260 261 s = splhi(); 262 va_start(arg, fmt); 263 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; 264 va_end(arg); 265 locked = iprintcanlock(&iprintlock); 266 if(screenputs != nil && iprintscreenputs) 267 screenputs(buf, n); 268 uartputs(buf, n); 269 if(locked) 270 unlock(&iprintlock); 271 splx(s); 272 273 return n; 274 } 275 276 void 277 panic(char *fmt, ...) 278 { 279 int n, s; 280 va_list arg; 281 char buf[PRINTSIZE]; 282 283 kprintoq = nil; /* don't try to write to /dev/kprint */ 284 285 if(panicking) 286 for(;;); 287 panicking = 1; 288 289 s = splhi(); 290 strcpy(buf, "panic: "); 291 va_start(arg, fmt); 292 n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; 293 va_end(arg); 294 iprint("%s\n", buf); 295 if(consdebug) 296 (*consdebug)(); 297 splx(s); 298 prflush(); 299 buf[n] = '\n'; 300 putstrn(buf, n+1); 301 dumpstack(); 302 303 restoretty(); exit(1); 304 } 305 306 /* libmp at least contains a few calls to sysfatal; simulate with panic */ 307 void 308 sysfatal(char *fmt, ...) 309 { 310 char err[256]; 311 va_list arg; 312 313 va_start(arg, fmt); 314 vseprint(err, err + sizeof err, fmt, arg); 315 va_end(arg); 316 panic("sysfatal: %s", err); 317 } 318 319 void 320 _assert(char *fmt) 321 { 322 panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt); 323 } 324 #endif 325 326 int 327 pprint(char *fmt, ...) 328 { 329 int n; 330 Chan *c; 331 va_list arg; 332 char buf[2*PRINTSIZE]; 333 334 if(up == nil || up->fgrp == nil) 335 return 0; 336 337 c = up->fgrp->fd[2]; 338 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) 339 return 0; 340 n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid); 341 va_start(arg, fmt); 342 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; 343 va_end(arg); 344 345 if(waserror()) 346 return 0; 347 devtab[c->type]->write(c, buf, n, c->offset); 348 poperror(); 349 350 lock(&c->ref.lk); 351 c->offset += n; 352 unlock(&c->ref.lk); 353 354 return n; 355 } 356 357 static void 358 echoscreen(char *buf, int n) 359 { 360 char *e, *p; 361 char ebuf[128]; 362 int x; 363 364 p = ebuf; 365 e = ebuf + sizeof(ebuf) - 4; 366 while(n-- > 0){ 367 if(p >= e){ 368 screenputs(ebuf, p - ebuf); 369 p = ebuf; 370 } 371 x = *buf++; 372 if(x == 0x15){ 373 *p++ = '^'; 374 *p++ = 'U'; 375 *p++ = '\n'; 376 } else 377 *p++ = x; 378 } 379 if(p != ebuf) 380 screenputs(ebuf, p - ebuf); 381 } 382 383 #if 0 // Plan 9 VX 384 static void 385 echoserialoq(char *buf, int n) 386 { 387 char *e, *p; 388 char ebuf[128]; 389 int x; 390 391 p = ebuf; 392 e = ebuf + sizeof(ebuf) - 4; 393 while(n-- > 0){ 394 if(p >= e){ 395 qiwrite(serialoq, ebuf, p - ebuf); 396 p = ebuf; 397 } 398 x = *buf++; 399 if(x == '\n'){ 400 *p++ = '\r'; 401 *p++ = '\n'; 402 } else if(x == 0x15){ 403 *p++ = '^'; 404 *p++ = 'U'; 405 *p++ = '\n'; 406 } else 407 *p++ = x; 408 } 409 if(p != ebuf) 410 qiwrite(serialoq, ebuf, p - ebuf); 411 } 412 #endif 413 414 void 415 echo(char *buf, int n) 416 { 417 static int ctrlt; 418 int x; 419 char *e, *p; 420 421 if(n == 0) 422 return; 423 424 e = buf+n; 425 for(p = buf; p < e; p++){ 426 switch(*p){ 427 case 0x10: /* ^P */ 428 if(cpuserver && !kbd.ctlpoff){ 429 active.exiting = 1; 430 return; 431 } 432 break; 433 case 0x14: /* ^T */ 434 ctrlt++; 435 if(ctrlt > 2) 436 ctrlt = 2; 437 continue; 438 } 439 440 if(ctrlt != 2) 441 continue; 442 443 /* ^T escapes */ 444 ctrlt = 0; 445 switch(*p){ 446 case 'S': 447 x = splhi(); 448 dumpstack(); 449 procdump(); 450 splx(x); 451 return; 452 case 's': 453 dumpstack(); 454 return; 455 case 'x': 456 xsummary(); 457 ixsummary(); 458 mallocsummary(); 459 // memorysummary(); 460 pagersummary(); 461 return; 462 case 'd': 463 if(consdebug == nil) 464 consdebug = rdb; 465 else 466 consdebug = nil; 467 print("consdebug now %#p\n", consdebug); 468 return; 469 case 'D': 470 if(consdebug == nil) 471 consdebug = rdb; 472 consdebug(); 473 return; 474 case 'p': 475 x = spllo(); 476 procdump(); 477 splx(x); 478 return; 479 case 'q': 480 scheddump(); 481 return; 482 case 'k': 483 killbig("^t ^t k"); 484 return; 485 case 'r': 486 restoretty(); exit(0); 487 return; 488 } 489 } 490 491 qproduce(kbdq, buf, n); 492 if(kbd.raw) 493 return; 494 kmesgputs(buf, n); 495 if(screenputs != nil) 496 echoscreen(buf, n); 497 uartecho(buf, n); // Plan 9 VX 498 } 499 500 /* 501 * Called by a uart interrupt for console input. 502 * 503 * turn '\r' into '\n' before putting it into the queue. 504 */ 505 int 506 kbdcr2nl(Queue *q, int ch) 507 { 508 char *next; 509 510 ilock(&kbd.lockputc); /* just a mutex */ 511 if(ch == '\r' && !kbd.raw) 512 ch = '\n'; 513 next = kbd.iw+1; 514 if(next >= kbd.ie) 515 next = kbd.istage; 516 if(next != kbd.ir){ 517 *kbd.iw = ch; 518 kbd.iw = next; 519 } 520 iunlock(&kbd.lockputc); 521 return 0; 522 } 523 524 /* 525 * Put character, possibly a rune, into read queue at interrupt time. 526 * Called at interrupt time to process a character. 527 */ 528 int 529 kbdputc(Queue *q, int ch) 530 { 531 int n; 532 Rune r; 533 char buf[UTFmax]; 534 535 r = ch; 536 n = runetochar(buf, &r); 537 echo(buf, n); 538 return 0; 539 540 #if 0 // Plan 9 VX 541 int i, n; 542 char buf[3]; 543 Rune r; 544 char *next; 545 546 if(kbd.ir == nil) 547 return 0; /* in case we're not inited yet */ 548 549 ilock(&kbd.lockputc); /* just a mutex */ 550 r = ch; 551 n = runetochar(buf, &r); 552 for(i = 0; i < n; i++){ 553 next = kbd.iw+1; 554 if(next >= kbd.ie) 555 next = kbd.istage; 556 if(next == kbd.ir) 557 break; 558 *kbd.iw = buf[i]; 559 kbd.iw = next; 560 } 561 iunlock(&kbd.lockputc); 562 return 0; 563 #endif 564 } 565 566 /* 567 * we save up input characters till clock time to reduce 568 * per character interrupt overhead. 569 */ 570 #if 0 // Plan 9 VX 571 static void 572 kbdputcclock(void) 573 { 574 char *iw; 575 576 /* this amortizes cost of qproduce */ 577 if(kbd.iw != kbd.ir){ 578 iw = kbd.iw; 579 if(iw < kbd.ir){ 580 echo(kbd.ir, kbd.ie-kbd.ir); 581 kbd.ir = kbd.istage; 582 } 583 if(kbd.ir != iw){ 584 echo(kbd.ir, iw-kbd.ir); 585 kbd.ir = iw; 586 } 587 } 588 } 589 #endif 590 591 enum{ 592 Qdir, 593 Qbintime, 594 Qcons, 595 Qconsctl, 596 Qcputime, 597 Qdrivers, 598 Qkmesg, 599 Qkprint, 600 Qhostdomain, 601 Qhostowner, 602 Qnull, 603 Qosversion, 604 Qpgrpid, 605 Qpid, 606 Qppid, 607 Qrandom, 608 Qreboot, 609 Qswap, 610 Qsysname, 611 Qsysstat, 612 Qtime, 613 Quser, 614 Qzero, 615 }; 616 617 enum 618 { 619 VLNUMSIZE= 22, 620 }; 621 622 static Dirtab consdir[]={ 623 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 624 "bintime", {Qbintime}, 24, 0664, 625 "cons", {Qcons}, 0, 0660, 626 "consctl", {Qconsctl}, 0, 0220, 627 "cputime", {Qcputime}, 6*NUMSIZE, 0444, 628 "drivers", {Qdrivers}, 0, 0444, 629 "hostdomain", {Qhostdomain}, DOMLEN, 0664, 630 "hostowner", {Qhostowner}, 0, 0664, 631 "kmesg", {Qkmesg}, 0, 0440, 632 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440, 633 "null", {Qnull}, 0, 0666, 634 "osversion", {Qosversion}, 0, 0444, 635 "pgrpid", {Qpgrpid}, NUMSIZE, 0444, 636 "pid", {Qpid}, NUMSIZE, 0444, 637 "ppid", {Qppid}, NUMSIZE, 0444, 638 "random", {Qrandom}, 0, 0444, 639 "reboot", {Qreboot}, 0, 0664, 640 "swap", {Qswap}, 0, 0664, 641 "sysname", {Qsysname}, 0, 0664, 642 "sysstat", {Qsysstat}, 0, 0666, 643 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664, 644 "user", {Quser}, 0, 0666, 645 "zero", {Qzero}, 0, 0444, 646 }; 647 648 int 649 readnum(ulong off, char *buf, ulong n, ulong val, int size) 650 { 651 char tmp[64]; 652 653 snprint(tmp, sizeof(tmp), "%*lud", size-1, val); 654 tmp[size-1] = ' '; 655 if(off >= size) 656 return 0; 657 if(off+n > size) 658 n = size-off; 659 memmove(buf, tmp+off, n); 660 return n; 661 } 662 663 int 664 readstr(ulong off, char *buf, ulong n, char *str) 665 { 666 int size; 667 668 size = strlen(str); 669 if(off >= size) 670 return 0; 671 if(off+n > size) 672 n = size-off; 673 memmove(buf, str+off, n); 674 return n; 675 } 676 677 static void 678 consinit(void) 679 { 680 todinit(); 681 randominit(); 682 #if 0 // Plan 9 VX 683 /* 684 * at 115200 baud, the 1024 char buffer takes 56 ms to process, 685 * processing it every 22 ms should be fine 686 */ 687 addclock0link(kbdputcclock, 22); 688 #endif 689 } 690 691 static Chan* 692 consattach(char *spec) 693 { 694 return devattach('c', spec); 695 } 696 697 static Walkqid* 698 conswalk(Chan *c, Chan *nc, char **name, int nname) 699 { 700 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen); 701 } 702 703 static int 704 consstat(Chan *c, uchar *dp, int n) 705 { 706 return devstat(c, dp, n, consdir, nelem(consdir), devgen); 707 } 708 709 static Chan* 710 consopen(Chan *c, int omode) 711 { 712 c->aux = nil; 713 c = devopen(c, omode, consdir, nelem(consdir), devgen); 714 switch((ulong)c->qid.path){ 715 case Qconsctl: 716 incref(&kbd.ctl); 717 break; 718 719 case Qkprint: 720 if(tas(&kprintinuse) != 0){ 721 c->flag &= ~COPEN; 722 error(Einuse); 723 } 724 if(kprintoq == nil){ 725 kprintoq = qopen(8*1024, Qcoalesce, 0, 0); 726 if(kprintoq == nil){ 727 c->flag &= ~COPEN; 728 error(Enomem); 729 } 730 qnoblock(kprintoq, 1); 731 }else 732 qreopen(kprintoq); 733 c->iounit = qiomaxatomic; 734 break; 735 } 736 return c; 737 } 738 739 static void 740 consclose(Chan *c) 741 { 742 switch((ulong)c->qid.path){ 743 /* last close of control file turns off raw */ 744 case Qconsctl: 745 if(c->flag&COPEN){ 746 if(decref(&kbd.ctl) == 0) 747 kbd.raw = 0; 748 } 749 break; 750 751 /* close of kprint allows other opens */ 752 case Qkprint: 753 if(c->flag & COPEN){ 754 kprintinuse = 0; 755 qhangup(kprintoq, nil); 756 } 757 break; 758 } 759 } 760 761 static long 762 consread(Chan *c, void *buf, long n, vlong off) 763 { 764 ulong l; 765 Mach *mp; 766 char *b, *bp, ch; 767 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */ 768 int i, k, id, send; 769 vlong offset = off; 770 771 if(n <= 0) 772 return n; 773 774 switch((ulong)c->qid.path){ 775 case Qdir: 776 return devdirread(c, buf, n, consdir, nelem(consdir), devgen); 777 778 case Qcons: 779 qlock(&kbd.lk); 780 if(waserror()) { 781 qunlock(&kbd.lk); 782 nexterror(); 783 } 784 while(!qcanread(lineq)){ 785 if(qread(kbdq, &ch, 1) == 0) 786 continue; 787 send = 0; 788 if(ch == 0){ 789 /* flush output on rawoff -> rawon */ 790 if(kbd.x > 0) 791 send = !qcanread(kbdq); 792 }else if(kbd.raw){ 793 kbd.line[kbd.x++] = ch; 794 send = !qcanread(kbdq); 795 }else{ 796 switch(ch){ 797 case '\b': 798 if(kbd.x > 0) 799 kbd.x--; 800 break; 801 case 0x15: /* ^U */ 802 kbd.x = 0; 803 break; 804 case '\n': 805 case 0x04: /* ^D */ 806 send = 1; 807 default: 808 if(ch != 0x04) 809 kbd.line[kbd.x++] = ch; 810 break; 811 } 812 } 813 if(send || kbd.x == sizeof kbd.line){ 814 qwrite(lineq, kbd.line, kbd.x); 815 kbd.x = 0; 816 } 817 } 818 n = qread(lineq, buf, n); 819 qunlock(&kbd.lk); 820 poperror(); 821 return n; 822 823 case Qcputime: 824 k = offset; 825 if(k >= 6*NUMSIZE) 826 return 0; 827 if(k+n > 6*NUMSIZE) 828 n = 6*NUMSIZE - k; 829 /* easiest to format in a separate buffer and copy out */ 830 for(i=0; i<6 && NUMSIZE*i<k+n; i++){ 831 l = up->time[i]; 832 if(i == TReal) 833 l = msec() - l; 834 l = TK2MS(l); 835 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 836 } 837 memmove(buf, tmp+k, n); 838 return n; 839 840 case Qkmesg: 841 /* 842 * This is unlocked to avoid tying up a process 843 * that's writing to the buffer. kmesg.n never 844 * gets smaller, so worst case the reader will 845 * see a slurred buffer. 846 */ 847 if(off >= kmesg.n) 848 n = 0; 849 else{ 850 if(off+n > kmesg.n) 851 n = kmesg.n - off; 852 memmove(buf, kmesg.buf+off, n); 853 } 854 return n; 855 856 case Qkprint: 857 return qread(kprintoq, buf, n); 858 859 case Qpgrpid: 860 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); 861 862 case Qpid: 863 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); 864 865 case Qppid: 866 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); 867 868 case Qtime: 869 return readtime((ulong)offset, buf, n); 870 871 case Qbintime: 872 return readbintime(buf, n); 873 874 case Qhostowner: 875 return readstr((ulong)offset, buf, n, eve); 876 877 case Qhostdomain: 878 return readstr((ulong)offset, buf, n, hostdomain); 879 880 case Quser: 881 return readstr((ulong)offset, buf, n, up->user); 882 883 case Qnull: 884 return 0; 885 886 case Qsysstat: 887 b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */ 888 bp = b; 889 for(id = 0; id < 32; id++) { 890 if(active.machs & (1<<id)) { 891 mp = MACHP(id); 892 readnum(0, bp, NUMSIZE, id, NUMSIZE); 893 bp += NUMSIZE; 894 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE); 895 bp += NUMSIZE; 896 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE); 897 bp += NUMSIZE; 898 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE); 899 bp += NUMSIZE; 900 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE); 901 bp += NUMSIZE; 902 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE); 903 bp += NUMSIZE; 904 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE); 905 bp += NUMSIZE; 906 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE); 907 bp += NUMSIZE; 908 readnum(0, bp, NUMSIZE, 909 (mp->perf.avg_inidle*100)/mp->perf.period, 910 NUMSIZE); 911 bp += NUMSIZE; 912 readnum(0, bp, NUMSIZE, 913 (mp->perf.avg_inintr*100)/mp->perf.period, 914 NUMSIZE); 915 bp += NUMSIZE; 916 *bp++ = '\n'; 917 } 918 } 919 if(waserror()){ 920 free(b); 921 nexterror(); 922 } 923 n = readstr((ulong)offset, buf, n, b); 924 free(b); 925 poperror(); 926 return n; 927 928 case Qswap: 929 tmp[0] = 0; 930 931 return readstr((ulong)offset, buf, n, tmp); 932 933 case Qsysname: 934 if(sysname == nil) 935 return 0; 936 return readstr((ulong)offset, buf, n, sysname); 937 938 case Qrandom: 939 return randomread(buf, n); 940 941 case Qdrivers: 942 b = malloc(READSTR); 943 if(b == nil) 944 error(Enomem); 945 n = 0; 946 for(i = 0; devtab[i] != nil; i++) 947 n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name); 948 if(waserror()){ 949 free(b); 950 nexterror(); 951 } 952 n = readstr((ulong)offset, buf, n, b); 953 free(b); 954 poperror(); 955 return n; 956 957 case Qzero: 958 memset(buf, 0, n); 959 return n; 960 961 case Qosversion: 962 snprint(tmp, sizeof tmp, "2000"); 963 n = readstr((ulong)offset, buf, n, tmp); 964 return n; 965 966 default: 967 print("consread %#llux\n", c->qid.path); 968 error(Egreg); 969 } 970 return -1; /* never reached */ 971 } 972 973 static long 974 conswrite(Chan *c, void *va, long n, vlong off) 975 { 976 char buf[256], ch; 977 long l, bp; 978 char *a; 979 Mach *mp; 980 int id, fd; 981 Chan *swc; 982 ulong offset; 983 Cmdbuf *cb; 984 Cmdtab *ct; 985 986 a = va; 987 offset = off; 988 989 switch((ulong)c->qid.path){ 990 case Qcons: 991 /* 992 * Can't page fault in putstrn, so copy the data locally. 993 */ 994 l = n; 995 while(l > 0){ 996 bp = l; 997 if(bp > sizeof buf) 998 bp = sizeof buf; 999 memmove(buf, a, bp); 1000 putstrn0(buf, bp, 1); 1001 a += bp; 1002 l -= bp; 1003 } 1004 break; 1005 1006 case Qconsctl: 1007 if(n >= sizeof(buf)) 1008 n = sizeof(buf)-1; 1009 strncpy(buf, a, n); 1010 buf[n] = 0; 1011 for(a = buf; a;){ 1012 if(strncmp(a, "rawon", 5) == 0){ 1013 kbd.raw = 1; 1014 /* clumsy hack - wake up reader */ 1015 ch = 0; 1016 qwrite(kbdq, &ch, 1); 1017 } else if(strncmp(a, "rawoff", 6) == 0){ 1018 kbd.raw = 0; 1019 } else if(strncmp(a, "ctlpon", 6) == 0){ 1020 kbd.ctlpoff = 0; 1021 } else if(strncmp(a, "ctlpoff", 7) == 0){ 1022 kbd.ctlpoff = 1; 1023 } 1024 if((a = strchr(a, ' '))) 1025 a++; 1026 } 1027 break; 1028 1029 case Qtime: 1030 if(!iseve()) 1031 error(Eperm); 1032 return writetime(a, n); 1033 1034 case Qbintime: 1035 if(!iseve()) 1036 error(Eperm); 1037 return writebintime(a, n); 1038 1039 case Qhostowner: 1040 return hostownerwrite(a, n); 1041 1042 case Qhostdomain: 1043 return hostdomainwrite(a, n); 1044 1045 case Quser: 1046 return userwrite(a, n); 1047 1048 case Qnull: 1049 break; 1050 1051 case Qreboot: 1052 if(!iseve()) 1053 error(Eperm); 1054 cb = parsecmd(a, n); 1055 1056 if(waserror()) { 1057 free(cb); 1058 nexterror(); 1059 } 1060 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg)); 1061 switch(ct->index) { 1062 case CMhalt: 1063 reboot(nil, 0, 0); 1064 break; 1065 case CMreboot: 1066 rebootcmd(cb->nf-1, cb->f+1); 1067 break; 1068 case CMpanic: 1069 *(ulong*)0=0; 1070 panic("/dev/reboot"); 1071 } 1072 poperror(); 1073 free(cb); 1074 break; 1075 1076 case Qsysstat: 1077 for(id = 0; id < 32; id++) { 1078 if(active.machs & (1<<id)) { 1079 mp = MACHP(id); 1080 mp->cs = 0; 1081 mp->intr = 0; 1082 mp->syscall = 0; 1083 mp->pfault = 0; 1084 mp->tlbfault = 0; 1085 mp->tlbpurge = 0; 1086 } 1087 } 1088 break; 1089 1090 case Qswap: 1091 if(n >= sizeof buf) 1092 error(Egreg); 1093 memmove(buf, va, n); /* so we can NUL-terminate */ 1094 buf[n] = 0; 1095 /* start a pager if not already started */ 1096 if(strncmp(buf, "start", 5) == 0){ 1097 kickpager(); 1098 break; 1099 } 1100 if(!iseve()) 1101 error(Eperm); 1102 if(buf[0]<'0' || '9'<buf[0]) 1103 error(Ebadarg); 1104 fd = strtoul(buf, 0, 0); 1105 swc = fdtochan(fd, -1, 1, 1); 1106 setswapchan(swc); 1107 break; 1108 1109 case Qsysname: 1110 if(offset != 0) 1111 error(Ebadarg); 1112 if(n <= 0 || n >= sizeof buf) 1113 error(Ebadarg); 1114 strncpy(buf, a, n); 1115 buf[n] = 0; 1116 if(buf[n-1] == '\n') 1117 buf[n-1] = 0; 1118 kstrdup(&sysname, buf); 1119 break; 1120 1121 default: 1122 print("conswrite: %#llux\n", c->qid.path); 1123 error(Egreg); 1124 } 1125 return n; 1126 } 1127 1128 Dev consdevtab = { 1129 'c', 1130 "cons", 1131 1132 devreset, 1133 consinit, 1134 devshutdown, 1135 consattach, 1136 conswalk, 1137 consstat, 1138 consopen, 1139 devcreate, 1140 consclose, 1141 consread, 1142 devbread, 1143 conswrite, 1144 devbwrite, 1145 devremove, 1146 devwstat, 1147 }; 1148 1149 static ulong randn; 1150 1151 static void 1152 seedrand(void) 1153 { 1154 if(!waserror()){ 1155 randomread((void*)&randn, sizeof(randn)); 1156 poperror(); 1157 } 1158 } 1159 1160 int 1161 nrand(int n) 1162 { 1163 if(randn == 0) 1164 seedrand(); 1165 randn = randn*1103515245 + 12345 + msec(); 1166 return (randn>>16) % n; 1167 } 1168 1169 int 1170 rand(void) 1171 { 1172 nrand(1); 1173 return randn; 1174 } 1175 1176 static uvlong uvorder = 0x0001020304050607ULL; 1177 1178 static uchar* 1179 le2vlong(vlong *to, uchar *f) 1180 { 1181 uchar *t, *o; 1182 int i; 1183 1184 t = (uchar*)to; 1185 o = (uchar*)&uvorder; 1186 for(i = 0; i < sizeof(vlong); i++) 1187 t[o[i]] = f[i]; 1188 return f+sizeof(vlong); 1189 } 1190 1191 static uchar* 1192 vlong2le(uchar *t, vlong from) 1193 { 1194 uchar *f, *o; 1195 int i; 1196 1197 f = (uchar*)&from; 1198 o = (uchar*)&uvorder; 1199 for(i = 0; i < sizeof(vlong); i++) 1200 t[i] = f[o[i]]; 1201 return t+sizeof(vlong); 1202 } 1203 1204 static long order = 0x00010203; 1205 1206 static uchar* 1207 le2long(long *to, uchar *f) 1208 { 1209 uchar *t, *o; 1210 int i; 1211 1212 t = (uchar*)to; 1213 o = (uchar*)ℴ 1214 for(i = 0; i < sizeof(long); i++) 1215 t[o[i]] = f[i]; 1216 return f+sizeof(long); 1217 } 1218 1219 /*static*/ uchar* 1220 long2le(uchar *t, long from) 1221 { 1222 uchar *f, *o; 1223 int i; 1224 1225 f = (uchar*)&from; 1226 o = (uchar*)ℴ 1227 for(i = 0; i < sizeof(long); i++) 1228 t[i] = f[o[i]]; 1229 return t+sizeof(long); 1230 } 1231 1232 char *Ebadtimectl = "bad time control"; 1233 1234 /* 1235 * like the old #c/time but with added info. Return 1236 * 1237 * secs nanosecs fastticks fasthz 1238 */ 1239 static int 1240 readtime(ulong off, char *buf, int n) 1241 { 1242 vlong nsec, ticks; 1243 long sec; 1244 char str[7*NUMSIZE]; 1245 1246 nsec = todget(&ticks); 1247 if(fasthz == 0LL) 1248 fastticks((uvlong*)&fasthz); 1249 sec = nsec/1000000000ULL; 1250 snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ", 1251 NUMSIZE-1, sec, 1252 VLNUMSIZE-1, nsec, 1253 VLNUMSIZE-1, ticks, 1254 VLNUMSIZE-1, fasthz); 1255 return readstr(off, buf, n, str); 1256 } 1257 1258 /* 1259 * set the time in seconds 1260 */ 1261 static int 1262 writetime(char *buf, int n) 1263 { 1264 char b[13]; 1265 long i; 1266 vlong now; 1267 1268 if(n >= sizeof(b)) 1269 error(Ebadtimectl); 1270 strncpy(b, buf, n); 1271 b[n] = 0; 1272 i = strtol(b, 0, 0); 1273 if(i <= 0) 1274 error(Ebadtimectl); 1275 now = i*1000000000LL; 1276 todset(now, 0, 0); 1277 return n; 1278 } 1279 1280 /* 1281 * read binary time info. all numbers are little endian. 1282 * ticks and nsec are syncronized. 1283 */ 1284 static int 1285 readbintime(char *buf, int n) 1286 { 1287 int i; 1288 vlong nsec, ticks; 1289 uchar *b = (uchar*)buf; 1290 1291 i = 0; 1292 if(fasthz == 0LL) 1293 fastticks((uvlong*)&fasthz); 1294 nsec = todget(&ticks); 1295 if(n >= 3*sizeof(uvlong)){ 1296 vlong2le(b+2*sizeof(uvlong), fasthz); 1297 i += sizeof(uvlong); 1298 } 1299 if(n >= 2*sizeof(uvlong)){ 1300 vlong2le(b+sizeof(uvlong), ticks); 1301 i += sizeof(uvlong); 1302 } 1303 if(n >= 8){ 1304 vlong2le(b, nsec); 1305 i += sizeof(vlong); 1306 } 1307 return i; 1308 } 1309 1310 /* 1311 * set any of the following 1312 * - time in nsec 1313 * - nsec trim applied over some seconds 1314 * - clock frequency 1315 */ 1316 static int 1317 writebintime(char *buf, int n) 1318 { 1319 uchar *p; 1320 vlong delta; 1321 long period; 1322 1323 n--; 1324 p = (uchar*)buf + 1; 1325 switch(*buf){ 1326 case 'n': 1327 if(n < sizeof(vlong)) 1328 error(Ebadtimectl); 1329 le2vlong(&delta, p); 1330 todset(delta, 0, 0); 1331 break; 1332 case 'd': 1333 if(n < sizeof(vlong)+sizeof(long)) 1334 error(Ebadtimectl); 1335 p = le2vlong(&delta, p); 1336 le2long(&period, p); 1337 todset(-1, delta, period); 1338 break; 1339 case 'f': 1340 if(n < sizeof(uvlong)) 1341 error(Ebadtimectl); 1342 le2vlong(&fasthz, p); 1343 todsetfreq(fasthz); 1344 break; 1345 } 1346 return n; 1347 } 1348 1349 // Plan 9 VX 1350 int 1351 tailkmesg(char *a, int n) 1352 { 1353 ilock(&kmesg.lk); 1354 if(n > kmesg.n) 1355 n = kmesg.n; 1356 memmove(a, kmesg.buf+kmesg.n-n, n); 1357 iunlock(&kmesg.lk); 1358 return n; 1359 }