Browse Source

Merge tag 'efi-2021-01-rc1' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for efi-2021-01-rc1

The following bugs in the UEFI system are resolved:

* illegal free in EFI_LOAD_FILE2_PROTOCOL implementation
* incorrect documentation of EFI_LOAD_FILE2_PROTOCOL implementation
* output of CRC32 as decimal instead hexadecimal in unit test
* use EfiReservedMemoryType for no-map reserved memory
* avoid unnecessary resets in UEFI unit tests
* call EFI bootmgr even without having /EFI/boot
Tom Rini 3 years ago
parent
commit
5dcf7cc590

+ 28 - 6
cmd/bootefi.c

@@ -135,12 +135,29 @@ done:
 	return ret;
 }
 
-static void efi_reserve_memory(u64 addr, u64 size)
+/**
+ * efi_reserve_memory() - add reserved memory to memory map
+ *
+ * @addr:	start address of the reserved memory range
+ * @size:	size of the reserved memory range
+ * @nomap:	indicates that the memory range shall not be accessed by the
+ *		UEFI payload
+ */
+static void efi_reserve_memory(u64 addr, u64 size, bool nomap)
 {
+	int type;
+	efi_uintn_t ret;
+
 	/* Convert from sandbox address space. */
 	addr = (uintptr_t)map_sysmem(addr, 0);
-	if (efi_add_memory_map(addr, size,
-			       EFI_RESERVED_MEMORY_TYPE) != EFI_SUCCESS)
+
+	if (nomap)
+		type = EFI_RESERVED_MEMORY_TYPE;
+	else
+		type = EFI_BOOT_SERVICES_DATA;
+
+	ret = efi_add_memory_map(addr, size, type);
+	if (ret != EFI_SUCCESS)
 		log_err("Reserved memory mapping failed addr %llx size %llx\n",
 			addr, size);
 }
@@ -166,7 +183,7 @@ static void efi_carve_out_dt_rsv(void *fdt)
 	for (i = 0; i < nr_rsv; i++) {
 		if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
 			continue;
-		efi_reserve_memory(addr, size);
+		efi_reserve_memory(addr, size, false);
 	}
 
 	/* process reserved-memory */
@@ -186,8 +203,13 @@ static void efi_carve_out_dt_rsv(void *fdt)
 			 * a size instead of a reg property.
 			 */
 			if (fdt_addr != FDT_ADDR_T_NONE &&
-			    fdtdec_get_is_enabled(fdt, subnode))
-				efi_reserve_memory(fdt_addr, fdt_size);
+			    fdtdec_get_is_enabled(fdt, subnode)) {
+				bool nomap;
+
+				nomap = !!fdt_getprop(fdt, subnode, "no-map",
+						      NULL);
+				efi_reserve_memory(fdt_addr, fdt_size, nomap);
+			}
 			subnode = fdt_next_subnode(fdt, subnode);
 		}
 	}

+ 0 - 1
configs/qemu_arm_defconfig

@@ -56,4 +56,3 @@ CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_PCI=y
-# CONFIG_EFI_GRUB_ARM32_WORKAROUND is not set

+ 6 - 3
include/config_distro_bootcmd.h

@@ -123,12 +123,14 @@
 
 
 #define BOOTENV_SHARED_EFI                                                \
-	"boot_efi_binary="                                                \
+	"boot_efi_bootmgr="                                               \
 		"if fdt addr ${fdt_addr_r}; then "                        \
 			"bootefi bootmgr ${fdt_addr_r};"                  \
 		"else "                                                   \
-			"bootefi bootmgr ${fdtcontroladdr};"              \
-		"fi;"                                                     \
+			"bootefi bootmgr;"                                \
+		"fi\0"                                                    \
+	\
+	"boot_efi_binary="                                                \
 		"load ${devtype} ${devnum}:${distro_bootpart} "           \
 			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
 		"if fdt addr ${fdt_addr_r}; then "                        \
@@ -152,6 +154,7 @@
 				"run load_efi_dtb; "                      \
 			"fi;"                                             \
 		"done;"                                                   \
+		"run boot_efi_bootmgr;"                                   \
 		"if test -e ${devtype} ${devnum}:${distro_bootpart} "     \
 					"efi/boot/"BOOTEFI_NAME"; then "  \
 				"echo Found EFI removable media binary "  \

+ 1 - 0
lib/efi_loader/Kconfig

@@ -164,6 +164,7 @@ config EFI_HAVE_RUNTIME_RESET
 
 config EFI_GRUB_ARM32_WORKAROUND
 	bool "Workaround for GRUB on 32bit ARM"
+	default n if ARCH_QEMU
 	default y
 	depends on ARM && !ARM64
 	help

+ 32 - 27
lib/efi_loader/efi_load_initrd.c

@@ -47,9 +47,9 @@ static const struct efi_initrd_dp dp = {
 /**
  * get_file_size() - retrieve the size of initramfs, set efi status on error
  *
- * @dev:			device to read from. i.e "mmc"
- * @part:			device partition. i.e "0:1"
- * @file:			name fo file
+ * @dev:			device to read from, e.g. "mmc"
+ * @part:			device partition, e.g. "0:1"
+ * @file:			name of file
  * @status:			EFI exit code in case of failure
  *
  * Return:			size of file
@@ -78,15 +78,16 @@ out:
 }
 
 /**
- * load_file2() - get information about random number generation
+ * efi_load_file2initrd() - load initial RAM disk
+ *
+ * This function implements the LoadFile service of the EFI_LOAD_FILE2_PROTOCOL
+ * in order to load an initial RAM disk requested by the Linux kernel stub.
  *
- * This function implement the LoadFile2() service in order to load an initram
- * disk requested by the Linux kernel stub.
  * See the UEFI spec for details.
  *
- * @this:			loadfile2 protocol instance
- * @file_path:			relative path of the file. "" in this case
- * @boot_policy:		must be false for Loadfile2
+ * @this:			EFI_LOAD_FILE2_PROTOCOL instance
+ * @file_path:			media device path of the file, "" in this case
+ * @boot_policy:		must be false
  * @buffer_size:		size of allocated buffer
  * @buffer:			buffer to load the file
  *
@@ -97,19 +98,20 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this,
 		      struct efi_device_path *file_path, bool boot_policy,
 		      efi_uintn_t *buffer_size, void *buffer)
 {
-	const char *filespec = CONFIG_EFI_INITRD_FILESPEC;
+	char *filespec;
 	efi_status_t status = EFI_NOT_FOUND;
 	loff_t file_sz = 0, read_sz = 0;
 	char *dev, *part, *file;
-	char *s;
+	char *pos;
 	int ret;
 
 	EFI_ENTRY("%p, %p, %d, %p, %p", this, file_path, boot_policy,
 		  buffer_size, buffer);
 
-	s = strdup(filespec);
-	if (!s)
+	filespec = strdup(CONFIG_EFI_INITRD_FILESPEC);
+	if (!filespec)
 		goto out;
+	pos = filespec;
 
 	if (!this || this != &efi_lf2_protocol ||
 	    !buffer_size) {
@@ -128,14 +130,20 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this,
 		goto out;
 	}
 
-	/* expect something like 'mmc 0:1 initrd.cpio.gz' */
-	dev = strsep(&s, " ");
+	/*
+	 * expect a string with three space separated parts:
+	 *
+	 * * a block device type, e.g. "mmc"
+	 * * a device and partition identifier, e.g. "0:1"
+	 * * a file path on the block device, e.g. "/boot/initrd.cpio.gz"
+	 */
+	dev = strsep(&pos, " ");
 	if (!dev)
 		goto out;
-	part = strsep(&s, " ");
+	part = strsep(&pos, " ");
 	if (!part)
 		goto out;
-	file = strsep(&s, " ");
+	file = strsep(&pos, " ");
 	if (!file)
 		goto out;
 
@@ -163,28 +171,25 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this,
 	}
 
 out:
-	free(s);
+	free(filespec);
 	return EFI_EXIT(status);
 }
 
 /**
- * efi_initrd_register() - Register a handle and loadfile2 protocol
+ * efi_initrd_register() - create handle for loading initial RAM disk
  *
- * This function creates a new handle and installs a linux specific GUID
- * to handle initram disk loading during boot.
- * See the UEFI spec for details.
+ * This function creates a new handle and installs a Linux specific vendor
+ * device path and an EFI_LOAD_FILE_2_PROTOCOL. Linux uses the device path
+ * to identify the handle and then calls the LoadFile service of the
+ * EFI_LOAD_FILE_2_PROTOCOL to read the initial RAM disk.
  *
- * Return:			status code
+ * Return:	status code
  */
 efi_status_t efi_initrd_register(void)
 {
 	efi_handle_t efi_initrd_handle = NULL;
 	efi_status_t ret;
 
-	/*
-	 * Set up the handle with the EFI_LOAD_FILE2_PROTOCOL which Linux may
-	 * use to load the initial ramdisk.
-	 */
 	ret = EFI_CALL(efi_install_multiple_protocol_interfaces
 		       (&efi_initrd_handle,
 			/* initramfs */

+ 31 - 0
lib/efi_selftest/efi_selftest.c

@@ -142,6 +142,27 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures)
 	return ret;
 }
 
+/*
+ * Check that a test requiring reset exists.
+ *
+ * @testname:	name of the test
+ * @return:	test, or NULL if not found
+ */
+static bool need_reset(const u16 *testname)
+{
+	struct efi_unit_test *test;
+
+	for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
+	     test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
+		if (testname && efi_st_strcmp_16_8(testname, test->name))
+			continue;
+		if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT ||
+		    test->phase == EFI_SETUP_AFTER_BOOTTIME_EXIT)
+			return true;
+	}
+	return false;
+}
+
 /*
  * Check that a test exists.
  *
@@ -290,6 +311,16 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
 			EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
 			&failures);
 
+	if (!need_reset(testname)) {
+		if (failures)
+			ret = EFI_PROTOCOL_ERROR;
+
+		/* Give feedback */
+		efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n",
+			      failures);
+		return ret;
+	}
+
 	/* Execute mixed tests */
 	efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
 			EFI_ST_SETUP, &failures);

+ 22 - 13
lib/efi_selftest/efi_selftest_console.c

@@ -44,25 +44,28 @@ static void mac(void *pointer, u16 **buf)
 }
 
 /*
- * Print a pointer to an u16 string
+ * printx() - print hexadecimal number to an u16 string
  *
- * @pointer: pointer
- * @buf: pointer to buffer address
- * on return position of terminating zero word
+ * @pointer:	pointer
+ * @prec:	minimum number of digits to print
+ * @buf:	pointer to buffer address,
+ *		on return position of terminating zero word
+ * @size:	size of value to be printed in bytes
  */
-static void pointer(void *pointer, u16 **buf)
+static void printx(u64 p, int prec, u16 **buf)
 {
 	int i;
 	u16 c;
-	uintptr_t p = (uintptr_t)pointer;
 	u16 *pos = *buf;
 
-	for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) {
-		c = (p >> i) & 0x0f;
-		c += '0';
-		if (c > '9')
-			c += 'a' - '9' - 1;
-		*pos++ = c;
+	for (i = 2 * sizeof(p) - 1; i >= 0; --i) {
+		c = (p >> (4 * i)) & 0x0f;
+		if (c || pos != *buf || !i || i < prec) {
+			c += '0';
+			if (c > '9')
+				c += 'a' - '9' - 1;
+			*pos++ = c;
+		}
 	}
 	*pos = 0;
 	*buf = pos;
@@ -212,7 +215,9 @@ void efi_st_printc(int color, const char *fmt, ...)
 					break;
 				default:
 					--c;
-					pointer(va_arg(args, void*), &pos);
+					printx((uintptr_t)va_arg(args, void *),
+					       2 * sizeof(void *), &pos);
+					break;
 				}
 				break;
 			case 's':
@@ -223,6 +228,10 @@ void efi_st_printc(int color, const char *fmt, ...)
 			case 'u':
 				uint2dec(va_arg(args, u32), prec, &pos);
 				break;
+			case 'x':
+				printx((u64)va_arg(args, unsigned int),
+				       prec, &pos);
+				break;
 			default:
 				break;
 			}

+ 1 - 1
lib/efi_selftest/efi_selftest_load_initrd.c

@@ -200,7 +200,7 @@ static int execute(void)
 		efi_st_error("Could not determine CRC32\n");
 		return EFI_ST_FAILURE;
 	}
-	efi_st_printf("CRC32 %u\n", (unsigned int)crc32);
+	efi_st_printf("CRC32 %.8x\n", (unsigned int)crc32);
 
 	status = boottime->free_pool(buf);
 	if (status != EFI_SUCCESS) {

+ 1 - 1
lib/efi_selftest/efi_selftest_set_virtual_address_map.c

@@ -23,7 +23,7 @@ static u32 notify_call_count;
 static bool convert_pointer_failed;
 
 /**
- * notify () - notification function
+ * notify() - notification function
  *
  * This function is called when the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event
  * occurs. The correct output of ConvertPointer() is checked.