From patchwork Wed Jun 27 03:56:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 140086 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp358409ljj; Tue, 26 Jun 2018 20:56:56 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKJ4oxrgVxusgAENalehJj5eXkal9g7oiJW1V3kaYvY5mVFWeuDV6JM8uVa2RhO2m3dTo7h X-Received: by 2002:a63:6243:: with SMTP id w64-v6mr3662712pgb.179.1530071815945; Tue, 26 Jun 2018 20:56:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530071815; cv=none; d=google.com; s=arc-20160816; b=QS3ut2/xCKdwyDuZHyKcri90Turtq2s6ZxZPYv2/sPaM8Z3m34bqF5iKjmlCGypZJ0 WKeXwLbXSc+90Pfg2mqEn186nPchesEXXxwp2v1rADT8GS/ZYculI4DOKWW8Bc+7XxJD jb35CCSx8H92fibkvrRIOhrpGjUjTLRjxmamhB/TPpQrvgdVXX+l9gIxZA9KuYAlQdhS jdEnrOZ3fe/jbdd/xVBtQzps/4tZDgo9yhVSt1RnfFbRjnkS9L5vwVo4WhQVkt3iwznz V1ytmCAw5AtP50br9Tgdl2iM5iH7Owk3Exl+Wv7sR4Uxf4LMxnhaHQ6ZxPMYGNrH9Bl6 CNwQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=15+sSAF9AcJ4lMhIaAxZSGY+9x7jvmd3pgJOaQeKZ8E=; b=VLMZgrRhdFA8gBd/SMQ2ZQ8DfG7RqiIdTfx5+RjthvVMQPjHNrohM8TY5JjegdH0lJ YlafDj7QjMb3MeypY1JpbaY6mcSd1GpSKDzzCIavwxyvSzGovxhwA1feLDalzRa0LPTF mAGeNoy6E0bJBNpBwKPGBO0I2sBWWYTh6NH26JJryicp106EOA7aNwshoVQrQh5rvPv+ 0jdVFGc/FI31C/Ol8RuW6W1+6tIZuWJEyETu191rwwSsTu7TJfM4PqqF4g0DBzNDjiQt EAO4w1MQFLLqXrf6I3TO8ZAnTirRM8sslgiAvM8PMlr9lW+DUUy94GOpSPCF9i4xkjL1 sOZw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=CmB3K8m8; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r7-v6si2745714pgn.326.2018.06.26.20.56.55; Tue, 26 Jun 2018 20:56:55 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=CmB3K8m8; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754173AbeF0D4x (ORCPT + 31 others); Tue, 26 Jun 2018 23:56:53 -0400 Received: from pb-smtp1.pobox.com ([64.147.108.70]:64970 "EHLO pb-smtp1.pobox.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751095AbeF0D4s (ORCPT ); Tue, 26 Jun 2018 23:56:48 -0400 Received: from pb-smtp1.pobox.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id DD5FD10A8A; Tue, 26 Jun 2018 23:56:45 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=pobox.com; h=from:to:cc :subject:date:message-id:in-reply-to:references; s=sasl; bh=/k49 lQdQFqsLzHrd9f8VFXr0ack=; b=CmB3K8m8/A7qNnD1zbwgOKojfcgBWwz3UwhR BoZL/+ke2shswBasZFP/PnCgA1NUWjJM/htyzT25OHQOVjjkjVy98oDW/04/SL/f rywHJYfEzvGktnp3BJu07/rOWG8B1ac3ENiN47ZCPlIvFw2dgHYHUrr4aTnAVz2h 47jUkoU= Received: from pb-smtp1.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id D501F10A89; Tue, 26 Jun 2018 23:56:45 -0400 (EDT) Received: from yoda.home (unknown [70.82.104.228]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pb-smtp1.pobox.com (Postfix) with ESMTPSA id 646A910A88; Tue, 26 Jun 2018 23:56:45 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 8AFA02DA062E; Tue, 26 Jun 2018 23:56:44 -0400 (EDT) From: Nicolas Pitre To: Greg Kroah-Hartman Cc: Dave Mielke , Samuel Thibault , Adam Borowski , Alan Cox , linux-kernel@vger.kernel.org, linux-console@vger.kernel.org Subject: [PATCH v3 1/3] vt: preserve unicode values corresponding to screen characters Date: Tue, 26 Jun 2018 23:56:40 -0400 Message-Id: <20180627035642.8561-2-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180627035642.8561-1-nicolas.pitre@linaro.org> References: <20180627035642.8561-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 1BF059BE-79BE-11E8-AB4D-0DFB1A68708C-78420484!pb-smtp1.pobox.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The vt code translates UTF-8 strings into glyph index values and stores those glyph values directly in the screen buffer. Because there can only be at most 512 glyphs, it is impossible to represent most unicode characters, in which case a default glyph (often '?') is displayed instead. The original unicode value is then lost. This patch implements the basic screen buffer handling to preserve unicode values alongside corresponding display glyphs. It is not activated by default, meaning that people not relying on that functionality won't get the implied overhead. Signed-off-by: Nicolas Pitre Tested-by: Dave Mielke Acked-by: Adam Borowski --- drivers/tty/vt/vt.c | 220 +++++++++++++++++++++++++++++++-- include/linux/console_struct.h | 2 + 2 files changed, 211 insertions(+), 11 deletions(-) -- 2.17.1 diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 1eb1a376a0..7b636638b3 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -317,6 +317,171 @@ void schedule_console_callback(void) schedule_work(&console_work); } +/* + * Code to manage unicode-based screen buffers + */ + +#ifdef NO_VC_UNI_SCREEN +/* this disables and optimizes related code away at compile time */ +#define get_vc_uniscr(vc) NULL +#else +#define get_vc_uniscr(vc) vc->vc_uni_screen +#endif + +typedef uint32_t char32_t; + +/* + * Our screen buffer is preceded by an array of line pointers so that + * scrolling only implies some pointer shuffling. + */ +struct uni_screen { + char32_t *lines[0]; +}; + +static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows) +{ + struct uni_screen *uniscr; + void *p; + unsigned int memsize, i; + + /* allocate everything in one go */ + memsize = cols * rows * sizeof(char32_t); + memsize += rows * sizeof(char32_t *); + p = kmalloc(memsize, GFP_KERNEL); + if (!p) + return NULL; + + /* initial line pointers */ + uniscr = p; + p = uniscr->lines + rows; + for (i = 0; i < rows; i++) { + uniscr->lines[i] = p; + p += cols * sizeof(char32_t); + } + return uniscr; +} + +static void vc_uniscr_set(struct vc_data *vc, struct uni_screen *new_uniscr) +{ + kfree(vc->vc_uni_screen); + vc->vc_uni_screen = new_uniscr; +} + +static void vc_uniscr_putc(struct vc_data *vc, char32_t uc) +{ + struct uni_screen *uniscr = get_vc_uniscr(vc); + + if (uniscr) + uniscr->lines[vc->vc_y][vc->vc_x] = uc; +} + +static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr) +{ + struct uni_screen *uniscr = get_vc_uniscr(vc); + + if (uniscr) { + char32_t *ln = uniscr->lines[vc->vc_y]; + unsigned int x = vc->vc_x, cols = vc->vc_cols; + + memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln)); + memset32(&ln[x], ' ', nr); + } +} + +static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr) +{ + struct uni_screen *uniscr = get_vc_uniscr(vc); + + if (uniscr) { + char32_t *ln = uniscr->lines[vc->vc_y]; + unsigned int x = vc->vc_x, cols = vc->vc_cols; + + memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln)); + memset32(&ln[cols - nr], ' ', nr); + } +} + +static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x, + unsigned int nr) +{ + struct uni_screen *uniscr = get_vc_uniscr(vc); + + if (uniscr) { + char32_t *ln = uniscr->lines[vc->vc_y]; + + memset32(&ln[x], ' ', nr); + } +} + +static void vc_uniscr_clear_lines(struct vc_data *vc, unsigned int y, + unsigned int nr) +{ + struct uni_screen *uniscr = get_vc_uniscr(vc); + + if (uniscr) { + unsigned int cols = vc->vc_cols; + + while (nr--) + memset32(uniscr->lines[y++], ' ', cols); + } +} + +static void vc_uniscr_scroll(struct vc_data *vc, unsigned int t, unsigned int b, + enum con_scroll dir, unsigned int nr) +{ + struct uni_screen *uniscr = get_vc_uniscr(vc); + + if (uniscr) { + unsigned int s, d, rescue, clear; + char32_t *save[nr]; + + s = clear = t; + d = t + nr; + rescue = b - nr; + if (dir == SM_UP) { + swap(s, d); + swap(clear, rescue); + } + memcpy(save, uniscr->lines + rescue, nr * sizeof(*save)); + memmove(uniscr->lines + d, uniscr->lines + s, + (b - t - nr) * sizeof(*uniscr->lines)); + memcpy(uniscr->lines + clear, save, nr * sizeof(*save)); + vc_uniscr_clear_lines(vc, clear, nr); + } +} + +static void vc_uniscr_copy_area(struct uni_screen *dst, + unsigned int dst_cols, + unsigned int dst_rows, + struct uni_screen *src, + unsigned int src_cols, + unsigned int src_top_row, + unsigned int src_bot_row) +{ + unsigned int dst_row = 0; + + if (!dst) + return; + + while (src_top_row < src_bot_row) { + char32_t *src_line = src->lines[src_top_row]; + char32_t *dst_line = dst->lines[dst_row]; + + memcpy(dst_line, src_line, src_cols * sizeof(char32_t)); + if (dst_cols - src_cols) + memset32(dst_line + src_cols, ' ', dst_cols - src_cols); + src_top_row++; + dst_row++; + } + while (dst_row < dst_rows) { + char32_t *dst_line = dst->lines[dst_row]; + + memset32(dst_line, ' ', dst_cols); + dst_row++; + } +} + + static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b, enum con_scroll dir, unsigned int nr) { @@ -326,6 +491,7 @@ static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b, nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; + vc_uniscr_scroll(vc, t, b, dir, nr); if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr)) return; @@ -533,6 +699,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr) { unsigned short *p = (unsigned short *) vc->vc_pos; + vc_uniscr_insert(vc, nr); scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2); scr_memsetw(p, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; @@ -545,6 +712,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr) { unsigned short *p = (unsigned short *) vc->vc_pos; + vc_uniscr_delete(vc, nr); scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2); scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, nr * 2); @@ -845,10 +1013,11 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, { unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; unsigned long end; - unsigned int old_rows, old_row_size; + unsigned int old_rows, old_row_size, first_copied_row; unsigned int new_cols, new_rows, new_row_size, new_screen_size; unsigned int user; unsigned short *newscreen; + struct uni_screen *new_uniscr = NULL; WARN_CONSOLE_UNLOCKED(); @@ -875,6 +1044,14 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (!newscreen) return -ENOMEM; + if (get_vc_uniscr(vc)) { + new_uniscr = vc_uniscr_alloc(new_cols, new_rows); + if (!new_uniscr) { + kfree(newscreen); + return -ENOMEM; + } + } + if (vc == sel_cons) clear_selection(); @@ -884,6 +1061,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, err = resize_screen(vc, new_cols, new_rows, user); if (err) { kfree(newscreen); + kfree(new_uniscr); return err; } @@ -904,18 +1082,24 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, * Cursor near the bottom, copy contents from the * bottom of buffer */ - old_origin += (old_rows - new_rows) * old_row_size; + first_copied_row = (old_rows - new_rows); } else { /* * Cursor is in no man's land, copy 1/2 screenful * from the top and bottom of cursor position */ - old_origin += (vc->vc_y - new_rows/2) * old_row_size; + first_copied_row = (vc->vc_y - new_rows/2); } - } - + old_origin += first_copied_row * old_row_size; + } else + first_copied_row = 0; end = old_origin + old_row_size * min(old_rows, new_rows); + vc_uniscr_copy_area(new_uniscr, new_cols, new_rows, + get_vc_uniscr(vc), rlth/2, first_copied_row, + min(old_rows, new_rows)); + vc_uniscr_set(vc, new_uniscr); + update_attr(vc); while (old_origin < end) { @@ -1013,6 +1197,7 @@ struct vc_data *vc_deallocate(unsigned int currcons) vc->vc_sw->con_deinit(vc); put_pid(vc->vt_pid); module_put(vc->vc_sw->owner); + vc_uniscr_set(vc, NULL); kfree(vc->vc_screenbuf); vc_cons[currcons].d = NULL; } @@ -1171,15 +1356,22 @@ static void csi_J(struct vc_data *vc, int vpar) switch (vpar) { case 0: /* erase from cursor to end of display */ + vc_uniscr_clear_line(vc, vc->vc_x, + vc->vc_cols - vc->vc_x); + vc_uniscr_clear_lines(vc, vc->vc_y + 1, + vc->vc_rows - vc->vc_y - 1); count = (vc->vc_scr_end - vc->vc_pos) >> 1; start = (unsigned short *)vc->vc_pos; break; case 1: /* erase from start to cursor */ + vc_uniscr_clear_line(vc, 0, vc->vc_x + 1); + vc_uniscr_clear_lines(vc, 0, vc->vc_y); count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; start = (unsigned short *)vc->vc_origin; break; case 2: /* erase whole display */ case 3: /* (and scrollback buffer later) */ + vc_uniscr_clear_lines(vc, 0, vc->vc_rows); count = vc->vc_cols * vc->vc_rows; start = (unsigned short *)vc->vc_origin; break; @@ -1200,25 +1392,27 @@ static void csi_J(struct vc_data *vc, int vpar) static void csi_K(struct vc_data *vc, int vpar) { unsigned int count; - unsigned short * start; + unsigned short *start = (unsigned short *)vc->vc_pos; + int offset; switch (vpar) { case 0: /* erase from cursor to end of line */ + offset = 0; count = vc->vc_cols - vc->vc_x; - start = (unsigned short *)vc->vc_pos; break; case 1: /* erase from start of line to cursor */ - start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); + offset = -vc->vc_x; count = vc->vc_x + 1; break; case 2: /* erase whole line */ - start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); + offset = -vc->vc_x; count = vc->vc_cols; break; default: return; } - scr_memsetw(start, vc->vc_video_erase_char, 2 * count); + vc_uniscr_clear_line(vc, vc->vc_x + offset, count); + scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count); vc->vc_need_wrap = 0; if (con_should_update(vc)) do_update_region(vc, (unsigned long) start, count); @@ -1232,6 +1426,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi vpar++; count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar; + vc_uniscr_clear_line(vc, vc->vc_x, count); scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); if (con_should_update(vc)) vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count); @@ -2188,7 +2383,7 @@ static void con_flush(struct vc_data *vc, unsigned long draw_from, /* acquires console_lock */ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) { - int c, tc, ok, n = 0, draw_x = -1; + int c, next_c, tc, ok, n = 0, draw_x = -1; unsigned int currcons; unsigned long draw_from = 0, draw_to = 0; struct vc_data *vc; @@ -2382,6 +2577,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co con_flush(vc, draw_from, draw_to, &draw_x); } + next_c = c; while (1) { if (vc->vc_need_wrap || vc->vc_decim) con_flush(vc, draw_from, draw_to, @@ -2392,6 +2588,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co } if (vc->vc_decim) insert_char(vc, 1); + vc_uniscr_putc(vc, next_c); scr_writew(himask ? ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : (vc_attr << 8) + tc, @@ -2412,6 +2609,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ if (tc < 0) tc = ' '; + next_c = ' '; } notify_write(vc, c); diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index c0ec478ea5..2c8d323989 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -19,6 +19,7 @@ struct vt_struct; struct uni_pagedir; +struct uni_screen; #define NPAR 16 @@ -140,6 +141,7 @@ struct vc_data { struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ struct uni_pagedir *vc_uni_pagedir; struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ + struct uni_screen *vc_uni_screen; /* unicode screen content */ bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */ /* additional information is in vt_kern.h */ }; From patchwork Wed Jun 27 03:56:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 140087 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp358465ljj; Tue, 26 Jun 2018 20:57:01 -0700 (PDT) X-Google-Smtp-Source: AAOMgpcJSbFPEHhlTD2jvykPtaXfggy+xgRrd5OZmK5SoerJ+5/aieiy0eshirYsV2nyAPZlJaRx X-Received: by 2002:a62:2541:: with SMTP id l62-v6mr4217534pfl.0.1530071821232; Tue, 26 Jun 2018 20:57:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530071821; cv=none; d=google.com; s=arc-20160816; b=AHvgkwfUrFJQ6sL1VFxPFt3zxHlSEujAFL0nnkPAtA8RNO7a1f28TJ+lKxU3rZJoAi vMJ9uB98rBE4FDsAqdP7dlcqBOUktq7jVf44FkOixnn7ZMALxL/mQiS9tWMsf3ZDzUGq NnafdY57iRdGoGOSYaTlpmIc7mBvMunF+sUfgK/qOfFLvafjk4wZjJTENOAMzpU6guzD F83mDKi6EsqnsZN6CDsy+BsIUGQ+5z4HpN4lidQtoH1G0H5aa+1ekEpMoELEa78rCD6S ohut/OJJFqZsCZAzeTJkboTM9Lc8SZWXfubkzVwNOKUZQC7nygMIhJkC4iP2etJBO7W9 2mNg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=dmXEr8YbgURJE9xgBBwmMcPYYKZupihvgmsvwAECn4c=; b=xEgUrD9g5yS0K+tZjsej3OotfDIcyxkwJRp9q5KCIfxg76IvESUn/tNQ/zjYGqv0vj +Br/0/P00lhlbL8ecN3SPW4UK186UXAs5chFGtcUgPvFKw0yotwjKLa9RQolvNe+DMJO IU21x3dE6bCK/T/jhqevmAFpQbqIRdzeCIHFvxzxRNgcKFTFepsPsm1wvDP+fHkzTNZS xy5yvpTc0FJIygxI2jQxRTl3nsVpDfWZ+zzpWy8iFOlJK4HISFxEP2tTxhJjvpliPgIZ YcbX1Wi+j5bF7HU/bskYlVPMgEbbP0fiOOSIkTa1RYEmAc4+TrbXTp46/GPYKDq8pdHL VPeg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=vx35hmET; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d22-v6si848331pfd.182.2018.06.26.20.57.00; Tue, 26 Jun 2018 20:57:01 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=vx35hmET; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754283AbeF0D4z (ORCPT + 31 others); Tue, 26 Jun 2018 23:56:55 -0400 Received: from pb-smtp2.pobox.com ([64.147.108.71]:50903 "EHLO pb-smtp2.pobox.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752199AbeF0D4s (ORCPT ); Tue, 26 Jun 2018 23:56:48 -0400 Received: from pb-smtp2.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 69510E7784; Tue, 26 Jun 2018 23:56:46 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=pobox.com; h=from:to:cc :subject:date:message-id:in-reply-to:references:mime-version :content-type:content-transfer-encoding; s=sasl; bh=MbdmwzLSGhO4 pGAgU4+wr+9nOLI=; b=vx35hmETD/S8NP+5kRSYM/OZY9tkoHeGAR9Ilz8hI8nB 7iwIDKC0wmvtz7200FuVAcSBZGsP3oOnxbdyJyi+5SsvXjuRRInnVqfZ1787w5Bm IINc30T0DQK0/INbAZPs98tpBdPYQIzbEwqcnNQ/PauhJElWvpVRf6mvgz0mttg= Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 54072E7781; Tue, 26 Jun 2018 23:56:46 -0400 (EDT) Received: from yoda.home (unknown [70.82.104.228]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pb-smtp2.pobox.com (Postfix) with ESMTPSA id 98FCEE777C; Tue, 26 Jun 2018 23:56:45 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id BDD062DA0661; Tue, 26 Jun 2018 23:56:44 -0400 (EDT) From: Nicolas Pitre To: Greg Kroah-Hartman Cc: Dave Mielke , Samuel Thibault , Adam Borowski , Alan Cox , linux-kernel@vger.kernel.org, linux-console@vger.kernel.org Subject: [PATCH v3 2/3] vt: introduce unicode mode for /dev/vcs Date: Tue, 26 Jun 2018 23:56:41 -0400 Message-Id: <20180627035642.8561-3-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180627035642.8561-1-nicolas.pitre@linaro.org> References: <20180627035642.8561-1-nicolas.pitre@linaro.org> MIME-Version: 1.0 X-Pobox-Relay-ID: 1C10BDA8-79BE-11E8-9009-40570C78B957-78420484!pb-smtp2.pobox.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Now that the core vt code knows how to preserve unicode values for each displayed character, it is then possible to let user space access it via /dev/vcs*. Unicode characters are presented as 32 bit values in native endianity via the /dev/vcsu* devices, mimicking the simple /dev/vcs* devices. Unicode with attributes (similarly to /dev/vcsa*) is not supported at the moment. Data is available only as long as the console is in UTF-8 mode. ENODATA is returned otherwise. This was tested with the latest development version (to become version 5.7) of BRLTTY. Amongst other things, this allows ⠋⠕⠗ ⠞⠓⠊⠎ ⠃⠗⠁⠊⠇⠇⠑⠀⠞⠑⠭⠞⠀to appear directly on braille displays regardless of the console font being used. Signed-off-by: Nicolas Pitre Tested-by: Dave Mielke Acked-by: Adam Borowski --- drivers/tty/vt/vc_screen.c | 89 ++++++++++++++++++++++++++++++++------ drivers/tty/vt/vt.c | 61 ++++++++++++++++++++++++++ include/linux/selection.h | 5 +++ 3 files changed, 141 insertions(+), 14 deletions(-) -- 2.17.1 diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index e4a66e1fd0..9c44252e52 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -10,6 +10,12 @@ * Attribute/character pair is in native endianity. * [minor: N+128] * + * /dev/vcsuN: similar to /dev/vcsaN but using 4-byte unicode values + * instead of 1-byte screen glyph values. + * [minor: N+64] + * + * /dev/vcsuaN: same idea as /dev/vcsaN for unicode (not yet implemented). + * * This replaces screendump and part of selection, so that the system * administrator can control access using file system permissions. * @@ -51,6 +57,26 @@ #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) +/* + * Our minor space: + * + * 0 ... 63 glyph mode without attributes + * 64 ... 127 unicode mode without attributes + * 128 ... 191 glyph mode with attributes + * 192 ... 255 unused (reserved for unicode with attributes) + * + * This relies on MAX_NR_CONSOLES being <= 63, meaning 63 actual consoles + * with minors 0, 64, 128 and 192 being proxies for the foreground console. + */ +#if MAX_NR_CONSOLES > 63 +#warning "/dev/vcs* devices may not accommodate more than 63 consoles" +#endif + +#define console(inode) (iminor(inode) & 63) +#define use_unicode(inode) (iminor(inode) & 64) +#define use_attributes(inode) (iminor(inode) & 128) + + struct vcs_poll_data { struct notifier_block notifier; unsigned int cons_num; @@ -102,7 +128,7 @@ vcs_poll_data_get(struct file *file) poll = kzalloc(sizeof(*poll), GFP_KERNEL); if (!poll) return NULL; - poll->cons_num = iminor(file_inode(file)) & 127; + poll->cons_num = console(file_inode(file)); init_waitqueue_head(&poll->waitq); poll->notifier.notifier_call = vcs_notifier; if (register_vt_notifier(&poll->notifier) != 0) { @@ -140,7 +166,7 @@ vcs_poll_data_get(struct file *file) static struct vc_data* vcs_vc(struct inode *inode, int *viewed) { - unsigned int currcons = iminor(inode) & 127; + unsigned int currcons = console(inode); WARN_CONSOLE_UNLOCKED(); @@ -164,7 +190,6 @@ static int vcs_size(struct inode *inode) { int size; - int minor = iminor(inode); struct vc_data *vc; WARN_CONSOLE_UNLOCKED(); @@ -175,8 +200,12 @@ vcs_size(struct inode *inode) size = vc->vc_rows * vc->vc_cols; - if (minor & 128) + if (use_attributes(inode)) { + if (use_unicode(inode)) + return -EOPNOTSUPP; size = 2*size + HEADER_SIZE; + } else if (use_unicode(inode)) + size *= 4; return size; } @@ -197,12 +226,10 @@ static ssize_t vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file_inode(file); - unsigned int currcons = iminor(inode); struct vc_data *vc; struct vcs_poll_data *poll; - long pos; - long attr, read; - int col, maxcol, viewed; + long pos, read; + int attr, uni_mode, row, col, maxcol, viewed; unsigned short *org = NULL; ssize_t ret; char *con_buf; @@ -218,7 +245,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) */ console_lock(); - attr = (currcons & 128); + uni_mode = use_unicode(inode); + attr = use_attributes(inode); ret = -ENXIO; vc = vcs_vc(inode, &viewed); if (!vc) @@ -227,6 +255,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ret = -EINVAL; if (pos < 0) goto unlock_out; + /* we enforce 32-bit alignment for pos and count in unicode mode */ + if (uni_mode && (pos | count) & 3) + goto unlock_out; + poll = file->private_data; if (count && poll) poll->seen_last_update = true; @@ -266,7 +298,27 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) con_buf_start = con_buf0 = con_buf; orig_count = this_round; maxcol = vc->vc_cols; - if (!attr) { + if (uni_mode) { + unsigned int nr; + + ret = vc_uniscr_check(vc); + if (ret) + break; + p /= 4; + row = p / vc->vc_cols; + col = p % maxcol; + nr = maxcol - col; + do { + if (nr > this_round/4) + nr = this_round/4; + vc_uniscr_copy_line(vc, con_buf0, row, col, nr); + con_buf0 += nr * 4; + this_round -= nr * 4; + row++; + col = 0; + nr = maxcol; + } while (this_round); + } else if (!attr) { org = screen_pos(vc, p, viewed); col = p % maxcol; p += maxcol - col; @@ -375,7 +427,6 @@ static ssize_t vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file_inode(file); - unsigned int currcons = iminor(inode); struct vc_data *vc; long pos; long attr, size, written; @@ -396,7 +447,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) */ console_lock(); - attr = (currcons & 128); + attr = use_attributes(inode); ret = -ENXIO; vc = vcs_vc(inode, &viewed); if (!vc) @@ -593,9 +644,15 @@ vcs_fasync(int fd, struct file *file, int on) static int vcs_open(struct inode *inode, struct file *filp) { - unsigned int currcons = iminor(inode) & 127; + unsigned int currcons = console(inode); + bool attr = use_attributes(inode); + bool uni_mode = use_unicode(inode); int ret = 0; - + + /* we currently don't support attributes in unicode mode */ + if (attr && uni_mode) + return -EOPNOTSUPP; + console_lock(); if(currcons && !vc_cons_allocated(currcons-1)) ret = -ENXIO; @@ -628,6 +685,8 @@ void vcs_make_sysfs(int index) { device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL, "vcs%u", index + 1); + device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 65), NULL, + "vcsu%u", index + 1); device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL, "vcsa%u", index + 1); } @@ -635,6 +694,7 @@ void vcs_make_sysfs(int index) void vcs_remove_sysfs(int index) { device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1)); + device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 65)); device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129)); } @@ -647,6 +707,7 @@ int __init vcs_init(void) vc_class = class_create(THIS_MODULE, "vc"); device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); + device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 64), NULL, "vcsu"); device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); for (i = 0; i < MIN_NR_CONSOLES; i++) vcs_make_sysfs(i); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 7b636638b3..062ce6be79 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -481,6 +481,67 @@ static void vc_uniscr_copy_area(struct uni_screen *dst, } } +/* + * Called from vcs_read() to make sure unicode screen retrieval is possible. + * This will initialize the unicode screen buffer if not already done. + * This returns 0 if OK, or a negative error code otherwise. + * In particular, -ENODATA is returned if the console is not in UTF-8 mode. + */ +int vc_uniscr_check(struct vc_data *vc) +{ + struct uni_screen *uniscr; + unsigned short *p; + int x, y, mask; + + if (__is_defined(NO_VC_UNI_SCREEN)) + return -EOPNOTSUPP; + + WARN_CONSOLE_UNLOCKED(); + + if (!vc->vc_utf) + return -ENODATA; + + if (vc->vc_uni_screen) + return 0; + + uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows); + if (!uniscr) + return -ENOMEM; + + /* + * Let's populate it initially with (imperfect) reverse translation. + * This is the next best thing we can do short of having it enabled + * from the start even when no users rely on this functionality. True + * unicode content will be available after a complete screen refresh. + */ + p = (unsigned short *)vc->vc_origin; + mask = vc->vc_hi_font_mask | 0xff; + for (y = 0; y < vc->vc_rows; y++) { + char32_t *line = uniscr->lines[y]; + for (x = 0; x < vc->vc_cols; x++) { + u16 glyph = scr_readw(p++) & mask; + line[x] = inverse_translate(vc, glyph, true); + } + } + + vc->vc_uni_screen = uniscr; + return 0; +} + +/* + * Called from vcs_read() to get the unicode data from the screen. + * 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, + unsigned int row, unsigned int col, unsigned int nr) +{ + struct uni_screen *uniscr = get_vc_uniscr(vc); + + BUG_ON(!uniscr); + memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t)); +} + static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b, enum con_scroll dir, unsigned int nr) diff --git a/include/linux/selection.h b/include/linux/selection.h index 5b278ce99d..2b34df9f1e 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -42,4 +42,9 @@ extern u16 vcs_scr_readw(struct vc_data *vc, const u16 *org); 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, + unsigned int row, unsigned int col, + unsigned int nr); + #endif From patchwork Wed Jun 27 03:56:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 140088 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp358784ljj; Tue, 26 Jun 2018 20:57:31 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKOCHIfvOTwg1feK/u+Odl13TghInWGxeI+fa7XYDPnKbu1gj9yAIwqYcl80iT6HK2EqQR9 X-Received: by 2002:a17:902:b217:: with SMTP id t23-v6mr4381946plr.312.1530071851657; Tue, 26 Jun 2018 20:57:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530071851; cv=none; d=google.com; s=arc-20160816; b=KStd7jyZySBtPgsSi5KkAmH667LnPkoI9XIqFgNGEa0fCUtXAMU+8/SudfUrrByv/J REYpO2dXNn2z+eq0BLs+FvtipVxtWVSLFq0hY/0iuZslGKJhMy2gfRfOCl/Kd2loLD0A qN+5BU4BdLkrIql6A4RwjwrB+jDTfY1p9ekLaO/KSPX8oBsf5WNUIByLZBgqQ0YY6cH+ SIi+oF9BENBsJPmAQqAtGtzz9FeCg3Fmlse7kqNnCuC8yrflqtC0/J3rlgM7X06PYpuK mQbKJecsNfLw92g3RYL7TJS0MXjYcsVLhlojARFsdmZHtuJNJVQxSvkGp7UpUUk/DBSD SLKg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=DbeQjCKISlqtemaVyjv7Z+nnAkbZkPz0fA9A5n1dtlI=; b=wneDl1IOI4fl62FskOvyFAQuTPIa6DcYBbPAFI1akbFXrwSWlKJKFjAO0a9opVlIyf SB0ujJfV8MAjHb2az/a8TId6LqGUyMLXgp5hFbnhQDWMbODgX+96m8D/uEEfuJY8gbmG Yp84bTm7aZyvDoCmQIm/iTmmljujncp/PKgMCfjJbu7hqLMIetThNjiSWFlmxb0Xm7th KkHB1w9rOZ4dbkRaKHX/9OrFzexQtAh80nCr/oviU40Z3MZefEoHNnGMPR5lRkv7ISyX HvadLaqj6bqi2/XapTQ6d5vwB4szQjjIVdxLeD97gXioDWeLueUhz8Ka5/TtWI1t2DzJ eUMg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=PYLJBPNl; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w135-v6si3109868pff.18.2018.06.26.20.57.31; Tue, 26 Jun 2018 20:57:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=PYLJBPNl; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753238AbeF0D4u (ORCPT + 31 others); Tue, 26 Jun 2018 23:56:50 -0400 Received: from pb-smtp2.pobox.com ([64.147.108.71]:50274 "EHLO pb-smtp2.pobox.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750909AbeF0D4s (ORCPT ); Tue, 26 Jun 2018 23:56:48 -0400 Received: from pb-smtp2.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 54FC7E7782; Tue, 26 Jun 2018 23:56:46 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=pobox.com; h=from:to:cc :subject:date:message-id:in-reply-to:references; s=sasl; bh=ABWv dJzh4qOnthHLY9zePogflFs=; b=PYLJBPNlfai7KssOzRHPYcJfQBVDiZhw8ixP V4DlhF0kYRvQ3a+qOcJkSX8877QcPFaytdovukSsurXR47P2VIPx14OgthBY+0JD StPALUs/NqF5v0hOARORmN8AesL9xaGExaJgOYm6yoBpOa+dN0PWqGIx0SMq0ldS 344f6jM= Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 4CC31E7780; Tue, 26 Jun 2018 23:56:46 -0400 (EDT) Received: from yoda.home (unknown [70.82.104.228]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pb-smtp2.pobox.com (Postfix) with ESMTPSA id A194CE777D; Tue, 26 Jun 2018 23:56:45 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id EA1242DA0674; Tue, 26 Jun 2018 23:56:44 -0400 (EDT) From: Nicolas Pitre To: Greg Kroah-Hartman Cc: Dave Mielke , Samuel Thibault , Adam Borowski , Alan Cox , linux-kernel@vger.kernel.org, linux-console@vger.kernel.org Subject: [PATCH v3 3/3] vt: unicode fallback for scrollback Date: Tue, 26 Jun 2018 23:56:42 -0400 Message-Id: <20180627035642.8561-4-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180627035642.8561-1-nicolas.pitre@linaro.org> References: <20180627035642.8561-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 1C1620EA-79BE-11E8-8995-40570C78B957-78420484!pb-smtp2.pobox.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org There is currently no provision for scrollback content in the core code, leaving that to backend video drivers where this can be highly optimized. There is currently no common method for those drivers to tell the core what part of the scrollback is actually displayed and what size the scrollback buffer is either. Because of that, the unicode screen buffer has no provision for any scrollback. At least we can provide backtranslated glyph values when the scrollback is active which should be plenty good enough for now. Signed-off-by: Nicolas Pitre Tested-by: Dave Mielke Acked-by: Adam Borowski --- drivers/tty/vt/vc_screen.c | 3 ++- drivers/tty/vt/vt.c | 31 +++++++++++++++++++++++++++++-- include/linux/selection.h | 2 +- 3 files changed, 32 insertions(+), 4 deletions(-) -- 2.17.1 diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 9c44252e52..2384ea85ff 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 062ce6be79..2d14bb195d 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 2b34df9f1e..067d2e99c7 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);