Messages in this thread Patch in this message | | | Date | Thu, 17 Feb 2000 14:01:09 +0100 | From | Petr Vandrovec <> | Subject | [PATCH] vc_screen once more |
| |
Hi Linus, during reading through code I found that when code was converted from old put_user to new in-kernel buffer, it started to try to store unaligned shorts and it is fatal on some architectures, AFAIK. So there is patch. For vcs_write, I added simple get_unaligned, as I did not found any reasonable way to fix it except splitting loop for attributed and non-attributed (vcsa & vcs) paths completely. For vcs_read, I rewrite inside loop so that now always character + attribute is copied into buffer - code is shorter, gets rid of ifdef __BIG_ENDIAN and I believe that it is more readable. I also changed logic for computing buffer sizes for HEADER_SIZE data, original code had some problems with writting beyond buffer when pos was in range 1..HEADER_SIZE-1. Patch was created on 2.3.46. Thanks, Petr Vandrovec vandrove@vc.cvut.cz
diff -urdN linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- linux/drivers/char/vc_screen.c Wed Feb 16 23:42:05 2000 +++ linux/drivers/char/vc_screen.c Thu Feb 17 12:44:41 2000 @@ -37,6 +37,7 @@ #include <linux/console.h> #include <asm/uaccess.h> #include <asm/byteorder.h> +#include <asm/unaligned.h> #undef attr #undef org @@ -175,71 +176,58 @@ con_buf0[1] = (char) video_num_columns; getconsxy(currcons, con_buf0 + 2); - tmp_count = HEADER_SIZE - p; + con_buf_start += p; + this_round += p; + if (this_round > CON_BUF_SIZE) { + this_round = CON_BUF_SIZE; + orig_count = this_round - p; + } + + tmp_count = HEADER_SIZE; if (tmp_count > this_round) tmp_count = this_round; /* Advance state pointers and move on. */ this_round -= tmp_count; - con_buf_start += p; - orig_count -= p; - p += tmp_count; - con_buf0 = con_buf + p; + p = HEADER_SIZE; + con_buf0 = con_buf + HEADER_SIZE; + /* If this_round >= 0, then p is even... */ + } else if (p & 1) { + /* Skip first byte for output if start address is odd + * Update region sizes up/down depending on free + * space in buffer. + */ + con_buf_start++; + if (this_round < CON_BUF_SIZE) + this_round++; + else + orig_count--; } - p -= HEADER_SIZE; - col = (p/2) % maxcol; if (this_round > 0) { - char tmp_byte; - - org = screen_pos(currcons, p/2, viewed); - if ((p & 1) && this_round > 0) { -#ifdef __BIG_ENDIAN - tmp_byte = vcs_scr_readw(currcons, org++) & 0xff; -#else - tmp_byte = vcs_scr_readw(currcons, org++) >> 8; -#endif - - *con_buf0++ = tmp_byte; + unsigned short *tmp_buf = (unsigned short *)con_buf0; - this_round--; - p++; - if (++col == maxcol) { - org = screen_pos(currcons, p/2, viewed); - col = 0; - } - } + p -= HEADER_SIZE; p /= 2; + col = p % maxcol; + + org = screen_pos(currcons, p, viewed); p += maxcol - col; - } - if (this_round > 1) { - size_t tmp_count = this_round; - unsigned short *tmp_buf = (unsigned short *)con_buf0; + /* Buffer has even length, so we can always copy + * character + attribute. We do not copy last byte + * to userspace if this_round is odd. + */ + this_round = (this_round + 1) >> 1; - while (tmp_count > 1) { + while (this_round) { *tmp_buf++ = vcs_scr_readw(currcons, org++); - tmp_count -= 2; + this_round --; if (++col == maxcol) { org = screen_pos(currcons, p, viewed); col = 0; p += maxcol; } } - - /* Advance pointers, and move on. */ - this_round = tmp_count; - con_buf0 = (char*)tmp_buf; - } - if (this_round > 0) { - char tmp_byte; - -#ifdef __BIG_ENDIAN - tmp_byte = vcs_scr_readw(currcons, org) >> 8; -#else - tmp_byte = vcs_scr_readw(currcons, org) & 0xff; -#endif - - *con_buf0++ = tmp_byte; } } @@ -415,7 +403,7 @@ while (this_round > 1) { unsigned short w; - w = *((const unsigned short *)con_buf0); + w = get_unaligned(((const unsigned short *)con_buf0)); vcs_scr_writew(currcons, w, org++); con_buf0 += 2; this_round -= 2; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |