linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] vgacon: Add support for soft scrollback
@ 2006-01-23  8:24 Antonino A. Daplas
  2006-01-25 13:52 ` Jan Engelhardt
  2006-01-31  6:58 ` Jindrich Makovicka
  0 siblings, 2 replies; 6+ messages in thread
From: Antonino A. Daplas @ 2006-01-23  8:24 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Linux Kernel Development

The scrollback buffer of the VGA console is located in VGA RAM. This
RAM is fixed in size and is very small. To make the scrollback buffer
larger, it must be placed instead in System RAM.

This patch adds this feature.  The feature and the size of the buffer
are made as a kernel config option.  Besides consuming kernel memory,
this feature will slow down the console by approximately 20%.

Signed-off-by: Antonino Daplas <adaplas@pol.net>
---

This patch is the result of a discussion on how to capture very long
oops tracings.  One of the suggestions was to increase the size of
the scrollback buffer of the VGA console.

I haven't tested the code rigorously, so let me know of any bugs. I
also tried to make it behave as close as possible to vgacon with a hard
scrollback.

Tony 

 drivers/video/console/Kconfig  |   24 ++++
 drivers/video/console/vgacon.c |  245 +++++++++++++++++++++++++++++++++-------
 2 files changed, 226 insertions(+), 43 deletions(-)

diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 6ee4498..4444bef 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -26,6 +26,30 @@ config VGA_CONSOLE
 #	   fi
 #	fi
 
+config VGACON_SOFT_SCROLLBACK
+       bool "Enable Scrollback Buffer in System RAM"
+       depends on VGA_CONSOLE
+       default n
+       help
+         The scrollback buffer of the standard VGA console is located in
+	 the VGA RAM.  The size of this RAM is fixed and is quite small.
+	 If you require a larger scrollback buffer, this can be placed in
+	 System RAM which is dynamically allocated during intialization.
+	 Placing the scrollback buffer in System RAM will slightly slow
+	 down the console.
+
+	 If you want this feature, say 'Y' here and enter the amount of
+	 RAM to allocate for this buffer.  If unsure, say 'N'.
+
+config VGACON_SOFT_SCROLLBACK_SIZE
+       int "Scrollback Buffer Size (in KB)"
+       depends on VGACON_SOFT_SCROLLBACK
+       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
+
 config VIDEO_SELECT
 	bool "Video mode selection support"
 	depends on  X86 && VGA_CONSOLE
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 12d9329..ec0aabc 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -93,7 +93,6 @@ static u8 vgacon_build_attr(struct vc_da
 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
 static unsigned long vgacon_uni_pagedir[2];
 
-
 /* Description of the hardware situation */
 static unsigned long	vga_vram_base;		/* Base of video memory */
 static unsigned long	vga_vram_end;		/* End of video memory */
@@ -161,6 +160,202 @@ static inline void write_vga(unsigned ch
 	spin_unlock_irqrestore(&vga_lock, flags);
 }
 
+static inline void vga_set_mem_top(struct vc_data *c)
+{
+	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
+}
+
+#ifdef CONFIG_VGACON_SOFT_SCROLLBACK
+#include <linux/bootmem.h>
+/* 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)
+{
+	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;
+	}
+}
+
+static void __init vgacon_scrollback_startup(void)
+{
+	vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
+					  * 1024);
+	vgacon_scrollback_init(vga_video_num_columns * 2);
+}
+
+static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
+{
+	void *p;
+
+	if (!vgacon_scrollback_size || c->vc_num != fg_console)
+		return;
+
+	p = (void *) (c->vc_origin + t * c->vc_size_row);
+
+	while (count--) {
+		scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail,
+			    p, c->vc_size_row);
+		vgacon_scrollback_cnt++;
+		p += c->vc_size_row;
+		vgacon_scrollback_tail += c->vc_size_row;
+
+		if (vgacon_scrollback_tail >= vgacon_scrollback_size)
+			vgacon_scrollback_tail = 0;
+
+		if (vgacon_scrollback_cnt > vgacon_scrollback_rows)
+			vgacon_scrollback_cnt = vgacon_scrollback_rows;
+
+		vgacon_scrollback_cur = vgacon_scrollback_cnt;
+	}
+}
+
+static void vgacon_restore_screen(struct vc_data *c)
+{
+	vgacon_scrollback_save = 0;
+
+	if (!vga_is_gfx && !vgacon_scrollback_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;
+	}
+}
+
+static int vgacon_scrolldelta(struct vc_data *c, int lines)
+{
+	int start, end, count, soff, diff;
+	void *d, *s;
+
+	if (!lines) {
+		c->vc_visible_origin = c->vc_origin;
+		vga_set_mem_top(c);
+		return 1;
+	}
+
+	if (!vgacon_scrollback)
+		return 1;
+
+	if (!vgacon_scrollback_save) {
+		vgacon_cursor(c, CM_ERASE);
+		vgacon_save_screen(c);
+		vgacon_scrollback_save = 1;
+	}
+
+	vgacon_scrollback_restore = 0;
+	start = vgacon_scrollback_cur + lines;
+	end = start + abs(lines);
+
+	if (start < 0)
+		start = 0;
+
+	if (start > vgacon_scrollback_cnt)
+		start = vgacon_scrollback_cnt;
+
+	if (end < 0)
+		end = 0;
+
+	if (end > vgacon_scrollback_cnt)
+		end = vgacon_scrollback_cnt;
+
+	vgacon_scrollback_cur = start;
+	count = end - start;
+	soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) *
+					 c->vc_size_row);
+	soff -= count * c->vc_size_row;
+
+	if (soff < 0)
+		soff += vgacon_scrollback_size;
+
+	count = vgacon_scrollback_cnt - start;
+
+	if (count > c->vc_rows)
+		count = c->vc_rows;
+
+	diff = c->vc_rows - count;
+
+	d = (void *) c->vc_origin;
+	s = (void *) c->vc_screenbuf;
+
+	while (count--) {
+		scr_memcpyw(d, vgacon_scrollback + soff, c->vc_size_row);
+		d += c->vc_size_row;
+		soff += c->vc_size_row;
+
+		if (soff >= vgacon_scrollback_size)
+			soff = 0;
+	}
+
+	if (diff == c->vc_rows) {
+		vgacon_cursor(c, CM_MOVE);
+	} else {
+		while (diff--) {
+			scr_memcpyw(d, s, c->vc_size_row);
+			d += c->vc_size_row;
+			s += c->vc_size_row;
+		}
+	}
+
+	return 1;
+}
+#else
+#define vgacon_scrollback_startup(...) do { } while (0)
+#define vgacon_scrollback_init(...)    do { } while (0)
+#define vgacon_scrollback_update(...)  do { } while (0)
+
+static void vgacon_restore_screen(struct vc_data *c)
+{
+	if (c->vc_origin != c->vc_visible_origin)
+		vgacon_scrolldelta(c, 0);
+}
+
+static int vgacon_scrolldelta(struct vc_data *c, int lines)
+{
+	if (!lines)		/* Turn scrollback off */
+		c->vc_visible_origin = c->vc_origin;
+	else {
+		int margin = c->vc_size_row * 4;
+		int ul, we, p, st;
+
+		printk("vgacon delta: %i\n", lines);
+		if (vga_rolled_over >
+		    (c->vc_scr_end - vga_vram_base) + margin) {
+			ul = c->vc_scr_end - vga_vram_base;
+			we = vga_rolled_over + c->vc_size_row;
+		} else {
+			ul = 0;
+			we = vga_vram_size;
+		}
+		p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
+		    lines * c->vc_size_row;
+		st = (c->vc_origin - vga_vram_base - ul + we) % we;
+		if (st < 2 * margin)
+			margin = 0;
+		if (p < margin)
+			p = 0;
+		if (p > st - margin)
+			p = st;
+		c->vc_visible_origin = vga_vram_base + (p + ul) % we;
+	}
+	vga_set_mem_top(c);
+	return 1;
+}
+#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
+
 static const char __init *vgacon_startup(void)
 {
 	const char *display_desc = NULL;
@@ -330,7 +525,7 @@ static const char __init *vgacon_startup
 
 	vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH;
 	vgacon_yres = vga_scan_lines;
-
+	vgacon_scrollback_startup();
 	return display_desc;
 }
 
@@ -357,11 +552,6 @@ static void vgacon_init(struct vc_data *
 		con_set_default_unimap(c);
 }
 
-static inline void vga_set_mem_top(struct vc_data *c)
-{
-	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
-}
-
 static void vgacon_deinit(struct vc_data *c)
 {
 	/* When closing the last console, reset video origin */
@@ -450,8 +640,8 @@ static void vgacon_set_cursor_size(int x
 
 static void vgacon_cursor(struct vc_data *c, int mode)
 {
-	if (c->vc_origin != c->vc_visible_origin)
-		vgacon_scrolldelta(c, 0);
+	vgacon_restore_screen(c);
+
 	switch (mode) {
 	case CM_ERASE:
 		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
@@ -592,6 +782,7 @@ static int vgacon_switch(struct vc_data 
 			vgacon_doresize(c, c->vc_cols, c->vc_rows);
 	}
 
+	vgacon_scrollback_init(c->vc_size_row);
 	return 0;		/* Redrawing not needed */
 }
 
@@ -1059,37 +1250,6 @@ static int vgacon_resize(struct vc_data 
 	return 0;
 }
 
-static int vgacon_scrolldelta(struct vc_data *c, int lines)
-{
-	if (!lines)		/* Turn scrollback off */
-		c->vc_visible_origin = c->vc_origin;
-	else {
-		int margin = c->vc_size_row * 4;
-		int ul, we, p, st;
-
-		if (vga_rolled_over >
-		    (c->vc_scr_end - vga_vram_base) + margin) {
-			ul = c->vc_scr_end - vga_vram_base;
-			we = vga_rolled_over + c->vc_size_row;
-		} else {
-			ul = 0;
-			we = vga_vram_size;
-		}
-		p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
-		    lines * c->vc_size_row;
-		st = (c->vc_origin - vga_vram_base - ul + we) % we;
-		if (st < 2 * margin)
-			margin = 0;
-		if (p < margin)
-			p = 0;
-		if (p > st - margin)
-			p = st;
-		c->vc_visible_origin = vga_vram_base + (p + ul) % we;
-	}
-	vga_set_mem_top(c);
-	return 1;
-}
-
 static int vgacon_set_origin(struct vc_data *c)
 {
 	if (vga_is_gfx ||	/* We don't play origin tricks in graphic modes */
@@ -1132,15 +1292,14 @@ static int vgacon_scroll(struct vc_data 
 	if (t || b != c->vc_rows || vga_is_gfx)
 		return 0;
 
-	if (c->vc_origin != c->vc_visible_origin)
-		vgacon_scrolldelta(c, 0);
-
 	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
 		return 0;
 
+	vgacon_restore_screen(c);
 	oldo = c->vc_origin;
 	delta = lines * c->vc_size_row;
 	if (dir == SM_UP) {
+		vgacon_scrollback_update(c, t, lines);
 		if (c->vc_scr_end + delta >= vga_vram_end) {
 			scr_memcpyw((u16 *) vga_vram_base,
 				    (u16 *) (oldo + delta),


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] vgacon: Add support for soft scrollback
  2006-01-23  8:24 [PATCH] vgacon: Add support for soft scrollback Antonino A. Daplas
@ 2006-01-25 13:52 ` Jan Engelhardt
  2006-01-25 23:35   ` Antonino A. Daplas
  2006-01-31  6:58 ` Jindrich Makovicka
  1 sibling, 1 reply; 6+ messages in thread
From: Jan Engelhardt @ 2006-01-25 13:52 UTC (permalink / raw)
  To: Antonino A. Daplas; +Cc: Andrew Morton, Linux Kernel Development


>This patch adds this feature.  The feature and the size of the buffer
>are made as a kernel config option.  Besides consuming kernel memory,
>this feature will slow down the console by approximately 20%.

Slower? Then I would rather prefer compact oopses.



Jan Engelhardt
-- 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] vgacon: Add support for soft scrollback
  2006-01-25 13:52 ` Jan Engelhardt
@ 2006-01-25 23:35   ` Antonino A. Daplas
  2006-01-26 20:44     ` Jan Engelhardt
  0 siblings, 1 reply; 6+ messages in thread
From: Antonino A. Daplas @ 2006-01-25 23:35 UTC (permalink / raw)
  To: Jan Engelhardt; +Cc: Andrew Morton, Linux Kernel Development

Jan Engelhardt wrote:
>> This patch adds this feature.  The feature and the size of the buffer
>> are made as a kernel config option.  Besides consuming kernel memory,
>> this feature will slow down the console by approximately 20%.
> 
> Slower?

Yes, I mentioned this before. The slowdown is unavoidable because the
contents of the scrollback is read from the VGA RAM.  It can be speeded
up but it will require an overhaul of vgacon to use buffers in system
RAM for the entire screen contents, visible and not visible.

Hard scrollback is still the default for vgacon, and soft scrollback
has to be selected during kernel config.

> Then I would rather prefer compact oopses.

Of course.

Tony

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] vgacon: Add support for soft scrollback
  2006-01-25 23:35   ` Antonino A. Daplas
@ 2006-01-26 20:44     ` Jan Engelhardt
  0 siblings, 0 replies; 6+ messages in thread
From: Jan Engelhardt @ 2006-01-26 20:44 UTC (permalink / raw)
  To: Antonino A. Daplas; +Cc: Andrew Morton, Linux Kernel Development


>Hard scrollback is still the default for vgacon, and soft scrollback
>has to be selected during kernel config.

kconfig - that's good to hear - then I'm absolutely fine with it.



Jan Engelhardt
-- 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] vgacon: Add support for soft scrollback
  2006-01-23  8:24 [PATCH] vgacon: Add support for soft scrollback Antonino A. Daplas
  2006-01-25 13:52 ` Jan Engelhardt
@ 2006-01-31  6:58 ` Jindrich Makovicka
  2006-02-01 16:04   ` Jan Engelhardt
  1 sibling, 1 reply; 6+ messages in thread
From: Jindrich Makovicka @ 2006-01-31  6:58 UTC (permalink / raw)
  To: linux-kernel

Antonino A. Daplas wrote:
> The scrollback buffer of the VGA console is located in VGA RAM. This
> RAM is fixed in size and is very small. To make the scrollback buffer
> larger, it must be placed instead in System RAM.
> 
> This patch adds this feature.  The feature and the size of the buffer
> are made as a kernel config option.  Besides consuming kernel memory,
> this feature will slow down the console by approximately 20%.
> 
> Signed-off-by: Antonino Daplas <adaplas@pol.net>
> ---
> 
> This patch is the result of a discussion on how to capture very long
> oops tracings.  One of the suggestions was to increase the size of
> the scrollback buffer of the VGA console.
> 
> I haven't tested the code rigorously, so let me know of any bugs. I
> also tried to make it behave as close as possible to vgacon with a hard
> scrollback.

[...]

> +static int vgacon_scrolldelta(struct vc_data *c, int lines)
> +{
> +	if (!lines)		/* Turn scrollback off */
> +		c->vc_visible_origin = c->vc_origin;
> +	else {
> +		int margin = c->vc_size_row * 4;
> +		int ul, we, p, st;
> +
> +		printk("vgacon delta: %i\n", lines);

                ^^^^^^
This disables the hard scrollback, as the console is immediately
scrolled back when the mesage gets printed.

Regards,
-- 
Jindrich Makovicka


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] vgacon: Add support for soft scrollback
  2006-01-31  6:58 ` Jindrich Makovicka
@ 2006-02-01 16:04   ` Jan Engelhardt
  0 siblings, 0 replies; 6+ messages in thread
From: Jan Engelhardt @ 2006-02-01 16:04 UTC (permalink / raw)
  To: Jindrich Makovicka; +Cc: linux-kernel

>> +
>> +		printk("vgacon delta: %i\n", lines);
>
>                ^^^^^^
>This disables the hard scrollback, as the console is immediately
>scrolled back when the mesage gets printed.
>

printk(KERN_DEBUG ) should probably help it. That way, only syslog picks it 
up.


Jan Engelhardt
-- 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2006-02-01 16:04 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-23  8:24 [PATCH] vgacon: Add support for soft scrollback Antonino A. Daplas
2006-01-25 13:52 ` Jan Engelhardt
2006-01-25 23:35   ` Antonino A. Daplas
2006-01-26 20:44     ` Jan Engelhardt
2006-01-31  6:58 ` Jindrich Makovicka
2006-02-01 16:04   ` Jan Engelhardt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).