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 * 4. 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 161 void 162 cninit_finish() 163 { 164 console_pausing = 0; 165 } 166 167 /* add a new physical console to back the virtual console */ 168 int 169 cnadd(struct consdev *cn) 170 { 171 struct cn_device *cnd; 172 int i; 173 174 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 175 if (cnd->cnd_cn == cn) 176 return (0); 177 for (i = 0; i < CNDEVTAB_SIZE; i++) { 178 cnd = &cn_devtab[i]; 179 if (cnd->cnd_cn == NULL) 180 break; 181 } 182 if (cnd->cnd_cn != NULL) 183 return (ENOMEM); 184 cnd->cnd_cn = cn; 185 if (cn->cn_name[0] == '\0') { 186 /* XXX: it is unclear if/where this print might output */ 187 printf("WARNING: console at %p has no name\n", cn); 188 } 189 STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next); 190 if (STAILQ_FIRST(&cn_devlist) == cnd) 191 ttyconsdev_select(cnd->cnd_cn->cn_name); 192 193 /* Add device to the active mask. */ 194 cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0); 195 196 return (0); 197 } 198 199 void 200 cnremove(struct consdev *cn) 201 { 202 struct cn_device *cnd; 203 int i; 204 205 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 206 if (cnd->cnd_cn != cn) 207 continue; 208 if (STAILQ_FIRST(&cn_devlist) == cnd) 209 ttyconsdev_select(NULL); 210 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 211 cnd->cnd_cn = NULL; 212 213 /* Remove this device from available mask. */ 214 for (i = 0; i < CNDEVTAB_SIZE; i++) 215 if (cnd == &cn_devtab[i]) { 216 cons_avail_mask &= ~(1 << i); 217 break; 218 } 219 #if 0 220 /* 221 * XXX 222 * syscons gets really confused if console resources are 223 * freed after the system has initialized. 224 */ 225 if (cn->cn_term != NULL) 226 cn->cn_ops->cn_term(cn); 227 #endif 228 return; 229 } 230 } 231 232 void 233 cnselect(struct consdev *cn) 234 { 235 struct cn_device *cnd; 236 237 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 238 if (cnd->cnd_cn != cn) 239 continue; 240 if (cnd == STAILQ_FIRST(&cn_devlist)) 241 return; 242 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 243 STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next); 244 ttyconsdev_select(cnd->cnd_cn->cn_name); 245 return; 246 } 247 } 248 249 void 250 cnavailable(struct consdev *cn, int available) 251 { 252 int i; 253 254 for (i = 0; i < CNDEVTAB_SIZE; i++) { 255 if (cn_devtab[i].cnd_cn == cn) 256 break; 257 } 258 if (available) { 259 if (i < CNDEVTAB_SIZE) 260 cons_avail_mask |= (1 << i); 261 cn->cn_flags &= ~CN_FLAG_NOAVAIL; 262 } else { 263 if (i < CNDEVTAB_SIZE) 264 cons_avail_mask &= ~(1 << i); 265 cn->cn_flags |= CN_FLAG_NOAVAIL; 266 } 267 } 268 269 int 270 cnunavailable(void) 271 { 272 273 return (cons_avail_mask == 0); 274 } 275 276 /* 277 * sysctl_kern_console() provides output parseable in conscontrol(1). 278 */ 279 static int 280 sysctl_kern_console(SYSCTL_HANDLER_ARGS) 281 { 282 struct cn_device *cnd; 283 struct consdev *cp, **list; 284 char *p; 285 int delete, error; 286 struct sbuf *sb; 287 288 sb = sbuf_new(NULL, NULL, CNDEVPATHMAX * 2, SBUF_AUTOEXTEND); 289 if (sb == NULL) 290 return (ENOMEM); 291 sbuf_clear(sb); 292 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 293 sbuf_printf(sb, "%s,", cnd->cnd_cn->cn_name); 294 sbuf_printf(sb, "/"); 295 SET_FOREACH(list, cons_set) { 296 cp = *list; 297 if (cp->cn_name[0] != '\0') 298 sbuf_printf(sb, "%s,", cp->cn_name); 299 } 300 sbuf_finish(sb); 301 error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req); 302 if (error == 0 && req->newptr != NULL) { 303 p = sbuf_data(sb); 304 error = ENXIO; 305 delete = 0; 306 if (*p == '-') { 307 delete = 1; 308 p++; 309 } 310 SET_FOREACH(list, cons_set) { 311 cp = *list; 312 if (strcmp(p, cp->cn_name) != 0) 313 continue; 314 if (delete) { 315 cnremove(cp); 316 error = 0; 317 } else { 318 error = cnadd(cp); 319 if (error == 0) 320 cnselect(cp); 321 } 322 break; 323 } 324 } 325 sbuf_delete(sb); 326 return (error); 327 } 328 329 SYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW, 330 0, 0, sysctl_kern_console, "A", "Console device control"); 331 332 /* 333 * User has changed the state of the console muting. 334 * This may require us to open or close the device in question. 335 */ 336 static int 337 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS) 338 { 339 int error; 340 341 error = sysctl_handle_int(oidp, &cn_mute, 0, req); 342 if (error != 0 || req->newptr == NULL) 343 return (error); 344 return (error); 345 } 346 347 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 348 0, sizeof(cn_mute), sysctl_kern_consmute, "I", 349 "State of the console muting"); 350 351 void 352 cngrab() 353 { 354 struct cn_device *cnd; 355 struct consdev *cn; 356 357 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 358 cn = cnd->cnd_cn; 359 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 360 cn->cn_ops->cn_grab(cn); 361 } 362 } 363 364 void 365 cnungrab() 366 { 367 struct cn_device *cnd; 368 struct consdev *cn; 369 370 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 371 cn = cnd->cnd_cn; 372 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 373 cn->cn_ops->cn_ungrab(cn); 374 } 375 } 376 377 /* 378 * Low level console routines. 379 */ 380 int 381 cngetc(void) 382 { 383 int c; 384 385 if (cn_mute) 386 return (-1); 387 while ((c = cncheckc()) == -1) 388 cpu_spinwait(); 389 if (c == '\r') 390 c = '\n'; /* console input is always ICRNL */ 391 return (c); 392 } 393 394 int 395 cncheckc(void) 396 { 397 struct cn_device *cnd; 398 struct consdev *cn; 399 int c; 400 401 if (cn_mute) 402 return (-1); 403 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 404 cn = cnd->cnd_cn; 405 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 406 c = cn->cn_ops->cn_getc(cn); 407 if (c != -1) 408 return (c); 409 } 410 } 411 return (-1); 412 } 413 414 void 415 cngets(char *cp, size_t size, int visible) 416 { 417 char *lp, *end; 418 int c; 419 420 cngrab(); 421 422 lp = cp; 423 end = cp + size - 1; 424 for (;;) { 425 c = cngetc() & 0177; 426 switch (c) { 427 case '\n': 428 case '\r': 429 cnputc(c); 430 *lp = '\0'; 431 cnungrab(); 432 return; 433 case '\b': 434 case '\177': 435 if (lp > cp) { 436 if (visible) 437 cnputs("\b \b"); 438 lp--; 439 } 440 continue; 441 case '\0': 442 continue; 443 default: 444 if (lp < end) { 445 switch (visible) { 446 case GETS_NOECHO: 447 break; 448 case GETS_ECHOPASS: 449 cnputc('*'); 450 break; 451 default: 452 cnputc(c); 453 break; 454 } 455 *lp++ = c; 456 } 457 } 458 } 459 } 460 461 void 462 cnputc(int c) 463 { 464 struct cn_device *cnd; 465 struct consdev *cn; 466 char *cp; 467 468 #ifdef EARLY_PRINTF 469 if (early_putc != NULL) { 470 if (c == '\n') 471 early_putc('\r'); 472 early_putc(c); 473 return; 474 } 475 #endif 476 477 if (cn_mute || c == '\0') 478 return; 479 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 480 cn = cnd->cnd_cn; 481 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 482 if (c == '\n') 483 cn->cn_ops->cn_putc(cn, '\r'); 484 cn->cn_ops->cn_putc(cn, c); 485 } 486 } 487 if (console_pausing && c == '\n' && !kdb_active) { 488 for (cp = console_pausestr; *cp != '\0'; cp++) 489 cnputc(*cp); 490 cngrab(); 491 if (cngetc() == '.') 492 console_pausing = 0; 493 cnungrab(); 494 cnputc('\r'); 495 for (cp = console_pausestr; *cp != '\0'; cp++) 496 cnputc(' '); 497 cnputc('\r'); 498 } 499 } 500 501 void 502 cnputs(char *p) 503 { 504 int c; 505 int unlock_reqd = 0; 506 507 if (use_cnputs_mtx) { 508 mtx_lock_spin(&cnputs_mtx); 509 unlock_reqd = 1; 510 } 511 512 while ((c = *p++) != '\0') 513 cnputc(c); 514 515 if (unlock_reqd) 516 mtx_unlock_spin(&cnputs_mtx); 517 } 518 519 static int consmsgbuf_size = 8192; 520 SYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0, 521 "Console tty buffer size"); 522 523 /* 524 * Redirect console output to a tty. 525 */ 526 void 527 constty_set(struct tty *tp) 528 { 529 int size; 530 531 KASSERT(tp != NULL, ("constty_set: NULL tp")); 532 if (consbuf == NULL) { 533 size = consmsgbuf_size; 534 consbuf = malloc(size, M_TTYCONS, M_WAITOK); 535 msgbuf_init(&consmsgbuf, consbuf, size); 536 callout_init(&conscallout, 0); 537 } 538 constty = tp; 539 constty_timeout(NULL); 540 } 541 542 /* 543 * Disable console redirection to a tty. 544 */ 545 void 546 constty_clear(void) 547 { 548 int c; 549 550 constty = NULL; 551 if (consbuf == NULL) 552 return; 553 callout_stop(&conscallout); 554 while ((c = msgbuf_getchar(&consmsgbuf)) != -1) 555 cnputc(c); 556 free(consbuf, M_TTYCONS); 557 consbuf = NULL; 558 } 559 560 /* Times per second to check for pending console tty messages. */ 561 static int constty_wakeups_per_second = 5; 562 SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, 563 &constty_wakeups_per_second, 0, 564 "Times per second to check for pending console tty messages"); 565 566 static void 567 constty_timeout(void *arg) 568 { 569 int c; 570 571 if (constty != NULL) { 572 tty_lock(constty); 573 while ((c = msgbuf_getchar(&consmsgbuf)) != -1) { 574 if (tty_putchar(constty, c) < 0) { 575 tty_unlock(constty); 576 constty = NULL; 577 break; 578 } 579 } 580 581 if (constty != NULL) 582 tty_unlock(constty); 583 } 584 if (constty != NULL) { 585 callout_reset(&conscallout, hz / constty_wakeups_per_second, 586 constty_timeout, NULL); 587 } else { 588 /* Deallocate the constty buffer memory. */ 589 constty_clear(); 590 } 591 } 592 593 static void 594 cn_drvinit(void *unused) 595 { 596 597 mtx_init(&cnputs_mtx, "cnputs_mtx", NULL, MTX_SPIN | MTX_NOWITNESS); 598 use_cnputs_mtx = 1; 599 } 600 601 SYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL); 602 603 /* 604 * Sysbeep(), if we have hardware for it 605 */ 606 607 #ifdef HAS_TIMER_SPKR 608 609 static int beeping; 610 static struct callout beeping_timer; 611 612 static void 613 sysbeepstop(void *chan) 614 { 615 616 timer_spkr_release(); 617 beeping = 0; 618 } 619 620 int 621 sysbeep(int pitch, int period) 622 { 623 624 if (timer_spkr_acquire()) { 625 if (!beeping) { 626 /* Something else owns it. */ 627 return (EBUSY); 628 } 629 } 630 timer_spkr_setfreq(pitch); 631 if (!beeping) { 632 beeping = period; 633 callout_reset(&beeping_timer, period, sysbeepstop, NULL); 634 } 635 return (0); 636 } 637 638 static void 639 sysbeep_init(void *unused) 640 { 641 642 callout_init(&beeping_timer, CALLOUT_MPSAFE); 643 } 644 SYSINIT(sysbeep, SI_SUB_SOFTINTR, SI_ORDER_ANY, sysbeep_init, NULL); 645 #else 646 647 /* 648 * No hardware, no sound 649 */ 650 651 int 652 sysbeep(int pitch __unused, int period __unused) 653 { 654 655 return (ENODEV); 656 } 657 658 #endif 659 660 /* 661 * Temporary support for sc(4) to vt(4) transition. 662 */ 663 static unsigned vty_prefer; 664 static char vty_name[16]; 665 SYSCTL_STRING(_kern, OID_AUTO, vty, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, vty_name, 666 0, "Console vty driver"); 667 668 int 669 vty_enabled(unsigned vty) 670 { 671 static unsigned vty_selected = 0; 672 673 if (vty_selected == 0) { 674 TUNABLE_STR_FETCH("kern.vty", vty_name, sizeof(vty_name)); 675 do { 676 #if defined(DEV_SC) 677 if (strcmp(vty_name, "sc") == 0) { 678 vty_selected = VTY_SC; 679 break; 680 } 681 #endif 682 #if defined(DEV_VT) 683 if (strcmp(vty_name, "vt") == 0) { 684 vty_selected = VTY_VT; 685 break; 686 } 687 #endif 688 if (vty_prefer != 0) { 689 vty_selected = vty_prefer; 690 break; 691 } 692 #if defined(DEV_VT) 693 vty_selected = VTY_VT; 694 #elif defined(DEV_SC) 695 vty_selected = VTY_SC; 696 #endif 697 } while (0); 698 699 if (vty_selected == VTY_VT) 700 strcpy(vty_name, "vt"); 701 else if (vty_selected == VTY_SC) 702 strcpy(vty_name, "sc"); 703 } 704 return ((vty_selected & vty) != 0); 705 } 706 707 void 708 vty_set_preferred(unsigned vty) 709 { 710 711 vty_prefer = vty; 712 #if !defined(DEV_SC) 713 vty_prefer &= ~VTY_SC; 714 #endif 715 #if !defined(DEV_VT) 716 vty_prefer &= ~VTY_VT; 717 #endif 718 } 719 720