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