From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751359AbdAMUJE (ORCPT ); Fri, 13 Jan 2017 15:09:04 -0500 Received: from mout.gmx.net ([212.227.15.15]:51306 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751322AbdAMUJB (ORCPT ); Fri, 13 Jan 2017 15:09:01 -0500 From: =?UTF-8?q?Manuel=20Sch=C3=B6lling?= To: gregkh@linuxfoundation.org Cc: jslaby@suse.com, kilobyte@angband.pl, lkml14@scotdoyle.com, rdunlap@infradead.org, shorne@gmail.com, andrey_utkin@fastmail.com, akpm@linux-foundation.org, paul.burton@imgtec.com, daniel.vetter@ffwll.ch, tj@kernel.org, hdegoede@redhat.com, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, =?UTF-8?q?Manuel=20Sch=C3=B6lling?= Subject: [PATCH v10 3/4] console: Add persistent scrollback buffers for all VGA consoles Date: Fri, 13 Jan 2017 21:07:57 +0100 Message-Id: <20170113200758.9880-4-manuel.schoelling@gmx.de> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170113200758.9880-1-manuel.schoelling@gmx.de> References: <20170113200758.9880-1-manuel.schoelling@gmx.de> In-Reply-To: <201701112105.R6Zog6jw%fengguang.wu@intel.com> References: <201701112105.R6Zog6jw%fengguang.wu@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Provags-ID: V03:K0:ZEQvP6dYR6xF8z98HjT2yAiyhihPOSlz4nm5/+8vGhAqa+7B3iA TYRavnyVNqT7WNJ9ZWW1+HWBd/HNNcNHLlBXqLoh5Ka68IZKSudCwNgGfyLZ77F+zcv8Gkn w6/NRGkKS5u7WqzKhowj5UXtCQMMyNjTKdrwX8GgvX9noyzqvyOF3Si6CkMM3d37OY9Gk15 Mtq2z6WYx+DKBBH2OKPGw== X-UI-Out-Filterresults: notjunk:1;V01:K0:iR7V1hKlW9U=:nL4yB5tk/jCoou3W/pIIr9 9VUgaCnbRT+IeOLvM2XrOpzFfWhGjpNkrjlX/1U8OJqpLzWlFlLLlCnrDZiAA5pRcG//we1YP mrw+TepyG6gqWTrdXhT1EivKkNti8YRay/ClYe2CAuW66CS2zL+MdPW7AEBGIMRyIW9okgk8R c1t4qrsKsK9NTkx3vJ3CLKJXXjr0fI4UXOPRp7Jn7FkpV3WyaU+6i0uz1bdnskz4G4di9suCm yE+i3TBGX2MipT9uMqOugVCEncO/N0vyWiF/VyuwB8Iv6XU726kchEeyFZ3G+BkPIa3IxLnUS AyEN+wSi3tJdWpVL+ChfZiw8NdngTaNFnJm0q506/3GoYTfdVGiBuGcFms7sug2SQ5yNhIL5Y 9UKITtfrrQjG1b64cQwNBBmwkw22ae+4yyna4EoWYKASVjk3uI9Dkz8ffksf+NsNpvHCsxGDS EZGa7OjcsfACBe6R6/FOJyU+GNt2yRIybxs1jURErSK3UjE6Eop+vSaDUZpwnk114R7GogaHz gonePIxHhoftcdb+SYCf/7sNDtCIvclV1MPlbeR/+1bZ7DyXGjkxAMkIfLDAsHFGzb3m7NK4w /ZLkX2WfbNqHPHkAaUMrH/v6KsBYRdVumoOFIy0s0hOujQSMOCEfcJHa+RIfOHCbn6rkWyBFQ slUDdpyrEHCnRLCxLfpKmQdMhFWV4wC6yodL3HmH8pyyft9RPVYS0418KpPEmQFYjRFL+r3Rt cYtTbq2/0klJmL3oZiATfUofowqdSOWobIHy4xOCsOPQEOBGDHHv5VjXq/CdLv0kFua5jk3Zi 2i6tUlZ Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add a scrollback buffers for each VGA console. The benefit is that the scrollback history is not flushed when switching between consoles but is persistent. The buffers are allocated on demand when a new console is opened. This breaks tools like clear_console that rely on flushing the scrollback history by switching back and forth between consoles which is why this feature is disabled by default. Use the escape sequence \e[3J instead for flushing the buffer. Signed-off-by: Manuel Schölling Reviewed-by: Andrey Utkin Tested-by: Andrey Utkin Tested-by: Adam Borowski --- drivers/video/console/Kconfig | 25 +++++++- drivers/video/console/vgacon.c | 142 ++++++++++++++++++++++++++--------------- 2 files changed, 111 insertions(+), 56 deletions(-) diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index c3f1fb9ee820..f500e58f7636 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -43,9 +43,28 @@ config VGACON_SOFT_SCROLLBACK_SIZE range 1 1024 default "64" help - Enter the amount of System RAM to allocate for the scrollback - buffer. Each 64KB will give you approximately 16 80x25 - screenfuls of scrollback buffer + Enter the amount of System RAM to allocate for scrollback + buffers of VGA consoles. Each 64KB will give you approximately + 16 80x25 screenfuls of scrollback buffer. + +config VGACON_SOFT_SCROLLBACK_PERSISTENT + bool "Persistent Scrollback History for each console" + depends on VGACON_SOFT_SCROLLBACK + default n + help + Say Y here if the scrollback history should persist when switching + between consoles. Otherwise, the scrollback history will be flushed + each time the console is switched. + + This feature might break your tool of choice to flush the scrollback + buffer, e.g. clear(1) will work fine but Debian's clear_console(1) + will be broken, which might cause security issues. + You can use the escape sequence \e[3J instead if this feature is + activated. + + Note that a buffer of VGACON_SOFT_SCROLLBACK_SIZE is taken for each + created tty device. + So if you use a RAM-constrained system, say N here. config MDA_CONSOLE depends on !M68K && !PARISC && ISA diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 9a7c2bbc5326..ca23d222e029 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -162,7 +162,7 @@ static inline void vga_set_mem_top(struct vc_data *c) #ifdef CONFIG_VGACON_SOFT_SCROLLBACK /* software scrollback */ -static struct vgacon_scrollback_info { +struct vgacon_scrollback_info { void *data; int tail; int size; @@ -171,74 +171,110 @@ static struct vgacon_scrollback_info { int cur; int save; int restore; -} vgacon_scrollback; +}; + +static struct vgacon_scrollback_info *vgacon_scrollback_cur; +#ifdef CONFIG_VGACON_SOFT_SCROLLBACK_PERSISTENT +static struct vgacon_scrollback_info vgacon_scrollbacks[MAX_NR_CONSOLES]; +#else +static struct vgacon_scrollback_info vgacon_scrollbacks[1]; +#endif -static void vgacon_scrollback_reset(size_t reset_size) +static void vgacon_scrollback_reset(int vc_num, size_t reset_size) { - if (vgacon_scrollback.data && reset_size > 0) - memset(vgacon_scrollback.data, 0, reset_size); + struct vgacon_scrollback_info *scrollback = &vgacon_scrollbacks[vc_num]; + + if (scrollback->data && reset_size > 0) + memset(scrollback->data, 0, reset_size); - vgacon_scrollback.cnt = 0; - vgacon_scrollback.tail = 0; - vgacon_scrollback.cur = 0; + scrollback->cnt = 0; + scrollback->tail = 0; + scrollback->cur = 0; } -static void vgacon_scrollback_init(int pitch) +static void vgacon_scrollback_init(int vc_num) { - int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch; - - if (vgacon_scrollback.data) { - vgacon_scrollback.cnt = 0; - vgacon_scrollback.tail = 0; - vgacon_scrollback.cur = 0; - vgacon_scrollback.rows = rows - 1; - vgacon_scrollback.size = rows * pitch; + int pitch = vga_video_num_columns * 2; + size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024; + int rows = size / pitch; + void *data; + + data = kmalloc_array(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, + GFP_NOWAIT); + + vgacon_scrollbacks[vc_num].data = data; + vgacon_scrollback_cur = &vgacon_scrollbacks[vc_num]; + + vgacon_scrollback_cur->rows = rows - 1; + vgacon_scrollback_cur->size = rows * pitch; + + vgacon_scrollback_reset(vc_num, size); +} + +static void vgacon_scrollback_switch(int vc_num) +{ +#ifndef CONFIG_VGACON_SOFT_SCROLLBACK_PERSISTENT + vc_num = 0; +#endif + + if (!vgacon_scrollbacks[vc_num].data) { + vgacon_scrollback_init(vc_num); + } else { +#ifdef CONFIG_VGACON_SOFT_SCROLLBACK_PERSISTENT + vgacon_scrollback_cur = &vgacon_scrollbacks[vc_num]; +#else + size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024; + + vgacon_scrollback_reset(vc_num, size); +#endif } } static void vgacon_scrollback_startup(void) { - vgacon_scrollback.data = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, - 1024, GFP_NOWAIT); - vgacon_scrollback_init(vga_video_num_columns * 2); + vgacon_scrollback_cur = &vgacon_scrollbacks[0]; + vgacon_scrollback_init(0); } static void vgacon_scrollback_update(struct vc_data *c, int t, int count) { void *p; - if (!vgacon_scrollback.size || c->vc_num != fg_console) + if (!vgacon_scrollback_cur->data || !vgacon_scrollback_cur->size || + c->vc_num != fg_console) return; p = (void *) (c->vc_origin + t * c->vc_size_row); while (count--) { - scr_memcpyw(vgacon_scrollback.data + vgacon_scrollback.tail, + scr_memcpyw(vgacon_scrollback_cur->data + + vgacon_scrollback_cur->tail, p, c->vc_size_row); - vgacon_scrollback.cnt++; + + vgacon_scrollback_cur->cnt++; p += c->vc_size_row; - vgacon_scrollback.tail += c->vc_size_row; + vgacon_scrollback_cur->tail += c->vc_size_row; - if (vgacon_scrollback.tail >= vgacon_scrollback.size) - vgacon_scrollback.tail = 0; + if (vgacon_scrollback_cur->tail >= vgacon_scrollback_cur->size) + vgacon_scrollback_cur->tail = 0; - if (vgacon_scrollback.cnt > vgacon_scrollback.rows) - vgacon_scrollback.cnt = vgacon_scrollback.rows; + if (vgacon_scrollback_cur->cnt > vgacon_scrollback_cur->rows) + vgacon_scrollback_cur->cnt = vgacon_scrollback_cur->rows; - vgacon_scrollback.cur = vgacon_scrollback.cnt; + vgacon_scrollback_cur->cur = vgacon_scrollback_cur->cnt; } } static void vgacon_restore_screen(struct vc_data *c) { - vgacon_scrollback.save = 0; + vgacon_scrollback_cur->save = 0; - if (!vga_is_gfx && !vgacon_scrollback.restore) { + if (!vga_is_gfx && !vgacon_scrollback_cur->restore) { scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); - vgacon_scrollback.restore = 1; - vgacon_scrollback.cur = vgacon_scrollback.cnt; + vgacon_scrollback_cur->restore = 1; + vgacon_scrollback_cur->cur = vgacon_scrollback_cur->cnt; } } @@ -252,41 +288,41 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines) return; } - if (!vgacon_scrollback.data) + if (!vgacon_scrollback_cur->data) return; - if (!vgacon_scrollback.save) { + if (!vgacon_scrollback_cur->save) { vgacon_cursor(c, CM_ERASE); vgacon_save_screen(c); - vgacon_scrollback.save = 1; + vgacon_scrollback_cur->save = 1; } - vgacon_scrollback.restore = 0; - start = vgacon_scrollback.cur + lines; + vgacon_scrollback_cur->restore = 0; + start = vgacon_scrollback_cur->cur + lines; end = start + abs(lines); if (start < 0) start = 0; - if (start > vgacon_scrollback.cnt) - start = vgacon_scrollback.cnt; + if (start > vgacon_scrollback_cur->cnt) + start = vgacon_scrollback_cur->cnt; if (end < 0) end = 0; - if (end > vgacon_scrollback.cnt) - end = vgacon_scrollback.cnt; + if (end > vgacon_scrollback_cur->cnt) + end = vgacon_scrollback_cur->cnt; - vgacon_scrollback.cur = start; + vgacon_scrollback_cur->cur = start; count = end - start; - soff = vgacon_scrollback.tail - ((vgacon_scrollback.cnt - end) * - c->vc_size_row); + soff = vgacon_scrollback_cur->tail - + ((vgacon_scrollback_cur->cnt - end) * c->vc_size_row); soff -= count * c->vc_size_row; if (soff < 0) - soff += vgacon_scrollback.size; + soff += vgacon_scrollback_cur->size; - count = vgacon_scrollback.cnt - start; + count = vgacon_scrollback_cur->cnt - start; if (count > c->vc_rows) count = c->vc_rows; @@ -300,13 +336,13 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines) count *= c->vc_size_row; /* how much memory to end of buffer left? */ - copysize = min(count, vgacon_scrollback.size - soff); - scr_memcpyw(d, vgacon_scrollback.data + soff, copysize); + copysize = min(count, vgacon_scrollback_cur->size - soff); + scr_memcpyw(d, vgacon_scrollback_cur->data + soff, copysize); d += copysize; count -= copysize; if (count) { - scr_memcpyw(d, vgacon_scrollback.data, count); + scr_memcpyw(d, vgacon_scrollback_cur->data, count); d += count; } @@ -320,13 +356,13 @@ static void vgacon_flush_scrollback(struct vc_data *c) { size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024; - if (c->vc_num == fg_console) - vgacon_scrollback_reset(size); + vgacon_scrollback_reset(c->vc_num, size); } #else #define vgacon_scrollback_startup(...) do { } while (0) #define vgacon_scrollback_init(...) do { } while (0) #define vgacon_scrollback_update(...) do { } while (0) +#define vgacon_scrollback_switch(...) do { } while (0) static void vgacon_restore_screen(struct vc_data *c) { @@ -805,7 +841,7 @@ static int vgacon_switch(struct vc_data *c) vgacon_doresize(c, c->vc_cols, c->vc_rows); } - vgacon_scrollback_init(c->vc_size_row); + vgacon_scrollback_switch(c->vc_num); return 0; /* Redrawing not needed */ } -- 2.11.0