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