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