xref: /dragonfly/sys/kern/tty_cons.c (revision 857fcb57)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1991 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *	from: @(#)cons.c	7.2 (Berkeley) 5/9/91
35  * $FreeBSD: src/sys/kern/tty_cons.c,v 1.81.2.4 2001/12/17 18:44:41 guido Exp $
36  */
37 
38 #include "opt_ddb.h"
39 #include "opt_comconsole.h"
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/caps.h>
44 #include <sys/conf.h>
45 #include <sys/cons.h>
46 #include <sys/kernel.h>
47 #include <sys/proc.h>
48 #include <sys/caps.h>
49 #include <sys/reboot.h>
50 #include <sys/sysctl.h>
51 #include <sys/tty.h>
52 #include <sys/uio.h>
53 #include <sys/msgport.h>
54 #include <sys/msgport2.h>
55 #include <sys/device.h>
56 
57 #include <ddb/ddb.h>
58 
59 #include <machine/cpu.h>
60 
61 static d_open_t cnopen;
62 static d_close_t cnclose;
63 static d_read_t cnread;
64 static d_write_t cnwrite;
65 static d_ioctl_t cnioctl;
66 static d_kqfilter_t cnkqfilter;
67 
68 static int cnintercept(struct dev_generic_args *ap);
69 
70 #define	CDEV_MAJOR	0
71 static struct dev_ops cn_ops = {
72 	{ "console", 0, D_TTY | D_MPSAFE },
73 	.d_open =	cnopen,
74 	.d_close =	cnclose,
75 	.d_read =	cnread,
76 	.d_write =	cnwrite,
77 	.d_ioctl =	cnioctl,
78 	.d_kqfilter =	cnkqfilter,
79 };
80 
81 static struct dev_ops cn_iops = {
82 	{ "intercept", 0, D_TTY | D_MPSAFE },
83 	.d_default =    cnintercept
84 };
85 
86 static struct dev_ops *cn_fwd_ops;
87 static cdev_t	cn_dev;
88 
89 //XXX: get this shit out! (alexh)
90 #if 0
91 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
92 	&cn_udev, sizeof cn_udev, "T,udev_t", "");
93 #endif
94 
95 static int cn_mute;
96 
97 #ifdef BREAK_TO_DEBUGGER
98 int	break_to_debugger = 1;		/* CTL-ALT-ESC on system keyboard */
99 #else
100 int	break_to_debugger = 0;
101 #endif
102 TUNABLE_INT("kern.break_to_debugger", &break_to_debugger);
103 SYSCTL_INT(_kern, OID_AUTO, break_to_debugger, CTLFLAG_RW,
104 	&break_to_debugger, 0, "");
105 
106 #ifdef ALT_BREAK_TO_DEBUGGER
107 int	alt_break_to_debugger = 1;	/* CR ~ ^B on serial port */
108 #else
109 int	alt_break_to_debugger = 0;
110 #endif
111 TUNABLE_INT("kern.alt_break_to_debugger", &alt_break_to_debugger);
112 SYSCTL_INT(_kern, OID_AUTO, alt_break_to_debugger, CTLFLAG_RW,
113 	&alt_break_to_debugger, 0, "");
114 
115 int	cons_unavail = 0;	/* XXX:
116 				 * physical console not available for
117 				 * input (i.e., it is in graphics mode)
118 				 */
119 int	sysbeep_enable = 1;
120 
121 static u_char cn_is_open;		/* nonzero if logical console is open */
122 static int openmode, openflag;		/* how /dev/console was openned */
123 static cdev_t cn_devfsdev;		/* represents the device private info */
124 static u_char cn_phys_is_open;		/* nonzero if physical device is open */
125 static u_char console_pausing;		/* pause after each line during probe */
126 static char *console_pausestr=
127 "<pause; press any key to proceed to next line or '.' to end pause mode>";
128 
129 struct consdev *cn_tab;		/* physical console device info */
130 struct consdev *gdb_tab;	/* physical gdb debugger device info */
131 
132 SYSCTL_INT(_kern, OID_AUTO, sysbeep_enable, CTLFLAG_RW, &sysbeep_enable, 0, "");
133 static uint32_t console_rdev;
134 SYSCTL_INT(_kern, OID_AUTO, console_rdev, CTLFLAG_RW,
135 	&console_rdev, 0, "");
136 
137 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
138 SET_DECLARE(cons_set, struct consdev);
139 
140 void
cninit(void)141 cninit(void)
142 {
143 	struct consdev *best_cp, *cp, **list;
144 
145 	/*
146 	 * Workaround for token acquisition and releases during the
147 	 * console init.  For some reason if lwkt_gettoken()'s mpcount
148 	 * optimization is turned off the console init blows up.  It
149 	 * might be trying to kprintf() something in the middle of
150 	 * its init.
151 	 */
152 	lwkt_gettoken(&tty_token);
153 	lwkt_gettoken(&vga_token);
154 
155 	/*
156 	 * Check if we should mute the console (for security reasons perhaps)
157 	 * It can be changes dynamically using sysctl kern.consmute
158 	 * once we are up and going.
159 	 *
160 	 */
161 	cn_mute = ((boothowto & (RB_MUTE
162 			|RB_SINGLE
163 			|RB_VERBOSE
164 			|RB_ASKNAME)) == RB_MUTE);
165 
166 	/*
167 	 * Find the first console with the highest priority.
168 	 */
169 	best_cp = NULL;
170 	SET_FOREACH(list, cons_set) {
171 		cp = *list;
172 		if (cp->cn_probe == NULL)
173 			continue;
174 		(*cp->cn_probe)(cp);
175 		if (cp->cn_pri > CN_DEAD && cp->cn_probegood &&
176 		    (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
177 			best_cp = cp;
178 	}
179 
180 	/*
181 	 * If no console, give up.
182 	 */
183 	if (best_cp == NULL) {
184 		if (cn_tab != NULL && cn_tab->cn_term != NULL)
185 			(*cn_tab->cn_term)(cn_tab);
186 		goto done;
187 	}
188 
189 	/*
190 	 * Initialize console, then attach to it.  This ordering allows
191 	 * debugging using the previous console, if any.
192 	 */
193 	(*best_cp->cn_init)(best_cp);
194 	if (cn_tab != NULL && cn_tab != best_cp) {
195 		/* Turn off the previous console.  */
196 		if (cn_tab->cn_term != NULL)
197 			(*cn_tab->cn_term)(cn_tab);
198 	}
199 	if (boothowto & RB_PAUSE)
200 		console_pausing = 1;
201 done:
202 	cn_tab = best_cp;
203 
204 	/*
205 	 * We can safely release the token after the init is done.
206 	 * Also assert that the mpcount is still correct or otherwise
207 	 * the SMP/AP boot will blow up on us.
208 	 */
209 	lwkt_reltoken(&vga_token);
210 	lwkt_reltoken(&tty_token);
211 }
212 
213 
214 /*
215  * Hook the open and close functions on the selected device.
216  */
217 void
cninit_finish(void)218 cninit_finish(void)
219 {
220 	if ((cn_tab == NULL) || cn_mute)
221 		return;
222 	if (cn_tab->cn_dev == NULL) {
223 		cn_tab->cn_init_fini(cn_tab);
224 		if (cn_tab->cn_dev == NULL) {
225 			kprintf("Unable to hook console! cn_tab %p\n", cn_tab);
226 			return;
227 		}
228 	}
229 
230 	cn_fwd_ops = dev_ops_intercept(cn_tab->cn_dev, &cn_iops);
231 	cn_dev = cn_tab->cn_dev;
232 	if (cn_dev) {
233 		console_rdev = makeudev(cn_dev->si_umajor,
234 					(cn_dev->si_uminor == 255 ?
235 					    0 : cn_dev->si_uminor));
236 	} else {
237 		console_rdev = 0;
238 	}
239 	console_pausing = 0;
240 }
241 
242 static void
cnuninit(void)243 cnuninit(void)
244 {
245 	if (cn_tab == NULL)
246 		return;
247 	if (cn_fwd_ops)
248 		dev_ops_restore(cn_tab->cn_dev, cn_fwd_ops);
249 	cn_fwd_ops = NULL;
250 	cn_dev = NULL;
251 }
252 
253 
254 /*
255  * User has changed the state of the console muting.
256  * This may require us to open or close the device in question.
257  */
258 static int
sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)259 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
260 {
261 	int error;
262 	int ocn_mute;
263 
264 	ocn_mute = cn_mute;
265 	error = sysctl_handle_int(oidp, &cn_mute, 0, req);
266 	if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
267 		if(ocn_mute && !cn_mute) {
268 			/*
269 			 * going from muted to unmuted.. open the physical dev
270 			 * if the console has been openned
271 			 */
272 			cninit_finish();
273 			if (cn_is_open) {
274 				/* XXX curproc is not what we want really */
275 				error = dev_dopen(cn_dev, openflag, openmode,
276 						  curproc->p_ucred, NULL, NULL);
277 			}
278 			/* if it failed, back it out */
279 			if ( error != 0) cnuninit();
280 		} else if (!ocn_mute && cn_mute) {
281 			/*
282 			 * going from unmuted to muted.. close the physical dev
283 			 * if it's only open via /dev/console
284 			 */
285 			if (cn_is_open) {
286 				error = dev_dclose(cn_dev, openflag,
287 						   openmode, NULL);
288 			}
289 			if (error == 0)
290 				cnuninit();
291 		}
292 		if (error != 0) {
293 			/*
294 	 		 * back out the change if there was an error
295 			 */
296 			cn_mute = ocn_mute;
297 		}
298 	}
299 	return (error);
300 }
301 
302 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
303 	0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
304 
305 
306 /*
307  * We intercept the OPEN and CLOSE calls on the original device, and
308  * forward the rest through.
309  */
310 static int
cnintercept(struct dev_generic_args * ap)311 cnintercept(struct dev_generic_args *ap)
312 {
313 	int error;
314 
315 	if (ap->a_desc == &dev_open_desc) {
316 		error = cnopen((struct dev_open_args *)ap);
317 	} else if (ap->a_desc == &dev_close_desc) {
318 		error = cnclose((struct dev_close_args *)ap);
319 	} else if (cn_fwd_ops) {
320 		error = dev_doperate_ops(cn_fwd_ops, ap);
321 	} else {
322 		error = ENXIO;
323 	}
324 	return (error);
325 }
326 
327 /*
328  * cnopen() is called as an intercept function (dev will be that of the
329  * actual physical device representing our console), and also called from
330  * the muting code and from the /dev/console switch (dev will have the
331  * console's cdevsw).
332  */
333 static int
cnopen(struct dev_open_args * ap)334 cnopen(struct dev_open_args *ap)
335 {
336 	cdev_t dev = ap->a_head.a_dev;
337 	int flag = ap->a_oflags;
338 	int mode = ap->a_devtype;
339 	cdev_t cndev;
340 	cdev_t physdev;
341 	int retval = 0;
342 
343 	/*
344 	 * Disallow access to disk volumes if RESTRICTEDROOT
345 	 */
346 	if (caps_priv_check_self(SYSCAP_RESTRICTEDROOT))
347 		return (EPERM);
348 
349 	if (cn_tab == NULL || cn_fwd_ops == NULL)
350 		return (0);
351 
352 	cndev = cn_tab->cn_dev;		/* actual physical device */
353 	physdev = (dev == cn_devfsdev) ? cndev : dev;
354 
355 	/*
356 	 * If mute is active, then non console opens don't get here
357 	 * so we don't need to check for that. They bypass this and go
358 	 * straight to the device.
359 	 *
360 	 * It is important to note that due to our intercept and the fact
361 	 * that we might be called via the original (intercepted) device,
362 	 * the original device's ops may point to us, so to avoid an
363 	 * infinite recursion we have to forward through cn_fwd_ops.
364 	 * This is a severe hack that really needs to be fixed XXX.
365 	 *
366 	 * XXX at the moment we assume that the port forwarding function
367 	 * is synchronous for open.
368 	 */
369 	if (!cn_mute) {
370 		ap->a_head.a_dev = physdev;
371 		retval = dev_doperate_ops(cn_fwd_ops, &ap->a_head);
372 	}
373 	if (retval == 0) {
374 		/*
375 		 * check if we openned it via /dev/console or
376 		 * via the physical entry (e.g. /dev/sio0).
377 		 */
378 		if (dev == cndev) {
379 			cn_phys_is_open = 1;
380 		} else if (physdev == cndev) {
381 			openmode = mode;
382 			openflag = flag;
383 			cn_is_open = 1;
384 		}
385 		dev->si_tty = cndev->si_tty;
386 	}
387 	return (retval);
388 }
389 
390 /*
391  * cnclose() is called as a port intercept function (dev will be that of the
392  * actual physical device representing our console), and also called from
393  * the muting code and from the /dev/console switch (dev will have the
394  * console's cdevsw).
395  */
396 static int
cnclose(struct dev_close_args * ap)397 cnclose(struct dev_close_args *ap)
398 {
399 	struct tty *cn_tp;
400 	cdev_t cndev;
401 	cdev_t physdev;
402 	cdev_t dev = ap->a_head.a_dev;
403 
404 	if (cn_tab == NULL || cn_fwd_ops == NULL)
405 		return(0);
406 	cndev = cn_tab->cn_dev;
407 	cn_tp = cndev->si_tty;
408 	physdev = (dev == cn_devfsdev) ? cndev : dev;
409 
410 	/*
411 	 * act appropriatly depending on whether it's /dev/console
412 	 * or the pysical device (e.g. /dev/sio) that's being closed.
413 	 * in either case, don't actually close the device unless
414 	 * both are closed.
415 	 */
416 	if (dev == cndev) {
417 		/* the physical device is about to be closed */
418 		cn_phys_is_open = 0;
419 		if (cn_is_open) {
420 			if (cn_tp) {
421 				/* perform a ttyhalfclose() */
422 				/* reset session and proc group */
423 				ttyclearsession(cn_tp);
424 			}
425 			return(0);
426 		}
427 	} else if (physdev == cndev) {
428 		/* the logical console is about to be closed */
429 		cn_is_open = 0;
430 		if (cn_phys_is_open)
431 			return(0);
432 		dev = cndev;
433 	}
434 	if (cn_fwd_ops) {
435 		ap->a_head.a_dev = dev;
436 		return (dev_doperate_ops(cn_fwd_ops, &ap->a_head));
437 	}
438 	return (0);
439 }
440 
441 /*
442  * The following functions are dispatched solely from the /dev/console
443  * device.  Their job is primarily to forward the request through.
444  * If the console is not attached to anything then write()'s are sunk
445  * to null and reads return 0 (mostly).
446  */
447 static int
cnread(struct dev_read_args * ap)448 cnread(struct dev_read_args *ap)
449 {
450 	if (cn_tab == NULL || cn_fwd_ops == NULL)
451 		return (0);
452 	ap->a_head.a_dev = cn_tab->cn_dev;
453 	return (dev_doperate(&ap->a_head));
454 }
455 
456 static int
cnwrite(struct dev_write_args * ap)457 cnwrite(struct dev_write_args *ap)
458 {
459 	struct uio *uio = ap->a_uio;
460 	cdev_t dev;
461 
462 	if (cn_tab == NULL || cn_fwd_ops == NULL) {
463 		uio->uio_resid = 0; /* dump the data */
464 		return (0);
465 	}
466 	if (constty)
467 		dev = constty->t_dev;
468 	else
469 		dev = cn_tab->cn_dev;
470 	log_console(uio);
471 	ap->a_head.a_dev = dev;
472 	return (dev_doperate(&ap->a_head));
473 }
474 
475 static int
cnioctl(struct dev_ioctl_args * ap)476 cnioctl(struct dev_ioctl_args *ap)
477 {
478 	int error;
479 
480 	if (cn_tab == NULL || cn_fwd_ops == NULL)
481 		return (0);
482 	KKASSERT(curproc != NULL);
483 	/*
484 	 * Superuser can always use this to wrest control of console
485 	 * output from the "virtual" console.
486 	 */
487 	if (ap->a_cmd == TIOCCONS && constty) {
488 		if (ap->a_cred) {
489 			error = caps_priv_check(ap->a_cred,
490 						SYSCAP_RESTRICTEDROOT);
491 			if (error)
492 				return (error);
493 		}
494 		constty = NULL;
495 		return (0);
496 	}
497 	ap->a_head.a_dev = cn_tab->cn_dev;
498 	return (dev_doperate(&ap->a_head));
499 }
500 
501 static int
cnkqfilter(struct dev_kqfilter_args * ap)502 cnkqfilter(struct dev_kqfilter_args *ap)
503 {
504 	if ((cn_tab == NULL) || cn_mute || cn_fwd_ops == NULL)
505 		return (1);
506 	ap->a_head.a_dev = cn_tab->cn_dev;
507 	return (dev_doperate(&ap->a_head));
508 }
509 
510 /*
511  * These synchronous functions are primarily used the kernel needs to
512  * access the keyboard (e.g. when running the debugger), or output data
513  * directly to the console.
514  */
515 int
cngetc(void)516 cngetc(void)
517 {
518 	int c;
519 	if ((cn_tab == NULL) || cn_mute)
520 		return (-1);
521 	c = (*cn_tab->cn_getc)(cn_tab->cn_private);
522 	if (c == '\r') c = '\n'; /* console input is always ICRNL */
523 	return (c);
524 }
525 
526 int
cncheckc(void)527 cncheckc(void)
528 {
529 	if ((cn_tab == NULL) || cn_mute)
530 		return (-1);
531 	return ((*cn_tab->cn_checkc)(cn_tab->cn_private));
532 }
533 
534 void
cnpoll(int on)535 cnpoll(int on)
536 {
537 	if ((cn_tab == NULL) || cn_mute)
538 		return;
539 	if (cn_tab->cn_poll)
540 		((*cn_tab->cn_poll)(cn_tab->cn_private, on));
541 }
542 
543 void
cnputc(int c)544 cnputc(int c)
545 {
546 	char *cp;
547 
548 	if ((cn_tab == NULL) || cn_mute)
549 		return;
550 	if (c) {
551 		if (c == '\n')
552 			(*cn_tab->cn_putc)(cn_tab->cn_private, '\r');
553 		(*cn_tab->cn_putc)(cn_tab->cn_private, c);
554 #ifdef DDB
555 		if (console_pausing && !db_active && (c == '\n')) {
556 #else
557 		if (console_pausing && (c == '\n')) {
558 #endif
559 			for(cp=console_pausestr; *cp != '\0'; cp++)
560 			    (*cn_tab->cn_putc)(cn_tab->cn_private, *cp);
561 			if (cngetc() == '.')
562 				console_pausing = 0;
563 			(*cn_tab->cn_putc)(cn_tab->cn_private, '\r');
564 			for(cp=console_pausestr; *cp != '\0'; cp++)
565 			    (*cn_tab->cn_putc)(cn_tab->cn_private, ' ');
566 			(*cn_tab->cn_putc)(cn_tab->cn_private, '\r');
567 		}
568 	}
569 }
570 
571 void
572 cndbctl(int on)
573 {
574 	static int refcount;
575 
576 	if (cn_tab == NULL)
577 		return;
578 	if (!on)
579 		refcount--;
580 	if (refcount == 0 && cn_tab->cn_dbctl != NULL)
581 		(*cn_tab->cn_dbctl)(cn_tab->cn_private, on);
582 	if (on)
583 		refcount++;
584 }
585 
586 static void
587 cn_drvinit(void *unused)
588 {
589 	cn_devfsdev = make_only_devfs_dev(&cn_ops, 0, UID_ROOT, GID_WHEEL,
590 					  0600, "console");
591 }
592 
593 SYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, cn_drvinit, NULL);
594