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