The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/tty_cons.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/conf.h>
   44 #include <sys/cons.h>
   45 #include <sys/kernel.h>
   46 #include <sys/proc.h>
   47 #include <sys/priv.h>
   48 #include <sys/reboot.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/tty.h>
   51 #include <sys/uio.h>
   52 #include <sys/msgport.h>
   53 #include <sys/msgport2.h>
   54 #include <sys/device.h>
   55 
   56 #include <ddb/ddb.h>
   57 
   58 #include <machine/cpu.h>
   59 
   60 static d_open_t cnopen;
   61 static d_close_t cnclose;
   62 static d_read_t cnread;
   63 static d_write_t cnwrite;
   64 static d_ioctl_t cnioctl;
   65 static d_kqfilter_t cnkqfilter;
   66 
   67 static int cnintercept(struct dev_generic_args *ap);
   68 
   69 #define CDEV_MAJOR      0
   70 static struct dev_ops cn_ops = {
   71         { "console", 0, D_TTY },
   72         .d_open =       cnopen,
   73         .d_close =      cnclose,
   74         .d_read =       cnread,
   75         .d_write =      cnwrite,
   76         .d_ioctl =      cnioctl,
   77         .d_kqfilter =   cnkqfilter,
   78 };
   79 
   80 static struct dev_ops cn_iops = {
   81         { "intercept", 0, D_TTY },
   82         .d_default =    cnintercept
   83 };
   84 
   85 static struct dev_ops *cn_fwd_ops;
   86 static cdev_t   cn_dev;
   87 
   88 //XXX: get this shit out! (alexh)
   89 #if 0
   90 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
   91         &cn_udev, sizeof cn_udev, "T,udev_t", "");
   92 #endif
   93 
   94 static int cn_mute;
   95 
   96 #ifdef BREAK_TO_DEBUGGER
   97 int     break_to_debugger = 1;
   98 #else
   99 int     break_to_debugger = 0;
  100 #endif
  101 TUNABLE_INT("kern.break_to_debugger", &break_to_debugger);
  102 SYSCTL_INT(_kern, OID_AUTO, break_to_debugger, CTLFLAG_RW,
  103         &break_to_debugger, 0, "");
  104 
  105 #ifdef ALT_BREAK_TO_DEBUGGER
  106 int     alt_break_to_debugger = 1;
  107 #else
  108 int     alt_break_to_debugger = 0;
  109 #endif
  110 TUNABLE_INT("kern.alt_break_to_debugger", &alt_break_to_debugger);
  111 SYSCTL_INT(_kern, OID_AUTO, alt_break_to_debugger, CTLFLAG_RW,
  112         &alt_break_to_debugger, 0, "");
  113 
  114 int     cons_unavail = 0;       /* XXX:
  115                                  * physical console not available for
  116                                  * input (i.e., it is in graphics mode)
  117                                  */
  118 int     sysbeep_enable = 1;
  119 
  120 static u_char cn_is_open;               /* nonzero if logical console is open */
  121 static int openmode, openflag;          /* how /dev/console was openned */
  122 static cdev_t cn_devfsdev;              /* represents the device private info */
  123 static u_char cn_phys_is_open;          /* nonzero if physical device is open */
  124 static u_char console_pausing;          /* pause after each line during probe */
  125 static char *console_pausestr=
  126 "<pause; press any key to proceed to next line or '.' to end pause mode>";
  127 
  128 struct consdev *cn_tab;         /* physical console device info */
  129 struct consdev *gdb_tab;        /* physical gdb debugger device info */
  130 
  131 SYSCTL_INT(_kern, OID_AUTO, sysbeep_enable, CTLFLAG_RW, &sysbeep_enable, 0, "");
  132 
  133 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  134 SET_DECLARE(cons_set, struct consdev);
  135 
  136 void
  137 cninit(void)
  138 {
  139         struct consdev *best_cp, *cp, **list;
  140 
  141         /*
  142          * Workaround for token acquisition and releases during the
  143          * console init.  For some reason if lwkt_gettoken()'s mpcount
  144          * optimization is turned off the console init blows up.  It
  145          * might be trying to kprintf() something in the middle of
  146          * its init.
  147          */
  148         lwkt_gettoken(&tty_token);
  149 
  150         /*
  151          * Check if we should mute the console (for security reasons perhaps)
  152          * It can be changes dynamically using sysctl kern.consmute
  153          * once we are up and going.
  154          *
  155          */
  156         cn_mute = ((boothowto & (RB_MUTE
  157                         |RB_SINGLE
  158                         |RB_VERBOSE
  159                         |RB_ASKNAME
  160                         |RB_CONFIG)) == RB_MUTE);
  161 
  162         /*
  163          * Find the first console with the highest priority.
  164          */
  165         best_cp = NULL;
  166         SET_FOREACH(list, cons_set) {
  167                 cp = *list;
  168                 if (cp->cn_probe == NULL)
  169                         continue;
  170                 (*cp->cn_probe)(cp);
  171                 if (cp->cn_pri > CN_DEAD && cp->cn_probegood &&
  172                     (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
  173                         best_cp = cp;
  174         }
  175 
  176         
  177         /*
  178          * If no console, give up.
  179          */
  180         if (best_cp == NULL) {
  181                 if (cn_tab != NULL && cn_tab->cn_term != NULL)
  182                         (*cn_tab->cn_term)(cn_tab);
  183                 goto done;
  184         }
  185 
  186         /*
  187          * Initialize console, then attach to it.  This ordering allows
  188          * debugging using the previous console, if any.
  189          */
  190         (*best_cp->cn_init)(best_cp);
  191         if (cn_tab != NULL && cn_tab != best_cp) {
  192                 /* Turn off the previous console.  */
  193                 if (cn_tab->cn_term != NULL)
  194                         (*cn_tab->cn_term)(cn_tab);
  195         }
  196         if (boothowto & RB_PAUSE)
  197                 console_pausing = 1;
  198 done:
  199         cn_tab = best_cp;
  200 
  201         /*
  202          * We can safely release the token after the init is done.
  203          * Also assert that the mpcount is still correct or otherwise
  204          * the SMP/AP boot will blow up on us.
  205          */
  206         lwkt_reltoken(&tty_token);
  207 }
  208 
  209 
  210 /*
  211  * Hook the open and close functions on the selected device.
  212  */
  213 void
  214 cninit_finish(void)
  215 {
  216         if ((cn_tab == NULL) || cn_mute)
  217                 return;
  218         if (cn_tab->cn_dev == NULL) {
  219                 cn_tab->cn_init_fini(cn_tab);
  220                 if (cn_tab->cn_dev == NULL) {
  221                         kprintf("Unable to hook console! cn_tab %p\n", cn_tab);
  222                         return;
  223                 }
  224         }
  225 
  226         cn_fwd_ops = dev_ops_intercept(cn_tab->cn_dev, &cn_iops);
  227         cn_dev = cn_tab->cn_dev;
  228         console_pausing = 0;
  229 }
  230 
  231 static void
  232 cnuninit(void)
  233 {
  234         if (cn_tab == NULL)
  235                 return;
  236         if (cn_fwd_ops)
  237                 dev_ops_restore(cn_tab->cn_dev, cn_fwd_ops);
  238         cn_fwd_ops = NULL;
  239         cn_dev = NULL;
  240 }
  241 
  242 
  243 /*
  244  * User has changed the state of the console muting.
  245  * This may require us to open or close the device in question.
  246  */
  247 static int
  248 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
  249 {
  250         int error;
  251         int ocn_mute;
  252 
  253         ocn_mute = cn_mute;
  254         error = sysctl_handle_int(oidp, &cn_mute, 0, req);
  255         if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
  256                 if(ocn_mute && !cn_mute) {
  257                         /*
  258                          * going from muted to unmuted.. open the physical dev 
  259                          * if the console has been openned
  260                          */
  261                         cninit_finish();
  262                         if (cn_is_open) {
  263                                 /* XXX curproc is not what we want really */
  264                                 error = dev_dopen(cn_dev, openflag,
  265                                                 openmode, curproc->p_ucred);
  266                         }
  267                         /* if it failed, back it out */
  268                         if ( error != 0) cnuninit();
  269                 } else if (!ocn_mute && cn_mute) {
  270                         /*
  271                          * going from unmuted to muted.. close the physical dev 
  272                          * if it's only open via /dev/console
  273                          */
  274                         if (cn_is_open) {
  275                                 error = dev_dclose(cn_dev, openflag,
  276                                                    openmode);
  277                         }
  278                         if (error == 0)
  279                                 cnuninit();
  280                 }
  281                 if (error != 0) {
  282                         /* 
  283                          * back out the change if there was an error
  284                          */
  285                         cn_mute = ocn_mute;
  286                 }
  287         }
  288         return (error);
  289 }
  290 
  291 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
  292         0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
  293 
  294 
  295 /*
  296  * We intercept the OPEN and CLOSE calls on the original device, and
  297  * forward the rest through.
  298  */
  299 static int
  300 cnintercept(struct dev_generic_args *ap)
  301 {
  302         int error;
  303 
  304         if (ap->a_desc == &dev_open_desc) {
  305                 error = cnopen((struct dev_open_args *)ap);
  306         } else if (ap->a_desc == &dev_close_desc) {
  307                 error = cnclose((struct dev_close_args *)ap);
  308         } else if (cn_fwd_ops) {
  309                 error = dev_doperate_ops(cn_fwd_ops, ap);
  310         } else {
  311                 error = ENXIO;
  312         }
  313         return (error);
  314 }
  315 
  316 /*
  317  * cnopen() is called as an intercept function (dev will be that of the
  318  * actual physical device representing our console), and also called from
  319  * the muting code and from the /dev/console switch (dev will have the
  320  * console's cdevsw).
  321  */
  322 static int
  323 cnopen(struct dev_open_args *ap)
  324 {
  325         cdev_t dev = ap->a_head.a_dev;
  326         int flag = ap->a_oflags;
  327         int mode = ap->a_devtype;
  328         cdev_t cndev;
  329         cdev_t physdev;
  330         int retval = 0;
  331 
  332         if (cn_tab == NULL || cn_fwd_ops == NULL)
  333                 return (0);
  334 
  335         cndev = cn_tab->cn_dev;         /* actual physical device */
  336         physdev = (dev == cn_devfsdev) ? cndev : dev;
  337 
  338         /*
  339          * If mute is active, then non console opens don't get here
  340          * so we don't need to check for that. They bypass this and go
  341          * straight to the device.
  342          *
  343          * It is important to note that due to our intercept and the fact
  344          * that we might be called via the original (intercepted) device,
  345          * the original device's ops may point to us, so to avoid an
  346          * infinite recursion we have to forward through cn_fwd_ops.
  347          * This is a severe hack that really needs to be fixed XXX.
  348          *
  349          * XXX at the moment we assume that the port forwarding function
  350          * is synchronous for open.
  351          */
  352         if (!cn_mute) {
  353                 ap->a_head.a_dev = physdev;
  354                 retval = dev_doperate_ops(cn_fwd_ops, &ap->a_head);
  355         }
  356         if (retval == 0) {
  357                 /*
  358                  * check if we openned it via /dev/console or
  359                  * via the physical entry (e.g. /dev/sio0).
  360                  */
  361                 if (dev == cndev) {
  362                         cn_phys_is_open = 1;
  363                 } else if (physdev == cndev) {
  364                         openmode = mode;
  365                         openflag = flag;
  366                         cn_is_open = 1;
  367                 }
  368                 dev->si_tty = cndev->si_tty;
  369         }
  370         return (retval);
  371 }
  372 
  373 /*
  374  * cnclose() is called as a port intercept function (dev will be that of the
  375  * actual physical device representing our console), and also called from
  376  * the muting code and from the /dev/console switch (dev will have the
  377  * console's cdevsw).
  378  */
  379 static int
  380 cnclose(struct dev_close_args *ap)
  381 {
  382         struct tty *cn_tp;
  383         cdev_t cndev;
  384         cdev_t physdev;
  385         cdev_t dev = ap->a_head.a_dev;
  386 
  387         if (cn_tab == NULL || cn_fwd_ops == NULL)
  388                 return(0);
  389         cndev = cn_tab->cn_dev;
  390         cn_tp = cndev->si_tty;
  391         physdev = (dev == cn_devfsdev) ? cndev : dev;
  392 
  393         /*
  394          * act appropriatly depending on whether it's /dev/console
  395          * or the pysical device (e.g. /dev/sio) that's being closed.
  396          * in either case, don't actually close the device unless
  397          * both are closed.
  398          */
  399         if (dev == cndev) {
  400                 /* the physical device is about to be closed */
  401                 cn_phys_is_open = 0;
  402                 if (cn_is_open) {
  403                         if (cn_tp) {
  404                                 /* perform a ttyhalfclose() */
  405                                 /* reset session and proc group */
  406                                 ttyclearsession(cn_tp);
  407                         }
  408                         return(0);
  409                 }
  410         } else if (physdev == cndev) {
  411                 /* the logical console is about to be closed */
  412                 cn_is_open = 0;
  413                 if (cn_phys_is_open)
  414                         return(0);
  415                 dev = cndev;
  416         }
  417         if (cn_fwd_ops) {
  418                 ap->a_head.a_dev = dev;
  419                 return (dev_doperate_ops(cn_fwd_ops, &ap->a_head));
  420         }
  421         return (0);
  422 }
  423 
  424 /*
  425  * The following functions are dispatched solely from the /dev/console
  426  * device.  Their job is primarily to forward the request through.
  427  * If the console is not attached to anything then write()'s are sunk
  428  * to null and reads return 0 (mostly).
  429  */
  430 static int
  431 cnread(struct dev_read_args *ap)
  432 {
  433         if (cn_tab == NULL || cn_fwd_ops == NULL)
  434                 return (0);
  435         ap->a_head.a_dev = cn_tab->cn_dev;
  436         return (dev_doperate(&ap->a_head));
  437 }
  438 
  439 static int
  440 cnwrite(struct dev_write_args *ap)
  441 {
  442         struct uio *uio = ap->a_uio;
  443         cdev_t dev;
  444 
  445         if (cn_tab == NULL || cn_fwd_ops == NULL) {
  446                 uio->uio_resid = 0; /* dump the data */
  447                 return (0);
  448         }
  449         if (constty)
  450                 dev = constty->t_dev;
  451         else
  452                 dev = cn_tab->cn_dev;
  453         log_console(uio);
  454         ap->a_head.a_dev = dev;
  455         return (dev_doperate(&ap->a_head));
  456 }
  457 
  458 static int
  459 cnioctl(struct dev_ioctl_args *ap)
  460 {
  461         int error;
  462 
  463         if (cn_tab == NULL || cn_fwd_ops == NULL)
  464                 return (0);
  465         KKASSERT(curproc != NULL);
  466         /*
  467          * Superuser can always use this to wrest control of console
  468          * output from the "virtual" console.
  469          */
  470         if (ap->a_cmd == TIOCCONS && constty) {
  471                 if (ap->a_cred) {
  472                         error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
  473                         if (error)
  474                                 return (error);
  475                 }
  476                 constty = NULL;
  477                 return (0);
  478         }
  479         ap->a_head.a_dev = cn_tab->cn_dev;
  480         return (dev_doperate(&ap->a_head));
  481 }
  482 
  483 static int
  484 cnkqfilter(struct dev_kqfilter_args *ap)
  485 {
  486         if ((cn_tab == NULL) || cn_mute || cn_fwd_ops == NULL)
  487                 return (1);
  488         ap->a_head.a_dev = cn_tab->cn_dev;
  489         return (dev_doperate(&ap->a_head));
  490 }
  491 
  492 /*
  493  * These synchronous functions are primarily used the kernel needs to 
  494  * access the keyboard (e.g. when running the debugger), or output data
  495  * directly to the console.
  496  */
  497 int
  498 cngetc(void)
  499 {
  500         int c;
  501         if ((cn_tab == NULL) || cn_mute)
  502                 return (-1);
  503         c = (*cn_tab->cn_getc)(cn_tab->cn_private);
  504         if (c == '\r') c = '\n'; /* console input is always ICRNL */
  505         return (c);
  506 }
  507 
  508 int
  509 cncheckc(void)
  510 {
  511         if ((cn_tab == NULL) || cn_mute)
  512                 return (-1);
  513         return ((*cn_tab->cn_checkc)(cn_tab->cn_private));
  514 }
  515 
  516 void
  517 cnputc(int c)
  518 {
  519         char *cp;
  520 
  521         if ((cn_tab == NULL) || cn_mute)
  522                 return;
  523         if (c) {
  524                 if (c == '\n')
  525                         (*cn_tab->cn_putc)(cn_tab->cn_private, '\r');
  526                 (*cn_tab->cn_putc)(cn_tab->cn_private, c);
  527 #ifdef DDB
  528                 if (console_pausing && !db_active && (c == '\n')) {
  529 #else
  530                 if (console_pausing && (c == '\n')) {
  531 #endif
  532                         for(cp=console_pausestr; *cp != '\0'; cp++)
  533                             (*cn_tab->cn_putc)(cn_tab->cn_private, *cp);
  534                         if (cngetc() == '.')
  535                                 console_pausing = 0;
  536                         (*cn_tab->cn_putc)(cn_tab->cn_private, '\r');
  537                         for(cp=console_pausestr; *cp != '\0'; cp++)
  538                             (*cn_tab->cn_putc)(cn_tab->cn_private, ' ');
  539                         (*cn_tab->cn_putc)(cn_tab->cn_private, '\r');
  540                 }
  541         }
  542 }
  543 
  544 void
  545 cndbctl(int on)
  546 {
  547         static int refcount;
  548 
  549         if (cn_tab == NULL)
  550                 return;
  551         if (!on)
  552                 refcount--;
  553         if (refcount == 0 && cn_tab->cn_dbctl != NULL)
  554                 (*cn_tab->cn_dbctl)(cn_tab->cn_private, on);
  555         if (on)
  556                 refcount++;
  557 }
  558 
  559 static void
  560 cn_drvinit(void *unused)
  561 {
  562         cn_devfsdev = make_only_devfs_dev(&cn_ops, 0, UID_ROOT, GID_WHEEL,
  563                                           0600, "console");
  564 }
  565 
  566 SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)

Cache object: 547f501352d610378ed612ef02cce181


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.