This allows a guest to be booted using SeaBIOS directly as its firmware rather than being loaded indirectly via hvmloader. This is presented as a proof of concept since it's not obvious yet which the best approach will be from either Xen or SeaBIOS's point of view.
Signed-off-by: Ian Campbell ian.campbell@citrix.com --- Makefile | 2 +- src/post.c | 5 ++ src/xen.c | 93 ++++++++++++++++++++++++++++++++++++++++++ src/xen.h | 26 ++++++++++++ src/xen/hvm/hvm_info_table.h | 75 +++++++++++++++++++++++++++++++++ 5 files changed, 200 insertions(+), 1 deletions(-) create mode 100644 src/xen.c create mode 100644 src/xen.h create mode 100644 src/xen/hvm/hvm_info_table.h
diff --git a/Makefile b/Makefile index 9affb39..6f12d5a 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/post.c b/src/post.c index 7d2b5f2..a2bd2d7 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
@@ -123,6 +124,9 @@ ram_probe(void)
/* reserve 256KB BIOS area at the end of 4 GB */ add_e820(0xfffc0000, 256*1024, E820_RESERVED); + + if (xen_reserved_size) + add_e820(0x100000000ull-xen_reserved_size, xen_reserved_size, E820_RESERVED); }
// Don't declare any memory between 0xa0000 and 0x100000 @@ -329,6 +333,7 @@ post(void) { // Detect ram and setup internal malloc. qemu_cfg_port_probe(); + xen_probe_hvm_info(); ram_probe(); malloc_setup();
diff --git a/src/xen.c b/src/xen.c new file mode 100644 index 0000000..29e7e68 --- /dev/null +++ b/src/xen.c @@ -0,0 +1,93 @@ +// 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 "cmos.h" + +u32 xen_reserved_size = 0; +u32 xen_nr_vcpus = 0; + +struct hvm_info_table *xen_hvm_info; + +static void validate_hvm_info(struct hvm_info_table *t) +{ + u8 *ptr = (u8 *)t; + u8 sum = 0; + int i; + + if ( memcmp(t->signature, "HVM INFO", 8) ) + panic("Bad hvm info signature\n"); + + if ( t->length < sizeof(struct hvm_info_table) ) + panic("Bad hvm info length\n"); + + for ( i = 0; i < t->length; i++ ) + sum += ptr[i]; + + if ( sum != 0 ) + panic("Bad hvm info checksum\n"); +} + +/* Replace possibly erroneous memory-size CMOS fields with correct values. */ +static void cmos_write_memory_size(u32 low_mem_pgend, u32 high_mem_pgend) +{ + u32 base_mem = 640, ext_mem, alt_mem; + u64 high = high_mem_pgend ? ((u64)high_mem_pgend << 12) - 0x100000000ull : 0ull; + + alt_mem = ext_mem = low_mem_pgend << 12; + ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0; + if ( ext_mem > 0xffff ) + ext_mem = 0xffff; + alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0; + + /* All BIOSes: conventional memory (CMOS *always* reports 640kB). */ + outb_cmos((u8)(base_mem >> 0), 0x15); + outb_cmos((u8)(base_mem >> 8), 0x16); + + /* All BIOSes: extended memory (1kB chunks above 1MB). */ + outb_cmos((u8)( ext_mem >> 0), CMOS_MEM_EXTMEM_LOW); + outb_cmos((u8)( ext_mem >> 8), CMOS_MEM_EXTMEM_HIGH); + + /* Some BIOSes: alternative extended memory (64kB chunks above 16MB). */ + outb_cmos((u8)( alt_mem >> 0), CMOS_MEM_EXTMEM2_LOW); + outb_cmos((u8)( alt_mem >> 8), CMOS_MEM_EXTMEM2_HIGH); + + /* RAM above 4GB */ + outb_cmos((u8) ((high >> 16) & 0xff), CMOS_MEM_HIGHMEM_LOW); + outb_cmos((u8) ((high >> 24) & 0xff), CMOS_MEM_HIGHMEM_MID); + outb_cmos((u8) ((high >> 32) & 0xff), CMOS_MEM_HIGHMEM_HIGH); +} + +void xen_probe_hvm_info(void) +{ + struct hvm_info_table *t; + + t = (struct hvm_info_table *)HVM_INFO_PADDR; + + validate_hvm_info(t); + + xen_hvm_info = t; + + dprintf(1, "Found HVM info table at %p\n", t); + dprintf(1, "Signature %c%c%c%c%c%c%c%c\n", + t->signature[0], t->signature[1], + t->signature[2], t->signature[3], + t->signature[4], t->signature[5], + t->signature[6], t->signature[7]); + dprintf(1, "Length %d, checksum %x\n", t->length, t->checksum); + dprintf(1, "ACPI:%d APIC:%d VCPUS:%d\n", + t->acpi_enabled, t->apic_mode, t->nr_vcpus); + dprintf(1, "low_mem_pgend: %x\n", t->low_mem_pgend); + dprintf(1, "high_mem_pgend: %x\n", t->high_mem_pgend); + dprintf(1, "reserved_mem_pgstart: %x\n", t->reserved_mem_pgstart); + + cmos_write_memory_size(t->low_mem_pgend, t->high_mem_pgend); + + xen_reserved_size = (u32)(0x100000000ull - ((u64)t->reserved_mem_pgstart<<12)); + + xen_nr_vcpus = t->nr_vcpus; +} diff --git a/src/xen.h b/src/xen.h new file mode 100644 index 0000000..eef9a0e --- /dev/null +++ b/src/xen.h @@ -0,0 +1,26 @@ +#ifndef __XEN_H +#define __XEN_H + +#ifdef CONFIG_XEN + +#include "util.h" + +#include "xen/hvm/hvm_info_table.h" + +void xen_probe_hvm_info(void); + +extern u32 xen_reserved_size; +extern u32 xen_nr_vcpus; + +extern struct hvm_info_table *xen_hvm_info; + +#else + +static voic xen_probe_hvm_info(void) {} + +#define xen_reserved_size 0 +#define xen_nr_vcpus 0 + +#endif + +#endif diff --git a/src/xen/hvm/hvm_info_table.h b/src/xen/hvm/hvm_info_table.h new file mode 100644 index 0000000..e665883 --- /dev/null +++ b/src/xen/hvm/hvm_info_table.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * hvm/hvm_info_table.h + * + * HVM parameter and information table, written into guest memory map. + * + * 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. + */ + +#ifndef __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ +#define __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ + +#define HVM_INFO_PFN 0x09F +#define HVM_INFO_OFFSET 0x800 +#define HVM_INFO_PADDR ((HVM_INFO_PFN << 12) + HVM_INFO_OFFSET) + +/* Maximum we can support with current vLAPIC ID mapping. */ +#define HVM_MAX_VCPUS 128 + +struct hvm_info_table { + char signature[8]; /* "HVM INFO" */ + u32 length; + u8 checksum; + + /* Should firmware build ACPI tables? */ + u8 acpi_enabled; + + /* Should firmware build APIC descriptors (APIC MADT / MP BIOS)? */ + u8 apic_mode; + + /* How many CPUs does this domain have? */ + u32 nr_vcpus; + + /* + * MEMORY MAP provided by HVM domain builder. + * Notes: + * 1. page_to_phys(x) = x << 12 + * 2. If a field is zero, the corresponding range does not exist. + */ + /* + * 0x0 to page_to_phys(low_mem_pgend)-1: + * RAM below 4GB (except for VGA hole 0xA0000-0xBFFFF) + */ + u32 low_mem_pgend; + /* + * page_to_phys(reserved_mem_pgstart) to 0xFFFFFFFF: + * Reserved for special memory mappings + */ + u32 reserved_mem_pgstart; + /* + * 0x100000000 to page_to_phys(high_mem_pgend)-1: + * RAM above 4GB + */ + u32 high_mem_pgend; + + /* Bitmap of which CPUs are online at boot time. */ + u8 vcpu_online[(HVM_MAX_VCPUS + 7)/8]; +}; + +#endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */