Date: Thu, 26 May 2016 21:43:22 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r300780 - in head/sys/boot/efi: include libefi Message-ID: <201605262143.u4QLhMRq035850@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhb Date: Thu May 26 21:43:22 2016 New Revision: 300780 URL: https://svnweb.freebsd.org/changeset/base/300780 Log: Add some routines for working with EFI DEVICE_PATH objects. - efi_lookup_devpath() uses the DEVICE_PATH_PROTOCOL to obtain the DEVICE_PATH for a given EFI handle. - efi_lookup_image_devpath() uses the LOADED_IMAGE_DEVICE_PATH_PROTOCOL to lookup the device path of the device used to load a loaded image. - efi_devpath_name() uses the DEVICE_PATH_TO_TEXT_PROTOCOL to generate a string description of a device path. The returned string is a CHAR16 string that can be printed via the recently added '%S' format in libstand's printf(). Note that the returned string is returned in allocated storage that should be freed by calling efi_free_devpath_name(). - efi_devpath_last_node() walks a DEVICE_PATH returning a pointer to the final node in the path (not counting the terminating node). That is, it returns a pointer to the last meaninful node in a DEVICE_PATH. - efi_devpath_trim() generates a new DEVICE_PATH from an existing DEVICE_PATH. The new DEVICE_PATH does not include the last non-terminating node in the original path. If the original DEVICE_PATH only contains the terminating node, this function returns NULL. The caller is responsible for freeing the returned DEVICE_PATH via free(). - efi_devpath_handle() attempts to find a handle that corresponds to a given device path. However, if nodes at the end of the device path do not have valid handles associated with them, this function will return a handle that matches a node earlier in the device path. In particular, this function returns a handle for the node closest to the end of the device path which has a valid handle. Sponsored by: Cisco Systems Added: head/sys/boot/efi/libefi/devpath.c (contents, props changed) Modified: head/sys/boot/efi/include/efilib.h head/sys/boot/efi/libefi/Makefile Modified: head/sys/boot/efi/include/efilib.h ============================================================================== --- head/sys/boot/efi/include/efilib.h Thu May 26 21:40:13 2016 (r300779) +++ head/sys/boot/efi/include/efilib.h Thu May 26 21:43:22 2016 (r300780) @@ -45,6 +45,14 @@ EFI_HANDLE efi_find_handle(struct devsw int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *, uint64_t *); int efi_handle_update_dev(EFI_HANDLE, struct devsw *, int, uint64_t); +EFI_DEVICE_PATH *efi_lookup_image_devpath(EFI_HANDLE); +EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE); +EFI_HANDLE efi_devpath_handle(EFI_DEVICE_PATH *); +EFI_DEVICE_PATH *efi_devpath_last_node(EFI_DEVICE_PATH *); +EFI_DEVICE_PATH *efi_devpath_trim(EFI_DEVICE_PATH *); +CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *); +void efi_free_devpath_name(CHAR16 *); + int efi_status_to_errno(EFI_STATUS); EFI_STATUS main(int argc, CHAR16 *argv[]); Modified: head/sys/boot/efi/libefi/Makefile ============================================================================== --- head/sys/boot/efi/libefi/Makefile Thu May 26 21:40:13 2016 (r300779) +++ head/sys/boot/efi/libefi/Makefile Thu May 26 21:43:22 2016 (r300780) @@ -4,8 +4,8 @@ LIB= efi INTERNALLIB= WARNS?= 2 -SRCS= delay.c efi_console.c efinet.c efipart.c env.c errno.c handles.c \ - libefi.c time.c +SRCS= delay.c devpath.c efi_console.c efinet.c efipart.c env.c errno.c \ + handles.c libefi.c time.c .if ${MACHINE_CPUARCH} == "aarch64" CFLAGS+= -msoft-float -mgeneral-regs-only Added: head/sys/boot/efi/libefi/devpath.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/boot/efi/libefi/devpath.c Thu May 26 21:43:22 2016 (r300780) @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 2016 John Baldwin <jhb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <efi.h> +#include <efilib.h> + +/* XXX: This belongs in an efifoo.h header. */ +#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ + { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } + +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } + +INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { + EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; + EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; +} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; + +static EFI_GUID ImageDevicePathGUID = + EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; +static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; +static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; +static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *textProtocol; + +EFI_DEVICE_PATH * +efi_lookup_image_devpath(EFI_HANDLE handle) +{ + EFI_DEVICE_PATH *devpath; + EFI_STATUS status; + + status = BS->HandleProtocol(handle, &ImageDevicePathGUID, + (VOID **)&devpath); + if (EFI_ERROR(status)) + devpath = NULL; + return (devpath); +} + +EFI_DEVICE_PATH * +efi_lookup_devpath(EFI_HANDLE handle) +{ + EFI_DEVICE_PATH *devpath; + EFI_STATUS status; + + status = BS->HandleProtocol(handle, &DevicePathGUID, (VOID **)&devpath); + if (EFI_ERROR(status)) + devpath = NULL; + return (devpath); +} + +CHAR16 * +efi_devpath_name(EFI_DEVICE_PATH *devpath) +{ + static int once = 1; + EFI_STATUS status; + + if (devpath == NULL) + return (NULL); + if (once) { + status = BS->LocateProtocol(&DevicePathToTextGUID, NULL, + (VOID **)&textProtocol); + if (EFI_ERROR(status)) + textProtocol = NULL; + once = 0; + } + if (textProtocol == NULL) + return (NULL); + + return (textProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE)); +} + +void +efi_free_devpath_name(CHAR16 *text) +{ + + BS->FreePool(text); +} + +EFI_DEVICE_PATH * +efi_devpath_last_node(EFI_DEVICE_PATH *devpath) +{ + + if (IsDevicePathEnd(devpath)) + return (NULL); + while (!IsDevicePathEnd(NextDevicePathNode(devpath))) + devpath = NextDevicePathNode(devpath); + return (devpath); +} + +EFI_DEVICE_PATH * +efi_devpath_trim(EFI_DEVICE_PATH *devpath) +{ + EFI_DEVICE_PATH *node, *copy; + size_t prefix, len; + + node = efi_devpath_last_node(devpath); + prefix = (UINT8 *)node - (UINT8 *)devpath; + if (prefix == 0) + return (NULL); + len = prefix + DevicePathNodeLength(NextDevicePathNode(node)); + copy = malloc(len); + memcpy(copy, devpath, prefix); + node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); + SetDevicePathEndNode(node); + return (copy); +} + +EFI_HANDLE +efi_devpath_handle(EFI_DEVICE_PATH *devpath) +{ + EFI_STATUS status; + EFI_HANDLE h; + + /* + * There isn't a standard way to locate a handle for a given + * device path. However, querying the EFI_DEVICE_PATH protocol + * for a given device path should give us a handle for the + * closest node in the path to the end that is valid. + */ + status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h); + if (EFI_ERROR(status)) + return (NULL); + return (h); +}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201605262143.u4QLhMRq035850>