diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/Kconfig | 6 | ||||
-rw-r--r-- | src/biostables.c | 22 | ||||
-rw-r--r-- | src/mtrr.c | 3 | ||||
-rw-r--r-- | src/pciinit.c | 5 | ||||
-rw-r--r-- | src/post.c | 10 | ||||
-rw-r--r-- | src/shadow.c | 5 | ||||
-rw-r--r-- | src/util.h | 1 | ||||
-rw-r--r-- | src/xen.c | 149 | ||||
-rw-r--r-- | src/xen.h | 135 |
10 files changed, 332 insertions, 6 deletions
@@ -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); +} @@ -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"); @@ -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"); @@ -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 |