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