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