Jan Beulich
2007-Aug-09 12:25 UTC
[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@novell.com> 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@lists.xensource.com http://lists.xensource.com/xen-devel