Prepare v2023.10
[platform/kernel/u-boot.git] / 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 <blk.h>
10 #include <efi_loader.h>
11 #include <malloc.h>
12
13 #define MAC_OUTPUT_LEN 22
14 #define UNKNOWN_OUTPUT_LEN 23
15
16 #define MAX_NODE_LEN 512
17 #define MAX_PATH_LEN 1024
18
19 const efi_guid_t efi_guid_device_path_to_text_protocol =
20                 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
21
22 /**
23  * efi_str_to_u16() - convert ASCII string to UTF-16
24  *
25  * A u16 buffer is allocated from pool. The ASCII string is copied to the u16
26  * buffer.
27  *
28  * @str:        ASCII string
29  * Return:      UTF-16 string. NULL if out of memory.
30  */
31 static u16 *efi_str_to_u16(char *str)
32 {
33         efi_uintn_t len;
34         u16 *out, *dst;
35
36         len = sizeof(u16) * (utf8_utf16_strlen(str) + 1);
37         out = efi_alloc(len);
38         if (!out)
39                 return NULL;
40         dst = out;
41         utf8_utf16_strcpy(&dst, str);
42         return out;
43 }
44
45 static char *dp_unknown(char *s, struct efi_device_path *dp)
46 {
47         s += sprintf(s, "UNKNOWN(%04x,%04x)", dp->type, dp->sub_type);
48         return s;
49 }
50
51 static char *dp_hardware(char *s, struct efi_device_path *dp)
52 {
53         switch (dp->sub_type) {
54         case DEVICE_PATH_SUB_TYPE_MEMORY: {
55                 struct efi_device_path_memory *mdp =
56                         (struct efi_device_path_memory *)dp;
57                 s += sprintf(s, "MemoryMapped(0x%x,0x%llx,0x%llx)",
58                              mdp->memory_type,
59                              mdp->start_address,
60                              mdp->end_address);
61                 break;
62         }
63         case DEVICE_PATH_SUB_TYPE_VENDOR: {
64                 int i, n;
65                 struct efi_device_path_vendor *vdp =
66                         (struct efi_device_path_vendor *)dp;
67
68                 s += sprintf(s, "VenHw(%pUl", &vdp->guid);
69                 n = (int)vdp->dp.length - sizeof(struct efi_device_path_vendor);
70                 /* Node must fit into MAX_NODE_LEN) */
71                 if (n > 0 && n < MAX_NODE_LEN / 2 - 22) {
72                         s += sprintf(s, ",");
73                         for (i = 0; i < n; ++i)
74                                 s += sprintf(s, "%02x", vdp->vendor_data[i]);
75                 }
76                 s += sprintf(s, ")");
77                 break;
78         }
79         case DEVICE_PATH_SUB_TYPE_CONTROLLER: {
80                 struct efi_device_path_controller *cdp =
81                         (struct efi_device_path_controller *)dp;
82
83                 s += sprintf(s, "Ctrl(0x%0x)", cdp->controller_number);
84                 break;
85         }
86         default:
87                 s = dp_unknown(s, dp);
88                 break;
89         }
90         return s;
91 }
92
93 static char *dp_acpi(char *s, struct efi_device_path *dp)
94 {
95         switch (dp->sub_type) {
96         case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: {
97                 struct efi_device_path_acpi_path *adp =
98                         (struct efi_device_path_acpi_path *)dp;
99
100                 s += sprintf(s, "Acpi(PNP%04X,%d)", EISA_PNP_NUM(adp->hid),
101                              adp->uid);
102                 break;
103         }
104         default:
105                 s = dp_unknown(s, dp);
106                 break;
107         }
108         return s;
109 }
110
111 static char *dp_msging(char *s, struct efi_device_path *dp)
112 {
113         switch (dp->sub_type) {
114         case DEVICE_PATH_SUB_TYPE_MSG_ATAPI: {
115                 struct efi_device_path_atapi *ide =
116                         (struct efi_device_path_atapi *)dp;
117                 s += sprintf(s, "Ata(%d,%d,%d)", ide->primary_secondary,
118                              ide->slave_master, ide->logical_unit_number);
119                 break;
120         }
121         case DEVICE_PATH_SUB_TYPE_MSG_SCSI: {
122                 struct efi_device_path_scsi *ide =
123                         (struct efi_device_path_scsi *)dp;
124                 s += sprintf(s, "Scsi(%u,%u)", ide->target_id,
125                              ide->logical_unit_number);
126                 break;
127         }
128         case DEVICE_PATH_SUB_TYPE_MSG_UART: {
129                 struct efi_device_path_uart *uart =
130                         (struct efi_device_path_uart *)dp;
131                 const char parity_str[6] = {'D', 'N', 'E', 'O', 'M', 'S'};
132                 const char *stop_bits_str[4] = { "D", "1", "1.5", "2" };
133
134                 s += sprintf(s, "Uart(%lld,%d,", uart->baud_rate,
135                              uart->data_bits);
136
137                 /*
138                  * Parity and stop bits can either both use keywords or both use
139                  * numbers but numbers and keywords should not be mixed. Let's
140                  * go for keywords as this is what EDK II does. For illegal
141                  * values fall back to numbers.
142                  */
143                 if (uart->parity < 6)
144                         s += sprintf(s, "%c,", parity_str[uart->parity]);
145                 else
146                         s += sprintf(s, "%d,", uart->parity);
147                 if (uart->stop_bits < 4)
148                         s += sprintf(s, "%s)", stop_bits_str[uart->stop_bits]);
149                 else
150                         s += sprintf(s, "%d)", uart->stop_bits);
151                 break;
152         }
153         case DEVICE_PATH_SUB_TYPE_MSG_USB: {
154                 struct efi_device_path_usb *udp =
155                         (struct efi_device_path_usb *)dp;
156                 s += sprintf(s, "USB(0x%x,0x%x)", udp->parent_port_number,
157                              udp->usb_interface);
158                 break;
159         }
160         case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
161                 int i, n = sizeof(struct efi_mac_addr);
162                 struct efi_device_path_mac_addr *mdp =
163                         (struct efi_device_path_mac_addr *)dp;
164
165                 if (mdp->if_type <= 1)
166                         n = 6;
167                 s += sprintf(s, "MAC(");
168                 for (i = 0; i < n; ++i)
169                         s += sprintf(s, "%02x", mdp->mac.addr[i]);
170                 s += sprintf(s, ",%u)", mdp->if_type);
171
172                 break;
173         }
174         case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: {
175                 struct efi_device_path_usb_class *ucdp =
176                         (struct efi_device_path_usb_class *)dp;
177
178                 s += sprintf(s, "UsbClass(0x%x,0x%x,0x%x,0x%x,0x%x)",
179                         ucdp->vendor_id, ucdp->product_id,
180                         ucdp->device_class, ucdp->device_subclass,
181                         ucdp->device_protocol);
182
183                 break;
184         }
185         case DEVICE_PATH_SUB_TYPE_MSG_SATA: {
186                 struct efi_device_path_sata *sdp =
187                         (struct efi_device_path_sata *) dp;
188
189                 s += sprintf(s, "Sata(0x%x,0x%x,0x%x)",
190                              sdp->hba_port,
191                              sdp->port_multiplier_port,
192                              sdp->logical_unit_number);
193                 break;
194         }
195         case DEVICE_PATH_SUB_TYPE_MSG_NVME: {
196                 struct efi_device_path_nvme *ndp =
197                         (struct efi_device_path_nvme *)dp;
198                 u32 ns_id;
199
200                 memcpy(&ns_id, &ndp->ns_id, sizeof(ns_id));
201                 s += sprintf(s, "NVMe(0x%x,", ns_id);
202
203                 /* Display byte 7 first, byte 0 last */
204                 for (int i = 0; i < 8; ++i)
205                         s += sprintf(s, "%s%02x", i ? "-" : "",
206                                      ndp->eui64[i ^ 7]);
207                 s += sprintf(s, ")");
208
209                 break;
210         }
211         case DEVICE_PATH_SUB_TYPE_MSG_URI: {
212                 struct efi_device_path_uri *udp =
213                         (struct efi_device_path_uri *)dp;
214                 int n;
215
216                 n = (int)udp->dp.length - sizeof(struct efi_device_path_uri);
217
218                 s += sprintf(s, "Uri(");
219                 if (n > 0 && n < MAX_NODE_LEN - 6)
220                         s += snprintf(s, n, "%s", (char *)udp->uri);
221                 s += sprintf(s, ")");
222                 break;
223         }
224         case DEVICE_PATH_SUB_TYPE_MSG_SD:
225         case DEVICE_PATH_SUB_TYPE_MSG_MMC: {
226                 const char *typename =
227                         (dp->sub_type == DEVICE_PATH_SUB_TYPE_MSG_SD) ?
228                                         "SD" : "eMMC";
229                 struct efi_device_path_sd_mmc_path *sddp =
230                         (struct efi_device_path_sd_mmc_path *)dp;
231                 s += sprintf(s, "%s(%u)", typename, sddp->slot_number);
232                 break;
233         }
234         default:
235                 s = dp_unknown(s, dp);
236                 break;
237         }
238         return s;
239 }
240
241 /*
242  * Convert a media device path node to text.
243  *
244  * @s           output buffer
245  * @dp          device path node
246  * Return:      next unused buffer address
247  */
248 static char *dp_media(char *s, struct efi_device_path *dp)
249 {
250         switch (dp->sub_type) {
251         case DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH: {
252                 struct efi_device_path_hard_drive_path *hddp =
253                         (struct efi_device_path_hard_drive_path *)dp;
254                 void *sig = hddp->partition_signature;
255                 u64 start;
256                 u64 end;
257
258                 /* Copy from packed structure to aligned memory */
259                 memcpy(&start, &hddp->partition_start, sizeof(start));
260                 memcpy(&end, &hddp->partition_end, sizeof(end));
261
262                 switch (hddp->signature_type) {
263                 case SIG_TYPE_MBR: {
264                         u32 signature;
265
266                         memcpy(&signature, sig, sizeof(signature));
267                         s += sprintf(
268                                 s, "HD(%d,MBR,0x%08x,0x%llx,0x%llx)",
269                                 hddp->partition_number, signature, start, end);
270                         break;
271                         }
272                 case SIG_TYPE_GUID:
273                         s += sprintf(
274                                 s, "HD(%d,GPT,%pUl,0x%llx,0x%llx)",
275                                 hddp->partition_number, sig, start, end);
276                         break;
277                 default:
278                         s += sprintf(
279                                 s, "HD(%d,0x%02x,0,0x%llx,0x%llx)",
280                                 hddp->partition_number, hddp->partmap_type,
281                                 start, end);
282                         break;
283                 }
284
285                 break;
286         }
287         case DEVICE_PATH_SUB_TYPE_CDROM_PATH: {
288                 struct efi_device_path_cdrom_path *cddp =
289                         (struct efi_device_path_cdrom_path *)dp;
290                 s += sprintf(s, "CDROM(%u,0x%llx,0x%llx)", cddp->boot_entry,
291                              cddp->partition_start, cddp->partition_size);
292                 break;
293         }
294         case DEVICE_PATH_SUB_TYPE_VENDOR_PATH: {
295                 int i, n;
296                 struct efi_device_path_vendor *vdp =
297                         (struct efi_device_path_vendor *)dp;
298
299                 s += sprintf(s, "VenMedia(%pUl", &vdp->guid);
300                 n = (int)vdp->dp.length - sizeof(struct efi_device_path_vendor);
301                 /* Node must fit into MAX_NODE_LEN) */
302                 if (n > 0 && n < MAX_NODE_LEN / 2 - 24) {
303                         s += sprintf(s, ",");
304                         for (i = 0; i < n; ++i)
305                                 s += sprintf(s, "%02x", vdp->vendor_data[i]);
306                 }
307                 s += sprintf(s, ")");
308                 break;
309         }
310         case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
311                 struct efi_device_path_file_path *fp =
312                         (struct efi_device_path_file_path *)dp;
313                 u16 *buffer;
314                 int slen = dp->length - sizeof(*dp);
315
316                 /* two bytes for \0, extra byte if dp->length is odd */
317                 buffer = calloc(1, slen + 3);
318                 if (!buffer) {
319                         log_err("Out of memory\n");
320                         return s;
321                 }
322                 memcpy(buffer, fp->str, dp->length - sizeof(*dp));
323                 s += snprintf(s, MAX_NODE_LEN - 1, "%ls", buffer);
324                 free(buffer);
325                 break;
326         }
327         default:
328                 s = dp_unknown(s, dp);
329                 break;
330         }
331         return s;
332 }
333
334 /*
335  * Converts a single node to a char string.
336  *
337  * @buffer              output buffer
338  * @dp                  device path or node
339  * Return:              end of string
340  */
341 static char *efi_convert_single_device_node_to_text(
342                 char *buffer,
343                 struct efi_device_path *dp)
344 {
345         char *str = buffer;
346
347         switch (dp->type) {
348         case DEVICE_PATH_TYPE_HARDWARE_DEVICE:
349                 str = dp_hardware(str, dp);
350                 break;
351         case DEVICE_PATH_TYPE_ACPI_DEVICE:
352                 str = dp_acpi(str, dp);
353                 break;
354         case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
355                 str = dp_msging(str, dp);
356                 break;
357         case DEVICE_PATH_TYPE_MEDIA_DEVICE:
358                 str = dp_media(str, dp);
359                 break;
360         case DEVICE_PATH_TYPE_END:
361                 break;
362         default:
363                 str = dp_unknown(str, dp);
364         }
365
366         *str = '\0';
367         return str;
368 }
369
370 /*
371  * This function implements the ConvertDeviceNodeToText service of the
372  * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
373  * See the Unified Extensible Firmware Interface (UEFI) specification
374  * for details.
375  *
376  * device_node          device node to be converted
377  * display_only         true if the shorter text representation shall be used
378  * allow_shortcuts      true if shortcut forms may be used
379  * Return:              text representation of the device path
380  *                      NULL if out of memory of device_path is NULL
381  */
382 static uint16_t EFIAPI *efi_convert_device_node_to_text(
383                 struct efi_device_path *device_node,
384                 bool display_only,
385                 bool allow_shortcuts)
386 {
387         char str[MAX_NODE_LEN];
388         uint16_t *text = NULL;
389
390         EFI_ENTRY("%p, %d, %d", device_node, display_only, allow_shortcuts);
391
392         if (!device_node)
393                 goto out;
394         efi_convert_single_device_node_to_text(str, device_node);
395
396         text = efi_str_to_u16(str);
397
398 out:
399         EFI_EXIT(EFI_SUCCESS);
400         return text;
401 }
402
403 /*
404  * This function implements the ConvertDevicePathToText service of the
405  * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
406  * See the Unified Extensible Firmware Interface (UEFI) specification
407  * for details.
408  *
409  * device_path          device path to be converted
410  * display_only         true if the shorter text representation shall be used
411  * allow_shortcuts      true if shortcut forms may be used
412  * Return:              text representation of the device path
413  *                      NULL if out of memory of device_path is NULL
414  */
415 static uint16_t EFIAPI *efi_convert_device_path_to_text(
416                 struct efi_device_path *device_path,
417                 bool display_only,
418                 bool allow_shortcuts)
419 {
420         uint16_t *text = NULL;
421         char buffer[MAX_PATH_LEN];
422         char *str = buffer;
423
424         EFI_ENTRY("%p, %d, %d", device_path, display_only, allow_shortcuts);
425
426         if (!device_path)
427                 goto out;
428         while (device_path && str + MAX_NODE_LEN < buffer + MAX_PATH_LEN) {
429                 if (device_path->type == DEVICE_PATH_TYPE_END) {
430                         if (device_path->sub_type !=
431                             DEVICE_PATH_SUB_TYPE_INSTANCE_END)
432                                 break;
433                         *str++ = ',';
434                 } else {
435                         *str++ = '/';
436                         str = efi_convert_single_device_node_to_text(
437                                                         str, device_path);
438                 }
439                 *(u8 **)&device_path += device_path->length;
440         }
441
442         *str = 0;
443         text = efi_str_to_u16(buffer);
444
445 out:
446         EFI_EXIT(EFI_SUCCESS);
447         return text;
448 }
449
450 /* helper for debug prints.. efi_free_pool() the result. */
451 uint16_t *efi_dp_str(struct efi_device_path *dp)
452 {
453         return EFI_CALL(efi_convert_device_path_to_text(dp, true, true));
454 }
455
456 const struct efi_device_path_to_text_protocol efi_device_path_to_text = {
457         .convert_device_node_to_text = efi_convert_device_node_to_text,
458         .convert_device_path_to_text = efi_convert_device_path_to_text,
459 };