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

[Xen-devel] [PATCH] x86-64: enable hypervsior output on VESA frame buffer



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

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>

Index: 2007-08-08/xen/arch/x86/setup.c
===================================================================
--- 2007-08-08.orig/xen/arch/x86/setup.c        2007-08-06 15:08:41.000000000 
+0200
+++ 2007-08-08/xen/arch/x86/setup.c     2007-08-08 11:57:50.000000000 +0200
@@ -106,6 +106,8 @@ extern void init_IRQ(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];
 
@@ -882,6 +884,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", 
@@ -947,6 +950,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;
Index: 2007-08-08/xen/arch/x86/string.c
===================================================================
--- 2007-08-08.orig/xen/arch/x86/string.c       2005-11-17 15:51:04.000000000 
+0100
+++ 2007-08-08/xen/arch/x86/string.c    2007-08-08 11:57:50.000000000 +0200
@@ -11,10 +11,18 @@
 #undef memcpy
 void *memcpy(void *dest, const void *src, size_t n)
 {
-    int d0, d1, d2;
+    long d0, d1, d2;
 
     __asm__ __volatile__ (
-        "   rep ; movsl      ; "
+#ifdef __i386__
+        "   rep movsl        ; "
+#else
+        "   rep movsq        ; "
+        "   testb $4,%b4     ; "
+        "   je 0f            ; "
+        "   movsl            ; "
+        "0:                  ; "
+#endif
         "   testb $2,%b4     ; "
         "   je 1f            ; "
         "   movsw            ; "
@@ -23,7 +31,7 @@ void *memcpy(void *dest, const void *src
         "   movsb            ; "
         "2:                    "
         : "=&c" (d0), "=&D" (d1), "=&S" (d2)
-        : "0" (n/4), "q" (n), "1" (dest), "2" (src)
+        : "0" (n/sizeof(long)), "q" (n), "1" (dest), "2" (src)
         : "memory");
 
     return dest;
@@ -32,10 +40,10 @@ void *memcpy(void *dest, const void *src
 #undef memset
 void *memset(void *s, int c, size_t n)
 {
-    int d0, d1;
+    long d0, d1;
 
     __asm__ __volatile__ (
-        "rep ; stosb"
+        "rep stosb"
         : "=&c" (d0), "=&D" (d1)
         : "a" (c), "1" (s), "0" (n)
         : "memory");
@@ -46,14 +54,14 @@ void *memset(void *s, int c, size_t n)
 #undef memmove
 void *memmove(void *dest, const void *src, size_t n)
 {
-    int d0, d1, d2;
+    long d0, d1, d2;
  
     if ( dest < src )
         return memcpy(dest, src, n);
 
     __asm__ __volatile__ (
         "   std         ; "
-        "   rep ; movsb ; "
+        "   rep movsb   ; "
         "   cld           "
         : "=&c" (d0), "=&S" (d1), "=&D" (d2)
         : "0" (n), "1" (n-1+(const char *)src), "2" (n-1+(char *)dest)
Index: 2007-08-08/xen/drivers/video/Makefile
===================================================================
--- 2007-08-08.orig/xen/drivers/video/Makefile  2006-08-16 08:58:13.000000000 
+0200
+++ 2007-08-08/xen/drivers/video/Makefile       2007-08-08 11:57:50.000000000 
+0200
@@ -1,4 +1,9 @@
-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
+vga.o: vesa.h
+vesa.o: font.h vesa.h
Index: 2007-08-08/xen/drivers/video/vesa.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ 2007-08-08/xen/drivers/video/vesa.c 2007-08-08 11:57:50.000000000 +0200
@@ -0,0 +1,304 @@
+/******************************************************************************
+ * 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 <asm/mtrr.h>
+#include "font.h"
+#include "vesa.h"
+
+#define vesa_lfb_info vga_console_info.u.vesa_lfb
+
+static unsigned char *lfb, *lbuf;
+static const struct font_desc *font;
+static bool_t vga_compat, redraw = 1;
+
+static unsigned int vram_total;
+integer_param("vesa-ram", vram_total);
+
+static unsigned int vram_remap;
+integer_param("vesa-map", vram_remap);
+
+static int vesa_mtrr;
+integer_param("vesa-mtrr", vesa_mtrr);
+
+static char __initdata opt_font[30] = "";
+string_param("font", opt_font);
+
+int __init vesa_early_init(void)
+{
+    int type;
+
+    /* XXX vga_compat = !(boot_video_info.capabilities & 2); */
+
+    if ( vesa_lfb_info.bits_per_pixel < 8 || vesa_lfb_info.bits_per_pixel > 32 
)
+        return -ENOSYS;
+
+    type = 0;
+    if ( opt_font )
+    {
+        const char *ptr;
+
+        if ( simple_strtoul(opt_font, &ptr, 10) == 8 &&
+             *ptr == 'x' )
+            type = simple_strtoul(ptr, &ptr, 10);
+        if ( *ptr )
+            type = 0;
+    }
+    switch ( type )
+    {
+    case 0:
+        switch ( vesa_lfb_info.height )
+        {
+        case 1 ... 600:
+            font = &font_vga_8x8;
+            break;
+        case 601 ... 768:
+            font = &font_vga_8x14;
+            break;
+        default:
+            font = &font_vga_8x16;
+            break;
+        }
+        break;
+    case 1 ... 8:
+        font = &font_vga_8x8;
+        break;
+    case 9 ... 14:
+        font = &font_vga_8x14;
+        break;
+    default:
+        font = &font_vga_8x16;
+        break;
+    }
+
+    return vesa_lfb_info.width / font->width;
+}
+
+void __init vesa_init(void)
+{
+    unsigned int size_vmode, size_remap, size_total;
+
+    if ( !font ||
+         vga_set_lines(vesa_lfb_info.height / font->height) < 0 )
+        return;
+
+    lbuf = xmalloc_bytes(vesa_lfb_info.bytes_per_line);
+    if ( !lbuf )
+        return;
+
+
+    /*   size_vmode -- that is the amount of memory needed for the
+     *                 used video mode, i.e. the minimum amount of
+     *                 memory we need. */
+    size_vmode = vesa_lfb_info.height * vesa_lfb_info.bytes_per_line;
+
+    /*   size_total -- all video memory we have. Used for mtrr
+     *                 entries. */
+    size_total = vesa_lfb_info.lfb_size << 16;
+    if ( vram_total )
+        size_total = vram_total << 20;
+    if ( size_total < size_vmode )
+        size_total = size_vmode;
+
+    /*   size_remap -- the amount of video memory we are going to
+     *                 use for vesafb.  With modern cards it is no
+     *                 option to simply use size_total as that
+     *                 wastes plenty of kernel address space. */
+    if ( vram_remap )
+        size_remap = vram_remap << 20;
+    else
+        size_remap = (size_vmode + (1 << L2_PAGETABLE_SHIFT) - 1) &
+                     ~((1 << L2_PAGETABLE_SHIFT) - 1);
+    if ( size_remap < size_vmode )
+        size_remap = size_vmode;
+    if ( size_remap > size_total )
+        size_remap = size_total;
+
+    if ( map_pages_to_xen(IOREMAP_VIRT_START,
+                          vesa_lfb_info.lfb_base >> PAGE_SHIFT,
+                          size_remap >> PAGE_SHIFT,
+                          PAGE_HYPERVISOR_NOCACHE) )
+        return;
+
+    lfb = memset((void *)IOREMAP_VIRT_START, 0x33, size_remap);
+
+    printk(KERN_INFO "vesafb: framebuffer at 0x%x, mapped to 0x%p, "
+           "using %uk, total %uk\n",
+           vesa_lfb_info.lfb_base, lfb,
+           size_remap >> 10, size_total >> 10);
+    printk(KERN_INFO "vesafb: mode is %dx%dx%u, linelength=%d, font %ux%u\n",
+           vesa_lfb_info.width, vesa_lfb_info.height,
+           vesa_lfb_info.bits_per_pixel, vesa_lfb_info.bytes_per_line,
+           font->width, font->height);
+    printk(KERN_INFO "vesafb: %scolor: "
+           "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+           vesa_lfb_info.bits_per_pixel > 8 ? "True" :
+                                              vga_compat ? "Pseudo" :
+                                                           "Static Pseudo",
+           vesa_lfb_info.rsvd_size, vesa_lfb_info.red_size,
+           vesa_lfb_info.green_size, vesa_lfb_info.blue_size,
+           vesa_lfb_info.rsvd_pos, vesa_lfb_info.red_pos,
+           vesa_lfb_info.green_pos, vesa_lfb_info.blue_pos);
+}
+
+void __init vesa_mtrr_init(void)
+{
+    int type;
+
+    if ( !lfb )
+        return;
+
+    switch ( vesa_mtrr )
+    {
+    case 1:
+        type = MTRR_TYPE_UNCACHABLE;
+        break;
+    case 2:
+        type = MTRR_TYPE_WRBACK;
+        break;
+    case 3:
+        type = MTRR_TYPE_WRCOMB;
+        break;
+    case 4:
+        type = MTRR_TYPE_WRTHROUGH;
+        break;
+    default:
+        return;
+    }
+
+    if ( type )
+    {
+        unsigned int size_vmode, size_total;
+        int rc;
+
+        /*   size_vmode -- that is the amount of memory needed for the
+         *                 used video mode, i.e. the minimum amount of
+         *                 memory we need. */
+        size_vmode = vesa_lfb_info.height * vesa_lfb_info.bytes_per_line;
+
+        /*   size_total -- all video memory we have. Used for mtrr
+         *                 entries. */
+        size_total = vesa_lfb_info.lfb_size << 16;
+        if ( vram_total )
+            size_total = vram_total << 20;
+        if ( size_total < size_vmode )
+            size_total = size_vmode;
+
+        /* Find the largest power-of-two */
+        while ( size_total & (size_total - 1) )
+            size_total &= size_total - 1;
+
+        /* Try and find a power of two to add */
+        do {
+            rc = mtrr_add(vesa_lfb_info.lfb_base,
+                          size_total, type, 1);
+            size_total >>= 1;
+        } while ( size_total >= PAGE_SIZE && rc == -EINVAL );
+    }
+}
+
+void __init vesa_endboot(void)
+{
+     redraw = 0;
+}
+
+/* Note that 'video' points to character/attribute pairs. */
+static void vesa_show_line(const unsigned char *video, unsigned char *pfb,
+                           unsigned int x, unsigned int y)
+{
+    const unsigned char *line;
+    unsigned int i, bytes = (vesa_lfb_info.bits_per_pixel + 7) >> 3;
+    unsigned int pixel = ((0xaaaaaaaa >> (32 - vesa_lfb_info.  red_size)) << 
vesa_lfb_info.  red_pos)
+                       | ((0xaaaaaaaa >> (32 - vesa_lfb_info.green_size)) << 
vesa_lfb_info.green_pos)
+                       | ((0xaaaaaaaa >> (32 - vesa_lfb_info. blue_size)) << 
vesa_lfb_info. blue_pos);
+
+    line = video + y * (vesa_lfb_info.width / font->width) * 2;
+    for ( i = 0; i < font->height; ++i )
+    {
+        unsigned char *ptr = lbuf;
+        unsigned int j;
+
+        for ( j = 0; j < x; ++j )
+        {
+            const unsigned char *bits = font->data;
+            unsigned int b;
+
+            bits += (line[j * 2] * font->height + i) * ((font->width + 7) >> 
3);
+            for ( b = font->width; b--; ptr += bytes )
+            {
+
+                if ( !test_bit(b, bits) )
+                {
+                    if ( bytes > 1 )
+                    {
+                       memset(ptr, 0, bytes);
+                       continue;
+                    }
+                    pixel = line[j * 2 + 1] >> 4;
+                }
+                else if ( bytes == 1 )
+                    pixel = line[j * 2 + 1] & 0xf;
+                memcpy(ptr, &pixel, bytes);
+            }
+        }
+        memset(ptr, 0, (vesa_lfb_info.width - j * font->width) * bytes);
+        memcpy(pfb, lbuf, vesa_lfb_info.width * bytes);
+        pfb += vesa_lfb_info.bytes_per_line;
+    }
+}
+
+void vesa_show(const unsigned char *video, unsigned int x, unsigned int y)
+{
+    static unsigned int last_y;
+    unsigned char *pfb = lfb;
+
+    if ( !lfb )
+        return;
+
+    if ( y == last_y && y + 1 == vesa_lfb_info.height / font->height )
+    {
+        unsigned int i;
+
+        /*
+         * Make room for a new line. Prefer redraw for performance reasons,
+         * but do not disturb what the guest may have drawn.
+         */
+        if ( redraw )
+        {
+            for ( i = 0; i < y; ++i )
+            {
+                vesa_show_line(video, pfb, vesa_lfb_info.width / font->width, 
i);
+                pfb += vesa_lfb_info.bytes_per_line * font->height;
+            }
+        }
+        else
+        {
+            unsigned int bytes = vesa_lfb_info.width *
+                                 ((vesa_lfb_info.bits_per_pixel + 7) >> 3);
+
+            for ( i = font->height; i < vesa_lfb_info.height; ++i )
+            {
+                memcpy(pfb, lfb + vesa_lfb_info.bytes_per_line * i, bytes);
+                pfb += vesa_lfb_info.bytes_per_line;
+            }
+        }
+    }
+    else
+        pfb += vesa_lfb_info.bytes_per_line * y * font->height;
+    last_y = y;
+
+    vesa_show_line(video, pfb, x, y);
+
+    if ( vesa_mtrr == 3 )
+        __asm__ __volatile__ ("sfence" : : : "memory");
+}
Index: 2007-08-08/xen/drivers/video/vesa.h
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ 2007-08-08/xen/drivers/video/vesa.h 2007-08-08 11:57:50.000000000 +0200
@@ -0,0 +1,30 @@
+#ifndef __X86_VESA_H__
+#define __X86_VESA_H__
+
+int vga_set_lines(unsigned int lines);
+
+#ifdef CONFIG_X86_64
+
+int vesa_early_init(void);
+void vesa_endboot(void);
+void vesa_show(const unsigned char *line, unsigned int x, unsigned int y);
+
+#else
+
+static inline int vesa_early_init(void)
+{
+       return -ENOSYS;
+}
+
+static inline void vesa_endboot(void)
+{
+}
+
+static inline void vesa_show(const unsigned char *line,
+                             unsigned int x, unsigned int y)
+{
+}
+
+#endif
+
+#endif /* __X86_VESA_H__ */
Index: 2007-08-08/xen/drivers/video/vga.c
===================================================================
--- 2007-08-08.orig/xen/drivers/video/vga.c     2007-06-20 08:32:49.000000000 
+0200
+++ 2007-08-08/xen/drivers/video/vga.c  2007-08-08 12:02:59.000000000 +0200
@@ -10,21 +10,18 @@
 #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"
+#include "vesa.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 xpos, ypos;
+static unsigned int xpos, ypos;
 static unsigned char *video;
 
 /*
@@ -55,14 +52,14 @@ static char opt_vga[30] = "";
 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)
 
 void __init vga_init(void)
 {
     char *p;
+    int rc;
 
     /* Look for 'keep' in comma-separated options. */
     for ( p = opt_vga; p != NULL; p = strchr(p, ',') )
@@ -83,20 +80,16 @@ void __init vga_init(void)
             return;
         /* Disable cursor. */
         outw(0x200a, 0x3d4);
+        COLUMNS = vga_console_info.u.text_mode_3.columns;
+        LINES = vga_console_info.u.text_mode_3.rows;
         memset(video, 0, VIDEO_SIZE);
         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 )
+        rc = vesa_early_init();
+        if ( rc <= 0 )
             return;
-        memset(video, 0, vga_console_info.u.vesa_lfb.lfb_size);
+        COLUMNS = rc;
         break;
-#else
-        return;
-#endif
     default:
         memset(&vga_console_info, 0, sizeof(vga_console_info));
         return;
@@ -107,11 +100,12 @@ void __init vga_init(void)
 
 void __init vga_endboot(void)
 {
-    if ( !vgacon_enabled )
+    if ( !vgacon_enabled || !video )
         return;
 
     printk("Xen is %s VGA console.\n",
            vgacon_keep ? "keeping" : "relinquishing");
+    vesa_endboot();
 
     vgacon_enabled = vgacon_keep;
 }
@@ -119,20 +113,22 @@ void __init vga_endboot(void)
 
 static void put_newline(void)
 {
-    xpos = 0;
-    ypos++;
+    vesa_show(video, xpos, ypos);
 
-    if ( ypos >= LINES )
+    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);
+        ypos = LINES - 1;
+        memmove(video, video + 2 * COLUMNS, ypos * 2 * COLUMNS);
+        memset(video + ypos * 2 * COLUMNS, 0, 2 * xpos);
     }
+    xpos = 0;
 }
 
 void vga_putchar(int c)
 {
+    if ( !video )
+        return;
+
     if ( !vgacon_enabled )
         return;
 
@@ -150,6 +146,18 @@ void vga_putchar(int c)
     }
 }
 
+int __init vga_set_lines(unsigned int lines)
+{
+    /* Must be done here - xmalloc() cannot be used in vga_init(). */
+    BUG_ON(LINES);
+    LINES = lines;
+    video = xmalloc_bytes(VIDEO_SIZE);
+    if ( !video )
+        return -ENOMEM;
+    memset(video, 0, VIDEO_SIZE);
+    return 0;
+}
+
 int __init fill_console_start_info(struct dom0_vga_console_info *ci)
 {
     memcpy(ci, &vga_console_info, sizeof(*ci));



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


 


Rackspace

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