Currently, efi_init_obj_list() scan disk devices only once, and never change a list of efi disk devices. This will possibly result in failing to find a removable storage which may be added later on. See [1].
In this patch, called is efi_disk_update() which is responsible for re-scanning UCLASS_BLK devices and removing/adding efi disks if necessary. For example, => efishell devices Scanning disk pci_mmc.blk... Found 3 disks Device Name ============================================ /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/HD(2,MBR,0x086246ba,0x40800,0x3f800) => usb start starting USB... USB0: USB EHCI 1.00 scanning bus 0 for devices... 3 USB Device(s) found scanning usb for storage devices... 1 Storage Device(s) found => efishell devices Scanning disk usb_mass_storage.lun0... Device Name ============================================ /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/SD(0)/SD(0)/HD(2,MBR,0x086246ba,0x40800,0x3f800) /VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b)/USBClass(0,0,9,0,1)/USBClass(46f4,1,0,0,0)/HD(1,0x01,0,0x40,0x14fe4c) Without this patch, the last device, USB mass storage, won't show up. [1] https://lists.denx.de/pipermail/u-boot/2018-October/345307.html Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org> --- cmd/bootefi.c | 17 +++- include/efi_loader.h | 4 + lib/efi_loader/efi_disk.c | 191 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 2 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 3cefb4d0ecaa..82649e211fda 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -56,9 +56,22 @@ efi_status_t efi_init_obj_list(void) */ efi_save_gd(); - /* Initialize once only */ - if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) + if (efi_obj_list_initialized == EFI_SUCCESS) { +#ifdef CONFIG_PARTITIONS + ret = efi_disk_update(); + if (ret != EFI_SUCCESS) + printf("+++ updating disks list failed\n"); + + /* + * It may sound odd, but most part of EFI should + * yet work. + */ +#endif return efi_obj_list_initialized; + } else if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) { + /* Initialize once only */ + return efi_obj_list_initialized; + } /* Initialize system table */ ret = efi_initialize_system_table(); diff --git a/include/efi_loader.h b/include/efi_loader.h index 5cc3bded03fa..3bae1844befb 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -260,6 +260,10 @@ efi_status_t efi_initialize_system_table(void); efi_status_t efi_console_register(void); /* Called by bootefi to make all disk storage accessible as EFI objects */ efi_status_t efi_disk_register(void); +/* Check validity of efi disk */ +bool efi_disk_is_valid(efi_handle_t handle); +/* Called by bootefi to find and update disk storage information */ +efi_status_t efi_disk_update(void); /* Create handles and protocols for the partitions of a block device */ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc, const char *if_typename, int diskid, diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index c037526ad2d0..0c4d79ee3fc9 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -14,10 +14,14 @@ const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID; +#define _EFI_DISK_FLAG_DELETED 0x1 /* to be removed */ +#define _EFI_DISK_FLAG_INVALID 0x80000000 /* in stale state */ + /** * struct efi_disk_obj - EFI disk object * * @header: EFI object header + * @flags: control flags * @ops: EFI disk I/O protocol interface * @ifname: interface name for block device * @dev_index: device index of block device @@ -30,6 +34,7 @@ const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID; */ struct efi_disk_obj { struct efi_object header; + int flags; struct efi_block_io ops; const char *ifname; int dev_index; @@ -41,6 +46,35 @@ struct efi_disk_obj { struct blk_desc *desc; }; +static void efi_disk_mark_deleted(struct efi_disk_obj *disk) +{ + disk->flags |= _EFI_DISK_FLAG_DELETED; +} + +static void efi_disk_clear_deleted(struct efi_disk_obj *disk) +{ + disk->flags &= ~_EFI_DISK_FLAG_DELETED; +} + +static bool efi_disk_deleted_marked(struct efi_disk_obj *disk) +{ + return disk->flags & _EFI_DISK_FLAG_DELETED; +} + +static void efi_disk_mark_invalid(struct efi_disk_obj *disk) +{ + disk->flags |= _EFI_DISK_FLAG_INVALID; +} + +bool efi_disk_is_valid(efi_handle_t handle) +{ + struct efi_disk_obj *disk; + + disk = container_of(handle, struct efi_disk_obj, header); + + return !(disk->flags & _EFI_DISK_FLAG_INVALID); +} + static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, char extended_verification) { @@ -64,6 +98,9 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this, unsigned long n; diskobj = container_of(this, struct efi_disk_obj, ops); + if (diskobj->flags & _EFI_DISK_FLAG_INVALID) + return EFI_DEVICE_ERROR; + desc = (struct blk_desc *) diskobj->desc; blksz = desc->blksz; blocks = buffer_size / blksz; @@ -440,3 +477,157 @@ efi_status_t efi_disk_register(void) return EFI_SUCCESS; } + +/* + * Mark all the block devices as "deleted," and return an array of + * handles for later use. It should be freed in a caller. + */ +static efi_status_t efi_disk_mark_deleted_all(efi_handle_t **handlesp) +{ + efi_handle_t *handles = NULL; + efi_uintn_t size = 0; + int num, i; + struct efi_disk_obj *disk; + efi_status_t ret; + + ret = efi_locate_handle(BY_PROTOCOL, &efi_block_io_guid, NULL, + &size, handles); + if (ret == EFI_BUFFER_TOO_SMALL) { + handles = calloc(1, size); + if (!handles) + return EFI_OUT_OF_RESOURCES; + + ret = efi_locate_handle(BY_PROTOCOL, &efi_block_io_guid, NULL, + &size, handles); + } + if (ret != EFI_SUCCESS) { + free(handles); + return ret; + } + + num = size / sizeof(*handles); + for (i = 0; i < num; i++) { + disk = container_of(handles[i], struct efi_disk_obj, header); + efi_disk_mark_deleted(disk); + } + + *handlesp = handles; + + return num; +} + +/* + * Clear "deleted" flag for a block device which is identified with desc. + * If desc is NULL, clear all devices. + * + * Return a number of disks cleared. + */ +static int efi_disk_clear_deleted_matched(struct blk_desc *desc, + efi_handle_t *handles, int num) +{ + struct efi_disk_obj *disk; + int disks, i; + + for (i = 0, disks = 0; i < num; i++) { + disk = container_of(handles[i], struct efi_disk_obj, header); + + if (!desc || disk->desc == desc) { + efi_disk_clear_deleted(disk); + disks++; + } + } + + return disks; +} + +/* + * Do delete all the block devices marked as "deleted" + */ +static efi_status_t efi_disk_do_delete(efi_handle_t *handles, int num) +{ + struct efi_disk_obj *disk; + int i; + + for (i = 0; i < num; i++) { + disk = container_of(handles[i], struct efi_disk_obj, header); + + if (!efi_disk_deleted_marked(disk)) + continue; + + efi_disk_mark_invalid(disk); + /* + * TODO: + * efi_delete_handle(handles[i]); + */ + } + + return EFI_SUCCESS; +} + +/* + * efi_disk_update - recreate efi disk mappings after initialization + * + * @return efi error code + */ +efi_status_t efi_disk_update(void) +{ +#ifdef CONFIG_BLK + efi_handle_t *handles = NULL; + struct udevice *dev; + struct blk_desc *desc; + const char *if_typename; + struct efi_disk_obj *disk; + int n, disks = 0; + efi_status_t ret; + + /* temporarily mark all the devices "deleted" */ + ret = efi_disk_mark_deleted_all(&handles); + if (ret & EFI_ERROR_MASK) { + printf("ERROR: Failed to rescan block devices.\n"); + return ret; + } + + n = (int)ret; + for (uclass_first_device_check(UCLASS_BLK, &dev); dev; + uclass_next_device_check(&dev)) { + desc = dev_get_uclass_platdata(dev); + if (n && efi_disk_clear_deleted_matched(desc, handles, n)) + /* existing device */ + continue; + + /* new device */ + if_typename = blk_get_if_type_name(desc->if_type); + + /* Add block device for the full device */ + printf("Scanning disk %s...\n", dev->name); + ret = efi_disk_add_dev(NULL, NULL, if_typename, + desc, desc->devnum, 0, 0, &disk); + if (ret == EFI_NOT_READY) { + printf("Disk %s not ready\n", dev->name); + continue; + } + if (ret != EFI_SUCCESS) { + printf("ERROR: failure to add disk device %s, r = %lu\n", + dev->name, ret & ~EFI_ERROR_MASK); + continue; + } + disks++; + + /* Partitions show up as block devices in EFI */ + disks += efi_disk_create_partitions(&disk->header, desc, + if_typename, + desc->devnum, dev->name); + } + + if (n) { + /* do delete "deleted" disks */ + ret = efi_disk_do_delete(handles, n); + + /* undo marking */ + efi_disk_clear_deleted_matched(NULL, handles, n); + + free(handles); + } +#endif + return EFI_SUCCESS; +} -- 2.19.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot