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