# HG changeset patch
# User Ian Campbell <ian.campbell@citrix.com>
# 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 <ian.campbell@citrix.com>

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);
 
