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