Add support for use as Xen HVM BIOS.
authorIan Campbell <ian.campbell@citrix.com>
Wed, 1 Jun 2011 10:00:29 +0000 (11:00 +0100)
committerKevin O'Connor <kevin@koconnor.net>
Mon, 13 Jun 2011 11:57:03 +0000 (07:57 -0400)
SeaBIOS is called by Xen's hvmloader which does the basic platform
setup (PCI, APIC, etc) and provides the various BIOS tables. Therefore
avoid re-doing that setup and copy out the tables as necessary. A
simple data structure is defined to pass the addresses of these
tables.

This patch also establishes the basic infrastructure to make
hypercalls, although it currently only uses it to query the hypervisor
version.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Makefile
src/Kconfig
src/biostables.c
src/mtrr.c
src/pciinit.c
src/post.c
src/shadow.c
src/util.h
src/xen.c [new file with mode: 0644]
src/xen.h [new file with mode: 0644]

index 07ba2d0c60adf79c19121d36d86760aa2eb2bf8d..05bcee3029ff591eff0db5ea12988d0ae3999872 100644 (file)
--- 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 \
index 15485ac257170d65b71381dcd4dd0ecbbd45dadb..b9875c8471d6a9c38d117b93264aad0dd430e0d0 100644 (file)
@@ -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
index 21b85734bb3c5a1d9b85c3da3481802e5da9545f..761b2608f4d20f28f743738dfe84ce31aa553519 100644 (file)
@@ -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);
+}
index 0502c1835403f56461bd2e39d1e6f8658fd73015..0548043376986bf861b4158ca8808b8e1a0a251f 100644 (file)
@@ -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;
index ee2e72dd4c54467887ece0823b667e8b4e09eeab..0bd9b72467f970ece9abf4d859618f61cdfc1f26 100644 (file)
@@ -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");
index 7d2b5f28290e2219b259b41e986adbb155058125..70d98a67224b71d091d7ec69e74f9d4b47c0689a 100644 (file)
@@ -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;
index ed530e0296548d768111db923601d0f53f27e96d..cb39ddf6114c50a3da92a0ad049924f2ea1e7ad3 100644 (file)
@@ -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");
index cb544321be67377dc46dee80e594b4571017e3e3..00433e28ded850a19328913bd81780299d80f570 100644 (file)
@@ -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 (file)
index 0000000..4072793
--- /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 (file)
index 0000000..0ed1e9f
--- /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