>From c2f5909e835903f7678f77b0a1626b9a974ef3aa Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 26 May 2011 16:10:25 +0100 Subject: [PATCH] Add basic support for use as Xen HVM BIOS. SeaBIOS is called by Xen's hvmloader which does the basic platform setup and provides various BIOS tables. Therefore avoid re-doing that setup and copy out the tables as necessary. Establish the basic infrastructure to make hypercalls. XXX TODO put hypercall page at a safe location. XXX TODO consider re-using coreboot table datastructure instead of ad-hoc. Signed-off-by: Ian Campbell --- Makefile | 2 +- src/Kconfig | 6 ++ src/coreboot.c | 4 +- src/mtrr.c | 3 +- src/pciinit.c | 5 +- src/post.c | 11 +++ src/shadow.c | 5 +- src/xen.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/xen.h | 56 ++++++++++++++ 9 files changed, 315 insertions(+), 8 deletions(-) create mode 100644 src/xen.c create mode 100644 src/xen.h diff --git a/Makefile b/Makefile index d17f85a..5a9a7a1 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 + pci_region.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 123db01..c2fe086 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/coreboot.c b/src/coreboot.c index f627531..ac480ad 100644 --- a/src/coreboot.c +++ b/src/coreboot.c @@ -216,7 +216,7 @@ copy_pir(void *pos) PirOffset = (u32)newpos - BUILD_BIOS_ADDR; } -static void +/*static*/ void copy_mptable(void *pos) { struct mptable_floating_s *p = pos; @@ -240,7 +240,7 @@ copy_mptable(void *pos) memcpy((void*)newpos + length, (void*)p->physaddr, mpclength); } -static void +/*static*/ void copy_acpi_rsdp(void *pos) { if (RsdpAddr) diff --git a/src/mtrr.c b/src/mtrr.c index 0502c18..0548043 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 ee2e72d..0bd9b72 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 7d2b5f2..07167c8 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_biostable(); + return; + } create_pirtable(); @@ -329,6 +336,7 @@ post(void) { // Detect ram and setup internal malloc. qemu_cfg_port_probe(); + xen_probe_hvm_info(); ram_probe(); malloc_setup(); @@ -380,6 +388,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 ed530e0..cb39ddf 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/xen.c b/src/xen.c new file mode 100644 index 0000000..0161b65 --- /dev/null +++ b/src/xen.c @@ -0,0 +1,231 @@ +// 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 + +#define INFO_PHYSICAL_ADDRESS 0x00001000 +#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000 /* MADE UP */ + +u32 xen_cpuid_base = 0; + +static void init_hypercalls(void) +{ + u32 eax, ebx, ecx, edx; + unsigned long i; + + /* Fill in hypercall transfer pages. */ + cpuid(xen_cpuid_base + 2, &eax, &ebx, &ecx, &edx); + for ( i = 0; i < eax; i++ ) + wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i); +} + +#define __STR(...) #__VA_ARGS__ +#define STR(...) __STR(__VA_ARGS__) + +/* + * NB. Hypercall address needs to be relative to a linkage symbol for + * some version of ld to relocate the relative calls properly. + */ +//#define hypercall_pa "_start - " STR(HVMLOADER_PHYSICAL_ADDRESS) \ +// " + " STR(HYPERCALL_PHYSICAL_ADDRESS) +#define hypercall_pa STR(HYPERCALL_PHYSICAL_ADDRESS) + +#define _hypercall0(type, name) \ +({ \ + long __res; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res) \ + : \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall1(type, name, a1) \ +({ \ + long __res, __ign1; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1) \ + : "1" ((long)(a1)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall2(type, name, a1, a2) \ +({ \ + long __res, __ign1, __ign2; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ + : "1" ((long)(a1)), "2" ((long)(a2)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall3(type, name, a1, a2, a3) \ +({ \ + long __res, __ign1, __ign2, __ign3; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall4(type, name, a1, a2, a3, a4) \ +({ \ + long __res, __ign1, __ign2, __ign3, __ign4; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3), "=S" (__ign4) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "4" ((long)(a4)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ +({ \ + long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \ + asm volatile ( \ + "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ + : "1" ((long)(a1)), "2" ((long)(a2)), \ + "3" ((long)(a3)), "4" ((long)(a4)), \ + "5" ((long)(a5)) \ + : "memory" ); \ + (type)__res; \ +}) + +static inline int +hypercall_xen_version( + int cmd, void *arg) +{ + return _hypercall2(int, xen_version, cmd, arg); +} + +void xen_probe(void) +{ + u32 base, eax, ebx, ecx, edx; + char signature[13]; + xen_extraversion_t extraversion; + + 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; + } + } + + if (!xen_cpuid_base) + return; + + init_hypercalls(); + + /* 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); +} + +struct xen_seabios_info { + char signature[14]; /* XenHVMSeaBIOS\0 */ + u16 length; + u32 acpi_rsdp; + u32 mptable; + u32 e820_nr; + struct e820entry e820[128]; + u8 checksum; +}; + +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_hvm_info(void) +{ + if (!usingXen()) + return; + + dprintf(1, "Probing for Xen info\n"); + + struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS; + + validate_info(info); + + dprintf(1, "BIOS INFO: SIGNATURE %s\n", info->signature); +} + +void xen_copy_biostable(void) +{ + struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS; + + dprintf(1, "xen: copy BIOS tables...\n"); + extern void copy_acpi_rsdp(void *pos); + dprintf(1, "xen: ... ACPI RSDP at %x\n", info->acpi_rsdp); + copy_acpi_rsdp((void *)info->acpi_rsdp); + + extern void copy_mptable(void *pos); + dprintf(1, "xen: ... MPTABLE at %x\n", info->mptable); + copy_mptable((void *)info->mptable); +} + +void xen_setup(void) +{ + u64 maxram = 0, maxram_over4G = 0; + int i; + struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS; + + dprintf(1, "xen: copy e820...\n"); + + for (i = 0; i < info->e820_nr; i++) { + struct e820entry *e = &info->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 0000000..ac89ff9 --- /dev/null +++ b/src/xen.h @@ -0,0 +1,56 @@ +#ifndef __XEN_H +#define __XEN_H + +#include "util.h" + +void xen_probe(void); +void xen_probe_hvm_info(void); + +extern u32 xen_cpuid_base; + +static inline int usingXen(void) { + if (!CONFIG_XEN) + return 0; + return (xen_cpuid_base != 0); +} + +void xen_copy_biostable(void); + +void xen_setup(void); + +/****************************************************************************** + * + * 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 -- 1.7.2.5