Mailing List Archive

[xen-unstable] x86-64: enable hypervisor output on VESA frame buffer
# HG changeset patch
# User kfraser@localhost.localdomain
# Date 1186996146 -3600
# Node ID f2649861d59428f16f6f7705e6de47d2cc02c3ae
# Parent c362bcee8047d3d30b8c7655d26d8a8702371b6f
x86-64: enable hypervisor output on VESA frame buffer

This is x86-64 only for now due to the virtual address space
constraints on x86-32.

New options 'vesa-ram', 'vesa-map', 'vesa-mtrr' are close equivalents
to the vesafb Linux options 'vtotal', 'vremap', 'mtrr'.

Also the font can be specified: font=8x{8,14,16}.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
---
xen/arch/x86/setup.c | 6
xen/drivers/char/console.c | 14 --
xen/drivers/video/Makefile | 12 +
xen/drivers/video/vesa.c | 307 +++++++++++++++++++++++++++++++++++++++++++++
xen/drivers/video/vga.c | 112 +++++++---------
xen/include/xen/vga.h | 8 -
6 files changed, 380 insertions(+), 79 deletions(-)

diff -r c362bcee8047 -r f2649861d594 xen/arch/x86/setup.c
--- a/xen/arch/x86/setup.c Sun Aug 12 16:09:13 2007 +0100
+++ b/xen/arch/x86/setup.c Mon Aug 13 10:09:06 2007 +0100
@@ -106,6 +106,8 @@ extern void trap_init(void);
extern void trap_init(void);
extern void early_time_init(void);
extern void early_cpu_init(void);
+extern void vesa_init(void);
+extern void vesa_mtrr_init(void);

struct tss_struct init_tss[NR_CPUS];

@@ -901,6 +903,7 @@ void __init __start_xen(unsigned long mb
#ifdef __x86_64__
init_xenheap_pages(xen_phys_start, __pa(&_start));
nr_pages += (__pa(&_start) - xen_phys_start) >> PAGE_SHIFT;
+ vesa_init();
#endif
xenheap_phys_start = xen_phys_start;
printk("Xen heap: %luMB (%lukB)\n",
@@ -966,6 +969,9 @@ void __init __start_xen(unsigned long mb
set_in_cr4(X86_CR4_OSFXSR);
if ( cpu_has_xmm )
set_in_cr4(X86_CR4_OSXMMEXCPT);
+#ifdef CONFIG_X86_64
+ vesa_mtrr_init();
+#endif

if ( opt_nosmp )
max_cpus = 0;
diff -r c362bcee8047 -r f2649861d594 xen/drivers/char/console.c
--- a/xen/drivers/char/console.c Sun Aug 12 16:09:13 2007 +0100
+++ b/xen/drivers/char/console.c Mon Aug 13 10:09:06 2007 +0100
@@ -331,13 +331,11 @@ static long guest_console_write(XEN_GUES
kbuf[kcount] = '\0';

sercon_puts(kbuf);
-
- for ( kptr = kbuf; *kptr != '\0'; kptr++ )
- {
- vga_putchar(*kptr);
- if ( opt_console_to_ring )
+ vga_puts(kbuf);
+
+ if ( opt_console_to_ring )
+ for ( kptr = kbuf; *kptr != '\0'; kptr++ )
putchar_console_ring(*kptr);
- }

if ( opt_console_to_ring )
send_guest_global_virq(dom0, VIRQ_CON_RING);
@@ -404,12 +402,10 @@ static void __putstr(const char *str)
int c;

sercon_puts(str);
+ vga_puts(str);

while ( (c = *str++) != '\0' )
- {
- vga_putchar(c);
putchar_console_ring(c);
- }

send_guest_global_virq(dom0, VIRQ_CON_RING);
}
diff -r c362bcee8047 -r f2649861d594 xen/drivers/video/Makefile
--- a/xen/drivers/video/Makefile Sun Aug 12 16:09:13 2007 +0100
+++ b/xen/drivers/video/Makefile Mon Aug 13 10:09:06 2007 +0100
@@ -1,4 +1,8 @@ obj-y += font_8x14.o
-obj-y += font_8x14.o
-obj-y += font_8x16.o
-obj-y += font_8x8.o
-obj-y += vga.o
+obj-y := vga.o
+obj-$(CONFIG_X86_64) += font_8x14.o
+obj-$(CONFIG_X86_64) += font_8x16.o
+obj-$(CONFIG_X86_64) += font_8x8.o
+obj-$(CONFIG_X86_64) += vesa.o
+
+# extra dependencies
+vesa.o: font.h
diff -r c362bcee8047 -r f2649861d594 xen/drivers/video/vesa.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/drivers/video/vesa.c Mon Aug 13 10:09:06 2007 +0100
@@ -0,0 +1,307 @@
+/******************************************************************************
+ * vesa.c
+ *
+ * VESA linear frame buffer handling.
+ */
+
+#include <xen/config.h>
+#include <xen/compile.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/errno.h>
+#include <xen/console.h>
+#include <xen/vga.h>
+#include "font.h"
+
+#define vlfb_info vga_console_info.u.vesa_lfb
+#define text_columns (vlfb_info.width / font->width)
+#define text_rows (vlfb_info.height / font->height)
+
+static void vesa_redraw_puts(const char *s);
+static void vesa_scroll_puts(const char *s);
+
+static unsigned char *lfb, *lbuf, *text_buf;
+static const struct font_desc *font;
+static bool_t vga_compat;
+static unsigned int pixel_on;
+static unsigned int xpos, ypos;
+
+static unsigned int vram_total;
+integer_param("vesa-ram", vram_total);
+
+static unsigned int vram_remap;
+integer_param("vesa-map", vram_remap);
+
+static int font_height;
+static void __init parse_font_height(const char *s)
+{
+ if ( simple_strtoul(s, &s, 10) == 8 && (*s++ == 'x') )
+ font_height = simple_strtoul(s, &s, 10);
+ if ( *s != '\0' )
+ font_height = 0;
+}
+custom_param("font", parse_font_height);
+
+void __init vesa_early_init(void)
+{
+ unsigned int vram_vmode;
+
+ /* XXX vga_compat = !(boot_video_info.capabilities & 2); */
+
+ if ( (vlfb_info.bits_per_pixel < 8) || (vlfb_info.bits_per_pixel > 32) )
+ return;
+
+ if ( font_height == 0 ) /* choose a sensible default */
+ font = ((vlfb_info.height <= 600) ? &font_vga_8x8 :
+ (vlfb_info.height <= 768) ? &font_vga_8x14 : &font_vga_8x16);
+ else if ( font_height <= 8 )
+ font = &font_vga_8x8;
+ else if ( font_height <= 14 )
+ font = &font_vga_8x14;
+ else
+ font = &font_vga_8x16;
+
+ /* vram_vmode -- that is the amount of memory needed for the
+ * used video mode, i.e. the minimum amount of
+ * memory we need. */
+ vram_vmode = vlfb_info.height * vlfb_info.bytes_per_line;
+
+ /* vram_total -- all video memory we have. Used for mtrr
+ * entries. */
+ vram_total = vram_total ? (vram_total << 20) : (vlfb_info.lfb_size << 16);
+ vram_total = max_t(unsigned int, vram_total, vram_vmode);
+
+ /* vram_remap -- the amount of video memory we are going to
+ * use for vesafb. With modern cards it is no
+ * option to simply use vram_total as that
+ * wastes plenty of kernel address space. */
+ vram_remap = (vram_remap ?
+ (vram_remap << 20) :
+ ((vram_vmode + (1 << L2_PAGETABLE_SHIFT) - 1) &
+ ~((1 << L2_PAGETABLE_SHIFT) - 1)));
+ vram_remap = max_t(unsigned int, vram_remap, vram_vmode);
+ vram_remap = min_t(unsigned int, vram_remap, vram_total);
+}
+
+void __init vesa_init(void)
+{
+ if ( !font )
+ goto fail;
+
+ lbuf = xmalloc_bytes(vlfb_info.bytes_per_line);
+ if ( !lbuf )
+ goto fail;
+
+ text_buf = xmalloc_bytes(text_columns * text_rows);
+ if ( !text_buf )
+ goto fail;
+
+ if ( map_pages_to_xen(IOREMAP_VIRT_START,
+ vlfb_info.lfb_base >> PAGE_SHIFT,
+ vram_remap >> PAGE_SHIFT,
+ PAGE_HYPERVISOR_NOCACHE) )
+ goto fail;
+
+ lfb = memset((void *)IOREMAP_VIRT_START, 0, vram_remap);
+ memset(text_buf, 0, text_columns * text_rows);
+
+ vga_puts = vesa_redraw_puts;
+
+ printk(XENLOG_INFO "vesafb: framebuffer at 0x%x, mapped to 0x%p, "
+ "using %uk, total %uk\n",
+ vlfb_info.lfb_base, lfb,
+ vram_remap >> 10, vram_total >> 10);
+ printk(XENLOG_INFO "vesafb: mode is %dx%dx%u, linelength=%d, font %ux%u\n",
+ vlfb_info.width, vlfb_info.height,
+ vlfb_info.bits_per_pixel, vlfb_info.bytes_per_line,
+ font->width, font->height);
+ printk(XENLOG_INFO "vesafb: %scolor: size=%d:%d:%d:%d, "
+ "shift=%d:%d:%d:%d\n",
+ vlfb_info.bits_per_pixel > 8 ? "True" :
+ vga_compat ? "Pseudo" : "Static Pseudo",
+ vlfb_info.rsvd_size, vlfb_info.red_size,
+ vlfb_info.green_size, vlfb_info.blue_size,
+ vlfb_info.rsvd_pos, vlfb_info.red_pos,
+ vlfb_info.green_pos, vlfb_info.blue_pos);
+
+ if ( vlfb_info.bits_per_pixel > 8 )
+ {
+ /* Light grey in truecolor. */
+ unsigned int grey = 0xaaaaaaaa;
+ pixel_on =
+ ((grey >> (32 - vlfb_info. red_size)) << vlfb_info. red_pos) |
+ ((grey >> (32 - vlfb_info.green_size)) << vlfb_info.green_pos) |
+ ((grey >> (32 - vlfb_info. blue_size)) << vlfb_info. blue_pos);
+ }
+ else
+ {
+ /* White(ish) in default pseudocolor palette. */
+ pixel_on = 7;
+ }
+
+ return;
+
+ fail:
+ xfree(lbuf);
+ xfree(text_buf);
+}
+
+void __init vesa_endboot(void)
+{
+ xpos = 0;
+ vga_puts = vesa_scroll_puts;
+}
+
+#if defined(CONFIG_X86)
+
+#include <asm/mtrr.h>
+
+static unsigned int vesa_mtrr;
+integer_param("vesa-mtrr", vesa_mtrr);
+
+void __init vesa_mtrr_init(void)
+{
+ static const int mtrr_types[] = {
+ 0, MTRR_TYPE_UNCACHABLE, MTRR_TYPE_WRBACK,
+ MTRR_TYPE_WRCOMB, MTRR_TYPE_WRTHROUGH };
+ unsigned int size_total;
+ int rc, type;
+
+ if ( !lfb || (vesa_mtrr == 0) || (vesa_mtrr >= ARRAY_SIZE(mtrr_types)) )
+ return;
+
+ type = mtrr_types[vesa_mtrr];
+ if ( !type )
+ return;
+
+ /* Find the largest power-of-two */
+ size_total = vram_total;
+ while ( size_total & (size_total - 1) )
+ size_total &= size_total - 1;
+
+ /* Try and find a power of two to add */
+ do {
+ rc = mtrr_add(vlfb_info.lfb_base, size_total, type, 1);
+ size_total >>= 1;
+ } while ( (size_total >= PAGE_SIZE) && (rc == -EINVAL) );
+}
+
+static void lfb_flush(void)
+{
+ if ( vesa_mtrr == 3 )
+ __asm__ __volatile__ ("sfence" : : : "memory");
+}
+
+#else /* !defined(CONFIG_X86) */
+
+#define lfb_flush() ((void)0)
+
+#endif
+
+/* Render one line of text to given linear framebuffer line. */
+static void vesa_show_line(
+ const unsigned char *text_line,
+ unsigned char *video_line,
+ unsigned int nr_chars)
+{
+ unsigned int i, j, b, bpp, pixel;
+
+ bpp = (vlfb_info.bits_per_pixel + 7) >> 3;
+
+ for ( i = 0; i < font->height; i++ )
+ {
+ unsigned char *ptr = lbuf;
+
+ for ( j = 0; j < nr_chars; j++ )
+ {
+ const unsigned char *bits = font->data;
+ bits += ((text_line[j] * font->height + i) *
+ ((font->width + 7) >> 3));
+ for ( b = font->width; b--; )
+ {
+ pixel = test_bit(b, bits) ? pixel_on : 0;
+ memcpy(ptr, &pixel, bpp);
+ ptr += bpp;
+ }
+ }
+
+ memset(ptr, 0, (vlfb_info.width - nr_chars * font->width) * bpp);
+ memcpy(video_line, lbuf, vlfb_info.width * bpp);
+ video_line += vlfb_info.bytes_per_line;
+ }
+}
+
+/* Fast mode which redraws all modified parts of a 2D text buffer. */
+static void vesa_redraw_puts(const char *s)
+{
+ unsigned int i, min_redraw_y = ypos;
+ char c;
+
+ /* Paste characters into text buffer. */
+ while ( (c = *s++) != '\0' )
+ {
+ if ( (c == '\n') || (xpos >= text_columns) )
+ {
+ if ( ++ypos >= text_rows )
+ {
+ min_redraw_y = 0;
+ ypos = text_rows - 1;
+ memmove(text_buf, text_buf + text_columns,
+ ypos * text_columns);
+ memset(text_buf + ypos * text_columns, 0, xpos);
+ }
+ xpos = 0;
+ }
+
+ if ( c != '\n' )
+ text_buf[xpos++ + ypos * text_columns] = c;
+ }
+
+ /* Render modified section of text buffer to VESA linear framebuffer. */
+ for ( i = min_redraw_y; i <= ypos; i++ )
+ vesa_show_line(text_buf + i * text_columns,
+ lfb + i * font->height * vlfb_info.bytes_per_line,
+ text_columns);
+
+ lfb_flush();
+}
+
+/* Slower line-based scroll mode which interacts better with dom0. */
+static void vesa_scroll_puts(const char *s)
+{
+ unsigned int i;
+ char c;
+
+ while ( (c = *s++) != '\0' )
+ {
+ if ( (c == '\n') || (xpos >= text_columns) )
+ {
+ unsigned int bytes = (vlfb_info.width *
+ ((vlfb_info.bits_per_pixel + 7) >> 3));
+ unsigned char *src = lfb + font->height * vlfb_info.bytes_per_line;
+ unsigned char *dst = lfb;
+
+ /* New line: scroll all previous rows up one line. */
+ for ( i = font->height; i < vlfb_info.height; i++ )
+ {
+ memcpy(dst, src, bytes);
+ src += vlfb_info.bytes_per_line;
+ dst += vlfb_info.bytes_per_line;
+ }
+
+ /* Render new line. */
+ vesa_show_line(
+ text_buf,
+ lfb + (text_rows-1) * font->height * vlfb_info.bytes_per_line,
+ xpos);
+
+ xpos = 0;
+ }
+
+ if ( c != '\n' )
+ text_buf[xpos++] = c;
+ }
+
+ lfb_flush();
+}
diff -r c362bcee8047 -r f2649861d594 xen/drivers/video/vga.c
--- a/xen/drivers/video/vga.c Sun Aug 12 16:09:13 2007 +0100
+++ b/xen/drivers/video/vga.c Mon Aug 13 10:09:06 2007 +0100
@@ -10,22 +10,20 @@
#include <xen/lib.h>
#include <xen/mm.h>
#include <xen/errno.h>
-#include <xen/event.h>
-#include <xen/spinlock.h>
#include <xen/console.h>
#include <xen/vga.h>
#include <asm/io.h>
-#include "font.h"

/* Filled in by arch boot code. */
struct xen_vga_console_info vga_console_info;

-static int vgacon_enabled = 0;
-static int vgacon_keep = 0;
-/*static const struct font_desc *font;*/
+static int vgacon_keep;
+static unsigned int xpos, ypos;
+static unsigned char *video;

-static int xpos, ypos;
-static unsigned char *video;
+static void vga_text_puts(const char *s);
+static void vga_noop_puts(const char *s) {}
+void (*vga_puts)(const char *) = vga_noop_puts;

/*
* 'vga=<mode-specifier>[,keep]' where <mode-specifier> is one of:
@@ -55,10 +53,16 @@ string_param("vga", opt_vga);
string_param("vga", opt_vga);

/* VGA text-mode definitions. */
-#define COLUMNS vga_console_info.u.text_mode_3.columns
-#define LINES vga_console_info.u.text_mode_3.rows
+static unsigned int columns, lines;
#define ATTRIBUTE 7
-#define VIDEO_SIZE (COLUMNS * LINES * 2)
+
+#ifdef CONFIG_X86_64
+void vesa_early_init(void);
+void vesa_endboot(void);
+#else
+#define vesa_early_init() ((void)0)
+#define vesa_endboot() ((void)0)
+#endif

void __init vga_init(void)
{
@@ -76,77 +80,61 @@ void __init vga_init(void)
switch ( vga_console_info.video_type )
{
case XEN_VGATYPE_TEXT_MODE_3:
- if ( memory_is_conventional_ram(0xB8000) )
+ if ( memory_is_conventional_ram(0xB8000) ||
+ ((video = ioremap(0xB8000, 0x8000)) == NULL) )
return;
- video = ioremap(0xB8000, 0x8000);
- if ( video == NULL )
- return;
- /* Disable cursor. */
- outw(0x200a, 0x3d4);
- memset(video, 0, VIDEO_SIZE);
+ outw(0x200a, 0x3d4); /* disable cursor */
+ columns = vga_console_info.u.text_mode_3.columns;
+ lines = vga_console_info.u.text_mode_3.rows;
+ memset(video, 0, columns * lines * 2);
+ vga_puts = vga_text_puts;
break;
case XEN_VGATYPE_VESA_LFB:
-#if 0
- /* XXX Implement me! */
- video = ioremap(vga_console_info.u.vesa_lfb.lfb_base,
- vga_console_info.u.vesa_lfb.lfb_size);
- if ( video == NULL )
- return;
- memset(video, 0, vga_console_info.u.vesa_lfb.lfb_size);
+ vesa_early_init();
break;
-#else
- return;
-#endif
default:
memset(&vga_console_info, 0, sizeof(vga_console_info));
- return;
+ break;
}
-
- vgacon_enabled = 1;
}

void __init vga_endboot(void)
{
- if ( !vgacon_enabled )
+ if ( vga_puts == vga_noop_puts )
return;

printk("Xen is %s VGA console.\n",
vgacon_keep ? "keeping" : "relinquishing");

- vgacon_enabled = vgacon_keep;
+ vesa_endboot();
+
+ if ( !vgacon_keep )
+ vga_puts = vga_noop_puts;
}

+static void vga_text_puts(const char *s)
+{
+ char c;

-static void put_newline(void)
-{
- xpos = 0;
- ypos++;
+ while ( (c = *s++) != '\0' )
+ {
+ if ( (c == '\n') || (xpos >= columns) )
+ {
+ if ( ++ypos >= lines )
+ {
+ ypos = lines - 1;
+ memmove(video, video + 2 * columns, ypos * 2 * columns);
+ memset(video + ypos * 2 * columns, 0, 2 * xpos);
+ }
+ xpos = 0;
+ }

- if ( ypos >= LINES )
- {
- ypos = LINES-1;
- memmove((char*)video,
- (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
- memset((char*)video + (LINES-1)*2*COLUMNS, 0, 2*COLUMNS);
- }
-}
-
-void vga_putchar(int c)
-{
- if ( !vgacon_enabled )
- return;
-
- if ( c == '\n' )
- {
- put_newline();
- }
- else
- {
- if ( xpos >= COLUMNS )
- put_newline();
- video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF;
- video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
- ++xpos;
+ if ( c != '\n' )
+ {
+ video[(xpos + ypos * columns) * 2] = c;
+ video[(xpos + ypos * columns) * 2 + 1] = ATTRIBUTE;
+ xpos++;
+ }
}
}

diff -r c362bcee8047 -r f2649861d594 xen/include/xen/vga.h
--- a/xen/include/xen/vga.h Sun Aug 12 16:09:13 2007 +0100
+++ b/xen/include/xen/vga.h Mon Aug 13 10:09:06 2007 +0100
@@ -15,11 +15,11 @@ extern struct xen_vga_console_info vga_c
extern struct xen_vga_console_info vga_console_info;
void vga_init(void);
void vga_endboot(void);
-void vga_putchar(int c);
+extern void (*vga_puts)(const char *);
#else
-#define vga_init() ((void)0)
-#define vga_endboot() ((void)0)
-#define vga_putchar(c) ((void)0)
+#define vga_init() ((void)0)
+#define vga_endboot() ((void)0)
+#define vga_puts(s) ((void)0)
#endif

#endif /* _XEN_VGA_H */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog