[PATCH] EFI: Fix ReadBlocks API reading incorrect sector for, UCLASS_PARTITION devices

AKASHI Takahiro takahiro.akashi at linaro.org
Wed Jun 29 06:43:16 CEST 2022


Hi Paul,

On Tue, Jun 28, 2022 at 09:02:47PM -0400, Paul Barbieri wrote:
> From 7a7dd7f16352fc916279cca05a3fa617f8bbef64 Mon Sep 17 00:00:00 2001
> From: Paul Barbieri <plb365 at gmail.com>
> Date: Tue, 28 Jun 2022 20:24:33 -0400
> Subject: [PATCH] EFI: Fix ReadBlocks API reading incorrect sector for
> UCLASS_PARTITION devices
> 
> The requested partition disk sector incorrectly has the partition start
> sector added in twice for UCLASS_PARTITION devices. The efi_disk_rw_blocks()
> routine adds the diskobj->offset to the requested lba. When the device
> is a UCLASS_PARTITION, the dev_read() or dev_write() routine is called
> which adds part-gpt_part_info.start. This causes I/O to the wrong sector.
> 
> Takahiro Akashi suggested removing the offset field from the efi_disk_obj
> structure since disk-uclass.c handles the partition start biasing. Device
> types other than UCLASS_PARTITION set the diskobj->offset field to zero
> which makes the field unnecessary. This change removes the offset field
> from the structure and removes all references from the code which is
> isolated to the lib/efi_loader/efi_disk.c module.

Your change on efi_disk.c looks good, but

> This change also adds a test for the EFI ReadBlocks() API in the EFI
> selftest code. There is already a test for reading a FAT file. The new
> test uses ReadBlocks() to read the same "disk" block and compare it to
> the data read from the file system API.

Your test will never exercise the code you added in efi_disk.c
(or efi_disk_rw_blocks()) because "block device" selftest uses
its own block device driver.

-Takahiro Akashi

> Signed-Off-by: Paul Barbieri <paul.barbieri at verizon.net>
> Cc: Heinrich Schuchardt <xypron.glpk at gmx.de>
> Cc: AKASHI Takahiro <takahiro.akashi at linaro.org>
> ---
>  lib/efi_loader/efi_disk.c                    |  8 +-------
>  lib/efi_selftest/efi_selftest_block_device.c | 19 +++++++++++++++++++
>  2 files changed, 20 insertions(+), 7 deletions(-)
> 
> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> index 1e82f52dc0..1d700b2a6b 100644
> --- a/lib/efi_loader/efi_disk.c
> +++ b/lib/efi_loader/efi_disk.c
> @@ -35,7 +35,6 @@ const efi_guid_t efi_system_partition_guid =
> PARTITION_SYSTEM_GUID;
>   * @dp:                device path to the block device
>   * @part:      partition
>   * @volume:    simple file system protocol of the partition
> - * @offset:    offset into disk for simple partition
>   * @dev:       associated DM device
>   */
>  struct efi_disk_obj {
> @@ -47,7 +46,6 @@ struct efi_disk_obj {
>         struct efi_device_path *dp;
>         unsigned int part;
>         struct efi_simple_file_system_protocol *volume;
> -       lbaint_t offset;
>         struct udevice *dev; /* TODO: move it to efi_object */
>  };
> 
> @@ -117,7 +115,6 @@ static efi_status_t efi_disk_rw_blocks(struct
> efi_block_io *this,
>         diskobj = container_of(this, struct efi_disk_obj, ops);
>         blksz = diskobj->media.block_size;
>         blocks = buffer_size / blksz;
> -       lba += diskobj->offset;
> 
>         EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
>                   blocks, lba, blksz, direction);
> @@ -440,13 +437,11 @@ static efi_status_t efi_disk_add_dev(
> 
>                 diskobj->dp = efi_dp_append_node(dp_parent, node);
>                 efi_free_pool(node);
> -               diskobj->offset = part_info->start;
>                 diskobj->media.last_block = part_info->size - 1;
>                 if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
>                         guid = &efi_system_partition_guid;
>         } else {
>                 diskobj->dp = efi_dp_from_part(desc, part);
> -               diskobj->offset = 0;
>                 diskobj->media.last_block = desc->lba - 1;
>         }
>         diskobj->part = part;
> @@ -501,12 +496,11 @@ static efi_status_t efi_disk_add_dev(
>                 *disk = diskobj;
> 
>         EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
> -                 ", offset " LBAF ", last_block %llu\n",
> +                 ", last_block %llu\n",
>                   diskobj->part,
>                   diskobj->media.media_present,
>                   diskobj->media.logical_partition,
>                   diskobj->media.removable_media,
> -                 diskobj->offset,
>                   diskobj->media.last_block);
> 
>         /* Store first EFI system partition */
> diff --git a/lib/efi_selftest/efi_selftest_block_device.c
> b/lib/efi_selftest/efi_selftest_block_device.c
> index 60fa655766..ef6bdafe2e 100644
> --- a/lib/efi_selftest/efi_selftest_block_device.c
> +++ b/lib/efi_selftest/efi_selftest_block_device.c
> @@ -11,6 +11,7 @@
>   * ConnectController is used to setup partitions and to install the simple
>   * file protocol.
>   * A known file is read from the file system and verified.
> + * Test that the read_blocks API correctly reads a block from the device.
>   */
> 
>  #include <efi_selftest.h>
> @@ -312,6 +313,7 @@ static int execute(void)
>         char buf[16] __aligned(ARCH_DMA_MINALIGN);
>         u32 part1_size;
>         u64 pos;
> +       char block[512];
> 
>         /* Connect controller to virtual disk */
>         ret = boottime->connect_controller(disk_handle, NULL, NULL, 1);
> @@ -449,6 +451,23 @@ static int execute(void)
>                 return EFI_ST_FAILURE;
>         }
> 
> +       /* Test read_blocks() can read same file data. */
> +       boottime->set_mem(block, block_io_protocol->media->block_size, 0);
> +       ret = block_io_protocol->read_blocks(block_io_protocol,
> + block_io_protocol->media->media_id,
> +                                     (0x5000 >> LB_BLOCK_SIZE) - 1,
> + block_io_protocol->media->block_size,
> +                                     block);
> +       if (ret != EFI_SUCCESS) {
> +               efi_st_error("ReadBlocks failed\n");
> +               return EFI_ST_FAILURE;
> +       }
> +
> +       if (memcmp(&block[1], buf, 11)) {
> +               efi_st_error("Unexpected block content\n");
> +               return EFI_ST_FAILURE;
> +       }
> +
>  #ifdef CONFIG_FAT_WRITE
>         /* Write file */
>         ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ |
> -- 
> 2.17.1
> 


More information about the U-Boot mailing list