efi: Add device-path support for EFI media devices

Add proper device-path handling for UCLASS_EFI_MEDIA devices in both
dp_size() and dp_fill() functions. This enables EFI applications to use
firmware device-paths for media devices accessed through the EFI block
I/O protocol.

Add some debugging while we are here.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2025-08-16 13:06:37 -06:00
parent 9a7c744421
commit cea7a888bf

View File

@@ -375,6 +375,10 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
size =
sizeof(struct efi_device_path_controller);
break;
case UCLASS_EFI_MEDIA:
/* EFI app */
size = sizeof(struct efi_device_path_udevice);
break;
default:
/* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
size = sizeof(struct efi_device_path_udevice);
@@ -389,6 +393,9 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
case UCLASS_USB_HUB:
size = sizeof(struct efi_device_path_usb);
break;
case UCLASS_EFI_MEDIA:
size = sizeof(struct efi_device_path_udevice);
break;
default:
size = sizeof(struct efi_device_path_udevice);
break;
@@ -519,6 +526,22 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
return &dp[1];
}
break;
case UCLASS_EFI_MEDIA:
if (IS_ENABLED(CONFIG_EFI_APP)) {
struct efi_device_path_udevice *dp = buf;
struct blk_desc *desc = dev_get_uclass_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
dp->dp.length = sizeof(*dp);
memcpy(&dp->guid, &efi_u_boot_guid, sizeof(efi_guid_t));
dp->uclass_id = (UCLASS_BLK & 0xffff) |
(desc->uclass_id << 16);
dp->dev_number = desc->devnum;
return &dp[1];
}
break;
default: {
/* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
struct efi_device_path_udevice *dp = buf;
@@ -1013,6 +1036,86 @@ out:
return EFI_SUCCESS;
}
/**
* efi_dp_from_efi_app() - create device path for EFI app
*
* Create a device path for EFI applications using firmware device paths
* from EFI media devices
*
* @devnr: device number string (format: "dev:part")
* @descp: pointer to store block device descriptor
* @partp: pointer to store partition number
* @dp: pointer to store created device path
* Return: U-Boot error code (0 on success, negative on error)
*/
static int efi_dp_from_efi_app(const char *devnr,
struct blk_desc **descp, int *partp,
struct efi_device_path **dpp)
{
struct efi_media_plat *plat;
struct efi_device_path *dp;
struct udevice *media_dev;
struct blk_desc *desc;
int part, dev_num;
char *ep;
int ret;
log_debug("using EFI app firmware device path for devnr='%s'\n", devnr);
/* parse device number from devnr (format: "devnum:part") */
dev_num = hextoul(devnr, &ep);
if (*ep != ':') {
log_err("invalid EFI device format: '%s'\n", devnr);
return log_msg_ret("eda", -EINVAL);
}
/* find the EFI media device */
ret = uclass_get_device(UCLASS_EFI_MEDIA, dev_num, &media_dev);
if (ret) {
log_err("cannot find EFI media device %d\n", dev_num);
return log_msg_ret("eda", -ENODEV);
}
plat = dev_get_plat(media_dev);
log_debug("found EFI media device %d with firmware device path: %pD\n",
dev_num, plat->device_path);
/* use the firmware device path and append partition */
part = simple_strtoul(ep + 1, NULL, 16);
if (part > 0) {
struct efi_device_path *part_dp;
struct disk_partition pinfo;
/* Get partition info */
part = blk_get_device_part_str("efi", devnr, &desc, &pinfo, 1);
if (part < 0 || !desc) {
log_err("cannot get partition info for '%s'\n", devnr);
return log_msg_ret("edb", part < 0 ? part : -ENODEV);
}
/* Create partition node */
part_dp = efi_dp_part_node(desc, part);
if (!part_dp)
return log_msg_ret("edn", -ENOMEM);
/* Combine firmware device path with partition */
dp = efi_dp_append_node(plat->device_path, part_dp);
efi_free_pool(part_dp);
} else {
/* Use whole device */
dp = efi_dp_dup(plat->device_path);
}
if (!dp)
return log_msg_ret("ede", -ENOMEM);
log_debug("created final device path: %pD\n", dp);
*descp = desc;
*partp = part;
*dpp = dp;
return 0;
}
/**
* efi_dp_from_name() - convert U-Boot device and file path to device path
*
@@ -1050,11 +1153,22 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
efi_net_dp_from_dev(&dp, eth_get_dev(), false);
} else if (!strcmp(dev, "Uart")) {
dp = efi_dp_from_uart();
} else if (IS_ENABLED(CONFIG_EFI_APP) && !strcmp(dev, "efi")) {
int ret;
ret = efi_dp_from_efi_app(devnr, &desc, &part, &dp);
if (ret)
return EFI_INVALID_PARAMETER;
} else {
log_debug("calling blk_get_device_part_str dev='%s', devnr='%s'\n",
dev, devnr);
part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1);
if (part < 0 || !desc)
if (part < 0 || !desc) {
log_err("Failed to find fs: dev='%s', devnr='%s', part=%d, desc=%p\n",
dev, devnr, part, desc);
return EFI_INVALID_PARAMETER;
}
dp = efi_dp_from_part(desc, part);
}