mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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:
1 parent
9119ea5153
commit
6d9199bd0f
6 files changed
+377
-76
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||