12a22d05dSAlexander Graf /* 22a22d05dSAlexander Graf * EFI application disk support 32a22d05dSAlexander Graf * 42a22d05dSAlexander Graf * Copyright (c) 2016 Alexander Graf 52a22d05dSAlexander Graf * 62a22d05dSAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 72a22d05dSAlexander Graf */ 82a22d05dSAlexander Graf 92a22d05dSAlexander Graf #include <common.h> 106dd9faf8SSimon Glass #include <blk.h> 112a22d05dSAlexander Graf #include <efi_loader.h> 122a22d05dSAlexander Graf #include <inttypes.h> 132a22d05dSAlexander Graf #include <part.h> 142a22d05dSAlexander Graf #include <malloc.h> 152a22d05dSAlexander Graf 162a22d05dSAlexander Graf static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID; 172a22d05dSAlexander Graf 182a22d05dSAlexander Graf struct efi_disk_obj { 192a22d05dSAlexander Graf /* Generic EFI object parent class data */ 202a22d05dSAlexander Graf struct efi_object parent; 212a22d05dSAlexander Graf /* EFI Interface callback struct for block I/O */ 222a22d05dSAlexander Graf struct efi_block_io ops; 232a22d05dSAlexander Graf /* U-Boot ifname for block device */ 242a22d05dSAlexander Graf const char *ifname; 252a22d05dSAlexander Graf /* U-Boot dev_index for block device */ 262a22d05dSAlexander Graf int dev_index; 272a22d05dSAlexander Graf /* EFI Interface Media descriptor struct, referenced by ops */ 282a22d05dSAlexander Graf struct efi_block_io_media media; 292a22d05dSAlexander Graf /* EFI device path to this block device */ 302a22d05dSAlexander Graf struct efi_device_path_file_path *dp; 318c3df0bfSAlexander Graf /* Offset into disk for simple partitions */ 328c3df0bfSAlexander Graf lbaint_t offset; 332a22d05dSAlexander Graf }; 342a22d05dSAlexander Graf 352a22d05dSAlexander Graf static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol, 362a22d05dSAlexander Graf void **protocol_interface, void *agent_handle, 372a22d05dSAlexander Graf void *controller_handle, uint32_t attributes) 382a22d05dSAlexander Graf { 392a22d05dSAlexander Graf struct efi_disk_obj *diskobj = handle; 402a22d05dSAlexander Graf 412a22d05dSAlexander Graf *protocol_interface = &diskobj->ops; 422a22d05dSAlexander Graf 432a22d05dSAlexander Graf return EFI_SUCCESS; 442a22d05dSAlexander Graf } 452a22d05dSAlexander Graf 462a22d05dSAlexander Graf static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol, 472a22d05dSAlexander Graf void **protocol_interface, void *agent_handle, 482a22d05dSAlexander Graf void *controller_handle, uint32_t attributes) 492a22d05dSAlexander Graf { 502a22d05dSAlexander Graf struct efi_disk_obj *diskobj = handle; 512a22d05dSAlexander Graf 522a22d05dSAlexander Graf *protocol_interface = diskobj->dp; 532a22d05dSAlexander Graf 542a22d05dSAlexander Graf return EFI_SUCCESS; 552a22d05dSAlexander Graf } 562a22d05dSAlexander Graf 572a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, 582a22d05dSAlexander Graf char extended_verification) 592a22d05dSAlexander Graf { 602a22d05dSAlexander Graf EFI_ENTRY("%p, %x", this, extended_verification); 612a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 622a22d05dSAlexander Graf } 632a22d05dSAlexander Graf 642a22d05dSAlexander Graf enum efi_disk_direction { 652a22d05dSAlexander Graf EFI_DISK_READ, 662a22d05dSAlexander Graf EFI_DISK_WRITE, 672a22d05dSAlexander Graf }; 682a22d05dSAlexander Graf 692a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, 702a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 712a22d05dSAlexander Graf void *buffer, enum efi_disk_direction direction) 722a22d05dSAlexander Graf { 732a22d05dSAlexander Graf struct efi_disk_obj *diskobj; 742a22d05dSAlexander Graf struct blk_desc *desc; 752a22d05dSAlexander Graf int blksz; 762a22d05dSAlexander Graf int blocks; 772a22d05dSAlexander Graf unsigned long n; 782a22d05dSAlexander Graf 792a22d05dSAlexander Graf diskobj = container_of(this, struct efi_disk_obj, ops); 802a22d05dSAlexander Graf if (!(desc = blk_get_dev(diskobj->ifname, diskobj->dev_index))) 812a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 822a22d05dSAlexander Graf blksz = desc->blksz; 832a22d05dSAlexander Graf blocks = buffer_size / blksz; 848c3df0bfSAlexander Graf lba += diskobj->offset; 852a22d05dSAlexander Graf 862a22d05dSAlexander Graf #ifdef DEBUG_EFI 872a22d05dSAlexander Graf printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__, 882a22d05dSAlexander Graf __LINE__, blocks, lba, blksz, direction); 892a22d05dSAlexander Graf #endif 902a22d05dSAlexander Graf 912a22d05dSAlexander Graf /* We only support full block access */ 922a22d05dSAlexander Graf if (buffer_size & (blksz - 1)) 932a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 942a22d05dSAlexander Graf 95*51735ae0SAlexander Graf if (direction == EFI_DISK_READ) { 962a22d05dSAlexander Graf n = desc->block_read(desc, lba, blocks, buffer); 97*51735ae0SAlexander Graf } else { 982a22d05dSAlexander Graf n = desc->block_write(desc, lba, blocks, buffer); 99*51735ae0SAlexander Graf } 1002a22d05dSAlexander Graf 1012a22d05dSAlexander Graf /* We don't do interrupts, so check for timers cooperatively */ 1022a22d05dSAlexander Graf efi_timer_check(); 1032a22d05dSAlexander Graf 1042a22d05dSAlexander Graf #ifdef DEBUG_EFI 1052a22d05dSAlexander Graf printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); 1062a22d05dSAlexander Graf #endif 1072a22d05dSAlexander Graf if (n != blocks) 1082a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 1092a22d05dSAlexander Graf 1102a22d05dSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1112a22d05dSAlexander Graf } 1122a22d05dSAlexander Graf 1132a22d05dSAlexander Graf static efi_status_t efi_disk_read_blocks(struct efi_block_io *this, 1142a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 1152a22d05dSAlexander Graf void *buffer) 1162a22d05dSAlexander Graf { 117*51735ae0SAlexander Graf void *real_buffer = buffer; 118*51735ae0SAlexander Graf efi_status_t r; 119*51735ae0SAlexander Graf 120*51735ae0SAlexander Graf #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER 121*51735ae0SAlexander Graf if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { 122*51735ae0SAlexander Graf r = efi_disk_read_blocks(this, media_id, lba, 123*51735ae0SAlexander Graf EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer); 124*51735ae0SAlexander Graf if (r != EFI_SUCCESS) 125*51735ae0SAlexander Graf return r; 126*51735ae0SAlexander Graf return efi_disk_read_blocks(this, media_id, lba + 127*51735ae0SAlexander Graf EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size, 128*51735ae0SAlexander Graf buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE, 129*51735ae0SAlexander Graf buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE); 130*51735ae0SAlexander Graf } 131*51735ae0SAlexander Graf 132*51735ae0SAlexander Graf real_buffer = efi_bounce_buffer; 133*51735ae0SAlexander Graf #endif 134*51735ae0SAlexander Graf 135*51735ae0SAlexander Graf EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, 136*51735ae0SAlexander Graf buffer_size, buffer); 137*51735ae0SAlexander Graf 138*51735ae0SAlexander Graf r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer, 1392a22d05dSAlexander Graf EFI_DISK_READ); 140*51735ae0SAlexander Graf 141*51735ae0SAlexander Graf /* Copy from bounce buffer to real buffer if necessary */ 142*51735ae0SAlexander Graf if ((r == EFI_SUCCESS) && (real_buffer != buffer)) 143*51735ae0SAlexander Graf memcpy(buffer, real_buffer, buffer_size); 144*51735ae0SAlexander Graf 145*51735ae0SAlexander Graf return EFI_EXIT(r); 1462a22d05dSAlexander Graf } 1472a22d05dSAlexander Graf 1482a22d05dSAlexander Graf static efi_status_t efi_disk_write_blocks(struct efi_block_io *this, 1492a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 1502a22d05dSAlexander Graf void *buffer) 1512a22d05dSAlexander Graf { 152*51735ae0SAlexander Graf void *real_buffer = buffer; 153*51735ae0SAlexander Graf efi_status_t r; 154*51735ae0SAlexander Graf 155*51735ae0SAlexander Graf #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER 156*51735ae0SAlexander Graf if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { 157*51735ae0SAlexander Graf r = efi_disk_write_blocks(this, media_id, lba, 158*51735ae0SAlexander Graf EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer); 159*51735ae0SAlexander Graf if (r != EFI_SUCCESS) 160*51735ae0SAlexander Graf return r; 161*51735ae0SAlexander Graf return efi_disk_write_blocks(this, media_id, lba + 162*51735ae0SAlexander Graf EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size, 163*51735ae0SAlexander Graf buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE, 164*51735ae0SAlexander Graf buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE); 165*51735ae0SAlexander Graf } 166*51735ae0SAlexander Graf 167*51735ae0SAlexander Graf real_buffer = efi_bounce_buffer; 168*51735ae0SAlexander Graf #endif 169*51735ae0SAlexander Graf 170*51735ae0SAlexander Graf EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, 171*51735ae0SAlexander Graf buffer_size, buffer); 172*51735ae0SAlexander Graf 173*51735ae0SAlexander Graf /* Populate bounce buffer if necessary */ 174*51735ae0SAlexander Graf if (real_buffer != buffer) 175*51735ae0SAlexander Graf memcpy(real_buffer, buffer, buffer_size); 176*51735ae0SAlexander Graf 177*51735ae0SAlexander Graf r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer, 1782a22d05dSAlexander Graf EFI_DISK_WRITE); 179*51735ae0SAlexander Graf 180*51735ae0SAlexander Graf return EFI_EXIT(r); 1812a22d05dSAlexander Graf } 1822a22d05dSAlexander Graf 1832a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this) 1842a22d05dSAlexander Graf { 1852a22d05dSAlexander Graf /* We always write synchronously */ 1862a22d05dSAlexander Graf EFI_ENTRY("%p", this); 1872a22d05dSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1882a22d05dSAlexander Graf } 1892a22d05dSAlexander Graf 1902a22d05dSAlexander Graf static const struct efi_block_io block_io_disk_template = { 1912a22d05dSAlexander Graf .reset = &efi_disk_reset, 1922a22d05dSAlexander Graf .read_blocks = &efi_disk_read_blocks, 1932a22d05dSAlexander Graf .write_blocks = &efi_disk_write_blocks, 1942a22d05dSAlexander Graf .flush_blocks = &efi_disk_flush_blocks, 1952a22d05dSAlexander Graf }; 1962a22d05dSAlexander Graf 1974a12a97cSAlexander Graf static void efi_disk_add_dev(char *name, 1986dd9faf8SSimon Glass const struct blk_driver *cur_drvr, 1994a12a97cSAlexander Graf const struct blk_desc *desc, 2004a12a97cSAlexander Graf int dev_index, 2014a12a97cSAlexander Graf lbaint_t offset) 2024a12a97cSAlexander Graf { 2034a12a97cSAlexander Graf struct efi_disk_obj *diskobj; 2044a12a97cSAlexander Graf struct efi_device_path_file_path *dp; 2054a12a97cSAlexander Graf int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); 2064a12a97cSAlexander Graf 2074a12a97cSAlexander Graf diskobj = calloc(1, objlen); 2084a12a97cSAlexander Graf 2094a12a97cSAlexander Graf /* Fill in object data */ 2104a12a97cSAlexander Graf diskobj->parent.protocols[0].guid = &efi_block_io_guid; 2114a12a97cSAlexander Graf diskobj->parent.protocols[0].open = efi_disk_open_block; 2124a12a97cSAlexander Graf diskobj->parent.protocols[1].guid = &efi_guid_device_path; 2134a12a97cSAlexander Graf diskobj->parent.protocols[1].open = efi_disk_open_dp; 2144a12a97cSAlexander Graf diskobj->parent.handle = diskobj; 2154a12a97cSAlexander Graf diskobj->ops = block_io_disk_template; 2166dd9faf8SSimon Glass diskobj->ifname = cur_drvr->if_typename; 2174a12a97cSAlexander Graf diskobj->dev_index = dev_index; 2188c3df0bfSAlexander Graf diskobj->offset = offset; 2194a12a97cSAlexander Graf 2204a12a97cSAlexander Graf /* Fill in EFI IO Media info (for read/write callbacks) */ 2214a12a97cSAlexander Graf diskobj->media.removable_media = desc->removable; 2224a12a97cSAlexander Graf diskobj->media.media_present = 1; 2234a12a97cSAlexander Graf diskobj->media.block_size = desc->blksz; 2244a12a97cSAlexander Graf diskobj->media.io_align = desc->blksz; 2254a12a97cSAlexander Graf diskobj->media.last_block = desc->lba; 2264a12a97cSAlexander Graf diskobj->ops.media = &diskobj->media; 2274a12a97cSAlexander Graf 2284a12a97cSAlexander Graf /* Fill in device path */ 2294a12a97cSAlexander Graf dp = (void*)&diskobj[1]; 2304a12a97cSAlexander Graf diskobj->dp = dp; 2314a12a97cSAlexander Graf dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; 2324a12a97cSAlexander Graf dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; 2334a12a97cSAlexander Graf dp[0].dp.length = sizeof(*dp); 2344a12a97cSAlexander Graf ascii2unicode(dp[0].str, name); 2354a12a97cSAlexander Graf 2364a12a97cSAlexander Graf dp[1].dp.type = DEVICE_PATH_TYPE_END; 2374a12a97cSAlexander Graf dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END; 2384a12a97cSAlexander Graf dp[1].dp.length = sizeof(*dp); 2394a12a97cSAlexander Graf 2404a12a97cSAlexander Graf /* Hook up to the device list */ 2414a12a97cSAlexander Graf list_add_tail(&diskobj->parent.link, &efi_obj_list); 2424a12a97cSAlexander Graf } 2434a12a97cSAlexander Graf 2448c3df0bfSAlexander Graf static int efi_disk_create_eltorito(struct blk_desc *desc, 2456dd9faf8SSimon Glass const struct blk_driver *cur_drvr, 2468c3df0bfSAlexander Graf int diskid) 2478c3df0bfSAlexander Graf { 2488c3df0bfSAlexander Graf int disks = 0; 2498c3df0bfSAlexander Graf #ifdef CONFIG_ISO_PARTITION 250ecbe1a07SAlexander Graf char devname[32] = { 0 }; /* dp->str is u16[32] long */ 2518c3df0bfSAlexander Graf disk_partition_t info; 2528c3df0bfSAlexander Graf int part = 1; 2538c3df0bfSAlexander Graf 2548c3df0bfSAlexander Graf if (desc->part_type != PART_TYPE_ISO) 2558c3df0bfSAlexander Graf return 0; 2568c3df0bfSAlexander Graf 2578c3df0bfSAlexander Graf while (!part_get_info(desc, part, &info)) { 2586dd9faf8SSimon Glass snprintf(devname, sizeof(devname), "%s%d:%d", 2596dd9faf8SSimon Glass cur_drvr->if_typename, diskid, part); 2608c3df0bfSAlexander Graf efi_disk_add_dev(devname, cur_drvr, desc, diskid, info.start); 2618c3df0bfSAlexander Graf part++; 2628c3df0bfSAlexander Graf disks++; 2638c3df0bfSAlexander Graf } 2648c3df0bfSAlexander Graf #endif 2658c3df0bfSAlexander Graf 2668c3df0bfSAlexander Graf return disks; 2678c3df0bfSAlexander Graf } 2688c3df0bfSAlexander Graf 2692a22d05dSAlexander Graf /* 2702a22d05dSAlexander Graf * U-Boot doesn't have a list of all online disk devices. So when running our 2712a22d05dSAlexander Graf * EFI payload, we scan through all of the potentially available ones and 2722a22d05dSAlexander Graf * store them in our object pool. 2732a22d05dSAlexander Graf * 2742a22d05dSAlexander Graf * This gets called from do_bootefi_exec(). 2752a22d05dSAlexander Graf */ 2762a22d05dSAlexander Graf int efi_disk_register(void) 2772a22d05dSAlexander Graf { 2786dd9faf8SSimon Glass const struct blk_driver *cur_drvr; 2796dd9faf8SSimon Glass int i, if_type; 2802a22d05dSAlexander Graf int disks = 0; 2812a22d05dSAlexander Graf 2822a22d05dSAlexander Graf /* Search for all available disk devices */ 2836dd9faf8SSimon Glass for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) { 2846dd9faf8SSimon Glass cur_drvr = blk_driver_lookup_type(if_type); 2856dd9faf8SSimon Glass if (!cur_drvr) 2866dd9faf8SSimon Glass continue; 2876dd9faf8SSimon Glass 2886dd9faf8SSimon Glass printf("Scanning disks on %s...\n", cur_drvr->if_typename); 2892a22d05dSAlexander Graf for (i = 0; i < 4; i++) { 2902a22d05dSAlexander Graf struct blk_desc *desc; 291ecbe1a07SAlexander Graf char devname[32] = { 0 }; /* dp->str is u16[32] long */ 2922a22d05dSAlexander Graf 2936dd9faf8SSimon Glass desc = blk_get_devnum_by_type(if_type, i); 2942a22d05dSAlexander Graf if (!desc) 2952a22d05dSAlexander Graf continue; 2962a22d05dSAlexander Graf if (desc->type == DEV_TYPE_UNKNOWN) 2972a22d05dSAlexander Graf continue; 2982a22d05dSAlexander Graf 2992a22d05dSAlexander Graf snprintf(devname, sizeof(devname), "%s%d", 3006dd9faf8SSimon Glass cur_drvr->if_typename, i); 3014a12a97cSAlexander Graf efi_disk_add_dev(devname, cur_drvr, desc, i, 0); 3022a22d05dSAlexander Graf disks++; 3038c3df0bfSAlexander Graf 3048c3df0bfSAlexander Graf /* 3058c3df0bfSAlexander Graf * El Torito images show up as block devices 3068c3df0bfSAlexander Graf * in an EFI world, so let's create them here 3078c3df0bfSAlexander Graf */ 3088c3df0bfSAlexander Graf disks += efi_disk_create_eltorito(desc, cur_drvr, i); 3092a22d05dSAlexander Graf } 3102a22d05dSAlexander Graf } 3112a22d05dSAlexander Graf printf("Found %d disks\n", disks); 3122a22d05dSAlexander Graf 3132a22d05dSAlexander Graf return 0; 3142a22d05dSAlexander Graf } 315