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
_init(void)185 _init(void)
186 {
187 return (mod_install(&modlinkage));
188 }
189
190 int
_fini(void)191 _fini(void)
192 {
193 return (EBUSY);
194 }
195
196 int
_info(struct modinfo * modinfop)197 _info(struct modinfo *modinfop)
198 {
199 return (mod_info(&modlinkage, modinfop));
200 }
201
202 /*
203 * DDI glue routines
204 */
205 static int
cn_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)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
cn_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)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 static int
cn_info(dev_info_t * dip __unused,ddi_info_cmd_t infocmd,void * arg,void ** result)241 cn_info(dev_info_t *dip __unused, ddi_info_cmd_t infocmd, void *arg,
242 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
cnopen(dev_t * dev,int flag,int state,struct cred * cred)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 static int
cnclose(dev_t dev __unused,int flag,int state,struct cred * cred)350 cnclose(dev_t dev __unused, int flag, int state, struct cred *cred)
351 {
352 int err = 0;
353 vnode_t *vp;
354
355 /*
356 * Since this is the _last_ close, it's our last chance to close the
357 * underlying device. (Note that if someone else has the underlying
358 * hardware console device open, we won't get here, since spec_close
359 * will see s_count > 1.)
360 */
361 if (state != OTYP_CHR)
362 return (ENXIO);
363
364 if (rconsvp == NULL)
365 return (0);
366
367 while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) {
368 err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
369 if (!err) {
370 rconsopen--;
371 }
372 }
373 return (err);
374 }
375
376 static int
cnread(dev_t dev __unused,struct uio * uio,struct cred * cred)377 cnread(dev_t dev __unused, 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 static int
cnwrite(dev_t dev __unused,struct uio * uio,struct cred * cred)404 cnwrite(dev_t dev __unused, 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 struct iovec buf[IOV_MAX_STACK];
417 int iovlen = 0;
418
419 if (uio->uio_iovcnt > IOV_MAX_STACK) {
420 iovlen = uio->uio_iovcnt * sizeof (iovec_t);
421 uiod.d_iov = kmem_alloc(iovlen, KM_SLEEP);
422 } else {
423 uiod.d_iov = buf;
424 }
425
426 /*
427 * strwrite modifies uio so need to make copy.
428 */
429 (void) uiodup(uio, &uiod.d_uio, uiod.d_iov, uio->uio_iovcnt);
430
431 (void) strwrite(vsconsvp, &uiod.d_uio, cred);
432 if (iovlen != 0)
433 kmem_free(uiod.d_iov, iovlen);
434 }
435
436 if (rconsvp->v_stream != NULL)
437 return (strwrite(rconsvp, uio, cred));
438 else
439 return (cdev_write(rconsdev, uio, cred));
440 }
441
442 static int
cnprivateioc(dev_t dev __unused,int cmd,intptr_t arg,int flag,struct cred * cred,int * rvalp)443 cnprivateioc(dev_t dev __unused, int cmd, intptr_t arg, int flag,
444 struct cred *cred, int *rvalp)
445 {
446 if (cmd == CONS_GETDEV) {
447 /*
448 * The user has requested the device number of the redirection
449 * client.
450 */
451 STRUCT_DECL(cons_getdev, cnd);
452 STRUCT_INIT(cnd, flag);
453
454 bzero(STRUCT_BUF(cnd), STRUCT_SIZE(cnd));
455
456 if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
457 dev32_t rconsdev32;
458
459 if (cmpldev(&rconsdev32, rconsdev) != 1) {
460 return (EOVERFLOW);
461 }
462
463 STRUCT_FSET(cnd, cnd_rconsdev, rconsdev32);
464 } else {
465 STRUCT_FSET(cnd, cnd_rconsdev, rconsdev);
466 }
467
468 if (ddi_copyout(STRUCT_BUF(cnd), (void *)arg,
469 STRUCT_SIZE(cnd), flag) != 0) {
470 return (EFAULT);
471 }
472
473 return (0);
474 }
475
476 if (cmd != CONS_GETTERM)
477 return (EINVAL);
478
479 /* Confirm iwscn is immediate target of cn redirection */
480 if (rconsvp != wsconsvp)
481 return (ENODEV);
482
483 /*
484 * If the redirection client is not wc, it should return
485 * error upon receiving the CONS_GETTERM ioctl.
486 *
487 * if it is wc, we know that the target supports the CONS_GETTERM
488 * ioctl, which very conviently has the exact same data
489 * format as this ioctl... so let's just pass it on.
490 */
491 return (cdev_ioctl(rconsdev, CONS_GETTERM, arg, flag, cred, rvalp));
492 }
493
494 /* ARGSUSED */
495 static int
cnioctl(dev_t dev,int cmd,intptr_t arg,int flag,struct cred * cred,int * rvalp)496 cnioctl(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
497 int *rvalp)
498 {
499 if (rconsvp == NULL)
500 return (0);
501
502 /*
503 * In wc, VT_SET_CONSUSER which comes from minor node 0
504 * has two sources -- either /dev/console or /dev/vt/0 .
505 * We need a way to differentiate them, so here we
506 * change VT_SET_CONSUSER to a private VT_RESET_CONSUSER
507 * ioctl.
508 */
509 if (cmd == VT_SET_CONSUSER)
510 cmd = VT_RESET_CONSUSER;
511
512 if ((cmd & _CNIOC_MASK) == _CNIOC)
513 return (cnprivateioc(dev, cmd, arg, flag, cred, rvalp));
514
515 if (rconsvp->v_stream != NULL)
516 return (strioctl(rconsvp, cmd, arg, flag, U_TO_K,
517 cred, rvalp));
518
519 return (cdev_ioctl(rconsdev, cmd, arg, flag, cred, rvalp));
520 }
521
522 /* ARGSUSED */
523 static int
cnpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)524 cnpoll(dev_t dev, short events, int anyyet, short *reventsp,
525 struct pollhead **phpp)
526 {
527 if (rconsvp == NULL)
528 return (nochpoll(dev, events, anyyet, reventsp, phpp));
529
530 if (rconsvp->v_stream != NULL)
531 return (strpoll(rconsvp->v_stream, events, anyyet, reventsp,
532 phpp));
533 else
534 return (cdev_poll(rconsdev, events, anyyet, reventsp, phpp));
535 }
536