xref: /freebsd/sys/kern/kern_cons.c (revision ab00ac327a66a53edaac95b536b209db3ae2cd9f)
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