1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Provide access to virtual console memory. 4 * /dev/vcs: the screen as it is being viewed right now (possibly scrolled) 5 * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63) 6 * [minor: N] 7 * 8 * /dev/vcsaN: idem, but including attributes, and prefixed with 9 * the 4 bytes lines,columns,x,y (as screendump used to give). 10 * Attribute/character pair is in native endianity. 11 * [minor: N+128] 12 * 13 * /dev/vcsuN: similar to /dev/vcsaN but using 4-byte unicode values 14 * instead of 1-byte screen glyph values. 15 * [minor: N+64] 16 * 17 * /dev/vcsuaN: same idea as /dev/vcsaN for unicode (not yet implemented). 18 * 19 * This replaces screendump and part of selection, so that the system 20 * administrator can control access using file system permissions. 21 * 22 * aeb@cwi.nl - efter Friedas begravelse - 950211 23 * 24 * machek@k332.feld.cvut.cz - modified not to send characters to wrong console 25 * - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...) 26 * - making it shorter - scr_readw are macros which expand in PRETTY long code 27 */ 28 29 #include <linux/kernel.h> 30 #include <linux/major.h> 31 #include <linux/errno.h> 32 #include <linux/export.h> 33 #include <linux/tty.h> 34 #include <linux/interrupt.h> 35 #include <linux/mm.h> 36 #include <linux/init.h> 37 #include <linux/vt_kern.h> 38 #include <linux/selection.h> 39 #include <linux/kbd_kern.h> 40 #include <linux/console.h> 41 #include <linux/device.h> 42 #include <linux/sched.h> 43 #include <linux/fs.h> 44 #include <linux/poll.h> 45 #include <linux/signal.h> 46 #include <linux/slab.h> 47 #include <linux/notifier.h> 48 49 #include <linux/uaccess.h> 50 #include <asm/byteorder.h> 51 #include <asm/unaligned.h> 52 53 #undef attr 54 #undef org 55 #undef addr 56 #define HEADER_SIZE 4 57 58 #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) 59 60 /* 61 * Our minor space: 62 * 63 * 0 ... 63 glyph mode without attributes 64 * 64 ... 127 unicode mode without attributes 65 * 128 ... 191 glyph mode with attributes 66 * 192 ... 255 unused (reserved for unicode with attributes) 67 * 68 * This relies on MAX_NR_CONSOLES being <= 63, meaning 63 actual consoles 69 * with minors 0, 64, 128 and 192 being proxies for the foreground console. 70 */ 71 #if MAX_NR_CONSOLES > 63 72 #warning "/dev/vcs* devices may not accommodate more than 63 consoles" 73 #endif 74 75 #define console(inode) (iminor(inode) & 63) 76 #define use_unicode(inode) (iminor(inode) & 64) 77 #define use_attributes(inode) (iminor(inode) & 128) 78 79 80 struct vcs_poll_data { 81 struct notifier_block notifier; 82 unsigned int cons_num; 83 int event; 84 wait_queue_head_t waitq; 85 struct fasync_struct *fasync; 86 }; 87 88 static int 89 vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param) 90 { 91 struct vt_notifier_param *param = _param; 92 struct vc_data *vc = param->vc; 93 struct vcs_poll_data *poll = 94 container_of(nb, struct vcs_poll_data, notifier); 95 int currcons = poll->cons_num; 96 int fa_band; 97 98 switch (code) { 99 case VT_UPDATE: 100 fa_band = POLL_PRI; 101 break; 102 case VT_DEALLOCATE: 103 fa_band = POLL_HUP; 104 break; 105 default: 106 return NOTIFY_DONE; 107 } 108 109 if (currcons == 0) 110 currcons = fg_console; 111 else 112 currcons--; 113 if (currcons != vc->vc_num) 114 return NOTIFY_DONE; 115 116 poll->event = code; 117 wake_up_interruptible(&poll->waitq); 118 kill_fasync(&poll->fasync, SIGIO, fa_band); 119 return NOTIFY_OK; 120 } 121 122 static void 123 vcs_poll_data_free(struct vcs_poll_data *poll) 124 { 125 unregister_vt_notifier(&poll->notifier); 126 kfree(poll); 127 } 128 129 static struct vcs_poll_data * 130 vcs_poll_data_get(struct file *file) 131 { 132 struct vcs_poll_data *poll = file->private_data, *kill = NULL; 133 134 if (poll) 135 return poll; 136 137 poll = kzalloc(sizeof(*poll), GFP_KERNEL); 138 if (!poll) 139 return NULL; 140 poll->cons_num = console(file_inode(file)); 141 init_waitqueue_head(&poll->waitq); 142 poll->notifier.notifier_call = vcs_notifier; 143 /* 144 * In order not to lose any update event, we must pretend one might 145 * have occurred before we have a chance to register our notifier. 146 * This is also how user space has come to detect which kernels 147 * support POLLPRI on /dev/vcs* devices i.e. using poll() with 148 * POLLPRI and a zero timeout. 149 */ 150 poll->event = VT_UPDATE; 151 152 if (register_vt_notifier(&poll->notifier) != 0) { 153 kfree(poll); 154 return NULL; 155 } 156 157 /* 158 * This code may be called either through ->poll() or ->fasync(). 159 * If we have two threads using the same file descriptor, they could 160 * both enter this function, both notice that the structure hasn't 161 * been allocated yet and go ahead allocating it in parallel, but 162 * only one of them must survive and be shared otherwise we'd leak 163 * memory with a dangling notifier callback. 164 */ 165 spin_lock(&file->f_lock); 166 if (!file->private_data) { 167 file->private_data = poll; 168 } else { 169 /* someone else raced ahead of us */ 170 kill = poll; 171 poll = file->private_data; 172 } 173 spin_unlock(&file->f_lock); 174 if (kill) 175 vcs_poll_data_free(kill); 176 177 return poll; 178 } 179 180 /* 181 * Returns VC for inode. 182 * Must be called with console_lock. 183 */ 184 static struct vc_data* 185 vcs_vc(struct inode *inode, int *viewed) 186 { 187 unsigned int currcons = console(inode); 188 189 WARN_CONSOLE_UNLOCKED(); 190 191 if (currcons == 0) { 192 currcons = fg_console; 193 if (viewed) 194 *viewed = 1; 195 } else { 196 currcons--; 197 if (viewed) 198 *viewed = 0; 199 } 200 return vc_cons[currcons].d; 201 } 202 203 /* 204 * Returns size for VC carried by inode. 205 * Must be called with console_lock. 206 */ 207 static int 208 vcs_size(struct inode *inode) 209 { 210 int size; 211 struct vc_data *vc; 212 213 WARN_CONSOLE_UNLOCKED(); 214 215 vc = vcs_vc(inode, NULL); 216 if (!vc) 217 return -ENXIO; 218 219 size = vc->vc_rows * vc->vc_cols; 220 221 if (use_attributes(inode)) { 222 if (use_unicode(inode)) 223 return -EOPNOTSUPP; 224 size = 2*size + HEADER_SIZE; 225 } else if (use_unicode(inode)) 226 size *= 4; 227 return size; 228 } 229 230 static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) 231 { 232 int size; 233 234 console_lock(); 235 size = vcs_size(file_inode(file)); 236 console_unlock(); 237 if (size < 0) 238 return size; 239 return fixed_size_llseek(file, offset, orig, size); 240 } 241 242 243 static ssize_t 244 vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 245 { 246 struct inode *inode = file_inode(file); 247 struct vc_data *vc; 248 struct vcs_poll_data *poll; 249 long pos, read; 250 int attr, uni_mode, row, col, maxcol, viewed; 251 unsigned short *org = NULL; 252 ssize_t ret; 253 char *con_buf; 254 255 con_buf = (char *) __get_free_page(GFP_KERNEL); 256 if (!con_buf) 257 return -ENOMEM; 258 259 pos = *ppos; 260 261 /* Select the proper current console and verify 262 * sanity of the situation under the console lock. 263 */ 264 console_lock(); 265 266 uni_mode = use_unicode(inode); 267 attr = use_attributes(inode); 268 ret = -ENXIO; 269 vc = vcs_vc(inode, &viewed); 270 if (!vc) 271 goto unlock_out; 272 273 ret = -EINVAL; 274 if (pos < 0) 275 goto unlock_out; 276 /* we enforce 32-bit alignment for pos and count in unicode mode */ 277 if (uni_mode && (pos | count) & 3) 278 goto unlock_out; 279 280 poll = file->private_data; 281 if (count && poll) 282 poll->event = 0; 283 read = 0; 284 ret = 0; 285 while (count) { 286 char *con_buf0, *con_buf_start; 287 long this_round, size; 288 ssize_t orig_count; 289 long p = pos; 290 291 /* Check whether we are above size each round, 292 * as copy_to_user at the end of this loop 293 * could sleep. 294 */ 295 size = vcs_size(inode); 296 if (size < 0) { 297 if (read) 298 break; 299 ret = size; 300 goto unlock_out; 301 } 302 if (pos >= size) 303 break; 304 if (count > size - pos) 305 count = size - pos; 306 307 this_round = count; 308 if (this_round > CON_BUF_SIZE) 309 this_round = CON_BUF_SIZE; 310 311 /* Perform the whole read into the local con_buf. 312 * Then we can drop the console spinlock and safely 313 * attempt to move it to userspace. 314 */ 315 316 con_buf_start = con_buf0 = con_buf; 317 orig_count = this_round; 318 maxcol = vc->vc_cols; 319 if (uni_mode) { 320 unsigned int nr; 321 322 ret = vc_uniscr_check(vc); 323 if (ret) 324 break; 325 p /= 4; 326 row = p / vc->vc_cols; 327 col = p % maxcol; 328 nr = maxcol - col; 329 do { 330 if (nr > this_round/4) 331 nr = this_round/4; 332 vc_uniscr_copy_line(vc, con_buf0, viewed, 333 row, col, nr); 334 con_buf0 += nr * 4; 335 this_round -= nr * 4; 336 row++; 337 col = 0; 338 nr = maxcol; 339 } while (this_round); 340 } else if (!attr) { 341 org = screen_pos(vc, p, viewed); 342 col = p % maxcol; 343 p += maxcol - col; 344 while (this_round-- > 0) { 345 *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff); 346 if (++col == maxcol) { 347 org = screen_pos(vc, p, viewed); 348 col = 0; 349 p += maxcol; 350 } 351 } 352 } else { 353 if (p < HEADER_SIZE) { 354 size_t tmp_count; 355 356 /* clamp header values if they don't fit */ 357 con_buf0[0] = min(vc->vc_rows, 0xFFu); 358 con_buf0[1] = min(vc->vc_cols, 0xFFu); 359 getconsxy(vc, con_buf0 + 2); 360 361 con_buf_start += p; 362 this_round += p; 363 if (this_round > CON_BUF_SIZE) { 364 this_round = CON_BUF_SIZE; 365 orig_count = this_round - p; 366 } 367 368 tmp_count = HEADER_SIZE; 369 if (tmp_count > this_round) 370 tmp_count = this_round; 371 372 /* Advance state pointers and move on. */ 373 this_round -= tmp_count; 374 p = HEADER_SIZE; 375 con_buf0 = con_buf + HEADER_SIZE; 376 /* If this_round >= 0, then p is even... */ 377 } else if (p & 1) { 378 /* Skip first byte for output if start address is odd 379 * Update region sizes up/down depending on free 380 * space in buffer. 381 */ 382 con_buf_start++; 383 if (this_round < CON_BUF_SIZE) 384 this_round++; 385 else 386 orig_count--; 387 } 388 if (this_round > 0) { 389 unsigned short *tmp_buf = (unsigned short *)con_buf0; 390 391 p -= HEADER_SIZE; 392 p /= 2; 393 col = p % maxcol; 394 395 org = screen_pos(vc, p, viewed); 396 p += maxcol - col; 397 398 /* Buffer has even length, so we can always copy 399 * character + attribute. We do not copy last byte 400 * to userspace if this_round is odd. 401 */ 402 this_round = (this_round + 1) >> 1; 403 404 while (this_round) { 405 *tmp_buf++ = vcs_scr_readw(vc, org++); 406 this_round --; 407 if (++col == maxcol) { 408 org = screen_pos(vc, p, viewed); 409 col = 0; 410 p += maxcol; 411 } 412 } 413 } 414 } 415 416 /* Finally, release the console semaphore while we push 417 * all the data to userspace from our temporary buffer. 418 * 419 * AKPM: Even though it's a semaphore, we should drop it because 420 * the pagefault handling code may want to call printk(). 421 */ 422 423 console_unlock(); 424 ret = copy_to_user(buf, con_buf_start, orig_count); 425 console_lock(); 426 427 if (ret) { 428 read += (orig_count - ret); 429 ret = -EFAULT; 430 break; 431 } 432 buf += orig_count; 433 pos += orig_count; 434 read += orig_count; 435 count -= orig_count; 436 } 437 *ppos += read; 438 if (read) 439 ret = read; 440 unlock_out: 441 console_unlock(); 442 free_page((unsigned long) con_buf); 443 return ret; 444 } 445 446 static ssize_t 447 vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 448 { 449 struct inode *inode = file_inode(file); 450 struct vc_data *vc; 451 long pos; 452 long attr, size, written; 453 char *con_buf0; 454 int col, maxcol, viewed; 455 u16 *org0 = NULL, *org = NULL; 456 size_t ret; 457 char *con_buf; 458 459 if (use_unicode(inode)) 460 return -EOPNOTSUPP; 461 462 con_buf = (char *) __get_free_page(GFP_KERNEL); 463 if (!con_buf) 464 return -ENOMEM; 465 466 pos = *ppos; 467 468 /* Select the proper current console and verify 469 * sanity of the situation under the console lock. 470 */ 471 console_lock(); 472 473 attr = use_attributes(inode); 474 ret = -ENXIO; 475 vc = vcs_vc(inode, &viewed); 476 if (!vc) 477 goto unlock_out; 478 479 size = vcs_size(inode); 480 ret = -EINVAL; 481 if (pos < 0 || pos > size) 482 goto unlock_out; 483 if (count > size - pos) 484 count = size - pos; 485 written = 0; 486 while (count) { 487 long this_round = count; 488 size_t orig_count; 489 long p; 490 491 if (this_round > CON_BUF_SIZE) 492 this_round = CON_BUF_SIZE; 493 494 /* Temporarily drop the console lock so that we can read 495 * in the write data from userspace safely. 496 */ 497 console_unlock(); 498 ret = copy_from_user(con_buf, buf, this_round); 499 console_lock(); 500 501 if (ret) { 502 this_round -= ret; 503 if (!this_round) { 504 /* Abort loop if no data were copied. Otherwise 505 * fail with -EFAULT. 506 */ 507 if (written) 508 break; 509 ret = -EFAULT; 510 goto unlock_out; 511 } 512 } 513 514 /* The vcs_size might have changed while we slept to grab 515 * the user buffer, so recheck. 516 * Return data written up to now on failure. 517 */ 518 size = vcs_size(inode); 519 if (size < 0) { 520 if (written) 521 break; 522 ret = size; 523 goto unlock_out; 524 } 525 if (pos >= size) 526 break; 527 if (this_round > size - pos) 528 this_round = size - pos; 529 530 /* OK, now actually push the write to the console 531 * under the lock using the local kernel buffer. 532 */ 533 534 con_buf0 = con_buf; 535 orig_count = this_round; 536 maxcol = vc->vc_cols; 537 p = pos; 538 if (!attr) { 539 org0 = org = screen_pos(vc, p, viewed); 540 col = p % maxcol; 541 p += maxcol - col; 542 543 while (this_round > 0) { 544 unsigned char c = *con_buf0++; 545 546 this_round--; 547 vcs_scr_writew(vc, 548 (vcs_scr_readw(vc, org) & 0xff00) | c, org); 549 org++; 550 if (++col == maxcol) { 551 org = screen_pos(vc, p, viewed); 552 col = 0; 553 p += maxcol; 554 } 555 } 556 } else { 557 if (p < HEADER_SIZE) { 558 char header[HEADER_SIZE]; 559 560 getconsxy(vc, header + 2); 561 while (p < HEADER_SIZE && this_round > 0) { 562 this_round--; 563 header[p++] = *con_buf0++; 564 } 565 if (!viewed) 566 putconsxy(vc, header + 2); 567 } 568 p -= HEADER_SIZE; 569 col = (p/2) % maxcol; 570 if (this_round > 0) { 571 org0 = org = screen_pos(vc, p/2, viewed); 572 if ((p & 1) && this_round > 0) { 573 char c; 574 575 this_round--; 576 c = *con_buf0++; 577 #ifdef __BIG_ENDIAN 578 vcs_scr_writew(vc, c | 579 (vcs_scr_readw(vc, org) & 0xff00), org); 580 #else 581 vcs_scr_writew(vc, (c << 8) | 582 (vcs_scr_readw(vc, org) & 0xff), org); 583 #endif 584 org++; 585 p++; 586 if (++col == maxcol) { 587 org = screen_pos(vc, p/2, viewed); 588 col = 0; 589 } 590 } 591 p /= 2; 592 p += maxcol - col; 593 } 594 while (this_round > 1) { 595 unsigned short w; 596 597 w = get_unaligned(((unsigned short *)con_buf0)); 598 vcs_scr_writew(vc, w, org++); 599 con_buf0 += 2; 600 this_round -= 2; 601 if (++col == maxcol) { 602 org = screen_pos(vc, p, viewed); 603 col = 0; 604 p += maxcol; 605 } 606 } 607 if (this_round > 0) { 608 unsigned char c; 609 610 c = *con_buf0++; 611 #ifdef __BIG_ENDIAN 612 vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org); 613 #else 614 vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org); 615 #endif 616 } 617 } 618 count -= orig_count; 619 written += orig_count; 620 buf += orig_count; 621 pos += orig_count; 622 if (org0) 623 update_region(vc, (unsigned long)(org0), org - org0); 624 } 625 *ppos += written; 626 ret = written; 627 if (written) 628 vcs_scr_updated(vc); 629 630 unlock_out: 631 console_unlock(); 632 free_page((unsigned long) con_buf); 633 return ret; 634 } 635 636 static __poll_t 637 vcs_poll(struct file *file, poll_table *wait) 638 { 639 struct vcs_poll_data *poll = vcs_poll_data_get(file); 640 __poll_t ret = DEFAULT_POLLMASK|EPOLLERR; 641 642 if (poll) { 643 poll_wait(file, &poll->waitq, wait); 644 switch (poll->event) { 645 case VT_UPDATE: 646 ret = DEFAULT_POLLMASK|EPOLLPRI; 647 break; 648 case VT_DEALLOCATE: 649 ret = DEFAULT_POLLMASK|EPOLLHUP|EPOLLERR; 650 break; 651 case 0: 652 ret = DEFAULT_POLLMASK; 653 break; 654 } 655 } 656 return ret; 657 } 658 659 static int 660 vcs_fasync(int fd, struct file *file, int on) 661 { 662 struct vcs_poll_data *poll = file->private_data; 663 664 if (!poll) { 665 /* don't allocate anything if all we want is disable fasync */ 666 if (!on) 667 return 0; 668 poll = vcs_poll_data_get(file); 669 if (!poll) 670 return -ENOMEM; 671 } 672 673 return fasync_helper(fd, file, on, &poll->fasync); 674 } 675 676 static int 677 vcs_open(struct inode *inode, struct file *filp) 678 { 679 unsigned int currcons = console(inode); 680 bool attr = use_attributes(inode); 681 bool uni_mode = use_unicode(inode); 682 int ret = 0; 683 684 /* we currently don't support attributes in unicode mode */ 685 if (attr && uni_mode) 686 return -EOPNOTSUPP; 687 688 console_lock(); 689 if(currcons && !vc_cons_allocated(currcons-1)) 690 ret = -ENXIO; 691 console_unlock(); 692 return ret; 693 } 694 695 static int vcs_release(struct inode *inode, struct file *file) 696 { 697 struct vcs_poll_data *poll = file->private_data; 698 699 if (poll) 700 vcs_poll_data_free(poll); 701 return 0; 702 } 703 704 static const struct file_operations vcs_fops = { 705 .llseek = vcs_lseek, 706 .read = vcs_read, 707 .write = vcs_write, 708 .poll = vcs_poll, 709 .fasync = vcs_fasync, 710 .open = vcs_open, 711 .release = vcs_release, 712 }; 713 714 static struct class *vc_class; 715 716 void vcs_make_sysfs(int index) 717 { 718 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL, 719 "vcs%u", index + 1); 720 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 65), NULL, 721 "vcsu%u", index + 1); 722 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL, 723 "vcsa%u", index + 1); 724 } 725 726 void vcs_remove_sysfs(int index) 727 { 728 device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1)); 729 device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 65)); 730 device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129)); 731 } 732 733 int __init vcs_init(void) 734 { 735 unsigned int i; 736 737 if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) 738 panic("unable to get major %d for vcs device", VCS_MAJOR); 739 vc_class = class_create(THIS_MODULE, "vc"); 740 741 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); 742 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 64), NULL, "vcsu"); 743 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); 744 for (i = 0; i < MIN_NR_CONSOLES; i++) 745 vcs_make_sysfs(i); 746 return 0; 747 } 748