[U-Boot] [PATCH 3/9] efi_loader: Add PE image loader

Leif Lindholm leif.lindholm at linaro.org
Sat Dec 26 17:26:33 CET 2015


On Tue, Dec 22, 2015 at 02:57:50PM +0100, Alexander Graf wrote:
> EFI uses the PE binary format for its application images. Add support to EFI PE
> binaries as well as all necessary bits for the "EFI image loader" interfaces.
> 
> Signed-off-by: Alexander Graf <agraf at suse.de>
> ---
>  include/efi_loader.h              |  37 +++++
>  include/pe.h                      | 277 ++++++++++++++++++++++++++++++++++++++
>  lib/efi_loader/efi_image_loader.c | 203 ++++++++++++++++++++++++++++
>  3 files changed, 517 insertions(+)
>  create mode 100644 include/efi_loader.h
>  create mode 100644 include/pe.h
>  create mode 100644 lib/efi_loader/efi_image_loader.c
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> new file mode 100644
> index 0000000..da82354
> --- /dev/null
> +++ b/include/efi_loader.h
> @@ -0,0 +1,37 @@
> +/*
> + *  EFI application loader
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#include <part_efi.h>
> +#include <efi_api.h>
> +#include <linux/list.h>
> +
> +extern const efi_guid_t efi_guid_device_path;
> +extern const efi_guid_t efi_guid_loaded_image;
> +
> +efi_status_t efi_return_handle(void *handle,
> +		efi_guid_t *protocol, void **protocol_interface,
> +		void *agent_handle, void *controller_handle,
> +		uint32_t attributes);
> +void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
> +
> +#define EFI_LOADER_POOL_SIZE (128 * 1024 * 1024)
> +void *efi_loader_alloc(uint64_t len);
> diff --git a/include/pe.h b/include/pe.h
> new file mode 100644
> index 0000000..009b0c5
> --- /dev/null
> +++ b/include/pe.h
> @@ -0,0 +1,277 @@
> +/*
> + *  Portable Executable binary format structures
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  Based on wine code
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#ifndef _PE_H
> +#define _PE_H
> +
> +typedef struct _IMAGE_DOS_HEADER {
> +	uint16_t e_magic;      /* 00: MZ Header signature */
> +	uint16_t e_cblp;       /* 02: Bytes on last page of file */
> +	uint16_t e_cp;         /* 04: Pages in file */
> +	uint16_t e_crlc;       /* 06: Relocations */
> +	uint16_t e_cparhdr;    /* 08: Size of header in paragraphs */
> +	uint16_t e_minalloc;   /* 0a: Minimum extra paragraphs needed */
> +	uint16_t e_maxalloc;   /* 0c: Maximum extra paragraphs needed */
> +	uint16_t e_ss;         /* 0e: Initial (relative) SS value */
> +	uint16_t e_sp;         /* 10: Initial SP value */
> +	uint16_t e_csum;       /* 12: Checksum */
> +	uint16_t e_ip;         /* 14: Initial IP value */
> +	uint16_t e_cs;         /* 16: Initial (relative) CS value */
> +	uint16_t e_lfarlc;     /* 18: File address of relocation table */
> +	uint16_t e_ovno;       /* 1a: Overlay number */
> +	uint16_t e_res[4];     /* 1c: Reserved words */
> +	uint16_t e_oemid;      /* 24: OEM identifier (for e_oeminfo) */
> +	uint16_t e_oeminfo;    /* 26: OEM information; e_oemid specific */
> +	uint16_t e_res2[10];   /* 28: Reserved words */
> +	uint32_t e_lfanew;     /* 3c: Offset to extended header */
> +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
> +
> +#define IMAGE_DOS_SIGNATURE		0x5A4D     /* MZ   */
> +#define IMAGE_NT_SIGNATURE		0x00004550 /* PE00 */
> +
> +#define IMAGE_FILE_MACHINE_ARM		0x01c0
> +#define IMAGE_FILE_MACHINE_THUMB	0x01c2
> +#define IMAGE_FILE_MACHINE_ARMNT	0x01c4
> +#define IMAGE_FILE_MACHINE_AMD64	0x8664
> +#define IMAGE_FILE_MACHINE_ARM64	0xaa64
> +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC	0x10b
> +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC	0x20b
> +#define IMAGE_SUBSYSTEM_EFI_APPLICATION	10
> +
> +typedef struct _IMAGE_FILE_HEADER {
> +	uint16_t  Machine;
> +	uint16_t  NumberOfSections;
> +	uint32_t TimeDateStamp;
> +	uint32_t PointerToSymbolTable;
> +	uint32_t NumberOfSymbols;
> +	uint16_t  SizeOfOptionalHeader;
> +	uint16_t  Characteristics;
> +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
> +
> +typedef struct _IMAGE_DATA_DIRECTORY {
> +	uint32_t VirtualAddress;
> +	uint32_t Size;
> +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
> +
> +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
> +
> +typedef struct _IMAGE_OPTIONAL_HEADER64 {
> +	uint16_t  Magic; /* 0x20b */
> +	uint8_t MajorLinkerVersion;
> +	uint8_t MinorLinkerVersion;
> +	uint32_t SizeOfCode;
> +	uint32_t SizeOfInitializedData;
> +	uint32_t SizeOfUninitializedData;
> +	uint32_t AddressOfEntryPoint;
> +	uint32_t BaseOfCode;
> +	uint64_t ImageBase;
> +	uint32_t SectionAlignment;
> +	uint32_t FileAlignment;
> +	uint16_t MajorOperatingSystemVersion;
> +	uint16_t MinorOperatingSystemVersion;
> +	uint16_t MajorImageVersion;
> +	uint16_t MinorImageVersion;
> +	uint16_t MajorSubsystemVersion;
> +	uint16_t MinorSubsystemVersion;
> +	uint32_t Win32VersionValue;
> +	uint32_t SizeOfImage;
> +	uint32_t SizeOfHeaders;
> +	uint32_t CheckSum;
> +	uint16_t Subsystem;
> +	uint16_t DllCharacteristics;
> +	uint64_t SizeOfStackReserve;
> +	uint64_t SizeOfStackCommit;
> +	uint64_t SizeOfHeapReserve;
> +	uint64_t SizeOfHeapCommit;
> +	uint32_t LoaderFlags;
> +	uint32_t NumberOfRvaAndSizes;
> +	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
> +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
> +
> +typedef struct _IMAGE_NT_HEADERS64 {
> +	uint32_t Signature;
> +	IMAGE_FILE_HEADER FileHeader;
> +	IMAGE_OPTIONAL_HEADER64 OptionalHeader;
> +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
> +
> +typedef struct _IMAGE_OPTIONAL_HEADER {
> +
> +	/* Standard fields */
> +
> +	uint16_t  Magic; /* 0x10b or 0x107 */     /* 0x00 */
> +	uint8_t  MajorLinkerVersion;
> +	uint8_t  MinorLinkerVersion;
> +	uint32_t SizeOfCode;
> +	uint32_t SizeOfInitializedData;
> +	uint32_t SizeOfUninitializedData;
> +	uint32_t AddressOfEntryPoint;            /* 0x10 */
> +	uint32_t BaseOfCode;
> +	uint32_t BaseOfData;
> +
> +	/* NT additional fields */
> +
> +	uint32_t ImageBase;
> +	uint32_t SectionAlignment;               /* 0x20 */
> +	uint32_t FileAlignment;
> +	uint16_t  MajorOperatingSystemVersion;
> +	uint16_t  MinorOperatingSystemVersion;
> +	uint16_t  MajorImageVersion;
> +	uint16_t  MinorImageVersion;
> +	uint16_t  MajorSubsystemVersion;          /* 0x30 */
> +	uint16_t  MinorSubsystemVersion;
> +	uint32_t Win32VersionValue;
> +	uint32_t SizeOfImage;
> +	uint32_t SizeOfHeaders;
> +	uint32_t CheckSum;                       /* 0x40 */
> +	uint16_t  Subsystem;
> +	uint16_t  DllCharacteristics;
> +	uint32_t SizeOfStackReserve;
> +	uint32_t SizeOfStackCommit;
> +	uint32_t SizeOfHeapReserve;              /* 0x50 */
> +	uint32_t SizeOfHeapCommit;
> +	uint32_t LoaderFlags;
> +	uint32_t NumberOfRvaAndSizes;
> +	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */
> +	/* 0xE0 */
> +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
> +
> +typedef struct _IMAGE_NT_HEADERS {
> +	uint32_t Signature; /* "PE"\0\0 */       /* 0x00 */
> +	IMAGE_FILE_HEADER FileHeader;         /* 0x04 */
> +	IMAGE_OPTIONAL_HEADER32 OptionalHeader;       /* 0x18 */
> +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
> +
> +#define IMAGE_SIZEOF_SHORT_NAME 8
> +
> +typedef struct _IMAGE_SECTION_HEADER {
> +	uint8_t	Name[IMAGE_SIZEOF_SHORT_NAME];
> +	union {
> +		uint32_t PhysicalAddress;
> +		uint32_t VirtualSize;
> +	} Misc;
> +	uint32_t VirtualAddress;
> +	uint32_t SizeOfRawData;
> +	uint32_t PointerToRawData;
> +	uint32_t PointerToRelocations;
> +	uint32_t PointerToLinenumbers;
> +	uint16_t	NumberOfRelocations;
> +	uint16_t	NumberOfLinenumbers;
> +	uint32_t Characteristics;
> +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
> +
> +#define IMAGE_DIRECTORY_ENTRY_BASERELOC         5
> +
> +typedef struct _IMAGE_BASE_RELOCATION
> +{
> +        uint32_t VirtualAddress;
> +        uint32_t SizeOfBlock;
> +        /* WORD TypeOffset[1]; */
> +} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
> +
> +typedef struct _IMAGE_RELOCATION
> +{
> +	union {
> +		uint32_t   VirtualAddress;
> +		uint32_t   RelocCount;
> +	} DUMMYUNIONNAME;
> +	uint32_t   SymbolTableIndex;
> +	uint16_t	Type;
> +} IMAGE_RELOCATION, *PIMAGE_RELOCATION;
> +
> +#define IMAGE_SIZEOF_RELOCATION 10
> +
> +/* generic relocation types */
> +#define IMAGE_REL_BASED_ABSOLUTE                0
> +#define IMAGE_REL_BASED_HIGH                    1
> +#define IMAGE_REL_BASED_LOW                     2
> +#define IMAGE_REL_BASED_HIGHLOW                 3
> +#define IMAGE_REL_BASED_HIGHADJ                 4
> +#define IMAGE_REL_BASED_MIPS_JMPADDR            5
> +#define IMAGE_REL_BASED_ARM_MOV32A              5 /* yes, 5 too */
> +#define IMAGE_REL_BASED_ARM_MOV32               5 /* yes, 5 too */
> +#define IMAGE_REL_BASED_SECTION                 6
> +#define IMAGE_REL_BASED_REL                     7
> +#define IMAGE_REL_BASED_ARM_MOV32T              7 /* yes, 7 too */
> +#define IMAGE_REL_BASED_THUMB_MOV32             7 /* yes, 7 too */
> +#define IMAGE_REL_BASED_MIPS_JMPADDR16          9
> +#define IMAGE_REL_BASED_IA64_IMM64              9 /* yes, 9 too */
> +#define IMAGE_REL_BASED_DIR64                   10
> +#define IMAGE_REL_BASED_HIGH3ADJ                11
> +
> +/* ARM relocation types */
> +#define IMAGE_REL_ARM_ABSOLUTE          0x0000
> +#define IMAGE_REL_ARM_ADDR              0x0001
> +#define IMAGE_REL_ARM_ADDR32NB          0x0002
> +#define IMAGE_REL_ARM_BRANCH24          0x0003
> +#define IMAGE_REL_ARM_BRANCH11          0x0004
> +#define IMAGE_REL_ARM_TOKEN             0x0005
> +#define IMAGE_REL_ARM_GPREL12           0x0006
> +#define IMAGE_REL_ARM_GPREL7            0x0007
> +#define IMAGE_REL_ARM_BLX24             0x0008
> +#define IMAGE_REL_ARM_BLX11             0x0009
> +#define IMAGE_REL_ARM_SECTION           0x000E
> +#define IMAGE_REL_ARM_SECREL            0x000F
> +#define IMAGE_REL_ARM_MOV32A            0x0010
> +#define IMAGE_REL_ARM_MOV32T            0x0011
> +#define IMAGE_REL_ARM_BRANCH20T 0x0012
> +#define IMAGE_REL_ARM_BRANCH24T 0x0014
> +#define IMAGE_REL_ARM_BLX23T            0x0015
> +
> +/* ARM64 relocation types */
> +#define IMAGE_REL_ARM64_ABSOLUTE        0x0000
> +#define IMAGE_REL_ARM64_ADDR32          0x0001
> +#define IMAGE_REL_ARM64_ADDR32NB        0x0002
> +#define IMAGE_REL_ARM64_BRANCH26        0x0003
> +#define IMAGE_REL_ARM64_PAGEBASE_REL21  0x0004
> +#define IMAGE_REL_ARM64_REL21           0x0005
> +#define IMAGE_REL_ARM64_PAGEOFFSET_12A  0x0006
> +#define IMAGE_REL_ARM64_PAGEOFFSET_12L  0x0007
> +#define IMAGE_REL_ARM64_SECREL          0x0008
> +#define IMAGE_REL_ARM64_SECREL_LOW12A   0x0009
> +#define IMAGE_REL_ARM64_SECREL_HIGH12A  0x000A
> +#define IMAGE_REL_ARM64_SECREL_LOW12L   0x000B
> +#define IMAGE_REL_ARM64_TOKEN           0x000C
> +#define IMAGE_REL_ARM64_SECTION         0x000D
> +#define IMAGE_REL_ARM64_ADDR64          0x000E
> +
> +/* AMD64 relocation types */
> +#define IMAGE_REL_AMD64_ABSOLUTE        0x0000
> +#define IMAGE_REL_AMD64_ADDR64          0x0001
> +#define IMAGE_REL_AMD64_ADDR32          0x0002
> +#define IMAGE_REL_AMD64_ADDR32NB        0x0003
> +#define IMAGE_REL_AMD64_REL32           0x0004
> +#define IMAGE_REL_AMD64_REL32_1         0x0005
> +#define IMAGE_REL_AMD64_REL32_2         0x0006
> +#define IMAGE_REL_AMD64_REL32_3         0x0007
> +#define IMAGE_REL_AMD64_REL32_4         0x0008
> +#define IMAGE_REL_AMD64_REL32_5         0x0009
> +#define IMAGE_REL_AMD64_SECTION         0x000A
> +#define IMAGE_REL_AMD64_SECREL          0x000B
> +#define IMAGE_REL_AMD64_SECREL7         0x000C
> +#define IMAGE_REL_AMD64_TOKEN           0x000D
> +#define IMAGE_REL_AMD64_SREL32          0x000E
> +#define IMAGE_REL_AMD64_PAIR            0x000F
> +#define IMAGE_REL_AMD64_SSPAN32         0x0010
> +
> +#endif /* _PE_H */
> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
> new file mode 100644
> index 0000000..688e177
> --- /dev/null
> +++ b/lib/efi_loader/efi_image_loader.c
> @@ -0,0 +1,203 @@
> +/*
> + *  EFI image loader
> + *
> + *  based partly on wine code
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#include <common.h>
> +#include <pe.h>
> +#include <efi_loader.h>
> +#include <asm/global_data.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define ROUND_UP(val, round) ((val + (round - 1)) & ~(round - 1))
> +#define MB (1024 * 1024)
> +
> +const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
> +const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
> +
> +efi_status_t efi_return_handle(void *handle, efi_guid_t *protocol,
> +			void **protocol_interface, void *agent_handle,
> +			void *controller_handle, uint32_t attributes)
> +{
> +	*protocol_interface = handle;
> +	return EFI_SUCCESS;
> +}
> +
> +/*
> + * EFI payloads potentially want to load pretty big images into memory,
> + * so our small malloc region isn't enough for them. However, they usually
> + * don't need a smart allocator either.
> + *
> + * So instead give them a really dumb one. We just reserve EFI_LOADER_POOL_SIZE
> + * bytes from 16MB below the malloc region start to give the stack some space.

Is there any chance you could break out the memory allocation and
memory map management as a separate patch, rather than spread across
3,4 and 6?

Assigning a specific 128MB pool for LOADER_DATA memory can have
unexpected side effects.

> + * Then every allocation gets a 4k aligned chunk from it. We never free.

Never freeing LOADER_DATA should not be an issue in and of itself. It
all gets zapped by the OS anyway.

> + */
> +void *efi_loader_alloc(uint64_t len)
> +{
> +	static unsigned long loader_pool;
> +	void *r;
> +
> +	if (!loader_pool) {
> +		loader_pool = gd->relocaddr - TOTAL_MALLOC_LEN -
> +			      EFI_LOADER_POOL_SIZE - (16 * MB);
> +	}
> +
> +	len = ROUND_UP(len, 4096);
> +	/* Out of memory */
> +	if ((loader_pool + len) >= (gd->relocaddr - TOTAL_MALLOC_LEN))
> +		return NULL;
> +
> +	r = (void *)loader_pool;
> +	loader_pool += len;
> +
> +	return r;
> +}
> +
> +/*
> + * This function loads all sections from a PE binary into a newly reserved
> + * piece of memory. On successful load it then returns the entry point for
> + * the binary. Otherwise NULL.
> + */
> +void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
> +{
> +	IMAGE_NT_HEADERS32 *nt;
> +	IMAGE_DOS_HEADER *dos;
> +	IMAGE_SECTION_HEADER *sections;
> +	int num_sections;
> +	void *efi_reloc;
> +	int i;
> +	const uint16_t *relocs;
> +	const IMAGE_BASE_RELOCATION *rel;
> +	const IMAGE_BASE_RELOCATION *end;
> +	unsigned long rel_size;
> +	int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
> +	void *entry;
> +	uint64_t image_size;
> +	unsigned long virt_size = 0;
> +
> +	dos = efi;
> +	if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
> +		printf("%s: Invalid DOS Signature\n", __func__);
> +		return NULL;
> +	}
> +
> +	nt = (void *) ((char *)efi + dos->e_lfanew);
> +	if (nt->Signature != IMAGE_NT_SIGNATURE) {
> +		printf("%s: Invalid NT Signature\n", __func__);
> +		return NULL;
> +	}
> +
> +	/* Calculate upper virtual address boundary */
> +	num_sections = nt->FileHeader.NumberOfSections;
> +	sections = (void *)&nt->OptionalHeader +
> +			    nt->FileHeader.SizeOfOptionalHeader;
> +
> +	for (i = num_sections - 1; i >= 0; i--) {
> +		IMAGE_SECTION_HEADER *sec = &sections[i];
> +		virt_size = max_t(unsigned long, virt_size,
> +				  sec->VirtualAddress + sec->Misc.VirtualSize);
> +	}
> +
> +	/* Read 32/64bit specific header bits */

I guess x86 may support 32-on-64 or 64-on-32, but ARM won't - so could
probably be compile-time conditionalised somehow.
(CONFIG_EFI_SUPPORTS_PE32/CONFIG_EFI_SUPPORTS_PE64)

> +	if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
> +		IMAGE_NT_HEADERS64 *nt64 = (void *)nt;
> +		IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader;
> +		image_size = opt->SizeOfImage;
> +		efi_reloc = efi_loader_alloc(virt_size);
> +		if (!efi_reloc) {
> +			printf("%s: Could not allocate %ld bytes\n",
> +				__func__, virt_size);
> +			return NULL;
> +		}
> +		entry = efi_reloc + opt->AddressOfEntryPoint;
> +		rel_size = opt->DataDirectory[rel_idx].Size;
> +		rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
> +	} else {

...and should still check the magic value for 32-bit?

> +		IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader;
> +		image_size = opt->SizeOfImage;
> +		efi_reloc = efi_loader_alloc(virt_size);
> +		if (!efi_reloc) {
> +			printf("%s: Could not allocate %ld bytes\n",
> +				__func__, virt_size);
> +			return NULL;
> +		}
> +		entry = efi_reloc + opt->AddressOfEntryPoint;
> +		rel_size = opt->DataDirectory[rel_idx].Size;
> +		rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
> +	}
> +
> +	/* Load sections into RAM */
> +	for (i = num_sections - 1; i >= 0; i--) {
> +		IMAGE_SECTION_HEADER *sec = &sections[i];
> +		memset(efi_reloc + sec->VirtualAddress, 0,
> +		       sec->Misc.VirtualSize);
> +		memcpy(efi_reloc + sec->VirtualAddress,
> +		       efi + sec->PointerToRawData,
> +		       sec->SizeOfRawData);
> +	}
> +
> +
> +	/* Run through relocations */
> +	end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size);
> +
> +	while (rel < end - 1 && rel->SizeOfBlock) {
> +		relocs = (const uint16_t *)(rel + 1);
> +		i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t);
> +		while (i--) {
> +			uint16_t offset = (*relocs & 0xfff) + rel->VirtualAddress;
> +			int type = *relocs >> 12;
> +			unsigned long delta = (unsigned long)efi_reloc;
> +			uint64_t *x64 = efi_reloc + offset;
> +			uint32_t *x32 = efi_reloc + offset;
> +			uint16_t *x16 = efi_reloc + offset;
> +
> +			switch (type) {
> +			case IMAGE_REL_BASED_ABSOLUTE:
> +				break;
> +			case IMAGE_REL_BASED_HIGH:
> +				*x16 += ((uint32_t)delta) >> 16;
> +				break;
> +			case IMAGE_REL_BASED_LOW:
> +				*x16 += (uint16_t)delta;
> +				break;
> +			case IMAGE_REL_BASED_HIGHLOW:
> +				*x32 += (uint32_t)delta;
> +				break;
> +			case IMAGE_REL_BASED_DIR64:
> +				*x64 += (uint64_t)delta;
> +				break;
> +			default:
> +				printf("Unknown Relocation off %x type %x\n",
> +				       offset, type);
> +			}
> +			relocs++;
> +		}
> +		rel = (const IMAGE_BASE_RELOCATION *)relocs;
> +	}
> +
> +	/* Populate the loaded image interface bits */
> +	loaded_image_info->image_base = efi;
> +	loaded_image_info->image_size = image_size;
> +
> +	return entry;
> +}
> -- 
> 2.1.4
> 


More information about the U-Boot mailing list