On Tue, 2011-05-24 at 22:44 -0400, Kevin O'Connor wrote: > On Tue, May 24, 2011 at 12:02:07PM +0100, Ian Campbell wrote: > > Would that involve pulling a bunch of mainboard specific stuff from > > coreboot into SeaBIOS? > > The idea - when it was last raised - was to provide raw info in a > coreboot specific manor (via the "coreboot tables"), and then have > SeaBIOS populate ACPI/SMBIOS/MPTable/etc. from that info. It was > never pursued.
Speaking of coreboot tables... I also need to pass some start of day info into seabios (ACPI tables, e820 etc). Currently I just used a little ad-hoc data structure at a known physical address but I wonder if perhaps I should/could reuse the coreboot table datastructures? They are existing and well defined and I suppose they are pretty static, but I don't want to add any additional compatibility burden if you guys would rather avoid it. FWIW my current patch for hvmloader->seabios (rather than direct SeaBIOS boot) is attached. Things I'd like to address before submitting it properly are putting the hypercall pages somewhere saner (and reserved etc) and using coreboot tables if desired (or at the very least do something better than commenting out the "static"...). I also attached the patches for hvmloader. Ian.
>From c2f5909e835903f7678f77b0a1626b9a974ef3aa Mon Sep 17 00:00:00 2001 From: Ian Campbell <[email protected]> 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 <[email protected]> --- 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
# HG changeset patch # User Ian Campbell <[email protected]> # Date 1306422697 -3600 # Node ID 9b32ecfdffae7b92f7e4d7698416f05bc5778515 # Parent 71a3a138138bb1499a4e11eaea35b66e5cb1924f hvmloader: allow per-BIOS decision on loading option ROMS SeaBIOS has functionality to load ROMs from the PCI device directly, it makes sense to use this when it is available. Signed-off-by: Ian Campbell <[email protected]> diff -r 71a3a138138b -r 9b32ecfdffae tools/firmware/hvmloader/config-seabios.h --- a/tools/firmware/hvmloader/config-seabios.h Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/config-seabios.h Thu May 26 16:11:37 2011 +0100 @@ -1,9 +1,6 @@ #ifndef __HVMLOADER_CONFIG_SEABIOS_H__ #define __HVMLOADER_CONFIG_SEABIOS_H__ -#define OPTIONROM_PHYSICAL_ADDRESS 0x000C8000 -#define OPTIONROM_PHYSICAL_END 0x000E0000 - #define SEABIOS_PHYSICAL_ADDRESS 0x000E0000 #endif /* __HVMLOADER_CONFIG_SEABIOS_H__ */ diff -r 71a3a138138b -r 9b32ecfdffae tools/firmware/hvmloader/config.h --- a/tools/firmware/hvmloader/config.h Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/config.h Thu May 26 16:11:37 2011 +0100 @@ -19,7 +19,10 @@ struct bios_config { /* SMBIOS */ unsigned int smbios_start, smbios_end; - /* Option ROMs */ + /* ROMS */ + int load_vgabios; + int load_etherboot; + int load_option_roms; unsigned int optionrom_start, optionrom_end; /* ACPI tables */ diff -r 71a3a138138b -r 9b32ecfdffae tools/firmware/hvmloader/hvmloader.c --- a/tools/firmware/hvmloader/hvmloader.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/hvmloader.c Thu May 26 16:11:37 2011 +0100 @@ -417,39 +417,48 @@ int main(void) ( (hvm_info->nr_vcpus > 1) || hvm_info->apic_mode ) ) bios->create_mp_tables(); - switch ( virtual_vga ) + if ( bios->load_vgabios ) { - case VGA_cirrus: - printf("Loading Cirrus VGABIOS ...\n"); - memcpy((void *)VGABIOS_PHYSICAL_ADDRESS, - vgabios_cirrusvga, sizeof(vgabios_cirrusvga)); - vgabios_sz = round_option_rom(sizeof(vgabios_cirrusvga)); - break; - case VGA_std: - printf("Loading Standard VGABIOS ...\n"); - memcpy((void *)VGABIOS_PHYSICAL_ADDRESS, - vgabios_stdvga, sizeof(vgabios_stdvga)); - vgabios_sz = round_option_rom(sizeof(vgabios_stdvga)); - break; - case VGA_pt: - printf("Loading VGABIOS of passthroughed gfx ...\n"); - vgabios_sz = - round_option_rom((*(uint8_t *)(VGABIOS_PHYSICAL_ADDRESS+2)) * 512); - break; - default: - printf("No emulated VGA adaptor ...\n"); - break; + switch ( virtual_vga ) + { + case VGA_cirrus: + printf("Loading Cirrus VGABIOS ...\n"); + memcpy((void *)VGABIOS_PHYSICAL_ADDRESS, + vgabios_cirrusvga, sizeof(vgabios_cirrusvga)); + vgabios_sz = round_option_rom(sizeof(vgabios_cirrusvga)); + break; + case VGA_std: + printf("Loading Standard VGABIOS ...\n"); + memcpy((void *)VGABIOS_PHYSICAL_ADDRESS, + vgabios_stdvga, sizeof(vgabios_stdvga)); + vgabios_sz = round_option_rom(sizeof(vgabios_stdvga)); + break; + case VGA_pt: + printf("Loading VGABIOS of passthroughed gfx ...\n"); + vgabios_sz = + round_option_rom((*(uint8_t *)(VGABIOS_PHYSICAL_ADDRESS+2)) * 512); + break; + default: + printf("No emulated VGA adaptor ...\n"); + break; + } } etherboot_phys_addr = VGABIOS_PHYSICAL_ADDRESS + vgabios_sz; - if ( etherboot_phys_addr < bios->optionrom_start ) - etherboot_phys_addr = bios->optionrom_start; - etherboot_sz = scan_etherboot_nic(bios->optionrom_end, - etherboot_phys_addr); + if ( bios->load_etherboot ) + { + if ( etherboot_phys_addr < bios->optionrom_start ) + etherboot_phys_addr = bios->optionrom_start; + etherboot_sz = scan_etherboot_nic(bios->optionrom_end, + etherboot_phys_addr); + } option_rom_phys_addr = etherboot_phys_addr + etherboot_sz; - option_rom_sz = pci_load_option_roms(bios->optionrom_end, - option_rom_phys_addr); + if ( bios->load_option_roms ) + { + option_rom_sz = pci_load_option_roms(bios->optionrom_end, + option_rom_phys_addr); + } if ( hvm_info->acpi_enabled ) { diff -r 71a3a138138b -r 9b32ecfdffae tools/firmware/hvmloader/rombios.c --- a/tools/firmware/hvmloader/rombios.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/rombios.c Thu May 26 16:11:37 2011 +0100 @@ -372,6 +372,10 @@ struct bios_config rombios_config = { .smbios_start = SMBIOS_PHYSICAL_ADDRESS, .smbios_end = SMBIOS_PHYSICAL_END, + .load_vgabios = 1, + .load_etherboot = 1, + .load_option_roms = 1, + .optionrom_start = OPTIONROM_PHYSICAL_ADDRESS, .optionrom_end = OPTIONROM_PHYSICAL_END, diff -r 71a3a138138b -r 9b32ecfdffae tools/firmware/hvmloader/seabios.c --- a/tools/firmware/hvmloader/seabios.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/seabios.c Thu May 26 16:11:37 2011 +0100 @@ -46,8 +46,12 @@ struct bios_config seabios_config = { .smbios_start = 0, .smbios_end = 0, - .optionrom_start = OPTIONROM_PHYSICAL_ADDRESS, - .optionrom_end = OPTIONROM_PHYSICAL_END, + .load_vgabios = 0, + .load_etherboot = 0, + .load_option_roms = 0, + + .optionrom_start = 0, + .optionrom_end = 0, .acpi_start = 0,
# HG changeset patch # User Ian Campbell <[email protected]> # Date 1306422697 -3600 # Node ID ff9f86ef7be234c46afc1072f5191428bf66a9cd # Parent 67d262e901a8fea9ac38fb106ccd7e2573e9506e hvmloader: further support for SeaBIOS Build the various BIOS tables and arrange for them to be passed to SeaBIOS. We define an ad-hoc structure at a known physical address for this purpose. Also add a simple "scratch allocator" returning memory which is passed to SeaBIOS but can be reused once the contents is consumed. SeaBIOS copies various supplied tables to its own buffers during init. XXX TODO refactor pci_setup and apic_setup into common location. XXX TODO consider re-using coreboot table datastructure instead of ad-hoc. Signed-off-by: Ian Campbell <[email protected]> diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/config-seabios.h --- a/tools/firmware/hvmloader/config-seabios.h Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/config-seabios.h Thu May 26 16:11:37 2011 +0100 @@ -1,6 +1,8 @@ #ifndef __HVMLOADER_CONFIG_SEABIOS_H__ #define __HVMLOADER_CONFIG_SEABIOS_H__ +#define BIOS_INFO_PHYSICAL_ADDRESS 0x00001000 + #define SEABIOS_PHYSICAL_ADDRESS 0x000E0000 #endif /* __HVMLOADER_CONFIG_SEABIOS_H__ */ diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/config.h --- a/tools/firmware/hvmloader/config.h Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/config.h Thu May 26 16:11:37 2011 +0100 @@ -25,9 +25,6 @@ struct bios_config { int load_option_roms; unsigned int optionrom_start, optionrom_end; - /* ACPI tables */ - unsigned int acpi_start; - void (*apic_setup)(void); void (*pci_setup)(void); void (*smp_setup)(void); @@ -38,7 +35,7 @@ struct bios_config { void (*vm86_setup)(void); void (*e820_setup)(void); - void (*acpi_build_tables)(unsigned int physical); + void (*acpi_build_tables)(void); void (*create_mp_tables)(void); }; @@ -73,6 +70,8 @@ extern unsigned long pci_mem_start, pci_ #define VGABIOS_PHYSICAL_ADDRESS 0x000C0000 #define HVMLOADER_PHYSICAL_ADDRESS 0x00100000 +extern unsigned long scratch_start; + #endif /* __HVMLOADER_CONFIG_H__ */ /* diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/hvmloader.c --- a/tools/firmware/hvmloader/hvmloader.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/hvmloader.c Thu May 26 16:11:37 2011 +0100 @@ -112,6 +112,8 @@ asm ( unsigned long pci_mem_start = PCI_MEM_START; unsigned long pci_mem_end = PCI_MEM_END; +unsigned long scratch_start = SCRATCH_PHYSICAL_ADDRESS; + enum virtual_vga virtual_vga = VGA_none; static void init_hypercalls(void) @@ -401,8 +403,7 @@ int main(void) if (bios->smbios_start) { printf("Writing SMBIOS tables ...\n"); - smbios_sz = hvm_write_smbios_tables(SCRATCH_PHYSICAL_ADDRESS, - bios->smbios_start, + smbios_sz = hvm_write_smbios_tables(bios->smbios_start, bios->smbios_end); } @@ -470,7 +471,7 @@ int main(void) if ( bios->acpi_build_tables ) { printf("Loading ACPI ...\n"); - bios->acpi_build_tables(bios->acpi_start); + bios->acpi_build_tables(); } hypercall_hvm_op(HVMOP_set_param, &p); } @@ -481,6 +482,9 @@ int main(void) cmos_write_memory_size(); printf("BIOS map:\n"); + if ( SCRATCH_PHYSICAL_ADDRESS != scratch_start ) + printf(" %05x-%05lx: Scratch space\n", + SCRATCH_PHYSICAL_ADDRESS, scratch_start); if ( vgabios_sz ) printf(" %05x-%05x: VGA BIOS\n", VGABIOS_PHYSICAL_ADDRESS, diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/mp_tables.c --- a/tools/firmware/hvmloader/mp_tables.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/mp_tables.c Thu May 26 16:11:37 2011 +0100 @@ -260,11 +260,12 @@ static void fill_mpfps(struct mp_floatin } /* create_mp_tables - creates MP tables for the guest based upon config data */ -void create_mp_tables(void *mp_table_base) +unsigned long create_mp_tables(void *mp_table_base) { char *p; int vcpu_nr, i, length; struct mp_io_intr_entry *mpiie; + struct mp_floating_pointer_struct *mpfps; vcpu_nr = hvm_info->nr_vcpus; @@ -313,9 +314,12 @@ void create_mp_tables(void *mp_table_bas /* find the next 16-byte boundary to place the mp floating pointer */ while ( (unsigned long)p & 0xF ) p++; + mpfps = (struct mp_floating_pointer_struct *)p; + p += sizeof(struct mp_floating_pointer_struct); - fill_mpfps((struct mp_floating_pointer_struct *)p, - (uint32_t)mp_table_base); + fill_mpfps(mpfps, (uint32_t)mp_table_base); fill_mp_config_table((struct mp_config_table *)mp_table_base, length); + + return (unsigned long)mpfps; } diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/rombios.c --- a/tools/firmware/hvmloader/rombios.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/rombios.c Thu May 26 16:11:37 2011 +0100 @@ -84,7 +84,8 @@ static void rombios_setup_bios_info(uint bios_info->bios32_entry = bioshigh; } -static void rombios_apic_setup(void) +/*XXX this should be common*/ +/*static*/ void rombios_apic_setup(void) { /* Set the IOAPIC ID to the static value used in the MP/ACPI tables. */ ioapic_write(0x00, IOAPIC_ID); @@ -99,7 +100,8 @@ static void rombios_apic_setup(void) ioapic_write(0x11, SET_APIC_ID(LAPIC_ID(0))); } -static void rombios_pci_setup(void) +/*XXX this should be common*/ +/*static*/ void rombios_pci_setup(void) { uint32_t base, devfn, bar_reg, bar_data, bar_sz, cmd, mmio_total = 0; uint16_t class, vendor_id, device_id; @@ -113,7 +115,7 @@ static void rombios_pci_setup(void) /* Create a list of device BARs in descending order of size. */ struct bars { uint32_t devfn, bar_reg, bar_sz; - } *bars = (struct bars *)SCRATCH_PHYSICAL_ADDRESS; + } *bars = (struct bars *)scratch_start; unsigned int i, nr_bars = 0; /* Program PCI-ISA bridge with appropriate link routes. */ @@ -343,6 +345,11 @@ static void reset_bios_checksum(void) *((uint8_t *)(ROMBIOS_BEGIN + ROMBIOS_MAXOFFSET)) = -checksum; } +static void rombios_acpi_build_tables(void) +{ + acpi_build_tables(ACPI_PHYSICAL_ADDRESS); +} + static void rombios_create_mp_tables(void) { /* Find the 'safe' place in ROMBIOS for the MP tables. */ @@ -379,8 +386,6 @@ struct bios_config rombios_config = { .optionrom_start = OPTIONROM_PHYSICAL_ADDRESS, .optionrom_end = OPTIONROM_PHYSICAL_END, - .acpi_start = ACPI_PHYSICAL_ADDRESS, - .apic_setup = rombios_apic_setup, .pci_setup = rombios_pci_setup, .smp_setup = smp_initialise, @@ -391,7 +396,7 @@ struct bios_config rombios_config = { .vm86_setup = rombios_init_vm86_tss, .e820_setup = rombios_setup_e820, - .acpi_build_tables = acpi_build_tables, + .acpi_build_tables = rombios_acpi_build_tables, .create_mp_tables = rombios_create_mp_tables, }; diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/seabios.c --- a/tools/firmware/hvmloader/seabios.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/seabios.c Thu May 26 16:11:37 2011 +0100 @@ -25,12 +25,75 @@ #include "util.h" +#include "acpi/acpi2_0.h" + #define ROM_INCLUDE_SEABIOS #include "roms.inc" +struct seabios_info { + char signature[14]; /* XenHVMSeaBIOS\0 */ + uint16_t length; + uint32_t acpi_rsdp; + uint32_t mptable; + uint32_t e820_nr; + struct e820entry e820[128]; + uint8_t checksum; +}; + + +static void seabios_setup_bios_info(uint32_t bioshigh) +{ + struct seabios_info *info = (void *)BIOS_INFO_PHYSICAL_ADDRESS; + uint32_t i; + uint8_t checksum; + + BUILD_BUG_ON(sizeof(struct seabios_info) > (0x9FC00 - BIOS_INFO_PHYSICAL_ADDRESS)); + + memcpy(info->signature, "XenHVMSeaBIOS", sizeof(info->signature)); + info->length = sizeof(*info); + + info->checksum = 0; + + checksum = 0; + for (i = 0; i < info->length; ++i) + checksum += ((uint8_t *)(info))[i]; + + info->checksum = -checksum; +} + static void seabios_pci_setup(void) { + extern void rombios_pci_setup(void); virtual_vga = VGA_cirrus; + rombios_pci_setup(); +} + +static void seabios_apic_setup(void) +{ + extern void rombios_apic_setup(void); + rombios_apic_setup(); +} + +static void seabios_acpi_build_tables(void) +{ + struct seabios_info *info = (void *)BIOS_INFO_PHYSICAL_ADDRESS; + void *rsdp = scratch_alloc(sizeof(struct acpi_20_rsdp), 0); + acpi_build_tables((unsigned long)rsdp); + info->acpi_rsdp = (unsigned long)rsdp; +} + +static void seabios_create_mp_tables(void) +{ + struct seabios_info *info = (void *)BIOS_INFO_PHYSICAL_ADDRESS; + void *table = scratch_alloc(32*1024, 0); + info->mptable = create_mp_tables(table); +} + +static void seabios_setup_e820(void) +{ + struct seabios_info *info = (void *)BIOS_INFO_PHYSICAL_ADDRESS; + info->e820_nr = build_e820_table(info->e820); + dump_e820_table(info->e820, info->e820_nr); } //BUILD_BUG_ON(sizeof(seabios) > (0x00100000U - SEABIOS_PHYSICAL_ADDRESS)); @@ -53,19 +116,17 @@ struct bios_config seabios_config = { .optionrom_start = 0, .optionrom_end = 0, - .acpi_start = 0, + .bios_info_setup = seabios_setup_bios_info, - .bios_info_setup = NULL, - - .apic_setup = NULL, + .apic_setup = seabios_apic_setup, .pci_setup = seabios_pci_setup, - .smp_setup = NULL, + .smp_setup = smp_initialise, .vm86_setup = NULL, - .e820_setup = NULL, + .e820_setup = seabios_setup_e820, - .acpi_build_tables = NULL, - .create_mp_tables = NULL, + .acpi_build_tables = seabios_acpi_build_tables, + .create_mp_tables = seabios_create_mp_tables, }; /* diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/smbios.c --- a/tools/firmware/hvmloader/smbios.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/smbios.c Thu May 26 16:11:37 2011 +0100 @@ -162,7 +162,7 @@ get_memsize(void) } int -hvm_write_smbios_tables(unsigned long scratch, unsigned long smbios_start, unsigned long smbios_end) +hvm_write_smbios_tables(unsigned long smbios_start, unsigned long smbios_end) { xen_domain_handle_t uuid; uint16_t xen_major_version, xen_minor_version; @@ -221,15 +221,15 @@ hvm_write_smbios_tables(unsigned long sc xen_version_str[sizeof(xen_version_str)-1] = '\0'; - /* SCRATCH_PHYSICAL_ADDRESS is a safe large memory area for scratch. */ - len = write_smbios_tables((void *)scratch, smbios_start, + /* scratch_start is a safe large memory area for scratch. */ + len = write_smbios_tables((void *)scratch_start, smbios_start, hvm_info->nr_vcpus, get_memsize(), uuid, xen_version_str, xen_major_version, xen_minor_version); if ( smbios_start + len > smbios_end ) goto error_out; /* Okay, not too large: copy out of scratch to final location. */ - memcpy((void *)smbios_start, (void *)scratch, len); + memcpy((void *)smbios_start, (void *)scratch_start, len); return len; diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/util.c --- a/tools/firmware/hvmloader/util.c Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/util.c Thu May 26 16:11:37 2011 +0100 @@ -362,6 +362,24 @@ void *mem_alloc(uint32_t size, uint32_t return (void *)(unsigned long)s; } +void *scratch_alloc(uint32_t size, uint32_t align) +{ + uint32_t s, e; + + /* Align to at least one kilobyte. */ + if ( align < 1024 ) + align = 1024; + + s = (scratch_start + align - 1) & ~(align - 1); + e = s + size - 1; + + BUG_ON(e < s); + + scratch_start = e; + + return (void *)(unsigned long)s; +} + uint32_t ioapic_read(uint32_t reg) { *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg; diff -r 67d262e901a8 -r ff9f86ef7be2 tools/firmware/hvmloader/util.h --- a/tools/firmware/hvmloader/util.h Thu May 26 16:11:37 2011 +0100 +++ b/tools/firmware/hvmloader/util.h Thu May 26 16:11:37 2011 +0100 @@ -168,6 +168,9 @@ int vprintf(const char *fmt, va_list ap) void *mem_alloc(uint32_t size, uint32_t align); #define virt_to_phys(v) ((unsigned long)(v)) +/* Allocate memory in a scratch region */ +void *scratch_alloc(uint32_t size, uint32_t align); + /* Connect our xenbus client to the backend. * Call once, before any other xenbus actions. */ void xenbus_setup(void); @@ -185,9 +188,8 @@ uint32_t rombios_highbios_setup(void); /* Miscellaneous. */ void cacheattr_init(void); -void create_mp_tables(void *table); -int hvm_write_smbios_tables(unsigned long scratch, - unsigned long smbios_start, +unsigned long create_mp_tables(void *table); +int hvm_write_smbios_tables(unsigned long smbios_start, unsigned long smbios_end); void smp_initialise(void);
_______________________________________________ SeaBIOS mailing list [email protected] http://www.seabios.org/mailman/listinfo/seabios
