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