aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/Kconfig6
-rw-r--r--src/biostables.c22
-rw-r--r--src/mtrr.c3
-rw-r--r--src/pciinit.c5
-rw-r--r--src/post.c10
-rw-r--r--src/shadow.c5
-rw-r--r--src/util.h1
-rw-r--r--src/xen.c149
-rw-r--r--src/xen.h135
10 files changed, 332 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index 07ba2d0c..05bcee30 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ SRC16=$(SRCBOTH) system.c disk.c font.c
SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c dev-i440fx.c \
- pci_region.c biostables.c
+ pci_region.c biostables.c xen.c
SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
diff --git a/src/Kconfig b/src/Kconfig
index 15485ac2..b9875c84 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -10,6 +10,12 @@ menu "General Features"
help
Configure as a coreboot payload.
+ config XEN
+ bool "Build for Xen HVM"
+ default n
+ help
+ Configure to be used by xen hvmloader, for a HVM guest.
+
config THREADS
bool "Parallelize hardware init"
default y
diff --git a/src/biostables.c b/src/biostables.c
index 21b85734..761b2608 100644
--- a/src/biostables.c
+++ b/src/biostables.c
@@ -9,6 +9,7 @@
#include "pci.h" // struct pir_header
#include "acpi.h" // struct rsdp_descriptor
#include "mptable.h" // MPTABLE_SIGNATURE
+#include "smbios.h" // struct smbios_entry_point
void
copy_pir(void *pos)
@@ -81,3 +82,24 @@ copy_acpi_rsdp(void *pos)
memcpy(newpos, pos, length);
RsdpAddr = newpos;
}
+
+void
+copy_smbios(void *pos)
+{
+ struct smbios_entry_point *p = pos;
+ if (memcmp(p->anchor_string, "_SM_", 4))
+ return;
+ if (checksum(pos, 0x10) != 0)
+ return;
+ if (memcmp(p->intermediate_anchor_string, "_DMI_", 5))
+ return;
+ if (checksum(pos+0x10, p->length-0x10) != 0)
+ return;
+ struct smbios_entry_point *newpos = malloc_fseg(sizeof(p->length));
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying SMBIOS entry point from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, p->length);
+}
diff --git a/src/mtrr.c b/src/mtrr.c
index 0502c183..05480433 100644
--- a/src/mtrr.c
+++ b/src/mtrr.c
@@ -6,6 +6,7 @@
#include "util.h" // dprintf
#include "biosvar.h" // GET_EBDA
+#include "xen.h" // usingXen
#define MSR_MTRRcap 0x000000fe
#define MSR_MTRRfix64K_00000 0x00000250
@@ -32,7 +33,7 @@
void mtrr_setup(void)
{
- if (!CONFIG_MTRR_INIT || CONFIG_COREBOOT)
+ if (!CONFIG_MTRR_INIT || CONFIG_COREBOOT || usingXen())
return;
u32 eax, ebx, ecx, edx, cpuid_features;
diff --git a/src/pciinit.c b/src/pciinit.c
index ee2e72dd..0bd9b724 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -11,6 +11,7 @@
#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
#include "pci_regs.h" // PCI_COMMAND
#include "dev-i440fx.h"
+#include "xen.h" // usingXen
#define PCI_ROM_SLOT 6
#define PCI_NUM_REGIONS 7
@@ -396,8 +397,8 @@ pci_bios_init_bus(void)
void
pci_setup(void)
{
- if (CONFIG_COREBOOT)
- // Already done by coreboot.
+ if (CONFIG_COREBOOT || usingXen())
+ // Already done by coreboot or Xen.
return;
dprintf(3, "pci setup\n");
diff --git a/src/post.c b/src/post.c
index 7d2b5f28..70d98a67 100644
--- a/src/post.c
+++ b/src/post.c
@@ -23,6 +23,7 @@
#include "usb.h" // usb_setup
#include "smbios.h" // smbios_init
#include "paravirt.h" // qemu_cfg_port_probe
+#include "xen.h" // xen_probe_hvm_info
#include "ps2port.h" // ps2port_setup
#include "virtio-blk.h" // virtio_blk_setup
@@ -101,6 +102,8 @@ ram_probe(void)
dprintf(3, "Find memory size\n");
if (CONFIG_COREBOOT) {
coreboot_setup();
+ } else if (usingXen()) {
+ xen_setup();
} else {
// On emulators, get memory size from nvram.
u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
@@ -158,6 +161,10 @@ init_bios_tables(void)
coreboot_copy_biostable();
return;
}
+ if (usingXen()) {
+ xen_copy_biostables();
+ return;
+ }
create_pirtable();
@@ -380,6 +387,9 @@ _start(void)
// This is a soft reboot - invoke a hard reboot.
tryReboot();
+ // Check if we are running under Xen.
+ xen_probe();
+
// Allow writes to modify bios area (0xf0000)
make_bios_writable();
HaveRunPost = 1;
diff --git a/src/shadow.c b/src/shadow.c
index ed530e02..cb39ddf6 100644
--- a/src/shadow.c
+++ b/src/shadow.c
@@ -10,6 +10,7 @@
#include "config.h" // CONFIG_*
#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
#include "dev-i440fx.h"
+#include "xen.h" // usingXen
// On the emulators, the bios at 0xf0000 is also at 0xffff0000
#define BIOS_SRC_OFFSET 0xfff00000
@@ -102,7 +103,7 @@ static const struct pci_device_id dram_controller_make_writable_tbl[] = {
void
make_bios_writable(void)
{
- if (CONFIG_COREBOOT)
+ if (CONFIG_COREBOOT || usingXen())
return;
dprintf(3, "enabling shadow ram\n");
@@ -127,7 +128,7 @@ static const struct pci_device_id dram_controller_make_readonly_tbl[] = {
void
make_bios_readonly(void)
{
- if (CONFIG_COREBOOT)
+ if (CONFIG_COREBOOT || usingXen())
return;
dprintf(3, "locking shadow ram\n");
diff --git a/src/util.h b/src/util.h
index cb544321..00433e28 100644
--- a/src/util.h
+++ b/src/util.h
@@ -409,6 +409,7 @@ void coreboot_setup(void);
void copy_pir(void *pos);
void copy_mptable(void *pos);
void copy_acpi_rsdp(void *pos);
+void copy_smbios(void *pos);
// vgahooks.c
extern int VGAbdf;
diff --git a/src/xen.c b/src/xen.c
new file mode 100644
index 00000000..40727930
--- /dev/null
+++ b/src/xen.c
@@ -0,0 +1,149 @@
+// Xen HVM support
+//
+// Copyright (C) 2011 Citrix Systems.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h"
+#include "xen.h"
+
+#include "memmap.h" // add_e820
+#include "types.h" // ASM32FLAT
+#include "util.h" // copy_acpi_rsdp
+
+#define INFO_PHYSICAL_ADDRESS 0x00001000
+
+u32 xen_cpuid_base = 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 void validate_info(struct xen_seabios_info *t)
+{
+ if ( memcmp(t->signature, "XenHVMSeaBIOS", 14) )
+ panic("Bad Xen info signature\n");
+
+ if ( t->length < sizeof(struct xen_seabios_info) )
+ panic("Bad Xen info length\n");
+
+ if (checksum(t, t->length) != 0)
+ panic("Bad Xen info checksum\n");
+}
+
+void xen_probe(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(1, "Found hypervisor signature \"%s\" at %x\n",
+ signature, base);
+ if (strcmp(signature, "XenVMMXenVMM") == 0) {
+ if ((eax - base) < 2)
+ panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n",
+ eax, base);
+ xen_cpuid_base = base;
+ break;
+ }
+ }
+}
+
+static int hypercall_xen_version( int cmd, void *arg)
+{
+ return _hypercall2(int, xen_version, cmd, arg);
+}
+
+/* Fill in hypercall transfer pages. */
+void xen_init_hypercalls(void)
+{
+ u32 eax, ebx, ecx, edx;
+ xen_extraversion_t extraversion;
+ unsigned long i;
+
+ if (!usingXen())
+ 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_copy_biostables(void)
+{
+ struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+ u32 *tables = (u32 *)info->tables;
+ int i;
+
+ dprintf(1, "xen: copy BIOS tables...\n");
+ for (i=0; i<info->tables_nr; i++) {
+ void *table = (void *)tables[i];
+ copy_acpi_rsdp(table);
+ copy_mptable(table);
+ copy_pir(table);
+ copy_smbios(table);
+ }
+}
+
+void xen_setup(void)
+{
+ u64 maxram = 0, maxram_over4G = 0;
+ int i;
+ struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+ struct e820entry *e820 = (struct e820entry *)info->e820;
+ validate_info(info);
+
+ dprintf(1, "xen: copy e820...\n");
+
+ for (i = 0; i < info->e820_nr; i++) {
+ struct e820entry *e = &e820[i];
+ if (e->type == E820_ACPI || e->type == E820_RAM) {
+ u64 end = e->start + e->size;
+ if (end > 0x100000000ull) {
+ end -= 0x100000000ull;
+ if (end > maxram_over4G)
+ maxram_over4G = end;
+ } else if (end > maxram)
+ maxram = end;
+ }
+ add_e820(e->start, e->size, e->type);
+ }
+
+ RamSize = maxram;
+ RamSizeOver4G = maxram_over4G;
+}
diff --git a/src/xen.h b/src/xen.h
new file mode 100644
index 00000000..0ed1e9f2
--- /dev/null
+++ b/src/xen.h
@@ -0,0 +1,135 @@
+#ifndef __XEN_H
+#define __XEN_H
+
+#include "util.h"
+
+extern u32 xen_cpuid_base;
+
+void xen_probe(void);
+void xen_setup(void);
+void xen_init_hypercalls(void);
+void xen_copy_biostables(void);
+
+static inline int usingXen(void) {
+ if (!CONFIG_XEN)
+ return 0;
+ return (xen_cpuid_base != 0);
+}
+
+unsigned long xen_hypercall_page;
+
+#define _hypercall0(type, name) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res) \
+ : "0" (__hentry) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall1(type, name, a1) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1) \
+ : "0" (__hentry), "1" ((long)(a1)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall2(type, name, a1, a2) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall3(type, name, a1, a2, a3) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3, __ign4; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ "5" ((long)(a5)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+/******************************************************************************
+ *
+ * The following interface definitions are taken from Xen and have the
+ * following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* xen.h */
+
+#define __HYPERVISOR_xen_version 17
+
+/* version.h */
+
+/* arg == xen_extraversion_t. */
+#define XENVER_extraversion 1
+typedef char xen_extraversion_t[16];
+#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t))
+
+#endif