efi_loader: correct EFI_BLOCK_IO_PROTOCOL.Media.LastBlock
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Sat, 23 Jan 2021 05:52:21 +0000 (06:52 +0100)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Sat, 23 Jan 2021 06:56:54 +0000 (07:56 +0100)
The field Media.LastBlock of the EFI_BLOCK_IO_PROTOCOL.Media was filled
incorrectly both for block devices as well as for partitions.

The field must be filled with the index of the last logical block (LBA):

* block devices: device size minus 1
* partitions: partition size minus 1

Reported-by: Alexander von Gluck IV <kallisti5@unixzen.com>
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
lib/efi_loader/efi_disk.c

index 26b9534..c0804ef 100644 (file)
@@ -343,7 +343,7 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
  * @if_typename:       interface name for block device
  * @desc:              internal block device
  * @dev_index:         device index for block device
- * @offset:            offset into disk for simple partitions
+ * @part_info:         partition info
  * @part:              partition
  * @disk:              pointer to receive the created handle
  * Return:             disk object
@@ -354,7 +354,7 @@ static efi_status_t efi_disk_add_dev(
                                const char *if_typename,
                                struct blk_desc *desc,
                                int dev_index,
-                               lbaint_t offset,
+                               struct disk_partition *part_info,
                                unsigned int part,
                                struct efi_disk_obj **disk)
 {
@@ -374,7 +374,7 @@ static efi_status_t efi_disk_add_dev(
        efi_add_handle(&diskobj->header);
 
        /* Fill in object data */
-       if (part) {
+       if (part_info) {
                struct efi_device_path *node = efi_dp_part_node(desc, part);
                struct efi_handler *handler;
                void *protocol_interface;
@@ -396,8 +396,12 @@ 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;
        } else {
                diskobj->dp = efi_dp_from_part(desc, part);
+               diskobj->offset = 0;
+               diskobj->media.last_block = desc->lba - 1;
        }
        diskobj->part = part;
 
@@ -432,7 +436,6 @@ static efi_status_t efi_disk_add_dev(
        diskobj->ops = block_io_disk_template;
        diskobj->ifname = if_typename;
        diskobj->dev_index = dev_index;
-       diskobj->offset = offset;
        diskobj->desc = desc;
 
        /* Fill in EFI IO Media info (for read/write callbacks) */
@@ -445,13 +448,21 @@ static efi_status_t efi_disk_add_dev(
        diskobj->media.media_id = 1;
        diskobj->media.block_size = desc->blksz;
        diskobj->media.io_align = desc->blksz;
-       diskobj->media.last_block = desc->lba - offset;
        if (part)
                diskobj->media.logical_partition = 1;
        diskobj->ops.media = &diskobj->media;
        if (disk)
                *disk = diskobj;
 
+       EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
+                 ", offset " LBAF ", 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 */
        if (part && !efi_system_partition.if_type) {
                int r;
@@ -493,7 +504,6 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
 {
        int disks = 0;
        char devname[32] = { 0 }; /* dp->str is u16[32] long */
-       struct disk_partition info;
        int part;
        struct efi_device_path *dp = NULL;
        efi_status_t ret;
@@ -506,12 +516,14 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
 
        /* Add devices for each partition */
        for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+               struct disk_partition info;
+
                if (part_get_info(desc, part, &info))
                        continue;
                snprintf(devname, sizeof(devname), "%s:%d", pdevname,
                         part);
                ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid,
-                                      info.start, part, NULL);
+                                      &info, part, NULL);
                if (ret != EFI_SUCCESS) {
                        log_err("Adding partition %s failed\n", pdevname);
                        continue;
@@ -553,7 +565,7 @@ efi_status_t efi_disk_register(void)
                /* Add block device for the full device */
                log_info("Scanning disk %s...\n", dev->name);
                ret = efi_disk_add_dev(NULL, NULL, if_typename,
-                                       desc, desc->devnum, 0, 0, &disk);
+                                       desc, desc->devnum, NULL, 0, &disk);
                if (ret == EFI_NOT_READY) {
                        log_notice("Disk %s not ready\n", dev->name);
                        continue;
@@ -599,7 +611,7 @@ efi_status_t efi_disk_register(void)
 
                        /* Add block device for the full device */
                        ret = efi_disk_add_dev(NULL, NULL, if_typename, desc,
-                                              i, 0, 0, &disk);
+                                              i, NULL, 0, &disk);
                        if (ret == EFI_NOT_READY) {
                                log_notice("Disk %s not ready\n", devname);
                                continue;