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

Re: [Xen-devel] [PATCH V4 15/15] Add ARM EFI boot support



On Tue, 9 Sep 2014, Roy Franz wrote:
> This patch adds EFI boot support for ARM based on the previous refactoring of
> the x86 EFI boot code.  All ARM specific code is in the ARM efi-boot.h header
> file, with the main EFI entry point common/efi/boot.c.  The PE/COFF header is
> open-coded in head.S, which allows us to have a single binary be both an EFI
> executable and a normal arm64 IMAGE file. There is currently no PE/COFF
> toolchain support for arm64, so it is not possible to create the PE/COFF 
> header
> in the same manner as on x86.  This also simplifies the build as compared to
> x86, as we always build the same executable, whereas x86 builds 2.  An ARM
> version of efi-bind.h is added, which is based on the x86_64 version with the
> x86 specific portions removed.  The Makefile in common/efi is different for 
> x86
> and ARM, as for ARM we always build in EFI support.
> 
> Signed-off-by: Roy Franz <roy.franz@xxxxxxxxxx>
> ---
>  config/arm64.mk                     |   1 +
>  xen/arch/arm/arm64/head.S           | 150 ++++++++-
>  xen/arch/arm/xen.lds.S              |   1 +
>  xen/common/Makefile                 |   1 +
>  xen/common/efi/Makefile             |   3 +
>  xen/include/asm-arm/arm64/efibind.h | 216 +++++++++++++
>  xen/include/asm-arm/efi-boot.h      | 630 
> ++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/efi.h           |  29 ++
>  xen/include/asm-arm/efibind.h       |   2 +
>  xen/include/asm-arm/setup.h         |   2 +-
>  10 files changed, 1031 insertions(+), 4 deletions(-)
>  create mode 100644 xen/common/efi/Makefile
>  create mode 100644 xen/include/asm-arm/arm64/efibind.h
>  create mode 100644 xen/include/asm-arm/efi-boot.h
>  create mode 100644 xen/include/asm-arm/efi.h
>  create mode 100644 xen/include/asm-arm/efibind.h
> 
> diff --git a/config/arm64.mk b/config/arm64.mk
> index 15b57a4..e6aab0e 100644
> --- a/config/arm64.mk
> +++ b/config/arm64.mk
> @@ -1,6 +1,7 @@
>  CONFIG_ARM := y
>  CONFIG_ARM_64 := y
>  CONFIG_ARM_$(XEN_OS) := y
> +CONFIG_EFI := y
>  
>  CONFIG_XEN_INSTALL_SUFFIX :=
>  
> diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
> index 43b5e72..158c102 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 */
> @@ -104,8 +106,14 @@ GLOBAL(start)
>          /*
>           * DO NOT MODIFY. Image header expected by Linux boot-loaders.
>           */
> -        b       real_start           /* branch to kernel start, magic */
> -        .long   0                    /* reserved */
> +efi_head:
> +        /*
> +         * This add instruction has no meaningful effect except that
> +         * its opcode forms the magic "MZ" signature of a PE/COFF file
> +         * that is required for UEFI applications.
> +         */
> +        add     x13, x18, #0x16
> +        b       real_start           /* branch to kernel start */
>          .quad   0                    /* Image load offset from start of RAM 
> */
>          .quad   0                    /* reserved */
>          .quad   0                    /* reserved */
> @@ -116,8 +124,113 @@ GLOBAL(start)
>          .byte   0x52
>          .byte   0x4d
>          .byte   0x64
> -        .word   0                    /* reserved */
> +        .long   pe_header - efi_head        /* Offset to the PE header. */
> +
> +        /*
> +         * Add the PE/COFF header to the file.  The address of this header
> +         * is at offset 0x3c in the file, and is part of Linux "Image"
> +         * header.  The arm64 Linux Image format is designed to support
> +         * being both an 'Image' format binary and a PE/COFF binary.
> +         * The PE/COFF format is defined by Microsoft, and is available
> +         * from: http://msdn.microsoft.com/en-us/gg463119.aspx
> +         * Version 8.3 adds support for arm64 and UEFI usage.
> +         */
> +
> +        .align  3
> +pe_header:
> +        .ascii  "PE"
> +        .short  0
> +coff_header:
> +        .short  0xaa64                          /* AArch64 */
> +        .short  2                               /* nr_sections */
> +        .long   0                               /* TimeDateStamp */
> +        .long   0                               /* PointerToSymbolTable */
> +        .long   1                               /* NumberOfSymbols */
> +        .short  section_table - optional_header /* SizeOfOptionalHeader */
> +        .short  0x206                           /* Characteristics. */
> +                                                /* IMAGE_FILE_DEBUG_STRIPPED 
> | */
> +                                                /* 
> IMAGE_FILE_EXECUTABLE_IMAGE | */
> +                                                /* 
> IMAGE_FILE_LINE_NUMS_STRIPPED */
> +optional_header:
> +        .short  0x20b                           /* PE32+ format */
> +        .byte   0x02                            /* MajorLinkerVersion */
> +        .byte   0x14                            /* MinorLinkerVersion */
> +        .long   _end - real_start               /* SizeOfCode */
> +        .long   0                               /* SizeOfInitializedData */
> +        .long   0                               /* SizeOfUninitializedData */
> +        .long   efi_start - efi_head            /* AddressOfEntryPoint */
> +        .long   real_start - efi_head           /* BaseOfCode */
> +
> +extra_header_fields:
> +        .quad   0                               /* ImageBase */
> +        .long   0x1000                          /* SectionAlignment (4 
> KByte) */
> +        .long   0x8                             /* FileAlignment */
> +        .short  0                               /* 
> MajorOperatingSystemVersion */
> +        .short  0                               /* 
> MinorOperatingSystemVersion */
> +        .short  0                               /* MajorImageVersion */
> +        .short  0                               /* MinorImageVersion */
> +        .short  0                               /* MajorSubsystemVersion */
> +        .short  0                               /* MinorSubsystemVersion */
> +        .long   0                               /* Win32VersionValue */
> +
> +        .long   _end - efi_head                 /* SizeOfImage */
> +
> +        /* Everything before the kernel image is considered part of the 
> header */
> +        .long   real_start - efi_head           /* SizeOfHeaders */
> +        .long   0                               /* CheckSum */
> +        .short  0xa                             /* Subsystem (EFI 
> application) */
> +        .short  0                               /* DllCharacteristics */
> +        .quad   0                               /* SizeOfStackReserve */
> +        .quad   0                               /* SizeOfStackCommit */
> +        .quad   0                               /* SizeOfHeapReserve */
> +        .quad   0                               /* SizeOfHeapCommit */
> +        .long   0                               /* LoaderFlags */
> +        .long   0x6                             /* NumberOfRvaAndSizes */
> +
> +        .quad   0                               /* ExportTable */
> +        .quad   0                               /* ImportTable */
> +        .quad   0                               /* ResourceTable */
> +        .quad   0                               /* ExceptionTable */
> +        .quad   0                               /* CertificationTable */
> +        .quad   0                               /* BaseRelocationTable */
> +
> +        /* Section table */
> +section_table:
>  
> +        /*
> +         * The EFI application loader requires a relocation section
> +         * because EFI applications must be relocatable.  This is a
> +         * dummy section as far as we are concerned.
> +         */
> +        .ascii  ".reloc"
> +        .byte   0
> +        .byte   0                               /* end of 0 padding of 
> section name */
> +        .long   0
> +        .long   0
> +        .long   0                               /* SizeOfRawData */
> +        .long   0                               /* PointerToRawData */
> +        .long   0                               /* PointerToRelocations */
> +        .long   0                               /* PointerToLineNumbers */
> +        .short  0                               /* NumberOfRelocations */
> +        .short  0                               /* NumberOfLineNumbers */
> +        .long   0x42100040                      /* Characteristics (section 
> flags) */
> +
> +
> +        .ascii  ".text"
> +        .byte   0
> +        .byte   0
> +        .byte   0                               /* end of 0 padding of 
> section name */
> +        .long   _end - real_start               /* VirtualSize */
> +        .long   real_start - efi_head           /* VirtualAddress */
> +        .long   __init_end_efi - real_start     /* SizeOfRawData */
> +        .long   real_start - efi_head           /* PointerToRawData */
> +
> +        .long   0                /* PointerToRelocations (0 for executables) 
> */
> +        .long   0                /* PointerToLineNumbers (0 for executables) 
> */
> +        .short  0                /* NumberOfRelocations  (0 for executables) 
> */
> +        .short  0                /* NumberOfLineNumbers  (0 for executables) 
> */
> +        .long   0xe0500020       /* Characteristics (section flags) */
> +        .align  5
>  real_start:
>          msr   DAIFSet, 0xf           /* Disable all interrupts */
>  
> @@ -617,6 +730,37 @@ putn:   ret
>  ENTRY(lookup_processor_type)
>          mov  x0, #0
>          ret
> +/*
> + *  Function to transition from EFI loader in C, to Xen entry point.
> + *  void noreturn efi_xen_start(void *fdt_ptr);
> + */
> +ENTRY(efi_xen_start)
> +        /*
> +         * Turn off cache and MMU as Xen expects. EFI enables them, but also
> +         * mandates a 1:1 (unity) VA->PA mapping, so we can turn off the
> +         * MMU while executing EFI code before entering Xen.
> +         * The EFI loader calls this to start Xen.
> +         * Preserve x0 (fdf pointer) across call to __flush_dcache_all,
> +         * restore for entry into Xen.
> +         */
> +        mov   x20, x0
> +        bl    __flush_dcache_all
> +        ic    ialluis
> +
> +        /* Turn off Dcache and MMU */
> +        mrs   x0, sctlr_el2
> +        bic   x0, x0, #1 << 0        /* clear SCTLR.M */
> +        bic   x0, x0, #1 << 2        /* clear SCTLR.C */

dsb?


> +        msr   sctlr_el2, x0
> +        isb
> +
> +        /* Jump to Xen entry point */
> +        mov   x0, x20
> +        mov   x1, xzr
> +        mov   x2, xzr
> +        mov   x3, xzr
> +        b     real_start
> +ENDPROC(efi_xen_start)
>  
>  /*
>   * Local variables:
> diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S
> index 079e085..d8b0cfe 100644
> --- a/xen/arch/arm/xen.lds.S
> +++ b/xen/arch/arm/xen.lds.S
> @@ -135,6 +135,7 @@ SECTIONS
>         *(.xsm_initcall.init)
>         __xsm_initcall_end = .;
>    } :text
> +  __init_end_efi = .;
>    . = ALIGN(STACK_SIZE);
>    __init_end = .;
>  
> diff --git a/xen/common/Makefile b/xen/common/Makefile
> index 3683ae3..e78cb29 100644
> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -67,4 +67,5 @@ subdir-$(x86_64) += hvm
>  subdir-$(coverage) += gcov
>  
>  subdir-y += libelf
> +subdir-$(CONFIG_EFI) += efi
>  subdir-$(HAS_DEVICE_TREE) += libfdt
> diff --git a/xen/common/efi/Makefile b/xen/common/efi/Makefile
> new file mode 100644
> index 0000000..195b2f3
> --- /dev/null
> +++ b/xen/common/efi/Makefile
> @@ -0,0 +1,3 @@
> +CFLAGS += -fshort-wchar
> +
> +obj-y += boot.init.o
> diff --git a/xen/include/asm-arm/arm64/efibind.h 
> b/xen/include/asm-arm/arm64/efibind.h
> new file mode 100644
> index 0000000..2b0bf40
> --- /dev/null
> +++ b/xen/include/asm-arm/arm64/efibind.h
> @@ -0,0 +1,216 @@
> +/*++
> +
> +Copyright (c) 1998  Intel Corporation
> +
> +Module Name:
> +
> +    efefind.h
> +
> +Abstract:
> +
> +    EFI to compile bindings
> +
> +
> +
> +
> +Revision History
> +
> +--*/
> +
> +#ifndef __GNUC__
> +#pragma pack()
> +#endif
> +
> +#define EFIERR(a)           (0x8000000000000000 | a)
> +#define EFI_ERROR_MASK      0x8000000000000000
> +#define EFIERR_OEM(a)       (0xc000000000000000 | a)
> +
> +#define BAD_POINTER         0xFBFBFBFBFBFBFBFB
> +#define MAX_ADDRESS         0xFFFFFFFFFFFFFFFF
> +
> +#define EFI_STUB_ERROR      MAX_ADDRESS
> +
> +#ifndef __ASSEMBLY__
> +//
> +// Basic int types of various widths
> +//
> +
> +#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L )
> +
> +    // No ANSI C 1999/2000 stdint.h integer width declarations
> +
> +    #if defined(__GNUC__)
> +        typedef unsigned long long  uint64_t __attribute__((aligned (8)));
> +        typedef long long           int64_t __attribute__((aligned (8)));
> +        typedef unsigned int        uint32_t;
> +        typedef int                 int32_t;
> +        typedef unsigned short      uint16_t;
> +        typedef short               int16_t;
> +        typedef unsigned char       uint8_t;
> +        typedef char                int8_t;
> +    #elif defined(UNIX_LP64)
> +
> +        /*  Use LP64 programming model from C_FLAGS for integer width 
> declarations */
> +
> +       typedef unsigned long       uint64_t;
> +       typedef long                int64_t;
> +       typedef unsigned int        uint32_t;
> +       typedef int                 int32_t;
> +       typedef unsigned short      uint16_t;
> +       typedef short               int16_t;
> +       typedef unsigned char       uint8_t;
> +       typedef char                int8_t;
> +    #else
> +
> +       /*  Assume P64 programming model from C_FLAGS for integer width 
> declarations */
> +
> +       typedef unsigned long long  uint64_t __attribute__((aligned (8)));
> +       typedef long long           int64_t __attribute__((aligned (8)));
> +       typedef unsigned int        uint32_t;
> +       typedef int                 int32_t;
> +       typedef unsigned short      uint16_t;
> +       typedef short               int16_t;
> +       typedef unsigned char       uint8_t;
> +       typedef char                int8_t;
> +    #endif
> +#endif
> +
> +//
> +// Basic EFI types of various widths
> +//
> +
> +#ifndef __WCHAR_TYPE__
> +# define __WCHAR_TYPE__ short
> +#endif
> +
> +typedef uint64_t   UINT64;
> +typedef int64_t    INT64;
> +
> +#ifndef _BASETSD_H_
> +    typedef uint32_t   UINT32;
> +    typedef int32_t    INT32;
> +#endif
> +
> +typedef uint16_t   UINT16;
> +typedef int16_t    INT16;
> +typedef uint8_t    UINT8;
> +typedef int8_t     INT8;
> +typedef __WCHAR_TYPE__ WCHAR;
> +
> +#undef VOID
> +#define VOID    void
> +
> +
> +typedef int64_t    INTN;
> +typedef uint64_t   UINTN;
> +
> +#define POST_CODE(_Data)
> +
> +
> +#define BREAKPOINT()        while (TRUE);    // Make it hang on Bios[Dbg]32
> +
> +//
> +// Pointers must be aligned to these address to function
> +//
> +
> +#define MIN_ALIGNMENT_SIZE  4
> +
> +#define ALIGN_VARIABLE(Value ,Adjustment) \
> +            (UINTN)Adjustment = 0; \
> +            if((UINTN)Value % MIN_ALIGNMENT_SIZE) \
> +                (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % 
> MIN_ALIGNMENT_SIZE); \
> +            Value = (UINTN)Value + (UINTN)Adjustment
> +
> +
> +//
> +// Define macros to build data structure signatures from characters.
> +//
> +
> +#define EFI_SIGNATURE_16(A,B)             ((A) | (B<<8))
> +#define EFI_SIGNATURE_32(A,B,C,D)         (EFI_SIGNATURE_16(A,B)     | 
> (EFI_SIGNATURE_16(C,D)     << 16))
> +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | 
> ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32))
> +
> +#define EXPORTAPI
> +
> +
> +//
> +// EFIAPI - prototype calling convention for EFI function pointers
> +// BOOTSERVICE - prototype for implementation of a boot service interface
> +// RUNTIMESERVICE - prototype for implementation of a runtime service 
> interface
> +// RUNTIMEFUNCTION - prototype for implementation of a runtime function that 
> is not a service
> +// RUNTIME_CODE - pragma macro for declaring runtime code
> +//
> +
> +#ifndef EFIAPI                  // Forces EFI calling conventions 
> reguardless of compiler options
> +        #define EFIAPI          // Substitute expresion to force C calling 
> convention
> +#endif
> +
> +#define BOOTSERVICE
> +//#define RUNTIMESERVICE(proto,a)    alloc_text("rtcode",a); proto a
> +//#define RUNTIMEFUNCTION(proto,a)   alloc_text("rtcode",a); proto a
> +#define RUNTIMESERVICE
> +#define RUNTIMEFUNCTION
> +
> +
> +#define RUNTIME_CODE(a)         alloc_text("rtcode", a)
> +#define BEGIN_RUNTIME_DATA()    data_seg("rtdata")
> +#define END_RUNTIME_DATA()      data_seg("")
> +
> +#define VOLATILE    volatile
> +
> +#define MEMORY_FENCE()
> +
> +
> +//
> +// When build similiar to FW, then link everything together as
> +// one big module.
> +//
> +
> +#define EFI_DRIVER_ENTRY_POINT(InitFunction)    \
> +    UINTN                                       \
> +    InitializeDriver (                          \
> +        VOID    *ImageHandle,                   \
> +        VOID    *SystemTable                    \
> +        )                                       \
> +    {                                           \
> +        return InitFunction(ImageHandle,        \
> +                SystemTable);                   \
> +    }                                           \
> +                                                \
> +    EFI_STATUS efi_main(                        \
> +        EFI_HANDLE image,                       \
> +        EFI_SYSTEM_TABLE *systab                \
> +        ) __attribute__((weak,                  \
> +                alias ("InitializeDriver")));
> +
> +#define LOAD_INTERNAL_DRIVER(_if, type, name, entry)    \
> +        (_if)->LoadInternal(type, name, entry)
> +
> +
> +//
> +// Some compilers don't support the forward reference construct:
> +//  typedef struct XXXXX
> +//
> +// The following macro provide a workaround for such cases.
> +//
> +#ifdef NO_INTERFACE_DECL
> +#define INTERFACE_DECL(x)
> +#else
> +#ifdef __GNUC__
> +#define INTERFACE_DECL(x) struct x
> +#else
> +#define INTERFACE_DECL(x) typedef struct x
> +#endif
> +#endif
> +
> +#endif
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/asm-arm/efi-boot.h b/xen/include/asm-arm/efi-boot.h
> new file mode 100644
> index 0000000..2db0966
> --- /dev/null
> +++ b/xen/include/asm-arm/efi-boot.h
> @@ -0,0 +1,630 @@
> +/*
> + * Architecture specific implementation for EFI boot code.  This file
> + * is intended to be included by XXX _only_, and therefore can define
> + * arch specific global variables.
> + */
> +#include <xen/libfdt/libfdt.h>
> +#include <asm/setup.h>
> +
> +static void noreturn blexit(const CHAR16 *str);
> +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode);
> +void noreturn efi_xen_start(void *fdt_ptr);
> +
> +#define DEVICE_TREE_GUID \
> +{0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 
> 0xe0}}
> +
> +static struct file __initdata dtbfile;
> +static void __initdata *fdt;
> +static void __initdata *memmap;
> +
> +static int __init 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 )
> +    {
> +        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 )
> +    {
> +        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 )
> +    {
> +        val = cpu_to_fdt32(0);
> +        if ( fdt_setprop(fdt, node, "ranges", &val, 0) )
> +            return -1;
> +    }
> +    else if ( fdt32_to_cpu(prop->len) )
> +            return -1;  /* Non-empty ranges property */
> +    return node;
> +}
> +
> +/*
> + * Set a single 'reg' property taking into account the
> + * configured addr and size cell sizes.
> + */
> +static int __init 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));
> +}
> +
> +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 = NULL;
> +    int i;
> +
> +    tables = sys_table->ConfigurationTable;
> +    for ( i = 0; i < sys_table->NumberOfTableEntries; i++ )
> +    {
> +        if ( match_guid(&tables[i].VendorGuid, &fdt_guid) )
> +        {
> +            fdt = tables[i].VendorTable;
> +            break;
> +        }
> +    }
> +    return fdt;
> +}
> +
> +static EFI_STATUS __init efi_get_memory_map(void **map,
> +                                            UINTN *mmap_size,
> +                                            UINTN *desc_size,
> +                                            UINT32 *desc_ver,
> +                                            UINTN *key_ptr)
> +{
> +    EFI_MEMORY_DESCRIPTOR *m = NULL;
> +    EFI_STATUS status;
> +    unsigned long key;
> +    u32 desc_version;
> +
> +    *map = NULL;
> +    *mmap_size = EFI_PAGE_SIZE;
> +again:
> +    *mmap_size += EFI_PAGE_SIZE;  /* Page size is allocation granularity */
> +    status = efi_bs->AllocatePool(EfiLoaderData, *mmap_size, (void **)&m);
> +    if ( status != EFI_SUCCESS )
> +        return status;
> +
> +    *desc_size = 0;
> +    key = 0;
> +    status = efi_bs->GetMemoryMap(mmap_size, m, &key, desc_size, 
> &desc_version);
> +    if ( status == EFI_BUFFER_TOO_SMALL )
> +    {
> +        efi_bs->FreePool(m);
> +        goto again;
> +    }
> +
> +    if ( status != EFI_SUCCESS )
> +    {
> +        efi_bs->FreePool(m);
> +        return status;
> +    }
> +
> +    if ( key_ptr && status == EFI_SUCCESS )
> +        *key_ptr = key;
> +    if ( desc_ver && status == EFI_SUCCESS )
> +        *desc_ver = desc_version;
> +
> +    *map = m;
> +    return status;
> +}
> +
> +static EFI_STATUS __init 
> efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *map,
> +                                                UINTN mmap_size,
> +                                                UINTN desc_size)
> +{
> +    int Index;
> +    int i = 0;
> +
> +    EFI_MEMORY_DESCRIPTOR *desc_ptr = map;
> +
> +    for ( Index = 0; Index < (mmap_size / desc_size); Index++ )
> +    {
> +        if ( desc_ptr->Type == EfiConventionalMemory
> +             || desc_ptr->Type == EfiBootServicesCode
> +             || desc_ptr->Type == EfiBootServicesData )
> +        {
> +            bootinfo.mem.bank[i].start = desc_ptr->PhysicalStart;
> +            bootinfo.mem.bank[i].size = desc_ptr->NumberOfPages * 
> EFI_PAGE_SIZE;
> +            if ( ++i >= NR_MEM_BANKS )
> +            {
> +                PrintStr(L"Warning: All ");
> +                DisplayUint(NR_MEM_BANKS, -1);
> +                PrintStr(L" bootinfo mem banks exhausted.\r\n");
> +                break;
> +            }
> +        }
> +        desc_ptr = NextMemoryDescriptor(desc_ptr, desc_size);
> +    }
> +
> +    bootinfo.mem.nr_banks = i;
> +    return EFI_SUCCESS;
> +
> +}
> +
> +/*
> + * 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.
> + */
> +EFI_STATUS __init fdt_add_uefi_nodes(EFI_SYSTEM_TABLE *sys_table,
> +                                            void *fdt,
> +                                            EFI_MEMORY_DESCRIPTOR 
> *memory_map,
> +                                            UINTN map_size,
> +                                            UINTN desc_size,
> +                                            UINT32 desc_ver)
> +{
> +    int node;
> +    int status;
> +    u32 fdt_val32;
> +    u64 fdt_val64;
> +    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;
> +    }
> +
> +    /* Add FDT entries for EFI runtime services in chosen node. */
> +    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;
> +        }
> +    }

setup_chosen_node?


> +    fdt_val64 = cpu_to_fdt64((u64)(uintptr_t)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)(uintptr_t)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
> +        fdt_size = 0;
> +
> +    pages = PFN_UP(fdt_size) + PFN_UP(add_size);

Shouldn't this be PFN_UP(fdt_size+add_size)?


> +    status = efi_bs->AllocatePages(AllocateAnyPages, EfiLoaderData,
> +                                   pages, &fdt_addr);
> +
> +    if ( status != EFI_SUCCESS )
> +        return NULL;
> +
> +    new_fdt = (void *)fdt_addr;
> +
> +    if ( fdt_size )
> +    {
> +        if ( fdt_open_into(dtbfile.ptr, new_fdt, pages * EFI_PAGE_SIZE) )
> +            return NULL;
> +    }
> +    else
> +    {
> +        /*
> +         * Create an empty FDT if not provided one, which is the expected 
> case
> +         * when booted from the UEFI shell on an ACPI only system.  We will 
> use
> +         * the FDT to pass the EFI information to Xen, as well as nodes for
> +         * any modules the stub loads.  The ACPI tables are part of the UEFI
> +         * system table that is passed in the FDT.
> +         */
> +        if ( fdt_create_empty_tree(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 ( dtbfile.size )
> +        efi_bs->FreePages(dtbfile.addr, PFN_UP(dtbfile.size));
> +
> +    /* Update 'file' info for new memory so we clean it up on error exits */
> +    dtbfile.addr = fdt_addr;
> +    dtbfile.size = pages * EFI_PAGE_SIZE;
> +    return new_fdt;
> +}
> +
> +static void __init efi_arch_pci(void)
> +{
> +}
> +
> +static void __init efi_arch_relocate_image(unsigned long delta)
> +{
> +}
> +
> +static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable,
> +                                               void *map,
> +                                               UINTN map_size,
> +                                               UINTN desc_size,
> +                                               UINT32 desc_ver)
> +{
> +    EFI_STATUS status;
> +
> +    status = efi_process_memory_map_bootinfo(map, map_size, desc_size);
> +    if ( EFI_ERROR(status) )
> +        blexit(L"ERROR processing EFI memory map\r\n");
> +
> +    status = fdt_add_uefi_nodes(SystemTable, fdt, map, map_size, desc_size,
> +                                desc_ver);
> +    if ( EFI_ERROR(status) )
> +        PrintErrMesg(L"ERROR updating FDT\r\n", status);
> +}
> +
> +static void __init efi_arch_pre_exit_boot(void)
> +{
> +}
> +
> +static void __init efi_arch_post_exit_boot(void)
> +{
> +    efi_xen_start(fdt);
> +}
> +
> +static void __init efi_arch_cfg_file(EFI_FILE_HANDLE dir_handle, char 
> *section)
> +{
> +    union string name;
> +    name.s = get_value(&cfg, section, "dtb");
> +    if ( name.s )
> +    {
> +        if ( !read_file(dir_handle, &dtbfile, name.s))
> +            blexit(NULL);
> +    }
> +    fdt = fdt_increase_size(&dtbfile, cfg.size + EFI_PAGE_SIZE);
> +    if ( !fdt )
> +        blexit(L"Unable to create new FDT\r\n");
> +}
> +
> +static void __init efi_arch_get_memory_map(UINTN *map_size,
> +                                             void **map,
> +                                             UINTN *map_key, UINTN 
> *desc_size,
> +                                             UINT32 *desc_ver)
> +{
> +    EFI_STATUS status;
> +
> +    status = efi_get_memory_map(map, map_size, desc_size, desc_ver, map_key);
> +    if ( EFI_ERROR(status) )
> +        blexit(L"ERROR getting EFI memory map.\r\n");
> +    memmap = *map;
> +}
> +
> +static void __init efi_arch_edd(void)
> +{
> +}
> +
> +static void __init efi_arch_video(bool_t base_video,
> +                                  UINTN cols, UINTN rows, UINTN depth,
> +                                  EFI_GRAPHICS_OUTPUT_PROTOCOL *gop)
> +{
> +}
> +
> +static void __init efi_arch_memory(void)
> +{
> +}
> +
> +static void __init efi_arch_handle_cmdline(CHAR16 *image_name,
> +                                           CHAR16 *cmdline_options,
> +                                           char *cfgfile_options)
> +{
> +    union string name;
> +    char *buf;
> +    EFI_STATUS status;
> +    int prop_len;
> +    int chosen;
> +
> +    /* locate chosen node, which is where we add Xen module info. */
> +    chosen = fdt_subnode_offset(fdt, 0, "chosen");
> +    if ( chosen < 0 )
> +        blexit(L"ERROR unable to find chosen node\r\n");
> +
> +    status = efi_bs->AllocatePool(EfiBootServicesData, EFI_PAGE_SIZE, (void 
> **)&buf);
> +    if ( EFI_ERROR(status) )
> +        PrintErrMesg(L"ERROR allocating memory.\r\n", status);
> +
> +    if ( image_name )
> +    {
> +        name.w = image_name;
> +        w2s(&name);
> +    }
> +    else
> +        name.s = "xen";
> +
> +    prop_len = 0;
> +    prop_len += snprintf(buf + prop_len,
> +                           EFI_PAGE_SIZE - prop_len, "%s", name.s);
> +    if ( prop_len >= EFI_PAGE_SIZE )
> +        blexit(L"FDT string overflow");
> +
> +    if ( cfgfile_options )
> +    {
> +        prop_len += snprintf(buf + prop_len,
> +                               EFI_PAGE_SIZE - prop_len, " %s", 
> cfgfile_options);
> +        if ( prop_len >= EFI_PAGE_SIZE )
> +            blexit(L"FDT string overflow");
> +    }
> +
> +    if ( cmdline_options )
> +    {
> +        name.w = cmdline_options;
> +        w2s(&name);
> +    }
> +    else
> +        name.s = NULL;
> +
> +    if ( name.s )
> +    {
> +        prop_len += snprintf(buf + prop_len,
> +                               EFI_PAGE_SIZE - prop_len, " %s", name.s);
> +        if ( prop_len >= EFI_PAGE_SIZE )
> +            blexit(L"FDT string overflow");
> +    }
> +
> +    if ( fdt_setprop_string(fdt, chosen, "xen,xen-bootargs", buf) < 0 )
> +        blexit(L"unable to set xen,xen-bootargs property.");
> +
> +    efi_bs->FreePool(buf);
> +}
> +
> +static void __init efi_arch_handle_module(struct file *file, char *name,
> +                                          char *options)
> +{
> +    int node;
> +    int chosen;
> +    int addr_len, size_len;
> +
> +    if ( file == &dtbfile )
> +        return;
> +    chosen = setup_chosen_node(fdt, &addr_len, &size_len);
> +    if ( chosen < 0 )
> +        blexit(L"Unable to setup chosen node\r\n");
> +
> +    if ( file == &ramdisk )
> +    {
> +        char ramdisk_compat[] = "multiboot,ramdisk\0multiboot,module";
> +        node = fdt_add_subnode(fdt, chosen, "ramdisk");
> +        if ( node < 0 )
> +            blexit(L"Error adding ramdisk FDT node.");
> +        if ( fdt_setprop(fdt, node, "compatible", ramdisk_compat,
> +                         sizeof(ramdisk_compat)) < 0 )
> +            blexit(L"unable to set compatible property.");
> +        if ( fdt_set_reg(fdt, node, addr_len, size_len, ramdisk.addr,
> +                    ramdisk.size) < 0 )
> +            blexit(L"unable to set reg property.");
> +    }
> +    else if ( file == &xsm )
> +    {
> +        char xsm_compat[] = "xen,xsm-policy\0multiboot,module";
> +        node = fdt_add_subnode(fdt, chosen, "xsm");
> +        if ( node < 0 )
> +            blexit(L"Error adding xsm FDT node.");
> +        if ( fdt_setprop(fdt, node, "compatible", xsm_compat,
> +                         sizeof(xsm_compat)) < 0 )
> +            blexit(L"unable to set compatible property.");
> +        if ( fdt_set_reg(fdt, node, addr_len, size_len, xsm.addr,
> +                    xsm.size) < 0 )
> +            blexit(L"unable to set reg property.");
> +    }
> +    else if ( file == &kernel )
> +    {
> +        char kernel_compat[] = "multiboot,kernel\0multiboot,module";
> +        node = fdt_add_subnode(fdt, chosen, "kernel");
> +        if ( node < 0 )
> +            blexit(L"Error adding dom0 FDT node.");
> +        if ( fdt_setprop(fdt, node, "compatible", kernel_compat,
> +                         sizeof(kernel_compat)) < 0 )
> +            blexit(L"unable to set compatible property.");
> +        if ( options && fdt_setprop_string(fdt, node, "bootargs", options) < 
> 0 )
> +            blexit(L"unable to set bootargs property.");
> +        if ( fdt_set_reg(fdt, node, addr_len, size_len, kernel.addr,
> +                         kernel.size) < 0 )
> +            blexit(L"unable to set reg property.");
> +    }
> +    else
> +        blexit(L"Unknown module type\r\n");
> +}
> +
> +static void __init efi_arch_cpu(void)
> +{
> +}
> +
> +static void __init efi_arch_smbios(void)
> +{
> +}
> +
> +static void __init efi_arch_blexit(void)
> +{
> +    if ( dtbfile.addr && dtbfile.size )
> +        efi_bs->FreePages(dtbfile.addr, PFN_UP(dtbfile.size));
> +    if ( memmap )
> +        efi_bs->FreePool(memmap);
> +}
> +
> +static void __init efi_arch_load_addr_check(EFI_LOADED_IMAGE *loaded_image)
> +{
> +    if ( (unsigned long)loaded_image->ImageBase & ((1 << 12) - 1) )
> +        blexit(L"Xen must be loaded at a 4 KByte boundary.");
> +}
> +
> +static void __init efi_arch_runtime_setup(EFI_SYSTEM_TABLE *SystemTable)
> +{
> +}
> +
> +static __init bool_t efi_arch_use_config_file(EFI_SYSTEM_TABLE *SystemTable)
> +{
> +    /*
> +     * For arm, we may get a device tree from GRUB (or other bootloader)
> +     * that contains modules that have already been loaded into memory.  In
> +     * this case, we do not use a configuration file, and rely on the
> +     * bootloader to have loaded all required modules and appropriate
> +     * options.
> +     */
> +
> +    fdt = lookup_fdt_config_table(SystemTable);
> +    dtbfile.ptr = fdt;
> +    dtbfile.size = 0;  /* Config table memory can't be freed, so set size to 
> 0 */
> +    if ( !fdt || fdt_node_offset_by_compatible(fdt, 0, "multiboot,module") < 
> 0 )
> +    {
> +        /*
> +         * We either have no FDT, or one without modules, so we must have a
> +         * Xen EFI configuration file to specify modules.  (dom0 required)
> +         */
> +        return 1;
> +    }
> +    PrintStr(L"Using modules provided by bootloader in FDT\r\n");
> +    /* We have modules already defined in fdt, just add space. */
> +    fdt = fdt_increase_size(&dtbfile, EFI_PAGE_SIZE);
> +    return 0;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/asm-arm/efi.h b/xen/include/asm-arm/efi.h
> new file mode 100644
> index 0000000..aae4716
> --- /dev/null
> +++ b/xen/include/asm-arm/efi.h
> @@ -0,0 +1,29 @@
> +#include <asm/efibind.h>
> +#include <efi/efidef.h>
> +#include <efi/efierr.h>
> +#include <efi/eficon.h>
> +#include <efi/efidevp.h>
> +#include <efi/eficapsule.h>
> +#include <efi/efiapi.h>
> +#include <xen/efi.h>
> +#include <xen/spinlock.h>
> +#include <asm/page.h>
> +
> +extern unsigned int efi_num_ct;
> +extern EFI_CONFIGURATION_TABLE *efi_ct;
> +
> +extern unsigned int efi_version, efi_fw_revision;
> +extern const CHAR16 *efi_fw_vendor;
> +
> +extern EFI_RUNTIME_SERVICES *efi_rs;
> +
> +extern UINTN efi_memmap_size, efi_mdesc_size;
> +extern void *efi_memmap;
> +
> +extern const struct efi_pci_rom *efi_pci_roms;
> +
> +extern UINT64 efi_boot_max_var_store_size, efi_boot_remain_var_store_size,
> +              efi_boot_max_var_size;
> +
> +unsigned long efi_rs_enter(void);
> +void efi_rs_leave(unsigned long);
> diff --git a/xen/include/asm-arm/efibind.h b/xen/include/asm-arm/efibind.h
> new file mode 100644
> index 0000000..09dca7a
> --- /dev/null
> +++ b/xen/include/asm-arm/efibind.h
> @@ -0,0 +1,2 @@
> +#include <xen/types.h>
> +#include <asm/arm64/efibind.h>
> diff --git a/xen/include/asm-arm/setup.h b/xen/include/asm-arm/setup.h
> index 36e5704..40814e6 100644
> --- a/xen/include/asm-arm/setup.h
> +++ b/xen/include/asm-arm/setup.h
> @@ -3,7 +3,7 @@
>  
>  #include <public/version.h>
>  
> -#define NR_MEM_BANKS 8
> +#define NR_MEM_BANKS 32

Why?
At the very least you should write it in the commit message.


>  #define MAX_MODULES 5 /* Current maximum useful modules */
>  
> -- 
> 2.1.0.rc1
> 

_______________________________________________
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®.