diff options
Diffstat (limited to 'lib/efi_loader/efi_disk.c')
-rw-r--r-- | lib/efi_loader/efi_disk.c | 121 |
1 files changed, 83 insertions, 38 deletions
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index aaff947596f..28e5b7fce59 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -27,6 +27,8 @@ struct efi_disk_obj { struct efi_block_io_media media; /* EFI device path to this block device */ struct efi_device_path_file_path *dp; + /* Offset into disk for simple partitions */ + lbaint_t offset; }; static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol, @@ -81,6 +83,7 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, return EFI_EXIT(EFI_DEVICE_ERROR); blksz = desc->blksz; blocks = buffer_size / blksz; + lba += diskobj->offset; #ifdef DEBUG_EFI printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__, @@ -138,6 +141,78 @@ static const struct efi_block_io block_io_disk_template = { .flush_blocks = &efi_disk_flush_blocks, }; +static void efi_disk_add_dev(char *name, + const struct block_drvr *cur_drvr, + const struct blk_desc *desc, + int dev_index, + lbaint_t offset) +{ + struct efi_disk_obj *diskobj; + struct efi_device_path_file_path *dp; + int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); + + diskobj = calloc(1, objlen); + + /* Fill in object data */ + diskobj->parent.protocols[0].guid = &efi_block_io_guid; + diskobj->parent.protocols[0].open = efi_disk_open_block; + diskobj->parent.protocols[1].guid = &efi_guid_device_path; + diskobj->parent.protocols[1].open = efi_disk_open_dp; + diskobj->parent.handle = diskobj; + diskobj->ops = block_io_disk_template; + diskobj->ifname = cur_drvr->name; + diskobj->dev_index = dev_index; + diskobj->offset = offset; + + /* Fill in EFI IO Media info (for read/write callbacks) */ + diskobj->media.removable_media = desc->removable; + diskobj->media.media_present = 1; + diskobj->media.block_size = desc->blksz; + diskobj->media.io_align = desc->blksz; + diskobj->media.last_block = desc->lba; + diskobj->ops.media = &diskobj->media; + + /* Fill in device path */ + dp = (void*)&diskobj[1]; + diskobj->dp = dp; + dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; + dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; + dp[0].dp.length = sizeof(*dp); + ascii2unicode(dp[0].str, name); + + dp[1].dp.type = DEVICE_PATH_TYPE_END; + dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END; + dp[1].dp.length = sizeof(*dp); + + /* Hook up to the device list */ + list_add_tail(&diskobj->parent.link, &efi_obj_list); +} + +static int efi_disk_create_eltorito(struct blk_desc *desc, + const struct block_drvr *cur_drvr, + int diskid) +{ + int disks = 0; +#ifdef CONFIG_ISO_PARTITION + char devname[32] = { 0 }; /* dp->str is u16[32] long */ + disk_partition_t info; + int part = 1; + + if (desc->part_type != PART_TYPE_ISO) + return 0; + + while (!part_get_info(desc, part, &info)) { + snprintf(devname, sizeof(devname), "%s%d:%d", cur_drvr->name, + diskid, part); + efi_disk_add_dev(devname, cur_drvr, desc, diskid, info.start); + part++; + disks++; + } +#endif + + return disks; +} + /* * U-Boot doesn't have a list of all online disk devices. So when running our * EFI payload, we scan through all of the potentially available ones and @@ -156,10 +231,7 @@ int efi_disk_register(void) printf("Scanning disks on %s...\n", cur_drvr->name); for (i = 0; i < 4; i++) { struct blk_desc *desc; - struct efi_disk_obj *diskobj; - struct efi_device_path_file_path *dp; - int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); - char devname[16] = { 0 }; /* dp->str is u16[16] long */ + char devname[32] = { 0 }; /* dp->str is u16[32] long */ desc = blk_get_dev(cur_drvr->name, i); if (!desc) @@ -167,43 +239,16 @@ int efi_disk_register(void) if (desc->type == DEV_TYPE_UNKNOWN) continue; - diskobj = calloc(1, objlen); - - /* Fill in object data */ - diskobj->parent.protocols[0].guid = &efi_block_io_guid; - diskobj->parent.protocols[0].open = efi_disk_open_block; - diskobj->parent.protocols[1].guid = &efi_guid_device_path; - diskobj->parent.protocols[1].open = efi_disk_open_dp; - diskobj->parent.handle = diskobj; - diskobj->ops = block_io_disk_template; - diskobj->ifname = cur_drvr->name; - diskobj->dev_index = i; - - /* Fill in EFI IO Media info (for read/write callbacks) */ - diskobj->media.removable_media = desc->removable; - diskobj->media.media_present = 1; - diskobj->media.block_size = desc->blksz; - diskobj->media.io_align = desc->blksz; - diskobj->media.last_block = desc->lba; - diskobj->ops.media = &diskobj->media; - - /* Fill in device path */ - dp = (void*)&diskobj[1]; - diskobj->dp = dp; - dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; - dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; - dp[0].dp.length = sizeof(*dp); snprintf(devname, sizeof(devname), "%s%d", cur_drvr->name, i); - ascii2unicode(dp[0].str, devname); - - dp[1].dp.type = DEVICE_PATH_TYPE_END; - dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END; - dp[1].dp.length = sizeof(*dp); - - /* Hook up to the device list */ - list_add_tail(&diskobj->parent.link, &efi_obj_list); + efi_disk_add_dev(devname, cur_drvr, desc, i, 0); disks++; + + /* + * El Torito images show up as block devices + * in an EFI world, so let's create them here + */ + disks += efi_disk_create_eltorito(desc, cur_drvr, i); } } printf("Found %d disks\n", disks); |