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