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 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/lock.h> 48 #include <sys/mutex.h> 49 #include <sys/conf.h> 50 #include <sys/cons.h> 51 #include <sys/fcntl.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/tty.h> 64 #include <sys/uio.h> 65 #include <sys/vnode.h> 66 67 #include <ddb/ddb.h> 68 69 #include <machine/cpu.h> 70 #include <machine/clock.h> 71 72 static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling"); 73 74 struct cn_device { 75 STAILQ_ENTRY(cn_device) cnd_next; 76 struct consdev *cnd_cn; 77 }; 78 79 #define CNDEVPATHMAX 32 80 #define CNDEVTAB_SIZE 4 81 static struct cn_device cn_devtab[CNDEVTAB_SIZE]; 82 static STAILQ_HEAD(, cn_device) cn_devlist = 83 STAILQ_HEAD_INITIALIZER(cn_devlist); 84 85 int cons_avail_mask = 0; /* Bit mask. Each registered low level console 86 * which is currently unavailable for inpit 87 * (i.e., if it is in graphics mode) will have 88 * this bit cleared. 89 */ 90 static int cn_mute; 91 static char *consbuf; /* buffer used by `consmsgbuf' */ 92 static struct callout conscallout; /* callout for outputting to constty */ 93 struct msgbuf consmsgbuf; /* message buffer for console tty */ 94 static u_char console_pausing; /* pause after each line during probe */ 95 static char *console_pausestr= 96 "<pause; press any key to proceed to next line or '.' to end pause mode>"; 97 struct tty *constty; /* pointer to console "window" tty */ 98 static struct mtx cnputs_mtx; /* Mutex for cnputs(). */ 99 static int use_cnputs_mtx = 0; /* != 0 if cnputs_mtx locking reqd. */ 100 101 static void constty_timeout(void *arg); 102 103 static struct consdev cons_consdev; 104 DATA_SET(cons_set, cons_consdev); 105 SET_DECLARE(cons_set, struct consdev); 106 107 void 108 cninit(void) 109 { 110 struct consdev *best_cn, *cn, **list; 111 112 /* 113 * Check if we should mute the console (for security reasons perhaps) 114 * It can be changes dynamically using sysctl kern.consmute 115 * once we are up and going. 116 * 117 */ 118 cn_mute = ((boothowto & (RB_MUTE 119 |RB_SINGLE 120 |RB_VERBOSE 121 |RB_ASKNAME)) == RB_MUTE); 122 123 /* 124 * Find the first console with the highest priority. 125 */ 126 best_cn = NULL; 127 SET_FOREACH(list, cons_set) { 128 cn = *list; 129 cnremove(cn); 130 /* Skip cons_consdev. */ 131 if (cn->cn_ops == NULL) 132 continue; 133 cn->cn_ops->cn_probe(cn); 134 if (cn->cn_pri == CN_DEAD) 135 continue; 136 if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri) 137 best_cn = cn; 138 if (boothowto & RB_MULTIPLE) { 139 /* 140 * Initialize console, and attach to it. 141 */ 142 cn->cn_ops->cn_init(cn); 143 cnadd(cn); 144 } 145 } 146 if (best_cn == NULL) 147 return; 148 if ((boothowto & RB_MULTIPLE) == 0) { 149 best_cn->cn_ops->cn_init(best_cn); 150 cnadd(best_cn); 151 } 152 if (boothowto & RB_PAUSE) 153 console_pausing = 1; 154 /* 155 * Make the best console the preferred console. 156 */ 157 cnselect(best_cn); 158 } 159 160 void 161 cninit_finish() 162 { 163 console_pausing = 0; 164 } 165 166 /* add a new physical console to back the virtual console */ 167 int 168 cnadd(struct consdev *cn) 169 { 170 struct cn_device *cnd; 171 int i; 172 173 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 174 if (cnd->cnd_cn == cn) 175 return (0); 176 for (i = 0; i < CNDEVTAB_SIZE; i++) { 177 cnd = &cn_devtab[i]; 178 if (cnd->cnd_cn == NULL) 179 break; 180 } 181 if (cnd->cnd_cn != NULL) 182 return (ENOMEM); 183 cnd->cnd_cn = cn; 184 if (cn->cn_name[0] == '\0') { 185 /* XXX: it is unclear if/where this print might output */ 186 printf("WARNING: console at %p has no name\n", cn); 187 } 188 STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next); 189 if (STAILQ_FIRST(&cn_devlist) == cnd) 190 ttyconsdev_select(cnd->cnd_cn->cn_name); 191 192 /* Add device to the active mask. */ 193 cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0); 194 195 return (0); 196 } 197 198 void 199 cnremove(struct consdev *cn) 200 { 201 struct cn_device *cnd; 202 int i; 203 204 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 205 if (cnd->cnd_cn != cn) 206 continue; 207 if (STAILQ_FIRST(&cn_devlist) == cnd) 208 ttyconsdev_select(NULL); 209 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 210 cnd->cnd_cn = NULL; 211 212 /* Remove this device from available mask. */ 213 for (i = 0; i < CNDEVTAB_SIZE; i++) 214 if (cnd == &cn_devtab[i]) { 215 cons_avail_mask &= ~(1 << i); 216 break; 217 } 218 #if 0 219 /* 220 * XXX 221 * syscons gets really confused if console resources are 222 * freed after the system has initialized. 223 */ 224 if (cn->cn_term != NULL) 225 cn->cn_ops->cn_term(cn); 226 #endif 227 return; 228 } 229 } 230 231 void 232 cnselect(struct consdev *cn) 233 { 234 struct cn_device *cnd; 235 236 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 237 if (cnd->cnd_cn != cn) 238 continue; 239 if (cnd == STAILQ_FIRST(&cn_devlist)) 240 return; 241 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 242 STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next); 243 ttyconsdev_select(cnd->cnd_cn->cn_name); 244 return; 245 } 246 } 247 248 void 249 cnavailable(struct consdev *cn, int available) 250 { 251 int i; 252 253 for (i = 0; i < CNDEVTAB_SIZE; i++) { 254 if (cn_devtab[i].cnd_cn == cn) 255 break; 256 } 257 if (available) { 258 if (i < CNDEVTAB_SIZE) 259 cons_avail_mask |= (1 << i); 260 cn->cn_flags &= ~CN_FLAG_NOAVAIL; 261 } else { 262 if (i < CNDEVTAB_SIZE) 263 cons_avail_mask &= ~(1 << i); 264 cn->cn_flags |= CN_FLAG_NOAVAIL; 265 } 266 } 267 268 int 269 cnunavailable(void) 270 { 271 272 return (cons_avail_mask == 0); 273 } 274 275 /* 276 * sysctl_kern_console() provides output parseable in conscontrol(1). 277 */ 278 static int 279 sysctl_kern_console(SYSCTL_HANDLER_ARGS) 280 { 281 struct cn_device *cnd; 282 struct consdev *cp, **list; 283 char *p; 284 int delete, error; 285 struct sbuf *sb; 286 287 sb = sbuf_new(NULL, NULL, CNDEVPATHMAX * 2, SBUF_AUTOEXTEND); 288 if (sb == NULL) 289 return (ENOMEM); 290 sbuf_clear(sb); 291 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 292 sbuf_printf(sb, "%s,", cnd->cnd_cn->cn_name); 293 sbuf_printf(sb, "/"); 294 SET_FOREACH(list, cons_set) { 295 cp = *list; 296 if (cp->cn_name[0] != '\0') 297 sbuf_printf(sb, "%s,", cp->cn_name); 298 } 299 sbuf_finish(sb); 300 error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req); 301 if (error == 0 && req->newptr != NULL) { 302 p = sbuf_data(sb); 303 error = ENXIO; 304 delete = 0; 305 if (*p == '-') { 306 delete = 1; 307 p++; 308 } 309 SET_FOREACH(list, cons_set) { 310 cp = *list; 311 if (strcmp(p, cp->cn_name) != 0) 312 continue; 313 if (delete) { 314 cnremove(cp); 315 error = 0; 316 } else { 317 error = cnadd(cp); 318 if (error == 0) 319 cnselect(cp); 320 } 321 break; 322 } 323 } 324 sbuf_delete(sb); 325 return (error); 326 } 327 328 SYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW, 329 0, 0, sysctl_kern_console, "A", "Console device control"); 330 331 /* 332 * User has changed the state of the console muting. 333 * This may require us to open or close the device in question. 334 */ 335 static int 336 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS) 337 { 338 int error; 339 340 error = sysctl_handle_int(oidp, &cn_mute, 0, req); 341 if (error != 0 || req->newptr == NULL) 342 return (error); 343 return (error); 344 } 345 346 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 347 0, sizeof(cn_mute), sysctl_kern_consmute, "I", 348 "State of the console muting"); 349 350 void 351 cngrab() 352 { 353 struct cn_device *cnd; 354 struct consdev *cn; 355 356 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 357 cn = cnd->cnd_cn; 358 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 359 cn->cn_ops->cn_grab(cn); 360 } 361 } 362 363 void 364 cnungrab() 365 { 366 struct cn_device *cnd; 367 struct consdev *cn; 368 369 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 370 cn = cnd->cnd_cn; 371 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 372 cn->cn_ops->cn_ungrab(cn); 373 } 374 } 375 376 /* 377 * Low level console routines. 378 */ 379 int 380 cngetc(void) 381 { 382 int c; 383 384 if (cn_mute) 385 return (-1); 386 while ((c = cncheckc()) == -1) 387 cpu_spinwait(); 388 if (c == '\r') 389 c = '\n'; /* console input is always ICRNL */ 390 return (c); 391 } 392 393 int 394 cncheckc(void) 395 { 396 struct cn_device *cnd; 397 struct consdev *cn; 398 int c; 399 400 if (cn_mute) 401 return (-1); 402 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 403 cn = cnd->cnd_cn; 404 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 405 c = cn->cn_ops->cn_getc(cn); 406 if (c != -1) 407 return (c); 408 } 409 } 410 return (-1); 411 } 412 413 void 414 cngets(char *cp, size_t size, int visible) 415 { 416 char *lp, *end; 417 int c; 418 419 cngrab(); 420 421 lp = cp; 422 end = cp + size - 1; 423 for (;;) { 424 c = cngetc() & 0177; 425 switch (c) { 426 case '\n': 427 case '\r': 428 cnputc(c); 429 *lp = '\0'; 430 cnungrab(); 431 return; 432 case '\b': 433 case '\177': 434 if (lp > cp) { 435 if (visible) 436 cnputs("\b \b"); 437 lp--; 438 } 439 continue; 440 case '\0': 441 continue; 442 default: 443 if (lp < end) { 444 switch (visible) { 445 case GETS_NOECHO: 446 break; 447 case GETS_ECHOPASS: 448 cnputc('*'); 449 break; 450 default: 451 cnputc(c); 452 break; 453 } 454 *lp++ = c; 455 } 456 } 457 } 458 } 459 460 void 461 cnputc(int c) 462 { 463 struct cn_device *cnd; 464 struct consdev *cn; 465 char *cp; 466 467 #ifdef EARLY_PRINTF 468 if (early_putc != NULL) { 469 if (c == '\n') 470 early_putc('\r'); 471 early_putc(c); 472 return; 473 } 474 #endif 475 476 if (cn_mute || c == '\0') 477 return; 478 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 479 cn = cnd->cnd_cn; 480 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 481 if (c == '\n') 482 cn->cn_ops->cn_putc(cn, '\r'); 483 cn->cn_ops->cn_putc(cn, c); 484 } 485 } 486 if (console_pausing && c == '\n' && !kdb_active) { 487 for (cp = console_pausestr; *cp != '\0'; cp++) 488 cnputc(*cp); 489 cngrab(); 490 if (cngetc() == '.') 491 console_pausing = 0; 492 cnungrab(); 493 cnputc('\r'); 494 for (cp = console_pausestr; *cp != '\0'; cp++) 495 cnputc(' '); 496 cnputc('\r'); 497 } 498 } 499 500 void 501 cnputs(char *p) 502 { 503 int c; 504 int unlock_reqd = 0; 505 506 if (use_cnputs_mtx) { 507 mtx_lock_spin(&cnputs_mtx); 508 unlock_reqd = 1; 509 } 510 511 while ((c = *p++) != '\0') 512 cnputc(c); 513 514 if (unlock_reqd) 515 mtx_unlock_spin(&cnputs_mtx); 516 } 517 518 static int consmsgbuf_size = 8192; 519 SYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0, 520 "Console tty buffer size"); 521 522 /* 523 * Redirect console output to a tty. 524 */ 525 void 526 constty_set(struct tty *tp) 527 { 528 int size; 529 530 KASSERT(tp != NULL, ("constty_set: NULL tp")); 531 if (consbuf == NULL) { 532 size = consmsgbuf_size; 533 consbuf = malloc(size, M_TTYCONS, M_WAITOK); 534 msgbuf_init(&consmsgbuf, consbuf, size); 535 callout_init(&conscallout, 0); 536 } 537 constty = tp; 538 constty_timeout(NULL); 539 } 540 541 /* 542 * Disable console redirection to a tty. 543 */ 544 void 545 constty_clear(void) 546 { 547 int c; 548 549 constty = NULL; 550 if (consbuf == NULL) 551 return; 552 callout_stop(&conscallout); 553 while ((c = msgbuf_getchar(&consmsgbuf)) != -1) 554 cnputc(c); 555 free(consbuf, M_TTYCONS); 556 consbuf = NULL; 557 } 558 559 /* Times per second to check for pending console tty messages. */ 560 static int constty_wakeups_per_second = 5; 561 SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, 562 &constty_wakeups_per_second, 0, 563 "Times per second to check for pending console tty messages"); 564 565 static void 566 constty_timeout(void *arg) 567 { 568 int c; 569 570 if (constty != NULL) { 571 tty_lock(constty); 572 while ((c = msgbuf_getchar(&consmsgbuf)) != -1) { 573 if (tty_putchar(constty, c) < 0) { 574 tty_unlock(constty); 575 constty = NULL; 576 break; 577 } 578 } 579 580 if (constty != NULL) 581 tty_unlock(constty); 582 } 583 if (constty != NULL) { 584 callout_reset(&conscallout, hz / constty_wakeups_per_second, 585 constty_timeout, NULL); 586 } else { 587 /* Deallocate the constty buffer memory. */ 588 constty_clear(); 589 } 590 } 591 592 static void 593 cn_drvinit(void *unused) 594 { 595 596 mtx_init(&cnputs_mtx, "cnputs_mtx", NULL, MTX_SPIN | MTX_NOWITNESS); 597 use_cnputs_mtx = 1; 598 } 599 600 SYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL); 601 602 /* 603 * Sysbeep(), if we have hardware for it 604 */ 605 606 #ifdef HAS_TIMER_SPKR 607 608 static int beeping; 609 610 static void 611 sysbeepstop(void *chan) 612 { 613 614 timer_spkr_release(); 615 beeping = 0; 616 } 617 618 int 619 sysbeep(int pitch, int period) 620 { 621 622 if (timer_spkr_acquire()) { 623 if (!beeping) { 624 /* Something else owns it. */ 625 return (EBUSY); 626 } 627 } 628 timer_spkr_setfreq(pitch); 629 if (!beeping) { 630 beeping = period; 631 timeout(sysbeepstop, (void *)NULL, period); 632 } 633 return (0); 634 } 635 636 #else 637 638 /* 639 * No hardware, no sound 640 */ 641 642 int 643 sysbeep(int pitch __unused, int period __unused) 644 { 645 646 return (ENODEV); 647 } 648 649 #endif 650 651