1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// Xen HVM support
//
// Copyright (C) 2011 Citrix Systems.
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "config.h" // CONFIG_XEN
#include "e820map.h" // e820_add
#include "hw/serialio.h" // DebugOutputPort
#include "malloc.h" // memalign_high
#include "memmap.h" // PAGE_SIZE
#include "output.h" // dprintf
#include "paravirt.h" // PlatformRunningOn
#include "string.h" // memcpy
#include "util.h" // copy_acpi_rsdp
#include "x86.h" // cpuid
#include "xen.h" // xen_extraversion_t
#define INFO_PHYSICAL_ADDRESS 0x00001000
u32 xen_cpuid_base = 0;
unsigned long xen_hypercall_page = 0;
struct xen_seabios_info {
char signature[14]; /* XenHVMSeaBIOS\0 */
u8 length; /* Length of this struct */
u8 checksum; /* Set such that the sum over bytes 0..length == 0 */
/*
* Physical address of an array of tables_nr elements.
*
* Each element is a 32 bit value contianing the physical address
* of a BIOS table.
*/
u32 tables;
u32 tables_nr;
/*
* Physical address of the e820 table, contains e820_nr entries.
*/
u32 e820;
u32 e820_nr;
} PACKED;
static struct xen_seabios_info *validate_info(void)
{
struct xen_seabios_info *t = (void *)INFO_PHYSICAL_ADDRESS;
if ( memcmp(t->signature, "XenHVMSeaBIOS", 14) ) {
dprintf(1, "Bad Xen info signature\n");
return NULL;
}
if ( t->length < sizeof(struct xen_seabios_info) ) {
dprintf(1, "Bad Xen info length\n");
return NULL;
}
if (checksum(t, t->length) != 0) {
dprintf(1, "Bad Xen info checksum\n");
return NULL;
}
return t;
}
void xen_preinit(void)
{
u32 base, eax, ebx, ecx, edx;
char signature[13];
if (!CONFIG_XEN)
return;
for (base = 0x40000000; base < 0x40010000; base += 0x100) {
cpuid(base, &eax, &ebx, &ecx, &edx);
memcpy(signature + 0, &ebx, 4);
memcpy(signature + 4, &ecx, 4);
memcpy(signature + 8, &edx, 4);
signature[12] = 0;
dprintf(9, "Found hypervisor signature \"%s\" at %x\n",
signature, base);
if (strcmp(signature, "XenVMMXenVMM") == 0) {
/* Set debug_io_port first, so the following messages work. */
code_mutable_preinit();
DebugOutputPort = 0xe9;
debug_banner();
dprintf(1, "\nFound Xen hypervisor signature at %x\n", base);
if ((eax - base) < 2)
panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n",
eax, base);
xen_cpuid_base = base;
break;
}
}
if (!xen_cpuid_base) {
dprintf(1, "No Xen hypervisor found.\n");
return;
}
if (validate_info())
PlatformRunningOn = PF_QEMU|PF_XEN;
else
dprintf(1, "Not enabling Xen support due to lack of Xen info\n");
}
static int hypercall_xen_version( int cmd, void *arg)
{
return _hypercall2(int, xen_version, cmd, arg);
}
/* Fill in hypercall transfer pages. */
void xen_hypercall_setup(void)
{
u32 eax, ebx, ecx, edx;
xen_extraversion_t extraversion;
unsigned long i;
if (!runningOnXen())
return;
cpuid(xen_cpuid_base + 2, &eax, &ebx, &ecx, &edx);
xen_hypercall_page = (unsigned long)memalign_high(PAGE_SIZE, eax*PAGE_SIZE);
if (!xen_hypercall_page)
panic("unable to allocate Xen hypercall page\n");
dprintf(1, "Allocated Xen hypercall page at %lx\n", xen_hypercall_page);
for ( i = 0; i < eax; i++ )
wrmsr(ebx, xen_hypercall_page + (i << 12) + i);
/* Print version information. */
cpuid(xen_cpuid_base + 1, &eax, &ebx, &ecx, &edx);
hypercall_xen_version(XENVER_extraversion, extraversion);
dprintf(1, "Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
}
void xen_biostable_setup(void)
{
struct xen_seabios_info *info = validate_info();
void **tables;
int i;
if (!info)
panic("Xen info corrupted\n");
tables = (void*)info->tables;
dprintf(1, "xen: copy BIOS tables...\n");
for (i=0; i<info->tables_nr; i++)
copy_table(tables[i]);
find_acpi_features();
}
void xen_ramsize_preinit(void)
{
int i;
struct xen_seabios_info *info = validate_info();
struct e820entry *e820;
if (!info)
panic("Xen info corrupted\n");
dprintf(1, "xen: copy e820...\n");
e820 = (struct e820entry *)info->e820;
for (i = 0; i < info->e820_nr; i++) {
struct e820entry *e = &e820[i];
e820_add(e->start, e->size, e->type);
}
}
|