mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-09-06 21:51:49 +00:00
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:
committed by
Will Deacon
parent
f41a132b0a
commit
55290abcfc
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user