* [PATCH] efi_loader: eliminate efi_disk_obj structure
@ 2023-12-13 8:57 Masahisa Kojima
2023-12-13 14:22 ` Heinrich Schuchardt
2023-12-14 1:24 ` AKASHI Takahiro
0 siblings, 2 replies; 9+ messages in thread
From: Masahisa Kojima @ 2023-12-13 8:57 UTC (permalink / raw)
To: u-boot; +Cc: Heinrich Schuchardt, Ilias Apalodimas, Masahisa Kojima
Current code uses struct efi_disk_obj to keep information
about block devices and partitions. As the efi handle already
has a field with the udevice, we should eliminate
struct efi_disk_obj and use an pointer to struct efi_object
for the handle.
efi_link_dev() call is moved inside of efi_disk_add_dev() function
to simplify the cleanup process in case of error.
Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
---
lib/efi_loader/efi_disk.c | 209 +++++++++++++++++++++-----------------
1 file changed, 116 insertions(+), 93 deletions(-)
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index f0d76113b0..cfb7ace551 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -27,27 +27,24 @@ struct efi_system_partition efi_system_partition = {
const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
-/**
- * struct efi_disk_obj - EFI disk object
- *
- * @header: EFI object header
- * @ops: EFI disk I/O protocol interface
- * @dev_index: device index of block device
- * @media: block I/O media information
- * @dp: device path to the block device
- * @part: partition
- * @volume: simple file system protocol of the partition
- * @dev: associated DM device
- */
-struct efi_disk_obj {
- struct efi_object header;
- struct efi_block_io ops;
- int dev_index;
- struct efi_block_io_media media;
- struct efi_device_path *dp;
- unsigned int part;
- struct efi_simple_file_system_protocol *volume;
-};
+static efi_handle_t efi_blkio_find_obj(struct efi_block_io *blkio)
+{
+ efi_handle_t handle;
+
+ list_for_each_entry(handle, &efi_obj_list, link) {
+ efi_status_t ret;
+ struct efi_handler *handler;
+
+ ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
+ if (ret != EFI_SUCCESS)
+ continue;
+
+ if (blkio == handler->protocol_interface)
+ return handle;
+ }
+
+ return NULL;
+}
/**
* efi_disk_reset() - reset block device
@@ -107,13 +104,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
u32 media_id, u64 lba, unsigned long buffer_size,
void *buffer, enum efi_disk_direction direction)
{
- struct efi_disk_obj *diskobj;
+ efi_handle_t handle;
int blksz;
int blocks;
unsigned long n;
- diskobj = container_of(this, struct efi_disk_obj, ops);
- blksz = diskobj->media.block_size;
+ handle = efi_blkio_find_obj(this);
+ if (!handle)
+ return EFI_INVALID_PARAMETER;
+
+ blksz = this->media->block_size;
blocks = buffer_size / blksz;
EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
@@ -124,18 +124,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
return EFI_BAD_BUFFER_SIZE;
if (CONFIG_IS_ENABLED(PARTITIONS) &&
- device_get_uclass_id(diskobj->header.dev) == UCLASS_PARTITION) {
+ device_get_uclass_id(handle->dev) == UCLASS_PARTITION) {
if (direction == EFI_DISK_READ)
- n = disk_blk_read(diskobj->header.dev, lba, blocks,
- buffer);
+ n = disk_blk_read(handle->dev, lba, blocks, buffer);
else
- n = disk_blk_write(diskobj->header.dev, lba, blocks,
- buffer);
+ n = disk_blk_write(handle->dev, lba, blocks, buffer);
} else {
/* dev is a block device (UCLASS_BLK) */
struct blk_desc *desc;
- desc = dev_get_uclass_plat(diskobj->header.dev);
+ desc = dev_get_uclass_plat(handle->dev);
if (direction == EFI_DISK_READ)
n = blk_dread(desc, lba, blocks, buffer);
else
@@ -388,6 +386,7 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
* @part: partition
* @disk: pointer to receive the created handle
* @agent_handle: handle of the EFI block driver
+ * @dev: pointer to udevice
* Return: disk object
*/
static efi_status_t efi_disk_add_dev(
@@ -397,24 +396,33 @@ static efi_status_t efi_disk_add_dev(
int dev_index,
struct disk_partition *part_info,
unsigned int part,
- struct efi_disk_obj **disk,
- efi_handle_t agent_handle)
+ efi_handle_t *disk,
+ efi_handle_t agent_handle,
+ struct udevice *dev)
{
- struct efi_disk_obj *diskobj;
- struct efi_object *handle;
+ efi_handle_t handle;
const efi_guid_t *esp_guid = NULL;
efi_status_t ret;
+ struct efi_block_io *blkio;
+ struct efi_block_io_media *media;
+ struct efi_device_path *dp = NULL;
+ struct efi_simple_file_system_protocol *volume = NULL;
/* Don't add empty devices */
if (!desc->lba)
return EFI_NOT_READY;
- diskobj = calloc(1, sizeof(*diskobj));
- if (!diskobj)
+ ret = efi_create_handle(&handle);
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ blkio = calloc(1, sizeof(*blkio));
+ media = calloc(1, sizeof(*media));
+ if (!blkio || !media)
return EFI_OUT_OF_RESOURCES;
- /* Hook up to the device list */
- efi_add_handle(&diskobj->header);
+ *blkio = block_io_disk_template;
+ blkio->media = media;
/* Fill in object data */
if (part_info) {
@@ -440,23 +448,22 @@ static efi_status_t efi_disk_add_dev(
* (controller).
*/
ret = efi_protocol_open(handler, &protocol_interface, NULL,
- &diskobj->header,
+ handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
if (ret != EFI_SUCCESS) {
log_debug("prot open failed\n");
goto error;
}
- diskobj->dp = efi_dp_append_node(dp_parent, node);
+ dp = efi_dp_append_node(dp_parent, node);
efi_free_pool(node);
- diskobj->media.last_block = part_info->size - 1;
+ blkio->media->last_block = part_info->size - 1;
if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
esp_guid = &efi_system_partition_guid;
} else {
- diskobj->dp = efi_dp_from_part(desc, part);
- diskobj->media.last_block = desc->lba - 1;
+ dp = efi_dp_from_part(desc, part);
+ blkio->media->last_block = desc->lba - 1;
}
- diskobj->part = part;
/*
* Install the device path and the block IO protocol.
@@ -465,11 +472,10 @@ static efi_status_t efi_disk_add_dev(
* already installed on an other handle and returns EFI_ALREADY_STARTED
* in this case.
*/
- handle = &diskobj->header;
ret = efi_install_multiple_protocol_interfaces(
&handle,
- &efi_guid_device_path, diskobj->dp,
- &efi_block_io_guid, &diskobj->ops,
+ &efi_guid_device_path, dp,
+ &efi_block_io_guid, blkio,
/*
* esp_guid must be last entry as it
* can be NULL. Its interface is NULL.
@@ -487,43 +493,39 @@ static efi_status_t efi_disk_add_dev(
*/
if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
efi_fs_exists(desc, part)) {
- ret = efi_create_simple_file_system(desc, part, diskobj->dp,
- &diskobj->volume);
+ ret = efi_create_simple_file_system(desc, part, dp, &volume);
if (ret != EFI_SUCCESS)
goto error;
- ret = efi_add_protocol(&diskobj->header,
+ ret = efi_add_protocol(handle,
&efi_simple_file_system_protocol_guid,
- diskobj->volume);
+ volume);
if (ret != EFI_SUCCESS)
goto error;
}
- diskobj->ops = block_io_disk_template;
- diskobj->dev_index = dev_index;
/* Fill in EFI IO Media info (for read/write callbacks) */
- diskobj->media.removable_media = desc->removable;
- diskobj->media.media_present = 1;
+ blkio->media->removable_media = desc->removable;
+ blkio->media->media_present = 1;
/*
* MediaID is just an arbitrary counter.
* We have to change it if the medium is removed or changed.
*/
- diskobj->media.media_id = 1;
- diskobj->media.block_size = desc->blksz;
- diskobj->media.io_align = desc->blksz;
+ blkio->media->media_id = 1;
+ blkio->media->block_size = desc->blksz;
+ blkio->media->io_align = desc->blksz;
if (part)
- diskobj->media.logical_partition = 1;
- diskobj->ops.media = &diskobj->media;
+ blkio->media->logical_partition = 1;
if (disk)
- *disk = diskobj;
+ *disk = handle;
EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
", last_block %llu\n",
- diskobj->part,
- diskobj->media.media_present,
- diskobj->media.logical_partition,
- diskobj->media.removable_media,
- diskobj->media.last_block);
+ part,
+ blkio->media->media_present,
+ blkio->media->logical_partition,
+ blkio->media->removable_media,
+ blkio->media->last_block);
/* Store first EFI system partition */
if (part && efi_system_partition.uclass_id == UCLASS_INVALID) {
@@ -536,11 +538,18 @@ static efi_status_t efi_disk_add_dev(
desc->devnum, part);
}
}
+
+ if (efi_link_dev(handle, dev))
+ goto error;
+
return EFI_SUCCESS;
error:
- efi_delete_handle(&diskobj->header);
- free(diskobj->volume);
- free(diskobj);
+ efi_delete_handle(handle);
+ efi_free_pool(dp);
+ free(blkio);
+ free(media);
+ free(volume);
+
return ret;
}
@@ -557,7 +566,7 @@ error:
*/
static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
{
- struct efi_disk_obj *disk;
+ efi_handle_t disk;
struct blk_desc *desc;
int diskid;
efi_status_t ret;
@@ -566,7 +575,7 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
diskid = desc->devnum;
ret = efi_disk_add_dev(NULL, NULL, desc,
- diskid, NULL, 0, &disk, agent_handle);
+ diskid, NULL, 0, &disk, agent_handle, dev);
if (ret != EFI_SUCCESS) {
if (ret == EFI_NOT_READY) {
log_notice("Disk %s not ready\n", dev->name);
@@ -578,12 +587,6 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
return ret;
}
- if (efi_link_dev(&disk->header, dev)) {
- efi_free_pool(disk->dp);
- efi_delete_handle(&disk->header);
-
- return -EINVAL;
- }
return 0;
}
@@ -609,7 +612,7 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
int diskid;
struct efi_handler *handler;
struct efi_device_path *dp_parent;
- struct efi_disk_obj *disk;
+ efi_handle_t disk;
efi_status_t ret;
if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
@@ -628,17 +631,11 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
dp_parent = (struct efi_device_path *)handler->protocol_interface;
ret = efi_disk_add_dev(parent, dp_parent, desc, diskid,
- info, part, &disk, agent_handle);
+ info, part, &disk, agent_handle, dev);
if (ret != EFI_SUCCESS) {
log_err("Adding partition for %s failed\n", dev->name);
return -1;
}
- if (efi_link_dev(&disk->header, dev)) {
- efi_free_pool(disk->dp);
- efi_delete_handle(&disk->header);
-
- return -1;
- }
return 0;
}
@@ -693,13 +690,34 @@ int efi_disk_probe(void *ctx, struct event *event)
return 0;
}
+static void get_disk_resources(efi_handle_t handle, struct efi_device_path **dp,
+ struct efi_block_io **blkio,
+ struct efi_simple_file_system_protocol **volume)
+{
+ efi_status_t ret;
+ struct efi_handler *handler;
+
+ ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
+ if (ret == EFI_SUCCESS)
+ *dp = handler->protocol_interface;
+
+ ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
+ if (ret == EFI_SUCCESS)
+ *blkio = handler->protocol_interface;
+
+ ret = efi_search_protocol(handle, &efi_simple_file_system_protocol_guid,
+ &handler);
+ if (ret == EFI_SUCCESS)
+ *volume = handler->protocol_interface;
+}
+
/**
- * efi_disk_remove - delete an efi_disk object for a block device or partition
+ * efi_disk_remove - delete an efi handle for a block device or partition
*
* @ctx: event context: driver binding protocol
* @event: EV_PM_PRE_REMOVE event
*
- * Delete an efi_disk object which is associated with the UCLASS_BLK or
+ * Delete an efi handle which is associated with the UCLASS_BLK or
* UCLASS_PARTITION device for which the EV_PM_PRE_REMOVE event is raised.
*
* Return: 0 on success, -1 otherwise
@@ -710,8 +728,10 @@ int efi_disk_remove(void *ctx, struct event *event)
struct udevice *dev = event->data.dm.dev;
efi_handle_t handle;
struct blk_desc *desc;
- struct efi_disk_obj *diskobj = NULL;
efi_status_t ret;
+ struct efi_device_path *dp = NULL;
+ struct efi_block_io *blkio = NULL;
+ struct efi_simple_file_system_protocol *volume = NULL;
if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
return 0;
@@ -721,11 +741,11 @@ int efi_disk_remove(void *ctx, struct event *event)
case UCLASS_BLK:
desc = dev_get_uclass_plat(dev);
if (desc && desc->uclass_id != UCLASS_EFI_LOADER)
- diskobj = container_of(handle, struct efi_disk_obj,
- header);
+ get_disk_resources(handle, &dp, &blkio, &volume);
+
break;
case UCLASS_PARTITION:
- diskobj = container_of(handle, struct efi_disk_obj, header);
+ get_disk_resources(handle, &dp, &blkio, &volume);
break;
default:
return 0;
@@ -736,8 +756,11 @@ int efi_disk_remove(void *ctx, struct event *event)
if (ret != EFI_SUCCESS)
return -1;
- if (diskobj)
- efi_free_pool(diskobj->dp);
+ efi_free_pool(dp);
+ if (blkio) {
+ free(blkio->media);
+ free(blkio);
+ }
dev_tag_del(dev, DM_TAG_EFI);
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] efi_loader: eliminate efi_disk_obj structure
2023-12-13 8:57 [PATCH] efi_loader: eliminate efi_disk_obj structure Masahisa Kojima
@ 2023-12-13 14:22 ` Heinrich Schuchardt
2023-12-13 19:50 ` Simon Glass
2023-12-14 1:55 ` Masahisa Kojima
2023-12-14 1:24 ` AKASHI Takahiro
1 sibling, 2 replies; 9+ messages in thread
From: Heinrich Schuchardt @ 2023-12-13 14:22 UTC (permalink / raw)
To: Masahisa Kojima; +Cc: Ilias Apalodimas, u-boot
On 13.12.23 09:57, Masahisa Kojima wrote:
> Current code uses struct efi_disk_obj to keep information
> about block devices and partitions. As the efi handle already
> has a field with the udevice, we should eliminate
> struct efi_disk_obj and use an pointer to struct efi_object
> for the handle.
>
> efi_link_dev() call is moved inside of efi_disk_add_dev() function
> to simplify the cleanup process in case of error.
I agree that using struct efi_disk_obj as a container for protocols of a
block IO device is a bit messy.
But we should keep looking up the handle easy. Currently we use
diskobj = container_of(this, struct efi_disk_obj, ops);
Instead we could append a private field with the handle to the
EFI_BLOCK_IO_PROTOCOL structure.
>
> Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
> ---
> lib/efi_loader/efi_disk.c | 209 +++++++++++++++++++++-----------------
> 1 file changed, 116 insertions(+), 93 deletions(-)
>
> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> index f0d76113b0..cfb7ace551 100644
> --- a/lib/efi_loader/efi_disk.c
> +++ b/lib/efi_loader/efi_disk.c
> @@ -27,27 +27,24 @@ struct efi_system_partition efi_system_partition = {
> const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
> const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
>
> -/**
> - * struct efi_disk_obj - EFI disk object
> - *
> - * @header: EFI object header
> - * @ops: EFI disk I/O protocol interface
> - * @dev_index: device index of block device
> - * @media: block I/O media information
> - * @dp: device path to the block device
> - * @part: partition
> - * @volume: simple file system protocol of the partition
> - * @dev: associated DM device
> - */
> -struct efi_disk_obj {
> - struct efi_object header;
> - struct efi_block_io ops;
> - int dev_index;
> - struct efi_block_io_media media;
> - struct efi_device_path *dp;
> - unsigned int part;
> - struct efi_simple_file_system_protocol *volume;
> -};
> +static efi_handle_t efi_blkio_find_obj(struct efi_block_io *blkio)
> +{
> + efi_handle_t handle;
> +
> + list_for_each_entry(handle, &efi_obj_list, link) {
> + efi_status_t ret;
> + struct efi_handler *handler;
> +
> + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> + if (ret != EFI_SUCCESS)
> + continue;
> +
> + if (blkio == handler->protocol_interface)
> + return handle;
> + }
Depending on the number of handles and pointers this will take a
considerable time. A private field for the handle appended to struct
efi_block_io would allow a fast lookup.
EDK II does the same. See the definition of RAM_DISK_PRIVATE_FROM_BLKIO
which uses macro BASE_CR() to find the private fields.
Best regards
Heinrich
> +
> + return NULL;
> +}
>
> /**
> * efi_disk_reset() - reset block device
> @@ -107,13 +104,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> u32 media_id, u64 lba, unsigned long buffer_size,
> void *buffer, enum efi_disk_direction direction)
> {
> - struct efi_disk_obj *diskobj;
> + efi_handle_t handle;
> int blksz;
> int blocks;
> unsigned long n;
>
> - diskobj = container_of(this, struct efi_disk_obj, ops);
> - blksz = diskobj->media.block_size;
> + handle = efi_blkio_find_obj(this);
> + if (!handle)
> + return EFI_INVALID_PARAMETER;
> +
> + blksz = this->media->block_size;
> blocks = buffer_size / blksz;
>
> EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
> @@ -124,18 +124,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> return EFI_BAD_BUFFER_SIZE;
>
> if (CONFIG_IS_ENABLED(PARTITIONS) &&
> - device_get_uclass_id(diskobj->header.dev) == UCLASS_PARTITION) {
> + device_get_uclass_id(handle->dev) == UCLASS_PARTITION) {
> if (direction == EFI_DISK_READ)
> - n = disk_blk_read(diskobj->header.dev, lba, blocks,
> - buffer);
> + n = disk_blk_read(handle->dev, lba, blocks, buffer);
> else
> - n = disk_blk_write(diskobj->header.dev, lba, blocks,
> - buffer);
> + n = disk_blk_write(handle->dev, lba, blocks, buffer);
> } else {
> /* dev is a block device (UCLASS_BLK) */
> struct blk_desc *desc;
>
> - desc = dev_get_uclass_plat(diskobj->header.dev);
> + desc = dev_get_uclass_plat(handle->dev);
> if (direction == EFI_DISK_READ)
> n = blk_dread(desc, lba, blocks, buffer);
> else
> @@ -388,6 +386,7 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
> * @part: partition
> * @disk: pointer to receive the created handle
> * @agent_handle: handle of the EFI block driver
> + * @dev: pointer to udevice
> * Return: disk object
> */
> static efi_status_t efi_disk_add_dev(
> @@ -397,24 +396,33 @@ static efi_status_t efi_disk_add_dev(
> int dev_index,
> struct disk_partition *part_info,
> unsigned int part,
> - struct efi_disk_obj **disk,
> - efi_handle_t agent_handle)
> + efi_handle_t *disk,
> + efi_handle_t agent_handle,
> + struct udevice *dev)
> {
> - struct efi_disk_obj *diskobj;
> - struct efi_object *handle;
> + efi_handle_t handle;
> const efi_guid_t *esp_guid = NULL;
> efi_status_t ret;
> + struct efi_block_io *blkio;
> + struct efi_block_io_media *media;
> + struct efi_device_path *dp = NULL;
> + struct efi_simple_file_system_protocol *volume = NULL;
>
> /* Don't add empty devices */
> if (!desc->lba)
> return EFI_NOT_READY;
>
> - diskobj = calloc(1, sizeof(*diskobj));
> - if (!diskobj)
> + ret = efi_create_handle(&handle);
> + if (ret != EFI_SUCCESS)
> + return ret;
> +
> + blkio = calloc(1, sizeof(*blkio));
> + media = calloc(1, sizeof(*media));
> + if (!blkio || !media)
> return EFI_OUT_OF_RESOURCES;
>
> - /* Hook up to the device list */
> - efi_add_handle(&diskobj->header);
> + *blkio = block_io_disk_template;
> + blkio->media = media;
>
> /* Fill in object data */
> if (part_info) {
> @@ -440,23 +448,22 @@ static efi_status_t efi_disk_add_dev(
> * (controller).
> */
> ret = efi_protocol_open(handler, &protocol_interface, NULL,
> - &diskobj->header,
> + handle,
> EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
> if (ret != EFI_SUCCESS) {
> log_debug("prot open failed\n");
> goto error;
> }
>
> - diskobj->dp = efi_dp_append_node(dp_parent, node);
> + dp = efi_dp_append_node(dp_parent, node);
> efi_free_pool(node);
> - diskobj->media.last_block = part_info->size - 1;
> + blkio->media->last_block = part_info->size - 1;
> if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
> esp_guid = &efi_system_partition_guid;
> } else {
> - diskobj->dp = efi_dp_from_part(desc, part);
> - diskobj->media.last_block = desc->lba - 1;
> + dp = efi_dp_from_part(desc, part);
> + blkio->media->last_block = desc->lba - 1;
> }
> - diskobj->part = part;
>
> /*
> * Install the device path and the block IO protocol.
> @@ -465,11 +472,10 @@ static efi_status_t efi_disk_add_dev(
> * already installed on an other handle and returns EFI_ALREADY_STARTED
> * in this case.
> */
> - handle = &diskobj->header;
> ret = efi_install_multiple_protocol_interfaces(
> &handle,
> - &efi_guid_device_path, diskobj->dp,
> - &efi_block_io_guid, &diskobj->ops,
> + &efi_guid_device_path, dp,
> + &efi_block_io_guid, blkio,
> /*
> * esp_guid must be last entry as it
> * can be NULL. Its interface is NULL.
> @@ -487,43 +493,39 @@ static efi_status_t efi_disk_add_dev(
> */
> if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
> efi_fs_exists(desc, part)) {
> - ret = efi_create_simple_file_system(desc, part, diskobj->dp,
> - &diskobj->volume);
> + ret = efi_create_simple_file_system(desc, part, dp, &volume);
> if (ret != EFI_SUCCESS)
> goto error;
>
> - ret = efi_add_protocol(&diskobj->header,
> + ret = efi_add_protocol(handle,
> &efi_simple_file_system_protocol_guid,
> - diskobj->volume);
> + volume);
> if (ret != EFI_SUCCESS)
> goto error;
> }
> - diskobj->ops = block_io_disk_template;
> - diskobj->dev_index = dev_index;
>
> /* Fill in EFI IO Media info (for read/write callbacks) */
> - diskobj->media.removable_media = desc->removable;
> - diskobj->media.media_present = 1;
> + blkio->media->removable_media = desc->removable;
> + blkio->media->media_present = 1;
> /*
> * MediaID is just an arbitrary counter.
> * We have to change it if the medium is removed or changed.
> */
> - diskobj->media.media_id = 1;
> - diskobj->media.block_size = desc->blksz;
> - diskobj->media.io_align = desc->blksz;
> + blkio->media->media_id = 1;
> + blkio->media->block_size = desc->blksz;
> + blkio->media->io_align = desc->blksz;
> if (part)
> - diskobj->media.logical_partition = 1;
> - diskobj->ops.media = &diskobj->media;
> + blkio->media->logical_partition = 1;
> if (disk)
> - *disk = diskobj;
> + *disk = handle;
>
> EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
> ", last_block %llu\n",
> - diskobj->part,
> - diskobj->media.media_present,
> - diskobj->media.logical_partition,
> - diskobj->media.removable_media,
> - diskobj->media.last_block);
> + part,
> + blkio->media->media_present,
> + blkio->media->logical_partition,
> + blkio->media->removable_media,
> + blkio->media->last_block);
>
> /* Store first EFI system partition */
> if (part && efi_system_partition.uclass_id == UCLASS_INVALID) {
> @@ -536,11 +538,18 @@ static efi_status_t efi_disk_add_dev(
> desc->devnum, part);
> }
> }
> +
> + if (efi_link_dev(handle, dev))
> + goto error;
> +
> return EFI_SUCCESS;
> error:
> - efi_delete_handle(&diskobj->header);
> - free(diskobj->volume);
> - free(diskobj);
> + efi_delete_handle(handle);
> + efi_free_pool(dp);
> + free(blkio);
> + free(media);
> + free(volume);
> +
> return ret;
> }
>
> @@ -557,7 +566,7 @@ error:
> */
> static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> {
> - struct efi_disk_obj *disk;
> + efi_handle_t disk;
> struct blk_desc *desc;
> int diskid;
> efi_status_t ret;
> @@ -566,7 +575,7 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> diskid = desc->devnum;
>
> ret = efi_disk_add_dev(NULL, NULL, desc,
> - diskid, NULL, 0, &disk, agent_handle);
> + diskid, NULL, 0, &disk, agent_handle, dev);
> if (ret != EFI_SUCCESS) {
> if (ret == EFI_NOT_READY) {
> log_notice("Disk %s not ready\n", dev->name);
> @@ -578,12 +587,6 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
>
> return ret;
> }
> - if (efi_link_dev(&disk->header, dev)) {
> - efi_free_pool(disk->dp);
> - efi_delete_handle(&disk->header);
> -
> - return -EINVAL;
> - }
>
> return 0;
> }
> @@ -609,7 +612,7 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
> int diskid;
> struct efi_handler *handler;
> struct efi_device_path *dp_parent;
> - struct efi_disk_obj *disk;
> + efi_handle_t disk;
> efi_status_t ret;
>
> if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
> @@ -628,17 +631,11 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
> dp_parent = (struct efi_device_path *)handler->protocol_interface;
>
> ret = efi_disk_add_dev(parent, dp_parent, desc, diskid,
> - info, part, &disk, agent_handle);
> + info, part, &disk, agent_handle, dev);
> if (ret != EFI_SUCCESS) {
> log_err("Adding partition for %s failed\n", dev->name);
> return -1;
> }
> - if (efi_link_dev(&disk->header, dev)) {
> - efi_free_pool(disk->dp);
> - efi_delete_handle(&disk->header);
> -
> - return -1;
> - }
>
> return 0;
> }
> @@ -693,13 +690,34 @@ int efi_disk_probe(void *ctx, struct event *event)
> return 0;
> }
>
> +static void get_disk_resources(efi_handle_t handle, struct efi_device_path **dp,
> + struct efi_block_io **blkio,
> + struct efi_simple_file_system_protocol **volume)
> +{
> + efi_status_t ret;
> + struct efi_handler *handler;
> +
> + ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
> + if (ret == EFI_SUCCESS)
> + *dp = handler->protocol_interface;
> +
> + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> + if (ret == EFI_SUCCESS)
> + *blkio = handler->protocol_interface;
> +
> + ret = efi_search_protocol(handle, &efi_simple_file_system_protocol_guid,
> + &handler);
> + if (ret == EFI_SUCCESS)
> + *volume = handler->protocol_interface;
> +}
> +
> /**
> - * efi_disk_remove - delete an efi_disk object for a block device or partition
> + * efi_disk_remove - delete an efi handle for a block device or partition
> *
> * @ctx: event context: driver binding protocol
> * @event: EV_PM_PRE_REMOVE event
> *
> - * Delete an efi_disk object which is associated with the UCLASS_BLK or
> + * Delete an efi handle which is associated with the UCLASS_BLK or
> * UCLASS_PARTITION device for which the EV_PM_PRE_REMOVE event is raised.
> *
> * Return: 0 on success, -1 otherwise
> @@ -710,8 +728,10 @@ int efi_disk_remove(void *ctx, struct event *event)
> struct udevice *dev = event->data.dm.dev;
> efi_handle_t handle;
> struct blk_desc *desc;
> - struct efi_disk_obj *diskobj = NULL;
> efi_status_t ret;
> + struct efi_device_path *dp = NULL;
> + struct efi_block_io *blkio = NULL;
> + struct efi_simple_file_system_protocol *volume = NULL;
>
> if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
> return 0;
> @@ -721,11 +741,11 @@ int efi_disk_remove(void *ctx, struct event *event)
> case UCLASS_BLK:
> desc = dev_get_uclass_plat(dev);
> if (desc && desc->uclass_id != UCLASS_EFI_LOADER)
> - diskobj = container_of(handle, struct efi_disk_obj,
> - header);
> + get_disk_resources(handle, &dp, &blkio, &volume);
> +
> break;
> case UCLASS_PARTITION:
> - diskobj = container_of(handle, struct efi_disk_obj, header);
> + get_disk_resources(handle, &dp, &blkio, &volume);
> break;
> default:
> return 0;
> @@ -736,8 +756,11 @@ int efi_disk_remove(void *ctx, struct event *event)
> if (ret != EFI_SUCCESS)
> return -1;
>
> - if (diskobj)
> - efi_free_pool(diskobj->dp);
> + efi_free_pool(dp);
> + if (blkio) {
> + free(blkio->media);
> + free(blkio);
> + }
>
> dev_tag_del(dev, DM_TAG_EFI);
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] efi_loader: eliminate efi_disk_obj structure
2023-12-13 14:22 ` Heinrich Schuchardt
@ 2023-12-13 19:50 ` Simon Glass
2023-12-14 1:55 ` Masahisa Kojima
1 sibling, 0 replies; 9+ messages in thread
From: Simon Glass @ 2023-12-13 19:50 UTC (permalink / raw)
To: Heinrich Schuchardt; +Cc: Masahisa Kojima, Ilias Apalodimas, u-boot
Hi Heinrich,
On Wed, 13 Dec 2023 at 07:23, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>
> On 13.12.23 09:57, Masahisa Kojima wrote:
> > Current code uses struct efi_disk_obj to keep information
> > about block devices and partitions. As the efi handle already
> > has a field with the udevice, we should eliminate
> > struct efi_disk_obj and use an pointer to struct efi_object
> > for the handle.
> >
> > efi_link_dev() call is moved inside of efi_disk_add_dev() function
> > to simplify the cleanup process in case of error.
>
> I agree that using struct efi_disk_obj as a container for protocols of a
> block IO device is a bit messy.
>
> But we should keep looking up the handle easy. Currently we use
>
> diskobj = container_of(this, struct efi_disk_obj, ops);
>
> Instead we could append a private field with the handle to the
> EFI_BLOCK_IO_PROTOCOL structure.
>
> >
> > Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
> > ---
> > lib/efi_loader/efi_disk.c | 209 +++++++++++++++++++++-----------------
> > 1 file changed, 116 insertions(+), 93 deletions(-)
> >
> > diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> > index f0d76113b0..cfb7ace551 100644
> > --- a/lib/efi_loader/efi_disk.c
> > +++ b/lib/efi_loader/efi_disk.c
> > @@ -27,27 +27,24 @@ struct efi_system_partition efi_system_partition = {
> > const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
> > const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
> >
> > -/**
> > - * struct efi_disk_obj - EFI disk object
> > - *
> > - * @header: EFI object header
> > - * @ops: EFI disk I/O protocol interface
> > - * @dev_index: device index of block device
> > - * @media: block I/O media information
> > - * @dp: device path to the block device
> > - * @part: partition
> > - * @volume: simple file system protocol of the partition
> > - * @dev: associated DM device
> > - */
> > -struct efi_disk_obj {
> > - struct efi_object header;
> > - struct efi_block_io ops;
> > - int dev_index;
> > - struct efi_block_io_media media;
> > - struct efi_device_path *dp;
> > - unsigned int part;
> > - struct efi_simple_file_system_protocol *volume;
> > -};
> > +static efi_handle_t efi_blkio_find_obj(struct efi_block_io *blkio)
> > +{
> > + efi_handle_t handle;
> > +
> > + list_for_each_entry(handle, &efi_obj_list, link) {
> > + efi_status_t ret;
> > + struct efi_handler *handler;
> > +
> > + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> > + if (ret != EFI_SUCCESS)
> > + continue;
> > +
> > + if (blkio == handler->protocol_interface)
> > + return handle;
> > + }
>
> Depending on the number of handles and pointers this will take a
> considerable time. A private field for the handle appended to struct
> efi_block_io would allow a fast lookup.
>
> EDK II does the same. See the definition of RAM_DISK_PRIVATE_FROM_BLKIO
> which uses macro BASE_CR() to find the private fields.
That seems pretty ugly to me, but if it really is that slow, I suppose it is OK.
Can we attach efi_block_io to the driver model BLK device?
Regards,
Simon
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] efi_loader: eliminate efi_disk_obj structure
2023-12-13 8:57 [PATCH] efi_loader: eliminate efi_disk_obj structure Masahisa Kojima
2023-12-13 14:22 ` Heinrich Schuchardt
@ 2023-12-14 1:24 ` AKASHI Takahiro
1 sibling, 0 replies; 9+ messages in thread
From: AKASHI Takahiro @ 2023-12-14 1:24 UTC (permalink / raw)
To: Masahisa Kojima; +Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas
Hi Kojima-san,
On Wed, Dec 13, 2023 at 05:57:37PM +0900, Masahisa Kojima wrote:
> Current code uses struct efi_disk_obj to keep information
> about block devices and partitions. As the efi handle already
> has a field with the udevice, we should eliminate
> struct efi_disk_obj and use an pointer to struct efi_object
> for the handle.
I don't still understand what is an advantage of your approach.
> efi_link_dev() call is moved inside of efi_disk_add_dev() function
> to simplify the cleanup process in case of error.
>
> Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
> ---
> lib/efi_loader/efi_disk.c | 209 +++++++++++++++++++++-----------------
> 1 file changed, 116 insertions(+), 93 deletions(-)
>
> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> index f0d76113b0..cfb7ace551 100644
> --- a/lib/efi_loader/efi_disk.c
> +++ b/lib/efi_loader/efi_disk.c
> @@ -27,27 +27,24 @@ struct efi_system_partition efi_system_partition = {
> const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
> const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
>
> -/**
> - * struct efi_disk_obj - EFI disk object
> - *
> - * @header: EFI object header
> - * @ops: EFI disk I/O protocol interface
> - * @dev_index: device index of block device
> - * @media: block I/O media information
> - * @dp: device path to the block device
> - * @part: partition
> - * @volume: simple file system protocol of the partition
> - * @dev: associated DM device
> - */
> -struct efi_disk_obj {
> - struct efi_object header;
This is a handy way of making it ease to dereference from an internal
structure to an external reference as Heinrich mentioned.
> - struct efi_block_io ops;
Along with "header" and "media", this allows us to congregate
a couple of "malloc" calls, instead of your change, into one.
> - int dev_index;
> - struct efi_device_path *dp;
> - unsigned int part;
> - struct efi_simple_file_system_protocol *volume;
If we carefully look into the base code, we will no longer have to
have those fields in this structure because they are mostly used in
a single internal function (if I'm correct).
So we can simply replace them with local variables (with some extra
changes).
-Takahiro Akashi
> -};
> +static efi_handle_t efi_blkio_find_obj(struct efi_block_io *blkio)
> +{
> + efi_handle_t handle;
> +
> + list_for_each_entry(handle, &efi_obj_list, link) {
> + efi_status_t ret;
> + struct efi_handler *handler;
> +
> + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> + if (ret != EFI_SUCCESS)
> + continue;
> +
> + if (blkio == handler->protocol_interface)
> + return handle;
> + }
> +
> + return NULL;
> +}
>
> /**
> * efi_disk_reset() - reset block device
> @@ -107,13 +104,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> u32 media_id, u64 lba, unsigned long buffer_size,
> void *buffer, enum efi_disk_direction direction)
> {
> - struct efi_disk_obj *diskobj;
> + efi_handle_t handle;
> int blksz;
> int blocks;
> unsigned long n;
>
> - diskobj = container_of(this, struct efi_disk_obj, ops);
> - blksz = diskobj->media.block_size;
> + handle = efi_blkio_find_obj(this);
> + if (!handle)
> + return EFI_INVALID_PARAMETER;
> +
> + blksz = this->media->block_size;
> blocks = buffer_size / blksz;
>
> EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
> @@ -124,18 +124,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> return EFI_BAD_BUFFER_SIZE;
>
> if (CONFIG_IS_ENABLED(PARTITIONS) &&
> - device_get_uclass_id(diskobj->header.dev) == UCLASS_PARTITION) {
> + device_get_uclass_id(handle->dev) == UCLASS_PARTITION) {
> if (direction == EFI_DISK_READ)
> - n = disk_blk_read(diskobj->header.dev, lba, blocks,
> - buffer);
> + n = disk_blk_read(handle->dev, lba, blocks, buffer);
> else
> - n = disk_blk_write(diskobj->header.dev, lba, blocks,
> - buffer);
> + n = disk_blk_write(handle->dev, lba, blocks, buffer);
> } else {
> /* dev is a block device (UCLASS_BLK) */
> struct blk_desc *desc;
>
> - desc = dev_get_uclass_plat(diskobj->header.dev);
> + desc = dev_get_uclass_plat(handle->dev);
> if (direction == EFI_DISK_READ)
> n = blk_dread(desc, lba, blocks, buffer);
> else
> @@ -388,6 +386,7 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
> * @part: partition
> * @disk: pointer to receive the created handle
> * @agent_handle: handle of the EFI block driver
> + * @dev: pointer to udevice
> * Return: disk object
> */
> static efi_status_t efi_disk_add_dev(
> @@ -397,24 +396,33 @@ static efi_status_t efi_disk_add_dev(
> int dev_index,
> struct disk_partition *part_info,
> unsigned int part,
> - struct efi_disk_obj **disk,
> - efi_handle_t agent_handle)
> + efi_handle_t *disk,
> + efi_handle_t agent_handle,
> + struct udevice *dev)
> {
> - struct efi_disk_obj *diskobj;
> - struct efi_object *handle;
> + efi_handle_t handle;
> const efi_guid_t *esp_guid = NULL;
> efi_status_t ret;
> + struct efi_block_io *blkio;
> + struct efi_block_io_media *media;
> + struct efi_device_path *dp = NULL;
> + struct efi_simple_file_system_protocol *volume = NULL;
>
> /* Don't add empty devices */
> if (!desc->lba)
> return EFI_NOT_READY;
>
> - diskobj = calloc(1, sizeof(*diskobj));
> - if (!diskobj)
> + ret = efi_create_handle(&handle);
> + if (ret != EFI_SUCCESS)
> + return ret;
> +
> + blkio = calloc(1, sizeof(*blkio));
> + media = calloc(1, sizeof(*media));
> + if (!blkio || !media)
> return EFI_OUT_OF_RESOURCES;
>
> - /* Hook up to the device list */
> - efi_add_handle(&diskobj->header);
> + *blkio = block_io_disk_template;
> + blkio->media = media;
>
> /* Fill in object data */
> if (part_info) {
> @@ -440,23 +448,22 @@ static efi_status_t efi_disk_add_dev(
> * (controller).
> */
> ret = efi_protocol_open(handler, &protocol_interface, NULL,
> - &diskobj->header,
> + handle,
> EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
> if (ret != EFI_SUCCESS) {
> log_debug("prot open failed\n");
> goto error;
> }
>
> - diskobj->dp = efi_dp_append_node(dp_parent, node);
> + dp = efi_dp_append_node(dp_parent, node);
> efi_free_pool(node);
> - diskobj->media.last_block = part_info->size - 1;
> + blkio->media->last_block = part_info->size - 1;
> if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
> esp_guid = &efi_system_partition_guid;
> } else {
> - diskobj->dp = efi_dp_from_part(desc, part);
> - diskobj->media.last_block = desc->lba - 1;
> + dp = efi_dp_from_part(desc, part);
> + blkio->media->last_block = desc->lba - 1;
> }
> - diskobj->part = part;
>
> /*
> * Install the device path and the block IO protocol.
> @@ -465,11 +472,10 @@ static efi_status_t efi_disk_add_dev(
> * already installed on an other handle and returns EFI_ALREADY_STARTED
> * in this case.
> */
> - handle = &diskobj->header;
> ret = efi_install_multiple_protocol_interfaces(
> &handle,
> - &efi_guid_device_path, diskobj->dp,
> - &efi_block_io_guid, &diskobj->ops,
> + &efi_guid_device_path, dp,
> + &efi_block_io_guid, blkio,
> /*
> * esp_guid must be last entry as it
> * can be NULL. Its interface is NULL.
> @@ -487,43 +493,39 @@ static efi_status_t efi_disk_add_dev(
> */
> if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
> efi_fs_exists(desc, part)) {
> - ret = efi_create_simple_file_system(desc, part, diskobj->dp,
> - &diskobj->volume);
> + ret = efi_create_simple_file_system(desc, part, dp, &volume);
> if (ret != EFI_SUCCESS)
> goto error;
>
> - ret = efi_add_protocol(&diskobj->header,
> + ret = efi_add_protocol(handle,
> &efi_simple_file_system_protocol_guid,
> - diskobj->volume);
> + volume);
> if (ret != EFI_SUCCESS)
> goto error;
> }
> - diskobj->ops = block_io_disk_template;
> - diskobj->dev_index = dev_index;
>
> /* Fill in EFI IO Media info (for read/write callbacks) */
> - diskobj->media.removable_media = desc->removable;
> - diskobj->media.media_present = 1;
> + blkio->media->removable_media = desc->removable;
> + blkio->media->media_present = 1;
> /*
> * MediaID is just an arbitrary counter.
> * We have to change it if the medium is removed or changed.
> */
> - diskobj->media.media_id = 1;
> - diskobj->media.block_size = desc->blksz;
> - diskobj->media.io_align = desc->blksz;
> + blkio->media->media_id = 1;
> + blkio->media->block_size = desc->blksz;
> + blkio->media->io_align = desc->blksz;
> if (part)
> - diskobj->media.logical_partition = 1;
> - diskobj->ops.media = &diskobj->media;
> + blkio->media->logical_partition = 1;
> if (disk)
> - *disk = diskobj;
> + *disk = handle;
>
> EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
> ", last_block %llu\n",
> - diskobj->part,
> - diskobj->media.media_present,
> - diskobj->media.logical_partition,
> - diskobj->media.removable_media,
> - diskobj->media.last_block);
> + part,
> + blkio->media->media_present,
> + blkio->media->logical_partition,
> + blkio->media->removable_media,
> + blkio->media->last_block);
>
> /* Store first EFI system partition */
> if (part && efi_system_partition.uclass_id == UCLASS_INVALID) {
> @@ -536,11 +538,18 @@ static efi_status_t efi_disk_add_dev(
> desc->devnum, part);
> }
> }
> +
> + if (efi_link_dev(handle, dev))
> + goto error;
> +
> return EFI_SUCCESS;
> error:
> - efi_delete_handle(&diskobj->header);
> - free(diskobj->volume);
> - free(diskobj);
> + efi_delete_handle(handle);
> + efi_free_pool(dp);
> + free(blkio);
> + free(media);
> + free(volume);
> +
> return ret;
> }
>
> @@ -557,7 +566,7 @@ error:
> */
> static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> {
> - struct efi_disk_obj *disk;
> + efi_handle_t disk;
> struct blk_desc *desc;
> int diskid;
> efi_status_t ret;
> @@ -566,7 +575,7 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> diskid = desc->devnum;
>
> ret = efi_disk_add_dev(NULL, NULL, desc,
> - diskid, NULL, 0, &disk, agent_handle);
> + diskid, NULL, 0, &disk, agent_handle, dev);
> if (ret != EFI_SUCCESS) {
> if (ret == EFI_NOT_READY) {
> log_notice("Disk %s not ready\n", dev->name);
> @@ -578,12 +587,6 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
>
> return ret;
> }
> - if (efi_link_dev(&disk->header, dev)) {
> - efi_free_pool(disk->dp);
> - efi_delete_handle(&disk->header);
> -
> - return -EINVAL;
> - }
>
> return 0;
> }
> @@ -609,7 +612,7 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
> int diskid;
> struct efi_handler *handler;
> struct efi_device_path *dp_parent;
> - struct efi_disk_obj *disk;
> + efi_handle_t disk;
> efi_status_t ret;
>
> if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
> @@ -628,17 +631,11 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
> dp_parent = (struct efi_device_path *)handler->protocol_interface;
>
> ret = efi_disk_add_dev(parent, dp_parent, desc, diskid,
> - info, part, &disk, agent_handle);
> + info, part, &disk, agent_handle, dev);
> if (ret != EFI_SUCCESS) {
> log_err("Adding partition for %s failed\n", dev->name);
> return -1;
> }
> - if (efi_link_dev(&disk->header, dev)) {
> - efi_free_pool(disk->dp);
> - efi_delete_handle(&disk->header);
> -
> - return -1;
> - }
>
> return 0;
> }
> @@ -693,13 +690,34 @@ int efi_disk_probe(void *ctx, struct event *event)
> return 0;
> }
>
> +static void get_disk_resources(efi_handle_t handle, struct efi_device_path **dp,
> + struct efi_block_io **blkio,
> + struct efi_simple_file_system_protocol **volume)
> +{
> + efi_status_t ret;
> + struct efi_handler *handler;
> +
> + ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
> + if (ret == EFI_SUCCESS)
> + *dp = handler->protocol_interface;
> +
> + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> + if (ret == EFI_SUCCESS)
> + *blkio = handler->protocol_interface;
> +
> + ret = efi_search_protocol(handle, &efi_simple_file_system_protocol_guid,
> + &handler);
> + if (ret == EFI_SUCCESS)
> + *volume = handler->protocol_interface;
> +}
> +
> /**
> - * efi_disk_remove - delete an efi_disk object for a block device or partition
> + * efi_disk_remove - delete an efi handle for a block device or partition
> *
> * @ctx: event context: driver binding protocol
> * @event: EV_PM_PRE_REMOVE event
> *
> - * Delete an efi_disk object which is associated with the UCLASS_BLK or
> + * Delete an efi handle which is associated with the UCLASS_BLK or
> * UCLASS_PARTITION device for which the EV_PM_PRE_REMOVE event is raised.
> *
> * Return: 0 on success, -1 otherwise
> @@ -710,8 +728,10 @@ int efi_disk_remove(void *ctx, struct event *event)
> struct udevice *dev = event->data.dm.dev;
> efi_handle_t handle;
> struct blk_desc *desc;
> - struct efi_disk_obj *diskobj = NULL;
> efi_status_t ret;
> + struct efi_device_path *dp = NULL;
> + struct efi_block_io *blkio = NULL;
> + struct efi_simple_file_system_protocol *volume = NULL;
>
> if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
> return 0;
> @@ -721,11 +741,11 @@ int efi_disk_remove(void *ctx, struct event *event)
> case UCLASS_BLK:
> desc = dev_get_uclass_plat(dev);
> if (desc && desc->uclass_id != UCLASS_EFI_LOADER)
> - diskobj = container_of(handle, struct efi_disk_obj,
> - header);
> + get_disk_resources(handle, &dp, &blkio, &volume);
> +
> break;
> case UCLASS_PARTITION:
> - diskobj = container_of(handle, struct efi_disk_obj, header);
> + get_disk_resources(handle, &dp, &blkio, &volume);
> break;
> default:
> return 0;
> @@ -736,8 +756,11 @@ int efi_disk_remove(void *ctx, struct event *event)
> if (ret != EFI_SUCCESS)
> return -1;
>
> - if (diskobj)
> - efi_free_pool(diskobj->dp);
> + efi_free_pool(dp);
> + if (blkio) {
> + free(blkio->media);
> + free(blkio);
> + }
>
> dev_tag_del(dev, DM_TAG_EFI);
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] efi_loader: eliminate efi_disk_obj structure
2023-12-13 14:22 ` Heinrich Schuchardt
2023-12-13 19:50 ` Simon Glass
@ 2023-12-14 1:55 ` Masahisa Kojima
2023-12-14 7:31 ` Heinrich Schuchardt
1 sibling, 1 reply; 9+ messages in thread
From: Masahisa Kojima @ 2023-12-14 1:55 UTC (permalink / raw)
To: Heinrich Schuchardt; +Cc: Ilias Apalodimas, u-boot
Hi Heinrich,
On Wed, 13 Dec 2023 at 23:22, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>
> On 13.12.23 09:57, Masahisa Kojima wrote:
> > Current code uses struct efi_disk_obj to keep information
> > about block devices and partitions. As the efi handle already
> > has a field with the udevice, we should eliminate
> > struct efi_disk_obj and use an pointer to struct efi_object
> > for the handle.
> >
> > efi_link_dev() call is moved inside of efi_disk_add_dev() function
> > to simplify the cleanup process in case of error.
>
> I agree that using struct efi_disk_obj as a container for protocols of a
> block IO device is a bit messy.
>
> But we should keep looking up the handle easy. Currently we use
>
> diskobj = container_of(this, struct efi_disk_obj, ops);
>
> Instead we could append a private field with the handle to the
> EFI_BLOCK_IO_PROTOCOL structure.
>
> >
> > Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
> > ---
> > lib/efi_loader/efi_disk.c | 209 +++++++++++++++++++++-----------------
> > 1 file changed, 116 insertions(+), 93 deletions(-)
> >
> > diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> > index f0d76113b0..cfb7ace551 100644
> > --- a/lib/efi_loader/efi_disk.c
> > +++ b/lib/efi_loader/efi_disk.c
> > @@ -27,27 +27,24 @@ struct efi_system_partition efi_system_partition = {
> > const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
> > const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
> >
> > -/**
> > - * struct efi_disk_obj - EFI disk object
> > - *
> > - * @header: EFI object header
> > - * @ops: EFI disk I/O protocol interface
> > - * @dev_index: device index of block device
> > - * @media: block I/O media information
> > - * @dp: device path to the block device
> > - * @part: partition
> > - * @volume: simple file system protocol of the partition
> > - * @dev: associated DM device
> > - */
> > -struct efi_disk_obj {
> > - struct efi_object header;
> > - struct efi_block_io ops;
> > - int dev_index;
> > - struct efi_block_io_media media;
> > - struct efi_device_path *dp;
> > - unsigned int part;
> > - struct efi_simple_file_system_protocol *volume;
> > -};
> > +static efi_handle_t efi_blkio_find_obj(struct efi_block_io *blkio)
> > +{
> > + efi_handle_t handle;
> > +
> > + list_for_each_entry(handle, &efi_obj_list, link) {
> > + efi_status_t ret;
> > + struct efi_handler *handler;
> > +
> > + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> > + if (ret != EFI_SUCCESS)
> > + continue;
> > +
> > + if (blkio == handler->protocol_interface)
> > + return handle;
> > + }
>
> Depending on the number of handles and pointers this will take a
> considerable time. A private field for the handle appended to struct
> efi_block_io would allow a fast lookup.
>
> EDK II does the same. See the definition of RAM_DISK_PRIVATE_FROM_BLKIO
> which uses macro BASE_CR() to find the private fields.
This patch tries to address this issue[0].
If I understand correctly, two options are suggested here.
1) a private field for the handle appended to struct efi_block_io
2) keep the private struct something like current struct
efi_disk_obj, same as EDK II does
struct efi_block_io is defined in UEFI spec, so probably option#2 is preferable
and it is almost the same as the current implementation.
I think we can proceed with the minor cleanup of struct efi_disk_obj
as Akashi-san suggested.
[0] https://source.denx.de/u-boot/custodians/u-boot-efi/-/issues/9
Thanks,
Masahisa Kojima
>
> Best regards
>
> Heinrich
>
> > +
> > + return NULL;
> > +}
> >
> > /**
> > * efi_disk_reset() - reset block device
> > @@ -107,13 +104,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> > u32 media_id, u64 lba, unsigned long buffer_size,
> > void *buffer, enum efi_disk_direction direction)
> > {
> > - struct efi_disk_obj *diskobj;
> > + efi_handle_t handle;
> > int blksz;
> > int blocks;
> > unsigned long n;
> >
> > - diskobj = container_of(this, struct efi_disk_obj, ops);
> > - blksz = diskobj->media.block_size;
> > + handle = efi_blkio_find_obj(this);
> > + if (!handle)
> > + return EFI_INVALID_PARAMETER;
> > +
> > + blksz = this->media->block_size;
> > blocks = buffer_size / blksz;
> >
> > EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
> > @@ -124,18 +124,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> > return EFI_BAD_BUFFER_SIZE;
> >
> > if (CONFIG_IS_ENABLED(PARTITIONS) &&
> > - device_get_uclass_id(diskobj->header.dev) == UCLASS_PARTITION) {
> > + device_get_uclass_id(handle->dev) == UCLASS_PARTITION) {
> > if (direction == EFI_DISK_READ)
> > - n = disk_blk_read(diskobj->header.dev, lba, blocks,
> > - buffer);
> > + n = disk_blk_read(handle->dev, lba, blocks, buffer);
> > else
> > - n = disk_blk_write(diskobj->header.dev, lba, blocks,
> > - buffer);
> > + n = disk_blk_write(handle->dev, lba, blocks, buffer);
> > } else {
> > /* dev is a block device (UCLASS_BLK) */
> > struct blk_desc *desc;
> >
> > - desc = dev_get_uclass_plat(diskobj->header.dev);
> > + desc = dev_get_uclass_plat(handle->dev);
> > if (direction == EFI_DISK_READ)
> > n = blk_dread(desc, lba, blocks, buffer);
> > else
> > @@ -388,6 +386,7 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
> > * @part: partition
> > * @disk: pointer to receive the created handle
> > * @agent_handle: handle of the EFI block driver
> > + * @dev: pointer to udevice
> > * Return: disk object
> > */
> > static efi_status_t efi_disk_add_dev(
> > @@ -397,24 +396,33 @@ static efi_status_t efi_disk_add_dev(
> > int dev_index,
> > struct disk_partition *part_info,
> > unsigned int part,
> > - struct efi_disk_obj **disk,
> > - efi_handle_t agent_handle)
> > + efi_handle_t *disk,
> > + efi_handle_t agent_handle,
> > + struct udevice *dev)
> > {
> > - struct efi_disk_obj *diskobj;
> > - struct efi_object *handle;
> > + efi_handle_t handle;
> > const efi_guid_t *esp_guid = NULL;
> > efi_status_t ret;
> > + struct efi_block_io *blkio;
> > + struct efi_block_io_media *media;
> > + struct efi_device_path *dp = NULL;
> > + struct efi_simple_file_system_protocol *volume = NULL;
> >
> > /* Don't add empty devices */
> > if (!desc->lba)
> > return EFI_NOT_READY;
> >
> > - diskobj = calloc(1, sizeof(*diskobj));
> > - if (!diskobj)
> > + ret = efi_create_handle(&handle);
> > + if (ret != EFI_SUCCESS)
> > + return ret;
> > +
> > + blkio = calloc(1, sizeof(*blkio));
> > + media = calloc(1, sizeof(*media));
> > + if (!blkio || !media)
> > return EFI_OUT_OF_RESOURCES;
> >
> > - /* Hook up to the device list */
> > - efi_add_handle(&diskobj->header);
> > + *blkio = block_io_disk_template;
> > + blkio->media = media;
> >
> > /* Fill in object data */
> > if (part_info) {
> > @@ -440,23 +448,22 @@ static efi_status_t efi_disk_add_dev(
> > * (controller).
> > */
> > ret = efi_protocol_open(handler, &protocol_interface, NULL,
> > - &diskobj->header,
> > + handle,
> > EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
> > if (ret != EFI_SUCCESS) {
> > log_debug("prot open failed\n");
> > goto error;
> > }
> >
> > - diskobj->dp = efi_dp_append_node(dp_parent, node);
> > + dp = efi_dp_append_node(dp_parent, node);
> > efi_free_pool(node);
> > - diskobj->media.last_block = part_info->size - 1;
> > + blkio->media->last_block = part_info->size - 1;
> > if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
> > esp_guid = &efi_system_partition_guid;
> > } else {
> > - diskobj->dp = efi_dp_from_part(desc, part);
> > - diskobj->media.last_block = desc->lba - 1;
> > + dp = efi_dp_from_part(desc, part);
> > + blkio->media->last_block = desc->lba - 1;
> > }
> > - diskobj->part = part;
> >
> > /*
> > * Install the device path and the block IO protocol.
> > @@ -465,11 +472,10 @@ static efi_status_t efi_disk_add_dev(
> > * already installed on an other handle and returns EFI_ALREADY_STARTED
> > * in this case.
> > */
> > - handle = &diskobj->header;
> > ret = efi_install_multiple_protocol_interfaces(
> > &handle,
> > - &efi_guid_device_path, diskobj->dp,
> > - &efi_block_io_guid, &diskobj->ops,
> > + &efi_guid_device_path, dp,
> > + &efi_block_io_guid, blkio,
> > /*
> > * esp_guid must be last entry as it
> > * can be NULL. Its interface is NULL.
> > @@ -487,43 +493,39 @@ static efi_status_t efi_disk_add_dev(
> > */
> > if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
> > efi_fs_exists(desc, part)) {
> > - ret = efi_create_simple_file_system(desc, part, diskobj->dp,
> > - &diskobj->volume);
> > + ret = efi_create_simple_file_system(desc, part, dp, &volume);
> > if (ret != EFI_SUCCESS)
> > goto error;
> >
> > - ret = efi_add_protocol(&diskobj->header,
> > + ret = efi_add_protocol(handle,
> > &efi_simple_file_system_protocol_guid,
> > - diskobj->volume);
> > + volume);
> > if (ret != EFI_SUCCESS)
> > goto error;
> > }
> > - diskobj->ops = block_io_disk_template;
> > - diskobj->dev_index = dev_index;
> >
> > /* Fill in EFI IO Media info (for read/write callbacks) */
> > - diskobj->media.removable_media = desc->removable;
> > - diskobj->media.media_present = 1;
> > + blkio->media->removable_media = desc->removable;
> > + blkio->media->media_present = 1;
> > /*
> > * MediaID is just an arbitrary counter.
> > * We have to change it if the medium is removed or changed.
> > */
> > - diskobj->media.media_id = 1;
> > - diskobj->media.block_size = desc->blksz;
> > - diskobj->media.io_align = desc->blksz;
> > + blkio->media->media_id = 1;
> > + blkio->media->block_size = desc->blksz;
> > + blkio->media->io_align = desc->blksz;
> > if (part)
> > - diskobj->media.logical_partition = 1;
> > - diskobj->ops.media = &diskobj->media;
> > + blkio->media->logical_partition = 1;
> > if (disk)
> > - *disk = diskobj;
> > + *disk = handle;
> >
> > EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
> > ", last_block %llu\n",
> > - diskobj->part,
> > - diskobj->media.media_present,
> > - diskobj->media.logical_partition,
> > - diskobj->media.removable_media,
> > - diskobj->media.last_block);
> > + part,
> > + blkio->media->media_present,
> > + blkio->media->logical_partition,
> > + blkio->media->removable_media,
> > + blkio->media->last_block);
> >
> > /* Store first EFI system partition */
> > if (part && efi_system_partition.uclass_id == UCLASS_INVALID) {
> > @@ -536,11 +538,18 @@ static efi_status_t efi_disk_add_dev(
> > desc->devnum, part);
> > }
> > }
> > +
> > + if (efi_link_dev(handle, dev))
> > + goto error;
> > +
> > return EFI_SUCCESS;
> > error:
> > - efi_delete_handle(&diskobj->header);
> > - free(diskobj->volume);
> > - free(diskobj);
> > + efi_delete_handle(handle);
> > + efi_free_pool(dp);
> > + free(blkio);
> > + free(media);
> > + free(volume);
> > +
> > return ret;
> > }
> >
> > @@ -557,7 +566,7 @@ error:
> > */
> > static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> > {
> > - struct efi_disk_obj *disk;
> > + efi_handle_t disk;
> > struct blk_desc *desc;
> > int diskid;
> > efi_status_t ret;
> > @@ -566,7 +575,7 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> > diskid = desc->devnum;
> >
> > ret = efi_disk_add_dev(NULL, NULL, desc,
> > - diskid, NULL, 0, &disk, agent_handle);
> > + diskid, NULL, 0, &disk, agent_handle, dev);
> > if (ret != EFI_SUCCESS) {
> > if (ret == EFI_NOT_READY) {
> > log_notice("Disk %s not ready\n", dev->name);
> > @@ -578,12 +587,6 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> >
> > return ret;
> > }
> > - if (efi_link_dev(&disk->header, dev)) {
> > - efi_free_pool(disk->dp);
> > - efi_delete_handle(&disk->header);
> > -
> > - return -EINVAL;
> > - }
> >
> > return 0;
> > }
> > @@ -609,7 +612,7 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
> > int diskid;
> > struct efi_handler *handler;
> > struct efi_device_path *dp_parent;
> > - struct efi_disk_obj *disk;
> > + efi_handle_t disk;
> > efi_status_t ret;
> >
> > if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
> > @@ -628,17 +631,11 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
> > dp_parent = (struct efi_device_path *)handler->protocol_interface;
> >
> > ret = efi_disk_add_dev(parent, dp_parent, desc, diskid,
> > - info, part, &disk, agent_handle);
> > + info, part, &disk, agent_handle, dev);
> > if (ret != EFI_SUCCESS) {
> > log_err("Adding partition for %s failed\n", dev->name);
> > return -1;
> > }
> > - if (efi_link_dev(&disk->header, dev)) {
> > - efi_free_pool(disk->dp);
> > - efi_delete_handle(&disk->header);
> > -
> > - return -1;
> > - }
> >
> > return 0;
> > }
> > @@ -693,13 +690,34 @@ int efi_disk_probe(void *ctx, struct event *event)
> > return 0;
> > }
> >
> > +static void get_disk_resources(efi_handle_t handle, struct efi_device_path **dp,
> > + struct efi_block_io **blkio,
> > + struct efi_simple_file_system_protocol **volume)
> > +{
> > + efi_status_t ret;
> > + struct efi_handler *handler;
> > +
> > + ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
> > + if (ret == EFI_SUCCESS)
> > + *dp = handler->protocol_interface;
> > +
> > + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> > + if (ret == EFI_SUCCESS)
> > + *blkio = handler->protocol_interface;
> > +
> > + ret = efi_search_protocol(handle, &efi_simple_file_system_protocol_guid,
> > + &handler);
> > + if (ret == EFI_SUCCESS)
> > + *volume = handler->protocol_interface;
> > +}
> > +
> > /**
> > - * efi_disk_remove - delete an efi_disk object for a block device or partition
> > + * efi_disk_remove - delete an efi handle for a block device or partition
> > *
> > * @ctx: event context: driver binding protocol
> > * @event: EV_PM_PRE_REMOVE event
> > *
> > - * Delete an efi_disk object which is associated with the UCLASS_BLK or
> > + * Delete an efi handle which is associated with the UCLASS_BLK or
> > * UCLASS_PARTITION device for which the EV_PM_PRE_REMOVE event is raised.
> > *
> > * Return: 0 on success, -1 otherwise
> > @@ -710,8 +728,10 @@ int efi_disk_remove(void *ctx, struct event *event)
> > struct udevice *dev = event->data.dm.dev;
> > efi_handle_t handle;
> > struct blk_desc *desc;
> > - struct efi_disk_obj *diskobj = NULL;
> > efi_status_t ret;
> > + struct efi_device_path *dp = NULL;
> > + struct efi_block_io *blkio = NULL;
> > + struct efi_simple_file_system_protocol *volume = NULL;
> >
> > if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
> > return 0;
> > @@ -721,11 +741,11 @@ int efi_disk_remove(void *ctx, struct event *event)
> > case UCLASS_BLK:
> > desc = dev_get_uclass_plat(dev);
> > if (desc && desc->uclass_id != UCLASS_EFI_LOADER)
> > - diskobj = container_of(handle, struct efi_disk_obj,
> > - header);
> > + get_disk_resources(handle, &dp, &blkio, &volume);
> > +
> > break;
> > case UCLASS_PARTITION:
> > - diskobj = container_of(handle, struct efi_disk_obj, header);
> > + get_disk_resources(handle, &dp, &blkio, &volume);
> > break;
> > default:
> > return 0;
> > @@ -736,8 +756,11 @@ int efi_disk_remove(void *ctx, struct event *event)
> > if (ret != EFI_SUCCESS)
> > return -1;
> >
> > - if (diskobj)
> > - efi_free_pool(diskobj->dp);
> > + efi_free_pool(dp);
> > + if (blkio) {
> > + free(blkio->media);
> > + free(blkio);
> > + }
> >
> > dev_tag_del(dev, DM_TAG_EFI);
> >
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] efi_loader: eliminate efi_disk_obj structure
2023-12-14 1:55 ` Masahisa Kojima
@ 2023-12-14 7:31 ` Heinrich Schuchardt
2023-12-14 8:23 ` Masahisa Kojima
0 siblings, 1 reply; 9+ messages in thread
From: Heinrich Schuchardt @ 2023-12-14 7:31 UTC (permalink / raw)
To: Masahisa Kojima; +Cc: Ilias Apalodimas, u-boot
Am 14. Dezember 2023 02:55:27 MEZ schrieb Masahisa Kojima <masahisa.kojima@linaro.org>:
>Hi Heinrich,
>
>On Wed, 13 Dec 2023 at 23:22, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>
>> On 13.12.23 09:57, Masahisa Kojima wrote:
>> > Current code uses struct efi_disk_obj to keep information
>> > about block devices and partitions. As the efi handle already
>> > has a field with the udevice, we should eliminate
>> > struct efi_disk_obj and use an pointer to struct efi_object
>> > for the handle.
>> >
>> > efi_link_dev() call is moved inside of efi_disk_add_dev() function
>> > to simplify the cleanup process in case of error.
>>
>> I agree that using struct efi_disk_obj as a container for protocols of a
>> block IO device is a bit messy.
>>
>> But we should keep looking up the handle easy. Currently we use
>>
>> diskobj = container_of(this, struct efi_disk_obj, ops);
>>
>> Instead we could append a private field with the handle to the
>> EFI_BLOCK_IO_PROTOCOL structure.
>>
>> >
>> > Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
>> > ---
>> > lib/efi_loader/efi_disk.c | 209 +++++++++++++++++++++-----------------
>> > 1 file changed, 116 insertions(+), 93 deletions(-)
>> >
>> > diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
>> > index f0d76113b0..cfb7ace551 100644
>> > --- a/lib/efi_loader/efi_disk.c
>> > +++ b/lib/efi_loader/efi_disk.c
>> > @@ -27,27 +27,24 @@ struct efi_system_partition efi_system_partition = {
>> > const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
>> > const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
>> >
>> > -/**
>> > - * struct efi_disk_obj - EFI disk object
>> > - *
>> > - * @header: EFI object header
>> > - * @ops: EFI disk I/O protocol interface
>> > - * @dev_index: device index of block device
>> > - * @media: block I/O media information
>> > - * @dp: device path to the block device
>> > - * @part: partition
>> > - * @volume: simple file system protocol of the partition
>> > - * @dev: associated DM device
>> > - */
>> > -struct efi_disk_obj {
>> > - struct efi_object header;
>> > - struct efi_block_io ops;
>> > - int dev_index;
>> > - struct efi_block_io_media media;
>> > - struct efi_device_path *dp;
>> > - unsigned int part;
>> > - struct efi_simple_file_system_protocol *volume;
>> > -};
>> > +static efi_handle_t efi_blkio_find_obj(struct efi_block_io *blkio)
>> > +{
>> > + efi_handle_t handle;
>> > +
>> > + list_for_each_entry(handle, &efi_obj_list, link) {
>> > + efi_status_t ret;
>> > + struct efi_handler *handler;
>> > +
>> > + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
>> > + if (ret != EFI_SUCCESS)
>> > + continue;
>> > +
>> > + if (blkio == handler->protocol_interface)
>> > + return handle;
>> > + }
>>
>> Depending on the number of handles and pointers this will take a
>> considerable time. A private field for the handle appended to struct
>> efi_block_io would allow a fast lookup.
>>
>> EDK II does the same. See the definition of RAM_DISK_PRIVATE_FROM_BLKIO
>> which uses macro BASE_CR() to find the private fields.
>
>This patch tries to address this issue[0].
>
>If I understand correctly, two options are suggested here.
> 1) a private field for the handle appended to struct efi_block_io
> 2) keep the private struct something like current struct
>efi_disk_obj, same as EDK II does
Edk II uses 1) as I indicated above.
The UEFI specification prescribes which fields must be in the struct. In both 1) and 2) you have private fields at a known offset to the structure.
EDK II can (this is configurable) additionally add a magic value to verify that the overall structure was provided by EDK II.
Best regards
Heinrich
>
>struct efi_block_io is defined in UEFI spec, so probably option#2 is preferable
>and it is almost the same as the current implementation.
>I think we can proceed with the minor cleanup of struct efi_disk_obj
>as Akashi-san suggested.
>
>[0] https://source.denx.de/u-boot/custodians/u-boot-efi/-/issues/9
>
>Thanks,
>Masahisa Kojima
>
>>
>> Best regards
>>
>> Heinrich
>>
>> > +
>> > + return NULL;
>> > +}
>> >
>> > /**
>> > * efi_disk_reset() - reset block device
>> > @@ -107,13 +104,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
>> > u32 media_id, u64 lba, unsigned long buffer_size,
>> > void *buffer, enum efi_disk_direction direction)
>> > {
>> > - struct efi_disk_obj *diskobj;
>> > + efi_handle_t handle;
>> > int blksz;
>> > int blocks;
>> > unsigned long n;
>> >
>> > - diskobj = container_of(this, struct efi_disk_obj, ops);
>> > - blksz = diskobj->media.block_size;
>> > + handle = efi_blkio_find_obj(this);
>> > + if (!handle)
>> > + return EFI_INVALID_PARAMETER;
>> > +
>> > + blksz = this->media->block_size;
>> > blocks = buffer_size / blksz;
>> >
>> > EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
>> > @@ -124,18 +124,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
>> > return EFI_BAD_BUFFER_SIZE;
>> >
>> > if (CONFIG_IS_ENABLED(PARTITIONS) &&
>> > - device_get_uclass_id(diskobj->header.dev) == UCLASS_PARTITION) {
>> > + device_get_uclass_id(handle->dev) == UCLASS_PARTITION) {
>> > if (direction == EFI_DISK_READ)
>> > - n = disk_blk_read(diskobj->header.dev, lba, blocks,
>> > - buffer);
>> > + n = disk_blk_read(handle->dev, lba, blocks, buffer);
>> > else
>> > - n = disk_blk_write(diskobj->header.dev, lba, blocks,
>> > - buffer);
>> > + n = disk_blk_write(handle->dev, lba, blocks, buffer);
>> > } else {
>> > /* dev is a block device (UCLASS_BLK) */
>> > struct blk_desc *desc;
>> >
>> > - desc = dev_get_uclass_plat(diskobj->header.dev);
>> > + desc = dev_get_uclass_plat(handle->dev);
>> > if (direction == EFI_DISK_READ)
>> > n = blk_dread(desc, lba, blocks, buffer);
>> > else
>> > @@ -388,6 +386,7 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
>> > * @part: partition
>> > * @disk: pointer to receive the created handle
>> > * @agent_handle: handle of the EFI block driver
>> > + * @dev: pointer to udevice
>> > * Return: disk object
>> > */
>> > static efi_status_t efi_disk_add_dev(
>> > @@ -397,24 +396,33 @@ static efi_status_t efi_disk_add_dev(
>> > int dev_index,
>> > struct disk_partition *part_info,
>> > unsigned int part,
>> > - struct efi_disk_obj **disk,
>> > - efi_handle_t agent_handle)
>> > + efi_handle_t *disk,
>> > + efi_handle_t agent_handle,
>> > + struct udevice *dev)
>> > {
>> > - struct efi_disk_obj *diskobj;
>> > - struct efi_object *handle;
>> > + efi_handle_t handle;
>> > const efi_guid_t *esp_guid = NULL;
>> > efi_status_t ret;
>> > + struct efi_block_io *blkio;
>> > + struct efi_block_io_media *media;
>> > + struct efi_device_path *dp = NULL;
>> > + struct efi_simple_file_system_protocol *volume = NULL;
>> >
>> > /* Don't add empty devices */
>> > if (!desc->lba)
>> > return EFI_NOT_READY;
>> >
>> > - diskobj = calloc(1, sizeof(*diskobj));
>> > - if (!diskobj)
>> > + ret = efi_create_handle(&handle);
>> > + if (ret != EFI_SUCCESS)
>> > + return ret;
>> > +
>> > + blkio = calloc(1, sizeof(*blkio));
>> > + media = calloc(1, sizeof(*media));
>> > + if (!blkio || !media)
>> > return EFI_OUT_OF_RESOURCES;
>> >
>> > - /* Hook up to the device list */
>> > - efi_add_handle(&diskobj->header);
>> > + *blkio = block_io_disk_template;
>> > + blkio->media = media;
>> >
>> > /* Fill in object data */
>> > if (part_info) {
>> > @@ -440,23 +448,22 @@ static efi_status_t efi_disk_add_dev(
>> > * (controller).
>> > */
>> > ret = efi_protocol_open(handler, &protocol_interface, NULL,
>> > - &diskobj->header,
>> > + handle,
>> > EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
>> > if (ret != EFI_SUCCESS) {
>> > log_debug("prot open failed\n");
>> > goto error;
>> > }
>> >
>> > - diskobj->dp = efi_dp_append_node(dp_parent, node);
>> > + dp = efi_dp_append_node(dp_parent, node);
>> > efi_free_pool(node);
>> > - diskobj->media.last_block = part_info->size - 1;
>> > + blkio->media->last_block = part_info->size - 1;
>> > if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
>> > esp_guid = &efi_system_partition_guid;
>> > } else {
>> > - diskobj->dp = efi_dp_from_part(desc, part);
>> > - diskobj->media.last_block = desc->lba - 1;
>> > + dp = efi_dp_from_part(desc, part);
>> > + blkio->media->last_block = desc->lba - 1;
>> > }
>> > - diskobj->part = part;
>> >
>> > /*
>> > * Install the device path and the block IO protocol.
>> > @@ -465,11 +472,10 @@ static efi_status_t efi_disk_add_dev(
>> > * already installed on an other handle and returns EFI_ALREADY_STARTED
>> > * in this case.
>> > */
>> > - handle = &diskobj->header;
>> > ret = efi_install_multiple_protocol_interfaces(
>> > &handle,
>> > - &efi_guid_device_path, diskobj->dp,
>> > - &efi_block_io_guid, &diskobj->ops,
>> > + &efi_guid_device_path, dp,
>> > + &efi_block_io_guid, blkio,
>> > /*
>> > * esp_guid must be last entry as it
>> > * can be NULL. Its interface is NULL.
>> > @@ -487,43 +493,39 @@ static efi_status_t efi_disk_add_dev(
>> > */
>> > if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
>> > efi_fs_exists(desc, part)) {
>> > - ret = efi_create_simple_file_system(desc, part, diskobj->dp,
>> > - &diskobj->volume);
>> > + ret = efi_create_simple_file_system(desc, part, dp, &volume);
>> > if (ret != EFI_SUCCESS)
>> > goto error;
>> >
>> > - ret = efi_add_protocol(&diskobj->header,
>> > + ret = efi_add_protocol(handle,
>> > &efi_simple_file_system_protocol_guid,
>> > - diskobj->volume);
>> > + volume);
>> > if (ret != EFI_SUCCESS)
>> > goto error;
>> > }
>> > - diskobj->ops = block_io_disk_template;
>> > - diskobj->dev_index = dev_index;
>> >
>> > /* Fill in EFI IO Media info (for read/write callbacks) */
>> > - diskobj->media.removable_media = desc->removable;
>> > - diskobj->media.media_present = 1;
>> > + blkio->media->removable_media = desc->removable;
>> > + blkio->media->media_present = 1;
>> > /*
>> > * MediaID is just an arbitrary counter.
>> > * We have to change it if the medium is removed or changed.
>> > */
>> > - diskobj->media.media_id = 1;
>> > - diskobj->media.block_size = desc->blksz;
>> > - diskobj->media.io_align = desc->blksz;
>> > + blkio->media->media_id = 1;
>> > + blkio->media->block_size = desc->blksz;
>> > + blkio->media->io_align = desc->blksz;
>> > if (part)
>> > - diskobj->media.logical_partition = 1;
>> > - diskobj->ops.media = &diskobj->media;
>> > + blkio->media->logical_partition = 1;
>> > if (disk)
>> > - *disk = diskobj;
>> > + *disk = handle;
>> >
>> > EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
>> > ", last_block %llu\n",
>> > - diskobj->part,
>> > - diskobj->media.media_present,
>> > - diskobj->media.logical_partition,
>> > - diskobj->media.removable_media,
>> > - diskobj->media.last_block);
>> > + part,
>> > + blkio->media->media_present,
>> > + blkio->media->logical_partition,
>> > + blkio->media->removable_media,
>> > + blkio->media->last_block);
>> >
>> > /* Store first EFI system partition */
>> > if (part && efi_system_partition.uclass_id == UCLASS_INVALID) {
>> > @@ -536,11 +538,18 @@ static efi_status_t efi_disk_add_dev(
>> > desc->devnum, part);
>> > }
>> > }
>> > +
>> > + if (efi_link_dev(handle, dev))
>> > + goto error;
>> > +
>> > return EFI_SUCCESS;
>> > error:
>> > - efi_delete_handle(&diskobj->header);
>> > - free(diskobj->volume);
>> > - free(diskobj);
>> > + efi_delete_handle(handle);
>> > + efi_free_pool(dp);
>> > + free(blkio);
>> > + free(media);
>> > + free(volume);
>> > +
>> > return ret;
>> > }
>> >
>> > @@ -557,7 +566,7 @@ error:
>> > */
>> > static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
>> > {
>> > - struct efi_disk_obj *disk;
>> > + efi_handle_t disk;
>> > struct blk_desc *desc;
>> > int diskid;
>> > efi_status_t ret;
>> > @@ -566,7 +575,7 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
>> > diskid = desc->devnum;
>> >
>> > ret = efi_disk_add_dev(NULL, NULL, desc,
>> > - diskid, NULL, 0, &disk, agent_handle);
>> > + diskid, NULL, 0, &disk, agent_handle, dev);
>> > if (ret != EFI_SUCCESS) {
>> > if (ret == EFI_NOT_READY) {
>> > log_notice("Disk %s not ready\n", dev->name);
>> > @@ -578,12 +587,6 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
>> >
>> > return ret;
>> > }
>> > - if (efi_link_dev(&disk->header, dev)) {
>> > - efi_free_pool(disk->dp);
>> > - efi_delete_handle(&disk->header);
>> > -
>> > - return -EINVAL;
>> > - }
>> >
>> > return 0;
>> > }
>> > @@ -609,7 +612,7 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
>> > int diskid;
>> > struct efi_handler *handler;
>> > struct efi_device_path *dp_parent;
>> > - struct efi_disk_obj *disk;
>> > + efi_handle_t disk;
>> > efi_status_t ret;
>> >
>> > if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
>> > @@ -628,17 +631,11 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
>> > dp_parent = (struct efi_device_path *)handler->protocol_interface;
>> >
>> > ret = efi_disk_add_dev(parent, dp_parent, desc, diskid,
>> > - info, part, &disk, agent_handle);
>> > + info, part, &disk, agent_handle, dev);
>> > if (ret != EFI_SUCCESS) {
>> > log_err("Adding partition for %s failed\n", dev->name);
>> > return -1;
>> > }
>> > - if (efi_link_dev(&disk->header, dev)) {
>> > - efi_free_pool(disk->dp);
>> > - efi_delete_handle(&disk->header);
>> > -
>> > - return -1;
>> > - }
>> >
>> > return 0;
>> > }
>> > @@ -693,13 +690,34 @@ int efi_disk_probe(void *ctx, struct event *event)
>> > return 0;
>> > }
>> >
>> > +static void get_disk_resources(efi_handle_t handle, struct efi_device_path **dp,
>> > + struct efi_block_io **blkio,
>> > + struct efi_simple_file_system_protocol **volume)
>> > +{
>> > + efi_status_t ret;
>> > + struct efi_handler *handler;
>> > +
>> > + ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
>> > + if (ret == EFI_SUCCESS)
>> > + *dp = handler->protocol_interface;
>> > +
>> > + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
>> > + if (ret == EFI_SUCCESS)
>> > + *blkio = handler->protocol_interface;
>> > +
>> > + ret = efi_search_protocol(handle, &efi_simple_file_system_protocol_guid,
>> > + &handler);
>> > + if (ret == EFI_SUCCESS)
>> > + *volume = handler->protocol_interface;
>> > +}
>> > +
>> > /**
>> > - * efi_disk_remove - delete an efi_disk object for a block device or partition
>> > + * efi_disk_remove - delete an efi handle for a block device or partition
>> > *
>> > * @ctx: event context: driver binding protocol
>> > * @event: EV_PM_PRE_REMOVE event
>> > *
>> > - * Delete an efi_disk object which is associated with the UCLASS_BLK or
>> > + * Delete an efi handle which is associated with the UCLASS_BLK or
>> > * UCLASS_PARTITION device for which the EV_PM_PRE_REMOVE event is raised.
>> > *
>> > * Return: 0 on success, -1 otherwise
>> > @@ -710,8 +728,10 @@ int efi_disk_remove(void *ctx, struct event *event)
>> > struct udevice *dev = event->data.dm.dev;
>> > efi_handle_t handle;
>> > struct blk_desc *desc;
>> > - struct efi_disk_obj *diskobj = NULL;
>> > efi_status_t ret;
>> > + struct efi_device_path *dp = NULL;
>> > + struct efi_block_io *blkio = NULL;
>> > + struct efi_simple_file_system_protocol *volume = NULL;
>> >
>> > if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
>> > return 0;
>> > @@ -721,11 +741,11 @@ int efi_disk_remove(void *ctx, struct event *event)
>> > case UCLASS_BLK:
>> > desc = dev_get_uclass_plat(dev);
>> > if (desc && desc->uclass_id != UCLASS_EFI_LOADER)
>> > - diskobj = container_of(handle, struct efi_disk_obj,
>> > - header);
>> > + get_disk_resources(handle, &dp, &blkio, &volume);
>> > +
>> > break;
>> > case UCLASS_PARTITION:
>> > - diskobj = container_of(handle, struct efi_disk_obj, header);
>> > + get_disk_resources(handle, &dp, &blkio, &volume);
>> > break;
>> > default:
>> > return 0;
>> > @@ -736,8 +756,11 @@ int efi_disk_remove(void *ctx, struct event *event)
>> > if (ret != EFI_SUCCESS)
>> > return -1;
>> >
>> > - if (diskobj)
>> > - efi_free_pool(diskobj->dp);
>> > + efi_free_pool(dp);
>> > + if (blkio) {
>> > + free(blkio->media);
>> > + free(blkio);
>> > + }
>> >
>> > dev_tag_del(dev, DM_TAG_EFI);
>> >
>>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] efi_loader: eliminate efi_disk_obj structure
2023-12-14 7:31 ` Heinrich Schuchardt
@ 2023-12-14 8:23 ` Masahisa Kojima
2023-12-17 10:26 ` Heinrich Schuchardt
0 siblings, 1 reply; 9+ messages in thread
From: Masahisa Kojima @ 2023-12-14 8:23 UTC (permalink / raw)
To: Heinrich Schuchardt; +Cc: Ilias Apalodimas, u-boot
Hi Heinrich,
On Thu, 14 Dec 2023 at 16:31, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>
>
>
> Am 14. Dezember 2023 02:55:27 MEZ schrieb Masahisa Kojima <masahisa.kojima@linaro.org>:
> >Hi Heinrich,
> >
> >On Wed, 13 Dec 2023 at 23:22, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >>
> >> On 13.12.23 09:57, Masahisa Kojima wrote:
> >> > Current code uses struct efi_disk_obj to keep information
> >> > about block devices and partitions. As the efi handle already
> >> > has a field with the udevice, we should eliminate
> >> > struct efi_disk_obj and use an pointer to struct efi_object
> >> > for the handle.
> >> >
> >> > efi_link_dev() call is moved inside of efi_disk_add_dev() function
> >> > to simplify the cleanup process in case of error.
> >>
> >> I agree that using struct efi_disk_obj as a container for protocols of a
> >> block IO device is a bit messy.
> >>
> >> But we should keep looking up the handle easy. Currently we use
> >>
> >> diskobj = container_of(this, struct efi_disk_obj, ops);
> >>
> >> Instead we could append a private field with the handle to the
> >> EFI_BLOCK_IO_PROTOCOL structure.
> >>
> >> >
> >> > Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
> >> > ---
> >> > lib/efi_loader/efi_disk.c | 209 +++++++++++++++++++++-----------------
> >> > 1 file changed, 116 insertions(+), 93 deletions(-)
> >> >
> >> > diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> >> > index f0d76113b0..cfb7ace551 100644
> >> > --- a/lib/efi_loader/efi_disk.c
> >> > +++ b/lib/efi_loader/efi_disk.c
> >> > @@ -27,27 +27,24 @@ struct efi_system_partition efi_system_partition = {
> >> > const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
> >> > const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
> >> >
> >> > -/**
> >> > - * struct efi_disk_obj - EFI disk object
> >> > - *
> >> > - * @header: EFI object header
> >> > - * @ops: EFI disk I/O protocol interface
> >> > - * @dev_index: device index of block device
> >> > - * @media: block I/O media information
> >> > - * @dp: device path to the block device
> >> > - * @part: partition
> >> > - * @volume: simple file system protocol of the partition
> >> > - * @dev: associated DM device
> >> > - */
> >> > -struct efi_disk_obj {
> >> > - struct efi_object header;
> >> > - struct efi_block_io ops;
> >> > - int dev_index;
> >> > - struct efi_block_io_media media;
> >> > - struct efi_device_path *dp;
> >> > - unsigned int part;
> >> > - struct efi_simple_file_system_protocol *volume;
> >> > -};
> >> > +static efi_handle_t efi_blkio_find_obj(struct efi_block_io *blkio)
> >> > +{
> >> > + efi_handle_t handle;
> >> > +
> >> > + list_for_each_entry(handle, &efi_obj_list, link) {
> >> > + efi_status_t ret;
> >> > + struct efi_handler *handler;
> >> > +
> >> > + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> >> > + if (ret != EFI_SUCCESS)
> >> > + continue;
> >> > +
> >> > + if (blkio == handler->protocol_interface)
> >> > + return handle;
> >> > + }
> >>
> >> Depending on the number of handles and pointers this will take a
> >> considerable time. A private field for the handle appended to struct
> >> efi_block_io would allow a fast lookup.
> >>
> >> EDK II does the same. See the definition of RAM_DISK_PRIVATE_FROM_BLKIO
> >> which uses macro BASE_CR() to find the private fields.
> >
> >This patch tries to address this issue[0].
> >
> >If I understand correctly, two options are suggested here.
> > 1) a private field for the handle appended to struct efi_block_io
> > 2) keep the private struct something like current struct
> >efi_disk_obj, same as EDK II does
>
> Edk II uses 1) as I indicated above.
Probably I misunderstand your suggestion, let me clarify again.
EDK II RamDisk implementation defines the private structure
RAM_DISK_PRIVATE_DATA[1].
RAM_DISK_PRIVATE_FROM_BLKIO macro returns the pointer to the
RAM_DISK_PRIVATE_DATA structure from the BLKIO protocol interface.
EFI_BLOCK_IO_PROTOCOL does not have a private field.
It is the same as the current U-Boot implementation of efi_disk.c using
struct efi_disk_obj and following code.
diskobj = container_of(this, struct efi_disk_obj, ops);
Do you suggest modifying struct efi_block_io to add private fields?
[1] https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h#L95
Thanks,
Masahisa Kojima
>
> The UEFI specification prescribes which fields must be in the struct. In both 1) and 2) you have private fields at a known offset to the structure.
>
> EDK II can (this is configurable) additionally add a magic value to verify that the overall structure was provided by EDK II.
>
> Best regards
>
> Heinrich
>
>
> >
> >struct efi_block_io is defined in UEFI spec, so probably option#2 is preferable
> >and it is almost the same as the current implementation.
> >I think we can proceed with the minor cleanup of struct efi_disk_obj
> >as Akashi-san suggested.
> >
> >[0] https://source.denx.de/u-boot/custodians/u-boot-efi/-/issues/9
> >
> >Thanks,
> >Masahisa Kojima
> >
> >>
> >> Best regards
> >>
> >> Heinrich
> >>
> >> > +
> >> > + return NULL;
> >> > +}
> >> >
> >> > /**
> >> > * efi_disk_reset() - reset block device
> >> > @@ -107,13 +104,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> >> > u32 media_id, u64 lba, unsigned long buffer_size,
> >> > void *buffer, enum efi_disk_direction direction)
> >> > {
> >> > - struct efi_disk_obj *diskobj;
> >> > + efi_handle_t handle;
> >> > int blksz;
> >> > int blocks;
> >> > unsigned long n;
> >> >
> >> > - diskobj = container_of(this, struct efi_disk_obj, ops);
> >> > - blksz = diskobj->media.block_size;
> >> > + handle = efi_blkio_find_obj(this);
> >> > + if (!handle)
> >> > + return EFI_INVALID_PARAMETER;
> >> > +
> >> > + blksz = this->media->block_size;
> >> > blocks = buffer_size / blksz;
> >> >
> >> > EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
> >> > @@ -124,18 +124,16 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> >> > return EFI_BAD_BUFFER_SIZE;
> >> >
> >> > if (CONFIG_IS_ENABLED(PARTITIONS) &&
> >> > - device_get_uclass_id(diskobj->header.dev) == UCLASS_PARTITION) {
> >> > + device_get_uclass_id(handle->dev) == UCLASS_PARTITION) {
> >> > if (direction == EFI_DISK_READ)
> >> > - n = disk_blk_read(diskobj->header.dev, lba, blocks,
> >> > - buffer);
> >> > + n = disk_blk_read(handle->dev, lba, blocks, buffer);
> >> > else
> >> > - n = disk_blk_write(diskobj->header.dev, lba, blocks,
> >> > - buffer);
> >> > + n = disk_blk_write(handle->dev, lba, blocks, buffer);
> >> > } else {
> >> > /* dev is a block device (UCLASS_BLK) */
> >> > struct blk_desc *desc;
> >> >
> >> > - desc = dev_get_uclass_plat(diskobj->header.dev);
> >> > + desc = dev_get_uclass_plat(handle->dev);
> >> > if (direction == EFI_DISK_READ)
> >> > n = blk_dread(desc, lba, blocks, buffer);
> >> > else
> >> > @@ -388,6 +386,7 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
> >> > * @part: partition
> >> > * @disk: pointer to receive the created handle
> >> > * @agent_handle: handle of the EFI block driver
> >> > + * @dev: pointer to udevice
> >> > * Return: disk object
> >> > */
> >> > static efi_status_t efi_disk_add_dev(
> >> > @@ -397,24 +396,33 @@ static efi_status_t efi_disk_add_dev(
> >> > int dev_index,
> >> > struct disk_partition *part_info,
> >> > unsigned int part,
> >> > - struct efi_disk_obj **disk,
> >> > - efi_handle_t agent_handle)
> >> > + efi_handle_t *disk,
> >> > + efi_handle_t agent_handle,
> >> > + struct udevice *dev)
> >> > {
> >> > - struct efi_disk_obj *diskobj;
> >> > - struct efi_object *handle;
> >> > + efi_handle_t handle;
> >> > const efi_guid_t *esp_guid = NULL;
> >> > efi_status_t ret;
> >> > + struct efi_block_io *blkio;
> >> > + struct efi_block_io_media *media;
> >> > + struct efi_device_path *dp = NULL;
> >> > + struct efi_simple_file_system_protocol *volume = NULL;
> >> >
> >> > /* Don't add empty devices */
> >> > if (!desc->lba)
> >> > return EFI_NOT_READY;
> >> >
> >> > - diskobj = calloc(1, sizeof(*diskobj));
> >> > - if (!diskobj)
> >> > + ret = efi_create_handle(&handle);
> >> > + if (ret != EFI_SUCCESS)
> >> > + return ret;
> >> > +
> >> > + blkio = calloc(1, sizeof(*blkio));
> >> > + media = calloc(1, sizeof(*media));
> >> > + if (!blkio || !media)
> >> > return EFI_OUT_OF_RESOURCES;
> >> >
> >> > - /* Hook up to the device list */
> >> > - efi_add_handle(&diskobj->header);
> >> > + *blkio = block_io_disk_template;
> >> > + blkio->media = media;
> >> >
> >> > /* Fill in object data */
> >> > if (part_info) {
> >> > @@ -440,23 +448,22 @@ static efi_status_t efi_disk_add_dev(
> >> > * (controller).
> >> > */
> >> > ret = efi_protocol_open(handler, &protocol_interface, NULL,
> >> > - &diskobj->header,
> >> > + handle,
> >> > EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
> >> > if (ret != EFI_SUCCESS) {
> >> > log_debug("prot open failed\n");
> >> > goto error;
> >> > }
> >> >
> >> > - diskobj->dp = efi_dp_append_node(dp_parent, node);
> >> > + dp = efi_dp_append_node(dp_parent, node);
> >> > efi_free_pool(node);
> >> > - diskobj->media.last_block = part_info->size - 1;
> >> > + blkio->media->last_block = part_info->size - 1;
> >> > if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
> >> > esp_guid = &efi_system_partition_guid;
> >> > } else {
> >> > - diskobj->dp = efi_dp_from_part(desc, part);
> >> > - diskobj->media.last_block = desc->lba - 1;
> >> > + dp = efi_dp_from_part(desc, part);
> >> > + blkio->media->last_block = desc->lba - 1;
> >> > }
> >> > - diskobj->part = part;
> >> >
> >> > /*
> >> > * Install the device path and the block IO protocol.
> >> > @@ -465,11 +472,10 @@ static efi_status_t efi_disk_add_dev(
> >> > * already installed on an other handle and returns EFI_ALREADY_STARTED
> >> > * in this case.
> >> > */
> >> > - handle = &diskobj->header;
> >> > ret = efi_install_multiple_protocol_interfaces(
> >> > &handle,
> >> > - &efi_guid_device_path, diskobj->dp,
> >> > - &efi_block_io_guid, &diskobj->ops,
> >> > + &efi_guid_device_path, dp,
> >> > + &efi_block_io_guid, blkio,
> >> > /*
> >> > * esp_guid must be last entry as it
> >> > * can be NULL. Its interface is NULL.
> >> > @@ -487,43 +493,39 @@ static efi_status_t efi_disk_add_dev(
> >> > */
> >> > if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
> >> > efi_fs_exists(desc, part)) {
> >> > - ret = efi_create_simple_file_system(desc, part, diskobj->dp,
> >> > - &diskobj->volume);
> >> > + ret = efi_create_simple_file_system(desc, part, dp, &volume);
> >> > if (ret != EFI_SUCCESS)
> >> > goto error;
> >> >
> >> > - ret = efi_add_protocol(&diskobj->header,
> >> > + ret = efi_add_protocol(handle,
> >> > &efi_simple_file_system_protocol_guid,
> >> > - diskobj->volume);
> >> > + volume);
> >> > if (ret != EFI_SUCCESS)
> >> > goto error;
> >> > }
> >> > - diskobj->ops = block_io_disk_template;
> >> > - diskobj->dev_index = dev_index;
> >> >
> >> > /* Fill in EFI IO Media info (for read/write callbacks) */
> >> > - diskobj->media.removable_media = desc->removable;
> >> > - diskobj->media.media_present = 1;
> >> > + blkio->media->removable_media = desc->removable;
> >> > + blkio->media->media_present = 1;
> >> > /*
> >> > * MediaID is just an arbitrary counter.
> >> > * We have to change it if the medium is removed or changed.
> >> > */
> >> > - diskobj->media.media_id = 1;
> >> > - diskobj->media.block_size = desc->blksz;
> >> > - diskobj->media.io_align = desc->blksz;
> >> > + blkio->media->media_id = 1;
> >> > + blkio->media->block_size = desc->blksz;
> >> > + blkio->media->io_align = desc->blksz;
> >> > if (part)
> >> > - diskobj->media.logical_partition = 1;
> >> > - diskobj->ops.media = &diskobj->media;
> >> > + blkio->media->logical_partition = 1;
> >> > if (disk)
> >> > - *disk = diskobj;
> >> > + *disk = handle;
> >> >
> >> > EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
> >> > ", last_block %llu\n",
> >> > - diskobj->part,
> >> > - diskobj->media.media_present,
> >> > - diskobj->media.logical_partition,
> >> > - diskobj->media.removable_media,
> >> > - diskobj->media.last_block);
> >> > + part,
> >> > + blkio->media->media_present,
> >> > + blkio->media->logical_partition,
> >> > + blkio->media->removable_media,
> >> > + blkio->media->last_block);
> >> >
> >> > /* Store first EFI system partition */
> >> > if (part && efi_system_partition.uclass_id == UCLASS_INVALID) {
> >> > @@ -536,11 +538,18 @@ static efi_status_t efi_disk_add_dev(
> >> > desc->devnum, part);
> >> > }
> >> > }
> >> > +
> >> > + if (efi_link_dev(handle, dev))
> >> > + goto error;
> >> > +
> >> > return EFI_SUCCESS;
> >> > error:
> >> > - efi_delete_handle(&diskobj->header);
> >> > - free(diskobj->volume);
> >> > - free(diskobj);
> >> > + efi_delete_handle(handle);
> >> > + efi_free_pool(dp);
> >> > + free(blkio);
> >> > + free(media);
> >> > + free(volume);
> >> > +
> >> > return ret;
> >> > }
> >> >
> >> > @@ -557,7 +566,7 @@ error:
> >> > */
> >> > static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> >> > {
> >> > - struct efi_disk_obj *disk;
> >> > + efi_handle_t disk;
> >> > struct blk_desc *desc;
> >> > int diskid;
> >> > efi_status_t ret;
> >> > @@ -566,7 +575,7 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> >> > diskid = desc->devnum;
> >> >
> >> > ret = efi_disk_add_dev(NULL, NULL, desc,
> >> > - diskid, NULL, 0, &disk, agent_handle);
> >> > + diskid, NULL, 0, &disk, agent_handle, dev);
> >> > if (ret != EFI_SUCCESS) {
> >> > if (ret == EFI_NOT_READY) {
> >> > log_notice("Disk %s not ready\n", dev->name);
> >> > @@ -578,12 +587,6 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
> >> >
> >> > return ret;
> >> > }
> >> > - if (efi_link_dev(&disk->header, dev)) {
> >> > - efi_free_pool(disk->dp);
> >> > - efi_delete_handle(&disk->header);
> >> > -
> >> > - return -EINVAL;
> >> > - }
> >> >
> >> > return 0;
> >> > }
> >> > @@ -609,7 +612,7 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
> >> > int diskid;
> >> > struct efi_handler *handler;
> >> > struct efi_device_path *dp_parent;
> >> > - struct efi_disk_obj *disk;
> >> > + efi_handle_t disk;
> >> > efi_status_t ret;
> >> >
> >> > if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
> >> > @@ -628,17 +631,11 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
> >> > dp_parent = (struct efi_device_path *)handler->protocol_interface;
> >> >
> >> > ret = efi_disk_add_dev(parent, dp_parent, desc, diskid,
> >> > - info, part, &disk, agent_handle);
> >> > + info, part, &disk, agent_handle, dev);
> >> > if (ret != EFI_SUCCESS) {
> >> > log_err("Adding partition for %s failed\n", dev->name);
> >> > return -1;
> >> > }
> >> > - if (efi_link_dev(&disk->header, dev)) {
> >> > - efi_free_pool(disk->dp);
> >> > - efi_delete_handle(&disk->header);
> >> > -
> >> > - return -1;
> >> > - }
> >> >
> >> > return 0;
> >> > }
> >> > @@ -693,13 +690,34 @@ int efi_disk_probe(void *ctx, struct event *event)
> >> > return 0;
> >> > }
> >> >
> >> > +static void get_disk_resources(efi_handle_t handle, struct efi_device_path **dp,
> >> > + struct efi_block_io **blkio,
> >> > + struct efi_simple_file_system_protocol **volume)
> >> > +{
> >> > + efi_status_t ret;
> >> > + struct efi_handler *handler;
> >> > +
> >> > + ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
> >> > + if (ret == EFI_SUCCESS)
> >> > + *dp = handler->protocol_interface;
> >> > +
> >> > + ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> >> > + if (ret == EFI_SUCCESS)
> >> > + *blkio = handler->protocol_interface;
> >> > +
> >> > + ret = efi_search_protocol(handle, &efi_simple_file_system_protocol_guid,
> >> > + &handler);
> >> > + if (ret == EFI_SUCCESS)
> >> > + *volume = handler->protocol_interface;
> >> > +}
> >> > +
> >> > /**
> >> > - * efi_disk_remove - delete an efi_disk object for a block device or partition
> >> > + * efi_disk_remove - delete an efi handle for a block device or partition
> >> > *
> >> > * @ctx: event context: driver binding protocol
> >> > * @event: EV_PM_PRE_REMOVE event
> >> > *
> >> > - * Delete an efi_disk object which is associated with the UCLASS_BLK or
> >> > + * Delete an efi handle which is associated with the UCLASS_BLK or
> >> > * UCLASS_PARTITION device for which the EV_PM_PRE_REMOVE event is raised.
> >> > *
> >> > * Return: 0 on success, -1 otherwise
> >> > @@ -710,8 +728,10 @@ int efi_disk_remove(void *ctx, struct event *event)
> >> > struct udevice *dev = event->data.dm.dev;
> >> > efi_handle_t handle;
> >> > struct blk_desc *desc;
> >> > - struct efi_disk_obj *diskobj = NULL;
> >> > efi_status_t ret;
> >> > + struct efi_device_path *dp = NULL;
> >> > + struct efi_block_io *blkio = NULL;
> >> > + struct efi_simple_file_system_protocol *volume = NULL;
> >> >
> >> > if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
> >> > return 0;
> >> > @@ -721,11 +741,11 @@ int efi_disk_remove(void *ctx, struct event *event)
> >> > case UCLASS_BLK:
> >> > desc = dev_get_uclass_plat(dev);
> >> > if (desc && desc->uclass_id != UCLASS_EFI_LOADER)
> >> > - diskobj = container_of(handle, struct efi_disk_obj,
> >> > - header);
> >> > + get_disk_resources(handle, &dp, &blkio, &volume);
> >> > +
> >> > break;
> >> > case UCLASS_PARTITION:
> >> > - diskobj = container_of(handle, struct efi_disk_obj, header);
> >> > + get_disk_resources(handle, &dp, &blkio, &volume);
> >> > break;
> >> > default:
> >> > return 0;
> >> > @@ -736,8 +756,11 @@ int efi_disk_remove(void *ctx, struct event *event)
> >> > if (ret != EFI_SUCCESS)
> >> > return -1;
> >> >
> >> > - if (diskobj)
> >> > - efi_free_pool(diskobj->dp);
> >> > + efi_free_pool(dp);
> >> > + if (blkio) {
> >> > + free(blkio->media);
> >> > + free(blkio);
> >> > + }
> >> >
> >> > dev_tag_del(dev, DM_TAG_EFI);
> >> >
> >>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] efi_loader: eliminate efi_disk_obj structure
2023-12-14 8:23 ` Masahisa Kojima
@ 2023-12-17 10:26 ` Heinrich Schuchardt
2023-12-18 8:33 ` Masahisa Kojima
0 siblings, 1 reply; 9+ messages in thread
From: Heinrich Schuchardt @ 2023-12-17 10:26 UTC (permalink / raw)
To: Masahisa Kojima; +Cc: Ilias Apalodimas, u-boot, AKASHI Takahiro
On 12/14/23 09:23, Masahisa Kojima wrote:
>>>> Depending on the number of handles and pointers this will take a
>>>> considerable time. A private field for the handle appended to struct
>>>> efi_block_io would allow a fast lookup.
>>>>
>>>> EDK II does the same. See the definition of RAM_DISK_PRIVATE_FROM_BLKIO
>>>> which uses macro BASE_CR() to find the private fields.
>>> This patch tries to address this issue[0].
>>>
>>> If I understand correctly, two options are suggested here.
>>> 1) a private field for the handle appended to struct efi_block_io
>>> 2) keep the private struct something like current struct
>>> efi_disk_obj, same as EDK II does
>> Edk II uses 1) as I indicated above.
> Probably I misunderstand your suggestion, let me clarify again.
>
> EDK II RamDisk implementation defines the private structure
> RAM_DISK_PRIVATE_DATA[1].
> RAM_DISK_PRIVATE_FROM_BLKIO macro returns the pointer to the
> RAM_DISK_PRIVATE_DATA structure from the BLKIO protocol interface.
> EFI_BLOCK_IO_PROTOCOL does not have a private field.
>
> It is the same as the current U-Boot implementation of efi_disk.c using
> struct efi_disk_obj and following code.
> diskobj = container_of(this, struct efi_disk_obj, ops);
>
> Do you suggest modifying struct efi_block_io to add private fields?
efi_block_io currently is what is defined in the UEFI specification.
We could define a new structure that includes efi_block_io and
additional private fields:
struct efi_block_io_plus_private {
struct efi_block_io block_io;
efi_handle_t handle;
}
Or we can change the definition of efi_block_io by adding private fields:
struct efi_block_io {
u64 revision;
struct efi_block_io_media *media;
...
efi_status_t (EFIAPI *flush_blocks)(struct efi_block_io *this);
# U-Boot private fields start here
efi_handle_t handle;
};
In either case we must not try to access the private fields if the
structure is not allocated by us.
The second option will require less code changes.
I would try to avoid using container_of() for accessing private fields
as it static code analysis and reading the code more difficult.
Best regards
Heinrich
>
> [1]https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h#L95
>
> Thanks,
> Masahisa Kojima
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] efi_loader: eliminate efi_disk_obj structure
2023-12-17 10:26 ` Heinrich Schuchardt
@ 2023-12-18 8:33 ` Masahisa Kojima
0 siblings, 0 replies; 9+ messages in thread
From: Masahisa Kojima @ 2023-12-18 8:33 UTC (permalink / raw)
To: Heinrich Schuchardt; +Cc: Ilias Apalodimas, u-boot, AKASHI Takahiro
Hi Heinrich,
On Sun, 17 Dec 2023 at 19:26, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>
> On 12/14/23 09:23, Masahisa Kojima wrote:
> >>>> Depending on the number of handles and pointers this will take a
> >>>> considerable time. A private field for the handle appended to struct
> >>>> efi_block_io would allow a fast lookup.
> >>>>
> >>>> EDK II does the same. See the definition of RAM_DISK_PRIVATE_FROM_BLKIO
> >>>> which uses macro BASE_CR() to find the private fields.
> >>> This patch tries to address this issue[0].
> >>>
> >>> If I understand correctly, two options are suggested here.
> >>> 1) a private field for the handle appended to struct efi_block_io
> >>> 2) keep the private struct something like current struct
> >>> efi_disk_obj, same as EDK II does
> >> Edk II uses 1) as I indicated above.
> > Probably I misunderstand your suggestion, let me clarify again.
> >
> > EDK II RamDisk implementation defines the private structure
> > RAM_DISK_PRIVATE_DATA[1].
> > RAM_DISK_PRIVATE_FROM_BLKIO macro returns the pointer to the
> > RAM_DISK_PRIVATE_DATA structure from the BLKIO protocol interface.
> > EFI_BLOCK_IO_PROTOCOL does not have a private field.
> >
> > It is the same as the current U-Boot implementation of efi_disk.c using
> > struct efi_disk_obj and following code.
> > diskobj = container_of(this, struct efi_disk_obj, ops);
> >
> > Do you suggest modifying struct efi_block_io to add private fields?
>
> efi_block_io currently is what is defined in the UEFI specification.
>
> We could define a new structure that includes efi_block_io and
> additional private fields:
>
> struct efi_block_io_plus_private {
> struct efi_block_io block_io;
> efi_handle_t handle;
> }
>
> Or we can change the definition of efi_block_io by adding private fields:
>
> struct efi_block_io {
> u64 revision;
> struct efi_block_io_media *media;
> ...
> efi_status_t (EFIAPI *flush_blocks)(struct efi_block_io *this);
> # U-Boot private fields start here
> efi_handle_t handle;
> };
>
> In either case we must not try to access the private fields if the
> structure is not allocated by us.
>
> The second option will require less code changes.
>
> I would try to avoid using container_of() for accessing private fields
> as it static code analysis and reading the code more difficult.
Thank you for the detailed explanation.
Avoiding container_of() means using cast instead?
Probably we define the following struct, cast the pointer of struct efi_block_io
to struct efi_block_io_plus_private pointer and check the signature before use.
struct efi_block_io_plus_private {
struct efi_block_io block_io;
u32 signature;
efi_handle_t handle;
}
I still hesitate to modify struct efi_block_io.
Thanks,
Masahisa Kojima
>
> Best regards
>
> Heinrich
>
> >
> > [1]https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h#L95
> >
> > Thanks,
> > Masahisa Kojima
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2023-12-18 8:33 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-13 8:57 [PATCH] efi_loader: eliminate efi_disk_obj structure Masahisa Kojima
2023-12-13 14:22 ` Heinrich Schuchardt
2023-12-13 19:50 ` Simon Glass
2023-12-14 1:55 ` Masahisa Kojima
2023-12-14 7:31 ` Heinrich Schuchardt
2023-12-14 8:23 ` Masahisa Kojima
2023-12-17 10:26 ` Heinrich Schuchardt
2023-12-18 8:33 ` Masahisa Kojima
2023-12-14 1:24 ` AKASHI Takahiro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox