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>
This commit is contained in:
kfraser@localhost.localdomain committed 2007-08-13 10:09:06 +01:00
1 parent 9119ea5153
commit 6d9199bd0f
6 files changed
+377 -76

No files matched your search

+6
View File
@@ -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];
@@ -901,6 +903,7 @@ void __init __start_xen(unsigned long mbi_p)
#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 mbi_p)
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;
+4 -8
View File
@@ -331,13 +331,11 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
kbuf[kcount] = '\0';
sercon_puts(kbuf);
vga_puts(kbuf);
for ( kptr = kbuf; *kptr != '\0'; kptr++ )
{
vga_putchar(*kptr);
if ( opt_console_to_ring )
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);
}
+8 -4
View File
@@ -1,4 +1,8 @@
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
+307
View File
@@ -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();
}
+48 -60
View File
@@ -10,23 +10,21 @@
#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 xpos, ypos;
static int vgacon_keep;
static unsigned 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 @@ 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)
#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 put_newline(void)
static void vga_text_puts(const char *s)
{
xpos = 0;
ypos++;
char c;
if ( ypos >= LINES )
while ( (c = *s++) != '\0' )
{
ypos = LINES-1;
memmove((char*)video,
(char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
memset((char*)video + (LINES-1)*2*COLUMNS, 0, 2*COLUMNS);
}
}
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;
}
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++;
}
}
}
+4 -4
View File
@@ -15,11 +15,11 @@
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 */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.