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