summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/bootefi.c36
-rw-r--r--cmd/bootmenu.c4
-rw-r--r--common/board_r.c2
-rw-r--r--common/main.c7
-rw-r--r--disk/Kconfig37
-rw-r--r--disk/Makefile3
-rw-r--r--disk/disk-uclass.c247
-rw-r--r--doc/board/apple/m1.rst3
-rw-r--r--doc/develop/driver-model/design.rst21
-rw-r--r--doc/kwboot.12
-rw-r--r--doc/usage/cmd/bootefi.rst21
-rw-r--r--drivers/block/blk-uclass.c4
-rw-r--r--drivers/core/tag.c4
-rw-r--r--include/dm/uclass-id.h1
-rw-r--r--include/efi_loader.h6
-rw-r--r--include/part.h39
-rw-r--r--include/sandboxblockdev.h2
-rw-r--r--lib/efi_driver/efi_block_device.c34
-rw-r--r--lib/efi_loader/Kconfig5
-rw-r--r--lib/efi_loader/Makefile2
-rw-r--r--lib/efi_loader/efi_device_path.c9
-rw-r--r--lib/efi_loader/efi_disk.c321
-rw-r--r--lib/efi_loader/efi_setup.c62
-rw-r--r--test/dm/Makefile1
-rw-r--r--test/dm/tag.c84
25 files changed, 789 insertions, 168 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 53d9f0e0dc..d80353fa71 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -422,10 +422,11 @@ static int do_efibootmgr(void)
* Set up memory image for the binary to be loaded, prepare device path, and
* then call do_bootefi_exec() to execute it.
*
- * @image_opt: string of image start address
+ * @image_opt: string with image start address
+ * @size_opt: string with image size or NULL
* Return: status code
*/
-static int do_bootefi_image(const char *image_opt)
+static int do_bootefi_image(const char *image_opt, const char *size_opt)
{
void *image_buf;
unsigned long addr, size;
@@ -443,14 +444,21 @@ static int do_bootefi_image(const char *image_opt)
/* Check that a numeric value was passed */
if (!addr)
return CMD_RET_USAGE;
-
image_buf = map_sysmem(addr, 0);
- if (image_buf != image_addr) {
- log_err("No UEFI binary known at %s\n", image_opt);
- return CMD_RET_FAILURE;
+ if (size_opt) {
+ size = strtoul(size_opt, NULL, 16);
+ if (!size)
+ return CMD_RET_USAGE;
+ efi_clear_bootdev();
+ } else {
+ if (image_buf != image_addr) {
+ log_err("No UEFI binary known at %s\n",
+ image_opt);
+ return CMD_RET_FAILURE;
+ }
+ size = image_size;
}
- size = image_size;
}
ret = efi_run_image(image_buf, size);
@@ -654,7 +662,7 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_FAILURE;
}
- if (argc > 2) {
+ if (argc > 2 && strcmp(argv[2], "-")) {
uintptr_t fdt_addr;
fdt_addr = hextoul(argv[2], NULL);
@@ -677,15 +685,15 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
return do_efi_selftest();
#endif
- return do_bootefi_image(argv[1]);
+ return do_bootefi_image(argv[1], argc > 3 ? argv[3] : NULL);
}
#ifdef CONFIG_SYS_LONGHELP
static char bootefi_help_text[] =
- "<image address> [fdt address]\n"
- " - boot EFI payload stored at address <image address>.\n"
- " If specified, the device tree located at <fdt address> gets\n"
- " exposed as EFI configuration table.\n"
+ "<image address> [fdt address [image size]]\n"
+ " - boot EFI payload stored at <image address>\n"
+ " fdt address, address of device-tree or '-'\n"
+ " image size, required if image not preloaded\n"
#ifdef CONFIG_CMD_BOOTEFI_HELLO
"bootefi hello\n"
" - boot a sample Hello World application stored within U-Boot\n"
@@ -707,7 +715,7 @@ static char bootefi_help_text[] =
#endif
U_BOOT_CMD(
- bootefi, 3, 0, do_bootefi,
+ bootefi, 4, 0, do_bootefi,
"Boots an EFI payload from memory",
bootefi_help_text
);
diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c
index 409ef9a848..d573487272 100644
--- a/cmd/bootmenu.c
+++ b/cmd/bootmenu.c
@@ -463,7 +463,7 @@ static void bootmenu_show(int delay)
}
for (iter = bootmenu->first; iter; iter = iter->next) {
- if (!menu_item_add(menu, iter->key, iter))
+ if (menu_item_add(menu, iter->key, iter) != 1)
goto cleanup;
}
@@ -476,7 +476,7 @@ static void bootmenu_show(int delay)
init = 1;
- if (menu_get_choice(menu, &choice)) {
+ if (menu_get_choice(menu, &choice) == 1) {
iter = choice;
title = strdup(iter->title);
command = strdup(iter->command);
diff --git a/common/board_r.c b/common/board_r.c
index 8dc87ed2be..7d0281f544 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -795,7 +795,7 @@ static init_fnc_t init_sequence_r[] = {
initr_mem,
#endif
#ifdef CONFIG_EFI_SETUP_EARLY
- (init_fnc_t)efi_init_obj_list,
+ efi_init_early,
#endif
run_main_loop,
};
diff --git a/common/main.c b/common/main.c
index 3f5214fd44..682f3359ea 100644
--- a/common/main.c
+++ b/common/main.c
@@ -54,8 +54,11 @@ void main_loop(void)
if (IS_ENABLED(CONFIG_UPDATE_TFTP))
update_tftp(0UL, NULL, NULL);
- if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
- efi_launch_capsules();
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY)) {
+ /* efi_init_early() already called */
+ if (efi_init_obj_list() == EFI_SUCCESS)
+ efi_launch_capsules();
+ }
s = bootdelay_process();
if (cli_process_fdt(&s))
diff --git a/disk/Kconfig b/disk/Kconfig
index 13700322e9..359af3b27e 100644
--- a/disk/Kconfig
+++ b/disk/Kconfig
@@ -2,8 +2,7 @@
menu "Partition Types"
config PARTITIONS
- bool "Enable Partition Labels (disklabels) support"
- default y
+ bool
help
Partition Labels (disklabels) Supported:
Zero or more of the following:
@@ -20,8 +19,7 @@ config PARTITIONS
as well.
config SPL_PARTITIONS
- bool "Enable Partition Labels (disklabels) support in SPL"
- default y if PARTITIONS
+ bool
select SPL_SPRINTF
select SPL_STRTO
help
@@ -30,8 +28,7 @@ config SPL_PARTITIONS
small amount of size to SPL, typically 500 bytes.
config TPL_PARTITIONS
- bool "Enable Partition Labels (disklabels) support in TPL"
- default y if PARTITIONS
+ bool
select TPL_SPRINTF
select TPL_STRTO
help
@@ -41,57 +38,61 @@ config TPL_PARTITIONS
config MAC_PARTITION
bool "Enable Apple's MacOS partition table"
- depends on PARTITIONS
+ select PARTITIONS
help
Say Y here if you would like to use device under U-Boot which
were partitioned on a Macintosh.
config SPL_MAC_PARTITION
bool "Enable Apple's MacOS partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
default y if MAC_PARTITION
+ select SPL_PARTITIONS
config DOS_PARTITION
bool "Enable MS Dos partition table"
- depends on PARTITIONS
default y if DISTRO_DEFAULTS
default y if x86 || CMD_FAT || USB_STORAGE
+ select PARTITIONS
help
traditional on the Intel architecture, USB sticks, etc.
config SPL_DOS_PARTITION
bool "Enable MS Dos partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
default n if ARCH_SUNXI
default y if DOS_PARTITION
+ select SPL_PARTITIONS
config ISO_PARTITION
bool "Enable ISO partition table"
- depends on PARTITIONS
default y if DISTRO_DEFAULTS
default y if MIPS || ARCH_TEGRA
+ select PARTITIONS
config SPL_ISO_PARTITION
bool "Enable ISO partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
+ select SPL_PARTITIONS
config AMIGA_PARTITION
bool "Enable AMIGA partition table"
- depends on PARTITIONS
+ select PARTITIONS
help
Say Y here if you would like to use device under U-Boot which
were partitioned under AmigaOS.
config SPL_AMIGA_PARTITION
bool "Enable AMIGA partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
default y if AMIGA_PARTITION
+ select SPL_PARTITIONS
config EFI_PARTITION
bool "Enable EFI GPT partition table"
- depends on PARTITIONS
default y if DISTRO_DEFAULTS
default y if ARCH_TEGRA
+ select PARTITIONS
select LIB_UUID
help
Say Y here if you would like to use device under U-Boot which
@@ -128,9 +129,10 @@ config EFI_PARTITION_ENTRIES_OFF
config SPL_EFI_PARTITION
bool "Enable EFI GPT partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
default n if ARCH_SUNXI
default y if EFI_PARTITION
+ select SPL_PARTITIONS
config PARTITION_UUIDS
bool "Enable support of UUID for partition"
@@ -143,12 +145,11 @@ config PARTITION_UUIDS
config SPL_PARTITION_UUIDS
bool "Enable support of UUID for partition in SPL"
- depends on SPL && PARTITIONS
+ depends on SPL_PARTITIONS
default y if SPL_EFI_PARTITION
config PARTITION_TYPE_GUID
bool "Enable support of GUID for partition type"
- depends on PARTITIONS
depends on EFI_PARTITION
help
Activate the configuration of GUID type
diff --git a/disk/Makefile b/disk/Makefile
index 5ca10c5576..ec148832b3 100644
--- a/disk/Makefile
+++ b/disk/Makefile
@@ -6,6 +6,9 @@
#ccflags-y += -DET_DEBUG -DDEBUG
obj-$(CONFIG_$(SPL_TPL_)PARTITIONS) += part.o
+ifdef CONFIG_$(SPL_TPL_)BLK
+obj-$(CONFIG_$(SPL_TPL_)PARTITIONS) += disk-uclass.o
+endif
obj-$(CONFIG_$(SPL_TPL_)MAC_PARTITION) += part_mac.o
obj-$(CONFIG_$(SPL_TPL_)DOS_PARTITION) += part_dos.o
obj-$(CONFIG_$(SPL_TPL_)ISO_PARTITION) += part_iso.o
diff --git a/disk/disk-uclass.c b/disk/disk-uclass.c
new file mode 100644
index 0000000000..72ff62ebf5
--- /dev/null
+++ b/disk/disk-uclass.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Software partition device (UCLASS_PARTITION)
+ *
+ * Copyright (c) 2021 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#define LOG_CATEGORY UCLASS_PARTITION
+
+#include <blk.h>
+#include <dm.h>
+#include <log.h>
+#include <part.h>
+#include <vsprintf.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+int part_create_block_devices(struct udevice *blk_dev)
+{
+ int part, count;
+ struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
+ struct disk_partition info;
+ struct disk_part *part_data;
+ char devname[32];
+ struct udevice *dev;
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(PARTITIONS) ||
+ !CONFIG_IS_ENABLED(HAVE_BLOCK_DEVICE))
+ return 0;
+
+ if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
+ return 0;
+
+ /* Add devices for each partition */
+ for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+ if (part_get_info(desc, part, &info))
+ continue;
+ snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
+ part);
+
+ ret = device_bind_driver(blk_dev, "blk_partition",
+ strdup(devname), &dev);
+ if (ret)
+ return ret;
+
+ part_data = dev_get_uclass_plat(dev);
+ part_data->partnum = part;
+ part_data->gpt_part_info = info;
+ count++;
+
+ ret = device_probe(dev);
+ if (ret) {
+ debug("Can't probe\n");
+ count--;
+ device_unbind(dev);
+
+ continue;
+ }
+ }
+ debug("%s: %d partitions found in %s\n", __func__, count,
+ blk_dev->name);
+
+ return 0;
+}
+
+static ulong blk_part_read(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, void *buffer)
+{
+ struct udevice *parent;
+ struct disk_part *part;
+ const struct blk_ops *ops;
+
+ parent = dev_get_parent(dev);
+ ops = blk_get_ops(parent);
+ if (!ops->read)
+ return -ENOSYS;
+
+ part = dev_get_uclass_plat(dev);
+ if (start >= part->gpt_part_info.size)
+ return 0;
+
+ if ((start + blkcnt) > part->gpt_part_info.size)
+ blkcnt = part->gpt_part_info.size - start;
+ start += part->gpt_part_info.start;
+
+ return ops->read(parent, start, blkcnt, buffer);
+}
+
+static ulong blk_part_write(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ struct udevice *parent;
+ struct disk_part *part;
+ const struct blk_ops *ops;
+
+ parent = dev_get_parent(dev);
+ ops = blk_get_ops(parent);
+ if (!ops->write)
+ return -ENOSYS;
+
+ part = dev_get_uclass_plat(dev);
+ if (start >= part->gpt_part_info.size)
+ return 0;
+
+ if ((start + blkcnt) > part->gpt_part_info.size)
+ blkcnt = part->gpt_part_info.size - start;
+ start += part->gpt_part_info.start;
+
+ return ops->write(parent, start, blkcnt, buffer);
+}
+
+static ulong blk_part_erase(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt)
+{
+ struct udevice *parent;
+ struct disk_part *part;
+ const struct blk_ops *ops;
+
+ parent = dev_get_parent(dev);
+ ops = blk_get_ops(parent);
+ if (!ops->erase)
+ return -ENOSYS;
+
+ part = dev_get_uclass_plat(dev);
+ if (start >= part->gpt_part_info.size)
+ return 0;
+
+ if ((start + blkcnt) > part->gpt_part_info.size)
+ blkcnt = part->gpt_part_info.size - start;
+ start += part->gpt_part_info.start;
+
+ return ops->erase(parent, start, blkcnt);
+}
+
+static const struct blk_ops blk_part_ops = {
+ .read = blk_part_read,
+ .write = blk_part_write,
+ .erase = blk_part_erase,
+};
+
+U_BOOT_DRIVER(blk_partition) = {
+ .name = "blk_partition",
+ .id = UCLASS_PARTITION,
+ .ops = &blk_part_ops,
+};
+
+/*
+ * BLOCK IO APIs
+ */
+static struct blk_desc *dev_get_blk(struct udevice *dev)
+{
+ struct blk_desc *block_dev;
+
+ switch (device_get_uclass_id(dev)) {
+ /*
+ * We won't support UCLASS_BLK with dev_* interfaces.
+ */
+ case UCLASS_PARTITION:
+ block_dev = dev_get_uclass_plat(dev_get_parent(dev));
+ break;
+ default:
+ block_dev = NULL;
+ break;
+ }
+
+ return block_dev;
+}
+
+unsigned long dev_read(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, void *buffer)
+{
+ struct blk_desc *block_dev;
+ const struct blk_ops *ops;
+ struct disk_part *part;
+ lbaint_t start_in_disk;
+ ulong blks_read;
+
+ block_dev = dev_get_blk(dev);
+ if (!block_dev)
+ return -ENOSYS;
+
+ ops = blk_get_ops(dev);
+ if (!ops->read)
+ return -ENOSYS;
+
+ start_in_disk = start;
+ if (device_get_uclass_id(dev) == UCLASS_PARTITION) {
+ part = dev_get_uclass_plat(dev);
+ start_in_disk += part->gpt_part_info.start;
+ }
+
+ if (blkcache_read(block_dev->if_type, block_dev->devnum,
+ start_in_disk, blkcnt, block_dev->blksz, buffer))
+ return blkcnt;
+ blks_read = ops->read(dev, start, blkcnt, buffer);
+ if (blks_read == blkcnt)
+ blkcache_fill(block_dev->if_type, block_dev->devnum,
+ start_in_disk, blkcnt, block_dev->blksz, buffer);
+
+ return blks_read;
+}
+
+unsigned long dev_write(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ struct blk_desc *block_dev;
+ const struct blk_ops *ops;
+
+ block_dev = dev_get_blk(dev);
+ if (!block_dev)
+ return -ENOSYS;
+
+ ops = blk_get_ops(dev);
+ if (!ops->write)
+ return -ENOSYS;
+
+ blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+
+ return ops->write(dev, start, blkcnt, buffer);
+}
+
+unsigned long dev_erase(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt)
+{
+ struct blk_desc *block_dev;
+ const struct blk_ops *ops;
+
+ block_dev = dev_get_blk(dev);
+ if (!block_dev)
+ return -ENOSYS;
+
+ ops = blk_get_ops(dev);
+ if (!ops->erase)
+ return -ENOSYS;
+
+ blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+
+ return ops->erase(dev, start, blkcnt);
+}
+
+UCLASS_DRIVER(partition) = {
+ .id = UCLASS_PARTITION,
+ .per_device_plat_auto = sizeof(struct disk_part),
+ .name = "partition",
+};
diff --git a/doc/board/apple/m1.rst b/doc/board/apple/m1.rst
index 083bfb0a1a..8fa7637629 100644
--- a/doc/board/apple/m1.rst
+++ b/doc/board/apple/m1.rst
@@ -10,6 +10,7 @@ the following SoCs work:
- Apple M1 SoC (t8103)
- Apple M1 Pro SoC (t6000)
- Apple M1 Max SoC (t6001)
+ - Apple M1 Ultra SoC (t6002)
On these SoCs the following hardware is supported:
@@ -78,5 +79,5 @@ supported SoCs.
- Base Address
* - M1 (t8103)
- 0x235200000
- * - M1 Pro/Max (t6000/t6001)
+ * - M1 Pro/Max/Ultra (t6000/t6001/t6002)
- 0x39b200000
diff --git a/doc/develop/driver-model/design.rst b/doc/develop/driver-model/design.rst
index b0e6337030..5f33f9fbb3 100644
--- a/doc/develop/driver-model/design.rst
+++ b/doc/develop/driver-model/design.rst
@@ -1042,6 +1042,27 @@ data structure might be worthwhile in some rare cases, once we understand
what the bottlenecks are.
+Tag Support
+-----------
+
+It is sometimes useful for a subsystem to associate its own private
+data (or object) to a DM device, i.e. struct udevice, to support
+additional features.
+
+Tag support in driver model will give us the ability to do so dynamically
+instead of modifying "udevice" data structure. In the initial release, we
+will support two type of attributes:
+
+- a pointer with dm_tag_set_ptr(), and
+- an unsigned long with dm_tag_set_val()
+
+For example, UEFI subsystem utilizes the feature to maintain efi_disk
+objects depending on linked udevice's lifecycle.
+
+While the current implementation is quite simple, it will get evolved
+as the feature is more extensively used in U-Boot subsystems.
+
+
Changes since v1
----------------
diff --git a/doc/kwboot.1 b/doc/kwboot.1
index f555ff26a2..d663bf1f77 100644
--- a/doc/kwboot.1
+++ b/doc/kwboot.1
@@ -74,7 +74,7 @@ BootROM's standard input and BootROM's terminal echo are active and working
fine. To workaround this BootROM bug with standard output, it is possible
to manually overwrite BootROM variables stored in SRAM which BootROM use
for checking if standard output is enabled or not. To enable BootROM
-standard output on UART, type this command folled by ENTER key:
+standard output on UART, type this command followed by ENTER key:
.RS 1.2i
.TP
diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
index 31279fc0cb..4cc8c0718c 100644
--- a/doc/usage/cmd/bootefi.rst
+++ b/doc/usage/cmd/bootefi.rst
@@ -9,7 +9,7 @@ Synopsis
::
- bootefi [image_addr] [fdt_addr]
+ bootefi [image_addr] [fdt_addr [image_size]]
bootefi bootmgr [fdt_addr]
bootefi hello [fdt_addr]
bootefi selftest [fdt_addr]
@@ -41,13 +41,28 @@ command sequence to run a UEFI application might look like
load mmc 0:1 $kernel_addr_r /EFI/grub/grubaa64.efi
bootefi $kernel_addr_r $fdt_addr_r
-The last file loaded defines the image file path in the loaded image protocol.
-Hence the executable should always be loaded last.
+The last UEFI binary loaded defines the image file path in the loaded image
+protocol.
The value of the environment variable *bootargs* is converted from UTF-8 to
UTF-16 and passed as load options in the loaded image protocol to the UEFI
binary.
+image_addr
+ Address of the UEFI binary.
+
+fdt_addr
+ Address of the device-tree or '-'. If no address is specifiy, the
+ environment variable $fdt_addr is used as first fallback, the address of
+ U-Boot's internal device-tree $fdtcontroladdr as second fallback.
+ When using ACPI no device-tree shall be specified.
+
+image_size
+ Size of the UEFI binary file. This argument is only needed if *image_addr*
+ does not match the address of the last loaded UEFI binary. In this case
+ a memory device path will be used as image file path in the loaded image
+ protocol.
+
Note
UEFI binaries that are contained in FIT images are launched via the
*bootm* command.
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index f1e4a85646..791e26c06e 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -741,6 +741,10 @@ static int blk_post_probe(struct udevice *dev)
struct blk_desc *desc = dev_get_uclass_plat(dev);
part_init(desc);
+
+ if (desc->part_type != PART_TYPE_UNKNOWN &&
+ part_create_block_devices(dev))
+ debug("*** creating partitions failed\n");
}
return 0;
diff --git a/drivers/core/tag.c b/drivers/core/tag.c
index 6829bcd880..22999193a5 100644
--- a/drivers/core/tag.c
+++ b/drivers/core/tag.c
@@ -29,7 +29,7 @@ int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
node = calloc(sizeof(*node), 1);
if (!node)
- return -ENOSPC;
+ return -ENOMEM;
node->dev = dev;
node->tag = tag;
@@ -53,7 +53,7 @@ int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val)
node = calloc(sizeof(*node), 1);
if (!node)
- return -ENOSPC;
+ return -ENOMEM;
node->dev = dev;
node->tag = tag;
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 0e26e1d138..230b1ea528 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -83,6 +83,7 @@ enum uclass_id {
UCLASS_P2SB, /* (x86) Primary-to-Sideband Bus */
UCLASS_PANEL, /* Display panel, such as an LCD */
UCLASS_PANEL_BACKLIGHT, /* Backlight controller for panel */
+ UCLASS_PARTITION, /* Logical disk partition device */
UCLASS_PCH, /* x86 platform controller hub */
UCLASS_PCI, /* PCI bus */
UCLASS_PCI_EP, /* PCI endpoint device */
diff --git a/include/efi_loader.h b/include/efi_loader.h
index c52ea59ec7..ba79a9afb4 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -493,6 +493,8 @@ struct efi_register_notify_event {
/* List of all events registered by RegisterProtocolNotify() */
extern struct list_head efi_register_notify_events;
+/* called at pre-initialization */
+int efi_init_early(void);
/* Initialize efi execution environment */
efi_status_t efi_init_obj_list(void);
/* Install device tree */
@@ -523,8 +525,8 @@ void efi_carve_out_dt_rsv(void *fdt);
void efi_try_purge_kaslr_seed(void *fdt);
/* Called by bootefi to make console interface available */
efi_status_t efi_console_register(void);
-/* Called by bootefi to make all disk storage accessible as EFI objects */
-efi_status_t efi_disk_register(void);
+/* Called by efi_init_obj_list() to initialize efi_disks */
+efi_status_t efi_disk_init(void);
/* Called by efi_init_obj_list() to install EFI_RNG_PROTOCOL */
efi_status_t efi_rng_register(void);
/* Called by efi_init_obj_list() to install EFI_TCG2_PROTOCOL */
diff --git a/include/part.h b/include/part.h
index 53cfbdd876..3a6958dcb2 100644
--- a/include/part.h
+++ b/include/part.h
@@ -10,6 +10,7 @@
#include <ide.h>
#include <uuid.h>
#include <linker_lists.h>
+#include <linux/errno.h>
#include <linux/list.h>
struct block_drvr {
@@ -86,7 +87,7 @@ struct disk_part {
};
/* Misc _get_dev functions */
-#ifdef CONFIG_PARTITIONS
+#if CONFIG_IS_ENABLED(PARTITIONS)
/**
* blk_get_dev() - get a pointer to a block device given its type and number
*
@@ -103,7 +104,6 @@ struct disk_part {
struct blk_desc *blk_get_dev(const char *ifname, int dev);
struct blk_desc *mg_disk_get_dev(int dev);
-int host_get_dev_err(int dev, struct blk_desc **blk_devp);
/* disk/part.c */
int part_get_info(struct blk_desc *dev_desc, int part,
@@ -275,6 +275,22 @@ static inline int blk_get_device_part_str(const char *ifname,
struct disk_partition *info,
int allow_whole_dev)
{ *dev_desc = NULL; return -1; }
+
+static inline int part_get_info_by_name_type(struct blk_desc *dev_desc,
+ const char *name,
+ struct disk_partition *info,
+ int part_type)
+{
+ return -ENOENT;
+}
+
+static inline int part_get_info_by_name(struct blk_desc *dev_desc,
+ const char *name,
+ struct disk_partition *info)
+{
+ return -ENOENT;
+}
+
static inline int
part_get_info_by_dev_and_name_or_num(const char *dev_iface,
const char *dev_part_str,
@@ -287,6 +303,23 @@ part_get_info_by_dev_and_name_or_num(const char *dev_iface,
}
#endif
+struct udevice;
+/**
+ * part_create_block_devices - Create block devices for disk partitions
+ *
+ * Create UCLASS_PARTITION udevices for each of disk partitions in @parent
+ *
+ * @blk_dev: Whole disk device
+ */
+int part_create_block_devices(struct udevice *blk_dev);
+
+unsigned long dev_read(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, void *buffer);
+unsigned long dev_write(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer);
+unsigned long dev_erase(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt);
+
/*
* We don't support printing partition information in SPL and only support
* getting partition information in a few cases.
@@ -496,7 +529,7 @@ int layout_mbr_partitions(struct disk_partition *p, int count,
#endif
-#ifdef CONFIG_PARTITIONS
+#if CONFIG_IS_ENABLED(PARTITIONS)
/**
* part_driver_get_count() - get partition driver count
*
diff --git a/include/sandboxblockdev.h b/include/sandboxblockdev.h
index 4ca9554e38..dc983f0417 100644
--- a/include/sandboxblockdev.h
+++ b/include/sandboxblockdev.h
@@ -26,4 +26,6 @@ struct host_block_dev {
*/
int host_dev_bind(int dev, char *filename, bool removable);
+int host_get_dev_err(int dev, struct blk_desc **blk_devp);
+
#endif
diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c
index 04cb3ef0d4..5baa6f87a3 100644
--- a/lib/efi_driver/efi_block_device.c
+++ b/lib/efi_driver/efi_block_device.c
@@ -35,6 +35,7 @@
#include <malloc.h>
#include <dm/device-internal.h>
#include <dm/root.h>
+#include <dm/tag.h>
/*
* EFI attributes of the udevice handled by this driver.
@@ -107,25 +108,6 @@ static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
}
/**
- * Create partions for 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)
-{
- struct blk_desc *desc;
- const char *if_typename;
-
- desc = dev_get_uclass_plat(dev);
- if_typename = blk_get_if_type_name(desc->if_type);
-
- return efi_disk_create_partitions(handle, desc, if_typename,
- desc->devnum, dev->name);
-}
-
-/**
* Create a block device for a handle
*
* @handle: handle
@@ -139,7 +121,6 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
char *name;
struct efi_object *obj = efi_search_obj(handle);
struct efi_block_io *io = interface;
- int disks;
struct efi_blk_plat *plat;
EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io);
@@ -173,15 +154,20 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
plat->handle = handle;
plat->io = interface;
+ /*
+ * FIXME: necessary because we won't do almost nothing in
+ * efi_disk_create() when called from device_probe().
+ */
+ ret = dev_tag_set_ptr(bdev, DM_TAG_EFI, handle);
+ if (ret)
+ /* FIXME: cleanup for bdev */
+ return ret;
+
ret = device_probe(bdev);
if (ret)
return ret;
EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name);
- /* Create handles for the partions of the block device */
- disks = efi_bl_bind_partitions(handle, bdev);
- EFI_PRINT("Found %d partitions\n", disks);
-
return 0;
}
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index d50cd2563d..6b245f50a7 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -14,8 +14,10 @@ config EFI_LOADER
depends on DM_ETH || !NET
depends on !EFI_APP
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
+ select DM_EVENT
+ select EVENT_DYNAMIC
select LIB_UUID
- select PARTITION_UUIDS
+ imply PARTITION_UUIDS
select HAVE_BLOCK_DEVICE
select REGEX
imply FAT
@@ -40,6 +42,7 @@ config CMD_BOOTEFI_BOOTMGR
config EFI_SETUP_EARLY
bool
+ default y
choice
prompt "Store for non-volatile UEFI variables"
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 034d26cf01..aaaa25cefe 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -68,7 +68,7 @@ obj-y += efi_watchdog.o
obj-$(CONFIG_EFI_ESRT) += efi_esrt.o
obj-$(CONFIG_LCD) += efi_gop.o
obj-$(CONFIG_DM_VIDEO) += efi_gop.o
-obj-$(CONFIG_PARTITIONS) += efi_disk.o
+obj-$(CONFIG_BLK) += efi_disk.o
obj-$(CONFIG_NET) += efi_net.o
obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o
obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 0542aaae16..50a988c561 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -864,11 +864,16 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
break;
case SIG_TYPE_GUID:
hddp->signature_type = 2;
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+ /* info.uuid exists only with PARTITION_UUIDS */
if (uuid_str_to_bin(info.uuid,
- hddp->partition_signature, 1))
+ hddp->partition_signature,
+ UUID_STR_FORMAT_GUID)) {
log_warning(
- "Partition no. %d: invalid guid: %s\n",
+ "Partition %d: invalid GUID %s\n",
part, info.uuid);
+ }
+#endif
break;
}
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index c905c12abc..8fb5b2363c 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -10,6 +10,9 @@
#include <common.h>
#include <blk.h>
#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/tag.h>
+#include <event.h>
#include <efi_loader.h>
#include <fs.h>
#include <log.h>
@@ -33,7 +36,7 @@ const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
* @part: partition
* @volume: simple file system protocol of the partition
* @offset: offset into disk for simple partition
- * @desc: internal block device descriptor
+ * @dev: associated DM device
*/
struct efi_disk_obj {
struct efi_object header;
@@ -45,7 +48,7 @@ struct efi_disk_obj {
unsigned int part;
struct efi_simple_file_system_protocol *volume;
lbaint_t offset;
- struct blk_desc *desc;
+ struct udevice *dev; /* TODO: move it to efi_object */
};
/**
@@ -80,14 +83,12 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
void *buffer, enum efi_disk_direction direction)
{
struct efi_disk_obj *diskobj;
- struct blk_desc *desc;
int blksz;
int blocks;
unsigned long n;
diskobj = container_of(this, struct efi_disk_obj, ops);
- desc = (struct blk_desc *) diskobj->desc;
- blksz = desc->blksz;
+ blksz = diskobj->media.block_size;
blocks = buffer_size / blksz;
lba += diskobj->offset;
@@ -98,10 +99,21 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
if (buffer_size & (blksz - 1))
return EFI_BAD_BUFFER_SIZE;
+#if CONFIG_IS_ENABLED(PARTITIONS)
+ if (direction == EFI_DISK_READ)
+ n = dev_read(diskobj->dev, lba, blocks, buffer);
+ else
+ n = dev_write(diskobj->dev, lba, blocks, buffer);
+#else
+ /* dev is always a block device (UCLASS_BLK) */
+ struct blk_desc *desc;
+
+ desc = dev_get_uclass_plat(diskobj->dev);
if (direction == EFI_DISK_READ)
n = blk_dread(desc, lba, blocks, buffer);
else
n = blk_dwrite(desc, lba, blocks, buffer);
+#endif
/* We don't do interrupts, so check for timers cooperatively */
efi_timer_check();
@@ -443,7 +455,6 @@ static efi_status_t efi_disk_add_dev(
diskobj->ops = block_io_disk_template;
diskobj->ifname = if_typename;
diskobj->dev_index = dev_index;
- diskobj->desc = desc;
/* Fill in EFI IO Media info (for read/write callbacks) */
diskobj->media.removable_media = desc->removable;
@@ -487,103 +498,255 @@ error:
return ret;
}
-/**
- * efi_disk_create_partitions() - create handles and protocols for partitions
+/*
+ * Create a handle for a whole raw disk
+ *
+ * @dev uclass device (UCLASS_BLK)
*
- * Create handles and protocols for the partitions of a block device.
+ * Create an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
*
- * @parent: handle of the parent disk
- * @desc: block device
- * @if_typename: interface type
- * @diskid: device number
- * @pdevname: device name
- * Return: number of partitions created
+ * @return 0 on success, -1 otherwise
*/
-int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
- const char *if_typename, int diskid,
- const char *pdevname)
+static int efi_disk_create_raw(struct udevice *dev)
{
- int disks = 0;
- char devname[32] = { 0 }; /* dp->str is u16[32] long */
- int part;
- struct efi_device_path *dp = NULL;
+ struct efi_disk_obj *disk;
+ struct blk_desc *desc;
+ const char *if_typename;
+ int diskid;
efi_status_t ret;
+
+ desc = dev_get_uclass_plat(dev);
+ if_typename = blk_get_if_type_name(desc->if_type);
+ diskid = desc->devnum;
+
+ ret = efi_disk_add_dev(NULL, NULL, if_typename, desc,
+ diskid, NULL, 0, &disk);
+ if (ret != EFI_SUCCESS) {
+ if (ret == EFI_NOT_READY)
+ log_notice("Disk %s not ready\n", dev->name);
+ else
+ log_err("Adding disk for %s failed\n", dev->name);
+
+ return -1;
+ }
+ disk->dev = dev;
+ if (dev_tag_set_ptr(dev, DM_TAG_EFI, &disk->header)) {
+ efi_free_pool(disk->dp);
+ efi_delete_handle(&disk->header);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Create a handle for a disk partition
+ *
+ * @dev uclass device (UCLASS_PARTITION)
+ *
+ * Create an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_PARTITION.
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_create_part(struct udevice *dev)
+{
+ efi_handle_t parent;
+ struct blk_desc *desc;
+ const char *if_typename;
+ struct disk_part *part_data;
+ struct disk_partition *info;
+ unsigned int part;
+ int diskid;
struct efi_handler *handler;
+ struct efi_device_path *dp_parent;
+ struct efi_disk_obj *disk;
+ efi_status_t ret;
+
+ if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
+ return -1;
+
+ desc = dev_get_uclass_plat(dev_get_parent(dev));
+ if_typename = blk_get_if_type_name(desc->if_type);
+ diskid = desc->devnum;
+
+ part_data = dev_get_uclass_plat(dev);
+ part = part_data->partnum;
+ info = &part_data->gpt_part_info;
- /* Get the device path of the parent */
ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
- if (ret == EFI_SUCCESS)
- dp = handler->protocol_interface;
-
- /* Add devices for each partition */
- for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
- struct disk_partition info;
-
- if (part_get_info(desc, part, &info))
- continue;
- snprintf(devname, sizeof(devname), "%s:%x", pdevname,
- part);
- ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid,
- &info, part, NULL);
- if (ret != EFI_SUCCESS) {
- log_err("Adding partition %s failed\n", pdevname);
- continue;
- }
- disks++;
+ if (ret != EFI_SUCCESS)
+ return -1;
+ dp_parent = (struct efi_device_path *)handler->protocol_interface;
+
+ ret = efi_disk_add_dev(parent, dp_parent, if_typename, desc, diskid,
+ info, part, &disk);
+ if (ret != EFI_SUCCESS) {
+ log_err("Adding partition for %s failed\n", dev->name);
+ return -1;
+ }
+ disk->dev = dev;
+ if (dev_tag_set_ptr(dev, DM_TAG_EFI, &disk->header)) {
+ efi_free_pool(disk->dp);
+ efi_delete_handle(&disk->header);
+
+ return -1;
}
- return disks;
+ return 0;
}
-/**
- * efi_disk_register() - register block devices
+/*
+ * Create efi_disk objects for a block device
*
- * U-Boot doesn't have a list of all online disk devices. So when running our
- * EFI payload, we scan through all of the potentially available ones and
- * store them in our object pool.
+ * @dev uclass device (UCLASS_BLK)
*
- * This function is called in efi_init_obj_list().
+ * Create efi_disk objects for partitions as well as a raw disk
+ * which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
+ * This function is expected to be called at EV_PM_POST_PROBE.
*
- * TODO(sjg@chromium.org): Actually with CONFIG_BLK, U-Boot does have this.
- * Consider converting the code to look up devices as needed. The EFI device
- * could be a child of the UCLASS_BLK block device, perhaps.
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_probe(void *ctx, struct event *event)
+{
+ struct udevice *dev;
+ enum uclass_id id;
+ struct blk_desc *desc;
+ struct udevice *child;
+ int ret;
+
+ dev = event->data.dm.dev;
+ id = device_get_uclass_id(dev);
+
+ /* TODO: We won't support partitions in a partition */
+ if (id != UCLASS_BLK)
+ return 0;
+
+ /*
+ * avoid creating duplicated objects now that efi_driver
+ * has already created an efi_disk at this moment.
+ */
+ desc = dev_get_uclass_plat(dev);
+ if (desc->if_type != IF_TYPE_EFI_LOADER) {
+ ret = efi_disk_create_raw(dev);
+ if (ret)
+ return -1;
+ }
+
+ device_foreach_child(child, dev) {
+ ret = efi_disk_create_part(child);
+ if (ret)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Delete an efi_disk object for a whole raw disk
*
- * Return: status code
+ * @dev uclass device (UCLASS_BLK)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
+ *
+ * @return 0 on success, -1 otherwise
*/
-efi_status_t efi_disk_register(void)
+static int efi_disk_delete_raw(struct udevice *dev)
{
- struct efi_disk_obj *disk;
- int disks = 0;
- efi_status_t ret;
+ efi_handle_t handle;
+ struct blk_desc *desc;
+ struct efi_disk_obj *diskobj;
+
+ if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
+ return -1;
+
+ desc = dev_get_uclass_plat(dev);
+ if (desc->if_type != IF_TYPE_EFI_LOADER) {
+ diskobj = container_of(handle, struct efi_disk_obj, header);
+ efi_free_pool(diskobj->dp);
+ }
+
+ efi_delete_handle(handle);
+ dev_tag_del(dev, DM_TAG_EFI);
+
+ return 0;
+}
+
+/*
+ * Delete an efi_disk object for a disk partition
+ *
+ * @dev uclass device (UCLASS_PARTITION)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_PARTITION.
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_delete_part(struct udevice *dev)
+{
+ efi_handle_t handle;
+ struct efi_disk_obj *diskobj;
+
+ if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
+ return -1;
+
+ diskobj = container_of(handle, struct efi_disk_obj, header);
+
+ efi_free_pool(diskobj->dp);
+ efi_delete_handle(handle);
+ dev_tag_del(dev, DM_TAG_EFI);
+
+ return 0;
+}
+
+/*
+ * Delete an efi_disk object for a block device
+ *
+ * @dev uclass device (UCLASS_BLK or UCLASS_PARTITION)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be either UCLASS_BLK or UCLASS_PARTITION.
+ * This function is expected to be called at EV_PM_PRE_REMOVE.
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_remove(void *ctx, struct event *event)
+{
+ enum uclass_id id;
struct udevice *dev;
- for (uclass_first_device_check(UCLASS_BLK, &dev); dev;
- uclass_next_device_check(&dev)) {
- struct blk_desc *desc = dev_get_uclass_plat(dev);
- const char *if_typename = blk_get_if_type_name(desc->if_type);
+ dev = event->data.dm.dev;
+ id = device_get_uclass_id(dev);
- /* Add block device for the full device */
- log_info("Scanning disk %s...\n", dev->name);
- ret = efi_disk_add_dev(NULL, NULL, if_typename,
- desc, desc->devnum, NULL, 0, &disk);
- if (ret == EFI_NOT_READY) {
- log_notice("Disk %s not ready\n", dev->name);
- continue;
- }
- if (ret) {
- log_err("ERROR: failure to add disk device %s, r = %lu\n",
- dev->name, ret & ~EFI_ERROR_MASK);
- continue;
- }
- disks++;
+ if (id == UCLASS_BLK)
+ return efi_disk_delete_raw(dev);
+ else if (id == UCLASS_PARTITION)
+ return efi_disk_delete_part(dev);
+ else
+ return 0;
+}
+
+efi_status_t efi_disk_init(void)
+{
+ int ret;
- /* Partitions show up as block devices in EFI */
- disks += efi_disk_create_partitions(
- &disk->header, desc, if_typename,
- desc->devnum, dev->name);
+ ret = event_register("efi_disk add", EVT_DM_POST_PROBE,
+ efi_disk_probe, NULL);
+ if (ret) {
+ log_err("Event registration for efi_disk add failed\n");
+ return EFI_OUT_OF_RESOURCES;
}
- log_info("Found %d disks\n", disks);
+ ret = event_register("efi_disk del", EVT_DM_PRE_REMOVE,
+ efi_disk_remove, NULL);
+ if (ret) {
+ log_err("Event registration for efi_disk del failed\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
return EFI_SUCCESS;
}
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index eee54e4878..250eeb2fcd 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -174,20 +174,18 @@ static efi_status_t efi_init_os_indications(void)
&os_indications_supported, false);
}
-
/**
- * efi_init_obj_list() - Initialize and populate EFI object list
+ * __efi_init_early() - handle initialization at early stage
+ *
+ * This function is called in efi_init_obj_list() only if
+ * !CONFIG_EFI_SETUP_EARLY.
*
* Return: status code
*/
-efi_status_t efi_init_obj_list(void)
+static efi_status_t __efi_init_early(void)
{
efi_status_t ret = EFI_SUCCESS;
- /* Initialize once only */
- if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
- return efi_obj_list_initialized;
-
/* Allow unaligned memory access */
allow_unaligned();
@@ -200,11 +198,51 @@ efi_status_t efi_init_obj_list(void)
if (ret != EFI_SUCCESS)
goto out;
-#ifdef CONFIG_PARTITIONS
- ret = efi_disk_register();
- if (ret != EFI_SUCCESS)
- goto out;
-#endif
+ ret = efi_disk_init();
+out:
+ return ret;
+}
+
+/**
+ * efi_init_early() - handle initialization at early stage
+ *
+ * external version of __efi_init_early(); expected to be called in
+ * board_init_r().
+ *
+ * Return: status code
+ */
+int efi_init_early(void)
+{
+ efi_status_t ret;
+
+ ret = __efi_init_early();
+ if (ret != EFI_SUCCESS) {
+ /* never re-init UEFI subsystem */
+ efi_obj_list_initialized = ret;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * efi_init_obj_list() - Initialize and populate EFI object list
+ *
+ * Return: status code
+ */
+efi_status_t efi_init_obj_list(void)
+{
+ efi_status_t ret = EFI_SUCCESS;
+
+ /* Initialize once only */
+ if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
+ return efi_obj_list_initialized;
+
+ if (!IS_ENABLED(CONFIG_EFI_SETUP_EARLY)) {
+ ret = __efi_init_early();
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
+
if (IS_ENABLED(CONFIG_EFI_RNG_PROTOCOL)) {
ret = efi_rng_register();
if (ret != EFI_SUCCESS)
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 9a1a904d90..f0a7c97e3d 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -102,6 +102,7 @@ obj-y += syscon.o
obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
obj-$(CONFIG_SYSINFO) += sysinfo.o
obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o
+obj-$(CONFIG_UT_DM) += tag.o
obj-$(CONFIG_TEE) += tee.o
obj-$(CONFIG_TIMER) += timer.o
obj-$(CONFIG_DM_USB) += usb.o
diff --git a/test/dm/tag.c b/test/dm/tag.c
new file mode 100644
index 0000000000..8ae8a1fcd6
--- /dev/null
+++ b/test/dm/tag.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DM tag test
+ *
+ * Copyright (c) 2021 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#include <common.h>
+#include <dm/tag.h>
+#include <dm/test.h> /* DM_TEST() */
+#include <test/test.h> /* struct unit_test_state */
+#include <test/ut.h> /* assertions */
+
+/*
+ * Test dm_tag_ptr() API
+ */
+static int dm_test_tag_ptr(struct unit_test_state *uts)
+{
+ ulong val;
+ void *ptr = NULL;
+
+ ut_assertok(dev_tag_set_ptr(uts->root, DM_TAG_EFI, &val));
+
+ ut_assertok(dev_tag_get_ptr(uts->root, DM_TAG_EFI, &ptr));
+
+ ut_asserteq_ptr(&val, ptr);
+
+ ut_assertok(dev_tag_del(uts->root, DM_TAG_EFI));
+
+ return 0;
+}
+
+DM_TEST(dm_test_tag_ptr, 0);
+
+/*
+ * Test dm_tag_val() API
+ */
+static int dm_test_tag_val(struct unit_test_state *uts)
+{
+ ulong val1 = 0x12345678, val2 = 0;
+
+ ut_assertok(dev_tag_set_val(uts->root, DM_TAG_EFI, val1));
+
+ ut_assertok(dev_tag_get_val(uts->root, DM_TAG_EFI, &val2));
+
+ ut_asserteq_64(val1, val2);
+
+ ut_assertok(dev_tag_del(uts->root, DM_TAG_EFI));
+
+ return 0;
+}
+
+DM_TEST(dm_test_tag_val, 0);
+
+/*
+ * Test against an invalid tag
+ */
+static int dm_test_tag_inval(struct unit_test_state *uts)
+{
+ ulong val;
+
+ ut_asserteq(-EINVAL, dev_tag_set_ptr(uts->root, DM_TAG_COUNT, &val));
+
+ return 0;
+}
+
+DM_TEST(dm_test_tag_inval, 0);
+
+/*
+ * Test dm_tag_del_all() AP:
+ */
+static int dm_test_tag_del_all(struct unit_test_state *uts)
+{
+ ulong val;
+
+ ut_assertok(dev_tag_set_ptr(uts->root, DM_TAG_EFI, &val));
+
+ ut_assertok(dev_tag_del_all(uts->root));
+
+ return 0;
+}
+
+DM_TEST(dm_test_tag_del_all, 0);