mirror of
https://github.com/u-boot/u-boot.git
synced 2025-01-19 17:23:24 +08:00
Pull request for UEFI sub-system for v2019.10-rc1 (2)
* Implement the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. * Address errors of type -Werror=address-of-packed-member when building with GCC9.1 * Fix an error when adding memory add addres 0x00000000. * Rework some code comments for Sphinx compliance. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAl0vSQEACgkQxIHbvCwF GsQfxQ//d/i5Ix7V5rtm9U1ew2lkaQw5O1/E//Ta//0AeWLaEnFf0ln1Fx5jLF6E f70uE6iDRgnxfZWD/rnCqv7HZrokpy3GuXnUfAZTgEvsngqicw8dAAU9Ql9Q62i9 N302GhaCGkbBp3MBOLRBXJmKuTnnzfU7jkeYo1tZbZe3AoqSNtI8ND86DHSotuUM 9Ck5367LdcG5O86N8gIxBtCcnthq94GgS/tY69iuPhhKqN3oV6MbzjqmI4wtkVH6 RhJSQspTsmyKTSivbcgpgIPXJJnTwh0nZcQWmzC81ehU3LF9i1M1J4SAqsZ7kpgt jWY959iXnd7iNfwFiCTLpf+mDrviyPzntt/aE8ras5IwbQdiwZONeQ/mhkP2Snoo RDX+dB3JqpyO/T+4uMdq+2saYBtKZ9CUKclqqh/xwvv5Bs63qHGC3KKYnjQx1sKA k5QD3XSOPDLYbqQBIcgiB9T5TWkO1igJVEWRxPtExl31DTkSXy6f7G1F7sZ+Ey+5 gugIhNeTCme4a9bSIc7FjFaZSvPR2SNd8azUkSfso6Vqd9bNRShBF7pImlrCRmj8 Xc0sknW824LOdeM6ZC54J7lYKyLfL3HljzYSiM7KExt21mAjNHWXt312hINr6SOA gz+/Osdyrv8GniP86Zw3kACto6Chaw51PEV1WReYPT3LNwinvoU= =aj4j -----END PGP SIGNATURE----- Merge tag 'efi-2019-10-rc1-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi Pull request for UEFI sub-system for v2019.10-rc1 (2) * Implement the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. * Address errors of type -Werror=address-of-packed-member when building with GCC9.1 * Fix an error when adding memory add addres 0x00000000. * Rework some code comments for Sphinx compliance.
This commit is contained in:
commit
fe4243870d
@ -17,14 +17,13 @@
|
||||
*/
|
||||
.globl ImageBase
|
||||
ImageBase:
|
||||
.ascii "MZ"
|
||||
.short IMAGE_DOS_SIGNATURE /* 'MZ' */
|
||||
.skip 58 /* 'MZ' + pad + offset == 64 */
|
||||
.long pe_header - ImageBase /* Offset to the PE header */
|
||||
pe_header:
|
||||
.ascii "PE"
|
||||
.short 0
|
||||
.long IMAGE_NT_SIGNATURE /* 'PE' */
|
||||
coff_header:
|
||||
.short 0xaa64 /* AArch64 */
|
||||
.short IMAGE_FILE_MACHINE_ARM64 /* AArch64 */
|
||||
.short 2 /* nr_sections */
|
||||
.long 0 /* TimeDateStamp */
|
||||
.long 0 /* PointerToSymbolTable */
|
||||
@ -36,7 +35,7 @@ coff_header:
|
||||
IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
|
||||
IMAGE_FILE_DEBUG_STRIPPED)
|
||||
optional_header:
|
||||
.short 0x20b /* PE32+ format */
|
||||
.short IMAGE_NT_OPTIONAL_HDR64_MAGIC /* PE32+ format */
|
||||
.byte 0x02 /* MajorLinkerVersion */
|
||||
.byte 0x14 /* MinorLinkerVersion */
|
||||
.long _edata - _start /* SizeOfCode */
|
||||
|
@ -16,14 +16,13 @@
|
||||
*/
|
||||
.globl image_base
|
||||
image_base:
|
||||
.ascii "MZ"
|
||||
.short IMAGE_DOS_SIGNATURE /* 'MZ' */
|
||||
.skip 58 /* 'MZ' + pad + offset == 64 */
|
||||
.long pe_header - image_base /* Offset to the PE header */
|
||||
pe_header:
|
||||
.ascii "PE"
|
||||
.short 0
|
||||
.long IMAGE_NT_SIGNATURE /* 'PE' */
|
||||
coff_header:
|
||||
.short 0x1c2 /* Mixed ARM/Thumb */
|
||||
.short IMAGE_FILE_MACHINE_THUMB /* Mixed ARM/Thumb */
|
||||
.short 2 /* nr_sections */
|
||||
.long 0 /* TimeDateStamp */
|
||||
.long 0 /* PointerToSymbolTable */
|
||||
@ -36,7 +35,7 @@ coff_header:
|
||||
IMAGE_FILE_32BIT_MACHINE | \
|
||||
IMAGE_FILE_DEBUG_STRIPPED)
|
||||
optional_header:
|
||||
.short 0x10b /* PE32 format */
|
||||
.short IMAGE_NT_OPTIONAL_HDR32_MAGIC /* PE32 format */
|
||||
.byte 0x02 /* MajorLinkerVersion */
|
||||
.byte 0x14 /* MinorLinkerVersion */
|
||||
.long _edata - _start /* SizeOfCode */
|
||||
|
@ -14,12 +14,12 @@
|
||||
#define SIZE_LONG 8
|
||||
#define SAVE_LONG(reg, idx) sd reg, (idx*SIZE_LONG)(sp)
|
||||
#define LOAD_LONG(reg, idx) ld reg, (idx*SIZE_LONG)(sp)
|
||||
#define PE_MACHINE 0x5064
|
||||
#define PE_MACHINE IMAGE_FILE_MACHINE_RISCV64
|
||||
#else
|
||||
#define SIZE_LONG 4
|
||||
#define SAVE_LONG(reg, idx) sw reg, (idx*SIZE_LONG)(sp)
|
||||
#define LOAD_LONG(reg, idx) lw reg, (idx*SIZE_LONG)(sp)
|
||||
#define PE_MACHINE 0x5032
|
||||
#define PE_MACHINE IMAGE_FILE_MACHINE_RISCV32
|
||||
#endif
|
||||
|
||||
|
||||
@ -30,12 +30,11 @@
|
||||
*/
|
||||
.globl ImageBase
|
||||
ImageBase:
|
||||
.ascii "MZ"
|
||||
.short IMAGE_DOS_SIGNATURE /* 'MZ' */
|
||||
.skip 58 /* 'MZ' + pad + offset == 64 */
|
||||
.long pe_header - ImageBase /* Offset to the PE header */
|
||||
pe_header:
|
||||
.ascii "PE"
|
||||
.short 0
|
||||
.long IMAGE_NT_SIGNATURE /* 'PE' */
|
||||
coff_header:
|
||||
.short PE_MACHINE /* RISC-V 64/32-bit */
|
||||
.short 2 /* nr_sections */
|
||||
@ -49,7 +48,7 @@ coff_header:
|
||||
IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
|
||||
IMAGE_FILE_DEBUG_STRIPPED)
|
||||
optional_header:
|
||||
.short 0x20b /* PE32+ format */
|
||||
.short IMAGE_NT_OPTIONAL_HDR64_MAGIC /* PE32+ format */
|
||||
.byte 0x02 /* MajorLinkerVersion */
|
||||
.byte 0x14 /* MinorLinkerVersion */
|
||||
.long _edata - _start /* SizeOfCode */
|
||||
|
@ -24,7 +24,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
static struct efi_device_path *bootefi_image_path;
|
||||
static struct efi_device_path *bootefi_device_path;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Set the load options of an image from an environment variable.
|
||||
*
|
||||
* @handle: the image handle
|
||||
@ -143,7 +143,7 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
|
||||
*
|
||||
* The mem_rsv entries of the FDT are added to the memory map. Any failures are
|
||||
@ -169,8 +169,8 @@ static void efi_carve_out_dt_rsv(void *fdt)
|
||||
|
||||
pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
|
||||
addr &= ~EFI_PAGE_MASK;
|
||||
if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
|
||||
false))
|
||||
if (efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
|
||||
false) != EFI_SUCCESS)
|
||||
printf("FDT memrsv map %d: Failed to add to map\n", i);
|
||||
}
|
||||
}
|
||||
@ -342,7 +342,7 @@ static int do_efibootmgr(void)
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* do_bootefi_image() - execute EFI binary
|
||||
*
|
||||
* Set up memory image for the binary to be loaded, prepare device path, and
|
||||
@ -612,6 +612,16 @@ U_BOOT_CMD(
|
||||
bootefi_help_text
|
||||
);
|
||||
|
||||
/**
|
||||
* efi_set_bootdev() - set boot device
|
||||
*
|
||||
* This function is called when a file is loaded, e.g. via the 'load' command.
|
||||
* We use the path to this file to inform the UEFI binary about the boot device.
|
||||
*
|
||||
* @dev: device, e.g. "MMC"
|
||||
* @devnr: number of the device, e.g. "1:2"
|
||||
* @path: path to file loaded
|
||||
*/
|
||||
void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
|
||||
{
|
||||
struct efi_device_path *device, *image;
|
||||
|
@ -394,6 +394,7 @@ static const struct efi_mem_attrs {
|
||||
|
||||
/**
|
||||
* print_memory_attributes() - print memory map attributes
|
||||
*
|
||||
* @attributes: Attribute value
|
||||
*
|
||||
* Print memory map attributes
|
||||
@ -487,9 +488,9 @@ static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
|
||||
* Return: CMD_RET_SUCCESS on success,
|
||||
* CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
|
||||
*
|
||||
* Implement efidebug "boot add" sub-command.
|
||||
* Create or change UEFI load option.
|
||||
* - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
|
||||
* Implement efidebug "boot add" sub-command. Create or change UEFI load option.
|
||||
*
|
||||
* efidebug boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
|
||||
*/
|
||||
static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
@ -587,7 +588,8 @@ out:
|
||||
*
|
||||
* Implement efidebug "boot rm" sub-command.
|
||||
* Delete UEFI load options.
|
||||
* - boot rm <id> ...
|
||||
*
|
||||
* efidebug boot rm <id> ...
|
||||
*/
|
||||
static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
@ -890,7 +892,8 @@ out:
|
||||
*
|
||||
* Implement efidebug "boot next" sub-command.
|
||||
* Set BootNext variable.
|
||||
* - boot next <id>
|
||||
*
|
||||
* efidebug boot next <id>
|
||||
*/
|
||||
static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
@ -938,7 +941,8 @@ out:
|
||||
*
|
||||
* Implement efidebug "boot order" sub-command.
|
||||
* Show order of UEFI load options, or change it in BootOrder variable.
|
||||
* - boot order [<id> ...]
|
||||
*
|
||||
* efidebug boot order [<id> ...]
|
||||
*/
|
||||
static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
|
@ -670,9 +670,18 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gpt_convert_efi_name_to_char(char *s, efi_char16_t *es, int n)
|
||||
/**
|
||||
* gpt_convert_efi_name_to_char() - convert u16 string to char string
|
||||
*
|
||||
* TODO: this conversion only supports ANSI characters
|
||||
*
|
||||
* @s: target buffer
|
||||
* @es: u16 string to be converted
|
||||
* @n: size of target buffer
|
||||
*/
|
||||
static void gpt_convert_efi_name_to_char(char *s, void *es, int n)
|
||||
{
|
||||
char *ess = (char *)es;
|
||||
char *ess = es;
|
||||
int i, j;
|
||||
|
||||
memset(s, '\0', n);
|
||||
|
87
doc/efi.rst
87
doc/efi.rst
@ -1,7 +1,64 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
EFI subsystem
|
||||
=============
|
||||
UEFI subsystem
|
||||
==============
|
||||
|
||||
Lauching UEFI images
|
||||
--------------------
|
||||
|
||||
Bootefi command
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The bootefi command is used to start UEFI applications or to install UEFI
|
||||
drivers. It takes two parameters
|
||||
|
||||
bootefi <image address> [fdt address]
|
||||
|
||||
* image address - the memory address of the UEFI binary
|
||||
* fdt address - the memory address of the flattened device tree
|
||||
|
||||
The environment variable 'bootargs' is passed as load options in the UEFI system
|
||||
table. The Linux kernel EFI stub uses the load options as command line
|
||||
arguments.
|
||||
|
||||
.. kernel-doc:: cmd/bootefi.c
|
||||
:internal:
|
||||
|
||||
Boot manager
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The UEFI specification foresees to define boot entries and boot sequence via UEFI
|
||||
variables. Booting according to these variables is possible via
|
||||
|
||||
bootefi bootmgr [fdt address]
|
||||
|
||||
* fdt address - the memory address of the flattened device tree
|
||||
|
||||
The relevant variables are:
|
||||
|
||||
* Boot0000-BootFFFF define boot entries
|
||||
* BootNext specifies next boot option to be booted
|
||||
* BootOrder specifies in which sequence the boot options shall be tried if
|
||||
BootNext is not defined or booting via BootNext fails
|
||||
|
||||
.. kernel-doc:: lib/efi_loader/efi_bootmgr.c
|
||||
:internal:
|
||||
|
||||
Efidebug command
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The efidebug command is used to set and display boot options as well as to
|
||||
display information about internal data of the UEFI subsystem (devices,
|
||||
drivers, handles, loaded images, and the memory map).
|
||||
|
||||
.. kernel-doc:: cmd/efidebug.c
|
||||
:internal:
|
||||
|
||||
Initialization of the UEFI sub-system
|
||||
-------------------------------------
|
||||
|
||||
.. kernel-doc:: lib/efi_loader/efi_setup.c
|
||||
:internal:
|
||||
|
||||
Boot services
|
||||
-------------
|
||||
@ -15,8 +72,34 @@ Image relocation
|
||||
.. kernel-doc:: lib/efi_loader/efi_image_loader.c
|
||||
:internal:
|
||||
|
||||
Memory services
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: lib/efi_loader/efi_memory.c
|
||||
:internal:
|
||||
|
||||
Runtime services
|
||||
----------------
|
||||
|
||||
.. kernel-doc:: lib/efi_loader/efi_runtime.c
|
||||
:internal:
|
||||
|
||||
Variable services
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: lib/efi_loader/efi_variable.c
|
||||
:internal:
|
||||
|
||||
UEFI drivers
|
||||
------------
|
||||
|
||||
UEFI driver uclass
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
.. kernel-doc:: lib/efi_driver/efi_uclass.c
|
||||
:internal:
|
||||
|
||||
Block device driver
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: lib/efi_driver/efi_block_device.c
|
||||
:internal:
|
||||
|
@ -29,6 +29,22 @@
|
||||
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
|
||||
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
|
||||
|
||||
/* Machine types */
|
||||
#define IMAGE_FILE_MACHINE_I386 0x014c
|
||||
#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_FILE_MACHINE_RISCV32 0x5032
|
||||
#define IMAGE_FILE_MACHINE_RISCV64 0x5064
|
||||
|
||||
/* Header magic constants */
|
||||
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b
|
||||
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b
|
||||
#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
|
||||
#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
|
||||
|
||||
/* Subsystem type */
|
||||
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
|
||||
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
|
||||
|
@ -178,7 +178,7 @@ s32 utf_to_upper(const s32 code);
|
||||
* ReturnValue: number of non-zero words.
|
||||
* This is not the number of utf-16 letters!
|
||||
*/
|
||||
size_t u16_strlen(const u16 *in);
|
||||
size_t u16_strlen(const void *in);
|
||||
|
||||
/**
|
||||
* u16_strlen - count non-zero words
|
||||
@ -214,7 +214,7 @@ u16 *u16_strcpy(u16 *dest, const u16 *src);
|
||||
* @src: source buffer (null terminated)
|
||||
* Return: allocated new buffer on success, NULL on failure
|
||||
*/
|
||||
u16 *u16_strdup(const u16 *src);
|
||||
u16 *u16_strdup(const void *src);
|
||||
|
||||
/**
|
||||
* utf16_to_utf8() - Convert an utf16 string to utf8
|
||||
|
@ -476,8 +476,8 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
|
||||
efi_uintn_t *descriptor_size,
|
||||
uint32_t *descriptor_version);
|
||||
/* Adds a range into the EFI memory map */
|
||||
uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||||
bool overlap_only_ram);
|
||||
efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||||
bool overlap_only_ram);
|
||||
/* Called by board init to initialize the EFI drivers */
|
||||
efi_status_t efi_driver_init(void);
|
||||
/* Called by board init to initialize the EFI memory map */
|
||||
@ -567,7 +567,7 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii)
|
||||
*unicode = 0;
|
||||
}
|
||||
|
||||
static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2)
|
||||
static inline int guidcmp(const void *g1, const void *g2)
|
||||
{
|
||||
return memcmp(g1, g2, sizeof(efi_guid_t));
|
||||
}
|
||||
|
16
include/pe.h
16
include/pe.h
@ -34,22 +34,6 @@ typedef struct _IMAGE_DOS_HEADER {
|
||||
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_I386 0x014c
|
||||
#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_FILE_MACHINE_RISCV32 0x5032
|
||||
#define IMAGE_FILE_MACHINE_RISCV64 0x5064
|
||||
|
||||
#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;
|
||||
|
@ -335,11 +335,16 @@ s32 utf_to_upper(const s32 code)
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t u16_strlen(const u16 *in)
|
||||
size_t u16_strlen(const void *in)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; in[i]; i++);
|
||||
return i;
|
||||
const char *pos = in;
|
||||
size_t ret;
|
||||
|
||||
for (; pos[0] || pos[1]; pos += 2)
|
||||
;
|
||||
ret = pos - (char *)in;
|
||||
ret >>= 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t u16_strnlen(const u16 *in, size_t count)
|
||||
@ -362,18 +367,18 @@ u16 *u16_strcpy(u16 *dest, const u16 *src)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
u16 *u16_strdup(const u16 *src)
|
||||
u16 *u16_strdup(const void *src)
|
||||
{
|
||||
u16 *new;
|
||||
size_t len;
|
||||
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
new = malloc((u16_strlen(src) + 1) * sizeof(u16));
|
||||
len = (u16_strlen(src) + 1) * sizeof(u16);
|
||||
new = malloc(len);
|
||||
if (!new)
|
||||
return NULL;
|
||||
|
||||
u16_strcpy(new, src);
|
||||
memcpy(new, src, len);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
@ -43,14 +43,14 @@ struct efi_blk_platdata {
|
||||
struct efi_block_io *io;
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* Read from block device
|
||||
*
|
||||
* @dev device
|
||||
* @blknr first block to be read
|
||||
* @blkcnt number of blocks to read
|
||||
* @buffer output buffer
|
||||
* @return number of blocks transferred
|
||||
* @dev: device
|
||||
* @blknr: first block to be read
|
||||
* @blkcnt: number of blocks to read
|
||||
* @buffer: output buffer
|
||||
* Return: number of blocks transferred
|
||||
*/
|
||||
static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
void *buffer)
|
||||
@ -72,14 +72,14 @@ static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Write to block device
|
||||
*
|
||||
* @dev device
|
||||
* @blknr first block to be write
|
||||
* @blkcnt number of blocks to write
|
||||
* @buffer input buffer
|
||||
* @return number of blocks transferred
|
||||
* @dev: device
|
||||
* @blknr: first block to be write
|
||||
* @blkcnt: number of blocks to write
|
||||
* @buffer: input buffer
|
||||
* Return: number of blocks transferred
|
||||
*/
|
||||
static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
const void *buffer)
|
||||
@ -102,11 +102,12 @@ static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Create partions for the block device.
|
||||
*
|
||||
* @handle EFI handle of the block device
|
||||
* @dev udevice of the block device
|
||||
* @handle: EFI handle of the block device
|
||||
* @dev: udevice of the block device
|
||||
* Return: number of partitions created
|
||||
*/
|
||||
static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
|
||||
{
|
||||
@ -120,12 +121,12 @@ static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
|
||||
desc->devnum, dev->name);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Create a block device for a handle
|
||||
*
|
||||
* @handle handle
|
||||
* @interface block io protocol
|
||||
* @return 0 = success
|
||||
* @handle: handle
|
||||
* @interface: block io protocol
|
||||
* Return: 0 = success
|
||||
*/
|
||||
static int efi_bl_bind(efi_handle_t handle, void *interface)
|
||||
{
|
||||
|
@ -27,7 +27,15 @@ static const struct efi_runtime_services *rs;
|
||||
*/
|
||||
|
||||
|
||||
/* Parse serialized data and transform it into efi_load_option structure */
|
||||
/**
|
||||
* efi_deserialize_load_option() - parse serialized data
|
||||
*
|
||||
* Parse serialized data describing a load option and transform it to the
|
||||
* efi_load_option structure.
|
||||
*
|
||||
* @lo: pointer to target
|
||||
* @data: serialized data
|
||||
*/
|
||||
void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data)
|
||||
{
|
||||
lo->attributes = get_unaligned_le32(data);
|
||||
@ -47,9 +55,14 @@ void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data)
|
||||
lo->optional_data = data;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* efi_serialize_load_option() - serialize load option
|
||||
*
|
||||
* Serialize efi_load_option structure into byte stream for BootXXXX.
|
||||
* Return a size of allocated data.
|
||||
*
|
||||
* @data: buffer for serialized data
|
||||
* @lo: load option
|
||||
* Return: size of allocated buffer
|
||||
*/
|
||||
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
|
||||
{
|
||||
@ -92,7 +105,16 @@ unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
|
||||
return size;
|
||||
}
|
||||
|
||||
/* free() the result */
|
||||
/**
|
||||
* get_var() - get UEFI variable
|
||||
*
|
||||
* It is the caller's duty to free the returned buffer.
|
||||
*
|
||||
* @name: name of variable
|
||||
* @vendor: vendor GUID of variable
|
||||
* @size: size of allocated buffer
|
||||
* Return: buffer with variable data or NULL
|
||||
*/
|
||||
static void *get_var(u16 *name, const efi_guid_t *vendor,
|
||||
efi_uintn_t *size)
|
||||
{
|
||||
@ -116,10 +138,16 @@ static void *get_var(u16 *name, const efi_guid_t *vendor,
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* try_load_entry() - try to load image for boot option
|
||||
*
|
||||
* Attempt to load load-option number 'n', returning device_path and file_path
|
||||
* if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
|
||||
* if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
|
||||
* and that the specified file to boot exists.
|
||||
*
|
||||
* @n: number of the boot option, e.g. 0x0a13 for Boot0A13
|
||||
* @handle: on return handle for the newly installed image
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t try_load_entry(u16 n, efi_handle_t *handle)
|
||||
{
|
||||
@ -180,10 +208,15 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* efi_bootmgr_load() - try to load from BootNext or BootOrder
|
||||
*
|
||||
* Attempt to load from BootNext or in the order specified by BootOrder
|
||||
* EFI variable, the available load-options, finding and returning
|
||||
* the first one that can be loaded successfully.
|
||||
*
|
||||
* @handle: on return handle for the newly installed image
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_bootmgr_load(efi_handle_t *handle)
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ static efi_uintn_t efi_tpl = TPL_APPLICATION;
|
||||
LIST_HEAD(efi_obj_list);
|
||||
|
||||
/* List of all events */
|
||||
LIST_HEAD(efi_events);
|
||||
__efi_runtime_data LIST_HEAD(efi_events);
|
||||
|
||||
/* List of queued events */
|
||||
LIST_HEAD(efi_event_queue);
|
||||
@ -596,7 +596,7 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
|
||||
/**
|
||||
* efi_delete_handle() - delete handle
|
||||
*
|
||||
* @obj: handle to delete
|
||||
* @handle: handle to delete
|
||||
*/
|
||||
void efi_delete_handle(efi_handle_t handle)
|
||||
{
|
||||
@ -628,6 +628,7 @@ static efi_status_t efi_is_event(const struct efi_event *event)
|
||||
|
||||
/**
|
||||
* efi_create_event() - create an event
|
||||
*
|
||||
* @type: type of the event to create
|
||||
* @notify_tpl: task priority level of the event
|
||||
* @notify_function: notification function of the event
|
||||
@ -650,6 +651,8 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
|
||||
struct efi_event **event)
|
||||
{
|
||||
struct efi_event *evt;
|
||||
efi_status_t ret;
|
||||
int pool_type;
|
||||
|
||||
if (event == NULL)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
@ -662,7 +665,10 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
|
||||
case EVT_NOTIFY_WAIT:
|
||||
case EVT_TIMER | EVT_NOTIFY_WAIT:
|
||||
case EVT_SIGNAL_EXIT_BOOT_SERVICES:
|
||||
pool_type = EFI_BOOT_SERVICES_DATA;
|
||||
break;
|
||||
case EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE:
|
||||
pool_type = EFI_RUNTIME_SERVICES_DATA;
|
||||
break;
|
||||
default:
|
||||
return EFI_INVALID_PARAMETER;
|
||||
@ -672,9 +678,11 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
|
||||
(!notify_function || is_valid_tpl(notify_tpl) != EFI_SUCCESS))
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
evt = calloc(1, sizeof(struct efi_event));
|
||||
if (!evt)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
ret = efi_allocate_pool(pool_type, sizeof(struct efi_event),
|
||||
(void **)&evt);
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
memset(evt, 0, sizeof(struct efi_event));
|
||||
evt->type = type;
|
||||
evt->notify_tpl = notify_tpl;
|
||||
evt->notify_function = notify_function;
|
||||
@ -982,7 +990,7 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
|
||||
list_del(&event->queue_link);
|
||||
|
||||
list_del(&event->link);
|
||||
free(event);
|
||||
efi_free_pool(event);
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
||||
@ -1411,9 +1419,9 @@ out:
|
||||
|
||||
/**
|
||||
* efi_search() - determine if an EFI handle implements a protocol
|
||||
*
|
||||
* @search_type: selection criterion
|
||||
* @protocol: GUID of the protocol
|
||||
* @search_key: registration key
|
||||
* @handle: handle
|
||||
*
|
||||
* See the documentation of the LocateHandle service in the UEFI specification.
|
||||
@ -1675,7 +1683,7 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
|
||||
* Initialize a loaded_image_info and loaded_image_info object with correct
|
||||
* protocols, boot-device, etc.
|
||||
*
|
||||
* In case of an error *handle_ptr and *info_ptr are set to NULL and an error
|
||||
* In case of an error \*handle_ptr and \*info_ptr are set to NULL and an error
|
||||
* code is returned.
|
||||
*
|
||||
* @device_path: device path of the loaded image
|
||||
@ -1932,7 +1940,7 @@ static void efi_exit_caches(void)
|
||||
static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
|
||||
efi_uintn_t map_key)
|
||||
{
|
||||
struct efi_event *evt;
|
||||
struct efi_event *evt, *next_event;
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
EFI_ENTRY("%p, %zx", image_handle, map_key);
|
||||
@ -1971,6 +1979,12 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
|
||||
/* Notify variable services */
|
||||
efi_variables_boot_exit_notify();
|
||||
|
||||
/* Remove all events except EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
|
||||
list_for_each_entry_safe(evt, next_event, &efi_events, link) {
|
||||
if (evt->type != EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)
|
||||
list_del(&evt->link);
|
||||
}
|
||||
|
||||
board_quiesce_devices();
|
||||
|
||||
/* Patch out unsupported runtime function */
|
||||
@ -3034,9 +3048,9 @@ out:
|
||||
/**
|
||||
* efi_update_exit_data() - fill exit data parameters of StartImage()
|
||||
*
|
||||
* @image_obj image handle
|
||||
* @exit_data_size size of the exit data buffer
|
||||
* @exit_data buffer with data returned by UEFI payload
|
||||
* @image_obj: image handle
|
||||
* @exit_data_size: size of the exit data buffer
|
||||
* @exit_data: buffer with data returned by UEFI payload
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t efi_update_exit_data(struct efi_loaded_image_obj *image_obj,
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <mmc.h>
|
||||
#include <efi_loader.h>
|
||||
#include <part.h>
|
||||
#include <asm-generic/unaligned.h>
|
||||
|
||||
/* template END node: */
|
||||
static const struct efi_device_path END = {
|
||||
@ -793,16 +794,36 @@ struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* convert path to an UEFI style path (i.e. DOS style backslashes and UTF-16) */
|
||||
static void path_to_uefi(u16 *uefi, const char *path)
|
||||
/**
|
||||
* path_to_uefi() - convert UTF-8 path to an UEFI style path
|
||||
*
|
||||
* Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
|
||||
* separators and UTF-16).
|
||||
*
|
||||
* @src: source buffer
|
||||
* @uefi: target buffer, possibly unaligned
|
||||
*/
|
||||
static void path_to_uefi(void *uefi, const char *src)
|
||||
{
|
||||
while (*path) {
|
||||
char c = *(path++);
|
||||
if (c == '/')
|
||||
c = '\\';
|
||||
*(uefi++) = c;
|
||||
u16 *pos = uefi;
|
||||
|
||||
/*
|
||||
* efi_set_bootdev() calls this routine indirectly before the UEFI
|
||||
* subsystem is initialized. So we cannot assume unaligned access to be
|
||||
* enabled.
|
||||
*/
|
||||
allow_unaligned();
|
||||
|
||||
while (*src) {
|
||||
s32 code = utf8_get(&src);
|
||||
|
||||
if (code < 0)
|
||||
code = '?';
|
||||
else if (code == '/')
|
||||
code = '\\';
|
||||
utf16_put(code, &pos);
|
||||
}
|
||||
*uefi = '\0';
|
||||
*pos = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -819,7 +840,8 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
|
||||
if (desc)
|
||||
dpsize = dp_part_size(desc, part);
|
||||
|
||||
fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
|
||||
fpsize = sizeof(struct efi_device_path) +
|
||||
2 * (utf8_utf16_strlen(path) + 1);
|
||||
dpsize += fpsize;
|
||||
|
||||
start = buf = dp_alloc(dpsize + sizeof(END));
|
||||
|
@ -755,6 +755,7 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
|
||||
struct efi_device_path_file_path *fdp =
|
||||
container_of(fp, struct efi_device_path_file_path, dp);
|
||||
struct efi_file_handle *f2;
|
||||
u16 *filename;
|
||||
|
||||
if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
|
||||
printf("bad file path!\n");
|
||||
@ -762,8 +763,12 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EFI_CALL(ret = f->open(f, &f2, fdp->str,
|
||||
filename = u16_strdup(fdp->str);
|
||||
if (!filename)
|
||||
return NULL;
|
||||
EFI_CALL(ret = f->open(f, &f2, filename,
|
||||
EFI_FILE_MODE_READ, 0));
|
||||
free(filename);
|
||||
if (ret != EFI_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
|
@ -37,17 +37,21 @@ void *efi_bounce_buffer;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* efi_pool_allocation - memory block allocated from pool
|
||||
* struct efi_pool_allocation - memory block allocated from pool
|
||||
*
|
||||
* @num_pages: number of pages allocated
|
||||
* @checksum: checksum
|
||||
* @data: allocated pool memory
|
||||
*
|
||||
* U-Boot services each EFI AllocatePool request as a separate
|
||||
* (multiple) page allocation. We have to track the number of pages
|
||||
* U-Boot services each UEFI AllocatePool() request as a separate
|
||||
* (multiple) page allocation. We have to track the number of pages
|
||||
* to be able to free the correct amount later.
|
||||
*
|
||||
* The checksum calculated in function checksum() is used in FreePool() to avoid
|
||||
* freeing memory not allocated by AllocatePool() and duplicate freeing.
|
||||
*
|
||||
* EFI requires 8 byte alignment for pool allocations, so we can
|
||||
* prepend each allocation with an 64 bit header tracking the
|
||||
* allocation size, and hand out the remainder to the caller.
|
||||
* prepend each allocation with these header fields.
|
||||
*/
|
||||
struct efi_pool_allocation {
|
||||
u64 num_pages;
|
||||
@ -223,8 +227,17 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map,
|
||||
return EFI_CARVE_LOOP_AGAIN;
|
||||
}
|
||||
|
||||
uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||||
bool overlap_only_ram)
|
||||
/**
|
||||
* efi_add_memory_map() - add memory area to the memory map
|
||||
*
|
||||
* @start: start address, must be a multiple of EFI_PAGE_SIZE
|
||||
* @pages: number of pages to add
|
||||
* @memory_type: type of memory added
|
||||
* @overlap_only_ram: the memory area must overlap existing
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||||
bool overlap_only_ram)
|
||||
{
|
||||
struct list_head *lhandle;
|
||||
struct efi_mem_list *newlist;
|
||||
@ -239,7 +252,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
if (!pages)
|
||||
return start;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
++efi_memory_map_key;
|
||||
newlist = calloc(1, sizeof(*newlist));
|
||||
@ -277,7 +290,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||||
* The user requested to only have RAM overlaps,
|
||||
* but we hit a non-RAM region. Error out.
|
||||
*/
|
||||
return 0;
|
||||
return EFI_NO_MAPPING;
|
||||
case EFI_CARVE_NO_OVERLAP:
|
||||
/* Just ignore this list entry */
|
||||
break;
|
||||
@ -307,7 +320,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||||
* The payload wanted to have RAM overlaps, but we overlapped
|
||||
* with an unallocated region. Error out.
|
||||
*/
|
||||
return 0;
|
||||
return EFI_NO_MAPPING;
|
||||
}
|
||||
|
||||
/* Add our new map */
|
||||
@ -326,7 +339,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -455,7 +468,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
|
||||
}
|
||||
|
||||
/* Reserve that map in our memory maps */
|
||||
if (efi_add_memory_map(addr, pages, memory_type, true) != addr)
|
||||
if (efi_add_memory_map(addr, pages, memory_type, true) != EFI_SUCCESS)
|
||||
/* Map would overlap, bail out */
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
@ -487,7 +500,6 @@ void *efi_alloc(uint64_t len, int memory_type)
|
||||
*/
|
||||
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
|
||||
{
|
||||
uint64_t r = 0;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = efi_check_allocated(memory, true);
|
||||
@ -501,13 +513,13 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
|
||||
ret = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
|
||||
/* Merging of adjacent free regions is missing */
|
||||
|
||||
if (r == memory)
|
||||
return EFI_SUCCESS;
|
||||
if (ret != EFI_SUCCESS)
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -391,8 +391,10 @@ efi_status_t __weak __efi_runtime EFIAPI efi_set_time(struct efi_time *time)
|
||||
*/
|
||||
static bool efi_is_runtime_service_pointer(void *p)
|
||||
{
|
||||
return p >= (void *)&efi_runtime_services.get_time &&
|
||||
p <= (void *)&efi_runtime_services.query_variable_info;
|
||||
return (p >= (void *)&efi_runtime_services.get_time &&
|
||||
p <= (void *)&efi_runtime_services.query_variable_info) ||
|
||||
p == (void *)&efi_events.prev ||
|
||||
p == (void *)&efi_events.next;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -424,7 +426,7 @@ void efi_runtime_detach(void)
|
||||
* @virtmap: virtual address mapping information
|
||||
* Return: status code EFI_UNSUPPORTED
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
|
||||
static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime(
|
||||
unsigned long memory_map_size,
|
||||
unsigned long descriptor_size,
|
||||
uint32_t descriptor_version,
|
||||
@ -577,6 +579,7 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
|
||||
int n = memory_map_size / descriptor_size;
|
||||
int i;
|
||||
int rt_code_sections = 0;
|
||||
struct efi_event *event;
|
||||
|
||||
EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
|
||||
descriptor_version, virtmap);
|
||||
@ -610,6 +613,13 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
|
||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
/* Notify EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
|
||||
list_for_each_entry(event, &efi_events, link) {
|
||||
if (event->notify_function)
|
||||
EFI_CALL_VOID(event->notify_function(
|
||||
event, event->notify_context));
|
||||
}
|
||||
|
||||
/* Rebind mmio pointers */
|
||||
for (i = 0; i < n; i++) {
|
||||
struct efi_mem_desc *map = (void*)virtmap +
|
||||
@ -684,10 +694,10 @@ efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len)
|
||||
struct efi_runtime_mmio_list *newmmio;
|
||||
u64 pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
|
||||
uint64_t addr = *(uintptr_t *)mmio_ptr;
|
||||
uint64_t retaddr;
|
||||
efi_status_t ret;
|
||||
|
||||
retaddr = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false);
|
||||
if (retaddr != addr)
|
||||
ret = efi_add_memory_map(addr, pages, EFI_MMAP_IO, false);
|
||||
if (ret != EFI_SUCCESS)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
newmmio = calloc(1, sizeof(*newmmio));
|
||||
|
@ -263,8 +263,8 @@ static char *efi_cur_variable;
|
||||
* is the size of variable name including NULL.
|
||||
*
|
||||
* Return: EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when
|
||||
the entire variable list has been returned,
|
||||
otherwise non-zero status code
|
||||
* the entire variable list has been returned,
|
||||
* otherwise non-zero status code
|
||||
*/
|
||||
static efi_status_t parse_uboot_variable(char *variable,
|
||||
efi_uintn_t *variable_name_size,
|
||||
@ -315,6 +315,7 @@ static efi_status_t parse_uboot_variable(char *variable,
|
||||
|
||||
/**
|
||||
* efi_get_next_variable_name() - enumerate the current variable names
|
||||
*
|
||||
* @variable_name_size: size of variable_name buffer in byte
|
||||
* @variable_name: name of uefi variable's name in u16
|
||||
* @vendor: vendor's guid
|
||||
@ -322,8 +323,7 @@ static efi_status_t parse_uboot_variable(char *variable,
|
||||
* This function implements the GetNextVariableName service.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details: http://wiki.phoenix.com/wiki/index.php/
|
||||
* EFI_RUNTIME_SERVICES#GetNextVariableName.28.29
|
||||
* details.
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
@ -550,6 +550,13 @@ efi_status_t __efi_runtime EFIAPI efi_query_variable_info(
|
||||
|
||||
/**
|
||||
* efi_get_variable_runtime() - runtime implementation of GetVariable()
|
||||
*
|
||||
* @variable_name: name of the variable
|
||||
* @vendor: vendor GUID
|
||||
* @attributes: attributes of the variable
|
||||
* @data_size: size of the buffer to which the variable value is copied
|
||||
* @data: buffer to which the variable value is copied
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t __efi_runtime EFIAPI
|
||||
efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
|
||||
@ -561,6 +568,11 @@ efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
|
||||
/**
|
||||
* efi_get_next_variable_name_runtime() - runtime implementation of
|
||||
* GetNextVariable()
|
||||
*
|
||||
* @variable_name_size: size of variable_name buffer in byte
|
||||
* @variable_name: name of uefi variable's name in u16
|
||||
* @vendor: vendor's guid
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t __efi_runtime EFIAPI
|
||||
efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
|
||||
@ -571,6 +583,13 @@ efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
|
||||
|
||||
/**
|
||||
* efi_set_variable_runtime() - runtime implementation of SetVariable()
|
||||
*
|
||||
* @variable_name: name of the variable
|
||||
* @vendor: vendor GUID
|
||||
* @attributes: attributes of the variable
|
||||
* @data_size: size of the buffer with the variable value
|
||||
* @data: buffer with the variable value
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t __efi_runtime EFIAPI
|
||||
efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
|
||||
|
@ -28,6 +28,7 @@ efi_selftest_manageprotocols.o \
|
||||
efi_selftest_memory.o \
|
||||
efi_selftest_open_protocol.o \
|
||||
efi_selftest_register_notify.o \
|
||||
efi_selftest_set_virtual_address_map.o \
|
||||
efi_selftest_snp.o \
|
||||
efi_selftest_textinput.o \
|
||||
efi_selftest_textinputex.o \
|
||||
|
@ -55,28 +55,6 @@ static int setup(const efi_handle_t handle,
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tear down unit test.
|
||||
*
|
||||
* Close the event created in setup.
|
||||
*
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int teardown(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
if (event_notify) {
|
||||
ret = boottime->close_event(event_notify);
|
||||
event_notify = NULL;
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("could not close event\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
}
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute unit test.
|
||||
*
|
||||
@ -107,5 +85,4 @@ EFI_UNIT_TEST(exitbootservices) = {
|
||||
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
|
||||
.setup = setup,
|
||||
.execute = execute,
|
||||
.teardown = teardown,
|
||||
};
|
||||
|
192
lib/efi_selftest/efi_selftest_set_virtual_address_map.c
Normal file
192
lib/efi_selftest/efi_selftest_set_virtual_address_map.c
Normal file
@ -0,0 +1,192 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* efi_selftest_set_virtual_address_map.c
|
||||
*
|
||||
* Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*
|
||||
* This test checks the notification of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
|
||||
* and the following services: SetVirtualAddressMap, ConvertPointer.
|
||||
*/
|
||||
|
||||
#include <efi_selftest.h>
|
||||
|
||||
static const struct efi_boot_services *boottime;
|
||||
static const struct efi_runtime_services *runtime;
|
||||
static struct efi_event *event;
|
||||
static struct efi_mem_desc *memory_map;
|
||||
static efi_uintn_t map_size;
|
||||
static efi_uintn_t desc_size;
|
||||
static u32 desc_version;
|
||||
static u64 page1;
|
||||
static u64 page2;
|
||||
static u32 notify_call_count;
|
||||
|
||||
/**
|
||||
* notify () - notification function
|
||||
*
|
||||
* This function is called when the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event
|
||||
* occurs. The correct output of ConvertPointer() is checked.
|
||||
*
|
||||
* @event notified event
|
||||
* @context pointer to the notification count
|
||||
*/
|
||||
static void EFIAPI notify(struct efi_event *event, void *context)
|
||||
{
|
||||
void *addr;
|
||||
efi_status_t ret;
|
||||
|
||||
++notify_call_count;
|
||||
|
||||
addr = (void *)(uintptr_t)page1;
|
||||
ret = runtime->convert_pointer(0, &addr);
|
||||
if (ret != EFI_SUCCESS)
|
||||
efi_st_todo("ConvertPointer failed\n");
|
||||
if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE)
|
||||
efi_st_todo("ConvertPointer wrong address\n");
|
||||
|
||||
addr = (void *)(uintptr_t)page2;
|
||||
ret = runtime->convert_pointer(0, &addr);
|
||||
if (ret != EFI_SUCCESS)
|
||||
efi_st_todo("ConvertPointer failed\n");
|
||||
if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE)
|
||||
efi_st_todo("ConvertPointer wrong address\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* setup() - setup unit test
|
||||
*
|
||||
* The memory map is read. Boottime only entries are deleted. Two entries for
|
||||
* newly allocated pages are added. For these virtual addresses deviating from
|
||||
* the physical addresses are set.
|
||||
*
|
||||
* @handle: handle of the loaded image
|
||||
* @systable: system table
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int setup(const efi_handle_t handle,
|
||||
const struct efi_system_table *systable)
|
||||
{
|
||||
efi_uintn_t map_key;
|
||||
efi_status_t ret;
|
||||
struct efi_mem_desc *end, *pos1, *pos2;
|
||||
|
||||
boottime = systable->boottime;
|
||||
runtime = systable->runtime;
|
||||
|
||||
ret = boottime->create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
|
||||
TPL_CALLBACK, notify, NULL,
|
||||
&event);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("could not create event\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
|
||||
&desc_version);
|
||||
if (ret != EFI_BUFFER_TOO_SMALL) {
|
||||
efi_st_error(
|
||||
"GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
/* Allocate extra space for newly allocated memory */
|
||||
map_size += 3 * sizeof(struct efi_mem_desc);
|
||||
ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
|
||||
(void **)&memory_map);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("AllocatePool failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
|
||||
&desc_size, &desc_version);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("GetMemoryMap failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
|
||||
EFI_BOOT_SERVICES_DATA, 2, &page1);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("AllocatePages failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
|
||||
EFI_BOOT_SERVICES_DATA, 3, &page2);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("AllocatePages failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
/* Remove entries not relevant for runtime from map */
|
||||
end = (struct efi_mem_desc *)((u8 *)memory_map + map_size);
|
||||
for (pos1 = memory_map, pos2 = memory_map;
|
||||
pos2 < end; ++pos2) {
|
||||
switch (pos2->type) {
|
||||
case EFI_LOADER_CODE:
|
||||
case EFI_LOADER_DATA:
|
||||
case EFI_BOOT_SERVICES_CODE:
|
||||
case EFI_BOOT_SERVICES_DATA:
|
||||
continue;
|
||||
}
|
||||
memcpy(pos1, pos2, desc_size);
|
||||
++pos1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add entries with virtual addresses deviating from the physical
|
||||
* addresses. By choosing virtual address ranges within the allocated
|
||||
* physical pages address space collisions are avoided.
|
||||
*/
|
||||
pos1->type = EFI_RUNTIME_SERVICES_DATA;
|
||||
pos1->reserved = 0;
|
||||
pos1->physical_start = page1;
|
||||
pos1->virtual_start = page1 + EFI_PAGE_SIZE;
|
||||
pos1->num_pages = 1;
|
||||
pos1->attribute = EFI_MEMORY_RUNTIME;
|
||||
++pos1;
|
||||
|
||||
pos1->type = EFI_RUNTIME_SERVICES_DATA;
|
||||
pos1->reserved = 0;
|
||||
pos1->physical_start = page2;
|
||||
pos1->virtual_start = page2 + 2 * EFI_PAGE_SIZE;
|
||||
pos1->num_pages = 1;
|
||||
pos1->attribute = EFI_MEMORY_RUNTIME;
|
||||
++pos1;
|
||||
|
||||
map_size = (u8 *)pos1 - (u8 *)memory_map;
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* execute() - execute unit test
|
||||
*
|
||||
* SetVirtualAddressMap() is called with the memory map prepared in setup().
|
||||
*
|
||||
* The triggering of the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event is checked via
|
||||
* the call count of the notification function.
|
||||
*
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int execute(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
ret = runtime->set_virtual_address_map(map_size, desc_size,
|
||||
desc_version, memory_map);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("SetVirtualAddressMap failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
if (notify_call_count != 1) {
|
||||
efi_st_error("EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE triggered %d times\n",
|
||||
notify_call_count);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_UNIT_TEST(virtaddrmap) = {
|
||||
.name = "virtual address map",
|
||||
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
|
||||
.setup = setup,
|
||||
.execute = execute,
|
||||
};
|
@ -50,6 +50,16 @@ static const char j1[] = {0x6a, 0x31, 0xa1, 0x6c, 0x00};
|
||||
static const char j2[] = {0x6a, 0x32, 0xc3, 0xc3, 0x6c, 0x00};
|
||||
static const char j3[] = {0x6a, 0x33, 0xf0, 0x90, 0xf0, 0x00};
|
||||
|
||||
static int unicode_test_u16_strlen(struct unit_test_state *uts)
|
||||
{
|
||||
ut_asserteq(6, u16_strlen(c1));
|
||||
ut_asserteq(8, u16_strlen(c2));
|
||||
ut_asserteq(3, u16_strlen(c3));
|
||||
ut_asserteq(6, u16_strlen(c4));
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(unicode_test_u16_strlen);
|
||||
|
||||
static int unicode_test_u16_strdup(struct unit_test_state *uts)
|
||||
{
|
||||
u16 *copy = u16_strdup(c4);
|
||||
|
Loading…
Reference in New Issue
Block a user