From 0f3ace92c6f7bd60a6688c0bacfa5aeacfdb5b73 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Dec 2022 13:28:06 +0000 Subject: [efi] Allow passing a NULL device path to path utility functions Signed-off-by: Michael Brown --- src/interface/efi/efi_path.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/interface/efi/efi_path.c') diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index bae0ac4b5..1a95a3b9a 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -43,12 +43,12 @@ /** * Find end of device path * - * @v path Path to device - * @ret path_end 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 ) { - while ( path->Type != END_DEVICE_PATH_TYPE ) { + 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? */ @@ -61,7 +61,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { /** * Find length of device path (excluding terminator) * - * @v path Path to device + * @v path Device path, or NULL * @ret path_len Length of device path */ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { -- cgit v1.2.3-55-g7522 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(-) (limited to 'src/interface/efi/efi_path.c') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 76ded728c..18810a751 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -21,6 +21,8 @@ struct fcp_description; 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 ); diff --git a/src/interface/efi/efi_local.c b/src/interface/efi/efi_local.c index d8edb6263..f54f5daea 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 1a95a3b9a..937d3c704 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -40,6 +40,31 @@ * */ +/** + * 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 * @@ -47,12 +72,11 @@ * @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.2.3-55-g7522 From b9571ca12ed80472051663e2618dfe083f995da3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Dec 2022 14:27:56 +0000 Subject: [efi] Add efi_path_vlan() utility function EFI provides no API for determining the VLAN tag (if any) for a specified device handle. There is the EFI_VLAN_CONFIG_PROTOCOL, but that exists only on the trunk device handle (not on the VLAN device handle), and provides no way to match VLAN tags against the trunk device's child device handles. The EDK2 codebase seems to rely solely on the device path to determine the VLAN tag for a specified device handle: both NetLibGetVlanId() and BmGetNetworkDescription() will parse the device path to search for a VLAN_DEVICE_PATH component. Add efi_path_vlan() which uses the same device path parsing logic to determine the VLAN tag. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 1 + src/interface/efi/efi_path.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'src/interface/efi/efi_path.c') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 18810a751..9dea74b5a 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -26,6 +26,7 @@ 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 unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path ); 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/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 937d3c704..fb0f3059d 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -94,6 +94,29 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { return ( ( ( void * ) end ) - ( ( void * ) path ) ); } +/** + * Get VLAN tag from device path + * + * @v path Device path + * @ret tag VLAN tag, or 0 if not a VLAN + */ +unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path ) { + EFI_DEVICE_PATH_PROTOCOL *next; + VLAN_DEVICE_PATH *vlan; + + /* Search for VLAN device path */ + for ( ; ( next = efi_path_next ( path ) ) ; path = next ) { + if ( ( path->Type == MESSAGING_DEVICE_PATH ) && + ( path->SubType == MSG_VLAN_DP ) ) { + vlan = container_of ( path, VLAN_DEVICE_PATH, Header ); + return vlan->VlanId; + } + } + + /* No VLAN device path found */ + return 0; +} + /** * Concatenate EFI device paths * -- cgit v1.2.3-55-g7522 From 204d39222a0ff9f91fdffc2809de0b7f5aaabbae Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Jan 2023 19:07:35 +0000 Subject: [efi] Add efi_path_terminate() utility function Signed-off-by: Michael Brown --- src/image/efi_image.c | 4 +--- src/include/ipxe/efi/efi_path.h | 13 +++++++++++++ src/interface/efi/efi_block.c | 4 +--- src/interface/efi/efi_path.c | 32 ++++++++------------------------ src/interface/efi/efi_snp_hii.c | 4 +--- 5 files changed, 24 insertions(+), 33 deletions(-) (limited to 'src/interface/efi/efi_path.c') diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 3c98decbf..66a19524b 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -96,9 +96,7 @@ efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) { efi_snprintf ( filepath->PathName, ( name_len + 1 /* NUL */ ), "%s", image->name ); end = ( ( ( void * ) filepath ) + filepath_len ); - end->Type = END_DEVICE_PATH_TYPE; - end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - end->Length[0] = sizeof ( *end ); + efi_path_terminate ( end ); return path; } diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 9dea74b5a..98b922ac1 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -21,6 +21,19 @@ struct fcp_description; struct ib_srp_device; struct usb_function; +/** + * Terminate device path + * + * @v end End of device path to fill in + */ +static inline void efi_path_terminate ( EFI_DEVICE_PATH_PROTOCOL *end ) { + + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + end->Length[1] = 0; +} + extern EFI_DEVICE_PATH_PROTOCOL * efi_path_next ( EFI_DEVICE_PATH_PROTOCOL *path ); extern EFI_DEVICE_PATH_PROTOCOL * diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 74cf7c0c0..cb73260d5 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -582,9 +582,7 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, sizeof ( efi_block_boot_filename ) ); } end = ( ( ( void * ) filepath ) + filepath_len ); - end->Type = END_DEVICE_PATH_TYPE; - end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - end->Length[0] = sizeof ( *end ); + efi_path_terminate ( end ); DBGC ( sandev, "EFIBLK %#02x trying to load %s\n", sandev->drive, efi_devpath_text ( boot_path ) ); diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index fb0f3059d..50027b75a 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -161,9 +161,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ) { } va_end ( args ); end = dst; - end->Type = END_DEVICE_PATH_TYPE; - end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - end->Length[0] = sizeof ( *end ); + efi_path_terminate ( end ); return path; } @@ -223,9 +221,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ) { } else { end = ( ( ( void * ) macpath ) + sizeof ( *macpath ) ); } - end->Type = END_DEVICE_PATH_TYPE; - end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - end->Length[0] = sizeof ( *end ); + efi_path_terminate ( end ); return path; } @@ -265,9 +261,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ) { uripath->Header.Length[1] = ( uripath_len >> 8 ); format_uri ( uri, uripath->Uri, uri_len ); end = ( ( ( void * ) path ) + uripath_len ); - end->Type = END_DEVICE_PATH_TYPE; - end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - end->Length[0] = sizeof ( *end ); + efi_path_terminate ( end ); return path; } @@ -324,9 +318,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_iscsi_path ( struct iscsi_session *iscsi ) { name = ( ( ( void * ) iscsipath ) + sizeof ( *iscsipath ) ); memcpy ( name, iscsi->target_iqn, name_len ); end = ( ( ( void * ) name ) + name_len ); - end->Type = END_DEVICE_PATH_TYPE; - end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - end->Length[0] = sizeof ( *end ); + efi_path_terminate ( end ); /* Free temporary paths */ free ( netpath ); @@ -366,9 +358,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_aoe_path ( struct aoe_device *aoedev ) { satapath.sata.Header.Length[0] = sizeof ( satapath.sata ); satapath.sata.HBAPortNumber = aoedev->major; satapath.sata.PortMultiplierPortNumber = aoedev->minor; - satapath.end.Type = END_DEVICE_PATH_TYPE; - satapath.end.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - satapath.end.Length[0] = sizeof ( satapath.end ); + efi_path_terminate ( &satapath.end ); /* Construct overall device path */ path = efi_paths ( netpath, &satapath, NULL ); @@ -409,9 +399,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_fcp_path ( struct fcp_description *desc ) { path->fc.Header.Length[0] = sizeof ( path->fc ); memcpy ( path->fc.WWN, &desc->wwn, sizeof ( path->fc.WWN ) ); memcpy ( path->fc.Lun, &desc->lun, sizeof ( path->fc.Lun ) ); - path->end.Type = END_DEVICE_PATH_TYPE; - path->end.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - path->end.Length[0] = sizeof ( path->end ); + efi_path_terminate ( &path->end ); return &path->fc.Header; } @@ -463,9 +451,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_ib_srp_path ( struct ib_srp_device *ib_srp ) { memcpy ( &ibpath->DeviceId, &id->ib.id_ext, sizeof ( ibpath->DeviceId ) ); end = ( ( ( void * ) ibpath ) + sizeof ( *ibpath ) ); - end->Type = END_DEVICE_PATH_TYPE; - end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - end->Length[0] = sizeof ( *end ); + efi_path_terminate ( end ); return path; } @@ -511,9 +497,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ) { /* Construct device path */ memcpy ( path, efidev->path, prefix_len ); end = ( ( ( void * ) path ) + len - sizeof ( *end ) ); - end->Type = END_DEVICE_PATH_TYPE; - end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - end->Length[0] = sizeof ( *end ); + efi_path_terminate ( end ); usbpath = ( ( ( void * ) end ) - sizeof ( *usbpath ) ); usbpath->InterfaceNumber = func->interface[0]; for ( ; usb ; usbpath--, usb = usb->port->hub->usb ) { diff --git a/src/interface/efi/efi_snp_hii.c b/src/interface/efi/efi_snp_hii.c index 5d5f80cd7..8b65c8a78 100644 --- a/src/interface/efi/efi_snp_hii.c +++ b/src/interface/efi/efi_snp_hii.c @@ -704,9 +704,7 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { vendor_path->Header.Length[0] = sizeof ( *vendor_path ); efi_snp_hii_random_guid ( &vendor_path->Guid ); path_end = ( ( void * ) ( vendor_path + 1 ) ); - path_end->Type = END_DEVICE_PATH_TYPE; - path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - path_end->Length[0] = sizeof ( *path_end ); + efi_path_terminate ( path_end ); /* Create device path and child handle for HII association */ if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( -- cgit v1.2.3-55-g7522 From 1cd0a248cc54a8b2fadc0d2c287d2f3528b749b4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Jan 2023 19:12:49 +0000 Subject: [efi] Add efi_path_prev() utility function Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 3 +++ src/interface/efi/efi_path.c | 27 ++++++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'src/interface/efi/efi_path.c') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 98b922ac1..e75ae42c4 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -37,6 +37,9 @@ static inline void efi_path_terminate ( EFI_DEVICE_PATH_PROTOCOL *end ) { extern EFI_DEVICE_PATH_PROTOCOL * efi_path_next ( EFI_DEVICE_PATH_PROTOCOL *path ); extern EFI_DEVICE_PATH_PROTOCOL * +efi_path_prev ( EFI_DEVICE_PATH_PROTOCOL *path, + EFI_DEVICE_PATH_PROTOCOL *curr ); +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 ); diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 50027b75a..b28ecddbb 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -65,6 +65,25 @@ EFI_DEVICE_PATH_PROTOCOL * efi_path_next ( EFI_DEVICE_PATH_PROTOCOL *path ) { return path; } +/** + * Find previous element of device path + * + * @v path Device path, or NULL for no path + * @v curr Current element in device path, or NULL for end of path + * @ret prev Previous element in device path, or NULL + */ +EFI_DEVICE_PATH_PROTOCOL * efi_path_prev ( EFI_DEVICE_PATH_PROTOCOL *path, + EFI_DEVICE_PATH_PROTOCOL *curr ) { + EFI_DEVICE_PATH_PROTOCOL *tmp; + + /* Find immediately preceding element */ + while ( ( tmp = efi_path_next ( path ) ) != curr ) { + path = tmp; + } + + return path; +} + /** * Find end of device path * @@ -72,14 +91,8 @@ EFI_DEVICE_PATH_PROTOCOL * efi_path_next ( EFI_DEVICE_PATH_PROTOCOL *path ) { * @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; - /* Find end of device path */ - while ( ( next = efi_path_next ( path ) ) != NULL ) { - path = next; - } - - return path; + return efi_path_prev ( path, NULL ); } /** -- cgit v1.2.3-55-g7522 From 5220bdc5242877d8d6d457b5f4f6f5f3da78a833 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 28 Jan 2023 17:15:16 +0000 Subject: [legal] Add missing FILE_LICENCE declaration to efi_path.c Signed-off-by: Michael Brown --- src/interface/efi/efi_path.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/interface/efi/efi_path.c') diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index b28ecddbb..a78f97fce 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -17,6 +17,8 @@ * 02110-1301, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include #include #include -- cgit v1.2.3-55-g7522