1 /* 2 * EFI application disk support 3 * 4 * Copyright (c) 2016 Alexander Graf 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <blk.h> 11 #include <dm.h> 12 #include <efi_loader.h> 13 #include <inttypes.h> 14 #include <part.h> 15 #include <malloc.h> 16 17 static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID; 18 19 struct efi_disk_obj { 20 /* Generic EFI object parent class data */ 21 struct efi_object parent; 22 /* EFI Interface callback struct for block I/O */ 23 struct efi_block_io ops; 24 /* U-Boot ifname for block device */ 25 const char *ifname; 26 /* U-Boot dev_index for block device */ 27 int dev_index; 28 /* EFI Interface Media descriptor struct, referenced by ops */ 29 struct efi_block_io_media media; 30 /* EFI device path to this block device */ 31 struct efi_device_path *dp; 32 /* partition # */ 33 unsigned int part; 34 /* Offset into disk for simple partitions */ 35 lbaint_t offset; 36 /* Internal block device */ 37 struct blk_desc *desc; 38 }; 39 40 static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, 41 char extended_verification) 42 { 43 EFI_ENTRY("%p, %x", this, extended_verification); 44 return EFI_EXIT(EFI_DEVICE_ERROR); 45 } 46 47 enum efi_disk_direction { 48 EFI_DISK_READ, 49 EFI_DISK_WRITE, 50 }; 51 52 static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, 53 u32 media_id, u64 lba, unsigned long buffer_size, 54 void *buffer, enum efi_disk_direction direction) 55 { 56 struct efi_disk_obj *diskobj; 57 struct blk_desc *desc; 58 int blksz; 59 int blocks; 60 unsigned long n; 61 62 diskobj = container_of(this, struct efi_disk_obj, ops); 63 desc = (struct blk_desc *) diskobj->desc; 64 blksz = desc->blksz; 65 blocks = buffer_size / blksz; 66 lba += diskobj->offset; 67 68 debug("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__, 69 __LINE__, blocks, lba, blksz, direction); 70 71 /* We only support full block access */ 72 if (buffer_size & (blksz - 1)) 73 return EFI_DEVICE_ERROR; 74 75 if (direction == EFI_DISK_READ) 76 n = blk_dread(desc, lba, blocks, buffer); 77 else 78 n = blk_dwrite(desc, lba, blocks, buffer); 79 80 /* We don't do interrupts, so check for timers cooperatively */ 81 efi_timer_check(); 82 83 debug("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); 84 85 if (n != blocks) 86 return EFI_DEVICE_ERROR; 87 88 return EFI_SUCCESS; 89 } 90 91 static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this, 92 u32 media_id, u64 lba, unsigned long buffer_size, 93 void *buffer) 94 { 95 void *real_buffer = buffer; 96 efi_status_t r; 97 98 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER 99 if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { 100 r = efi_disk_read_blocks(this, media_id, lba, 101 EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer); 102 if (r != EFI_SUCCESS) 103 return r; 104 return efi_disk_read_blocks(this, media_id, lba + 105 EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size, 106 buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE, 107 buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE); 108 } 109 110 real_buffer = efi_bounce_buffer; 111 #endif 112 113 EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, 114 buffer_size, buffer); 115 116 r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer, 117 EFI_DISK_READ); 118 119 /* Copy from bounce buffer to real buffer if necessary */ 120 if ((r == EFI_SUCCESS) && (real_buffer != buffer)) 121 memcpy(buffer, real_buffer, buffer_size); 122 123 return EFI_EXIT(r); 124 } 125 126 static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this, 127 u32 media_id, u64 lba, unsigned long buffer_size, 128 void *buffer) 129 { 130 void *real_buffer = buffer; 131 efi_status_t r; 132 133 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER 134 if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { 135 r = efi_disk_write_blocks(this, media_id, lba, 136 EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer); 137 if (r != EFI_SUCCESS) 138 return r; 139 return efi_disk_write_blocks(this, media_id, lba + 140 EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size, 141 buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE, 142 buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE); 143 } 144 145 real_buffer = efi_bounce_buffer; 146 #endif 147 148 EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba, 149 buffer_size, buffer); 150 151 /* Populate bounce buffer if necessary */ 152 if (real_buffer != buffer) 153 memcpy(real_buffer, buffer, buffer_size); 154 155 r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer, 156 EFI_DISK_WRITE); 157 158 return EFI_EXIT(r); 159 } 160 161 static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this) 162 { 163 /* We always write synchronously */ 164 EFI_ENTRY("%p", this); 165 return EFI_EXIT(EFI_SUCCESS); 166 } 167 168 static const struct efi_block_io block_io_disk_template = { 169 .reset = &efi_disk_reset, 170 .read_blocks = &efi_disk_read_blocks, 171 .write_blocks = &efi_disk_write_blocks, 172 .flush_blocks = &efi_disk_flush_blocks, 173 }; 174 175 static void efi_disk_add_dev(const char *name, 176 const char *if_typename, 177 struct blk_desc *desc, 178 int dev_index, 179 lbaint_t offset, 180 unsigned int part) 181 { 182 struct efi_disk_obj *diskobj; 183 184 /* Don't add empty devices */ 185 if (!desc->lba) 186 return; 187 188 diskobj = calloc(1, sizeof(*diskobj)); 189 190 /* Fill in object data */ 191 diskobj->dp = efi_dp_from_part(desc, part); 192 diskobj->part = part; 193 diskobj->parent.protocols[0].guid = &efi_block_io_guid; 194 diskobj->parent.protocols[0].protocol_interface = &diskobj->ops; 195 diskobj->parent.protocols[1].guid = &efi_guid_device_path; 196 diskobj->parent.protocols[1].protocol_interface = diskobj->dp; 197 diskobj->parent.handle = diskobj; 198 diskobj->ops = block_io_disk_template; 199 diskobj->ifname = if_typename; 200 diskobj->dev_index = dev_index; 201 diskobj->offset = offset; 202 diskobj->desc = desc; 203 204 /* Fill in EFI IO Media info (for read/write callbacks) */ 205 diskobj->media.removable_media = desc->removable; 206 diskobj->media.media_present = 1; 207 diskobj->media.block_size = desc->blksz; 208 diskobj->media.io_align = desc->blksz; 209 diskobj->media.last_block = desc->lba - offset; 210 diskobj->ops.media = &diskobj->media; 211 212 /* Hook up to the device list */ 213 list_add_tail(&diskobj->parent.link, &efi_obj_list); 214 } 215 216 static int efi_disk_create_eltorito(struct blk_desc *desc, 217 const char *if_typename, 218 int diskid, 219 const char *pdevname) 220 { 221 int disks = 0; 222 #if CONFIG_IS_ENABLED(ISO_PARTITION) 223 char devname[32] = { 0 }; /* dp->str is u16[32] long */ 224 disk_partition_t info; 225 int part = 1; 226 227 if (desc->part_type != PART_TYPE_ISO) 228 return 0; 229 230 /* and devices for each partition: */ 231 while (!part_get_info(desc, part, &info)) { 232 snprintf(devname, sizeof(devname), "%s:%d", pdevname, 233 part); 234 efi_disk_add_dev(devname, if_typename, desc, diskid, 235 info.start, part); 236 part++; 237 disks++; 238 } 239 240 /* ... and add block device: */ 241 efi_disk_add_dev(devname, if_typename, desc, diskid, 0, 0); 242 #endif 243 244 return disks; 245 } 246 247 /* 248 * U-Boot doesn't have a list of all online disk devices. So when running our 249 * EFI payload, we scan through all of the potentially available ones and 250 * store them in our object pool. 251 * 252 * TODO(sjg@chromium.org): Actually with CONFIG_BLK, U-Boot does have this. 253 * Consider converting the code to look up devices as needed. The EFI device 254 * could be a child of the UCLASS_BLK block device, perhaps. 255 * 256 * This gets called from do_bootefi_exec(). 257 */ 258 int efi_disk_register(void) 259 { 260 int disks = 0; 261 #ifdef CONFIG_BLK 262 struct udevice *dev; 263 264 for (uclass_first_device_check(UCLASS_BLK, &dev); 265 dev; 266 uclass_next_device_check(&dev)) { 267 struct blk_desc *desc = dev_get_uclass_platdata(dev); 268 const char *if_typename = dev->driver->name; 269 disk_partition_t info; 270 int part = 1; 271 272 printf("Scanning disk %s...\n", dev->name); 273 274 /* add devices for each partition: */ 275 while (!part_get_info(desc, part, &info)) { 276 efi_disk_add_dev(dev->name, if_typename, desc, 277 desc->devnum, 0, part); 278 part++; 279 } 280 281 /* ... and add block device: */ 282 efi_disk_add_dev(dev->name, if_typename, desc, 283 desc->devnum, 0, 0); 284 285 disks++; 286 287 /* 288 * El Torito images show up as block devices in an EFI world, 289 * so let's create them here 290 */ 291 disks += efi_disk_create_eltorito(desc, if_typename, 292 desc->devnum, dev->name); 293 } 294 #else 295 int i, if_type; 296 297 /* Search for all available disk devices */ 298 for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) { 299 const struct blk_driver *cur_drvr; 300 const char *if_typename; 301 302 cur_drvr = blk_driver_lookup_type(if_type); 303 if (!cur_drvr) 304 continue; 305 306 if_typename = cur_drvr->if_typename; 307 printf("Scanning disks on %s...\n", if_typename); 308 for (i = 0; i < 4; i++) { 309 struct blk_desc *desc; 310 char devname[32] = { 0 }; /* dp->str is u16[32] long */ 311 312 desc = blk_get_devnum_by_type(if_type, i); 313 if (!desc) 314 continue; 315 if (desc->type == DEV_TYPE_UNKNOWN) 316 continue; 317 318 snprintf(devname, sizeof(devname), "%s%d", 319 if_typename, i); 320 efi_disk_add_dev(devname, if_typename, desc, i, 0, 0); 321 disks++; 322 323 /* 324 * El Torito images show up as block devices 325 * in an EFI world, so let's create them here 326 */ 327 disks += efi_disk_create_eltorito(desc, if_typename, 328 i, devname); 329 } 330 } 331 #endif 332 printf("Found %d disks\n", disks); 333 334 return 0; 335 } 336