From c4471e3408d85c51a69991974985fe283d869eac Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 5 Mar 2024 20:00:15 +0000 Subject: [efi] Add efi_path_guid() utility function EFI provides no API for determining the partition GUID (if any) for a specified device handle. The partition GUID appears to be exposed only as part of the device path. Add efi_path_guid() to extract the partition GUID (if any) from a device path. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 2 ++ src/include/ipxe/errfile.h | 1 + src/interface/efi/efi_path.c | 43 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index e75ae42c..20ff43f6 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -20,6 +20,7 @@ struct aoe_device; struct fcp_description; struct ib_srp_device; struct usb_function; +union uuid; /** * Terminate device path @@ -43,6 +44,7 @@ extern EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); extern unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern int efi_path_guid ( EFI_DEVICE_PATH_PROTOCOL *path, union uuid *uuid ); extern EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ); extern EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ); diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7cff594d..1fe34113 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -80,6 +80,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_acpimac ( ERRFILE_CORE | 0x00280000 ) #define ERRFILE_efi_strings ( ERRFILE_CORE | 0x00290000 ) #define ERRFILE_uuid ( ERRFILE_CORE | 0x002a0000 ) +#define ERRFILE_efi_path ( ERRFILE_CORE | 0x002b0000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index a78f97fc..d1e22eea 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -22,9 +22,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include +#include #include #include #include @@ -132,6 +134,47 @@ unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path ) { return 0; } +/** + * Get partition GUID from device path + * + * @v path Device path + * @v guid Partition GUID to fill in + * @ret rc Return status code + */ +int efi_path_guid ( EFI_DEVICE_PATH_PROTOCOL *path, union uuid *guid ) { + EFI_DEVICE_PATH_PROTOCOL *next; + HARDDRIVE_DEVICE_PATH *hd; + int rc; + + /* Search for most specific partition device path */ + rc = -ENOENT; + for ( ; ( next = efi_path_next ( path ) ) ; path = next ) { + + /* Skip non-harddrive device paths */ + if ( path->Type != MEDIA_DEVICE_PATH ) + continue; + if ( path->SubType != MEDIA_HARDDRIVE_DP ) + continue; + + /* Skip non-GUID signatures */ + hd = container_of ( path, HARDDRIVE_DEVICE_PATH, Header ); + if ( hd->SignatureType != SIGNATURE_TYPE_GUID ) + continue; + + /* Extract GUID */ + memcpy ( guid, hd->Signature, sizeof ( *guid ) ); + uuid_mangle ( guid ); + + /* Record success, but continue searching in case + * there exists a more specific GUID (e.g. a partition + * GUID rather than a disk GUID). + */ + rc = 0; + } + + return rc; +} + /** * Concatenate EFI device paths * -- cgit v1.2.3-55-g7522