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, NULL }
 179 };
 180 
 181 int
 182 _init(void)
 183 {
 184         return (mod_install(&modlinkage));
 185 }
 186 
 187 int
 188 _fini(void)
 189 {
 190         return (EBUSY);
 191 }
 192 
 193 int
 194 _info(struct modinfo *modinfop)
 195 {
 196         return (mod_info(&modlinkage, modinfop));
 197 }
 198 
 199 /*
 200  * DDI glue routines
 201  */
 202 static int
 203 cn_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 204 {
 205         if (cmd != DDI_ATTACH)
 206                 return (DDI_FAILURE);
 207 
 208         if (ddi_create_minor_node(devi, "syscon", S_IFCHR,
 209             0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
 210                 return (DDI_FAILURE);
 211         }
 212         if (ddi_create_minor_node(devi, "systty", S_IFCHR,
 213             0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
 214                 ddi_remove_minor_node(devi, NULL);
 215                 return (DDI_FAILURE);
 216         }
 217         if (ddi_create_minor_node(devi, "console", S_IFCHR,
 218             0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
 219                 ddi_remove_minor_node(devi, NULL);
 220                 return (DDI_FAILURE);
 221         }
 222 
 223         cn_dip = devi;
 224         return (DDI_SUCCESS);
 225 }
 226 
 227 static int
 228 cn_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 229 {
 230         if (cmd != DDI_DETACH)
 231                 return (DDI_FAILURE);
 232         ddi_remove_minor_node(devi, NULL);
 233         uconsdev = NODEV;
 234         return (DDI_SUCCESS);
 235 }
 236 
 237 /* ARGSUSED */
 238 static int
 239 cn_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 240 {
 241         int error = DDI_FAILURE;
 242 
 243         switch (infocmd) {
 244         case DDI_INFO_DEVT2DEVINFO:
 245                 if (getminor((dev_t)arg) == 0 && cn_dip != NULL) {
 246                         *result = (void *) cn_dip;
 247                         error = DDI_SUCCESS;
 248                 }
 249                 break;
 250 
 251         case DDI_INFO_DEVT2INSTANCE:
 252                 if (getminor((dev_t)arg) == 0) {
 253                         *result = (void *)0;
 254                         error = DDI_SUCCESS;
 255                 }
 256                 break;
 257 
 258         default:
 259                 break;
 260         }
 261 
 262         return (error);
 263 }
 264 
 265 /*
 266  * XXX  Caution: before allowing more than 256 minor devices on the
 267  *      console, make sure you understand the 'compatibility' hack
 268  *      in ufs_iget() that translates old dev_t's to new dev_t's.
 269  *      See bugid 1098104 for the sordid details.
 270  */
 271 
 272 /* ARGSUSED */
 273 static int
 274 cnopen(dev_t *dev, int flag, int state, struct cred *cred)
 275 {
 276         int     err;
 277         static int      been_here;
 278         vnode_t *vp = rconsvp;
 279 
 280         ASSERT(cred != NULL);
 281 
 282         if (rconsvp == NULL)
 283                 return (0);
 284 
 285         /*
 286          * Enable virtual console I/O for console logging if needed.
 287          */
 288         if (vsconsvp != NULL && vsconsvp->v_stream == NULL) {
 289                 if (VOP_OPEN(&vsconsvp, FREAD | FWRITE, cred, NULL) != 0) {
 290                         cmn_err(CE_WARN, "cnopen: failed to open vsconsvp "
 291                             "for virtual console logging");
 292                 }
 293         }
 294 
 295         /*
 296          * XXX: Clean up inactive PIDs from previous opens if any.
 297          * These would have been created as a result of an I_SETSIG
 298          * issued against console.  This is a workaround, and
 299          * console driver must be correctly redesigned not to need
 300          * this hook.
 301          */
 302         if (vp->v_stream) {
 303                 str_cn_clean(vp);
 304         }
 305 
 306         /*
 307          * XXX: Set hook to tell /proc about underlying console.  (There's
 308          *      gotta be a better way...)
 309          */
 310         if (state != OTYP_CHR || getminor(*dev) != 0)
 311                 return (ENXIO);
 312         if (been_here == 0) {
 313                 uconsdev = *dev;
 314                 been_here = 1;
 315                 if (vn_open("/dev/console", UIO_SYSSPACE, FWRITE | FNOCTTY,
 316                     0, &console_vnode, 0, 0) == 0)
 317                         console_taskq = taskq_create("console_taskq",
 318                             1, maxclsyspri - 1, LOG_LOWAT / LOG_MSGSIZE,
 319                             LOG_HIWAT / LOG_MSGSIZE, TASKQ_PREPOPULATE);
 320         }
 321 
 322         if ((err = VOP_OPEN(&vp, flag, cred, NULL)) != 0)
 323                 return (err);
 324 
 325         /*
 326          * The underlying driver is not allowed to have cloned itself
 327          * for this open.
 328          */
 329         if (vp != rconsvp) {
 330                 /*
 331                  * It might happen that someone set rconsvp to NULL
 332                  * whilst we were in the middle of the open.
 333                  */
 334                 if (rconsvp == NULL) {
 335                         (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
 336                         return (0);
 337                 }
 338                 cmn_err(CE_PANIC, "cnopen: cloned open");
 339         }
 340 
 341         rconsopen++;
 342 
 343         return (0);
 344 }
 345 
 346 /* ARGSUSED */
 347 static int
 348 cnclose(dev_t dev, int flag, int state, struct cred *cred)
 349 {
 350         int     err = 0;
 351         vnode_t *vp;
 352 
 353         /*
 354          * Since this is the _last_ close, it's our last chance to close the
 355          * underlying device.  (Note that if someone else has the underlying
 356          * hardware console device open, we won't get here, since spec_close
 357          * will see s_count > 1.)
 358          */
 359         if (state != OTYP_CHR)
 360                 return (ENXIO);
 361 
 362         if (rconsvp == NULL)
 363                 return (0);
 364 
 365         while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) {
 366                 err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
 367                 if (!err) {
 368                         rconsopen--;
 369                 }
 370         }
 371         return (err);
 372 }
 373 
 374 /* ARGSUSED */
 375 static int
 376 cnread(dev_t dev, struct uio *uio, struct cred *cred)
 377 {
 378         kcondvar_t      sleep_forever;
 379         kmutex_t        sleep_forever_mutex;
 380 
 381         if (rconsvp == NULL) {
 382                 /*
 383                  * Go to sleep forever.  This seems like the least
 384                  * harmful thing to do if there's no console.
 385                  * EOF might be better if we're ending up single-user
 386                  * mode.
 387                  */
 388                 cv_init(&sleep_forever, NULL, CV_DRIVER, NULL);
 389                 mutex_init(&sleep_forever_mutex, NULL, MUTEX_DRIVER, NULL);
 390                 mutex_enter(&sleep_forever_mutex);
 391                 (void) cv_wait_sig(&sleep_forever, &sleep_forever_mutex);
 392                 mutex_exit(&sleep_forever_mutex);
 393                 return (EIO);
 394         }
 395 
 396         if (rconsvp->v_stream != NULL)
 397                 return (strread(rconsvp, uio, cred));
 398         else
 399                 return (cdev_read(rconsdev, uio, cred));
 400 }
 401 
 402 /* ARGSUSED */
 403 static int
 404 cnwrite(dev_t dev, struct uio *uio, struct cred *cred)
 405 {
 406         if (rconsvp == NULL) {
 407                 uio->uio_resid = 0;
 408                 return (0);
 409         }
 410 
 411         /*
 412          * Output to virtual console for logging if enabled.
 413          */
 414         if (vsconsvp != NULL && vsconsvp->v_stream != NULL) {
 415                 struiod_t uiod;
 416 
 417                 /*
 418                  * strwrite modifies uio so need to make copy.
 419                  */
 420                 (void) uiodup(uio, &uiod.d_uio, uiod.d_iov,
 421                     sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
 422 
 423                 (void) strwrite(vsconsvp, &uiod.d_uio, cred);
 424         }
 425 
 426         if (rconsvp->v_stream != NULL)
 427                 return (strwrite(rconsvp, uio, cred));
 428         else
 429                 return (cdev_write(rconsdev, uio, cred));
 430 }
 431 
 432 /* ARGSUSED */
 433 static int
 434 cnprivateioc(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
 435         int *rvalp)
 436 {
 437 
 438         /* currently we only support one ioctl */
 439         if (cmd != CONS_GETTERM)
 440                 return (EINVAL);
 441 
 442         /* Confirm iwscn is immediate target of cn redirection */
 443         if (rconsvp != wsconsvp)
 444                 return (ENODEV);
 445 
 446         /*
 447          * If the redirection client is not wc, it should return
 448          * error upon receiving the CONS_GETTERM ioctl.
 449          *
 450          * if it is wc, we know that the target supports the CONS_GETTERM
 451          * ioctl, which very conviently has the exact same data
 452          * format as this ioctl...  so let's just pass it on.
 453          */
 454         return (cdev_ioctl(rconsdev, CONS_GETTERM, arg, flag, cred, rvalp));
 455 }
 456 
 457 /* ARGSUSED */
 458 static int
 459 cnioctl(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
 460         int *rvalp)
 461 {
 462         if (rconsvp == NULL)
 463                 return (0);
 464 
 465         /*
 466          * In wc, VT_SET_CONSUSER which comes from minor node 0
 467          * has two sources -- either /dev/console or /dev/vt/0 .
 468          * We need a way to differentiate them, so here we
 469          * change VT_SET_CONSUSER to a private VT_RESET_CONSUSER
 470          * ioctl.
 471          */
 472         if (cmd == VT_SET_CONSUSER)
 473                 cmd = VT_RESET_CONSUSER;
 474 
 475         if ((cmd & _CNIOC_MASK) == _CNIOC)
 476                 return (cnprivateioc(dev, cmd, arg, flag, cred, rvalp));
 477 
 478         if (rconsvp->v_stream != NULL)
 479                 return (strioctl(rconsvp, cmd, arg, flag, U_TO_K,
 480                     cred, rvalp));
 481 
 482         return (cdev_ioctl(rconsdev, cmd, arg, flag, cred, rvalp));
 483 }
 484 
 485 /* ARGSUSED */
 486 static int
 487 cnpoll(dev_t dev, short events, int anyyet, short *reventsp,
 488         struct pollhead **phpp)
 489 {
 490         if (rconsvp == NULL)
 491                 return (nochpoll(dev, events, anyyet, reventsp, phpp));
 492 
 493         if (rconsvp->v_stream != NULL)
 494                 return (strpoll(rconsvp->v_stream, events, anyyet, reventsp,
 495                     phpp));
 496         else
 497                 return (cdev_poll(rconsdev, events, anyyet, reventsp, phpp));
 498 }