]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/efi/libefi/devpath.c
Checkpoint initial integration work
[FreeBSD/FreeBSD.git] / sys / boot / efi / libefi / devpath.c
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$");
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
40 INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL);
41
42 typedef
43 CHAR16*
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
50 typedef
51 CHAR16*
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
58 typedef 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
63 static EFI_GUID ImageDevicePathGUID =
64     EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID;
65 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
66 static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
67 static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *textProtocol;
68
69 EFI_DEVICE_PATH *
70 efi_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
82 EFI_DEVICE_PATH *
83 efi_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
94 CHAR16 *
95 efi_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
115 void
116 efi_free_devpath_name(CHAR16 *text)
117 {
118
119         BS->FreePool(text);
120 }
121
122 EFI_DEVICE_PATH *
123 efi_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
133 EFI_DEVICE_PATH *
134 efi_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
151 EFI_HANDLE
152 efi_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 }