]> git.sur5r.net Git - u-boot/blob - lib/efi_loader/efi_device_path_to_text.c
SPDX: Convert a few files that were missed before
[u-boot] / lib / efi_loader / efi_device_path_to_text.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI device path interface
4  *
5  *  Copyright (c) 2017 Heinrich Schuchardt
6  */
7
8 #include <common.h>
9 #include <efi_loader.h>
10
11 #define MAC_OUTPUT_LEN 22
12 #define UNKNOWN_OUTPUT_LEN 23
13
14 #define MAX_NODE_LEN 512
15 #define MAX_PATH_LEN 1024
16
17 const efi_guid_t efi_guid_device_path_to_text_protocol =
18                 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
19
20 static u16 *efi_str_to_u16(char *str)
21 {
22         efi_uintn_t len;
23         u16 *out;
24         efi_status_t ret;
25
26         len = strlen(str) + 1;
27         ret = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, len * sizeof(u16),
28                                 (void **)&out);
29         if (ret != EFI_SUCCESS)
30                 return NULL;
31         ascii2unicode(out, str);
32         out[len - 1] = 0;
33         return out;
34 }
35
36 static char *dp_unknown(char *s, struct efi_device_path *dp)
37 {
38         s += sprintf(s, "UNKNOWN(%04x,%04x)", dp->type, dp->sub_type);
39         return s;
40 }
41
42 static char *dp_hardware(char *s, struct efi_device_path *dp)
43 {
44         switch (dp->sub_type) {
45         case DEVICE_PATH_SUB_TYPE_MEMORY: {
46                 struct efi_device_path_memory *mdp =
47                         (struct efi_device_path_memory *)dp;
48                 s += sprintf(s, "MemoryMapped(0x%x,0x%llx,0x%llx)",
49                              mdp->memory_type,
50                              mdp->start_address,
51                              mdp->end_address);
52                 break;
53         }
54         case DEVICE_PATH_SUB_TYPE_VENDOR: {
55                 struct efi_device_path_vendor *vdp =
56                         (struct efi_device_path_vendor *)dp;
57                 s += sprintf(s, "VenHw(%pUl)", &vdp->guid);
58                 break;
59         }
60         default:
61                 s = dp_unknown(s, dp);
62                 break;
63         }
64         return s;
65 }
66
67 static char *dp_acpi(char *s, struct efi_device_path *dp)
68 {
69         switch (dp->sub_type) {
70         case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: {
71                 struct efi_device_path_acpi_path *adp =
72                         (struct efi_device_path_acpi_path *)dp;
73                 s += sprintf(s, "Acpi(PNP%04x", EISA_PNP_NUM(adp->hid));
74                 if (adp->uid)
75                         s += sprintf(s, ",%d", adp->uid);
76                 s += sprintf(s, ")");
77                 break;
78         }
79         default:
80                 s = dp_unknown(s, dp);
81                 break;
82         }
83         return s;
84 }
85
86 static char *dp_msging(char *s, struct efi_device_path *dp)
87 {
88         switch (dp->sub_type) {
89         case DEVICE_PATH_SUB_TYPE_MSG_ATAPI: {
90                 struct efi_device_path_atapi *ide =
91                         (struct efi_device_path_atapi *)dp;
92                 s += sprintf(s, "Ata(%d,%d,%d)", ide->primary_secondary,
93                              ide->slave_master, ide->logical_unit_number);
94                 break;
95         }
96         case DEVICE_PATH_SUB_TYPE_MSG_SCSI: {
97                 struct efi_device_path_scsi *ide =
98                         (struct efi_device_path_scsi *)dp;
99                 s += sprintf(s, "Scsi(%u,%u)", ide->target_id,
100                              ide->logical_unit_number);
101                 break;
102         }
103         case DEVICE_PATH_SUB_TYPE_MSG_USB: {
104                 struct efi_device_path_usb *udp =
105                         (struct efi_device_path_usb *)dp;
106                 s += sprintf(s, "USB(0x%x,0x%x)", udp->parent_port_number,
107                              udp->usb_interface);
108                 break;
109         }
110         case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
111                 struct efi_device_path_mac_addr *mdp =
112                         (struct efi_device_path_mac_addr *)dp;
113
114                 if (mdp->if_type != 0 && mdp->if_type != 1)
115                         break;
116
117                 s += sprintf(s, "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
118                         mdp->mac.addr[0], mdp->mac.addr[1],
119                         mdp->mac.addr[2], mdp->mac.addr[3],
120                         mdp->mac.addr[4], mdp->mac.addr[5],
121                         mdp->if_type);
122
123                 break;
124         }
125         case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: {
126                 struct efi_device_path_usb_class *ucdp =
127                         (struct efi_device_path_usb_class *)dp;
128
129                 s += sprintf(s, "USBClass(%x,%x,%x,%x,%x)",
130                         ucdp->vendor_id, ucdp->product_id,
131                         ucdp->device_class, ucdp->device_subclass,
132                         ucdp->device_protocol);
133
134                 break;
135         }
136         case DEVICE_PATH_SUB_TYPE_MSG_SD:
137         case DEVICE_PATH_SUB_TYPE_MSG_MMC: {
138                 const char *typename =
139                         (dp->sub_type == DEVICE_PATH_SUB_TYPE_MSG_SD) ?
140                                         "SD" : "eMMC";
141                 struct efi_device_path_sd_mmc_path *sddp =
142                         (struct efi_device_path_sd_mmc_path *)dp;
143                 s += sprintf(s, "%s(%u)", typename, sddp->slot_number);
144                 break;
145         }
146         default:
147                 s = dp_unknown(s, dp);
148                 break;
149         }
150         return s;
151 }
152
153 /*
154  * Convert a media device path node to text.
155  *
156  * @s           output buffer
157  * @dp          device path node
158  * @return      next unused buffer address
159  */
160 static char *dp_media(char *s, struct efi_device_path *dp)
161 {
162         switch (dp->sub_type) {
163         case DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH: {
164                 struct efi_device_path_hard_drive_path *hddp =
165                         (struct efi_device_path_hard_drive_path *)dp;
166                 void *sig = hddp->partition_signature;
167                 u64 start;
168                 u64 end;
169
170                 /* Copy from packed structure to aligned memory */
171                 memcpy(&start, &hddp->partition_start, sizeof(start));
172                 memcpy(&end, &hddp->partition_end, sizeof(end));
173
174                 switch (hddp->signature_type) {
175                 case SIG_TYPE_MBR: {
176                         u32 signature;
177
178                         memcpy(&signature, sig, sizeof(signature));
179                         s += sprintf(
180                                 s, "HD(%d,MBR,0x%08x,0x%llx,0x%llx)",
181                                 hddp->partition_number, signature, start, end);
182                         break;
183                         }
184                 case SIG_TYPE_GUID:
185                         s += sprintf(
186                                 s, "HD(%d,GPT,%pUl,0x%llx,0x%llx)",
187                                 hddp->partition_number, sig, start, end);
188                         break;
189                 default:
190                         s += sprintf(
191                                 s, "HD(%d,0x%02x,0,0x%llx,0x%llx)",
192                                 hddp->partition_number, hddp->partmap_type,
193                                 start, end);
194                         break;
195                 }
196
197                 break;
198         }
199         case DEVICE_PATH_SUB_TYPE_CDROM_PATH: {
200                 struct efi_device_path_cdrom_path *cddp =
201                         (struct efi_device_path_cdrom_path *)dp;
202                 s += sprintf(s, "CDROM(0x%x)", cddp->boot_entry);
203                 break;
204         }
205         case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
206                 struct efi_device_path_file_path *fp =
207                         (struct efi_device_path_file_path *)dp;
208                 int slen = (dp->length - sizeof(*dp)) / 2;
209                 if (slen > MAX_NODE_LEN - 2)
210                         slen = MAX_NODE_LEN - 2;
211                 s += sprintf(s, "%-.*ls", slen, fp->str);
212                 break;
213         }
214         default:
215                 s = dp_unknown(s, dp);
216                 break;
217         }
218         return s;
219 }
220
221 /*
222  * Converts a single node to a char string.
223  *
224  * @buffer              output buffer
225  * @dp                  device path or node
226  * @return              end of string
227  */
228 static char *efi_convert_single_device_node_to_text(
229                 char *buffer,
230                 struct efi_device_path *dp)
231 {
232         char *str = buffer;
233
234         switch (dp->type) {
235         case DEVICE_PATH_TYPE_HARDWARE_DEVICE:
236                 str = dp_hardware(str, dp);
237                 break;
238         case DEVICE_PATH_TYPE_ACPI_DEVICE:
239                 str = dp_acpi(str, dp);
240                 break;
241         case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
242                 str = dp_msging(str, dp);
243                 break;
244         case DEVICE_PATH_TYPE_MEDIA_DEVICE:
245                 str = dp_media(str, dp);
246                 break;
247         case DEVICE_PATH_TYPE_END:
248                 break;
249         default:
250                 str = dp_unknown(str, dp);
251         }
252
253         *str = '\0';
254         return str;
255 }
256
257 /*
258  * This function implements the ConvertDeviceNodeToText service of the
259  * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
260  * See the Unified Extensible Firmware Interface (UEFI) specification
261  * for details.
262  *
263  * device_node          device node to be converted
264  * display_only         true if the shorter text represenation shall be used
265  * allow_shortcuts      true if shortcut forms may be used
266  * @return              text represenation of the device path
267  *                      NULL if out of memory of device_path is NULL
268  */
269 static uint16_t EFIAPI *efi_convert_device_node_to_text(
270                 struct efi_device_path *device_node,
271                 bool display_only,
272                 bool allow_shortcuts)
273 {
274         char str[MAX_NODE_LEN];
275         uint16_t *text = NULL;
276
277         EFI_ENTRY("%p, %d, %d", device_node, display_only, allow_shortcuts);
278
279         if (!device_node)
280                 goto out;
281         efi_convert_single_device_node_to_text(str, device_node);
282
283         text = efi_str_to_u16(str);
284
285 out:
286         EFI_EXIT(EFI_SUCCESS);
287         return text;
288 }
289
290 /*
291  * This function implements the ConvertDevicePathToText service of the
292  * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
293  * See the Unified Extensible Firmware Interface (UEFI) specification
294  * for details.
295  *
296  * device_path          device path to be converted
297  * display_only         true if the shorter text represenation shall be used
298  * allow_shortcuts      true if shortcut forms may be used
299  * @return              text represenation of the device path
300  *                      NULL if out of memory of device_path is NULL
301  */
302 static uint16_t EFIAPI *efi_convert_device_path_to_text(
303                 struct efi_device_path *device_path,
304                 bool display_only,
305                 bool allow_shortcuts)
306 {
307         uint16_t *text = NULL;
308         char buffer[MAX_PATH_LEN];
309         char *str = buffer;
310
311         EFI_ENTRY("%p, %d, %d", device_path, display_only, allow_shortcuts);
312
313         if (!device_path)
314                 goto out;
315         while (device_path &&
316                str + MAX_NODE_LEN < buffer + MAX_PATH_LEN) {
317                 *str++ = '/';
318                 str = efi_convert_single_device_node_to_text(str, device_path);
319                 device_path = efi_dp_next(device_path);
320         }
321
322         text = efi_str_to_u16(buffer);
323
324 out:
325         EFI_EXIT(EFI_SUCCESS);
326         return text;
327 }
328
329 /* helper for debug prints.. efi_free_pool() the result. */
330 uint16_t *efi_dp_str(struct efi_device_path *dp)
331 {
332         return EFI_CALL(efi_convert_device_path_to_text(dp, true, true));
333 }
334
335 const struct efi_device_path_to_text_protocol efi_device_path_to_text = {
336         .convert_device_node_to_text = efi_convert_device_node_to_text,
337         .convert_device_path_to_text = efi_convert_device_path_to_text,
338 };