Files
u-boot/cmd/part_find.c
Simon Glass 1137ab205f cmd: Refactor part_find() into separate functions
This function uses #ifdefs and ends up with a very large indent, Split
it into two separate functions, one for the EFI app and one for other
builds.

Drop the use of config.h while we are here.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-09-25 09:47:09 -06:00

191 lines
4.7 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Aurora Innovation, Inc. Copyright 2022.
*
*/
#include <blk.h>
#include <command.h>
#include <dm.h>
#include <env.h>
#include <part.h>
#include <efi.h>
#include <efi_api.h>
static bool partition_is_on_device(const struct efi_device_path *device,
const struct efi_device_path *part,
__u32 *part_no)
{
size_t d_len, p_len;
const struct efi_device_path *p, *d;
for (d = device; d->type != DEVICE_PATH_TYPE_END; d = (void *)d + d->length) {
}
d_len = (void *)d - (void *)device;
for (p = part; p->type != DEVICE_PATH_TYPE_END &&
!(p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH);
p = (void *)p + p->length) {
}
if (p->type != DEVICE_PATH_TYPE_MEDIA_DEVICE ||
p->sub_type != DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
// Not a partition.
return false;
}
p_len = (void *)p - (void *)part;
if (p_len == d_len && !memcmp(device, part, p_len)) {
if (part_no)
*part_no = ((__u32 *)p)[1];
return true;
}
return false;
}
/**
* part_self_find() - Check if a device contains the loaded-image path
*
* @udev: Block device to check
* @loaded_image_path: EFI path of the loaded image
* Return 0 if found, -ENOENT if not, other -ve value on error
*/
static int part_self_find(struct udevice *udev,
struct efi_device_path *loaded_image_path)
{
struct blk_desc *desc = dev_get_uclass_plat(udev);
if (desc->uclass_id == UCLASS_EFI_MEDIA) {
struct efi_media_plat *plat = dev_get_plat(udev->parent);
u32 loader_part_no;
if (partition_is_on_device(plat->device_path, loaded_image_path,
&loader_part_no)) {
char env[256];
int ret;
ret = snprintf(env, sizeof(env), "%s %x:%x",
blk_get_uclass_name(desc->uclass_id),
desc->devnum, loader_part_no);
if (ret < 0 || ret == sizeof(env))
return -ENOSPC;
if (env_set("target_part", env))
return -ENOMEM;
return 0;
}
}
return -ENOENT;
}
/**
* part_blk_find() - Check if a device contains a partition with a type uuid
*
* @udev: Block device to check
* @uuid: UUID to search for (in string form)
* Return 0 if found, -ENOENT if not, other -ve value on error
*/
static int part_blk_find(struct udevice *udev, const char *uuid)
{
struct blk_desc *desc = dev_get_uclass_plat(udev);
int i;
for (i = 1; i <= MAX_SEARCH_PARTITIONS; i++) {
struct disk_partition info;
int ret;
ret = part_get_info(desc, i, &info);
if (ret)
break;
if (strcasecmp(uuid, info.type_guid) == 0) {
char env[256];
ret = snprintf(env, sizeof(env), "%s %x:%x",
blk_get_uclass_name(desc->uclass_id),
desc->devnum, i);
if (ret < 0 || ret == sizeof(env))
return -ENOSPC;
debug("Setting target_part to %s\n", env);
if (env_set("target_part", env))
return -ENOMEM;
return 0;
}
}
return -ENOENT;
}
static int part_find(int argc, char *const argv[])
{
efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
struct efi_device_path *loaded_image_path = NULL;
bool part_self = false;
struct driver *d = ll_entry_start(struct driver, driver);
const int n_ents = ll_entry_count(struct driver, driver);
struct driver *entry;
struct udevice *udev;
struct uclass *uc;
int ret;
if (argc != 2)
return CMD_RET_USAGE;
if (IS_ENABLED(CONFIG_EFI_CLIENT)) {
struct efi_boot_services *boot = efi_get_boot();
struct efi_priv *priv = efi_get_priv();
part_self = !strncmp(argv[1], "self", 6);
if (part_self) {
ret = boot->handle_protocol(priv->loaded_image->device_handle,
&efi_devpath_guid,
(void **)&loaded_image_path);
if (ret)
log_warning("failed to get device path for loaded image (ret=%d)",
ret);
}
}
ret = uclass_get(UCLASS_BLK, &uc);
if (ret) {
puts("Could not get BLK uclass.\n");
return CMD_RET_FAILURE;
}
for (entry = d; entry < d + n_ents; entry++) {
if (entry->id != UCLASS_BLK)
continue;
uclass_foreach_dev(udev, uc) {
if (udev->driver != entry)
continue;
if (IS_ENABLED(CONFIG_EFI_CLIENT) && part_self)
ret = part_self_find(udev, loaded_image_path);
else
ret = part_blk_find(udev, argv[1]);
if (!ret)
return 0;
if (ret != -ENOENT)
break;
}
}
return CMD_RET_FAILURE;
}
static int do_part_find(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
return part_find(argc, argv);
}
U_BOOT_CMD(
part_find, 2, 0, do_part_find, "Find a partition",
"<guid>\n"
"- Examine the list of known partitions for one that has a type\n"
" GUID that matches 'guid', expressed in the standard text format.\n"
" If successful, the target_part environment variable will be set\n"
" to the corresponding 'interface dev:part'.\n"
);