Let the allocation of registers be done by compilers nowadays. The average
[dragonfly.git] / sys / kern / tty_cons.c
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. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *      from: @(#)cons.c        7.2 (Berkeley) 5/9/91
39  * $FreeBSD: src/sys/kern/tty_cons.c,v 1.81.2.4 2001/12/17 18:44:41 guido Exp $
40  * $DragonFly: src/sys/kern/tty_cons.c,v 1.14 2004/09/13 16:22:36 dillon Exp $
41  */
42
43 #include "opt_ddb.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/conf.h>
48 #include <sys/cons.h>
49 #include <sys/kernel.h>
50 #include <sys/proc.h>
51 #include <sys/reboot.h>
52 #include <sys/sysctl.h>
53 #include <sys/tty.h>
54 #include <sys/uio.h>
55 #include <sys/msgport.h>
56 #include <sys/msgport2.h>
57 #include <sys/device.h>
58
59 #include <ddb/ddb.h>
60
61 #include <machine/cpu.h>
62
63 static int cnopen(struct cdevmsg_open *msg);
64 static int cnclose(struct cdevmsg_close *msg);
65 static int cnread(struct cdevmsg_read *msg);
66 static int cnwrite(struct cdevmsg_write *msg);
67 static int cnioctl(struct cdevmsg_ioctl *msg);
68 static int cnpoll(struct cdevmsg_poll *msg);
69 static int cnkqfilter(struct cdevmsg_kqfilter *msg);
70
71 static int console_putport(lwkt_port_t port, lwkt_msg_t lmsg);
72 static int console_interceptport(lwkt_port_t port, lwkt_msg_t lmsg);
73
74 static struct lwkt_port cn_port;        /* console device port */
75 static struct lwkt_port cn_iport;       /* intercept port */
76
77 #define CDEV_MAJOR      0
78 static struct cdevsw cn_cdevsw = {
79         /* name */      "console",
80         /* maj */       CDEV_MAJOR,
81         /* flags */     D_TTY | D_KQFILTER,
82         /* port */      &cn_port,
83         /* clone */     NULL
84 };
85
86 static dev_t    cn_dev_t;
87 static udev_t   cn_udev_t;
88 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
89         &cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
90
91 static int cn_mute;
92
93 int     cons_unavail = 0;       /* XXX:
94                                  * physical console not available for
95                                  * input (i.e., it is in graphics mode)
96                                  */
97
98 static u_char cn_is_open;               /* nonzero if logical console is open */
99 static int openmode, openflag;          /* how /dev/console was openned */
100 static dev_t cn_devfsdev;               /* represents the device private info */
101 static u_char cn_phys_is_open;          /* nonzero if physical device is open */
102        struct consdev *cn_tab;          /* physical console device info */
103 static u_char console_pausing;          /* pause after each line during probe */
104 static char *console_pausestr=
105 "<pause; press any key to proceed to next line or '.' to end pause mode>";
106
107 static lwkt_port_t      cn_fwd_port;
108
109 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
110 SET_DECLARE(cons_set, struct consdev);
111
112 void
113 cninit()
114 {
115         struct consdev *best_cp, *cp, **list;
116
117         /*
118          * Our port intercept
119          */
120         lwkt_initport(&cn_port, NULL);
121         cn_port.mp_putport = console_putport;
122         lwkt_initport(&cn_iport, NULL);
123         cn_iport.mp_putport = console_interceptport;
124
125         /*
126          * Find the first console with the highest priority.
127          */
128         best_cp = NULL;
129         SET_FOREACH(list, cons_set) {
130                 cp = *list;
131                 if (cp->cn_probe == NULL)
132                         continue;
133                 (*cp->cn_probe)(cp);
134                 if (cp->cn_pri > CN_DEAD &&
135                     (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
136                         best_cp = cp;
137         }
138
139         /*
140          * Check if we should mute the console (for security reasons perhaps)
141          * It can be changes dynamically using sysctl kern.consmute
142          * once we are up and going.
143          * 
144          */
145         cn_mute = ((boothowto & (RB_MUTE
146                         |RB_SINGLE
147                         |RB_VERBOSE
148                         |RB_ASKNAME
149                         |RB_CONFIG)) == RB_MUTE);
150         
151         /*
152          * If no console, give up.
153          */
154         if (best_cp == NULL) {
155                 if (cn_tab != NULL && cn_tab->cn_term != NULL)
156                         (*cn_tab->cn_term)(cn_tab);
157                 cn_tab = best_cp;
158                 return;
159         }
160
161         /*
162          * Initialize console, then attach to it.  This ordering allows
163          * debugging using the previous console, if any.
164          */
165         (*best_cp->cn_init)(best_cp);
166         if (cn_tab != NULL && cn_tab != best_cp) {
167                 /* Turn off the previous console.  */
168                 if (cn_tab->cn_term != NULL)
169                         (*cn_tab->cn_term)(cn_tab);
170         }
171         if (boothowto & RB_PAUSE)
172                 console_pausing = 1;
173         cn_tab = best_cp;
174 }
175
176 /*
177  * Hook the open and close functions on the selected device.
178  */
179 void
180 cninit_finish()
181 {
182         if ((cn_tab == NULL) || cn_mute)
183                 return;
184
185         /*
186          * Hook the open and close functions.  XXX bad hack.
187          */
188         if (dev_is_good(cn_tab->cn_dev))
189                 cn_fwd_port = cdevsw_dev_override(cn_tab->cn_dev, &cn_iport);
190         cn_dev_t = cn_tab->cn_dev;
191         cn_udev_t = dev2udev(cn_dev_t);
192         console_pausing = 0;
193 }
194
195 static void
196 cnuninit(void)
197 {
198         if (cn_tab == NULL)
199                 return;
200
201         /*
202          * Unhook the open and close functions.  XXX bad hack
203          */
204         if (cn_fwd_port)
205                 cdevsw_dev_override(cn_tab->cn_dev, cn_fwd_port);
206         cn_fwd_port = NULL;
207         cn_dev_t = NODEV;
208         cn_udev_t = NOUDEV;
209 }
210
211 /*
212  * User has changed the state of the console muting.
213  * This may require us to open or close the device in question.
214  */
215 static int
216 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
217 {
218         int error;
219         int ocn_mute;
220
221         ocn_mute = cn_mute;
222         error = sysctl_handle_int(oidp, &cn_mute, 0, req);
223         if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
224                 if(ocn_mute && !cn_mute) {
225                         /*
226                          * going from muted to unmuted.. open the physical dev 
227                          * if the console has been openned
228                          */
229                         cninit_finish();
230                         if (cn_is_open) {
231                                 /* XXX curproc is not what we want really */
232                                 error = dev_dopen(cn_dev_t, openflag,
233                                                 openmode, curthread);
234                         }
235                         /* if it failed, back it out */
236                         if ( error != 0) cnuninit();
237                 } else if (!ocn_mute && cn_mute) {
238                         /*
239                          * going from unmuted to muted.. close the physical dev 
240                          * if it's only open via /dev/console
241                          */
242                         if (cn_is_open) {
243                                 error = dev_dclose(cn_dev_t, openflag,
244                                                 openmode, curthread);
245                         }
246                         if (error == 0)
247                                 cnuninit();
248                 }
249                 if (error != 0) {
250                         /* 
251                          * back out the change if there was an error
252                          */
253                         cn_mute = ocn_mute;
254                 }
255         }
256         return (error);
257 }
258
259 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
260         0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
261
262 /*
263  * We intercept the OPEN and CLOSE calls on the original device, and
264  * forward the rest through.
265  */
266 static int
267 console_interceptport(lwkt_port_t port, lwkt_msg_t lmsg)
268 {
269         cdevallmsg_t msg = (cdevallmsg_t)lmsg;
270         int error;
271
272         switch(msg->am_lmsg.ms_cmd.cm_op) {
273         case CDEV_CMD_OPEN:
274                 error = cnopen(&msg->am_open);
275                 break;
276         case CDEV_CMD_CLOSE:
277                 error = cnclose(&msg->am_close);
278                 break;
279         default:
280                 error = lwkt_forwardmsg(cn_fwd_port, &msg->am_lmsg);
281                 break;
282         }
283         return(error);
284 }
285
286 /*
287  * This is the port handler for /dev/console.  These functions will basically
288  * past the request through to the actual physical device representing the
289  * console. 
290  *
291  * Note, however, that cnopen() and cnclose() are also called from the mute
292  * code and the intercept code.
293  */
294 static int
295 console_putport(lwkt_port_t port, lwkt_msg_t lmsg)
296 {
297         cdevallmsg_t msg = (cdevallmsg_t)lmsg;
298         int error;
299
300         switch(msg->am_lmsg.ms_cmd.cm_op) {
301         case CDEV_CMD_OPEN:
302                 error = cnopen(&msg->am_open);
303                 break;
304         case CDEV_CMD_CLOSE:
305                 error = cnclose(&msg->am_close);
306                 break;
307         case CDEV_CMD_STRATEGY:
308                 nostrategy(msg->am_strategy.bp);
309                 error = 0;
310                 break;
311         case CDEV_CMD_IOCTL:
312                 error = cnioctl(&msg->am_ioctl);
313                 break;
314         case CDEV_CMD_DUMP:
315                 error = nodump(msg->am_dump.msg.dev, 0, 0, 0);
316                 break;
317         case CDEV_CMD_PSIZE:
318                 error = nopsize(msg->am_psize.msg.dev);
319                 break;
320         case CDEV_CMD_READ:
321                 error = cnread(&msg->am_read);
322                 break;
323         case CDEV_CMD_WRITE:
324                 error = cnwrite(&msg->am_write);
325                 break;
326         case CDEV_CMD_POLL:
327                 error = cnpoll(&msg->am_poll);
328                 break;
329         case CDEV_CMD_KQFILTER:
330                 error = cnkqfilter(&msg->am_kqfilter);
331                 break;
332         case CDEV_CMD_MMAP:
333                 error = nommap(msg->am_mmap.msg.dev,
334                                 msg->am_mmap.offset,
335                                 msg->am_mmap.nprot);
336                 break;
337         default:
338                 error = ENODEV;
339                 break;
340         }
341         return(error);
342 }
343
344 /*
345  * cnopen() is called as a port intercept function (dev will be that of the
346  * actual physical device representing our console), and also called from
347  * the muting code and from the /dev/console switch (dev will have the
348  * console's cdevsw).
349  */
350 static int
351 cnopen(struct cdevmsg_open *msg)
352 {
353         dev_t dev = msg->msg.dev;
354         int flag = msg->oflags;
355         int mode = msg->devtype;
356         dev_t cndev, physdev;
357         int retval = 0;
358
359         if (cn_tab == NULL || cn_fwd_port == NULL)
360                 return (0);
361         cndev = cn_tab->cn_dev;
362         physdev = (major(dev) == major(cndev) ? dev : cndev);
363
364         /*
365          * If mute is active, then non console opens don't get here
366          * so we don't need to check for that. They bypass this and go
367          * straight to the device.
368          *
369          * XXX at the moment we assume that the port forwarding function
370          * is synchronous for open.
371          */
372         if (!cn_mute) {
373                 msg->msg.dev = physdev;
374                 retval = lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg);
375         }
376         if (retval == 0) {
377                 /* 
378                  * check if we openned it via /dev/console or 
379                  * via the physical entry (e.g. /dev/sio0).
380                  */
381                 if (dev == cndev)
382                         cn_phys_is_open = 1;
383                 else if (physdev == cndev) {
384                         openmode = mode;
385                         openflag = flag;
386                         cn_is_open = 1;
387                 }
388                 dev->si_tty = physdev->si_tty;
389         }
390         return (retval);
391 }
392
393 /*
394  * cnclose() is called as a port intercept function (dev will be that of the
395  * actual physical device representing our console), and also called from
396  * the muting code and from the /dev/console switch (dev will have the
397  * console's cdevsw).
398  */
399 static int
400 cnclose(struct cdevmsg_close *msg)
401 {
402         dev_t dev = msg->msg.dev;
403         dev_t cndev;
404         struct tty *cn_tp;
405
406         if (cn_tab == NULL || cn_fwd_port == NULL)
407                 return (0);
408         cndev = cn_tab->cn_dev;
409         cn_tp = cndev->si_tty;
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 (major(dev) != major(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_port) {
435                 msg->msg.dev = dev;
436                 return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
437         }
438         return (0);
439 }
440
441 /*
442  * The following functions are dispatched solely from the /dev/console
443  * port switch.  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
448 cnread(struct cdevmsg_read *msg)
449 {
450         if (cn_tab == NULL || cn_fwd_port == NULL)
451                 return (0);
452         msg->msg.dev = cn_tab->cn_dev;
453         return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
454 }
455
456 static int
457 cnwrite(struct cdevmsg_write *msg)
458 {
459         struct uio *uio = msg->uio;
460         dev_t dev;
461
462         if (cn_tab == NULL || cn_fwd_port == 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         msg->msg.dev = dev;
472         return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
473 }
474
475 static int
476 cnioctl(struct cdevmsg_ioctl *msg)
477 {
478         u_long cmd = msg->cmd;
479         int error;
480
481         if (cn_tab == NULL || cn_fwd_port == NULL)
482                 return (0);
483         KKASSERT(msg->td->td_proc != NULL);
484         /*
485          * Superuser can always use this to wrest control of console
486          * output from the "virtual" console.
487          */
488         if (cmd == TIOCCONS && constty) {
489                 error = suser(msg->td);
490                 if (error)
491                         return (error);
492                 constty = NULL;
493                 return (0);
494         }
495         msg->msg.dev = cn_tab->cn_dev;
496         return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
497 }
498
499 static int
500 cnpoll(struct cdevmsg_poll *msg)
501 {
502         if ((cn_tab == NULL) || cn_mute || cn_fwd_port == NULL)
503                 return (1);
504         msg->msg.dev = cn_tab->cn_dev;
505         return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
506 }
507
508 static int
509 cnkqfilter(struct cdevmsg_kqfilter *msg)
510 {
511         if ((cn_tab == NULL) || cn_mute || cn_fwd_port == NULL)
512                 return (1);
513         msg->msg.dev = cn_tab->cn_dev;
514         return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
515 }
516
517 /*
518  * These synchronous functions are primarily used the kernel needs to 
519  * access the keyboard (e.g. when running the debugger), or output data
520  * directly to the console.
521  */
522 int
523 cngetc(void)
524 {
525         int c;
526         if ((cn_tab == NULL) || cn_mute)
527                 return (-1);
528         c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
529         if (c == '\r') c = '\n'; /* console input is always ICRNL */
530         return (c);
531 }
532
533 int
534 cncheckc(void)
535 {
536         if ((cn_tab == NULL) || cn_mute)
537                 return (-1);
538         return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
539 }
540
541 void
542 cnputc(int c)
543 {
544         char *cp;
545
546         if ((cn_tab == NULL) || cn_mute)
547                 return;
548         if (c) {
549                 if (c == '\n')
550                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
551                 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
552 #ifdef DDB
553                 if (console_pausing && !db_active && (c == '\n')) {
554 #else
555                 if (console_pausing && (c == '\n')) {
556 #endif
557                         for(cp=console_pausestr; *cp != '\0'; cp++)
558                             (*cn_tab->cn_putc)(cn_tab->cn_dev, *cp);
559                         if (cngetc() == '.')
560                                 console_pausing = 0;
561                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
562                         for(cp=console_pausestr; *cp != '\0'; cp++)
563                             (*cn_tab->cn_putc)(cn_tab->cn_dev, ' ');
564                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
565                 }
566         }
567 }
568
569 void
570 cndbctl(int on)
571 {
572         static int refcount;
573
574         if (cn_tab == NULL)
575                 return;
576         if (!on)
577                 refcount--;
578         if (refcount == 0 && cn_tab->cn_dbctl != NULL)
579                 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on);
580         if (on)
581                 refcount++;
582 }
583
584 static void
585 cn_drvinit(void *unused)
586 {
587         cdevsw_add(&cn_cdevsw, 0, 0);
588         cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL,
589                                 0600, "console");
590 }
591
592 SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)