From 099e4d39b355a10b0bc7d23bb0e96615bf06470b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Dec 2022 13:33:38 +0000 Subject: [efi] Expose efi_path_next() utility function Provide a single central implementation of the logic for stepping through elements of an EFI device path. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 2 ++ src/interface/efi/efi_local.c | 20 ++++++++++---------- src/interface/efi/efi_path.c | 34 +++++++++++++++++++++++++++++----- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 76ded72..18810a7 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -22,6 +22,8 @@ struct ib_srp_device; struct usb_function; extern EFI_DEVICE_PATH_PROTOCOL * +efi_path_next ( EFI_DEVICE_PATH_PROTOCOL *path ); +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 EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, diff --git a/src/interface/efi/efi_local.c b/src/interface/efi/efi_local.c index d8edb62..f54f5da 100644 --- a/src/interface/efi/efi_local.c +++ b/src/interface/efi/efi_local.c @@ -419,14 +419,15 @@ static int efi_local_open_resolved ( struct efi_local *local, * Open specified path * * @v local Local file - * @v path Path to file + * @v filename Path to file relative to our own image * @ret rc Return status code */ -static int efi_local_open_path ( struct efi_local *local, const char *path ) { - FILEPATH_DEVICE_PATH *fp = container_of ( efi_loaded_image->FilePath, - FILEPATH_DEVICE_PATH, Header); - size_t fp_len = efi_path_len ( &fp->Header ); - char base[ fp_len / 2 /* Cannot exceed this length */ ]; +static int efi_local_open_path ( struct efi_local *local, + const char *filename ) { + EFI_DEVICE_PATH_PROTOCOL *path = efi_loaded_image->FilePath; + EFI_DEVICE_PATH_PROTOCOL *next; + FILEPATH_DEVICE_PATH *fp; + char base[ efi_path_len ( path ) / 2 /* Cannot exceed this length */ ]; size_t remaining = sizeof ( base ); size_t len; char *resolved; @@ -436,13 +437,12 @@ static int efi_local_open_path ( struct efi_local *local, const char *path ) { /* Construct base path to our own image, if possible */ memset ( base, 0, sizeof ( base ) ); tmp = base; - while ( fp && ( fp->Header.Type != END_DEVICE_PATH_TYPE ) ) { + for ( ; ( next = efi_path_next ( path ) ) ; path = next ) { + fp = container_of ( path, FILEPATH_DEVICE_PATH, Header ); len = snprintf ( tmp, remaining, "%ls", fp->PathName ); assert ( len < remaining ); tmp += len; remaining -= len; - fp = ( ( ( void * ) fp ) + ( ( fp->Header.Length[1] << 8 ) | - fp->Header.Length[0] ) ); } DBGC2 ( local, "LOCAL %p base path \"%s\"\n", local, base ); @@ -454,7 +454,7 @@ static int efi_local_open_path ( struct efi_local *local, const char *path ) { } /* Resolve path */ - resolved = resolve_path ( base, path ); + resolved = resolve_path ( base, filename ); if ( ! resolved ) { rc = -ENOMEM; goto err_resolve; diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 1a95a3b..937d3c7 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -41,18 +41,42 @@ */ /** + * Find next element in device path + * + * @v path Device path, or NULL + * @v next Next element in device path, or NULL if at end + */ +EFI_DEVICE_PATH_PROTOCOL * efi_path_next ( EFI_DEVICE_PATH_PROTOCOL *path ) { + + /* Check for non-existent device path */ + if ( ! path ) + return NULL; + + /* Check for end of device path */ + if ( path->Type == END_DEVICE_PATH_TYPE ) + return NULL; + + /* Move to next component of the device path */ + path = ( ( ( void * ) path ) + + /* There's this amazing new-fangled thing known as + * a UINT16, but who wants to use one of those? */ + ( ( path->Length[1] << 8 ) | path->Length[0] ) ); + + return path; +} + +/** * Find end of device path * * @v path Device path, or NULL * @ret path_end End of device path, or NULL */ EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { + EFI_DEVICE_PATH_PROTOCOL *next; - while ( path && ( path->Type != END_DEVICE_PATH_TYPE ) ) { - path = ( ( ( void * ) path ) + - /* There's this amazing new-fangled thing known as - * a UINT16, but who wants to use one of those? */ - ( ( path->Length[1] << 8 ) | path->Length[0] ) ); + /* Find end of device path */ + while ( ( next = efi_path_next ( path ) ) != NULL ) { + path = next; } return path; -- cgit v1.1