From 4551caa40d39f850be0b9c1c2be17df921df99b2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 4 Nov 2011 10:48:06 +0400 Subject: [PATCH] kvm tools: Fix VESA BIOS mode info Some VGA data such as VESA info needs a proper tuning for addresses passed on kernel requests. We returned linear addresses there while spec points out that far pointers are needed. This fixes a long-standing issue that caused Linux kernel to never exit the mode scanning loop in arch/x86/boot/video-vesa.c::vesa_probe() because returned mode info table segment/offset pair was bogus. The issue triggered on some machines when CONFIG_FB_VESA was disabled. Also use already VESA structures defined in header now that we no longer use the struct to store VESA BIOS data. Reported-by: Pekka Enberg CC: Sasha Levin CC: Ingo Molnar CC: Asias He Signed-off-by: Cyrill Gorcunov [ penberg@kernel.org: minor cleanups to setup_vga_rom() ] Signed-off-by: Pekka Enberg --- tools/kvm/Makefile | 1 + tools/kvm/bios.c | 17 +++++++++ tools/kvm/bios/int10.c | 74 ++++++++---------------------------- tools/kvm/include/kvm/bios.h | 4 ++ 4 files changed, 37 insertions(+), 59 deletions(-) diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index d4598caa6932..20389f9c7b24 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -225,6 +225,7 @@ BIOS_CFLAGS += -march=i386 BIOS_CFLAGS += -mregparm=3 BIOS_CFLAGS += -fno-stack-protector +BIOS_CFLAGS += -I../../arch/$(ARCH) bios.o: bios/bios.bin bios/bios-rom.h diff --git a/tools/kvm/bios.c b/tools/kvm/bios.c index 6aefd1bdc19b..47b1f5445d1d 100644 --- a/tools/kvm/bios.c +++ b/tools/kvm/bios.c @@ -103,6 +103,20 @@ static void e820_setup(struct kvm *kvm) e820->nr_map = i; } +static void setup_vga_rom(struct kvm *kvm) +{ + u16 *mode; + void *p; + + p = guest_flat_to_host(kvm, VGA_ROM_OEM_STRING); + memset(p, 0, VGA_ROM_OEM_STRING_SIZE); + strncpy(p, "KVM VESA", VGA_ROM_OEM_STRING_SIZE); + + mode = guest_flat_to_host(kvm, VGA_ROM_MODES); + mode[0] = 0x0112; + mode[1] = 0xffff; +} + /** * setup_bios - inject BIOS into guest memory * @kvm - guest system descriptor @@ -137,6 +151,9 @@ void setup_bios(struct kvm *kvm) /* E820 memory map must be present */ e820_setup(kvm); + /* VESA needs own tricks */ + setup_vga_rom(kvm); + /* * Setup a *fake* real mode vector table, it has only * one real hadler which does just iret diff --git a/tools/kvm/bios/int10.c b/tools/kvm/bios/int10.c index 32f7c923d459..7cc0b3f2162e 100644 --- a/tools/kvm/bios/int10.c +++ b/tools/kvm/bios/int10.c @@ -4,59 +4,17 @@ #include "bios/memcpy.h" -#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24)) - -/* VESA General Information table */ -struct vesa_general_info { - u32 signature; /* 0 Magic number = "VESA" */ - u16 version; /* 4 */ - void *vendor_string; /* 6 */ - u32 capabilities; /* 10 */ - void *video_mode_ptr; /* 14 */ - u16 total_memory; /* 18 */ - u16 modes[2]; /* 20 */ - char oem_string[11]; /* 24 */ - - u8 reserved[223]; /* 35 */ -} __attribute__ ((packed)); - -struct vminfo { - u16 mode_attr; /* 0 */ - u8 win_attr[2]; /* 2 */ - u16 win_grain; /* 4 */ - u16 win_size; /* 6 */ - u16 win_seg[2]; /* 8 */ - u32 win_scheme; /* 12 */ - u16 logical_scan; /* 16 */ - - u16 h_res; /* 18 */ - u16 v_res; /* 20 */ - u8 char_width; /* 22 */ - u8 char_height; /* 23 */ - u8 memory_planes; /* 24 */ - u8 bpp; /* 25 */ - u8 banks; /* 26 */ - u8 memory_layout; /* 27 */ - u8 bank_size; /* 28 */ - u8 image_planes; /* 29 */ - u8 page_function; /* 30 */ - - u8 rmask; /* 31 */ - u8 rpos; /* 32 */ - u8 gmask; /* 33 */ - u8 gpos; /* 34 */ - u8 bmask; /* 35 */ - u8 bpos; /* 36 */ - u8 resv_mask; /* 37 */ - u8 resv_pos; /* 38 */ - u8 dcm_info; /* 39 */ - - u32 lfb_ptr; /* 40 Linear frame buffer address */ - u32 offscreen_ptr; /* 44 Offscreen memory address */ - u16 offscreen_size; /* 48 */ - - u8 reserved[206]; /* 50 */ -}; +#include + +static far_ptr gen_far_ptr(unsigned int pa) +{ + far_ptr ptr; + + ptr.seg = (pa >> 4); + ptr.off = pa - (ptr.seg << 4); + + return ptr; +} static inline void outb(unsigned short port, unsigned char val) { @@ -76,9 +34,9 @@ static inline void int10_putchar(struct biosregs *args) static void vbe_get_mode(struct biosregs *args) { - struct vminfo *info = (struct vminfo *) args->edi; + struct vesa_mode_info *info = (struct vesa_mode_info *) args->edi; - *info = (struct vminfo) { + *info = (struct vesa_mode_info) { .mode_attr = 0xd9, /* 11011011 */ .logical_scan = VESA_WIDTH*4, .h_res = VESA_WIDTH, @@ -105,12 +63,10 @@ static void vbe_get_info(struct biosregs *args) info = (struct vesa_general_info) { .signature = VESA_MAGIC, .version = 0x102, - .vendor_string = &infop->oem_string, + .vendor_string = gen_far_ptr(VGA_ROM_BEGIN), .capabilities = 0x10, - .video_mode_ptr = &infop->modes, + .video_mode_ptr = gen_far_ptr(VGA_ROM_MODES), .total_memory = (4 * VESA_WIDTH * VESA_HEIGHT) / 0x10000, - .oem_string = "KVM VESA", - .modes = { 0x0112, 0xffff }, }; memcpy16(args->es, infop, args->ds, &info, sizeof(info)); diff --git a/tools/kvm/include/kvm/bios.h b/tools/kvm/include/kvm/bios.h index 39cc972e9cc3..c12fba731f25 100644 --- a/tools/kvm/include/kvm/bios.h +++ b/tools/kvm/include/kvm/bios.h @@ -33,6 +33,10 @@ #define VGA_RAM_END 0x000bffff #define VGA_ROM_BEGIN 0x000c0000 +#define VGA_ROM_OEM_STRING VGA_ROM_BEGIN +#define VGA_ROM_OEM_STRING_SIZE 16 +#define VGA_ROM_MODES (VGA_ROM_OEM_STRING + VGA_ROM_OEM_STRING_SIZE) +#define VGA_ROM_MODES_SIZE 32 #define VGA_ROM_END 0x000c7fff /* we handle one page only */ -- 2.39.5