xref: /rk3399_rockchip-uboot/lib/efi_loader/efi_disk.c (revision 4a12a97c14217a5b02791040e464449f779fce43)
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