mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-06-15 18:05:49 +00:00
f323796502
The x86 BIOS code included some definitions for the E820 table from the Linux system headers, but those could not be found on x86_64 multiarch systems without the compat headers installed. Pull the required definitions into the kvmtool source directory, removing the reference to <asm/e820.h>. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
174 lines
4.2 KiB
C
174 lines
4.2 KiB
C
#include "kvm/kvm.h"
|
|
#include "kvm/boot-protocol.h"
|
|
#include "kvm/e820.h"
|
|
#include "kvm/interrupt.h"
|
|
#include "kvm/util.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "bios/bios-rom.h"
|
|
|
|
struct irq_handler {
|
|
unsigned long address;
|
|
unsigned int irq;
|
|
void *handler;
|
|
size_t size;
|
|
};
|
|
|
|
#define BIOS_IRQ_PA_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name)
|
|
#define BIOS_IRQ_FUNC(name) ((char *)&bios_rom[BIOS_OFFSET__##name])
|
|
#define BIOS_IRQ_SIZE(name) (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name))
|
|
|
|
#define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler) \
|
|
{ \
|
|
.irq = _irq, \
|
|
.address = BIOS_IRQ_PA_ADDR(_handler), \
|
|
.handler = BIOS_IRQ_FUNC(_handler), \
|
|
.size = BIOS_IRQ_SIZE(_handler), \
|
|
}
|
|
|
|
static struct irq_handler bios_irq_handlers[] = {
|
|
DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10),
|
|
DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15),
|
|
};
|
|
|
|
static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler)
|
|
{
|
|
struct real_intr_desc intr_desc;
|
|
void *p;
|
|
|
|
p = guest_flat_to_host(kvm, handler->address);
|
|
memcpy(p, handler->handler, handler->size);
|
|
|
|
intr_desc = (struct real_intr_desc) {
|
|
.segment = REAL_SEGMENT(MB_BIOS_BEGIN),
|
|
.offset = handler->address - MB_BIOS_BEGIN,
|
|
};
|
|
|
|
DIE_IF((handler->address - MB_BIOS_BEGIN) > 0xffffUL);
|
|
|
|
interrupt_table__set(&kvm->arch.interrupt_table, &intr_desc, handler->irq);
|
|
}
|
|
|
|
/**
|
|
* e820_setup - setup some simple E820 memory map
|
|
* @kvm - guest system descriptor
|
|
*/
|
|
static void e820_setup(struct kvm *kvm)
|
|
{
|
|
struct e820map *e820;
|
|
struct e820entry *mem_map;
|
|
unsigned int i = 0;
|
|
|
|
e820 = guest_flat_to_host(kvm, E820_MAP_START);
|
|
mem_map = e820->map;
|
|
|
|
mem_map[i++] = (struct e820entry) {
|
|
.addr = REAL_MODE_IVT_BEGIN,
|
|
.size = EBDA_START - REAL_MODE_IVT_BEGIN,
|
|
.type = E820_RAM,
|
|
};
|
|
mem_map[i++] = (struct e820entry) {
|
|
.addr = EBDA_START,
|
|
.size = VGA_RAM_BEGIN - EBDA_START,
|
|
.type = E820_RESERVED,
|
|
};
|
|
mem_map[i++] = (struct e820entry) {
|
|
.addr = MB_BIOS_BEGIN,
|
|
.size = MB_BIOS_END - MB_BIOS_BEGIN,
|
|
.type = E820_RESERVED,
|
|
};
|
|
if (kvm->ram_size < KVM_32BIT_GAP_START) {
|
|
mem_map[i++] = (struct e820entry) {
|
|
.addr = BZ_KERNEL_START,
|
|
.size = kvm->ram_size - BZ_KERNEL_START,
|
|
.type = E820_RAM,
|
|
};
|
|
} else {
|
|
mem_map[i++] = (struct e820entry) {
|
|
.addr = BZ_KERNEL_START,
|
|
.size = KVM_32BIT_GAP_START - BZ_KERNEL_START,
|
|
.type = E820_RAM,
|
|
};
|
|
mem_map[i++] = (struct e820entry) {
|
|
.addr = KVM_32BIT_MAX_MEM_SIZE,
|
|
.size = kvm->ram_size - KVM_32BIT_MAX_MEM_SIZE,
|
|
.type = E820_RAM,
|
|
};
|
|
}
|
|
|
|
BUG_ON(i > E820_X_MAX);
|
|
|
|
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
|
|
*/
|
|
void setup_bios(struct kvm *kvm)
|
|
{
|
|
unsigned long address = MB_BIOS_BEGIN;
|
|
struct real_intr_desc intr_desc;
|
|
unsigned int i;
|
|
void *p;
|
|
|
|
/*
|
|
* before anything else -- clean some known areas
|
|
* we definitely don't want any trash here
|
|
*/
|
|
p = guest_flat_to_host(kvm, BDA_START);
|
|
memset(p, 0, BDA_END - BDA_START);
|
|
|
|
p = guest_flat_to_host(kvm, EBDA_START);
|
|
memset(p, 0, EBDA_END - EBDA_START);
|
|
|
|
p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
|
|
memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN);
|
|
|
|
p = guest_flat_to_host(kvm, VGA_ROM_BEGIN);
|
|
memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN);
|
|
|
|
/* just copy the bios rom into the place */
|
|
p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
|
|
memcpy(p, bios_rom, bios_rom_size);
|
|
|
|
/* 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 handler which does just iret
|
|
*/
|
|
address = BIOS_IRQ_PA_ADDR(bios_intfake);
|
|
intr_desc = (struct real_intr_desc) {
|
|
.segment = REAL_SEGMENT(MB_BIOS_BEGIN),
|
|
.offset = address - MB_BIOS_BEGIN,
|
|
};
|
|
interrupt_table__setup(&kvm->arch.interrupt_table, &intr_desc);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++)
|
|
setup_irq_handler(kvm, &bios_irq_handlers[i]);
|
|
|
|
/* we almost done */
|
|
p = guest_flat_to_host(kvm, 0);
|
|
interrupt_table__copy(&kvm->arch.interrupt_table, p, REAL_INTR_SIZE);
|
|
}
|