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