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) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2026 RackTop Systems, Inc. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/param.h> 29 #include <sys/signal.h> 30 #include <sys/cred.h> 31 #include <sys/vnode.h> 32 #include <sys/termios.h> 33 #include <sys/termio.h> 34 #include <sys/ttold.h> 35 #include <sys/stropts.h> 36 #include <sys/stream.h> 37 #include <sys/strsun.h> 38 #include <sys/tty.h> 39 #include <sys/buf.h> 40 #include <sys/uio.h> 41 #include <sys/stat.h> 42 #include <sys/sysmacros.h> 43 #include <sys/errno.h> 44 #include <sys/proc.h> 45 #include <sys/procset.h> 46 #include <sys/fault.h> 47 #include <sys/siginfo.h> 48 #include <sys/debug.h> 49 #include <sys/kd.h> 50 #include <sys/vt.h> 51 #include <sys/vtdaemon.h> 52 #include <sys/session.h> 53 #include <sys/door.h> 54 #include <sys/kmem.h> 55 #include <sys/cpuvar.h> 56 #include <sys/kbio.h> 57 #include <sys/strredir.h> 58 #include <sys/fs/snode.h> 59 #include <sys/consdev.h> 60 #include <sys/conf.h> 61 #include <sys/cmn_err.h> 62 #include <sys/console.h> 63 #include <sys/promif.h> 64 #include <sys/note.h> 65 #include <sys/polled_io.h> 66 #include <sys/systm.h> 67 #include <sys/ddi.h> 68 #include <sys/sunddi.h> 69 #include <sys/sunndi.h> 70 #include <sys/esunddi.h> 71 #include <sys/sunldi.h> 72 #include <sys/debug.h> 73 #include <sys/console.h> 74 #include <sys/ddi_impldefs.h> 75 #include <sys/policy.h> 76 #include <sys/tem.h> 77 #include <sys/wscons.h> 78 #include <sys/systm.h> 79 #include <sys/modctl.h> 80 #include <sys/vt_impl.h> 81 #include <sys/consconfig_dacf.h> 82 83 /* 84 * This file belongs to wc STREAMS module which has a D_MTPERMODE 85 * inner perimeter. See "Locking Policy" comment in wscons.c for 86 * more information. 87 */ 88 89 /* 90 * Minor name device file Hotkeys 91 * 92 * 0 the system console /dev/console Alt + F1 93 * 0: virtual console #1 /dev/vt/0 Alt + F1 94 * 95 * 2: virtual console #2 /dev/vt/2 Alt + F2 96 * 3: virtual console #3 /dev/vt/3 Alt + F3 97 * ...... 98 * n: virtual console #n /dev/vt/n Alt + Fn 99 * 100 * Note that vtdaemon is running on /dev/vt/1 (minor=1), 101 * which is not available to end users. 102 * 103 */ 104 105 #define VT_DAEMON_MINOR 1 106 #define VT_IS_DAEMON(minor) ((minor) == VT_DAEMON_MINOR) 107 108 extern void wc_get_size(vc_state_t *pvc); 109 extern boolean_t consconfig_console_is_tipline(void); 110 111 112 minor_t vc_last_console = VT_MINOR_INVALID; /* the last used console */ 113 volatile uint_t vc_target_console; /* arg (1..n) */ 114 115 static volatile minor_t vc_inuse_max_minor = 0; 116 static list_t vc_waitactive_list; 117 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_target_console)) 118 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_last_console)) 119 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_inuse_max_minor)) 120 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_waitactive_list)) 121 122 static int vt_pending_vtno = -1; 123 kmutex_t vt_pending_vtno_lock; 124 _NOTE(MUTEX_PROTECTS_DATA(vt_pending_vtno_lock, vt_pending_vtno)) 125 126 static int vt_activate(uint_t vt_no, cred_t *credp); 127 static void vt_copyout(queue_t *qp, mblk_t *mp, mblk_t *tmp, uint_t size); 128 static void vt_copyin(queue_t *qp, mblk_t *mp, uint_t size); 129 static void vt_iocnak(queue_t *qp, mblk_t *mp, int error); 130 static void vt_iocack(queue_t *qp, mblk_t *mp); 131 132 static uint_t vt_minor2arg(minor_t minor); 133 static minor_t vt_arg2minor(uint_t arg); 134 135 /* 136 * If the system console is directed to tipline, consider /dev/vt/0 as 137 * not being used. 138 * For other VT, if it is opened and tty is initialized, consider it 139 * as being used. 140 */ 141 #define VT_IS_INUSE(id) \ 142 (((vt_minor2vc(id))->vc_flags & WCS_ISOPEN) && \ 143 ((vt_minor2vc(id))->vc_flags & WCS_INIT) && \ 144 (id != 0 || !consconfig_console_is_tipline())) 145 146 /* 147 * the vt switching message is encoded as: 148 * 149 * ------------------------------------------------------------- 150 * | \033 | 'Q' | vtno + 'A' | opcode | 'z' | '\0' | 151 * ------------------------------------------------------------- 152 */ 153 #define VT_MSG_SWITCH(mp) \ 154 ((int)((mp)->b_wptr - (mp)->b_rptr) >= 5 && \ 155 *((mp)->b_rptr) == '\033' && \ 156 *((mp)->b_rptr + 1) == 'Q' && \ 157 *((mp)->b_rptr + 4) == 'z') 158 159 #define VT_MSG_VTNO(mp) (*((mp)->b_rptr + 2) - 'A') 160 #define VT_MSG_OPCODE(mp) (*((mp)->b_rptr + 3)) 161 162 #define VT_DOORCALL_MAX_RETRY 3 163 164 static void 165 vt_init_ttycommon(tty_common_t *pcommon) 166 { 167 struct termios *termiosp; 168 int len; 169 170 mutex_init(&pcommon->t_excl, NULL, MUTEX_DEFAULT, NULL); 171 pcommon->t_iflag = 0; 172 173 /* 174 * Get the default termios settings (cflag). 175 * These are stored as a property in the 176 * "options" node. 177 */ 178 if (ddi_getlongprop(DDI_DEV_T_ANY, 179 ddi_root_node(), 0, "ttymodes", 180 (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS) { 181 182 if (len == sizeof (struct termios)) 183 pcommon->t_cflag = termiosp->c_cflag; 184 else 185 cmn_err(CE_WARN, 186 "wc: Couldn't get ttymodes property!"); 187 188 kmem_free(termiosp, len); 189 } else { 190 /* 191 * Gack! Whine about it. 192 */ 193 cmn_err(CE_WARN, 194 "wc: Couldn't get ttymodes property!"); 195 } 196 197 pcommon->t_iocpending = NULL; 198 } 199 200 static int 201 vt_config(uint_t count) 202 { 203 if (consmode != CONS_KFB) 204 return (ENOTSUP); 205 206 /* one for system console, one for vtdaemon */ 207 if (count < 2) 208 return (ENXIO); 209 210 /* 211 * Shouldn't allow to shrink the max vt minor to be smaller than 212 * the max in used minor. 213 */ 214 if (count <= vc_inuse_max_minor) 215 return (EBUSY); 216 217 mutex_enter(&vc_lock); 218 vt_resize(count); 219 mutex_exit(&vc_lock); 220 221 return (0); 222 } 223 224 void 225 vt_clean(queue_t *q, vc_state_t *pvc) 226 { 227 ASSERT(MUTEX_HELD(&pvc->vc_state_lock)); 228 229 if (pvc->vc_bufcallid != 0) { 230 qunbufcall(q, pvc->vc_bufcallid); 231 pvc->vc_bufcallid = 0; 232 } 233 if (pvc->vc_timeoutid != 0) { 234 (void) quntimeout(q, pvc->vc_timeoutid); 235 pvc->vc_timeoutid = 0; 236 } 237 ttycommon_close(&pvc->vc_ttycommon); 238 tem_clean(pvc->vc_tem); 239 pvc->vc_flags &= ~WCS_INIT; 240 } 241 242 /* 243 * Reply the VT_WAITACTIVE ioctl. 244 * Argument 'close' usage: 245 * B_TRUE: the vt designated by argument 'minor' is being closed. 246 * B_FALSE: the vt designated by argument 'minor' has been activated just now. 247 */ 248 static void 249 vc_waitactive_reply(int minor, boolean_t close) 250 { 251 vc_waitactive_msg_t *index, *tmp; 252 vc_state_t *pvc; 253 254 index = list_head(&vc_waitactive_list); 255 256 while (index != NULL) { 257 tmp = index; 258 index = list_next(&vc_waitactive_list, index); 259 260 if ((close && tmp->wa_msg_minor == minor) || 261 (!close && tmp->wa_wait_minor == minor)) { 262 list_remove(&vc_waitactive_list, tmp); 263 pvc = vt_minor2vc(tmp->wa_msg_minor); 264 265 if (close) 266 vt_iocnak(pvc->vc_wq, tmp->wa_mp, ENXIO); 267 else 268 vt_iocack(pvc->vc_wq, tmp->wa_mp); 269 270 kmem_free(tmp, sizeof (vc_waitactive_msg_t)); 271 } 272 } 273 } 274 275 void 276 vt_close(queue_t *q, vc_state_t *pvc, cred_t *credp) 277 { 278 minor_t index; 279 280 mutex_enter(&pvc->vc_state_lock); 281 vt_clean(q, pvc); 282 pvc->vc_flags &= ~WCS_ISOPEN; 283 mutex_exit(&pvc->vc_state_lock); 284 285 tem_destroy(pvc->vc_tem, credp); 286 pvc->vc_tem = NULL; 287 288 index = pvc->vc_minor; 289 if (index == vc_inuse_max_minor) { 290 while ((--index > 0) && !VT_IS_INUSE(index)) 291 ; 292 vc_inuse_max_minor = index; 293 } 294 295 vc_waitactive_reply(pvc->vc_minor, B_TRUE); 296 } 297 298 static void 299 vt_init_tty(vc_state_t *pvc) 300 { 301 ASSERT(MUTEX_HELD(&pvc->vc_state_lock)); 302 303 pvc->vc_flags |= WCS_INIT; 304 vt_init_ttycommon(&pvc->vc_ttycommon); 305 wc_get_size(pvc); 306 } 307 308 /* 309 * minor 0: /dev/vt/0 (index = 0, indicating the system console) 310 * minor 1: /dev/vt/1 (index = 1, vtdaemon special console) 311 * minor 2: /dev/vt/2 (index = 2, virtual consoles) 312 * ...... 313 * minor n: /dev/vt/n (index = n) 314 * 315 * 316 * The system console (minor 0), is opened firstly and used during console 317 * configuration. It also acts as the system hard console even when all 318 * virtual consoles go off. 319 * 320 * In tipline case, minor 0 (/dev/vt/0) is reserved, and cannot be switched to. 321 * And the system console is redirected to the tipline. During normal cases, 322 * we can switch from virtual consoles to it by pressing 'Alt + F1'. 323 * 324 * minor 1 (/dev/vt/1) is reserved for vtdaemon special console, and it's 325 * not available to end users. 326 * 327 * During early console configuration, consconfig_dacf opens wscons and then 328 * issue a WC_OPEN_FB ioctl to kick off terminal init process. So during 329 * consconfig_dacf first opening of wscons, tems (of type tem_state_t) is 330 * not initialized. We do not initialize the tem_vt_state_t instance returned 331 * by tem_init() for this open, since we do not have enough info to handle 332 * normal terminal operation at this moment. This tem_vt_state_t instance 333 * will get initialized when handling WC_OPEN_FB. 334 */ 335 int 336 vt_open(minor_t minor, queue_t *rq, cred_t *crp) 337 { 338 vc_state_t *pvc; 339 340 if (!vt_minor_valid(minor)) 341 return (ENXIO); 342 343 pvc = vt_minor2vc(minor); 344 if (pvc == NULL) 345 return (ENXIO); 346 347 /* Re-open (qreopen): already attached, nothing to do. */ 348 if (rq->q_ptr != NULL) { 349 ASSERT3P(rq->q_ptr, ==, pvc); 350 return (0); 351 } 352 353 mutex_enter(&vc_lock); 354 mutex_enter(&pvc->vc_state_lock); 355 356 if (!(pvc->vc_flags & WCS_ISOPEN)) { 357 pvc->vc_tem = tem_init(crp); 358 } 359 360 if (!(pvc->vc_flags & WCS_INIT)) 361 vt_init_tty(pvc); 362 363 /* 364 * In normal case, the first screen is the system console; 365 * In tipline case, the first screen is the first VT that gets started. 366 */ 367 if (vc_active_console == VT_MINOR_INVALID && minor != VT_DAEMON_MINOR) 368 if (minor == 0 || consmode == CONS_KFB) { 369 boolean_t unblank = B_FALSE; 370 371 vc_active_console = minor; 372 vc_last_console = minor; 373 if (minor != 0) { 374 /* 375 * If we are not opening the system console 376 * as the first console, clear the phyical 377 * screen. 378 */ 379 unblank = B_TRUE; 380 } 381 382 tem_activate(pvc->vc_tem, unblank, crp); 383 } 384 385 if ((pvc->vc_ttycommon.t_flags & TS_XCLUDE) && 386 (secpolicy_excl_open(crp) != 0)) { 387 mutex_exit(&pvc->vc_state_lock); 388 mutex_exit(&vc_lock); 389 return (EBUSY); 390 } 391 392 if (minor > vc_inuse_max_minor) 393 vc_inuse_max_minor = minor; 394 395 pvc->vc_flags |= WCS_ISOPEN; 396 pvc->vc_ttycommon.t_readq = rq; 397 pvc->vc_ttycommon.t_writeq = WR(rq); 398 tem_init_q(pvc->vc_tem, rq); 399 400 mutex_exit(&pvc->vc_state_lock); 401 mutex_exit(&vc_lock); 402 403 rq->q_ptr = pvc; 404 WR(rq)->q_ptr = pvc; 405 pvc->vc_wq = WR(rq); 406 407 qprocson(rq); 408 return (0); 409 } 410 411 static minor_t 412 vt_find_prev(minor_t cur) 413 { 414 minor_t i, t, max; 415 416 ASSERT(vc_active_console != VT_MINOR_INVALID); 417 418 max = VC_INSTANCES_COUNT; 419 420 for (i = cur - 1; (t = (i + max) % max) != cur; i--) 421 if (!VT_IS_DAEMON(t) && VT_IS_INUSE(t)) 422 return (t); 423 424 return (VT_MINOR_INVALID); 425 } 426 427 static minor_t 428 vt_find_next(minor_t cur) 429 { 430 minor_t i, t, max; 431 432 ASSERT(vc_active_console != VT_MINOR_INVALID); 433 434 max = VC_INSTANCES_COUNT; 435 436 for (i = cur + 1; (t = (i + max) % max) != cur; i++) 437 if (!VT_IS_DAEMON(t) && VT_IS_INUSE(t)) 438 return (t); 439 440 return (VT_MINOR_INVALID); 441 } 442 443 /* ARGSUSED */ 444 void 445 vt_send_hotkeys(void *timeout_arg) 446 { 447 door_handle_t door; 448 vt_cmd_arg_t arg; 449 int error = 0; 450 int retries = 0; 451 door_arg_t door_arg; 452 453 arg.vt_ev = VT_EV_HOTKEYS; 454 455 mutex_enter(&vt_pending_vtno_lock); 456 arg.vt_num = vt_pending_vtno; 457 mutex_exit(&vt_pending_vtno_lock); 458 459 /* only available in kernel context or user context */ 460 if (door_ki_open(VT_DAEMON_DOOR_FILE, &door) != 0) { 461 mutex_enter(&vt_pending_vtno_lock); 462 vt_pending_vtno = -1; 463 mutex_exit(&vt_pending_vtno_lock); 464 return; 465 } 466 467 door_arg.rbuf = NULL; 468 door_arg.rsize = 0; 469 door_arg.data_ptr = (void *)&arg; 470 door_arg.data_size = sizeof (arg); 471 door_arg.desc_ptr = NULL; 472 door_arg.desc_num = 0; 473 474 /* 475 * Make door upcall 476 */ 477 while ((error = door_ki_upcall(door, &door_arg)) != 0 && 478 retries < VT_DOORCALL_MAX_RETRY) 479 if (error == EAGAIN || error == EINTR) 480 retries++; 481 else 482 break; 483 484 door_ki_rele(door); 485 486 mutex_enter(&vt_pending_vtno_lock); 487 vt_pending_vtno = -1; 488 mutex_exit(&vt_pending_vtno_lock); 489 } 490 491 static boolean_t 492 vt_validate_hotkeys(int minor) 493 { 494 /* 495 * minor should not succeed the existing minor numbers range. 496 */ 497 if (!vt_minor_valid(minor)) 498 return (B_FALSE); 499 500 /* 501 * Shouldn't switch to /dev/vt/1 or an unused vt. 502 */ 503 if (!VT_IS_DAEMON(minor) && VT_IS_INUSE(minor)) 504 return (B_TRUE); 505 506 return (B_FALSE); 507 } 508 509 static void 510 vt_trigger_hotkeys(int vtno) 511 { 512 mutex_enter(&vt_pending_vtno_lock); 513 514 if (vt_pending_vtno != -1) { 515 mutex_exit(&vt_pending_vtno_lock); 516 return; 517 } 518 519 vt_pending_vtno = vtno; 520 mutex_exit(&vt_pending_vtno_lock); 521 (void) timeout(vt_send_hotkeys, NULL, 1); 522 } 523 524 /* 525 * return value: 526 * 0: non msg of vt hotkeys 527 * 1: msg of vt hotkeys 528 */ 529 int 530 vt_check_hotkeys(mblk_t *mp) 531 { 532 int vtno = 0; 533 minor_t minor = 0; 534 535 /* LINTED E_PTRDIFF_OVERFLOW */ 536 if (!VT_MSG_SWITCH(mp)) 537 return (0); 538 539 switch (VT_MSG_OPCODE(mp)) { 540 case 'B': 541 /* find out the previous vt */ 542 if (vc_active_console == VT_MINOR_INVALID) 543 return (1); 544 545 if (VT_IS_DAEMON(vc_active_console)) { 546 minor = vt_find_prev(vt_arg2minor(vc_target_console)); 547 break; 548 } 549 550 minor = vt_find_prev(vc_active_console); 551 break; 552 case 'F': 553 /* find out the next vt */ 554 if (vc_active_console == VT_MINOR_INVALID) 555 return (1); 556 557 if (VT_IS_DAEMON(vc_active_console)) { 558 minor = vt_find_next(vt_arg2minor(vc_target_console)); 559 break; 560 } 561 562 minor = vt_find_next(vc_active_console); 563 break; 564 case 'H': 565 /* find out the specified vt */ 566 minor = VT_MSG_VTNO(mp); 567 568 /* check for system console, Alt + F1 */ 569 if (minor == 1) 570 minor = 0; 571 break; 572 case 'L': 573 /* find out the last vt */ 574 if ((minor = vc_last_console) == VT_MINOR_INVALID) 575 return (1); 576 break; 577 default: 578 return (1); 579 } 580 581 if (!vt_validate_hotkeys(minor)) 582 return (1); 583 584 /* 585 * for system console, the argument of vtno for 586 * vt_activate is 1, though its minor is 0 587 */ 588 if (minor == 0) 589 vtno = 1; /* for system console */ 590 else 591 vtno = minor; 592 593 vt_trigger_hotkeys(vtno); 594 return (1); 595 } 596 597 static void 598 vt_proc_sendsig(pid_t pid, int sig) 599 { 600 register proc_t *p; 601 602 if (pid <= 0) 603 return; 604 605 mutex_enter(&pidlock); 606 if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) { 607 mutex_exit(&pidlock); 608 return; 609 } 610 611 psignal(p, sig); 612 mutex_exit(&pidlock); 613 } 614 615 static int 616 vt_proc_exists(pid_t pid) 617 { 618 register proc_t *p; 619 620 if (pid <= 0) 621 return (EINVAL); 622 623 mutex_enter(&pidlock); 624 if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) { 625 mutex_exit(&pidlock); 626 return (ESRCH); 627 } 628 mutex_exit(&pidlock); 629 630 return (0); 631 } 632 633 #define SIG_VALID(x) (((x) > 0) && ((x) <= MAXSIG) && \ 634 ((x) != SIGKILL) && ((x) != SIGSTOP)) 635 636 static int 637 vt_setmode(vc_state_t *pvc, struct vt_mode *pmode) 638 { 639 if ((pmode->mode != VT_PROCESS) && (pmode->mode != VT_AUTO)) 640 return (EINVAL); 641 642 if (!SIG_VALID(pmode->relsig) || !SIG_VALID(pmode->acqsig)) 643 return (EINVAL); 644 645 if (pmode->mode == VT_PROCESS) { 646 pvc->vc_pid = curproc->p_pid; 647 } else { 648 pvc->vc_dispnum = 0; 649 pvc->vc_login = 0; 650 } 651 652 pvc->vc_switch_mode = pmode->mode; 653 pvc->vc_waitv = pmode->waitv; 654 pvc->vc_relsig = pmode->relsig; 655 pvc->vc_acqsig = pmode->acqsig; 656 657 return (0); 658 } 659 660 static void 661 vt_reset(vc_state_t *pvc) 662 { 663 pvc->vc_switch_mode = VT_AUTO; 664 pvc->vc_pid = -1; 665 pvc->vc_dispnum = 0; 666 pvc->vc_login = 0; 667 pvc->vc_switchto = VT_MINOR_INVALID; 668 } 669 670 /* 671 * switch to vt_no from vc_active_console 672 */ 673 static int 674 vt_switch(uint_t vt_no, cred_t *credp) 675 { 676 vc_state_t *pvc_active = vt_minor2vc(vc_active_console); 677 vc_state_t *pvc = vt_minor2vc(vt_no); 678 minor_t index; 679 680 ASSERT(pvc_active && pvc); 681 682 /* sanity test for the target VT and the active VT */ 683 if (!((pvc->vc_flags & WCS_ISOPEN) && (pvc->vc_flags & WCS_INIT))) 684 return (EINVAL); 685 686 if (!((pvc_active->vc_flags & WCS_ISOPEN) && 687 (pvc_active->vc_flags & WCS_INIT))) 688 return (EINVAL); 689 690 mutex_enter(&vc_lock); 691 692 tem_switch(pvc_active->vc_tem, pvc->vc_tem, credp); 693 694 if (!VT_IS_DAEMON(vc_active_console)) 695 vc_last_console = vc_active_console; 696 else 697 vc_last_console = vt_arg2minor(vc_target_console); 698 699 vc_active_console = pvc->vc_minor; 700 701 if (pvc->vc_switch_mode == VT_PROCESS) { 702 pvc->vc_switchto = pvc->vc_minor; 703 704 /* send it an acquired signal */ 705 vt_proc_sendsig(pvc->vc_pid, pvc->vc_acqsig); 706 } 707 708 vc_waitactive_reply(vc_active_console, B_FALSE); 709 710 mutex_exit(&vc_lock); 711 712 if (!VT_IS_DAEMON(vt_no)) { 713 /* 714 * Applications that open the virtual console device may request 715 * asynchronous notification of VT switching from a previous VT 716 * to another one by setting the S_MSG flag in an I_SETSIG 717 * STREAMS ioctl. Such processes receive a SIGPOLL signal when 718 * a VT switching succeeds. 719 */ 720 for (index = 0; index < VC_INSTANCES_COUNT; index++) { 721 vc_state_t *tmp_pvc = vt_minor2vc(index); 722 mblk_t *mp; 723 724 if ((tmp_pvc->vc_flags & WCS_ISOPEN) && 725 (tmp_pvc->vc_flags & WCS_INIT) && 726 (mp = allocb(sizeof (unsigned char), BPRI_HI))) { 727 mp->b_datap->db_type = M_PCSIG; 728 *mp->b_wptr = SIGPOLL; 729 mp->b_wptr += sizeof (unsigned char); 730 putnext(RD(tmp_pvc->vc_wq), mp); 731 } 732 } 733 } 734 735 return (0); 736 737 } 738 739 /* 740 * vt_no from 0 to n 741 * 742 * 0 for the vtdaemon sepcial console (only vtdaemon will use it) 743 * 1 for the system console (Alt + F1, or Alt + Ctrl + F1), 744 * aka Virtual Console #1 745 * 746 * 2 for Virtual Console #2 747 * n for Virtual Console #n 748 */ 749 static minor_t 750 vt_arg2minor(uint_t arg) 751 { 752 if (arg == 0) 753 return (1); 754 755 if (arg == 1) 756 return (0); 757 758 return (arg); 759 } 760 761 static uint_t 762 vt_minor2arg(minor_t minor) 763 { 764 if (minor == 0) 765 return (1); 766 767 if (VT_IS_DAEMON(minor)) { 768 /* here it should be the real console */ 769 return (vc_target_console); 770 } 771 772 return (minor); 773 } 774 775 static int 776 vt_activate(uint_t vt_no, cred_t *credp) 777 { 778 vc_state_t *pvc; 779 minor_t minor; 780 781 minor = vt_arg2minor(vt_no); 782 if (!vt_minor_valid(minor)) 783 return (ENXIO); 784 if (minor == vc_active_console) { 785 if (VT_IS_DAEMON(minor)) { 786 /* 787 * vtdaemon is reactivating itself to do locking 788 * on behalf of another console, so record current 789 * target console as the last console. 790 */ 791 vc_last_console = vt_arg2minor(vc_target_console); 792 } 793 794 return (0); 795 } 796 797 /* 798 * In tipline case, the system console is redirected to tipline 799 * and thus is always available. 800 */ 801 if (minor == 0 && consconfig_console_is_tipline()) 802 return (0); 803 804 if (!VT_IS_INUSE(minor)) 805 return (ENXIO); 806 807 pvc = vt_minor2vc(minor); 808 if (pvc == NULL) 809 return (ENXIO); 810 if (pvc->vc_tem == NULL) 811 return (ENXIO); 812 813 pvc = vt_minor2vc(vc_active_console); 814 if (pvc == NULL) 815 return (ENXIO); 816 if (pvc->vc_switch_mode != VT_PROCESS) 817 return (vt_switch(minor, credp)); 818 819 /* 820 * Validate the process, reset the 821 * vt to auto mode if failed. 822 */ 823 if (pvc->vc_pid == -1 || vt_proc_exists(pvc->vc_pid) != 0) { 824 /* 825 * Xserver has not started up yet, 826 * or it dose not exist. 827 */ 828 vt_reset(pvc); 829 return (0); 830 } 831 832 /* 833 * Send the release signal to the process, 834 * and wait VT_RELDISP ioctl from Xserver 835 * after its leaving VT. 836 */ 837 vt_proc_sendsig(pvc->vc_pid, pvc->vc_relsig); 838 pvc->vc_switchto = minor; 839 840 /* 841 * We don't need a timeout here, for if Xserver refuses 842 * or fails to respond to release signal using VT_RELDISP, 843 * we cannot successfully switch to our text mode. Actually 844 * users can try again. At present we don't support force 845 * switch. 846 */ 847 return (0); 848 } 849 850 static int 851 vt_reldisp(vc_state_t *pvc, int arg, cred_t *credp) 852 { 853 minor_t target_vtno = pvc->vc_switchto; 854 855 if ((pvc->vc_switch_mode != VT_PROCESS) || 856 (pvc->vc_minor != vc_active_console)) 857 return (EACCES); 858 859 if (target_vtno == VT_MINOR_INVALID) 860 return (EINVAL); 861 862 pvc->vc_switchto = VT_MINOR_INVALID; 863 864 if (arg == VT_ACKACQ) 865 return (0); 866 867 if (arg == 0) 868 return (0); /* refuse to release */ 869 870 /* Xserver has left VT */ 871 return (vt_switch(target_vtno, credp)); 872 } 873 874 void 875 vt_ioctl(queue_t *q, mblk_t *mp) 876 { 877 vc_state_t *pvc = (vc_state_t *)q->q_ptr; 878 struct iocblk *iocp; 879 struct vt_mode vtmode; 880 struct vt_stat vtinfo; 881 struct vt_dispinfo vtdisp; 882 mblk_t *tmp; 883 int minor; 884 int arg; 885 int error = 0; 886 vc_waitactive_msg_t *wait_msg; 887 888 iocp = (struct iocblk *)(void *)mp->b_rptr; 889 if (consmode != CONS_KFB && iocp->ioc_cmd != VT_ENABLED) { 890 vt_iocnak(q, mp, EINVAL); 891 return; 892 } 893 894 switch (iocp->ioc_cmd) { 895 case VT_ENABLED: 896 if (!(tmp = allocb(sizeof (int), BPRI_MED))) { 897 error = ENOMEM; 898 break; 899 } 900 *(int *)(void *)tmp->b_rptr = consmode; 901 tmp->b_wptr += sizeof (int); 902 vt_copyout(q, mp, tmp, sizeof (int)); 903 return; 904 905 case KDSETMODE: 906 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr; 907 if (arg != KD_TEXT && arg != KD_GRAPHICS) { 908 error = EINVAL; 909 break; 910 } 911 if (tem_get_fbmode(pvc->vc_tem) == arg) 912 break; 913 914 tem_set_fbmode(pvc->vc_tem, (uchar_t)arg, iocp->ioc_cr); 915 916 break; 917 918 case KDGETMODE: 919 if (!(tmp = allocb(sizeof (int), BPRI_MED))) { 920 error = ENOMEM; 921 break; 922 } 923 *(int *)(void *)tmp->b_rptr = tem_get_fbmode(pvc->vc_tem); 924 tmp->b_wptr += sizeof (int); 925 vt_copyout(q, mp, tmp, sizeof (int)); 926 return; 927 928 case VT_OPENQRY: /* return number of first free VT */ 929 if (!(tmp = allocb(sizeof (int), BPRI_MED))) { 930 error = ENOMEM; 931 break; 932 } 933 934 /* minors of 0 and 1 are not available to end users */ 935 for (minor = 2; vt_minor_valid(minor); minor++) 936 if (!VT_IS_INUSE(minor)) 937 break; 938 939 if (!vt_minor_valid(minor)) 940 minor = -1; 941 *(int *)(void *)tmp->b_rptr = minor; /* /dev/vt/minor */ 942 tmp->b_wptr += sizeof (int); 943 vt_copyout(q, mp, tmp, sizeof (int)); 944 return; 945 946 case VT_GETMODE: 947 vtmode.mode = pvc->vc_switch_mode; 948 vtmode.waitv = pvc->vc_waitv; 949 vtmode.relsig = pvc->vc_relsig; 950 vtmode.acqsig = pvc->vc_acqsig; 951 vtmode.frsig = 0; 952 if (!(tmp = allocb(sizeof (struct vt_mode), BPRI_MED))) { 953 error = ENOMEM; 954 break; 955 } 956 *(struct vt_mode *)(void *)tmp->b_rptr = vtmode; 957 tmp->b_wptr += sizeof (struct vt_mode); 958 vt_copyout(q, mp, tmp, sizeof (struct vt_mode)); 959 return; 960 961 case VT_SETMODE: 962 vt_copyin(q, mp, sizeof (struct vt_mode)); 963 return; 964 965 case VT_SETDISPINFO: 966 /* always enforce sys_devices privilege for setdispinfo */ 967 if ((error = secpolicy_console(iocp->ioc_cr)) != 0) 968 break; 969 970 pvc->vc_dispnum = *(intptr_t *)(void *)mp->b_cont->b_rptr; 971 break; 972 973 case VT_SETDISPLOGIN: 974 pvc->vc_login = *(intptr_t *)(void *)mp->b_cont->b_rptr; 975 break; 976 977 case VT_GETDISPINFO: 978 vtdisp.v_pid = pvc->vc_pid; 979 vtdisp.v_dispnum = pvc->vc_dispnum; 980 vtdisp.v_login = pvc->vc_login; 981 if (!(tmp = allocb(sizeof (struct vt_dispinfo), BPRI_MED))) { 982 error = ENOMEM; 983 break; 984 } 985 *(struct vt_dispinfo *)(void *)tmp->b_rptr = vtdisp; 986 tmp->b_wptr += sizeof (struct vt_dispinfo); 987 vt_copyout(q, mp, tmp, sizeof (struct vt_dispinfo)); 988 return; 989 990 case VT_RELDISP: 991 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr; 992 error = vt_reldisp(pvc, arg, iocp->ioc_cr); 993 break; 994 995 case VT_CONFIG: 996 /* always enforce sys_devices privilege for config */ 997 if ((error = secpolicy_console(iocp->ioc_cr)) != 0) 998 break; 999 1000 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr; 1001 error = vt_config(arg); 1002 break; 1003 1004 case VT_ACTIVATE: 1005 /* always enforce sys_devices privilege for secure switch */ 1006 if ((error = secpolicy_console(iocp->ioc_cr)) != 0) 1007 break; 1008 1009 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr; 1010 error = vt_activate(arg, iocp->ioc_cr); 1011 break; 1012 1013 case VT_WAITACTIVE: 1014 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr; 1015 arg = vt_arg2minor(arg); 1016 if (!vt_minor_valid(arg)) { 1017 error = ENXIO; 1018 break; 1019 } 1020 if (arg == vc_active_console) 1021 break; 1022 1023 wait_msg = kmem_zalloc(sizeof (vc_waitactive_msg_t), 1024 KM_NOSLEEP); 1025 if (wait_msg == NULL) { 1026 error = ENXIO; 1027 break; 1028 } 1029 1030 wait_msg->wa_mp = mp; 1031 wait_msg->wa_msg_minor = pvc->vc_minor; 1032 wait_msg->wa_wait_minor = arg; 1033 list_insert_head(&vc_waitactive_list, wait_msg); 1034 1035 return; 1036 1037 case VT_GETSTATE: 1038 /* 1039 * Here v_active is the argument for vt_activate, 1040 * not minor. 1041 */ 1042 vtinfo.v_active = vt_minor2arg(vc_active_console); 1043 vtinfo.v_state = 3; /* system console and vtdaemon */ 1044 1045 /* we only support 16 vt states since the v_state is short */ 1046 for (minor = 2; minor < 16; minor++) { 1047 pvc = vt_minor2vc(minor); 1048 if (pvc == NULL) 1049 break; 1050 if (VT_IS_INUSE(minor)) 1051 vtinfo.v_state |= (1 << pvc->vc_minor); 1052 } 1053 1054 if (!(tmp = allocb(sizeof (struct vt_stat), BPRI_MED))) { 1055 error = ENOMEM; 1056 break; 1057 } 1058 *(struct vt_stat *)(void *)tmp->b_rptr = vtinfo; 1059 tmp->b_wptr += sizeof (struct vt_stat); 1060 vt_copyout(q, mp, tmp, sizeof (struct vt_stat)); 1061 return; 1062 1063 case VT_SET_TARGET: 1064 /* always enforce sys_devices privilege */ 1065 if ((error = secpolicy_console(iocp->ioc_cr)) != 0) 1066 break; 1067 1068 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr; 1069 1070 /* vtdaemon is doing authentication for this target console */ 1071 vc_target_console = arg; 1072 break; 1073 1074 case VT_GETACTIVE: /* get real active console (minor) */ 1075 if (!(tmp = allocb(sizeof (int), BPRI_MED))) { 1076 error = ENOMEM; 1077 break; 1078 } 1079 *(int *)(void *)tmp->b_rptr = vc_active_console; 1080 tmp->b_wptr += sizeof (int); 1081 vt_copyout(q, mp, tmp, sizeof (int)); 1082 return; 1083 1084 case VT_GET_CONSUSER: 1085 if (!(tmp = allocb(sizeof (int), BPRI_MED))) { 1086 error = ENOMEM; 1087 break; 1088 } 1089 1090 if (vc_cons_user == VT_MINOR_INVALID) { 1091 /* 1092 * Return -1 if console user link points to 1093 * /dev/console 1094 */ 1095 *(int *)(void *)tmp->b_rptr = -1; 1096 } else { 1097 *(int *)(void *)tmp->b_rptr = vc_cons_user; 1098 } 1099 1100 tmp->b_wptr += sizeof (int); 1101 vt_copyout(q, mp, tmp, sizeof (int)); 1102 return; 1103 1104 case VT_RESET_CONSUSER: 1105 /* always enforce sys_devices privilege */ 1106 if ((error = secpolicy_console(iocp->ioc_cr)) != 0) 1107 break; 1108 1109 /* Ensure it comes from /dev/console */ 1110 if (pvc->vc_minor != 0) { 1111 error = ENXIO; 1112 break; 1113 } 1114 1115 mutex_enter(&vc_lock); 1116 vc_cons_user = VT_MINOR_INVALID; 1117 mutex_exit(&vc_lock); 1118 break; 1119 1120 case VT_SET_CONSUSER: 1121 /* always enforce sys_devices privilege */ 1122 if ((error = secpolicy_console(iocp->ioc_cr)) != 0) 1123 break; 1124 1125 mutex_enter(&vc_lock); 1126 vc_cons_user = pvc->vc_minor; 1127 mutex_exit(&vc_lock); 1128 break; 1129 1130 default: 1131 error = ENXIO; 1132 break; 1133 } 1134 1135 if (error != 0) 1136 vt_iocnak(q, mp, error); 1137 else 1138 vt_iocack(q, mp); 1139 } 1140 1141 void 1142 vt_miocdata(queue_t *qp, mblk_t *mp) 1143 { 1144 vc_state_t *pvc = (vc_state_t *)qp->q_ptr; 1145 struct copyresp *copyresp; 1146 struct vt_mode *pmode; 1147 int error = 0; 1148 1149 copyresp = (struct copyresp *)(void *)mp->b_rptr; 1150 if (copyresp->cp_rval) { 1151 vt_iocnak(qp, mp, EAGAIN); 1152 return; 1153 } 1154 1155 switch (copyresp->cp_cmd) { 1156 case VT_SETMODE: 1157 pmode = (struct vt_mode *)(void *)mp->b_cont->b_rptr; 1158 error = vt_setmode(pvc, pmode); 1159 break; 1160 1161 case KDGETMODE: 1162 case VT_OPENQRY: 1163 case VT_GETMODE: 1164 case VT_GETDISPINFO: 1165 case VT_GETSTATE: 1166 case VT_ENABLED: 1167 case VT_GETACTIVE: 1168 break; 1169 1170 default: 1171 error = ENXIO; 1172 break; 1173 } 1174 1175 if (error != 0) 1176 vt_iocnak(qp, mp, error); 1177 else 1178 vt_iocack(qp, mp); 1179 } 1180 1181 static void 1182 vt_iocack(queue_t *qp, mblk_t *mp) 1183 { 1184 struct iocblk *iocbp = (struct iocblk *)(void *)mp->b_rptr; 1185 1186 mp->b_datap->db_type = M_IOCACK; 1187 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 1188 iocbp->ioc_error = 0; 1189 iocbp->ioc_count = 0; 1190 iocbp->ioc_rval = 0; 1191 if (mp->b_cont != NULL) { 1192 freemsg(mp->b_cont); 1193 mp->b_cont = NULL; 1194 } 1195 qreply(qp, mp); 1196 } 1197 1198 static void 1199 vt_iocnak(queue_t *qp, mblk_t *mp, int error) 1200 { 1201 struct iocblk *iocp = (struct iocblk *)(void *)mp->b_rptr; 1202 1203 mp->b_datap->db_type = M_IOCNAK; 1204 iocp->ioc_rval = 0; 1205 iocp->ioc_count = 0; 1206 iocp->ioc_error = error; 1207 if (mp->b_cont != NULL) { 1208 freemsg(mp->b_cont); 1209 mp->b_cont = NULL; 1210 } 1211 qreply(qp, mp); 1212 } 1213 1214 static void 1215 vt_copyin(queue_t *qp, mblk_t *mp, uint_t size) 1216 { 1217 struct copyreq *cqp; 1218 1219 cqp = (struct copyreq *)(void *)mp->b_rptr; 1220 cqp->cq_addr = *((caddr_t *)(void *)mp->b_cont->b_rptr); 1221 cqp->cq_size = size; 1222 cqp->cq_flag = 0; 1223 cqp->cq_private = (mblk_t *)NULL; 1224 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 1225 mp->b_datap->db_type = M_COPYIN; 1226 if (mp->b_cont) 1227 freemsg(mp->b_cont); 1228 mp->b_cont = (mblk_t *)NULL; 1229 qreply(qp, mp); 1230 } 1231 1232 static void 1233 vt_copyout(queue_t *qp, mblk_t *mp, mblk_t *tmp, uint_t size) 1234 { 1235 struct copyreq *cqp; 1236 1237 cqp = (struct copyreq *)(void *)mp->b_rptr; 1238 cqp->cq_size = size; 1239 cqp->cq_addr = *((caddr_t *)(void *)mp->b_cont->b_rptr); 1240 cqp->cq_flag = 0; 1241 cqp->cq_private = (mblk_t *)NULL; 1242 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 1243 mp->b_datap->db_type = M_COPYOUT; 1244 if (mp->b_cont) 1245 freemsg(mp->b_cont); 1246 mp->b_cont = tmp; 1247 qreply(qp, mp); 1248 } 1249 1250 /* 1251 * Get vc state from minor. 1252 * Once a caller gets a vc_state_t from this function, 1253 * the vc_state_t is guaranteed not being freed before 1254 * the caller leaves this STREAMS module by the D_MTPERMOD 1255 * perimeter. 1256 */ 1257 vc_state_t * 1258 vt_minor2vc(minor_t minor) 1259 { 1260 avl_index_t where; 1261 vc_state_t target; 1262 1263 if (minor != VT_ACTIVE) { 1264 target.vc_minor = minor; 1265 return (avl_find(&vc_avl_root, &target, &where)); 1266 } 1267 1268 if (vc_active_console == VT_MINOR_INVALID) 1269 target.vc_minor = 0; 1270 else 1271 target.vc_minor = vc_active_console; 1272 1273 return (avl_find(&vc_avl_root, &target, &where)); 1274 } 1275 1276 static void 1277 vt_state_init(vc_state_t *vcptr, minor_t minor) 1278 { 1279 mutex_init(&vcptr->vc_state_lock, NULL, MUTEX_DRIVER, NULL); 1280 1281 mutex_enter(&vcptr->vc_state_lock); 1282 vcptr->vc_flags = 0; 1283 mutex_exit(&vcptr->vc_state_lock); 1284 1285 vcptr->vc_pid = -1; 1286 vcptr->vc_dispnum = 0; 1287 vcptr->vc_login = 0; 1288 vcptr->vc_switchto = VT_MINOR_INVALID; 1289 vcptr->vc_switch_mode = VT_AUTO; 1290 vcptr->vc_relsig = SIGUSR1; 1291 vcptr->vc_acqsig = SIGUSR1; 1292 vcptr->vc_tem = NULL; 1293 vcptr->vc_bufcallid = 0; 1294 vcptr->vc_timeoutid = 0; 1295 vcptr->vc_wq = NULL; 1296 vcptr->vc_minor = minor; 1297 } 1298 1299 void 1300 vt_resize(uint_t count) 1301 { 1302 uint_t vc_num, i; 1303 1304 ASSERT(MUTEX_HELD(&vc_lock)); 1305 1306 vc_num = VC_INSTANCES_COUNT; 1307 1308 if (count == vc_num) 1309 return; 1310 1311 if (count > vc_num) { 1312 for (i = vc_num; i < count; i++) { 1313 vc_state_t *vcptr = kmem_zalloc(sizeof (vc_state_t), 1314 KM_SLEEP); 1315 vt_state_init(vcptr, i); 1316 avl_add(&vc_avl_root, vcptr); 1317 } 1318 return; 1319 } 1320 1321 for (i = vc_num; i > count; i--) { 1322 avl_index_t where; 1323 vc_state_t target, *found; 1324 1325 target.vc_minor = i - 1; 1326 found = avl_find(&vc_avl_root, &target, &where); 1327 ASSERT(found != NULL && found->vc_flags == 0); 1328 avl_remove(&vc_avl_root, found); 1329 kmem_free(found, sizeof (vc_state_t)); 1330 } 1331 } 1332 1333 static int 1334 vc_avl_compare(const void *first, const void *second) 1335 { 1336 const vc_state_t *vcptr1 = first; 1337 const vc_state_t *vcptr2 = second; 1338 1339 if (vcptr1->vc_minor < vcptr2->vc_minor) 1340 return (-1); 1341 1342 if (vcptr1->vc_minor == vcptr2->vc_minor) 1343 return (0); 1344 1345 return (1); 1346 } 1347 1348 /* 1349 * Only called from wc init(). 1350 */ 1351 void 1352 vt_init(void) 1353 { 1354 #ifdef __lock_lint 1355 ASSERT(NO_COMPETING_THREADS); 1356 #endif 1357 1358 avl_create(&vc_avl_root, vc_avl_compare, sizeof (vc_state_t), 1359 offsetof(vc_state_t, vc_avl_node)); 1360 1361 list_create(&vc_waitactive_list, sizeof (vc_waitactive_msg_t), 1362 offsetof(vc_waitactive_msg_t, wa_list_node)); 1363 1364 mutex_init(&vc_lock, NULL, MUTEX_DRIVER, NULL); 1365 mutex_init(&vt_pending_vtno_lock, NULL, MUTEX_DRIVER, NULL); 1366 } 1367