1 /*- 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1991 The Regents of the University of California. 4 * Copyright (c) 1999 Michael Smith 5 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 6 * 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * the Systems Programming Group of the University of Utah Computer 11 * Science Department. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 38 */ 39 40 #include <sys/cdefs.h> 41 __FBSDID("$FreeBSD$"); 42 43 #include "opt_ddb.h" 44 #include "opt_syscons.h" 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/lock.h> 49 #include <sys/mutex.h> 50 #include <sys/conf.h> 51 #include <sys/cons.h> 52 #include <sys/fcntl.h> 53 #include <sys/kdb.h> 54 #include <sys/kernel.h> 55 #include <sys/malloc.h> 56 #include <sys/msgbuf.h> 57 #include <sys/namei.h> 58 #include <sys/priv.h> 59 #include <sys/proc.h> 60 #include <sys/queue.h> 61 #include <sys/reboot.h> 62 #include <sys/sysctl.h> 63 #include <sys/sbuf.h> 64 #include <sys/tty.h> 65 #include <sys/uio.h> 66 #include <sys/vnode.h> 67 68 #include <ddb/ddb.h> 69 70 #include <machine/cpu.h> 71 #include <machine/clock.h> 72 73 static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling"); 74 75 struct cn_device { 76 STAILQ_ENTRY(cn_device) cnd_next; 77 struct consdev *cnd_cn; 78 }; 79 80 #define CNDEVPATHMAX 32 81 #define CNDEVTAB_SIZE 4 82 static struct cn_device cn_devtab[CNDEVTAB_SIZE]; 83 static STAILQ_HEAD(, cn_device) cn_devlist = 84 STAILQ_HEAD_INITIALIZER(cn_devlist); 85 86 int cons_avail_mask = 0; /* Bit mask. Each registered low level console 87 * which is currently unavailable for inpit 88 * (i.e., if it is in graphics mode) will have 89 * this bit cleared. 90 */ 91 static int cn_mute; 92 static char *consbuf; /* buffer used by `consmsgbuf' */ 93 static struct callout conscallout; /* callout for outputting to constty */ 94 struct msgbuf consmsgbuf; /* message buffer for console tty */ 95 static u_char console_pausing; /* pause after each line during probe */ 96 static char *console_pausestr= 97 "<pause; press any key to proceed to next line or '.' to end pause mode>"; 98 struct tty *constty; /* pointer to console "window" tty */ 99 static struct mtx cnputs_mtx; /* Mutex for cnputs(). */ 100 static int use_cnputs_mtx = 0; /* != 0 if cnputs_mtx locking reqd. */ 101 102 static void constty_timeout(void *arg); 103 104 static struct consdev cons_consdev; 105 DATA_SET(cons_set, cons_consdev); 106 SET_DECLARE(cons_set, struct consdev); 107 108 void 109 cninit(void) 110 { 111 struct consdev *best_cn, *cn, **list; 112 113 /* 114 * Check if we should mute the console (for security reasons perhaps) 115 * It can be changes dynamically using sysctl kern.consmute 116 * once we are up and going. 117 * 118 */ 119 cn_mute = ((boothowto & (RB_MUTE 120 |RB_SINGLE 121 |RB_VERBOSE 122 |RB_ASKNAME)) == RB_MUTE); 123 124 /* 125 * Find the first console with the highest priority. 126 */ 127 best_cn = NULL; 128 SET_FOREACH(list, cons_set) { 129 cn = *list; 130 cnremove(cn); 131 /* Skip cons_consdev. */ 132 if (cn->cn_ops == NULL) 133 continue; 134 cn->cn_ops->cn_probe(cn); 135 if (cn->cn_pri == CN_DEAD) 136 continue; 137 if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri) 138 best_cn = cn; 139 if (boothowto & RB_MULTIPLE) { 140 /* 141 * Initialize console, and attach to it. 142 */ 143 cn->cn_ops->cn_init(cn); 144 cnadd(cn); 145 } 146 } 147 if (best_cn == NULL) 148 return; 149 if ((boothowto & RB_MULTIPLE) == 0) { 150 best_cn->cn_ops->cn_init(best_cn); 151 cnadd(best_cn); 152 } 153 if (boothowto & RB_PAUSE) 154 console_pausing = 1; 155 /* 156 * Make the best console the preferred console. 157 */ 158 cnselect(best_cn); 159 160 #ifdef EARLY_PRINTF 161 /* 162 * Release early console. 163 */ 164 early_putc = NULL; 165 #endif 166 } 167 168 void 169 cninit_finish() 170 { 171 console_pausing = 0; 172 } 173 174 /* add a new physical console to back the virtual console */ 175 int 176 cnadd(struct consdev *cn) 177 { 178 struct cn_device *cnd; 179 int i; 180 181 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 182 if (cnd->cnd_cn == cn) 183 return (0); 184 for (i = 0; i < CNDEVTAB_SIZE; i++) { 185 cnd = &cn_devtab[i]; 186 if (cnd->cnd_cn == NULL) 187 break; 188 } 189 if (cnd->cnd_cn != NULL) 190 return (ENOMEM); 191 cnd->cnd_cn = cn; 192 if (cn->cn_name[0] == '\0') { 193 /* XXX: it is unclear if/where this print might output */ 194 printf("WARNING: console at %p has no name\n", cn); 195 } 196 STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next); 197 if (STAILQ_FIRST(&cn_devlist) == cnd) 198 ttyconsdev_select(cnd->cnd_cn->cn_name); 199 200 /* Add device to the active mask. */ 201 cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0); 202 203 return (0); 204 } 205 206 void 207 cnremove(struct consdev *cn) 208 { 209 struct cn_device *cnd; 210 int i; 211 212 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 213 if (cnd->cnd_cn != cn) 214 continue; 215 if (STAILQ_FIRST(&cn_devlist) == cnd) 216 ttyconsdev_select(NULL); 217 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 218 cnd->cnd_cn = NULL; 219 220 /* Remove this device from available mask. */ 221 for (i = 0; i < CNDEVTAB_SIZE; i++) 222 if (cnd == &cn_devtab[i]) { 223 cons_avail_mask &= ~(1 << i); 224 break; 225 } 226 #if 0 227 /* 228 * XXX 229 * syscons gets really confused if console resources are 230 * freed after the system has initialized. 231 */ 232 if (cn->cn_term != NULL) 233 cn->cn_ops->cn_term(cn); 234 #endif 235 return; 236 } 237 } 238 239 void 240 cnselect(struct consdev *cn) 241 { 242 struct cn_device *cnd; 243 244 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 245 if (cnd->cnd_cn != cn) 246 continue; 247 if (cnd == STAILQ_FIRST(&cn_devlist)) 248 return; 249 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 250 STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next); 251 ttyconsdev_select(cnd->cnd_cn->cn_name); 252 return; 253 } 254 } 255 256 void 257 cnavailable(struct consdev *cn, int available) 258 { 259 int i; 260 261 for (i = 0; i < CNDEVTAB_SIZE; i++) { 262 if (cn_devtab[i].cnd_cn == cn) 263 break; 264 } 265 if (available) { 266 if (i < CNDEVTAB_SIZE) 267 cons_avail_mask |= (1 << i); 268 cn->cn_flags &= ~CN_FLAG_NOAVAIL; 269 } else { 270 if (i < CNDEVTAB_SIZE) 271 cons_avail_mask &= ~(1 << i); 272 cn->cn_flags |= CN_FLAG_NOAVAIL; 273 } 274 } 275 276 int 277 cnunavailable(void) 278 { 279 280 return (cons_avail_mask == 0); 281 } 282 283 /* 284 * sysctl_kern_console() provides output parseable in conscontrol(1). 285 */ 286 static int 287 sysctl_kern_console(SYSCTL_HANDLER_ARGS) 288 { 289 struct cn_device *cnd; 290 struct consdev *cp, **list; 291 char *p; 292 int delete, error; 293 struct sbuf *sb; 294 295 sb = sbuf_new(NULL, NULL, CNDEVPATHMAX * 2, SBUF_AUTOEXTEND | 296 SBUF_INCLUDENUL); 297 if (sb == NULL) 298 return (ENOMEM); 299 sbuf_clear(sb); 300 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 301 sbuf_printf(sb, "%s,", cnd->cnd_cn->cn_name); 302 sbuf_printf(sb, "/"); 303 SET_FOREACH(list, cons_set) { 304 cp = *list; 305 if (cp->cn_name[0] != '\0') 306 sbuf_printf(sb, "%s,", cp->cn_name); 307 } 308 sbuf_finish(sb); 309 error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req); 310 if (error == 0 && req->newptr != NULL) { 311 p = sbuf_data(sb); 312 error = ENXIO; 313 delete = 0; 314 if (*p == '-') { 315 delete = 1; 316 p++; 317 } 318 SET_FOREACH(list, cons_set) { 319 cp = *list; 320 if (strcmp(p, cp->cn_name) != 0) 321 continue; 322 if (delete) { 323 cnremove(cp); 324 error = 0; 325 } else { 326 error = cnadd(cp); 327 if (error == 0) 328 cnselect(cp); 329 } 330 break; 331 } 332 } 333 sbuf_delete(sb); 334 return (error); 335 } 336 337 SYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW, 338 0, 0, sysctl_kern_console, "A", "Console device control"); 339 340 /* 341 * User has changed the state of the console muting. 342 * This may require us to open or close the device in question. 343 */ 344 static int 345 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS) 346 { 347 int error; 348 349 error = sysctl_handle_int(oidp, &cn_mute, 0, req); 350 if (error != 0 || req->newptr == NULL) 351 return (error); 352 return (error); 353 } 354 355 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 356 0, sizeof(cn_mute), sysctl_kern_consmute, "I", 357 "State of the console muting"); 358 359 void 360 cngrab() 361 { 362 struct cn_device *cnd; 363 struct consdev *cn; 364 365 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 366 cn = cnd->cnd_cn; 367 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 368 cn->cn_ops->cn_grab(cn); 369 } 370 } 371 372 void 373 cnungrab() 374 { 375 struct cn_device *cnd; 376 struct consdev *cn; 377 378 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 379 cn = cnd->cnd_cn; 380 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 381 cn->cn_ops->cn_ungrab(cn); 382 } 383 } 384 385 /* 386 * Low level console routines. 387 */ 388 int 389 cngetc(void) 390 { 391 int c; 392 393 if (cn_mute) 394 return (-1); 395 while ((c = cncheckc()) == -1) 396 cpu_spinwait(); 397 if (c == '\r') 398 c = '\n'; /* console input is always ICRNL */ 399 return (c); 400 } 401 402 int 403 cncheckc(void) 404 { 405 struct cn_device *cnd; 406 struct consdev *cn; 407 int c; 408 409 if (cn_mute) 410 return (-1); 411 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 412 cn = cnd->cnd_cn; 413 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 414 c = cn->cn_ops->cn_getc(cn); 415 if (c != -1) 416 return (c); 417 } 418 } 419 return (-1); 420 } 421 422 void 423 cngets(char *cp, size_t size, int visible) 424 { 425 char *lp, *end; 426 int c; 427 428 cngrab(); 429 430 lp = cp; 431 end = cp + size - 1; 432 for (;;) { 433 c = cngetc() & 0177; 434 switch (c) { 435 case '\n': 436 case '\r': 437 cnputc(c); 438 *lp = '\0'; 439 cnungrab(); 440 return; 441 case '\b': 442 case '\177': 443 if (lp > cp) { 444 if (visible) 445 cnputs("\b \b"); 446 lp--; 447 } 448 continue; 449 case '\0': 450 continue; 451 default: 452 if (lp < end) { 453 switch (visible) { 454 case GETS_NOECHO: 455 break; 456 case GETS_ECHOPASS: 457 cnputc('*'); 458 break; 459 default: 460 cnputc(c); 461 break; 462 } 463 *lp++ = c; 464 } 465 } 466 } 467 } 468 469 void 470 cnputc(int c) 471 { 472 struct cn_device *cnd; 473 struct consdev *cn; 474 char *cp; 475 476 #ifdef EARLY_PRINTF 477 if (early_putc != NULL) { 478 if (c == '\n') 479 early_putc('\r'); 480 early_putc(c); 481 return; 482 } 483 #endif 484 485 if (cn_mute || c == '\0') 486 return; 487 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 488 cn = cnd->cnd_cn; 489 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 490 if (c == '\n') 491 cn->cn_ops->cn_putc(cn, '\r'); 492 cn->cn_ops->cn_putc(cn, c); 493 } 494 } 495 if (console_pausing && c == '\n' && !kdb_active) { 496 for (cp = console_pausestr; *cp != '\0'; cp++) 497 cnputc(*cp); 498 cngrab(); 499 if (cngetc() == '.') 500 console_pausing = 0; 501 cnungrab(); 502 cnputc('\r'); 503 for (cp = console_pausestr; *cp != '\0'; cp++) 504 cnputc(' '); 505 cnputc('\r'); 506 } 507 } 508 509 void 510 cnputs(char *p) 511 { 512 int c; 513 int unlock_reqd = 0; 514 515 if (use_cnputs_mtx) { 516 /* 517 * NOTE: Debug prints and/or witness printouts in 518 * console driver clients can cause the "cnputs_mtx" 519 * mutex to recurse. Simply return if that happens. 520 */ 521 if (mtx_owned(&cnputs_mtx)) 522 return; 523 mtx_lock_spin(&cnputs_mtx); 524 unlock_reqd = 1; 525 } 526 527 while ((c = *p++) != '\0') 528 cnputc(c); 529 530 if (unlock_reqd) 531 mtx_unlock_spin(&cnputs_mtx); 532 } 533 534 static int consmsgbuf_size = 8192; 535 SYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0, 536 "Console tty buffer size"); 537 538 /* 539 * Redirect console output to a tty. 540 */ 541 void 542 constty_set(struct tty *tp) 543 { 544 int size; 545 546 KASSERT(tp != NULL, ("constty_set: NULL tp")); 547 if (consbuf == NULL) { 548 size = consmsgbuf_size; 549 consbuf = malloc(size, M_TTYCONS, M_WAITOK); 550 msgbuf_init(&consmsgbuf, consbuf, size); 551 callout_init(&conscallout, 0); 552 } 553 constty = tp; 554 constty_timeout(NULL); 555 } 556 557 /* 558 * Disable console redirection to a tty. 559 */ 560 void 561 constty_clear(void) 562 { 563 int c; 564 565 constty = NULL; 566 if (consbuf == NULL) 567 return; 568 callout_stop(&conscallout); 569 while ((c = msgbuf_getchar(&consmsgbuf)) != -1) 570 cnputc(c); 571 free(consbuf, M_TTYCONS); 572 consbuf = NULL; 573 } 574 575 /* Times per second to check for pending console tty messages. */ 576 static int constty_wakeups_per_second = 5; 577 SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, 578 &constty_wakeups_per_second, 0, 579 "Times per second to check for pending console tty messages"); 580 581 static void 582 constty_timeout(void *arg) 583 { 584 int c; 585 586 if (constty != NULL) { 587 tty_lock(constty); 588 while ((c = msgbuf_getchar(&consmsgbuf)) != -1) { 589 if (tty_putchar(constty, c) < 0) { 590 tty_unlock(constty); 591 constty = NULL; 592 break; 593 } 594 } 595 596 if (constty != NULL) 597 tty_unlock(constty); 598 } 599 if (constty != NULL) { 600 callout_reset(&conscallout, hz / constty_wakeups_per_second, 601 constty_timeout, NULL); 602 } else { 603 /* Deallocate the constty buffer memory. */ 604 constty_clear(); 605 } 606 } 607 608 static void 609 cn_drvinit(void *unused) 610 { 611 612 mtx_init(&cnputs_mtx, "cnputs_mtx", NULL, MTX_SPIN | MTX_NOWITNESS); 613 use_cnputs_mtx = 1; 614 } 615 616 SYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL); 617 618 /* 619 * Sysbeep(), if we have hardware for it 620 */ 621 622 #ifdef HAS_TIMER_SPKR 623 624 static int beeping; 625 static struct callout beeping_timer; 626 627 static void 628 sysbeepstop(void *chan) 629 { 630 631 timer_spkr_release(); 632 beeping = 0; 633 } 634 635 int 636 sysbeep(int pitch, int period) 637 { 638 639 if (timer_spkr_acquire()) { 640 if (!beeping) { 641 /* Something else owns it. */ 642 return (EBUSY); 643 } 644 } 645 timer_spkr_setfreq(pitch); 646 if (!beeping) { 647 beeping = period; 648 callout_reset(&beeping_timer, period, sysbeepstop, NULL); 649 } 650 return (0); 651 } 652 653 static void 654 sysbeep_init(void *unused) 655 { 656 657 callout_init(&beeping_timer, 1); 658 } 659 SYSINIT(sysbeep, SI_SUB_SOFTINTR, SI_ORDER_ANY, sysbeep_init, NULL); 660 #else 661 662 /* 663 * No hardware, no sound 664 */ 665 666 int 667 sysbeep(int pitch __unused, int period __unused) 668 { 669 670 return (ENODEV); 671 } 672 673 #endif 674 675 /* 676 * Temporary support for sc(4) to vt(4) transition. 677 */ 678 static unsigned vty_prefer; 679 static char vty_name[16]; 680 SYSCTL_STRING(_kern, OID_AUTO, vty, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, vty_name, 681 0, "Console vty driver"); 682 683 int 684 vty_enabled(unsigned vty) 685 { 686 static unsigned vty_selected = 0; 687 688 if (vty_selected == 0) { 689 TUNABLE_STR_FETCH("kern.vty", vty_name, sizeof(vty_name)); 690 do { 691 #if defined(DEV_SC) 692 if (strcmp(vty_name, "sc") == 0) { 693 vty_selected = VTY_SC; 694 break; 695 } 696 #endif 697 #if defined(DEV_VT) 698 if (strcmp(vty_name, "vt") == 0) { 699 vty_selected = VTY_VT; 700 break; 701 } 702 #endif 703 if (vty_prefer != 0) { 704 vty_selected = vty_prefer; 705 break; 706 } 707 #if defined(DEV_VT) 708 vty_selected = VTY_VT; 709 #elif defined(DEV_SC) 710 vty_selected = VTY_SC; 711 #endif 712 } while (0); 713 714 if (vty_selected == VTY_VT) 715 strcpy(vty_name, "vt"); 716 else if (vty_selected == VTY_SC) 717 strcpy(vty_name, "sc"); 718 } 719 return ((vty_selected & vty) != 0); 720 } 721 722 void 723 vty_set_preferred(unsigned vty) 724 { 725 726 vty_prefer = vty; 727 #if !defined(DEV_SC) 728 vty_prefer &= ~VTY_SC; 729 #endif 730 #if !defined(DEV_VT) 731 vty_prefer &= ~VTY_VT; 732 #endif 733 } 734 735