1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Provide access to virtual console memory. 4 * /dev/vcs0: 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 con_buf = (char *) __get_free_page(GFP_KERNEL); 460 if (!con_buf) 461 return -ENOMEM; 462 463 pos = *ppos; 464 465 /* Select the proper current console and verify 466 * sanity of the situation under the console lock. 467 */ 468 console_lock(); 469 470 attr = use_attributes(inode); 471 ret = -ENXIO; 472 vc = vcs_vc(inode, &viewed); 473 if (!vc) 474 goto unlock_out; 475 476 size = vcs_size(inode); 477 ret = -EINVAL; 478 if (pos < 0 || pos > size) 479 goto unlock_out; 480 if (count > size - pos) 481 count = size - pos; 482 written = 0; 483 while (count) { 484 long this_round = count; 485 size_t orig_count; 486 long p; 487 488 if (this_round > CON_BUF_SIZE) 489 this_round = CON_BUF_SIZE; 490 491 /* Temporarily drop the console lock so that we can read 492 * in the write data from userspace safely. 493 */ 494 console_unlock(); 495 ret = copy_from_user(con_buf, buf, this_round); 496 console_lock(); 497 498 if (ret) { 499 this_round -= ret; 500 if (!this_round) { 501 /* Abort loop if no data were copied. Otherwise 502 * fail with -EFAULT. 503 */ 504 if (written) 505 break; 506 ret = -EFAULT; 507 goto unlock_out; 508 } 509 } 510 511 /* The vcs_size might have changed while we slept to grab 512 * the user buffer, so recheck. 513 * Return data written up to now on failure. 514 */ 515 size = vcs_size(inode); 516 if (size < 0) { 517 if (written) 518 break; 519 ret = size; 520 goto unlock_out; 521 } 522 if (pos >= size) 523 break; 524 if (this_round > size - pos) 525 this_round = size - pos; 526 527 /* OK, now actually push the write to the console 528 * under the lock using the local kernel buffer. 529 */ 530 531 con_buf0 = con_buf; 532 orig_count = this_round; 533 maxcol = vc->vc_cols; 534 p = pos; 535 if (!attr) { 536 org0 = org = screen_pos(vc, p, viewed); 537 col = p % maxcol; 538 p += maxcol - col; 539 540 while (this_round > 0) { 541 unsigned char c = *con_buf0++; 542 543 this_round--; 544 vcs_scr_writew(vc, 545 (vcs_scr_readw(vc, org) & 0xff00) | c, org); 546 org++; 547 if (++col == maxcol) { 548 org = screen_pos(vc, p, viewed); 549 col = 0; 550 p += maxcol; 551 } 552 } 553 } else { 554 if (p < HEADER_SIZE) { 555 char header[HEADER_SIZE]; 556 557 getconsxy(vc, header + 2); 558 while (p < HEADER_SIZE && this_round > 0) { 559 this_round--; 560 header[p++] = *con_buf0++; 561 } 562 if (!viewed) 563 putconsxy(vc, header + 2); 564 } 565 p -= HEADER_SIZE; 566 col = (p/2) % maxcol; 567 if (this_round > 0) { 568 org0 = org = screen_pos(vc, p/2, viewed); 569 if ((p & 1) && this_round > 0) { 570 char c; 571 572 this_round--; 573 c = *con_buf0++; 574 #ifdef __BIG_ENDIAN 575 vcs_scr_writew(vc, c | 576 (vcs_scr_readw(vc, org) & 0xff00), org); 577 #else 578 vcs_scr_writew(vc, (c << 8) | 579 (vcs_scr_readw(vc, org) & 0xff), org); 580 #endif 581 org++; 582 p++; 583 if (++col == maxcol) { 584 org = screen_pos(vc, p/2, viewed); 585 col = 0; 586 } 587 } 588 p /= 2; 589 p += maxcol - col; 590 } 591 while (this_round > 1) { 592 unsigned short w; 593 594 w = get_unaligned(((unsigned short *)con_buf0)); 595 vcs_scr_writew(vc, w, org++); 596 con_buf0 += 2; 597 this_round -= 2; 598 if (++col == maxcol) { 599 org = screen_pos(vc, p, viewed); 600 col = 0; 601 p += maxcol; 602 } 603 } 604 if (this_round > 0) { 605 unsigned char c; 606 607 c = *con_buf0++; 608 #ifdef __BIG_ENDIAN 609 vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org); 610 #else 611 vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org); 612 #endif 613 } 614 } 615 count -= orig_count; 616 written += orig_count; 617 buf += orig_count; 618 pos += orig_count; 619 if (org0) 620 update_region(vc, (unsigned long)(org0), org - org0); 621 } 622 *ppos += written; 623 ret = written; 624 if (written) 625 vcs_scr_updated(vc); 626 627 unlock_out: 628 console_unlock(); 629 free_page((unsigned long) con_buf); 630 return ret; 631 } 632 633 static __poll_t 634 vcs_poll(struct file *file, poll_table *wait) 635 { 636 struct vcs_poll_data *poll = vcs_poll_data_get(file); 637 __poll_t ret = DEFAULT_POLLMASK|EPOLLERR; 638 639 if (poll) { 640 poll_wait(file, &poll->waitq, wait); 641 switch (poll->event) { 642 case VT_UPDATE: 643 ret = DEFAULT_POLLMASK|EPOLLPRI; 644 break; 645 case VT_DEALLOCATE: 646 ret = DEFAULT_POLLMASK|EPOLLHUP|EPOLLERR; 647 break; 648 case 0: 649 ret = DEFAULT_POLLMASK; 650 break; 651 } 652 } 653 return ret; 654 } 655 656 static int 657 vcs_fasync(int fd, struct file *file, int on) 658 { 659 struct vcs_poll_data *poll = file->private_data; 660 661 if (!poll) { 662 /* don't allocate anything if all we want is disable fasync */ 663 if (!on) 664 return 0; 665 poll = vcs_poll_data_get(file); 666 if (!poll) 667 return -ENOMEM; 668 } 669 670 return fasync_helper(fd, file, on, &poll->fasync); 671 } 672 673 static int 674 vcs_open(struct inode *inode, struct file *filp) 675 { 676 unsigned int currcons = console(inode); 677 bool attr = use_attributes(inode); 678 bool uni_mode = use_unicode(inode); 679 int ret = 0; 680 681 /* we currently don't support attributes in unicode mode */ 682 if (attr && uni_mode) 683 return -EOPNOTSUPP; 684 685 console_lock(); 686 if(currcons && !vc_cons_allocated(currcons-1)) 687 ret = -ENXIO; 688 console_unlock(); 689 return ret; 690 } 691 692 static int vcs_release(struct inode *inode, struct file *file) 693 { 694 struct vcs_poll_data *poll = file->private_data; 695 696 if (poll) 697 vcs_poll_data_free(poll); 698 return 0; 699 } 700 701 static const struct file_operations vcs_fops = { 702 .llseek = vcs_lseek, 703 .read = vcs_read, 704 .write = vcs_write, 705 .poll = vcs_poll, 706 .fasync = vcs_fasync, 707 .open = vcs_open, 708 .release = vcs_release, 709 }; 710 711 static struct class *vc_class; 712 713 void vcs_make_sysfs(int index) 714 { 715 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL, 716 "vcs%u", index + 1); 717 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 65), NULL, 718 "vcsu%u", index + 1); 719 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL, 720 "vcsa%u", index + 1); 721 } 722 723 void vcs_remove_sysfs(int index) 724 { 725 device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1)); 726 device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 65)); 727 device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129)); 728 } 729 730 int __init vcs_init(void) 731 { 732 unsigned int i; 733 734 if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) 735 panic("unable to get major %d for vcs device", VCS_MAJOR); 736 vc_class = class_create(THIS_MODULE, "vc"); 737 738 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); 739 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 64), NULL, "vcsu"); 740 device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); 741 for (i = 0; i < MIN_NR_CONSOLES; i++) 742 vcs_make_sysfs(i); 743 return 0; 744 } 745