[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |