[RFC v2 15/20] efi_loader: disk: a helper function to create efi_disk objects from udevice
AKASHI Takahiro
takahiro.akashi at linaro.org
Fri Dec 10 07:49:42 CET 2021
Add efi_disk_probe() function.
This function creates an efi_disk object for a raw disk device (UCLASS_BLK)
and additional objects for related partitions (UCLASS_PARTITION).
So this function is expected to be called through driver model's "probe"
interface every time one raw disk device is detected and activated.
We assume that partition devices (UCLASS_PARTITION) have been created
when this function is invoked.
Signed-off-by: AKASHI Takahiro <takahiro.akashi at linaro.org>
---
include/efi_loader.h | 4 +-
lib/efi_loader/Kconfig | 2 +
lib/efi_loader/efi_disk.c | 206 ++++++++++++++++++++++++-------------
lib/efi_loader/efi_setup.c | 11 +-
4 files changed, 142 insertions(+), 81 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index d52e399841ba..a51095930efa 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -519,8 +519,8 @@ efi_status_t EFIAPI efi_convert_pointer(efi_uintn_t debug_disposition,
void efi_carve_out_dt_rsv(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/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 700dc838ddb9..108c00343fce 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -11,6 +11,7 @@ config EFI_LOADER
# We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB
depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT
depends on BLK
+ depends on EVENT
depends on DM_ETH || !NET
depends on !EFI_APP
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
@@ -41,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/efi_disk.c b/lib/efi_loader/efi_disk.c
index 45127d176869..2941b0c3db47 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>
@@ -487,103 +490,158 @@ error:
return ret;
}
-/**
- * efi_disk_create_partitions() - create handles and protocols for partitions
+/*
+ * Create a handle for a whole raw disk
*
- * Create handles and protocols for the partitions of a block device.
+ * @dev uclass device (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
+ * Create an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
+ *
+ * @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;
- struct efi_handler *handler;
- /* 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++;
+ 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 disks;
+ return 0;
}
-/**
- * efi_disk_register() - register block devices
- *
- * 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.
+/*
+ * Create a handle for a disk partition
*
- * This function is called in efi_init_obj_list().
+ * @dev uclass device (UCLASS_PARTITION)
*
- * TODO(sjg at 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.
+ * Create an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_PARTITION.
*
- * Return: status code
+ * @return 0 on success, -1 otherwise
*/
-efi_status_t efi_disk_register(void)
+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;
- int disks = 0;
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;
+
+ ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
+ 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 0;
+}
+
+/*
+ * Create efi_disk objects for a block device
+ *
+ * @dev uclass device (UCLASS_BLK)
+ *
+ * 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.
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_probe(void *ctx, struct event *event)
+{
struct udevice *dev;
+ enum uclass_id id;
+ struct udevice *child;
+ int ret;
- 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++;
+ /* TODO: We won't support partitions in a partition */
+ if (id != UCLASS_BLK) {
+ if (id != UCLASS_PARTITION)
+ log_info("Not a block device: %s\n", dev->name);
+ return 0;
+ }
+
+ ret = efi_disk_create_raw(dev);
+ if (ret)
+ return -1;
- /* Partitions show up as block devices in EFI */
- disks += efi_disk_create_partitions(
- &disk->header, desc, if_typename,
- desc->devnum, dev->name);
+ device_foreach_child(child, dev) {
+ ret = efi_disk_create_part(child);
+ if (ret)
+ return -1;
}
- log_info("Found %d disks\n", disks);
+ return 0;
+}
+
+efi_status_t efi_disk_init(void)
+{
+ int ret;
+
+ 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;
+ }
return EFI_SUCCESS;
}
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index 1aba71cd9624..1c912b0157aa 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -200,11 +200,12 @@ 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
+ if (IS_ENABLED(CONFIG_BLK)) {
+ ret = efi_disk_init();
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
+
if (IS_ENABLED(CONFIG_EFI_RNG_PROTOCOL)) {
ret = efi_rng_register();
if (ret != EFI_SUCCESS)
--
2.33.0
More information about the U-Boot
mailing list