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