diff options
author | Michael Brown <mcb30@ipxe.org> | 2023-01-23 19:15:45 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2023-01-23 19:27:13 +0000 |
commit | 2fef0c541e4e2417fc285c4d9ddfcb6f23f394ad (patch) | |
tree | a81c522bfe50ab496e0aa078a95f6cb4e2cbd0ba | |
parent | 1cd0a248cc54a8b2fadc0d2c287d2f3528b749b4 (diff) | |
download | ipxe-2fef0c541e4e2417fc285c4d9ddfcb6f23f394ad.zip ipxe-2fef0c541e4e2417fc285c4d9ddfcb6f23f394ad.tar.gz ipxe-2fef0c541e4e2417fc285c4d9ddfcb6f23f394ad.tar.bz2 |
[efi] Extend efi_locate_device() to allow searching up the device path
Extend the functionality of efi_locate_device() to allow callers to
find instances of the protocol that may exist further up the device
path.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/drivers/net/efi/nii.c | 2 | ||||
-rw-r--r-- | src/drivers/net/efi/snponly.c | 2 | ||||
-rw-r--r-- | src/include/ipxe/efi/efi_utils.h | 2 | ||||
-rw-r--r-- | src/interface/efi/efi_utils.c | 56 |
4 files changed, 45 insertions, 17 deletions
diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index 5d9aea8..be5bce4 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -222,7 +222,7 @@ static int nii_pci_open ( struct nii_nic *nii ) { /* Locate PCI I/O protocol */ if ( ( rc = efi_locate_device ( device, &efi_pci_io_protocol_guid, - &pci_device ) ) != 0 ) { + &pci_device, 0 ) ) != 0 ) { DBGC ( nii, "NII %s could not locate PCI I/O protocol: %s\n", nii->dev.name, strerror ( rc ) ); goto err_locate; diff --git a/src/drivers/net/efi/snponly.c b/src/drivers/net/efi/snponly.c index cb7ea1b..674e0a0 100644 --- a/src/drivers/net/efi/snponly.c +++ b/src/drivers/net/efi/snponly.c @@ -80,7 +80,7 @@ static int chained_locate ( struct chained_protocol *chained ) { /* Locate handle supporting this protocol */ if ( ( rc = efi_locate_device ( device, chained->protocol, - &parent ) ) != 0 ) { + &parent, 0 ) ) != 0 ) { DBGC ( device, "CHAINED %s does not support %s: %s\n", efi_handle_name ( device ), efi_guid_ntoa ( chained->protocol ), strerror ( rc ) ); diff --git a/src/include/ipxe/efi/efi_utils.h b/src/include/ipxe/efi/efi_utils.h index 270d38d..98659b1 100644 --- a/src/include/ipxe/efi/efi_utils.h +++ b/src/include/ipxe/efi/efi_utils.h @@ -13,7 +13,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); struct device; extern int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol, - EFI_HANDLE *parent ); + EFI_HANDLE *parent, unsigned int skip ); extern int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ); extern void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ); extern void efi_device_info ( EFI_HANDLE device, const char *prefix, diff --git a/src/interface/efi/efi_utils.c b/src/interface/efi/efi_utils.c index 8e660e9..53f82bf 100644 --- a/src/interface/efi/efi_utils.c +++ b/src/interface/efi/efi_utils.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <string.h> #include <errno.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_path.h> #include <ipxe/efi/efi_pci.h> #include <ipxe/efi/efi_utils.h> @@ -38,23 +39,26 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v device EFI device handle * @v protocol Protocol GUID * @v parent Parent EFI device handle to fill in + * @v skip Number of protocol-supporting parent devices to skip * @ret rc Return status code */ int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol, - EFI_HANDLE *parent ) { + EFI_HANDLE *parent, unsigned int skip ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { EFI_DEVICE_PATH_PROTOCOL *path; void *interface; - } path; - EFI_DEVICE_PATH_PROTOCOL *devpath; + } u; + EFI_DEVICE_PATH_PROTOCOL *path; + EFI_DEVICE_PATH_PROTOCOL *end; + size_t len; EFI_STATUS efirc; int rc; /* Get device path */ if ( ( efirc = bs->OpenProtocol ( device, &efi_device_path_protocol_guid, - &path.interface, + &u.interface, efi_image_handle, device, EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ rc = -EEFI ( efirc ); @@ -62,22 +66,46 @@ int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol, efi_handle_name ( device ), strerror ( rc ) ); goto err_open_device_path; } - devpath = path.path; - /* Check for presence of specified protocol */ - if ( ( efirc = bs->LocateDevicePath ( protocol, &devpath, - parent ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( device, "EFIDEV %s has no parent supporting %s: %s\n", - efi_handle_name ( device ), - efi_guid_ntoa ( protocol ), strerror ( rc ) ); - goto err_locate_protocol; + /* Create modifiable copy of device path */ + len = ( efi_path_len ( u.path ) + sizeof ( EFI_DEVICE_PATH_PROTOCOL )); + path = malloc ( len ); + if ( ! path ) { + rc = -ENOMEM; + goto err_alloc_path; + } + memcpy ( path, u.path, len ); + + /* Locate parent device(s) */ + while ( 1 ) { + + /* Check for presence of specified protocol */ + end = path; + if ( ( efirc = bs->LocateDevicePath ( protocol, &end, + parent ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFIDEV %s has no parent supporting " + "%s: %s\n", efi_devpath_text ( path ), + efi_guid_ntoa ( protocol ), strerror ( rc ) ); + goto err_locate_protocol; + } + + /* Stop if we have skipped the requested number of devices */ + if ( ! skip-- ) + break; + + /* Trim device path */ + efi_path_terminate ( end ); + end = efi_path_prev ( path, end ); + efi_path_terminate ( end ); } /* Success */ rc = 0; err_locate_protocol: + free ( path ); + err_alloc_path: bs->CloseProtocol ( device, &efi_device_path_protocol_guid, efi_image_handle, device ); err_open_device_path: @@ -150,7 +178,7 @@ static int efi_pci_info ( EFI_HANDLE device, const char *prefix, /* Find parent PCI device */ if ( ( rc = efi_locate_device ( device, &efi_pci_io_protocol_guid, - &pci_device ) ) != 0 ) { + &pci_device, 0 ) ) != 0 ) { DBGC ( device, "EFIDEV %s is not a PCI device: %s\n", efi_handle_name ( device ), strerror ( rc ) ); return rc; |