On 5/8/24 14:04, Dan Carpenter wrote:
On Wed, May 08, 2024 at 07:24:01PM +0800, Weizhao Ouyang wrote:
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index de0d49ebebda..919e3cba071b 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -922,6 +922,105 @@ static bool device_is_present_and_system_part(struct
efi_device_path *dp)
return true;
}
+/**
+ * get_esp_from_boot_option_file_path - get the expand device path
+ *
+ * Get a possible efi system partition by expanding a boot option
+ * file path.
+ *
+ * @boot_dev The device path pointing to a boot option
+ * Return: The full ESP device path or NULL if fail
+ */
+static struct efi_device_path *get_esp_from_boot_option_file_path(struct
efi_device_path *boot_dev)
+{
+ efi_status_t ret = EFI_SUCCESS;
+ efi_handle_t handle;
+ struct efi_device_path *dp = boot_dev;
+ struct efi_device_path *full_path = NULL;
+
+ ret =
EFI_CALL(efi_locate_device_path(&efi_simple_file_system_protocol_guid,
+ &dp,
+ &handle));
+ if (ret != EFI_SUCCESS)
+ ret = EFI_CALL(efi_locate_device_path(&efi_block_io_guid, &dp,
&handle));
+
+ /* Expand Media Device Path */
+ if (ret == EFI_SUCCESS && EFI_DP_TYPE(dp, END, END)) {
Flip this around. Always do failure handling. Never do success
handling. full_path is always NULL. Just return that. Delete
the variable.
if (ret != EFI_SUCCESS ||
!EFI_DP_TYPE(dp, END, END))
return NULL;
+ struct efi_device_path *temp_dp;
+ struct efi_block_io *block_io;
+ void *buffer;
+ efi_handle_t *simple_file_system_handle;
+ efi_uintn_t number_handles, index;
+ u32 size;
+ u32 temp_size;
+
+ temp_dp = boot_dev;
+ ret =
EFI_CALL(efi_locate_device_path(&efi_simple_file_system_protocol_guid,
+ &temp_dp,
+ &handle));
+ /*
+ * For device path pointing to simple file system, it only
expands to one
+ * full path
+ */
+ if (ret == EFI_SUCCESS && EFI_DP_TYPE(temp_dp, END, END)) {
"Always" was hyperbole. This success handling is fine.
+ if (device_is_present_and_system_part(temp_dp))
+ return temp_dp;
+ }
+
+ /*
+ * For device path only pointing to the removable device
handle, try to
+ * search all its children handles
+ */
+ ret = EFI_CALL(efi_locate_device_path(&efi_block_io_guid, &temp_dp,
&handle));
ret is not used. Delete.
Errors should be handled and not ignored.
+ EFI_CALL(efi_connect_controller(handle, NULL, NULL, true));
+
+ /* Align with edk2, issue a dummy read to the device to check
the device change */
+ ret = EFI_CALL(efi_handle_protocol(handle, &efi_block_io_guid,
(void **)&block_io));
+ if (ret == EFI_SUCCESS) {
if (ret != EFI_SUCCESS)
return NULL;
+ buffer = memalign(block_io->media->io_align,
block_io->media->block_size);
+ if (buffer) {
if (!buffer)
return NULL;
+ ret = EFI_CALL(block_io->read_blocks(block_io,
+
block_io->media->media_id,
+ 0,
+
block_io->media->block_size,
+ buffer));
Delete the unused "ret = " assignment.
ditto
Best regards
Heinrich
+ free(buffer);
+ } else {
+ return full_path;
+ }
+ } else {
+ return full_path;
+ }
+
+ /* detect the default boot file from removable media */
+ size = efi_dp_size(boot_dev) - sizeof(struct efi_device_path);
+ EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
+
&efi_simple_file_system_protocol_guid,
+ NULL,
+ &number_handles,
+ &simple_file_system_handle));
+ for (index = 0; index < number_handles; index++) {
+
EFI_CALL(efi_handle_protocol(simple_file_system_handle[index],
+ &efi_guid_device_path,
+ (void **)&temp_dp));
+
+ log_debug("Search ESP %pD\n", temp_dp);
+ temp_size = efi_dp_size(temp_dp) - sizeof(struct
efi_device_path);
+ if (size <= temp_size && !memcmp(temp_dp, boot_dev,
size)) {
+ if (device_is_present_and_system_part(temp_dp))
{
You could combine these conditions:
if (size <= temp_size &&
memcmp(temp_dp, boot_dev, size) == 0 &&
device_is_present_and_system_part(temp_dp)) {
efi_free_pool(simple_file_system_handle);
return temp_dp;
}
+
efi_free_pool(simple_file_system_handle);
+ return temp_dp;
+ }
+ }
+ }
+
+ if (simple_file_system_handle)
+ efi_free_pool(simple_file_system_handle);
+ }
+
+ return full_path;
+}
+
/**
* find_boot_device - identify the boot device
*
@@ -938,6 +1037,7 @@ static efi_status_t find_boot_device(void)
int i, num;
struct efi_simple_file_system_protocol *volume;
struct efi_device_path *boot_dev = NULL;
+ struct efi_device_path *full_path = NULL;
No need to initialize this to NULL, it disables static checker warnings
for uninitialized variables so it can lead to bugs.
efi_status_t ret;
/* find active boot device in BootNext */
@@ -961,8 +1061,14 @@ static efi_status_t find_boot_device(void)
if (device_is_present_and_system_part(boot_dev)) {
goto found;
} else {
- efi_free_pool(boot_dev);
- boot_dev = NULL;
+ full_path =
get_esp_from_boot_option_file_path(boot_dev);
+ if (full_path) {
+ boot_dev = full_path;
Later, we free full_path but do we ever free the original boot_dev?
+ goto found;
+ } else {
+ efi_free_pool(boot_dev);
+ boot_dev = NULL;
+ }
Better to delete indenting where you can:
full_path =
get_esp_from_boot_option_file_path(boot_dev);
if (full_path) {
boot_dev = full_path;
goto found;
}
efi_free_pool(boot_dev);
boot_dev = NULL;
regards,
dan carpenter