1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1982, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Indirect console driver for Sun.
  28  *
  29  * Redirects all I/O to the device designated as the underlying "hardware"
  30  * console, as given by the value of rconsvp.  The implementation assumes that
  31  * rconsvp denotes a STREAMS device; the assumption is justified since
  32  * consoles must be capable of effecting tty semantics.
  33  *
  34  * rconsvp is set in autoconf.c:consconfig(), based on information obtained
  35  * from the EEPROM.
  36  *
  37  * XXX: The driver still needs to be converted to use ANSI C consistently
  38  *      throughout.
  39  */
  40 
  41 #include <sys/types.h>
  42 #include <sys/open.h>
  43 #include <sys/param.h>
  44 #include <sys/systm.h>
  45 #include <sys/signal.h>
  46 #include <sys/cred.h>
  47 #include <sys/user.h>
  48 #include <sys/proc.h>
  49 #include <sys/disp.h>
  50 #include <sys/file.h>
  51 #include <sys/taskq.h>
  52 #include <sys/log.h>
  53 #include <sys/vnode.h>
  54 #include <sys/uio.h>
  55 #include <sys/stat.h>
  56 
  57 #include <sys/console.h>
  58 #include <sys/consdev.h>
  59 
  60 #include <sys/stream.h>
  61 #include <sys/strsubr.h>
  62 #include <sys/poll.h>
  63 
  64 #include <sys/debug.h>
  65 
  66 #include <sys/conf.h>
  67 #include <sys/ddi.h>
  68 #include <sys/sunddi.h>
  69 #include <sys/vt.h>
  70 
  71 static int cnopen(dev_t *, int, int, struct cred *);
  72 static int cnclose(dev_t, int, int, struct cred *);
  73 static int cnread(dev_t, struct uio *, struct cred *);
  74 static int cnwrite(dev_t, struct uio *, struct cred *);
  75 static int cnioctl(dev_t, int, intptr_t, int, struct cred *, int *);
  76 static int cnpoll(dev_t, short, int, short *, struct pollhead **);
  77 static int cn_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
  78 static int cn_attach(dev_info_t *, ddi_attach_cmd_t);
  79 static int cn_detach(dev_info_t *, ddi_detach_cmd_t);
  80 
  81 static dev_info_t *cn_dip;              /* private copy of devinfo pointer */
  82 
  83 static struct cb_ops cn_cb_ops = {
  84 
  85         cnopen,                 /* open */
  86         cnclose,                /* close */
  87         nodev,                  /* strategy */
  88         nodev,                  /* print */
  89         nodev,                  /* dump */
  90         cnread,                 /* read */
  91         cnwrite,                /* write */
  92         cnioctl,                /* ioctl */
  93         nodev,                  /* devmap */
  94         nodev,                  /* mmap */
  95         nodev,                  /* segmap */
  96         cnpoll,                 /* poll */
  97         ddi_prop_op,            /* cb_prop_op */
  98         0,                      /* streamtab  */
  99         D_NEW | D_MP            /* Driver compatibility flag */
 100 
 101 };
 102 
 103 static struct dev_ops cn_ops = {
 104 
 105         DEVO_REV,               /* devo_rev, */
 106         0,                      /* refcnt  */
 107         cn_info,                /* info */
 108         nulldev,                /* identify */
 109         nulldev,                /* probe */
 110         cn_attach,              /* attach */
 111         cn_detach,              /* detach */
 112         nodev,                  /* reset */
 113         &cn_cb_ops,         /* driver operations */
 114         (struct bus_ops *)0,    /* bus operations */
 115         NULL,                   /* power */
 116         ddi_quiesce_not_needed,         /* quiesce */
 117 
 118 };
 119 
 120 /*
 121  * Global variables associated with the console device:
 122  *
 123  * XXX: There are too many of these!
 124  * moved to space.c to become resident in the kernel so that cons
 125  * can be loadable.
 126  */
 127 
 128 extern dev_t    rconsdev;       /* "hardware" console */
 129 extern vnode_t  *rconsvp;       /* pointer to vnode for that device */
 130 
 131 /*
 132  * XXX: consulted in prsubr.c, for /proc entry point for obtaining ps info.
 133  */
 134 extern dev_t    uconsdev;       /* What the user thinks is the console device */
 135 
 136 /*
 137  * Private driver state:
 138  */
 139 
 140 /*
 141  * The underlying console device potentially can be opened through (at least)
 142  * two paths: through this driver and through the underlying device's driver.
 143  * To ensure that reference counts are meaningful and therefore that close
 144  * routines are called at the right time, it's important to make sure that
 145  * rconsvp's s_count field (i.e., the count on the underlying device) never
 146  * has a contribution of more than one through this driver, regardless of how
 147  * many times this driver's been opened.  rconsopen keeps track of the
 148  * necessary information to ensure this property.
 149  */
 150 static uint_t   rconsopen;
 151 
 152 
 153 #include <sys/types.h>
 154 #include <sys/conf.h>
 155 #include <sys/param.h>
 156 #include <sys/systm.h>
 157 #include <sys/errno.h>
 158 #include <sys/modctl.h>
 159 
 160 
 161 extern int nodev(), nulldev();
 162 extern int dseekneg_flag;
 163 extern struct mod_ops mod_driverops;
 164 extern struct dev_ops cn_ops;
 165 
 166 /*
 167  * Module linkage information for the kernel.
 168  */
 169 
 170 static struct modldrv modldrv = {
 171         &mod_driverops, /* Type of module.  This one is a pseudo driver */
 172         "Console redirection driver",
 173         &cn_ops,    /* driver ops */
 174 };
 175 
 176 static struct modlinkage modlinkage = {
 177         MODREV_1,
 178         &modldrv,
 179         NULL
 180 };
 181 
 182 int
 183 _init(void)
 184 {
 185         return (mod_install(&modlinkage));
 186 }
 187 
 188 int
 189 _fini(void)
 190 {
 191         return (EBUSY);
 192 }
 193 
 194 int
 195 _info(struct modinfo *modinfop)
 196 {
 197         return (mod_info(&modlinkage, modinfop));
 198 }
 199 
 200 /*
 201  * DDI glue routines
 202  */
 203 static int
 204 cn_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 205 {
 206         if (cmd != DDI_ATTACH)
 207                 return (DDI_FAILURE);
 208 
 209         if (ddi_create_minor_node(devi, "syscon", S_IFCHR,
 210             0, DDI_PSEUDO, 0) == DDI_FAILURE) {
 211                 return (DDI_FAILURE);
 212         }
 213         if (ddi_create_minor_node(devi, "systty", S_IFCHR,
 214             0, DDI_PSEUDO, 0) == DDI_FAILURE) {
 215                 ddi_remove_minor_node(devi, NULL);
 216                 return (DDI_FAILURE);
 217         }
 218         if (ddi_create_minor_node(devi, "console", S_IFCHR,
 219             0, DDI_PSEUDO, 0) == DDI_FAILURE) {
 220                 ddi_remove_minor_node(devi, NULL);
 221                 return (DDI_FAILURE);
 222         }
 223 
 224         cn_dip = devi;
 225         return (DDI_SUCCESS);
 226 }
 227 
 228 static int
 229 cn_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 230 {
 231         if (cmd != DDI_DETACH)
 232                 return (DDI_FAILURE);
 233         ddi_remove_minor_node(devi, NULL);
 234         uconsdev = NODEV;
 235         return (DDI_SUCCESS);
 236 }
 237 
 238 /* ARGSUSED */
 239 static int
 240 cn_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 241 {
 242         int error = DDI_FAILURE;
 243 
 244         switch (infocmd) {
 245         case DDI_INFO_DEVT2DEVINFO:
 246                 if (getminor((dev_t)arg) == 0 && cn_dip != NULL) {
 247                         *result = (void *) cn_dip;
 248                         error = DDI_SUCCESS;
 249                 }
 250                 break;
 251 
 252         case DDI_INFO_DEVT2INSTANCE:
 253                 if (getminor((dev_t)arg) == 0) {
 254                         *result = (void *)0;
 255                         error = DDI_SUCCESS;
 256                 }
 257                 break;
 258 
 259         default:
 260                 break;
 261         }
 262 
 263         return (error);
 264 }
 265 
 266 /*
 267  * XXX  Caution: before allowing more than 256 minor devices on the
 268  *      console, make sure you understand the 'compatibility' hack
 269  *      in ufs_iget() that translates old dev_t's to new dev_t's.
 270  *      See bugid 1098104 for the sordid details.
 271  */
 272 
 273 /* ARGSUSED */
 274 static int
 275 cnopen(dev_t *dev, int flag, int state, struct cred *cred)
 276 {
 277         int     err;
 278         static int      been_here;
 279         vnode_t *vp = rconsvp;
 280 
 281         ASSERT(cred != NULL);
 282 
 283         if (rconsvp == NULL)
 284                 return (0);
 285 
 286         /*
 287          * Enable virtual console I/O for console logging if needed.
 288          */
 289         if (vsconsvp != NULL && vsconsvp->v_stream == NULL) {
 290                 if (VOP_OPEN(&vsconsvp, FREAD | FWRITE, cred, NULL) != 0) {
 291                         cmn_err(CE_WARN, "cnopen: failed to open vsconsvp "
 292                             "for virtual console logging");
 293                 }
 294         }
 295 
 296         /*
 297          * XXX: Clean up inactive PIDs from previous opens if any.
 298          * These would have been created as a result of an I_SETSIG
 299          * issued against console.  This is a workaround, and
 300          * console driver must be correctly redesigned not to need
 301          * this hook.
 302          */
 303         if (vp->v_stream) {
 304                 str_cn_clean(vp);
 305         }
 306 
 307         /*
 308          * XXX: Set hook to tell /proc about underlying console.  (There's
 309          *      gotta be a better way...)
 310          */
 311         if (state != OTYP_CHR || getminor(*dev) != 0)
 312                 return (ENXIO);
 313         if (been_here == 0) {
 314                 uconsdev = *dev;
 315                 been_here = 1;
 316                 if (vn_open("/dev/console", UIO_SYSSPACE, FWRITE | FNOCTTY,
 317                     0, &console_vnode, 0, 0) == 0)
 318                         console_taskq = taskq_create("console_taskq",
 319                             1, maxclsyspri - 1, LOG_LOWAT / LOG_MSGSIZE,
 320                             LOG_HIWAT / LOG_MSGSIZE, TASKQ_PREPOPULATE);
 321         }
 322 
 323         if ((err = VOP_OPEN(&vp, flag, cred, NULL)) != 0)
 324                 return (err);
 325 
 326         /*
 327          * The underlying driver is not allowed to have cloned itself
 328          * for this open.
 329          */
 330         if (vp != rconsvp) {
 331                 /*
 332                  * It might happen that someone set rconsvp to NULL
 333                  * whilst we were in the middle of the open.
 334                  */
 335                 if (rconsvp == NULL) {
 336                         (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
 337                         return (0);
 338                 }
 339                 cmn_err(CE_PANIC, "cnopen: cloned open");
 340         }
 341 
 342         rconsopen++;
 343 
 344         return (0);
 345 }
 346 
 347 /* ARGSUSED */
 348 static int
 349 cnclose(dev_t dev, int flag, int state, struct cred *cred)
 350 {
 351         int     err = 0;
 352         vnode_t *vp;
 353 
 354         /*
 355          * Since this is the _last_ close, it's our last chance to close the
 356          * underlying device.  (Note that if someone else has the underlying
 357          * hardware console device open, we won't get here, since spec_close
 358          * will see s_count > 1.)
 359          */
 360         if (state != OTYP_CHR)
 361                 return (ENXIO);
 362 
 363         if (rconsvp == NULL)
 364                 return (0);
 365 
 366         while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) {
 367                 err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
 368                 if (!err) {
 369                         rconsopen--;
 370                 }
 371         }
 372         return (err);
 373 }
 374 
 375 /* ARGSUSED */
 376 static int
 377 cnread(dev_t dev, struct uio *uio, struct cred *cred)
 378 {
 379         kcondvar_t      sleep_forever;
 380         kmutex_t        sleep_forever_mutex;
 381 
 382         if (rconsvp == NULL) {
 383                 /*
 384                  * Go to sleep forever.  This seems like the least
 385                  * harmful thing to do if there's no console.
 386                  * EOF might be better if we're ending up single-user
 387                  * mode.
 388                  */
 389                 cv_init(&sleep_forever, NULL, CV_DRIVER, NULL);
 390                 mutex_init(&sleep_forever_mutex, NULL, MUTEX_DRIVER, NULL);
 391                 mutex_enter(&sleep_forever_mutex);
 392                 (void) cv_wait_sig(&sleep_forever, &sleep_forever_mutex);
 393                 mutex_exit(&sleep_forever_mutex);
 394                 return (EIO);
 395         }
 396 
 397         if (rconsvp->v_stream != NULL)
 398                 return (strread(rconsvp, uio, cred));
 399         else
 400                 return (cdev_read(rconsdev, uio, cred));
 401 }
 402 
 403 /* ARGSUSED */
 404 static int
 405 cnwrite(dev_t dev, struct uio *uio, struct cred *cred)
 406 {
 407         if (rconsvp == NULL) {
 408                 uio->uio_resid = 0;
 409                 return (0);
 410         }
 411 
 412         /*
 413          * Output to virtual console for logging if enabled.
 414          */
 415         if (vsconsvp != NULL && vsconsvp->v_stream != NULL) {
 416                 struiod_t uiod;
 417 
 418                 /*
 419                  * strwrite modifies uio so need to make copy.
 420                  */
 421                 (void) uiodup(uio, &uiod.d_uio, uiod.d_iov,
 422                     sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
 423 
 424                 (void) strwrite(vsconsvp, &uiod.d_uio, cred);
 425         }
 426 
 427         if (rconsvp->v_stream != NULL)
 428                 return (strwrite(rconsvp, uio, cred));
 429         else
 430                 return (cdev_write(rconsdev, uio, cred));
 431 }
 432 
 433 /* ARGSUSED */
 434 static int
 435 cnprivateioc(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
 436         int *rvalp)
 437 {
 438 
 439         /* currently we only support one ioctl */
 440         if (cmd != CONS_GETTERM)
 441                 return (EINVAL);
 442 
 443         /* Confirm iwscn is immediate target of cn redirection */
 444         if (rconsvp != wsconsvp)
 445                 return (ENODEV);
 446 
 447         /*
 448          * If the redirection client is not wc, it should return
 449          * error upon receiving the CONS_GETTERM ioctl.
 450          *
 451          * if it is wc, we know that the target supports the CONS_GETTERM
 452          * ioctl, which very conviently has the exact same data
 453          * format as this ioctl...  so let's just pass it on.
 454          */
 455         return (cdev_ioctl(rconsdev, CONS_GETTERM, arg, flag, cred, rvalp));
 456 }
 457 
 458 /* ARGSUSED */
 459 static int
 460 cnioctl(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
 461         int *rvalp)
 462 {
 463         if (rconsvp == NULL)
 464                 return (0);
 465 
 466         /*
 467          * In wc, VT_SET_CONSUSER which comes from minor node 0
 468          * has two sources -- either /dev/console or /dev/vt/0 .
 469          * We need a way to differentiate them, so here we
 470          * change VT_SET_CONSUSER to a private VT_RESET_CONSUSER
 471          * ioctl.
 472          */
 473         if (cmd == VT_SET_CONSUSER)
 474                 cmd = VT_RESET_CONSUSER;
 475 
 476         if ((cmd & _CNIOC_MASK) == _CNIOC)
 477                 return (cnprivateioc(dev, cmd, arg, flag, cred, rvalp));
 478 
 479         if (rconsvp->v_stream != NULL)
 480                 return (strioctl(rconsvp, cmd, arg, flag, U_TO_K,
 481                     cred, rvalp));
 482 
 483         return (cdev_ioctl(rconsdev, cmd, arg, flag, cred, rvalp));
 484 }
 485 
 486 /* ARGSUSED */
 487 static int
 488 cnpoll(dev_t dev, short events, int anyyet, short *reventsp,
 489         struct pollhead **phpp)
 490 {
 491         if (rconsvp == NULL)
 492                 return (nochpoll(dev, events, anyyet, reventsp, phpp));
 493 
 494         if (rconsvp->v_stream != NULL)
 495                 return (strpoll(rconsvp->v_stream, events, anyyet, reventsp,
 496                     phpp));
 497         else
 498                 return (cdev_poll(rconsdev, events, anyyet, reventsp, phpp));
 499 }