xref: /rk3399_rockchip-uboot/lib/efi_loader/efi_disk.c (revision ecbe1a07c507d37aeb5f0f9ce1c4cc20c70fec64)
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;
308c3df0bfSAlexander Graf 	/* Offset into disk for simple partitions */
318c3df0bfSAlexander Graf 	lbaint_t offset;
322a22d05dSAlexander Graf };
332a22d05dSAlexander Graf 
342a22d05dSAlexander Graf static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
352a22d05dSAlexander Graf 			void **protocol_interface, void *agent_handle,
362a22d05dSAlexander Graf 			void *controller_handle, uint32_t attributes)
372a22d05dSAlexander Graf {
382a22d05dSAlexander Graf 	struct efi_disk_obj *diskobj = handle;
392a22d05dSAlexander Graf 
402a22d05dSAlexander Graf 	*protocol_interface = &diskobj->ops;
412a22d05dSAlexander Graf 
422a22d05dSAlexander Graf 	return EFI_SUCCESS;
432a22d05dSAlexander Graf }
442a22d05dSAlexander Graf 
452a22d05dSAlexander Graf static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol,
462a22d05dSAlexander Graf 			void **protocol_interface, void *agent_handle,
472a22d05dSAlexander Graf 			void *controller_handle, uint32_t attributes)
482a22d05dSAlexander Graf {
492a22d05dSAlexander Graf 	struct efi_disk_obj *diskobj = handle;
502a22d05dSAlexander Graf 
512a22d05dSAlexander Graf 	*protocol_interface = diskobj->dp;
522a22d05dSAlexander Graf 
532a22d05dSAlexander Graf 	return EFI_SUCCESS;
542a22d05dSAlexander Graf }
552a22d05dSAlexander Graf 
562a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
572a22d05dSAlexander Graf 			char extended_verification)
582a22d05dSAlexander Graf {
592a22d05dSAlexander Graf 	EFI_ENTRY("%p, %x", this, extended_verification);
602a22d05dSAlexander Graf 	return EFI_EXIT(EFI_DEVICE_ERROR);
612a22d05dSAlexander Graf }
622a22d05dSAlexander Graf 
632a22d05dSAlexander Graf enum efi_disk_direction {
642a22d05dSAlexander Graf 	EFI_DISK_READ,
652a22d05dSAlexander Graf 	EFI_DISK_WRITE,
662a22d05dSAlexander Graf };
672a22d05dSAlexander Graf 
682a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this,
692a22d05dSAlexander Graf 			u32 media_id, u64 lba, unsigned long buffer_size,
702a22d05dSAlexander Graf 			void *buffer, enum efi_disk_direction direction)
712a22d05dSAlexander Graf {
722a22d05dSAlexander Graf 	struct efi_disk_obj *diskobj;
732a22d05dSAlexander Graf 	struct blk_desc *desc;
742a22d05dSAlexander Graf 	int blksz;
752a22d05dSAlexander Graf 	int blocks;
762a22d05dSAlexander Graf 	unsigned long n;
772a22d05dSAlexander Graf 
782a22d05dSAlexander Graf 	EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
792a22d05dSAlexander Graf 		  buffer_size, buffer);
802a22d05dSAlexander Graf 
812a22d05dSAlexander Graf 	diskobj = container_of(this, struct efi_disk_obj, ops);
822a22d05dSAlexander Graf 	if (!(desc = blk_get_dev(diskobj->ifname, diskobj->dev_index)))
832a22d05dSAlexander Graf 		return EFI_EXIT(EFI_DEVICE_ERROR);
842a22d05dSAlexander Graf 	blksz = desc->blksz;
852a22d05dSAlexander Graf 	blocks = buffer_size / blksz;
868c3df0bfSAlexander Graf 	lba += diskobj->offset;
872a22d05dSAlexander Graf 
882a22d05dSAlexander Graf #ifdef DEBUG_EFI
892a22d05dSAlexander Graf 	printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__,
902a22d05dSAlexander Graf 	       __LINE__, blocks, lba, blksz, direction);
912a22d05dSAlexander Graf #endif
922a22d05dSAlexander Graf 
932a22d05dSAlexander Graf 	/* We only support full block access */
942a22d05dSAlexander Graf 	if (buffer_size & (blksz - 1))
952a22d05dSAlexander Graf 		return EFI_EXIT(EFI_DEVICE_ERROR);
962a22d05dSAlexander Graf 
972a22d05dSAlexander Graf 	if (direction == EFI_DISK_READ)
982a22d05dSAlexander Graf 		n = desc->block_read(desc, lba, blocks, buffer);
992a22d05dSAlexander Graf 	else
1002a22d05dSAlexander Graf 		n = desc->block_write(desc, lba, blocks, buffer);
1012a22d05dSAlexander Graf 
1022a22d05dSAlexander Graf 	/* We don't do interrupts, so check for timers cooperatively */
1032a22d05dSAlexander Graf 	efi_timer_check();
1042a22d05dSAlexander Graf 
1052a22d05dSAlexander Graf #ifdef DEBUG_EFI
1062a22d05dSAlexander Graf 	printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
1072a22d05dSAlexander Graf #endif
1082a22d05dSAlexander Graf 	if (n != blocks)
1092a22d05dSAlexander Graf 		return EFI_EXIT(EFI_DEVICE_ERROR);
1102a22d05dSAlexander Graf 
1112a22d05dSAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
1122a22d05dSAlexander Graf }
1132a22d05dSAlexander Graf 
1142a22d05dSAlexander Graf static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
1152a22d05dSAlexander Graf 			u32 media_id, u64 lba, unsigned long buffer_size,
1162a22d05dSAlexander Graf 			void *buffer)
1172a22d05dSAlexander Graf {
1182a22d05dSAlexander Graf 	return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
1192a22d05dSAlexander Graf 				  EFI_DISK_READ);
1202a22d05dSAlexander Graf }
1212a22d05dSAlexander Graf 
1222a22d05dSAlexander Graf static efi_status_t efi_disk_write_blocks(struct efi_block_io *this,
1232a22d05dSAlexander Graf 			u32 media_id, u64 lba, unsigned long buffer_size,
1242a22d05dSAlexander Graf 			void *buffer)
1252a22d05dSAlexander Graf {
1262a22d05dSAlexander Graf 	return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
1272a22d05dSAlexander Graf 				  EFI_DISK_WRITE);
1282a22d05dSAlexander Graf }
1292a22d05dSAlexander Graf 
1302a22d05dSAlexander Graf static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this)
1312a22d05dSAlexander Graf {
1322a22d05dSAlexander Graf 	/* We always write synchronously */
1332a22d05dSAlexander Graf 	EFI_ENTRY("%p", this);
1342a22d05dSAlexander Graf 	return EFI_EXIT(EFI_SUCCESS);
1352a22d05dSAlexander Graf }
1362a22d05dSAlexander Graf 
1372a22d05dSAlexander Graf static const struct efi_block_io block_io_disk_template = {
1382a22d05dSAlexander Graf 	.reset = &efi_disk_reset,
1392a22d05dSAlexander Graf 	.read_blocks = &efi_disk_read_blocks,
1402a22d05dSAlexander Graf 	.write_blocks = &efi_disk_write_blocks,
1412a22d05dSAlexander Graf 	.flush_blocks = &efi_disk_flush_blocks,
1422a22d05dSAlexander Graf };
1432a22d05dSAlexander Graf 
1444a12a97cSAlexander Graf static void efi_disk_add_dev(char *name,
1454a12a97cSAlexander Graf 			     const struct block_drvr *cur_drvr,
1464a12a97cSAlexander Graf 			     const struct blk_desc *desc,
1474a12a97cSAlexander Graf 			     int dev_index,
1484a12a97cSAlexander Graf 			     lbaint_t offset)
1494a12a97cSAlexander Graf {
1504a12a97cSAlexander Graf 	struct efi_disk_obj *diskobj;
1514a12a97cSAlexander Graf 	struct efi_device_path_file_path *dp;
1524a12a97cSAlexander Graf 	int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2);
1534a12a97cSAlexander Graf 
1544a12a97cSAlexander Graf 	diskobj = calloc(1, objlen);
1554a12a97cSAlexander Graf 
1564a12a97cSAlexander Graf 	/* Fill in object data */
1574a12a97cSAlexander Graf 	diskobj->parent.protocols[0].guid = &efi_block_io_guid;
1584a12a97cSAlexander Graf 	diskobj->parent.protocols[0].open = efi_disk_open_block;
1594a12a97cSAlexander Graf 	diskobj->parent.protocols[1].guid = &efi_guid_device_path;
1604a12a97cSAlexander Graf 	diskobj->parent.protocols[1].open = efi_disk_open_dp;
1614a12a97cSAlexander Graf 	diskobj->parent.handle = diskobj;
1624a12a97cSAlexander Graf 	diskobj->ops = block_io_disk_template;
1634a12a97cSAlexander Graf 	diskobj->ifname = cur_drvr->name;
1644a12a97cSAlexander Graf 	diskobj->dev_index = dev_index;
1658c3df0bfSAlexander Graf 	diskobj->offset = offset;
1664a12a97cSAlexander Graf 
1674a12a97cSAlexander Graf 	/* Fill in EFI IO Media info (for read/write callbacks) */
1684a12a97cSAlexander Graf 	diskobj->media.removable_media = desc->removable;
1694a12a97cSAlexander Graf 	diskobj->media.media_present = 1;
1704a12a97cSAlexander Graf 	diskobj->media.block_size = desc->blksz;
1714a12a97cSAlexander Graf 	diskobj->media.io_align = desc->blksz;
1724a12a97cSAlexander Graf 	diskobj->media.last_block = desc->lba;
1734a12a97cSAlexander Graf 	diskobj->ops.media = &diskobj->media;
1744a12a97cSAlexander Graf 
1754a12a97cSAlexander Graf 	/* Fill in device path */
1764a12a97cSAlexander Graf 	dp = (void*)&diskobj[1];
1774a12a97cSAlexander Graf 	diskobj->dp = dp;
1784a12a97cSAlexander Graf 	dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
1794a12a97cSAlexander Graf 	dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
1804a12a97cSAlexander Graf 	dp[0].dp.length = sizeof(*dp);
1814a12a97cSAlexander Graf 	ascii2unicode(dp[0].str, name);
1824a12a97cSAlexander Graf 
1834a12a97cSAlexander Graf 	dp[1].dp.type = DEVICE_PATH_TYPE_END;
1844a12a97cSAlexander Graf 	dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END;
1854a12a97cSAlexander Graf 	dp[1].dp.length = sizeof(*dp);
1864a12a97cSAlexander Graf 
1874a12a97cSAlexander Graf 	/* Hook up to the device list */
1884a12a97cSAlexander Graf 	list_add_tail(&diskobj->parent.link, &efi_obj_list);
1894a12a97cSAlexander Graf }
1904a12a97cSAlexander Graf 
1918c3df0bfSAlexander Graf static int efi_disk_create_eltorito(struct blk_desc *desc,
1928c3df0bfSAlexander Graf 				    const struct block_drvr *cur_drvr,
1938c3df0bfSAlexander Graf 				    int diskid)
1948c3df0bfSAlexander Graf {
1958c3df0bfSAlexander Graf 	int disks = 0;
1968c3df0bfSAlexander Graf #ifdef CONFIG_ISO_PARTITION
197*ecbe1a07SAlexander Graf 	char devname[32] = { 0 }; /* dp->str is u16[32] long */
1988c3df0bfSAlexander Graf 	disk_partition_t info;
1998c3df0bfSAlexander Graf 	int part = 1;
2008c3df0bfSAlexander Graf 
2018c3df0bfSAlexander Graf 	if (desc->part_type != PART_TYPE_ISO)
2028c3df0bfSAlexander Graf 		return 0;
2038c3df0bfSAlexander Graf 
2048c3df0bfSAlexander Graf 	while (!part_get_info(desc, part, &info)) {
2058c3df0bfSAlexander Graf 		snprintf(devname, sizeof(devname), "%s%d:%d", cur_drvr->name,
2068c3df0bfSAlexander Graf 			 diskid, part);
2078c3df0bfSAlexander Graf 		efi_disk_add_dev(devname, cur_drvr, desc, diskid, info.start);
2088c3df0bfSAlexander Graf 		part++;
2098c3df0bfSAlexander Graf 		disks++;
2108c3df0bfSAlexander Graf 	}
2118c3df0bfSAlexander Graf #endif
2128c3df0bfSAlexander Graf 
2138c3df0bfSAlexander Graf 	return disks;
2148c3df0bfSAlexander Graf }
2158c3df0bfSAlexander Graf 
2162a22d05dSAlexander Graf /*
2172a22d05dSAlexander Graf  * U-Boot doesn't have a list of all online disk devices. So when running our
2182a22d05dSAlexander Graf  * EFI payload, we scan through all of the potentially available ones and
2192a22d05dSAlexander Graf  * store them in our object pool.
2202a22d05dSAlexander Graf  *
2212a22d05dSAlexander Graf  * This gets called from do_bootefi_exec().
2222a22d05dSAlexander Graf  */
2232a22d05dSAlexander Graf int efi_disk_register(void)
2242a22d05dSAlexander Graf {
2252a22d05dSAlexander Graf 	const struct block_drvr *cur_drvr;
2262a22d05dSAlexander Graf 	int i;
2272a22d05dSAlexander Graf 	int disks = 0;
2282a22d05dSAlexander Graf 
2292a22d05dSAlexander Graf 	/* Search for all available disk devices */
2302a22d05dSAlexander Graf 	for (cur_drvr = block_drvr; cur_drvr->name; cur_drvr++) {
2312a22d05dSAlexander Graf 		printf("Scanning disks on %s...\n", cur_drvr->name);
2322a22d05dSAlexander Graf 		for (i = 0; i < 4; i++) {
2332a22d05dSAlexander Graf 			struct blk_desc *desc;
234*ecbe1a07SAlexander Graf 			char devname[32] = { 0 }; /* dp->str is u16[32] long */
2352a22d05dSAlexander Graf 
2362a22d05dSAlexander Graf 			desc = blk_get_dev(cur_drvr->name, i);
2372a22d05dSAlexander Graf 			if (!desc)
2382a22d05dSAlexander Graf 				continue;
2392a22d05dSAlexander Graf 			if (desc->type == DEV_TYPE_UNKNOWN)
2402a22d05dSAlexander Graf 				continue;
2412a22d05dSAlexander Graf 
2422a22d05dSAlexander Graf 			snprintf(devname, sizeof(devname), "%s%d",
2432a22d05dSAlexander Graf 				 cur_drvr->name, i);
2444a12a97cSAlexander Graf 			efi_disk_add_dev(devname, cur_drvr, desc, i, 0);
2452a22d05dSAlexander Graf 			disks++;
2468c3df0bfSAlexander Graf 
2478c3df0bfSAlexander Graf 			/*
2488c3df0bfSAlexander Graf 			 * El Torito images show up as block devices
2498c3df0bfSAlexander Graf 			 * in an EFI world, so let's create them here
2508c3df0bfSAlexander Graf 			 */
2518c3df0bfSAlexander Graf 			disks += efi_disk_create_eltorito(desc, cur_drvr, i);
2522a22d05dSAlexander Graf 		}
2532a22d05dSAlexander Graf 	}
2542a22d05dSAlexander Graf 	printf("Found %d disks\n", disks);
2552a22d05dSAlexander Graf 
2562a22d05dSAlexander Graf 	return 0;
2572a22d05dSAlexander Graf }
258