diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 9c44252e52a3..2384ea85ffaf 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -311,7 +311,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) do { if (nr > this_round/4) nr = this_round/4; - vc_uniscr_copy_line(vc, con_buf0, row, col, nr); + vc_uniscr_copy_line(vc, con_buf0, viewed, + row, col, nr); con_buf0 += nr * 4; this_round -= nr * 4; row++; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 062ce6be7957..2d14bb195d98 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -533,13 +533,40 @@ int vc_uniscr_check(struct vc_data *vc) * This must be preceded by a successful call to vc_uniscr_check() once * the console lock has been taken. */ -void vc_uniscr_copy_line(struct vc_data *vc, void *dest, +void vc_uniscr_copy_line(struct vc_data *vc, void *dest, int viewed, unsigned int row, unsigned int col, unsigned int nr) { struct uni_screen *uniscr = get_vc_uniscr(vc); + int offset = row * vc->vc_size_row + col * 2; + unsigned long pos; BUG_ON(!uniscr); - memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t)); + + pos = (unsigned long)screenpos(vc, offset, viewed); + if (pos >= vc->vc_origin && pos < vc->vc_scr_end) { + /* + * Desired position falls in the main screen buffer. + * However the actual row/col might be different if + * scrollback is active. + */ + row = (pos - vc->vc_origin) / vc->vc_size_row; + col = ((pos - vc->vc_origin) % vc->vc_size_row) / 2; + memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t)); + } else { + /* + * Scrollback is active. For now let's simply backtranslate + * the screen glyphs until the unicode screen buffer does + * synchronize with console display drivers for a scrollback + * buffer of its own. + */ + u16 *p = (u16 *)pos; + int mask = vc->vc_hi_font_mask | 0xff; + char32_t *uni_buf = dest; + while (nr--) { + u16 glyph = scr_readw(p++) & mask; + *uni_buf++ = inverse_translate(vc, glyph, true); + } + } } diff --git a/include/linux/selection.h b/include/linux/selection.h index 2b34df9f1e26..067d2e99c79f 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -43,7 +43,7 @@ extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org); extern void vcs_scr_updated(struct vc_data *vc); extern int vc_uniscr_check(struct vc_data *vc); -extern void vc_uniscr_copy_line(struct vc_data *vc, void *dest, +extern void vc_uniscr_copy_line(struct vc_data *vc, void *dest, int viewed, unsigned int row, unsigned int col, unsigned int nr);