瀏覽代碼

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.
Tom Rini 4 年之前
父節點
當前提交
fe4243870d

+ 4 - 5
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 */

+ 4 - 5
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 */

+ 5 - 6
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 */

+ 15 - 5
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;

+ 10 - 6
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[])

+ 11 - 2
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);

+ 85 - 2
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:

+ 16 - 0
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

+ 2 - 2
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

+ 3 - 3
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));
 }

+ 0 - 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;

+ 14 - 9
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;
 }

+ 20 - 19
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)
 {

+ 40 - 7
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)
 {

+ 26 - 12
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,

+ 31 - 9
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));

+ 6 - 1
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;
 

+ 29 - 17
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;
 }
 
 /**

+ 16 - 6
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));

+ 23 - 4
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,

+ 1 - 0
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 \

+ 0 - 23
lib/efi_selftest/efi_selftest_exitbootservices.c

@@ -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 - 0
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,
+};

+ 10 - 0
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);