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 40#include <sys/cdefs.h> 41#include "opt_ddb.h" 42#include "opt_syscons.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/lock.h> 47#include <sys/mutex.h> 48#include <sys/conf.h> 49#include <sys/cons.h> 50#include <sys/fcntl.h> 51#include <sys/kbio.h> 52#include <sys/kdb.h> 53#include <sys/kernel.h> 54#include <sys/malloc.h> 55#include <sys/msgbuf.h> 56#include <sys/namei.h> 57#include <sys/priv.h> 58#include <sys/proc.h> 59#include <sys/queue.h> 60#include <sys/reboot.h> 61#include <sys/sysctl.h> 62#include <sys/sbuf.h> 63#include <sys/tslog.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 <dev/kbd/kbdreg.h> 71 72#include <machine/cpu.h> 73#include <machine/clock.h> 74 75/* 76 * Check for 'options EARLY_PRINTF' that may have been used in old kernel 77 * config files. If you are hitting this error you should update your 78 * config to use 'options EARLY_PRINTF=<device name>', e.g. with the 79 * Arm pl011 use: 80 * 81 * options EARLY_PRINTF=pl011 82 */ 83#if CHECK_EARLY_PRINTF(1) 84#error Update your config to use 'options EARLY_PRINTF=<device name>' 85#endif 86 87static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling"); 88 89struct cn_device { 90 STAILQ_ENTRY(cn_device) cnd_next; 91 struct consdev *cnd_cn; 92}; 93 94#define CNDEVPATHMAX 32 95#define CNDEVTAB_SIZE 4 96static struct cn_device cn_devtab[CNDEVTAB_SIZE]; 97static STAILQ_HEAD(, cn_device) cn_devlist = 98 STAILQ_HEAD_INITIALIZER(cn_devlist); 99 100int cons_avail_mask = 0; /* Bit mask. Each registered low level console 101 * which is currently unavailable for inpit 102 * (i.e., if it is in graphics mode) will have 103 * this bit cleared. 104 */ 105 106int cn_mute; 107SYSCTL_INT(_kern, OID_AUTO, consmute, CTLFLAG_RW, &cn_mute, 0, 108 "State of the console muting"); 109 110static char *consbuf; /* buffer used by `consmsgbuf' */ 111static struct callout conscallout; /* callout for outputting to constty */ 112struct msgbuf consmsgbuf; /* message buffer for console tty */ 113static bool console_pausing; /* pause after each line during probe */ 114static const char console_pausestr[] = 115"<pause; press any key to proceed to next line or '.' to end pause mode>"; 116struct tty *constty; /* pointer to console "window" tty */ 117static struct mtx constty_mtx; /* Mutex for constty assignment. */ 118MTX_SYSINIT(constty_mtx, &constty_mtx, "constty_mtx", MTX_DEF); 119static struct mtx cnputs_mtx; /* Mutex for cnputs(). */ 120MTX_SYSINIT(cnputs_mtx, &cnputs_mtx, "cnputs_mtx", MTX_SPIN | MTX_NOWITNESS); 121 122static void constty_timeout(void *arg); 123 124static struct consdev cons_consdev; 125DATA_SET(cons_set, cons_consdev); 126SET_DECLARE(cons_set, struct consdev); 127 128/* 129 * Stub for configurations that don't actually have a keyboard driver. Inclusion 130 * of kbd.c is contingent on any number of keyboard/console drivers being 131 * present in the kernel; rather than trying to catch them all, we'll just 132 * maintain this weak kbdinit that will be overridden by the strong version in 133 * kbd.c if it's present. 134 */ 135__weak_symbol void 136kbdinit(void) 137{ 138 139} 140 141static void 142mute_console(void *data __unused) 143{ 144 145 if ((boothowto & (RB_MUTEMSGS | RB_VERBOSE)) == RB_MUTEMSGS) { 146 printf("-- Muting boot messages --\n"); 147 cn_mute = 1; 148 } 149} 150 151SYSINIT(mute_console, SI_SUB_COPYRIGHT, SI_ORDER_ANY, mute_console, NULL); 152 153void 154cninit(void) 155{ 156 struct consdev *best_cn, *cn, **list; 157 158 TSENTER(); 159 /* 160 * Check if we should mute the console (for security reasons perhaps) 161 * It can be changes dynamically using sysctl kern.consmute 162 * once we are up and going. 163 * 164 */ 165 cn_mute = ((boothowto & (RB_MUTE 166 |RB_SINGLE 167 |RB_VERBOSE 168 |RB_ASKNAME)) == RB_MUTE); 169 170 /* 171 * Bring up the kbd layer just in time for cnprobe. Console drivers 172 * have a dependency on kbd being ready, so this fits nicely between the 173 * machdep callers of cninit() and MI probing/initialization of consoles 174 * here. 175 */ 176 kbdinit(); 177 178 /* 179 * Find the first console with the highest priority. 180 */ 181 best_cn = NULL; 182 SET_FOREACH(list, cons_set) { 183 cn = *list; 184 cnremove(cn); 185 /* Skip cons_consdev. */ 186 if (cn->cn_ops == NULL) 187 continue; 188 cn->cn_ops->cn_probe(cn); 189 if (cn->cn_pri == CN_DEAD) 190 continue; 191 if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri) 192 best_cn = cn; 193 if (boothowto & RB_MULTIPLE) { 194 /* 195 * Initialize console, and attach to it. 196 */ 197 cn->cn_ops->cn_init(cn); 198 cnadd(cn); 199 } 200 } 201 if (best_cn == NULL) 202 return; 203 if ((boothowto & RB_MULTIPLE) == 0) { 204 best_cn->cn_ops->cn_init(best_cn); 205 cnadd(best_cn); 206 } 207 if (boothowto & RB_PAUSE) 208 console_pausing = true; 209 /* 210 * Make the best console the preferred console. 211 */ 212 cnselect(best_cn); 213 214#ifdef EARLY_PRINTF 215 /* 216 * Release early console. 217 */ 218 early_putc = NULL; 219#endif 220 TSEXIT(); 221} 222 223void 224cninit_finish(void) 225{ 226 console_pausing = false; 227} 228 229/* add a new physical console to back the virtual console */ 230int 231cnadd(struct consdev *cn) 232{ 233 struct cn_device *cnd; 234 int i; 235 236 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 237 if (cnd->cnd_cn == cn) 238 return (0); 239 for (i = 0; i < CNDEVTAB_SIZE; i++) { 240 cnd = &cn_devtab[i]; 241 if (cnd->cnd_cn == NULL) 242 break; 243 } 244 if (cnd->cnd_cn != NULL) 245 return (ENOMEM); 246 cnd->cnd_cn = cn; 247 if (cn->cn_name[0] == '\0') { 248 /* XXX: it is unclear if/where this print might output */ 249 printf("WARNING: console at %p has no name\n", cn); 250 } 251 STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next); 252 if (STAILQ_FIRST(&cn_devlist) == cnd) 253 ttyconsdev_select(cnd->cnd_cn->cn_name); 254 255 /* Add device to the active mask. */ 256 cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0); 257 258 return (0); 259} 260 261void 262cnremove(struct consdev *cn) 263{ 264 struct cn_device *cnd; 265 int i; 266 267 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 268 if (cnd->cnd_cn != cn) 269 continue; 270 if (STAILQ_FIRST(&cn_devlist) == cnd) 271 ttyconsdev_select(NULL); 272 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 273 cnd->cnd_cn = NULL; 274 275 /* Remove this device from available mask. */ 276 for (i = 0; i < CNDEVTAB_SIZE; i++) 277 if (cnd == &cn_devtab[i]) { 278 cons_avail_mask &= ~(1 << i); 279 break; 280 } 281#if 0 282 /* 283 * XXX 284 * syscons gets really confused if console resources are 285 * freed after the system has initialized. 286 */ 287 if (cn->cn_term != NULL) 288 cn->cn_ops->cn_term(cn); 289#endif 290 return; 291 } 292} 293 294void 295cnselect(struct consdev *cn) 296{ 297 struct cn_device *cnd; 298 299 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 300 if (cnd->cnd_cn != cn) 301 continue; 302 if (cnd == STAILQ_FIRST(&cn_devlist)) 303 return; 304 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 305 STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next); 306 ttyconsdev_select(cnd->cnd_cn->cn_name); 307 return; 308 } 309} 310 311void 312cnavailable(struct consdev *cn, int available) 313{ 314 int i; 315 316 for (i = 0; i < CNDEVTAB_SIZE; i++) { 317 if (cn_devtab[i].cnd_cn == cn) 318 break; 319 } 320 if (available) { 321 if (i < CNDEVTAB_SIZE) 322 cons_avail_mask |= (1 << i); 323 cn->cn_flags &= ~CN_FLAG_NOAVAIL; 324 } else { 325 if (i < CNDEVTAB_SIZE) 326 cons_avail_mask &= ~(1 << i); 327 cn->cn_flags |= CN_FLAG_NOAVAIL; 328 } 329} 330 331int 332cnunavailable(void) 333{ 334 335 return (cons_avail_mask == 0); 336} 337 338/* 339 * sysctl_kern_console() provides output parseable in conscontrol(1). 340 */ 341static int 342sysctl_kern_console(SYSCTL_HANDLER_ARGS) 343{ 344 struct cn_device *cnd; 345 struct consdev *cp, **list; 346 char *p; 347 bool delete; 348 int error; 349 struct sbuf *sb; 350 351 sb = sbuf_new(NULL, NULL, CNDEVPATHMAX * 2, SBUF_AUTOEXTEND | 352 SBUF_INCLUDENUL); 353 if (sb == NULL) 354 return (ENOMEM); 355 sbuf_clear(sb); 356 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 357 sbuf_printf(sb, "%s,", cnd->cnd_cn->cn_name); 358 sbuf_putc(sb, '/'); 359 SET_FOREACH(list, cons_set) { 360 cp = *list; 361 if (cp->cn_name[0] != '\0') 362 sbuf_printf(sb, "%s,", cp->cn_name); 363 } 364 sbuf_finish(sb); 365 error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req); 366 if (error == 0 && req->newptr != NULL) { 367 p = sbuf_data(sb); 368 error = ENXIO; 369 delete = false; 370 if (*p == '-') { 371 delete = true; 372 p++; 373 } 374 SET_FOREACH(list, cons_set) { 375 cp = *list; 376 if (strcmp(p, cp->cn_name) != 0) 377 continue; 378 if (delete) { 379 cnremove(cp); 380 error = 0; 381 } else { 382 error = cnadd(cp); 383 if (error == 0) 384 cnselect(cp); 385 } 386 break; 387 } 388 } 389 sbuf_delete(sb); 390 return (error); 391} 392 393SYSCTL_PROC(_kern, OID_AUTO, console, 394 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, 0, 395 sysctl_kern_console, "A", 396 "Console device control"); 397 398void 399cngrab(void) 400{ 401 struct cn_device *cnd; 402 struct consdev *cn; 403 404 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 405 cn = cnd->cnd_cn; 406 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 407 cn->cn_ops->cn_grab(cn); 408 } 409} 410 411void 412cnungrab(void) 413{ 414 struct cn_device *cnd; 415 struct consdev *cn; 416 417 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 418 cn = cnd->cnd_cn; 419 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 420 cn->cn_ops->cn_ungrab(cn); 421 } 422} 423 424void 425cnresume(void) 426{ 427 struct cn_device *cnd; 428 struct consdev *cn; 429 430 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 431 cn = cnd->cnd_cn; 432 if (cn->cn_ops->cn_resume != NULL) 433 cn->cn_ops->cn_resume(cn); 434 } 435} 436 437/* 438 * Low level console routines. 439 */ 440int 441cngetc(void) 442{ 443 int c; 444 445 if (cn_mute) 446 return (-1); 447 while ((c = cncheckc()) == -1) 448 cpu_spinwait(); 449 if (c == '\r') 450 c = '\n'; /* console input is always ICRNL */ 451 return (c); 452} 453 454int 455cncheckc(void) 456{ 457 struct cn_device *cnd; 458 struct consdev *cn; 459 int c; 460 461 if (cn_mute) 462 return (-1); 463 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 464 cn = cnd->cnd_cn; 465 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 466 c = cn->cn_ops->cn_getc(cn); 467 if (c != -1) 468 return (c); 469 } 470 } 471 return (-1); 472} 473 474void 475cngets(char *cp, size_t size, int visible) 476{ 477 char *lp, *end; 478 int c; 479 480 cngrab(); 481 482 lp = cp; 483 end = cp + size - 1; 484 for (;;) { 485 c = cngetc() & 0177; 486 switch (c) { 487 case '\n': 488 case '\r': 489 cnputc(c); 490 *lp = '\0'; 491 cnungrab(); 492 return; 493 case '\b': 494 case '\177': 495 if (lp > cp) { 496 if (visible) 497 cnputs("\b \b"); 498 lp--; 499 } 500 continue; 501 case '\0': 502 continue; 503 default: 504 if (lp < end) { 505 switch (visible) { 506 case GETS_NOECHO: 507 break; 508 case GETS_ECHOPASS: 509 cnputc('*'); 510 break; 511 default: 512 cnputc(c); 513 break; 514 } 515 *lp++ = c; 516 } 517 } 518 } 519} 520 521void 522cnputc(int c) 523{ 524 struct cn_device *cnd; 525 struct consdev *cn; 526 const char *cp; 527 528#ifdef EARLY_PRINTF 529 if (early_putc != NULL) { 530 if (c == '\n') 531 early_putc('\r'); 532 early_putc(c); 533 return; 534 } 535#endif 536 537 if (cn_mute || c == '\0') 538 return; 539 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 540 cn = cnd->cnd_cn; 541 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 542 if (c == '\n') 543 cn->cn_ops->cn_putc(cn, '\r'); 544 cn->cn_ops->cn_putc(cn, c); 545 } 546 } 547 if (console_pausing && c == '\n' && !kdb_active) { 548 for (cp = console_pausestr; *cp != '\0'; cp++) 549 cnputc(*cp); 550 cngrab(); 551 if (cngetc() == '.') 552 console_pausing = false; 553 cnungrab(); 554 cnputc('\r'); 555 for (cp = console_pausestr; *cp != '\0'; cp++) 556 cnputc(' '); 557 cnputc('\r'); 558 } 559} 560 561void 562cnputsn(const char *p, size_t n) 563{ 564 size_t i; 565 bool unlock_reqd = false; 566 567 if (mtx_initialized(&cnputs_mtx)) { 568 /* 569 * NOTE: Debug prints and/or witness printouts in 570 * console driver clients can cause the "cnputs_mtx" 571 * mutex to recurse. Simply return if that happens. 572 */ 573 if (mtx_owned(&cnputs_mtx)) 574 return; 575 mtx_lock_spin(&cnputs_mtx); 576 unlock_reqd = true; 577 } 578 579 for (i = 0; i < n; i++) 580 cnputc(p[i]); 581 582 if (unlock_reqd) 583 mtx_unlock_spin(&cnputs_mtx); 584} 585 586void 587cnputs(const char *p) 588{ 589 cnputsn(p, strlen(p)); 590} 591 592static unsigned int consmsgbuf_size = 65536; 593SYSCTL_UINT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RWTUN, &consmsgbuf_size, 594 0, "Console tty buffer size"); 595 596/* 597 * Redirect console output to a tty. 598 */ 599int 600constty_set(struct tty *tp) 601{ 602 int size = consmsgbuf_size; 603 void *buf = NULL; 604 605 tty_assert_locked(tp); 606 if (constty == tp) 607 return (0); 608 if (constty != NULL) 609 return (EBUSY); 610 611 if (consbuf == NULL) { 612 tty_unlock(tp); 613 buf = malloc(size, M_TTYCONS, M_WAITOK); 614 tty_lock(tp); 615 } 616 mtx_lock(&constty_mtx); 617 if (constty != NULL) { 618 mtx_unlock(&constty_mtx); 619 free(buf, M_TTYCONS); 620 return (EBUSY); 621 } 622 if (consbuf == NULL) { 623 consbuf = buf; 624 msgbuf_init(&consmsgbuf, buf, size); 625 } else 626 free(buf, M_TTYCONS); 627 constty = tp; 628 mtx_unlock(&constty_mtx); 629 630 callout_init_mtx(&conscallout, tty_getlock(tp), 0); 631 constty_timeout(tp); 632 return (0); 633} 634 635/* 636 * Disable console redirection to a tty. 637 */ 638int 639constty_clear(struct tty *tp) 640{ 641 int c; 642 643 tty_assert_locked(tp); 644 if (constty != tp) 645 return (ENXIO); 646 callout_stop(&conscallout); 647 mtx_lock(&constty_mtx); 648 constty = NULL; 649 mtx_unlock(&constty_mtx); 650 while ((c = msgbuf_getchar(&consmsgbuf)) != -1) 651 cnputc(c); 652 /* We never free consbuf because it can still be in use. */ 653 return (0); 654} 655 656/* Times per second to check for pending console tty messages. */ 657static int constty_wakeups_per_second = 15; 658SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, 659 &constty_wakeups_per_second, 0, 660 "Times per second to check for pending console tty messages"); 661 662static void 663constty_timeout(void *arg) 664{ 665 struct tty *tp = arg; 666 int c; 667 668 tty_assert_locked(tp); 669 while ((c = msgbuf_getchar(&consmsgbuf)) != -1) { 670 if (tty_putchar(tp, c) < 0) { 671 constty_clear(tp); 672 return; 673 } 674 } 675 callout_reset_sbt(&conscallout, SBT_1S / constty_wakeups_per_second, 676 0, constty_timeout, tp, C_PREL(1)); 677} 678 679/* 680 * Sysbeep(), if we have hardware for it 681 */ 682 683#ifdef HAS_TIMER_SPKR 684 685static bool beeping; 686static struct callout beeping_timer; 687 688static void 689sysbeepstop(void *chan) 690{ 691 692 timer_spkr_release(); 693 beeping = false; 694} 695 696int 697sysbeep(int pitch, sbintime_t duration) 698{ 699 700 if (timer_spkr_acquire()) { 701 if (!beeping) { 702 /* Something else owns it. */ 703 return (EBUSY); 704 } 705 } 706 timer_spkr_setfreq(pitch); 707 if (!beeping) { 708 beeping = true; 709 callout_reset_sbt(&beeping_timer, duration, 0, sysbeepstop, 710 NULL, C_PREL(5)); 711 } 712 return (0); 713} 714 715static void 716sysbeep_init(void *unused) 717{ 718 719 callout_init(&beeping_timer, 1); 720} 721SYSINIT(sysbeep, SI_SUB_SOFTINTR, SI_ORDER_ANY, sysbeep_init, NULL); 722#else 723 724/* 725 * No hardware, no sound 726 */ 727 728int 729sysbeep(int pitch __unused, sbintime_t duration __unused) 730{ 731 732 return (ENODEV); 733} 734 735#endif 736 737/* 738 * Temporary support for sc(4) to vt(4) transition. 739 */ 740static char vty_name[16]; 741SYSCTL_STRING(_kern, OID_AUTO, vty, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, vty_name, 742 0, "Console vty driver"); 743 744int 745vty_enabled(unsigned vty) 746{ 747 static unsigned vty_selected = 0; 748 749 if (vty_selected == 0) { 750 TUNABLE_STR_FETCH("kern.vty", vty_name, sizeof(vty_name)); 751 do { 752#if defined(DEV_SC) 753 if (strcmp(vty_name, "sc") == 0) { 754 vty_selected = VTY_SC; 755 break; 756 } 757#endif 758#if defined(DEV_VT) 759 if (strcmp(vty_name, "vt") == 0) { 760 vty_selected = VTY_VT; 761 break; 762 } 763#endif 764#if defined(DEV_VT) 765 vty_selected = VTY_VT; 766#elif defined(DEV_SC) 767 vty_selected = VTY_SC; 768#endif 769 } while (0); 770 771 if (vty_selected == VTY_VT) 772 strcpy(vty_name, "vt"); 773 else if (vty_selected == VTY_SC) 774 strcpy(vty_name, "sc"); 775 } 776 return ((vty_selected & vty) != 0); 777} 778