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> 102a22d05dSAlexander Graf #include <efi_loader.h> 112a22d05dSAlexander Graf #include <inttypes.h> 122a22d05dSAlexander Graf #include <part.h> 132a22d05dSAlexander Graf #include <malloc.h> 142a22d05dSAlexander Graf 152a22d05dSAlexander Graf static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID; 162a22d05dSAlexander Graf 172a22d05dSAlexander Graf struct efi_disk_obj { 182a22d05dSAlexander Graf /* Generic EFI object parent class data */ 192a22d05dSAlexander Graf struct efi_object parent; 202a22d05dSAlexander Graf /* EFI Interface callback struct for block I/O */ 212a22d05dSAlexander Graf struct efi_block_io ops; 222a22d05dSAlexander Graf /* U-Boot ifname for block device */ 232a22d05dSAlexander Graf const char *ifname; 242a22d05dSAlexander Graf /* U-Boot dev_index for block device */ 252a22d05dSAlexander Graf int dev_index; 262a22d05dSAlexander Graf /* EFI Interface Media descriptor struct, referenced by ops */ 272a22d05dSAlexander Graf struct efi_block_io_media media; 282a22d05dSAlexander Graf /* EFI device path to this block device */ 292a22d05dSAlexander Graf struct efi_device_path_file_path *dp; 302a22d05dSAlexander Graf }; 312a22d05dSAlexander Graf 322a22d05dSAlexander Graf static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol, 332a22d05dSAlexander Graf void **protocol_interface, void *agent_handle, 342a22d05dSAlexander Graf void *controller_handle, uint32_t attributes) 352a22d05dSAlexander Graf { 362a22d05dSAlexander Graf struct efi_disk_obj *diskobj = handle; 372a22d05dSAlexander Graf 382a22d05dSAlexander Graf *protocol_interface = &diskobj->ops; 392a22d05dSAlexander Graf 402a22d05dSAlexander Graf return EFI_SUCCESS; 412a22d05dSAlexander Graf } 422a22d05dSAlexander Graf 432a22d05dSAlexander Graf static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol, 442a22d05dSAlexander Graf void **protocol_interface, void *agent_handle, 452a22d05dSAlexander Graf void *controller_handle, uint32_t attributes) 462a22d05dSAlexander Graf { 472a22d05dSAlexander Graf struct efi_disk_obj *diskobj = handle; 482a22d05dSAlexander Graf 492a22d05dSAlexander Graf *protocol_interface = diskobj->dp; 502a22d05dSAlexander Graf 512a22d05dSAlexander Graf return EFI_SUCCESS; 522a22d05dSAlexander Graf } 532a22d05dSAlexander Graf 542a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, 552a22d05dSAlexander Graf char extended_verification) 562a22d05dSAlexander Graf { 572a22d05dSAlexander Graf EFI_ENTRY("%p, %x", this, extended_verification); 582a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 592a22d05dSAlexander Graf } 602a22d05dSAlexander Graf 612a22d05dSAlexander Graf enum efi_disk_direction { 622a22d05dSAlexander Graf EFI_DISK_READ, 632a22d05dSAlexander Graf EFI_DISK_WRITE, 642a22d05dSAlexander Graf }; 652a22d05dSAlexander Graf 662a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, 672a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 682a22d05dSAlexander Graf void *buffer, enum efi_disk_direction direction) 692a22d05dSAlexander Graf { 702a22d05dSAlexander Graf struct efi_disk_obj *diskobj; 712a22d05dSAlexander Graf struct blk_desc *desc; 722a22d05dSAlexander Graf int blksz; 732a22d05dSAlexander Graf int blocks; 742a22d05dSAlexander Graf unsigned long n; 752a22d05dSAlexander Graf 762a22d05dSAlexander Graf EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, 772a22d05dSAlexander Graf buffer_size, buffer); 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; 842a22d05dSAlexander Graf 852a22d05dSAlexander Graf #ifdef DEBUG_EFI 862a22d05dSAlexander Graf printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__, 872a22d05dSAlexander Graf __LINE__, blocks, lba, blksz, direction); 882a22d05dSAlexander Graf #endif 892a22d05dSAlexander Graf 902a22d05dSAlexander Graf /* We only support full block access */ 912a22d05dSAlexander Graf if (buffer_size & (blksz - 1)) 922a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 932a22d05dSAlexander Graf 942a22d05dSAlexander Graf if (direction == EFI_DISK_READ) 952a22d05dSAlexander Graf n = desc->block_read(desc, lba, blocks, buffer); 962a22d05dSAlexander Graf else 972a22d05dSAlexander Graf n = desc->block_write(desc, lba, blocks, buffer); 982a22d05dSAlexander Graf 992a22d05dSAlexander Graf /* We don't do interrupts, so check for timers cooperatively */ 1002a22d05dSAlexander Graf efi_timer_check(); 1012a22d05dSAlexander Graf 1022a22d05dSAlexander Graf #ifdef DEBUG_EFI 1032a22d05dSAlexander Graf printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); 1042a22d05dSAlexander Graf #endif 1052a22d05dSAlexander Graf if (n != blocks) 1062a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 1072a22d05dSAlexander Graf 1082a22d05dSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1092a22d05dSAlexander Graf } 1102a22d05dSAlexander Graf 1112a22d05dSAlexander Graf static efi_status_t efi_disk_read_blocks(struct efi_block_io *this, 1122a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 1132a22d05dSAlexander Graf void *buffer) 1142a22d05dSAlexander Graf { 1152a22d05dSAlexander Graf return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer, 1162a22d05dSAlexander Graf EFI_DISK_READ); 1172a22d05dSAlexander Graf } 1182a22d05dSAlexander Graf 1192a22d05dSAlexander Graf static efi_status_t efi_disk_write_blocks(struct efi_block_io *this, 1202a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 1212a22d05dSAlexander Graf void *buffer) 1222a22d05dSAlexander Graf { 1232a22d05dSAlexander Graf return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer, 1242a22d05dSAlexander Graf EFI_DISK_WRITE); 1252a22d05dSAlexander Graf } 1262a22d05dSAlexander Graf 1272a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this) 1282a22d05dSAlexander Graf { 1292a22d05dSAlexander Graf /* We always write synchronously */ 1302a22d05dSAlexander Graf EFI_ENTRY("%p", this); 1312a22d05dSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 1322a22d05dSAlexander Graf } 1332a22d05dSAlexander Graf 1342a22d05dSAlexander Graf static const struct efi_block_io block_io_disk_template = { 1352a22d05dSAlexander Graf .reset = &efi_disk_reset, 1362a22d05dSAlexander Graf .read_blocks = &efi_disk_read_blocks, 1372a22d05dSAlexander Graf .write_blocks = &efi_disk_write_blocks, 1382a22d05dSAlexander Graf .flush_blocks = &efi_disk_flush_blocks, 1392a22d05dSAlexander Graf }; 1402a22d05dSAlexander Graf 141*4a12a97cSAlexander Graf static void efi_disk_add_dev(char *name, 142*4a12a97cSAlexander Graf const struct block_drvr *cur_drvr, 143*4a12a97cSAlexander Graf const struct blk_desc *desc, 144*4a12a97cSAlexander Graf int dev_index, 145*4a12a97cSAlexander Graf lbaint_t offset) 146*4a12a97cSAlexander Graf { 147*4a12a97cSAlexander Graf struct efi_disk_obj *diskobj; 148*4a12a97cSAlexander Graf struct efi_device_path_file_path *dp; 149*4a12a97cSAlexander Graf int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); 150*4a12a97cSAlexander Graf 151*4a12a97cSAlexander Graf diskobj = calloc(1, objlen); 152*4a12a97cSAlexander Graf 153*4a12a97cSAlexander Graf /* Fill in object data */ 154*4a12a97cSAlexander Graf diskobj->parent.protocols[0].guid = &efi_block_io_guid; 155*4a12a97cSAlexander Graf diskobj->parent.protocols[0].open = efi_disk_open_block; 156*4a12a97cSAlexander Graf diskobj->parent.protocols[1].guid = &efi_guid_device_path; 157*4a12a97cSAlexander Graf diskobj->parent.protocols[1].open = efi_disk_open_dp; 158*4a12a97cSAlexander Graf diskobj->parent.handle = diskobj; 159*4a12a97cSAlexander Graf diskobj->ops = block_io_disk_template; 160*4a12a97cSAlexander Graf diskobj->ifname = cur_drvr->name; 161*4a12a97cSAlexander Graf diskobj->dev_index = dev_index; 162*4a12a97cSAlexander Graf 163*4a12a97cSAlexander Graf /* Fill in EFI IO Media info (for read/write callbacks) */ 164*4a12a97cSAlexander Graf diskobj->media.removable_media = desc->removable; 165*4a12a97cSAlexander Graf diskobj->media.media_present = 1; 166*4a12a97cSAlexander Graf diskobj->media.block_size = desc->blksz; 167*4a12a97cSAlexander Graf diskobj->media.io_align = desc->blksz; 168*4a12a97cSAlexander Graf diskobj->media.last_block = desc->lba; 169*4a12a97cSAlexander Graf diskobj->ops.media = &diskobj->media; 170*4a12a97cSAlexander Graf 171*4a12a97cSAlexander Graf /* Fill in device path */ 172*4a12a97cSAlexander Graf dp = (void*)&diskobj[1]; 173*4a12a97cSAlexander Graf diskobj->dp = dp; 174*4a12a97cSAlexander Graf dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; 175*4a12a97cSAlexander Graf dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; 176*4a12a97cSAlexander Graf dp[0].dp.length = sizeof(*dp); 177*4a12a97cSAlexander Graf ascii2unicode(dp[0].str, name); 178*4a12a97cSAlexander Graf 179*4a12a97cSAlexander Graf dp[1].dp.type = DEVICE_PATH_TYPE_END; 180*4a12a97cSAlexander Graf dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END; 181*4a12a97cSAlexander Graf dp[1].dp.length = sizeof(*dp); 182*4a12a97cSAlexander Graf 183*4a12a97cSAlexander Graf /* Hook up to the device list */ 184*4a12a97cSAlexander Graf list_add_tail(&diskobj->parent.link, &efi_obj_list); 185*4a12a97cSAlexander Graf } 186*4a12a97cSAlexander Graf 1872a22d05dSAlexander Graf /* 1882a22d05dSAlexander Graf * U-Boot doesn't have a list of all online disk devices. So when running our 1892a22d05dSAlexander Graf * EFI payload, we scan through all of the potentially available ones and 1902a22d05dSAlexander Graf * store them in our object pool. 1912a22d05dSAlexander Graf * 1922a22d05dSAlexander Graf * This gets called from do_bootefi_exec(). 1932a22d05dSAlexander Graf */ 1942a22d05dSAlexander Graf int efi_disk_register(void) 1952a22d05dSAlexander Graf { 1962a22d05dSAlexander Graf const struct block_drvr *cur_drvr; 1972a22d05dSAlexander Graf int i; 1982a22d05dSAlexander Graf int disks = 0; 1992a22d05dSAlexander Graf 2002a22d05dSAlexander Graf /* Search for all available disk devices */ 2012a22d05dSAlexander Graf for (cur_drvr = block_drvr; cur_drvr->name; cur_drvr++) { 2022a22d05dSAlexander Graf printf("Scanning disks on %s...\n", cur_drvr->name); 2032a22d05dSAlexander Graf for (i = 0; i < 4; i++) { 2042a22d05dSAlexander Graf struct blk_desc *desc; 2052a22d05dSAlexander Graf char devname[16] = { 0 }; /* dp->str is u16[16] long */ 2062a22d05dSAlexander Graf 2072a22d05dSAlexander Graf desc = blk_get_dev(cur_drvr->name, i); 2082a22d05dSAlexander Graf if (!desc) 2092a22d05dSAlexander Graf continue; 2102a22d05dSAlexander Graf if (desc->type == DEV_TYPE_UNKNOWN) 2112a22d05dSAlexander Graf continue; 2122a22d05dSAlexander Graf 2132a22d05dSAlexander Graf snprintf(devname, sizeof(devname), "%s%d", 2142a22d05dSAlexander Graf cur_drvr->name, i); 215*4a12a97cSAlexander Graf efi_disk_add_dev(devname, cur_drvr, desc, i, 0); 2162a22d05dSAlexander Graf disks++; 2172a22d05dSAlexander Graf } 2182a22d05dSAlexander Graf } 2192a22d05dSAlexander Graf printf("Found %d disks\n", disks); 2202a22d05dSAlexander Graf 2212a22d05dSAlexander Graf return 0; 2222a22d05dSAlexander Graf } 223