[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH RFC 19/19] Add EFI stub for ARM64



This patch adds the real EFI application entry point in head.S,
and adds the efi.c file that will contain the EFI stub implementation.
The assembly wrapper is responsible for returning the processor state
to what XEN expects when starting.  The EFI stub processes the
XEN EFI configuration file to load the dom0 kernel, ramdisk, etc and
constructs a device tree for XEN to use, then transfers control to
the normal XEN image entry point.

Signed-off-by: Roy Franz <roy.franz@xxxxxxxxxx>
---
 xen/arch/arm/Makefile     |   2 +
 xen/arch/arm/arm64/head.S |  62 ++++-
 xen/arch/arm/efi-shared.c |   1 +
 xen/arch/arm/efi.c        | 686 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 750 insertions(+), 1 deletion(-)
 create mode 120000 xen/arch/arm/efi-shared.c
 create mode 100644 xen/arch/arm/efi.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 63e0460..c3ed74f 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -33,6 +33,8 @@ obj-y += hvm.o
 obj-y += device.o
 obj-y += decode.o
 obj-y += processor.o
+obj-y += efi.o
+obj-y += efi-shared.o
 
 #obj-bin-y += ....o
 
diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index 9b88aeb..9882519 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -24,6 +24,8 @@
 #include <asm/page.h>
 #include <asm/asm_defns.h>
 #include <asm/early_printk.h>
+#include <efi/efierr.h>
+#include <asm/arm64/efibind.h>
 
 #define PT_PT     0xf7f /* nG=1 AF=1 SH=11 AP=01 NS=1 ATTR=111 T=1 P=1 */
 #define PT_MEM    0xf7d /* nG=1 AF=1 SH=11 AP=01 NS=1 ATTR=111 T=0 P=1 */
@@ -100,7 +102,6 @@
          */
 
         .global start
-efi_stub_entry:  /* Dummy symbol so we can compile before actual stub added */
 start:
 #ifdef CONFIG_EFI_STUB
         /*
@@ -667,6 +668,65 @@ GLOBAL(lookup_processor_type)
         mov  x0, #0
         ret
 
+
+
+ENTRY(efi_stub_entry)
+       stp     x29, x30, [sp, #-32]!
+
+       /*
+        * Call efi_entry to do the real work.
+        * x0 and x1 are already set up by firmware.
+        *
+        * unsigned long efi_entry(EFI_HANDLE handle,
+        *                         EFI_SYSTEM_TABLE *sys_table);
+        */
+
+       bl      efi_entry
+       cmp     x0, EFI_STUB_ERROR
+       b.eq    efi_load_fail
+
+       /*
+        * efi_entry() will return here with device tree address in x0.
+        *  Save value in register which is preserved by __flush_dcache_all.
+        */
+       mov     x20, x0
+
+       /* Turn off Dcache and MMU */
+       mrs     x0, CurrentEL
+       cmp     x0, #PSR_MODE_EL2t
+       ccmp    x0, #PSR_MODE_EL2h, #0x4, ne
+       b.ne    1f
+       mrs     x0, sctlr_el2
+       bic     x0, x0, #1 << 0 // clear SCTLR.M
+       bic     x0, x0, #1 << 2 // clear SCTLR.C
+       msr     sctlr_el2, x0
+       isb
+       b       2f
+1:
+       mrs     x0, sctlr_el1
+       bic     x0, x0, #1 << 0 // clear SCTLR.M
+       bic     x0, x0, #1 << 2 // clear SCTLR.C
+       msr     sctlr_el1, x0
+       isb
+2:
+/*     bl      __flush_dcache_all */  /* RFRANZ_TODO */
+
+       /* Jump to XEN entry point */
+       mov     x0, x20
+       mov     x1, xzr
+       mov     x2, xzr
+       mov     x3, xzr
+       b       real_start
+
+efi_load_fail:
+       mov     x0, #EFI_LOAD_ERROR
+       ldp     x29, x30, [sp], #32
+       ret
+
+ENDPROC(efi_stub_entry)
+
+
+
 /*
  * Local variables:
  * mode: ASM
diff --git a/xen/arch/arm/efi-shared.c b/xen/arch/arm/efi-shared.c
new file mode 120000
index 0000000..096ee3a
--- /dev/null
+++ b/xen/arch/arm/efi-shared.c
@@ -0,0 +1 @@
+../x86/efi/efi-shared.c
\ No newline at end of file
diff --git a/xen/arch/arm/efi.c b/xen/arch/arm/efi.c
new file mode 100644
index 0000000..d13e718
--- /dev/null
+++ b/xen/arch/arm/efi.c
@@ -0,0 +1,686 @@
+#include "efi.h"
+#include <efi/efiprot.h>
+#include <efi/eficon.h>
+#include <efi/efipciio.h>
+#include <efi/efi-shared.h>
+#include <public/xen.h>
+#include <xen/compile.h>
+#include <xen/ctype.h>
+#include <xen/init.h>
+#include <xen/keyhandler.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/pfn.h>
+#if EFI_PAGE_SIZE != PAGE_SIZE
+# error Cannot use xen/pfn.h here!
+#endif
+#include <xen/string.h>
+#include <xen/stringify.h>
+#include <xen/libfdt/libfdt.h>
+
+/*
+ * This define and the code associated with it is a temporary, and will
+ * be replaced by changes to the XEN kernel to use the EFI memory map
+ * that is passed in the device tree instead of the normal FDT memory map.
+ * The XEN kernel changes are largely indpendent of the stub, so this code
+ * has been added to allow review and some testing of the stub code while
+ * the XEN kernel code is being developed.
+ */
+#define ADD_EFI_MEMORY_TO_FDT
+
+#define DEVICE_TREE_GUID \
+{0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}}
+
+extern CHAR16 __initdata newline[];
+extern SIMPLE_TEXT_OUTPUT_INTERFACE *__initdata StdOut;
+extern SIMPLE_TEXT_OUTPUT_INTERFACE *__initdata StdERR;
+extern EFI_BOOT_SERVICES *__initdata efi_bs;
+
+
+static EFI_HANDLE __initdata efi_ih;
+
+static struct file __initdata cfg;
+static struct file __initdata kernel;
+static struct file __initdata ramdisk;
+static struct file __initdata dtb;
+
+static unsigned long mmap_size;
+static EFI_MEMORY_DESCRIPTOR *mmap_ptr;
+
+static void *new_fdt;
+
+#ifdef ADD_EFI_MEMORY_TO_FDT
+static int IsLinuxReservedRegion(int MemoryType)
+{
+    switch ( MemoryType )
+    {
+        case EfiMemoryMappedIO:
+        case EfiMemoryMappedIOPortSpace:
+        case EfiRuntimeServicesCode:
+        case EfiRuntimeServicesData:
+        case EfiUnusableMemory:
+        case EfiACPIReclaimMemory:
+        case EfiACPIMemoryNVS:
+        case EfiLoaderData:
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+
+static EFI_STATUS __init efi_process_memory_map(EFI_MEMORY_DESCRIPTOR *map,
+                                                unsigned long mmap_size,
+                                                unsigned long desc_size,
+                                                void *fdt)
+{
+    int Index;
+    int err;
+
+    EFI_MEMORY_DESCRIPTOR *desc_ptr = map;
+
+    /* Go through the list and add the reserved region to the Device Tree */
+    for ( Index = 0; Index < (mmap_size / desc_size); Index++ )
+    {
+        if ( IsLinuxReservedRegion(desc_ptr->Type) )
+        {
+            err = fdt_add_mem_rsv(fdt, desc_ptr->PhysicalStart, 
desc_ptr->NumberOfPages * EFI_PAGE_SIZE);
+            if ( err != 0 )
+                PrintStr(L"Warning: Fail to add 'memreserve'\n\n");
+        }
+        desc_ptr = NextMemoryDescriptor(desc_ptr, desc_size);
+    }
+
+    return EFI_SUCCESS;
+
+}
+#endif
+
+static EFI_STATUS __init efi_get_memory_map(EFI_SYSTEM_TABLE *sys_table_arg,
+                                            EFI_MEMORY_DESCRIPTOR **map,
+                                            unsigned long *mmap_size,
+                                            unsigned long *desc_size,
+                                            UINT32 *desc_ver,
+                                            unsigned long *key_ptr)
+{
+    EFI_MEMORY_DESCRIPTOR *m = NULL;
+    EFI_STATUS status;
+    unsigned long key;
+    u32 desc_version;
+
+    *mmap_size = sizeof(*m) * 32;
+again:
+    /*
+     * Add an additional 2 efi_memory_desc_t because we're doing an
+         * allocation which may be in a new descriptor region, and this
+         * may create additional entries.
+     */
+    *mmap_size += 2 * sizeof(*m);
+    status = sys_table_arg->BootServices->AllocatePool(EfiLoaderData,
+                                                       *mmap_size, (void 
**)&m);
+    if ( status != EFI_SUCCESS )
+        goto fail;
+
+    *desc_size = 0;
+    key = 0;
+    status = sys_table_arg->BootServices->GetMemoryMap(mmap_size, m,
+                                                       &key, desc_size, 
&desc_version);
+    if ( status == EFI_BUFFER_TOO_SMALL )
+    {
+        sys_table_arg->BootServices->FreePool(m);
+        goto again;
+    }
+
+    if ( status != EFI_SUCCESS )
+        sys_table_arg->BootServices->FreePool(m);
+
+    if ( key_ptr && status == EFI_SUCCESS )
+        *key_ptr = key;
+    if ( desc_ver && status == EFI_SUCCESS )
+        *desc_ver = desc_version;
+
+fail:
+    *map = m;
+    return status;
+}
+
+
+static void __init *lookup_fdt_config_table(EFI_SYSTEM_TABLE *sys_table)
+{
+    const EFI_GUID fdt_guid = DEVICE_TREE_GUID;
+    EFI_CONFIGURATION_TABLE *tables;
+    void *fdt;
+    int i;
+
+    tables = sys_table->ConfigurationTable;
+    fdt = NULL;
+
+    for ( i = 0; i < sys_table->NumberOfTableEntries; i++ ) if ( 
match_guid(&tables[i].VendorGuid, &fdt_guid) == 0 )
+        {
+            fdt = tables[i].VendorTable;
+            break;
+        }
+    return fdt;
+}
+
+/*
+ * Get (or set if not present) the #addr-cells and #size cells
+ * properties of the chose node.  We need to know these to properly
+ * construct the address ranges used to describe the files loaded
+ * by the stub.
+ */
+static int setup_chosen_node(void *fdt, int *addr_cells, int *size_cells)
+{
+    int node;
+    const struct fdt_property *prop;
+    int len;
+    uint32_t val;
+
+    if (!fdt || !addr_cells || !size_cells)
+        return -1;
+
+
+    /* locate chosen node, which is where we add XEN module info. */
+    node = fdt_subnode_offset(fdt, 0, "chosen");
+    if (node < 0)
+    {
+            node = fdt_add_subnode(fdt, 0, "chosen");
+            if (node < 0)
+                return node;
+    }
+
+    /* Get or set #address-cells and #size-cells */
+    prop = fdt_get_property(fdt, node, "#address-cells", &len);
+    if (!prop)
+    {
+        PrintStr(L"No #address-cells in chosen node, setting to 2\r\n");
+        val = cpu_to_fdt32(2);
+        if (fdt_setprop(fdt, node, "#address-cells", &val, sizeof(val)))
+            return -1;
+        *addr_cells = 2;
+    }
+    else
+        *addr_cells = fdt32_to_cpu(*((uint32_t *)prop->data));
+
+    prop = fdt_get_property(fdt, node, "#size-cells", &len);
+    if (!prop)
+    {
+        PrintStr(L"No #size-cells in chosen node, setting to 2\r\n");
+        val = cpu_to_fdt32(2);
+        if (fdt_setprop(fdt, node, "#size-cells", &val, sizeof(val)))
+            return -1;
+        *size_cells = 2;
+    }
+    else
+        *size_cells = fdt32_to_cpu(*((uint32_t *)prop->data));
+
+    /*
+     * Make sure ranges is empty if it exists, otherwise create empty ranges
+     * property.
+     */
+    prop = fdt_get_property(fdt, node, "ranges", &len);
+    if (!prop)
+    {
+        PrintStr(L"No ranges in chosen node, creating empty\r\n");
+        val = cpu_to_fdt32(2);
+        if (fdt_setprop(fdt, node, "#size-cells", &val, 0))
+            return -1;
+    }
+    else
+    {
+        if (fdt32_to_cpu(prop->len))
+        {
+            PrintStr(L"Non-empty ranges in chosen node, aborting\r\n");
+            return -1;
+        }
+    }
+    return node;
+}
+
+
+/*
+ * Set a single 'reg' property taking into account the
+ * configured addr and size cell sizes.
+ */
+static int fdt_set_reg(void *fdt, int node, int addr_cells, int size_cells,
+                       uint64_t addr, uint64_t len)
+{
+    uint8_t data[16]; /* at most 2 64 bit words */
+    void *p = data;
+
+    /* Make sure that the values provided can be represented in
+     * the reg property.
+     */
+    if (addr_cells == 1 && (addr >> 32))
+        return -1;
+    if (size_cells == 1 && (len >> 32))
+        return -1;
+
+    if (addr_cells == 1)
+    {
+        *(uint32_t *)p = cpu_to_fdt32(addr);
+        p += sizeof(uint32_t);
+    }
+    else if (addr_cells == 2)
+    {
+        *(uint64_t *)p = cpu_to_fdt64(addr);
+        p += sizeof(uint64_t);
+    }
+    else
+        return -1;
+
+
+    if (size_cells == 1)
+    {
+        *(uint32_t *)p = cpu_to_fdt32(len);
+        p += sizeof(uint32_t);
+    }
+    else if (size_cells == 2)
+    {
+        *(uint64_t *)p = cpu_to_fdt64(len);
+        p += sizeof(uint64_t);
+    }
+    else
+        return -1;
+
+    return(fdt_setprop(fdt, node, "reg", data, p - (void *)data));
+}
+
+/*
+ * Add the FDT nodes for the standard EFI information, which consist
+ * of the System table address, the address of the final EFI memory map,
+ * and memory map information.
+ */
+static EFI_STATUS fdt_add_uefi_nodes(EFI_SYSTEM_TABLE *sys_table, void *fdt,
+                               EFI_MEMORY_DESCRIPTOR *memory_map,
+                               unsigned long map_size, unsigned long desc_size,
+                               u32 desc_ver)
+{
+    int node;
+    int status;
+    u32 fdt_val32;
+    u64 fdt_val64;
+
+#ifndef ADD_EFI_MEMORY_TO_FDT
+    int prev;
+    /*
+     * Delete any memory nodes present.  The EFI memory map is the only
+     * memory description provided to XEN.
+     */
+    prev = 0;
+    for (;;)
+    {
+        const char *type;
+        int len;
+
+        node = fdt_next_node(fdt, prev, NULL);
+        if (node < 0)
+        break;
+
+        type = fdt_getprop(fdt, node, "device_type", &len);
+        if (type && strncmp(type, "memory", len) == 0)
+        {
+            fdt_del_node(fdt, node);
+            continue;
+        }
+
+        prev = node;
+    }
+#endif
+
+    node = fdt_subnode_offset(fdt, 0, "chosen");
+    if ( node < 0 )
+    {
+        node = fdt_add_subnode(fdt, 0, "chosen");
+        if ( node < 0 )
+        {
+            status = node; /* node is error code when negative */
+            goto fdt_set_fail;
+        }
+    }
+
+    /* Add FDT entries for EFI runtime services in chosen node. */
+    node = fdt_subnode_offset(fdt, 0, "chosen");
+    fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table);
+    status = fdt_setprop(fdt, node, "linux,uefi-system-table",
+                         &fdt_val64, sizeof(fdt_val64));
+    if ( status )
+        goto fdt_set_fail;
+
+    fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
+    status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
+                         &fdt_val64,  sizeof(fdt_val64));
+    if ( status )
+        goto fdt_set_fail;
+
+    fdt_val32 = cpu_to_fdt32(map_size);
+    status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
+                         &fdt_val32,  sizeof(fdt_val32));
+    if ( status )
+        goto fdt_set_fail;
+
+    fdt_val32 = cpu_to_fdt32(desc_size);
+    status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
+                         &fdt_val32, sizeof(fdt_val32));
+    if ( status )
+        goto fdt_set_fail;
+
+    fdt_val32 = cpu_to_fdt32(desc_ver);
+    status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
+                         &fdt_val32, sizeof(fdt_val32));
+    if ( status )
+        goto fdt_set_fail;
+
+    return EFI_SUCCESS;
+
+fdt_set_fail:
+    if ( status == -FDT_ERR_NOSPACE )
+        return EFI_BUFFER_TOO_SMALL;
+
+    return EFI_LOAD_ERROR;
+}
+
+
+
+/*
+ * Allocates new memory for a larger FDT, and frees existing memory if
+ * struct file size is non-zero.  Updates file struct with new memory
+ * address/size for later freeing.  If fdtfile.ptr is NULL, an empty FDT
+ * is created.
+ */
+static void __init *fdt_increase_size(struct file *fdtfile, int add_size)
+{
+    EFI_STATUS status;
+    EFI_PHYSICAL_ADDRESS fdt_addr;
+    int fdt_size;
+    int pages;
+    void *new_fdt;
+
+
+    if ( fdtfile->ptr )
+        fdt_size = fdt_totalsize(fdtfile->ptr);
+    else
+    {
+        /* RFRANZ_TODO - missing fdt_create_empty_tree() in libfdt. */
+        return NULL;
+    }
+
+    pages = PFN_UP(fdt_size) + PFN_UP(add_size);
+    status = efi_bs->AllocatePages(AllocateAnyPages, EfiLoaderData,
+                                   pages, &fdt_addr);
+
+    if ( status != EFI_SUCCESS )
+        return NULL;
+
+    new_fdt = (void *)fdt_addr;
+
+    if ( fdt_open_into(dtb.ptr, new_fdt, pages * EFI_PAGE_SIZE) )
+        return NULL;
+
+    /*
+     * Now that we have the new FDT allocated and copied, free the
+     * original and update the struct file so that the error handling
+     * code will free it.  If the original FDT came from a configuration
+     * table, we don't own that memory and can't free it.
+     */
+    if ( dtb.size )
+        efi_bs->FreePages(dtb.addr, PFN_UP(dtb.size));
+
+    /* Update 'file' info for new memory so we clean it up on error exits */
+    dtb.addr = fdt_addr;
+    dtb.size = pages * EFI_PAGE_SIZE;
+    return new_fdt;
+}
+
+
+/*
+ * Allocate a new FDT with enough space for EFI and XEN related updates,
+ * populating with content from a FDT specified in the configuration file
+ * or configuration table if present.  If neither is available, create an
+ * empty FDT.
+ */
+static void __init *create_new_fdt(EFI_SYSTEM_TABLE *SystemTable,
+                            EFI_FILE_HANDLE dir_handle, struct file *cfgfile,
+                            const char *section)
+{
+    union string name = { NULL };
+
+    /* load dtb from config file or configuration table */
+    name.s = get_value(cfgfile, section, "dtb");
+    if ( name.s )
+    {
+        truncate_string(name.s);
+        read_file(dir_handle, s2w(&name), &dtb);
+        efi_bs->FreePool(name.w);
+    }
+    else
+    {
+        /* Get DTB from configuration table. */
+        dtb.ptr = lookup_fdt_config_table(SystemTable);
+        if ( dtb.ptr )
+        {
+            /* Set dtb.size to zero so config table memory is not freed. */
+            dtb.size = 0;
+        }
+        else
+        {
+            /*
+             * No FDT was provided, so create an empty one to populate with
+             * the EFI and module related params.
+             *
+             * RFRANZ_TODO: libfdt in XEN is missing fdt_create_empty_tree()
+             * likely need libfdt update to support this.
+             */
+            blexit(L"No FDT specified.");
+        }
+    }
+
+
+    /*
+     * Allocate space for new FDT, making sure we have enough space
+     * for the fields we are adding, so we don't have to deal
+     * with increasing the size again later, which complicates
+     * things.  Use the size of the configuration file as an uppper
+     * bound on how much size can be added based on configuration
+     * file contents.
+     */
+    return fdt_increase_size(&dtb, cfg.size + EFI_PAGE_SIZE);
+}
+
+
+#define COMPAT_BUF_SIZE 500 /* FDT string buffer size. */
+unsigned long efi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
+{
+    EFI_GUID loaded_image_guid = LOADED_IMAGE_PROTOCOL;
+    EFI_LOADED_IMAGE *loaded_image;
+    EFI_FILE_HANDLE dir_handle;
+    EFI_STATUS status;
+    union string section = { NULL }, cmdline = { NULL }, name = { NULL };
+    CHAR16 * file_name,*cfg_file_name = NULL,*image_name = NULL;
+    bool_t base_video = 0;
+    int node;
+    int chosen;
+    int addr_len, size_len;
+    char *options;
+    char compat_buf[COMPAT_BUF_SIZE];
+    int compat_len = 0;
+    unsigned long desc_size;
+    UINT32 desc_ver = 0;
+    unsigned long map_key = 0;
+
+    efi_ih = ImageHandle;
+    efi_bs = SystemTable->BootServices;
+    StdOut = SystemTable->ConOut;
+
+    /* Check if we were booted by the EFI firmware */
+    if ( SystemTable->Hdr.Signature != EFI_SYSTEM_TABLE_SIGNATURE )
+        goto fail;
+
+    /* Get loaded image protocol */
+    status = efi_bs->HandleProtocol(ImageHandle, &loaded_image_guid,
+                                    (void **)&loaded_image);
+    if ( status != EFI_SUCCESS )
+        blexit(L"ERROR - no loaded image protocol\r\n");
+
+    PrintStr(L"Xen " __stringify(XEN_VERSION)"." __stringify(XEN_SUBVERSION)
+             XEN_EXTRAVERSION " (c/s " XEN_CHANGESET ") EFI loader\r\n");
+
+    if ( (unsigned long)loaded_image->ImageBase & ((1 << 20) - 1) )
+        blexit(L"Xen must be loaded at a 2MByte boundary.");
+
+    /* Get the file system interface. */
+    dir_handle = get_parent_handle(loaded_image, &file_name);
+
+    handle_cmdline(loaded_image, &cfg_file_name, &base_video, &image_name,
+                   &section.w, &cmdline.w);
+
+    if ( cmdline.w )
+        w2s(&cmdline);
+
+    /* Open and read config file */
+    read_config_file(&dir_handle, &cfg, cfg_file_name,
+                     &section, file_name);
+
+    new_fdt = create_new_fdt(SystemTable, dir_handle, &cfg, section.s);
+    if ( !new_fdt )
+        blexit(L"Unable to create new FDT\r\n");
+
+    chosen = setup_chosen_node(new_fdt, &addr_len, &size_len);
+    if ( chosen < 0 )
+        blexit(L"Unable to setup chosen node\r\n");
+
+
+    name.s = get_value(&cfg, section.s, "kernel");
+    if ( !name.s )
+        blexit(L"No Dom0 kernel image specified.");
+    options = truncate_string(name.s);
+    if ( options )
+        fdt_setprop_string(new_fdt, chosen, "xen,dom0-bootargs", options);
+    s2w(&name);
+    read_file(dir_handle, name.w, &kernel);
+
+    node = fdt_add_subnode(new_fdt, chosen, "kernel");
+    if ( node < 0 )
+        blexit(L"Error adding dom0 FDT node.");
+
+    compat_len = 0;
+    compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - 
compat_len, "xen,linux-zimage") + 1;
+    if ( compat_len > COMPAT_BUF_SIZE )
+        blexit(L"FDT string overflow");
+    compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - 
compat_len, "xen,multiboot-module") + 1;
+    if ( compat_len > COMPAT_BUF_SIZE )
+        blexit(L"FDT string overflow");
+    if ( fdt_setprop(new_fdt, node, "compatible", compat_buf, compat_len) < 0 )
+        blexit(L"unable to set compatible property.");
+    fdt_set_reg(new_fdt, node, addr_len, size_len, kernel.addr, kernel.size);
+    efi_bs->FreePool(name.w);
+
+
+    name.s = get_value(&cfg, section.s, "ramdisk");
+    if ( name.s )
+    {
+        truncate_string(name.s);
+        read_file(dir_handle, s2w(&name), &ramdisk);
+
+        node = fdt_add_subnode(new_fdt, chosen, "ramdisk");
+        if ( node < 0 )
+            blexit(L"Error adding ramdisk FDT node.");
+
+        compat_len = 0;
+        compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - 
compat_len, "xen,linux-initrd") + 1;
+        if ( compat_len > COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+        compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - 
compat_len, "xen,multiboot-module") + 1;
+        if ( compat_len > COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+        if ( fdt_setprop(new_fdt, node, "compatible", compat_buf, compat_len) 
< 0 )
+            blexit(L"unable to set compatible property.");
+        fdt_set_reg(new_fdt, node, addr_len, size_len, ramdisk.addr, 
ramdisk.size);
+        efi_bs->FreePool(name.w);
+    }
+
+
+    /*
+     * cmdline has remaining options from EFI command line.  Prepend these
+     * to the options from the configuration file.  Put the image name at
+     * the beginning of the bootargs.
+     *
+     */
+    if ( image_name )
+    {
+        name.w = image_name;
+        w2s(&name);
+    }
+    else
+        name.s = "xen";
+
+    compat_len = 0;
+    compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - 
compat_len, "%s", name.s);
+    if ( compat_len >= COMPAT_BUF_SIZE )
+        blexit(L"FDT string overflow");
+    if ( cmdline.s )
+    {
+        compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - 
compat_len, " %s", cmdline.s);
+        if ( compat_len >= COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+    }
+    name.s = get_value(&cfg, section.s, "options");
+    if ( name.s )
+    {
+        compat_len += snprintf(compat_buf + compat_len, COMPAT_BUF_SIZE - 
compat_len, " %s", name.s);
+        if ( compat_len >= COMPAT_BUF_SIZE )
+            blexit(L"FDT string overflow");
+    }
+
+
+    if ( fdt_setprop_string(new_fdt, chosen, "xen,xen-bootargs", compat_buf) < 
0 )
+        blexit(L"unable to set xen,xen-bootargs property.");
+
+    status = efi_get_memory_map(SystemTable, &mmap_ptr, &mmap_size, 
&desc_size, &desc_ver, &map_key);
+    if ( status != EFI_SUCCESS )
+        blexit(L"unable to get EFI memory map");
+
+#ifdef ADD_EFI_MEMORY_TO_FDT
+    efi_process_memory_map(mmap_ptr, mmap_size, desc_size, new_fdt);
+#endif
+
+    status = fdt_add_uefi_nodes(SystemTable, new_fdt, mmap_ptr, mmap_size, 
desc_size, desc_ver);
+    if ( status != EFI_SUCCESS )
+    {
+        if ( status == EFI_BUFFER_TOO_SMALL )
+            PrintStr(L"ERROR: FDT buffer too small\r\n");
+        blexit(L"Unable to create new FDT with UEFI nodes");
+    }
+
+    status = efi_bs->ExitBootServices(ImageHandle, map_key);
+    if ( status != EFI_SUCCESS )
+        blexit(L"Unable to exit boot services.");
+
+    return((unsigned long)new_fdt);
+
+
+fail:
+    blexit(L"ERROR: Unable to start XEN\r\n");
+}
+
+
+void __init noreturn blexit(const CHAR16 *str)
+{
+    if ( str )
+        PrintStr((CHAR16 *)str);
+    PrintStr(newline);
+
+    if ( cfg.addr )
+        efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size));
+    if ( kernel.addr )
+        efi_bs->FreePages(kernel.addr, PFN_UP(kernel.size));
+    if ( ramdisk.addr )
+        efi_bs->FreePages(ramdisk.addr, PFN_UP(ramdisk.size));
+    if ( dtb.addr && dtb.size )
+        efi_bs->FreePages(dtb.addr, PFN_UP(dtb.size));
+    if ( mmap_ptr )
+        efi_bs->FreePool(mmap_ptr);
+
+    efi_bs->Exit(efi_ih, EFI_SUCCESS, 0, NULL);
+    unreachable(); /* not reached */
+}
-- 
2.0.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.