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