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