devpath.c revision 303975
1/*- 2 * Copyright (c) 2016 John Baldwin <jhb@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: releng/11.0/sys/boot/efi/libefi/devpath.c 300780 2016-05-26 21:43:22Z jhb $"); 29 30#include <efi.h> 31#include <efilib.h> 32 33/* XXX: This belongs in an efifoo.h header. */ 34#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ 35 { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } 36 37#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ 38 { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } 39 40INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); 41 42typedef 43CHAR16* 44(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( 45 IN struct _EFI_DEVICE_PATH *This, 46 IN BOOLEAN DisplayOnly, 47 IN BOOLEAN AllowShortCuts 48 ); 49 50typedef 51CHAR16* 52(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( 53 IN struct _EFI_DEVICE_PATH *This, 54 IN BOOLEAN DisplayOnly, 55 IN BOOLEAN AllowShortCuts 56 ); 57 58typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { 59 EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; 60 EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; 61} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; 62 63static EFI_GUID ImageDevicePathGUID = 64 EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; 65static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 66static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; 67static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *textProtocol; 68 69EFI_DEVICE_PATH * 70efi_lookup_image_devpath(EFI_HANDLE handle) 71{ 72 EFI_DEVICE_PATH *devpath; 73 EFI_STATUS status; 74 75 status = BS->HandleProtocol(handle, &ImageDevicePathGUID, 76 (VOID **)&devpath); 77 if (EFI_ERROR(status)) 78 devpath = NULL; 79 return (devpath); 80} 81 82EFI_DEVICE_PATH * 83efi_lookup_devpath(EFI_HANDLE handle) 84{ 85 EFI_DEVICE_PATH *devpath; 86 EFI_STATUS status; 87 88 status = BS->HandleProtocol(handle, &DevicePathGUID, (VOID **)&devpath); 89 if (EFI_ERROR(status)) 90 devpath = NULL; 91 return (devpath); 92} 93 94CHAR16 * 95efi_devpath_name(EFI_DEVICE_PATH *devpath) 96{ 97 static int once = 1; 98 EFI_STATUS status; 99 100 if (devpath == NULL) 101 return (NULL); 102 if (once) { 103 status = BS->LocateProtocol(&DevicePathToTextGUID, NULL, 104 (VOID **)&textProtocol); 105 if (EFI_ERROR(status)) 106 textProtocol = NULL; 107 once = 0; 108 } 109 if (textProtocol == NULL) 110 return (NULL); 111 112 return (textProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE)); 113} 114 115void 116efi_free_devpath_name(CHAR16 *text) 117{ 118 119 BS->FreePool(text); 120} 121 122EFI_DEVICE_PATH * 123efi_devpath_last_node(EFI_DEVICE_PATH *devpath) 124{ 125 126 if (IsDevicePathEnd(devpath)) 127 return (NULL); 128 while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 129 devpath = NextDevicePathNode(devpath); 130 return (devpath); 131} 132 133EFI_DEVICE_PATH * 134efi_devpath_trim(EFI_DEVICE_PATH *devpath) 135{ 136 EFI_DEVICE_PATH *node, *copy; 137 size_t prefix, len; 138 139 node = efi_devpath_last_node(devpath); 140 prefix = (UINT8 *)node - (UINT8 *)devpath; 141 if (prefix == 0) 142 return (NULL); 143 len = prefix + DevicePathNodeLength(NextDevicePathNode(node)); 144 copy = malloc(len); 145 memcpy(copy, devpath, prefix); 146 node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); 147 SetDevicePathEndNode(node); 148 return (copy); 149} 150 151EFI_HANDLE 152efi_devpath_handle(EFI_DEVICE_PATH *devpath) 153{ 154 EFI_STATUS status; 155 EFI_HANDLE h; 156 157 /* 158 * There isn't a standard way to locate a handle for a given 159 * device path. However, querying the EFI_DEVICE_PATH protocol 160 * for a given device path should give us a handle for the 161 * closest node in the path to the end that is valid. 162 */ 163 status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h); 164 if (EFI_ERROR(status)) 165 return (NULL); 166 return (h); 167} 168