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 <boot/vesa.h> header now
that we no longer use the struct to store VESA BIOS data.

Reported-by: Pekka Enberg <penberg@kernel.org>
CC: Sasha Levin <levinsasha928@gmail.com>
CC: Ingo Molnar <mingo@elte.hu>
CC: Asias He <asias.hejun@gmail.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
[ penberg@kernel.org: minor cleanups to setup_vga_rom() ]
Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
Cyrill Gorcunov
2015-06-01 16:39:48 +01:00
committed by Will Deacon
parent f41a132b0a
commit 55290abcfc
4 changed files with 34 additions and 56 deletions
+1
View File
@@ -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
+17
View File
@@ -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
+12 -56
View File
@@ -4,59 +4,17 @@
#include "bios/memcpy.h"
#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24))
#include <boot/vesa.h>
/* 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 */
static far_ptr gen_far_ptr(unsigned int pa)
{
far_ptr ptr;
u8 reserved[223]; /* 35 */
} __attribute__ ((packed));
ptr.seg = (pa >> 4);
ptr.off = pa - (ptr.seg << 4);
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 */
};
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));
+4
View File
@@ -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 */