From patchwork Mon Apr 18 19:56:57 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Manuel_Sch=C3=B6lling?= X-Patchwork-Id: 8874791 Return-Path: X-Original-To: patchwork-linux-fbdev@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 26A0C9F441 for ; Mon, 18 Apr 2016 19:58:17 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D5491201C0 for ; Mon, 18 Apr 2016 19:58:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7CE9A201BC for ; Mon, 18 Apr 2016 19:58:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752706AbcDRT5d (ORCPT ); Mon, 18 Apr 2016 15:57:33 -0400 Received: from mout.gmx.net ([212.227.17.20]:61375 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752698AbcDRT5b (ORCPT ); Mon, 18 Apr 2016 15:57:31 -0400 Received: from schoellingm.dzne.de ([37.201.194.187]) by mail.gmx.com (mrgmx102) with ESMTPSA (Nemesis) id 0Mg0IT-1b47P92EPV-00NRiw; Mon, 18 Apr 2016 21:57:10 +0200 From: =?UTF-8?q?Manuel=20Sch=C3=B6lling?= To: gregkh@linuxfoundation.org Cc: jslaby@suse.com, thomas@winischhofer.net, plagnioj@jcrosoft.com, tomi.valkeinen@ti.com, jejb@parisc-linux.org, deller@gmx.de, manuel.schoelling@gmx.de, sfr@canb.auug.org.au, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, linux-fbdev@vger.kernel.org, linux-parisc@vger.kernel.org Subject: [PATCH 1/2] console: Add persistent scrollback buffers for all VGA consoles Date: Mon, 18 Apr 2016 21:56:57 +0200 Message-Id: <1461009418-1795-2-git-send-email-manuel.schoelling@gmx.de> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1461009418-1795-1-git-send-email-manuel.schoelling@gmx.de> References: <1461009418-1795-1-git-send-email-manuel.schoelling@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K0:Y21VVWYjTiPKWYBIs4/ZM7R5hIjfVR9/x2If6KGqTSpMQCJqRIo aHZj3psoWLiCXr46zn+i6P3au7VIu1M0EtvmjDb9msTB/g2w9LuBEZb3pAcN2MY1uEVgnpI NOHDg9cnm/E7/kEhbna/+ebuvN1gwDwRjK3DKhiyoOw0xRCJNhvUUmtpcmqz2xT/JfCXhQy qqNL1oWNcPvMTqciqFVog== X-UI-Out-Filterresults: notjunk:1; V01:K0:MYpIUaHLdiI=:1IRAGmn4oiHkgLVBMm+GZz sbaWdjcN1HBU7LPTkWIo3ygg9kenSMvZ7CjiLxnXUddo+7G3FzhIDCU6bER2jBrYM+uKcO3a0 +eXlnFZmfFAQ9yQAM69eDsptFc+Y4V1dyAsdbKvBfFv3f4s6UlAJwHUnHdvZR8emeVtMUZ5HQ N/M3r0npu2FLaKK5iHqXhuo6OowVbXTShw4jhKvMHymXRVRdc3p16aXSFOS8JqIdPdC7vY5Ch XwsnzN13teThfd+voY324vnSFngUKBU+AytXc9CQALEEMHFEN0pKUpWoBP4NgqdVSN3j5oTW7 eQJ5B9jGtXS9bIxALJfdshrnG5llIEHGsEZAWNnIbjlkiO1JoqfQikZUhybk3ylGp0EZ2LuG1 MIxL0ZBcBxdgKyd7L87vapv+MiEevzH1f/dYB8duMe/keVkc5WEgolko1mGm5K510tS/JTa+c lwTeeuIXyrn130MhuRdvJCsxADZx6p00dMyoHqRf5m9MpcteDYj7FU7CbzetuPKvpG+EQelO/ aVordGydSxEqtpk5NhQgqXYzCuj2zzDw95HdtOJIUXfl+KuAcOuAD7d5hp5gYdj34yeREvC28 846KhAotZu6p0MdvUgiKi5iK/79NLrmqk0rsYyukv2WdNpIKVY7UI49mtrPkFeIM/y+sOV5DQ apj8ipkMV8FrkWFzdjHgaDe1S9GkRibSPagAPGQEaDZAD02Q6EhisEbzOpqUJysfLgYgaH+Ic ff11+JvUWg03HCfoupHvGJ+2aB2xxlDFaeiCghe8sk22pfv6lKmVsJ80TdWAFpUbqn6QyIEE0 +d3zBwa Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Signed-off-by: Manuel Schölling --- drivers/video/console/Kconfig | 22 +++++- drivers/video/console/vgacon.c | 172 +++++++++++++++++++++++++++-------------- 2 files changed, 133 insertions(+), 61 deletions(-) diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 38da6e2..f101a63 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -43,9 +43,25 @@ 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_FOR_EACH_CONSOLE + bool "Persistent Scrollback History for each console" + depends on VGACON_SOFT_SCROLLBACK + default n + help + Say Y here if for each VGA console a scrollback buffer should + be allocated. The scrollback history will persist when switching + between consoles. If you say N here, scrollback is only supported + for the active VGA console and scrollback history will be flushed + when switching between consoles. + + This breaks legacy versions of tools like clear_console which + might raise security issues. + + 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 517f565..6c0b9ba 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1,5 +1,5 @@ /* - * linux/drivers/video/vgacon.c -- Low level VGA based console driver + * linux/drivers/video/console/vgacon.c -- Low level VGA based console driver * * Created 28 Sep 1997 by Geert Uytterhoeven * @@ -106,12 +106,12 @@ static unsigned char vga_hardscroll_enabled __read_mostly; static unsigned char vga_hardscroll_user_enable __read_mostly = 1; static unsigned char vga_font_is_default = 1; static int vga_vesa_blanked; -static int vga_palette_blanked; -static int vga_is_gfx; -static int vga_512_chars; -static int vga_video_font_height; -static int vga_scan_lines __read_mostly; -static unsigned int vga_rolled_over; +static int vga_palette_blanked; +static int vga_is_gfx; +static int vga_512_chars; +static int vga_video_font_height; +static int vga_scan_lines __read_mostly; +static unsigned int vga_rolled_over; static int vgacon_text_mode_force; @@ -182,70 +182,125 @@ static inline void vga_set_mem_top(struct vc_data *c) #ifdef CONFIG_VGACON_SOFT_SCROLLBACK /* software scrollback */ -static void *vgacon_scrollback; -static int vgacon_scrollback_tail; -static int vgacon_scrollback_size; -static int vgacon_scrollback_rows; -static int vgacon_scrollback_cnt; -static int vgacon_scrollback_cur; -static int vgacon_scrollback_save; -static int vgacon_scrollback_restore; - -static void vgacon_scrollback_init(int pitch) +struct vgacon_scrollback_info { + void *data; + int tail; + int size; + int rows; + int cnt; + int cur; + int save; + int restore; +}; +static struct vgacon_scrollback_info *vgacon_scrollback_cur; +#ifdef CONFIG_VGACON_SOFT_SCROLLBACK_FOR_EACH_CONSOLE +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) { - int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch; - - if (vgacon_scrollback) { - vgacon_scrollback_cnt = 0; - vgacon_scrollback_tail = 0; - vgacon_scrollback_cur = 0; - vgacon_scrollback_rows = rows - 1; - vgacon_scrollback_size = rows * pitch; + if (vgacon_scrollback_cur->data && reset_size > 0) + memset(vgacon_scrollback_cur->data, 0, reset_size); + + vgacon_scrollback_cur->cnt = 0; + vgacon_scrollback_cur->tail = 0; + vgacon_scrollback_cur->cur = 0; +} + +static void vgacon_scrollback_init(int vc_num) +{ + int pitch = vga_video_num_columns * 2; + size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024; + int rows = size/pitch; + void *data; + + data = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT); + if (data) { + 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(0); + } else { + pr_warn("VGAcon: failed to allocate memory for scrollback. Trying to reuse previous buffer.\n"); + /* Leave vgacon_scrollback_cur untouched but reset its content */ + vgacon_scrollback_reset(size); } } +static void vgacon_switch_scrollback(int vc_num) +{ +#ifdef CONFIG_VGACON_SOFT_SCROLLBACK_FOR_EACH_CONSOLE + if (!vgacon_scrollbacks[vc_num].data) + vgacon_scrollback_init(vc_num); + else + vgacon_scrollback_cur = &vgacon_scrollbacks[vc_num]; +#else + vc_num = 0; + + if (!vgacon_scrollbacks[vc_num].data) + vgacon_scrollback_init(vc_num); + else { + size_t size = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024; + + vgacon_scrollback_reset(size); + } +#endif +} + static void vgacon_scrollback_startup(void) { - vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT); - vgacon_scrollback_init(vga_video_num_columns * 2); + int i; + + for (i = 0; i < ARRAY_SIZE(vgacon_scrollbacks); ++i) + vgacon_scrollbacks[i].data = NULL; + + 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) return; p = (void *) (c->vc_origin + t * c->vc_size_row); while (count--) { - scr_memcpyw(vgacon_scrollback + 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; } } @@ -259,41 +314,41 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) return 1; } - if (!vgacon_scrollback) + if (!vgacon_scrollback_cur->data) return 1; - 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; + soff -= ((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; @@ -307,13 +362,13 @@ static int 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 + 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, count); + scr_memcpyw(d, vgacon_scrollback_cur->data, count); d += count; } @@ -328,6 +383,7 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) #define vgacon_scrollback_startup(...) do { } while (0) #define vgacon_scrollback_init(...) do { } while (0) #define vgacon_scrollback_update(...) do { } while (0) +#define vgacon_switch_scrollback(...) do { } while (0) static void vgacon_restore_screen(struct vc_data *c) { @@ -843,7 +899,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_switch_scrollback(c->vc_num); return 0; /* Redrawing not needed */ }