Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / src / fw / xen.c
diff --git a/qemu/roms/seabios/src/fw/xen.c b/qemu/roms/seabios/src/fw/xen.c
new file mode 100644 (file)
index 0000000..dd8e8af
--- /dev/null
@@ -0,0 +1,147 @@
+// 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 "hw/serialio.h" // DebugOutputPort
+#include "malloc.h" // memalign_high
+#include "memmap.h" // add_e820
+#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"
+
+#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 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_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. */
+            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;
+    }
+    PlatformRunningOn = PF_QEMU|PF_XEN;
+}
+
+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 = (void *)INFO_PHYSICAL_ADDRESS;
+    void **tables = (void*)info->tables;
+    int i;
+
+    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 = (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];
+        add_e820(e->start, e->size, e->type);
+    }
+}