summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2019-07-23 22:29:53 -0400
committerTom Rini <trini@konsulko.com>2019-07-23 22:29:53 -0400
commitfe4243870df152f839f88e5aa355f53cfba0a866 (patch)
tree6f748cbe5c48597a4075ebea87344c4763736686
parentff8c23e784f57a7098e91a200ed7f5a48612b653 (diff)
parentf62be16ddb76a32e6315bb9517b49e639726e1fa (diff)
downloadu-boot-WIP/23Jul2019.tar.gz
Merge tag 'efi-2019-10-rc1-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efiWIP/23Jul2019
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.
-rw-r--r--arch/arm/lib/crt0_aarch64_efi.S9
-rw-r--r--arch/arm/lib/crt0_arm_efi.S9
-rw-r--r--arch/riscv/lib/crt0_riscv_efi.S11
-rw-r--r--cmd/bootefi.c20
-rw-r--r--cmd/efidebug.c16
-rw-r--r--disk/part_efi.c13
-rw-r--r--doc/efi.rst87
-rw-r--r--include/asm-generic/pe.h16
-rw-r--r--include/charset.h4
-rw-r--r--include/efi_loader.h6
-rw-r--r--include/pe.h16
-rw-r--r--lib/charset.c23
-rw-r--r--lib/efi_driver/efi_block_device.c39
-rw-r--r--lib/efi_loader/efi_bootmgr.c47
-rw-r--r--lib/efi_loader/efi_boottime.c38
-rw-r--r--lib/efi_loader/efi_device_path.c40
-rw-r--r--lib/efi_loader/efi_file.c7
-rw-r--r--lib/efi_loader/efi_memory.c46
-rw-r--r--lib/efi_loader/efi_runtime.c22
-rw-r--r--lib/efi_loader/efi_variable.c27
-rw-r--r--lib/efi_selftest/Makefile1
-rw-r--r--lib/efi_selftest/efi_selftest_exitbootservices.c23
-rw-r--r--lib/efi_selftest/efi_selftest_set_virtual_address_map.c192
-rw-r--r--test/unicode_ut.c10
24 files changed, 563 insertions, 159 deletions
diff --git a/arch/arm/lib/crt0_aarch64_efi.S b/arch/arm/lib/crt0_aarch64_efi.S
index cb205fa30a..368933ecf2 100644
--- a/arch/arm/lib/crt0_aarch64_efi.S
+++ b/arch/arm/lib/crt0_aarch64_efi.S
@@ -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 */
diff --git a/arch/arm/lib/crt0_arm_efi.S b/arch/arm/lib/crt0_arm_efi.S
index 5470e2ff0e..cc8a115f31 100644
--- a/arch/arm/lib/crt0_arm_efi.S
+++ b/arch/arm/lib/crt0_arm_efi.S
@@ -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 */
diff --git a/arch/riscv/lib/crt0_riscv_efi.S b/arch/riscv/lib/crt0_riscv_efi.S
index b7b5329e1f..87fe1e56f9 100644
--- a/arch/riscv/lib/crt0_riscv_efi.S
+++ b/arch/riscv/lib/crt0_riscv_efi.S
@@ -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 */
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index c19256e00d..a45bfd139f 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -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;
diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index cb152b3339..02dc491a68 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -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[])
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 3e026697db..359b55a818 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -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);
diff --git a/doc/efi.rst b/doc/efi.rst
index 5337a55c3b..39e2dbae0b 100644
--- a/doc/efi.rst
+++ b/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:
diff --git a/include/asm-generic/pe.h b/include/asm-generic/pe.h
index faae534e37..b247519a3d 100644
--- a/include/asm-generic/pe.h
+++ b/include/asm-generic/pe.h
@@ -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
diff --git a/include/charset.h b/include/charset.h
index 4f7ae8fafd..020f8a90df 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -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
diff --git a/include/efi_loader.h b/include/efi_loader.h
index db4763fc9b..5298ea7997 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -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));
}
diff --git a/include/pe.h b/include/pe.h
index 36e1908b7e..bff3b0aa7a 100644
--- a/include/pe.h
+++ b/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;
diff --git a/lib/charset.c b/lib/charset.c
index 5e349ed5ee..72d745da4f 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -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;
}
diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c
index 3f147cf608..cf02341931 100644
--- a/lib/efi_driver/efi_block_device.c
+++ b/lib/efi_driver/efi_block_device.c
@@ -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)
{
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index b2102c5b5a..2ea21448f0 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -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)
{
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index c2f89805c7..4f6e8d1679 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -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,
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 10f890f44f..eeeb806836 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -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));
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 36ca719a82..f4ca5694ee 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -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;
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 27379381e8..b5775e0399 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -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;
}
/**
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 7a64dd42ca..8b56ab0207 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -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));
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index bc8ed678c9..889a7f2ba0 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -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,
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 88678755cc..5d7a1643ef 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -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 \
diff --git a/lib/efi_selftest/efi_selftest_exitbootservices.c b/lib/efi_selftest/efi_selftest_exitbootservices.c
index f1a136044d..4fecd1b415 100644
--- a/lib/efi_selftest/efi_selftest_exitbootservices.c
+++ b/lib/efi_selftest/efi_selftest_exitbootservices.c
@@ -56,28 +56,6 @@ static int setup(const efi_handle_t handle,
}
/*
- * 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.
*
* Check that the notification function of the EVT_SIGNAL_EXIT_BOOT_SERVICES
@@ -107,5 +85,4 @@ EFI_UNIT_TEST(exitbootservices) = {
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
- .teardown = teardown,
};
diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c
new file mode 100644
index 0000000000..6ee7bbeb01
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c
@@ -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,
+};
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index 8e1efe6f69..1ccd36e7c9 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -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);