[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86-64: enable hypervisor output on VESA frame buffer



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# 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@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 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@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.