1*2a22d05dSAlexander Graf /* 2*2a22d05dSAlexander Graf * EFI application disk support 3*2a22d05dSAlexander Graf * 4*2a22d05dSAlexander Graf * Copyright (c) 2016 Alexander Graf 5*2a22d05dSAlexander Graf * 6*2a22d05dSAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 7*2a22d05dSAlexander Graf */ 8*2a22d05dSAlexander Graf 9*2a22d05dSAlexander Graf #include <common.h> 10*2a22d05dSAlexander Graf #include <efi_loader.h> 11*2a22d05dSAlexander Graf #include <inttypes.h> 12*2a22d05dSAlexander Graf #include <part.h> 13*2a22d05dSAlexander Graf #include <malloc.h> 14*2a22d05dSAlexander Graf 15*2a22d05dSAlexander Graf static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID; 16*2a22d05dSAlexander Graf 17*2a22d05dSAlexander Graf struct efi_disk_obj { 18*2a22d05dSAlexander Graf /* Generic EFI object parent class data */ 19*2a22d05dSAlexander Graf struct efi_object parent; 20*2a22d05dSAlexander Graf /* EFI Interface callback struct for block I/O */ 21*2a22d05dSAlexander Graf struct efi_block_io ops; 22*2a22d05dSAlexander Graf /* U-Boot ifname for block device */ 23*2a22d05dSAlexander Graf const char *ifname; 24*2a22d05dSAlexander Graf /* U-Boot dev_index for block device */ 25*2a22d05dSAlexander Graf int dev_index; 26*2a22d05dSAlexander Graf /* EFI Interface Media descriptor struct, referenced by ops */ 27*2a22d05dSAlexander Graf struct efi_block_io_media media; 28*2a22d05dSAlexander Graf /* EFI device path to this block device */ 29*2a22d05dSAlexander Graf struct efi_device_path_file_path *dp; 30*2a22d05dSAlexander Graf }; 31*2a22d05dSAlexander Graf 32*2a22d05dSAlexander Graf static void ascii2unicode(u16 *unicode, char *ascii) 33*2a22d05dSAlexander Graf { 34*2a22d05dSAlexander Graf while (*ascii) 35*2a22d05dSAlexander Graf *(unicode++) = *(ascii++); 36*2a22d05dSAlexander Graf } 37*2a22d05dSAlexander Graf 38*2a22d05dSAlexander Graf static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol, 39*2a22d05dSAlexander Graf void **protocol_interface, void *agent_handle, 40*2a22d05dSAlexander Graf void *controller_handle, uint32_t attributes) 41*2a22d05dSAlexander Graf { 42*2a22d05dSAlexander Graf struct efi_disk_obj *diskobj = handle; 43*2a22d05dSAlexander Graf 44*2a22d05dSAlexander Graf *protocol_interface = &diskobj->ops; 45*2a22d05dSAlexander Graf 46*2a22d05dSAlexander Graf return EFI_SUCCESS; 47*2a22d05dSAlexander Graf } 48*2a22d05dSAlexander Graf 49*2a22d05dSAlexander Graf static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol, 50*2a22d05dSAlexander Graf void **protocol_interface, void *agent_handle, 51*2a22d05dSAlexander Graf void *controller_handle, uint32_t attributes) 52*2a22d05dSAlexander Graf { 53*2a22d05dSAlexander Graf struct efi_disk_obj *diskobj = handle; 54*2a22d05dSAlexander Graf 55*2a22d05dSAlexander Graf *protocol_interface = diskobj->dp; 56*2a22d05dSAlexander Graf 57*2a22d05dSAlexander Graf return EFI_SUCCESS; 58*2a22d05dSAlexander Graf } 59*2a22d05dSAlexander Graf 60*2a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, 61*2a22d05dSAlexander Graf char extended_verification) 62*2a22d05dSAlexander Graf { 63*2a22d05dSAlexander Graf EFI_ENTRY("%p, %x", this, extended_verification); 64*2a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 65*2a22d05dSAlexander Graf } 66*2a22d05dSAlexander Graf 67*2a22d05dSAlexander Graf enum efi_disk_direction { 68*2a22d05dSAlexander Graf EFI_DISK_READ, 69*2a22d05dSAlexander Graf EFI_DISK_WRITE, 70*2a22d05dSAlexander Graf }; 71*2a22d05dSAlexander Graf 72*2a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, 73*2a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 74*2a22d05dSAlexander Graf void *buffer, enum efi_disk_direction direction) 75*2a22d05dSAlexander Graf { 76*2a22d05dSAlexander Graf struct efi_disk_obj *diskobj; 77*2a22d05dSAlexander Graf struct blk_desc *desc; 78*2a22d05dSAlexander Graf int blksz; 79*2a22d05dSAlexander Graf int blocks; 80*2a22d05dSAlexander Graf unsigned long n; 81*2a22d05dSAlexander Graf 82*2a22d05dSAlexander Graf EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, 83*2a22d05dSAlexander Graf buffer_size, buffer); 84*2a22d05dSAlexander Graf 85*2a22d05dSAlexander Graf diskobj = container_of(this, struct efi_disk_obj, ops); 86*2a22d05dSAlexander Graf if (!(desc = blk_get_dev(diskobj->ifname, diskobj->dev_index))) 87*2a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 88*2a22d05dSAlexander Graf blksz = desc->blksz; 89*2a22d05dSAlexander Graf blocks = buffer_size / blksz; 90*2a22d05dSAlexander Graf 91*2a22d05dSAlexander Graf #ifdef DEBUG_EFI 92*2a22d05dSAlexander Graf printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__, 93*2a22d05dSAlexander Graf __LINE__, blocks, lba, blksz, direction); 94*2a22d05dSAlexander Graf #endif 95*2a22d05dSAlexander Graf 96*2a22d05dSAlexander Graf /* We only support full block access */ 97*2a22d05dSAlexander Graf if (buffer_size & (blksz - 1)) 98*2a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 99*2a22d05dSAlexander Graf 100*2a22d05dSAlexander Graf if (direction == EFI_DISK_READ) 101*2a22d05dSAlexander Graf n = desc->block_read(desc, lba, blocks, buffer); 102*2a22d05dSAlexander Graf else 103*2a22d05dSAlexander Graf n = desc->block_write(desc, lba, blocks, buffer); 104*2a22d05dSAlexander Graf 105*2a22d05dSAlexander Graf /* We don't do interrupts, so check for timers cooperatively */ 106*2a22d05dSAlexander Graf efi_timer_check(); 107*2a22d05dSAlexander Graf 108*2a22d05dSAlexander Graf #ifdef DEBUG_EFI 109*2a22d05dSAlexander Graf printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); 110*2a22d05dSAlexander Graf #endif 111*2a22d05dSAlexander Graf if (n != blocks) 112*2a22d05dSAlexander Graf return EFI_EXIT(EFI_DEVICE_ERROR); 113*2a22d05dSAlexander Graf 114*2a22d05dSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 115*2a22d05dSAlexander Graf } 116*2a22d05dSAlexander Graf 117*2a22d05dSAlexander Graf static efi_status_t efi_disk_read_blocks(struct efi_block_io *this, 118*2a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 119*2a22d05dSAlexander Graf void *buffer) 120*2a22d05dSAlexander Graf { 121*2a22d05dSAlexander Graf return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer, 122*2a22d05dSAlexander Graf EFI_DISK_READ); 123*2a22d05dSAlexander Graf } 124*2a22d05dSAlexander Graf 125*2a22d05dSAlexander Graf static efi_status_t efi_disk_write_blocks(struct efi_block_io *this, 126*2a22d05dSAlexander Graf u32 media_id, u64 lba, unsigned long buffer_size, 127*2a22d05dSAlexander Graf void *buffer) 128*2a22d05dSAlexander Graf { 129*2a22d05dSAlexander Graf return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer, 130*2a22d05dSAlexander Graf EFI_DISK_WRITE); 131*2a22d05dSAlexander Graf } 132*2a22d05dSAlexander Graf 133*2a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this) 134*2a22d05dSAlexander Graf { 135*2a22d05dSAlexander Graf /* We always write synchronously */ 136*2a22d05dSAlexander Graf EFI_ENTRY("%p", this); 137*2a22d05dSAlexander Graf return EFI_EXIT(EFI_SUCCESS); 138*2a22d05dSAlexander Graf } 139*2a22d05dSAlexander Graf 140*2a22d05dSAlexander Graf static const struct efi_block_io block_io_disk_template = { 141*2a22d05dSAlexander Graf .reset = &efi_disk_reset, 142*2a22d05dSAlexander Graf .read_blocks = &efi_disk_read_blocks, 143*2a22d05dSAlexander Graf .write_blocks = &efi_disk_write_blocks, 144*2a22d05dSAlexander Graf .flush_blocks = &efi_disk_flush_blocks, 145*2a22d05dSAlexander Graf }; 146*2a22d05dSAlexander Graf 147*2a22d05dSAlexander Graf /* 148*2a22d05dSAlexander Graf * U-Boot doesn't have a list of all online disk devices. So when running our 149*2a22d05dSAlexander Graf * EFI payload, we scan through all of the potentially available ones and 150*2a22d05dSAlexander Graf * store them in our object pool. 151*2a22d05dSAlexander Graf * 152*2a22d05dSAlexander Graf * This gets called from do_bootefi_exec(). 153*2a22d05dSAlexander Graf */ 154*2a22d05dSAlexander Graf int efi_disk_register(void) 155*2a22d05dSAlexander Graf { 156*2a22d05dSAlexander Graf const struct block_drvr *cur_drvr; 157*2a22d05dSAlexander Graf int i; 158*2a22d05dSAlexander Graf int disks = 0; 159*2a22d05dSAlexander Graf 160*2a22d05dSAlexander Graf /* Search for all available disk devices */ 161*2a22d05dSAlexander Graf for (cur_drvr = block_drvr; cur_drvr->name; cur_drvr++) { 162*2a22d05dSAlexander Graf printf("Scanning disks on %s...\n", cur_drvr->name); 163*2a22d05dSAlexander Graf for (i = 0; i < 4; i++) { 164*2a22d05dSAlexander Graf struct blk_desc *desc; 165*2a22d05dSAlexander Graf struct efi_disk_obj *diskobj; 166*2a22d05dSAlexander Graf struct efi_device_path_file_path *dp; 167*2a22d05dSAlexander Graf int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); 168*2a22d05dSAlexander Graf char devname[16] = { 0 }; /* dp->str is u16[16] long */ 169*2a22d05dSAlexander Graf 170*2a22d05dSAlexander Graf desc = blk_get_dev(cur_drvr->name, i); 171*2a22d05dSAlexander Graf if (!desc) 172*2a22d05dSAlexander Graf continue; 173*2a22d05dSAlexander Graf if (desc->type == DEV_TYPE_UNKNOWN) 174*2a22d05dSAlexander Graf continue; 175*2a22d05dSAlexander Graf 176*2a22d05dSAlexander Graf diskobj = calloc(1, objlen); 177*2a22d05dSAlexander Graf 178*2a22d05dSAlexander Graf /* Fill in object data */ 179*2a22d05dSAlexander Graf diskobj->parent.protocols[0].guid = &efi_block_io_guid; 180*2a22d05dSAlexander Graf diskobj->parent.protocols[0].open = efi_disk_open_block; 181*2a22d05dSAlexander Graf diskobj->parent.protocols[1].guid = &efi_guid_device_path; 182*2a22d05dSAlexander Graf diskobj->parent.protocols[1].open = efi_disk_open_dp; 183*2a22d05dSAlexander Graf diskobj->parent.handle = diskobj; 184*2a22d05dSAlexander Graf diskobj->ops = block_io_disk_template; 185*2a22d05dSAlexander Graf diskobj->ifname = cur_drvr->name; 186*2a22d05dSAlexander Graf diskobj->dev_index = i; 187*2a22d05dSAlexander Graf 188*2a22d05dSAlexander Graf /* Fill in EFI IO Media info (for read/write callbacks) */ 189*2a22d05dSAlexander Graf diskobj->media.removable_media = desc->removable; 190*2a22d05dSAlexander Graf diskobj->media.media_present = 1; 191*2a22d05dSAlexander Graf diskobj->media.block_size = desc->blksz; 192*2a22d05dSAlexander Graf diskobj->media.io_align = desc->blksz; 193*2a22d05dSAlexander Graf diskobj->media.last_block = desc->lba; 194*2a22d05dSAlexander Graf diskobj->ops.media = &diskobj->media; 195*2a22d05dSAlexander Graf 196*2a22d05dSAlexander Graf /* Fill in device path */ 197*2a22d05dSAlexander Graf dp = (void*)&diskobj[1]; 198*2a22d05dSAlexander Graf diskobj->dp = dp; 199*2a22d05dSAlexander Graf dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; 200*2a22d05dSAlexander Graf dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; 201*2a22d05dSAlexander Graf dp[0].dp.length = sizeof(*dp); 202*2a22d05dSAlexander Graf snprintf(devname, sizeof(devname), "%s%d", 203*2a22d05dSAlexander Graf cur_drvr->name, i); 204*2a22d05dSAlexander Graf ascii2unicode(dp[0].str, devname); 205*2a22d05dSAlexander Graf 206*2a22d05dSAlexander Graf dp[1].dp.type = DEVICE_PATH_TYPE_END; 207*2a22d05dSAlexander Graf dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END; 208*2a22d05dSAlexander Graf dp[1].dp.length = sizeof(*dp); 209*2a22d05dSAlexander Graf 210*2a22d05dSAlexander Graf /* Hook up to the device list */ 211*2a22d05dSAlexander Graf list_add_tail(&diskobj->parent.link, &efi_obj_list); 212*2a22d05dSAlexander Graf disks++; 213*2a22d05dSAlexander Graf } 214*2a22d05dSAlexander Graf } 215*2a22d05dSAlexander Graf printf("Found %d disks\n", disks); 216*2a22d05dSAlexander Graf 217*2a22d05dSAlexander Graf return 0; 218*2a22d05dSAlexander Graf } 219