1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * EFI device path from u-boot device-model mapping
4  *
5  * (C) Copyright 2017 Rob Clark
6  */
7 
8 #define LOG_CATEGORY LOGL_ERR
9 
10 #include <common.h>
11 #include <blk.h>
12 #include <dm.h>
13 #include <usb.h>
14 #include <mmc.h>
15 #include <efi_loader.h>
16 #include <part.h>
17 
18 /* template END node: */
19 static const struct efi_device_path END = {
20 	.type     = DEVICE_PATH_TYPE_END,
21 	.sub_type = DEVICE_PATH_SUB_TYPE_END,
22 	.length   = sizeof(END),
23 };
24 
25 /* template ROOT node: */
26 static const struct efi_device_path_vendor ROOT = {
27 	.dp = {
28 		.type     = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
29 		.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
30 		.length   = sizeof(ROOT),
31 	},
32 	.guid = U_BOOT_GUID,
33 };
34 
35 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
36 /*
37  * Determine if an MMC device is an SD card.
38  *
39  * @desc	block device descriptor
40  * @return	true if the device is an SD card
41  */
42 static bool is_sd(struct blk_desc *desc)
43 {
44 	struct mmc *mmc = find_mmc_device(desc->devnum);
45 
46 	if (!mmc)
47 		return false;
48 
49 	return IS_SD(mmc) != 0U;
50 }
51 #endif
52 
53 static void *dp_alloc(size_t sz)
54 {
55 	void *buf;
56 
57 	if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) !=
58 	    EFI_SUCCESS) {
59 		debug("EFI: ERROR: out of memory in %s\n", __func__);
60 		return NULL;
61 	}
62 
63 	memset(buf, 0, sz);
64 	return buf;
65 }
66 
67 /*
68  * Iterate to next block in device-path, terminating (returning NULL)
69  * at /End* node.
70  */
71 struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
72 {
73 	if (dp == NULL)
74 		return NULL;
75 	if (dp->type == DEVICE_PATH_TYPE_END)
76 		return NULL;
77 	dp = ((void *)dp) + dp->length;
78 	if (dp->type == DEVICE_PATH_TYPE_END)
79 		return NULL;
80 	return (struct efi_device_path *)dp;
81 }
82 
83 /*
84  * Compare two device-paths, stopping when the shorter of the two hits
85  * an End* node. This is useful to, for example, compare a device-path
86  * representing a device with one representing a file on the device, or
87  * a device with a parent device.
88  */
89 int efi_dp_match(const struct efi_device_path *a,
90 		 const struct efi_device_path *b)
91 {
92 	while (1) {
93 		int ret;
94 
95 		ret = memcmp(&a->length, &b->length, sizeof(a->length));
96 		if (ret)
97 			return ret;
98 
99 		ret = memcmp(a, b, a->length);
100 		if (ret)
101 			return ret;
102 
103 		a = efi_dp_next(a);
104 		b = efi_dp_next(b);
105 
106 		if (!a || !b)
107 			return 0;
108 	}
109 }
110 
111 /*
112  * We can have device paths that start with a USB WWID or a USB Class node,
113  * and a few other cases which don't encode the full device path with bus
114  * hierarchy:
115  *
116  *   - MESSAGING:USB_WWID
117  *   - MESSAGING:USB_CLASS
118  *   - MEDIA:FILE_PATH
119  *   - MEDIA:HARD_DRIVE
120  *   - MESSAGING:URI
121  *
122  * See UEFI spec (section 3.1.2, about short-form device-paths)
123  */
124 static struct efi_device_path *shorten_path(struct efi_device_path *dp)
125 {
126 	while (dp) {
127 		/*
128 		 * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..
129 		 * in practice fallback.efi just uses MEDIA:HARD_DRIVE
130 		 * so not sure when we would see these other cases.
131 		 */
132 		if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||
133 		    EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
134 		    EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
135 			return dp;
136 
137 		dp = efi_dp_next(dp);
138 	}
139 
140 	return dp;
141 }
142 
143 static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
144 				   struct efi_device_path **rem)
145 {
146 	struct efi_object *efiobj;
147 	efi_uintn_t dp_size = efi_dp_instance_size(dp);
148 
149 	list_for_each_entry(efiobj, &efi_obj_list, link) {
150 		struct efi_handler *handler;
151 		struct efi_device_path *obj_dp;
152 		efi_status_t ret;
153 
154 		ret = efi_search_protocol(efiobj,
155 					  &efi_guid_device_path, &handler);
156 		if (ret != EFI_SUCCESS)
157 			continue;
158 		obj_dp = handler->protocol_interface;
159 
160 		do {
161 			if (efi_dp_match(dp, obj_dp) == 0) {
162 				if (rem) {
163 					/*
164 					 * Allow partial matches, but inform
165 					 * the caller.
166 					 */
167 					*rem = ((void *)dp) +
168 						efi_dp_instance_size(obj_dp);
169 					return efiobj;
170 				} else {
171 					/* Only return on exact matches */
172 					if (efi_dp_instance_size(obj_dp) ==
173 					    dp_size)
174 						return efiobj;
175 				}
176 			}
177 
178 			obj_dp = shorten_path(efi_dp_next(obj_dp));
179 		} while (short_path && obj_dp);
180 	}
181 
182 	return NULL;
183 }
184 
185 /*
186  * Find an efiobj from device-path, if 'rem' is not NULL, returns the
187  * remaining part of the device path after the matched object.
188  */
189 struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
190 				   struct efi_device_path **rem)
191 {
192 	struct efi_object *efiobj;
193 
194 	/* Search for an exact match first */
195 	efiobj = find_obj(dp, false, NULL);
196 
197 	/* Then for a fuzzy match */
198 	if (!efiobj)
199 		efiobj = find_obj(dp, false, rem);
200 
201 	/* And now for a fuzzy short match */
202 	if (!efiobj)
203 		efiobj = find_obj(dp, true, rem);
204 
205 	return efiobj;
206 }
207 
208 /*
209  * Determine the last device path node that is not the end node.
210  *
211  * @dp		device path
212  * @return	last node before the end node if it exists
213  *		otherwise NULL
214  */
215 const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
216 {
217 	struct efi_device_path *ret;
218 
219 	if (!dp || dp->type == DEVICE_PATH_TYPE_END)
220 		return NULL;
221 	while (dp) {
222 		ret = (struct efi_device_path *)dp;
223 		dp = efi_dp_next(dp);
224 	}
225 	return ret;
226 }
227 
228 /* get size of the first device path instance excluding end node */
229 efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
230 {
231 	efi_uintn_t sz = 0;
232 
233 	if (!dp || dp->type == DEVICE_PATH_TYPE_END)
234 		return 0;
235 	while (dp) {
236 		sz += dp->length;
237 		dp = efi_dp_next(dp);
238 	}
239 
240 	return sz;
241 }
242 
243 /* get size of multi-instance device path excluding end node */
244 efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
245 {
246 	const struct efi_device_path *p = dp;
247 
248 	if (!p)
249 		return 0;
250 	while (p->type != DEVICE_PATH_TYPE_END ||
251 	       p->sub_type != DEVICE_PATH_SUB_TYPE_END)
252 		p = (void *)p + p->length;
253 
254 	return (void *)p - (void *)dp;
255 }
256 
257 /* copy multi-instance device path */
258 struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
259 {
260 	struct efi_device_path *ndp;
261 	size_t sz = efi_dp_size(dp) + sizeof(END);
262 
263 	if (!dp)
264 		return NULL;
265 
266 	ndp = dp_alloc(sz);
267 	if (!ndp)
268 		return NULL;
269 	memcpy(ndp, dp, sz);
270 
271 	return ndp;
272 }
273 
274 struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
275 				      const struct efi_device_path *dp2)
276 {
277 	struct efi_device_path *ret;
278 
279 	if (!dp1 && !dp2) {
280 		/* return an end node */
281 		ret = efi_dp_dup(&END);
282 	} else if (!dp1) {
283 		ret = efi_dp_dup(dp2);
284 	} else if (!dp2) {
285 		ret = efi_dp_dup(dp1);
286 	} else {
287 		/* both dp1 and dp2 are non-null */
288 		unsigned sz1 = efi_dp_size(dp1);
289 		unsigned sz2 = efi_dp_size(dp2);
290 		void *p = dp_alloc(sz1 + sz2 + sizeof(END));
291 		if (!p)
292 			return NULL;
293 		memcpy(p, dp1, sz1);
294 		/* the end node of the second device path has to be retained */
295 		memcpy(p + sz1, dp2, sz2 + sizeof(END));
296 		ret = p;
297 	}
298 
299 	return ret;
300 }
301 
302 struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
303 					   const struct efi_device_path *node)
304 {
305 	struct efi_device_path *ret;
306 
307 	if (!node && !dp) {
308 		ret = efi_dp_dup(&END);
309 	} else if (!node) {
310 		ret = efi_dp_dup(dp);
311 	} else if (!dp) {
312 		size_t sz = node->length;
313 		void *p = dp_alloc(sz + sizeof(END));
314 		if (!p)
315 			return NULL;
316 		memcpy(p, node, sz);
317 		memcpy(p + sz, &END, sizeof(END));
318 		ret = p;
319 	} else {
320 		/* both dp and node are non-null */
321 		size_t sz = efi_dp_size(dp);
322 		void *p = dp_alloc(sz + node->length + sizeof(END));
323 		if (!p)
324 			return NULL;
325 		memcpy(p, dp, sz);
326 		memcpy(p + sz, node, node->length);
327 		memcpy(p + sz + node->length, &END, sizeof(END));
328 		ret = p;
329 	}
330 
331 	return ret;
332 }
333 
334 struct efi_device_path *efi_dp_create_device_node(const u8 type,
335 						  const u8 sub_type,
336 						  const u16 length)
337 {
338 	struct efi_device_path *ret;
339 
340 	ret = dp_alloc(length);
341 	if (!ret)
342 		return ret;
343 	ret->type = type;
344 	ret->sub_type = sub_type;
345 	ret->length = length;
346 	return ret;
347 }
348 
349 struct efi_device_path *efi_dp_append_instance(
350 		const struct efi_device_path *dp,
351 		const struct efi_device_path *dpi)
352 {
353 	size_t sz, szi;
354 	struct efi_device_path *p, *ret;
355 
356 	if (!dpi)
357 		return NULL;
358 	if (!dp)
359 		return efi_dp_dup(dpi);
360 	sz = efi_dp_size(dp);
361 	szi = efi_dp_instance_size(dpi);
362 	p = dp_alloc(sz + szi + 2 * sizeof(END));
363 	if (!p)
364 		return NULL;
365 	ret = p;
366 	memcpy(p, dp, sz + sizeof(END));
367 	p = (void *)p + sz;
368 	p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
369 	p = (void *)p + sizeof(END);
370 	memcpy(p, dpi, szi);
371 	p = (void *)p + szi;
372 	memcpy(p, &END, sizeof(END));
373 	return ret;
374 }
375 
376 struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
377 						 efi_uintn_t *size)
378 {
379 	size_t sz;
380 	struct efi_device_path *p;
381 
382 	if (size)
383 		*size = 0;
384 	if (!dp || !*dp)
385 		return NULL;
386 	sz = efi_dp_instance_size(*dp);
387 	p = dp_alloc(sz + sizeof(END));
388 	if (!p)
389 		return NULL;
390 	memcpy(p, *dp, sz + sizeof(END));
391 	*dp = (void *)*dp + sz;
392 	if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
393 		*dp = (void *)*dp + sizeof(END);
394 	else
395 		*dp = NULL;
396 	if (size)
397 		*size = sz + sizeof(END);
398 	return p;
399 }
400 
401 bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
402 {
403 	const struct efi_device_path *p = dp;
404 
405 	if (!p)
406 		return false;
407 	while (p->type != DEVICE_PATH_TYPE_END)
408 		p = (void *)p + p->length;
409 	return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
410 }
411 
412 #ifdef CONFIG_DM
413 /* size of device-path not including END node for device and all parents
414  * up to the root device.
415  */
416 static unsigned dp_size(struct udevice *dev)
417 {
418 	if (!dev || !dev->driver)
419 		return sizeof(ROOT);
420 
421 	switch (dev->driver->id) {
422 	case UCLASS_ROOT:
423 	case UCLASS_SIMPLE_BUS:
424 		/* stop traversing parents at this point: */
425 		return sizeof(ROOT);
426 	case UCLASS_ETH:
427 		return dp_size(dev->parent) +
428 			sizeof(struct efi_device_path_mac_addr);
429 #ifdef CONFIG_BLK
430 	case UCLASS_BLK:
431 		switch (dev->parent->uclass->uc_drv->id) {
432 #ifdef CONFIG_IDE
433 		case UCLASS_IDE:
434 			return dp_size(dev->parent) +
435 				sizeof(struct efi_device_path_atapi);
436 #endif
437 #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
438 		case UCLASS_SCSI:
439 			return dp_size(dev->parent) +
440 				sizeof(struct efi_device_path_scsi);
441 #endif
442 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
443 		case UCLASS_MMC:
444 			return dp_size(dev->parent) +
445 				sizeof(struct efi_device_path_sd_mmc_path);
446 #endif
447 		default:
448 			return dp_size(dev->parent);
449 		}
450 #endif
451 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
452 	case UCLASS_MMC:
453 		return dp_size(dev->parent) +
454 			sizeof(struct efi_device_path_sd_mmc_path);
455 #endif
456 	case UCLASS_MASS_STORAGE:
457 	case UCLASS_USB_HUB:
458 		return dp_size(dev->parent) +
459 			sizeof(struct efi_device_path_usb_class);
460 	default:
461 		/* just skip over unknown classes: */
462 		return dp_size(dev->parent);
463 	}
464 }
465 
466 /*
467  * Recursively build a device path.
468  *
469  * @buf		pointer to the end of the device path
470  * @dev		device
471  * @return	pointer to the end of the device path
472  */
473 static void *dp_fill(void *buf, struct udevice *dev)
474 {
475 	if (!dev || !dev->driver)
476 		return buf;
477 
478 	switch (dev->driver->id) {
479 	case UCLASS_ROOT:
480 	case UCLASS_SIMPLE_BUS: {
481 		/* stop traversing parents at this point: */
482 		struct efi_device_path_vendor *vdp = buf;
483 		*vdp = ROOT;
484 		return &vdp[1];
485 	}
486 #ifdef CONFIG_DM_ETH
487 	case UCLASS_ETH: {
488 		struct efi_device_path_mac_addr *dp =
489 			dp_fill(buf, dev->parent);
490 		struct eth_pdata *pdata = dev->platdata;
491 
492 		dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
493 		dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
494 		dp->dp.length = sizeof(*dp);
495 		memset(&dp->mac, 0, sizeof(dp->mac));
496 		/* We only support IPv4 */
497 		memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
498 		/* Ethernet */
499 		dp->if_type = 1;
500 		return &dp[1];
501 	}
502 #endif
503 #ifdef CONFIG_BLK
504 	case UCLASS_BLK:
505 		switch (dev->parent->uclass->uc_drv->id) {
506 #ifdef CONFIG_IDE
507 		case UCLASS_IDE: {
508 			struct efi_device_path_atapi *dp =
509 			dp_fill(buf, dev->parent);
510 			struct blk_desc *desc = dev_get_uclass_platdata(dev);
511 
512 			dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
513 			dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
514 			dp->dp.length = sizeof(*dp);
515 			dp->logical_unit_number = desc->devnum;
516 			dp->primary_secondary = IDE_BUS(desc->devnum);
517 			dp->slave_master = desc->devnum %
518 				(CONFIG_SYS_IDE_MAXDEVICE /
519 				 CONFIG_SYS_IDE_MAXBUS);
520 			return &dp[1];
521 			}
522 #endif
523 #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
524 		case UCLASS_SCSI: {
525 			struct efi_device_path_scsi *dp =
526 				dp_fill(buf, dev->parent);
527 			struct blk_desc *desc = dev_get_uclass_platdata(dev);
528 
529 			dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
530 			dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
531 			dp->dp.length = sizeof(*dp);
532 			dp->logical_unit_number = desc->lun;
533 			dp->target_id = desc->target;
534 			return &dp[1];
535 			}
536 #endif
537 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
538 		case UCLASS_MMC: {
539 			struct efi_device_path_sd_mmc_path *sddp =
540 				dp_fill(buf, dev->parent);
541 			struct blk_desc *desc = dev_get_uclass_platdata(dev);
542 
543 			sddp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
544 			sddp->dp.sub_type = is_sd(desc) ?
545 				DEVICE_PATH_SUB_TYPE_MSG_SD :
546 				DEVICE_PATH_SUB_TYPE_MSG_MMC;
547 			sddp->dp.length   = sizeof(*sddp);
548 			sddp->slot_number = dev->seq;
549 			return &sddp[1];
550 			}
551 #endif
552 		default:
553 			debug("%s(%u) %s: unhandled parent class: %s (%u)\n",
554 			      __FILE__, __LINE__, __func__,
555 			      dev->name, dev->parent->uclass->uc_drv->id);
556 			return dp_fill(buf, dev->parent);
557 		}
558 #endif
559 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
560 	case UCLASS_MMC: {
561 		struct efi_device_path_sd_mmc_path *sddp =
562 			dp_fill(buf, dev->parent);
563 		struct mmc *mmc = mmc_get_mmc_dev(dev);
564 		struct blk_desc *desc = mmc_get_blk_desc(mmc);
565 
566 		sddp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
567 		sddp->dp.sub_type = is_sd(desc) ?
568 			DEVICE_PATH_SUB_TYPE_MSG_SD :
569 			DEVICE_PATH_SUB_TYPE_MSG_MMC;
570 		sddp->dp.length   = sizeof(*sddp);
571 		sddp->slot_number = dev->seq;
572 
573 		return &sddp[1];
574 	}
575 #endif
576 	case UCLASS_MASS_STORAGE:
577 	case UCLASS_USB_HUB: {
578 		struct efi_device_path_usb_class *udp =
579 			dp_fill(buf, dev->parent);
580 		struct usb_device *udev = dev_get_parent_priv(dev);
581 		struct usb_device_descriptor *desc = &udev->descriptor;
582 
583 		udp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
584 		udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
585 		udp->dp.length   = sizeof(*udp);
586 		udp->vendor_id   = desc->idVendor;
587 		udp->product_id  = desc->idProduct;
588 		udp->device_class    = desc->bDeviceClass;
589 		udp->device_subclass = desc->bDeviceSubClass;
590 		udp->device_protocol = desc->bDeviceProtocol;
591 
592 		return &udp[1];
593 	}
594 	default:
595 		debug("%s(%u) %s: unhandled device class: %s (%u)\n",
596 		      __FILE__, __LINE__, __func__,
597 		      dev->name, dev->driver->id);
598 		return dp_fill(buf, dev->parent);
599 	}
600 }
601 
602 /* Construct a device-path from a device: */
603 struct efi_device_path *efi_dp_from_dev(struct udevice *dev)
604 {
605 	void *buf, *start;
606 
607 	start = buf = dp_alloc(dp_size(dev) + sizeof(END));
608 	if (!buf)
609 		return NULL;
610 	buf = dp_fill(buf, dev);
611 	*((struct efi_device_path *)buf) = END;
612 
613 	return start;
614 }
615 #endif
616 
617 static unsigned dp_part_size(struct blk_desc *desc, int part)
618 {
619 	unsigned dpsize;
620 
621 #ifdef CONFIG_BLK
622 	{
623 		struct udevice *dev;
624 		int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
625 
626 		if (ret)
627 			dev = desc->bdev->parent;
628 		dpsize = dp_size(dev);
629 	}
630 #else
631 	dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
632 #endif
633 
634 	if (part == 0) /* the actual disk, not a partition */
635 		return dpsize;
636 
637 	if (desc->part_type == PART_TYPE_ISO)
638 		dpsize += sizeof(struct efi_device_path_cdrom_path);
639 	else
640 		dpsize += sizeof(struct efi_device_path_hard_drive_path);
641 
642 	return dpsize;
643 }
644 
645 /*
646  * Create a device node for a block device partition.
647  *
648  * @buf		buffer to which the device path is written
649  * @desc	block device descriptor
650  * @part	partition number, 0 identifies a block device
651  */
652 static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
653 {
654 	disk_partition_t info;
655 
656 	part_get_info(desc, part, &info);
657 
658 	if (desc->part_type == PART_TYPE_ISO) {
659 		struct efi_device_path_cdrom_path *cddp = buf;
660 
661 		cddp->boot_entry = part;
662 		cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
663 		cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
664 		cddp->dp.length = sizeof(*cddp);
665 		cddp->partition_start = info.start;
666 		cddp->partition_end = info.size;
667 
668 		buf = &cddp[1];
669 	} else {
670 		struct efi_device_path_hard_drive_path *hddp = buf;
671 
672 		hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
673 		hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
674 		hddp->dp.length = sizeof(*hddp);
675 		hddp->partition_number = part;
676 		hddp->partition_start = info.start;
677 		hddp->partition_end = info.size;
678 		if (desc->part_type == PART_TYPE_EFI)
679 			hddp->partmap_type = 2;
680 		else
681 			hddp->partmap_type = 1;
682 
683 		switch (desc->sig_type) {
684 		case SIG_TYPE_NONE:
685 		default:
686 			hddp->signature_type = 0;
687 			memset(hddp->partition_signature, 0,
688 			       sizeof(hddp->partition_signature));
689 			break;
690 		case SIG_TYPE_MBR:
691 			hddp->signature_type = 1;
692 			memset(hddp->partition_signature, 0,
693 			       sizeof(hddp->partition_signature));
694 			memcpy(hddp->partition_signature, &desc->mbr_sig,
695 			       sizeof(desc->mbr_sig));
696 			break;
697 		case SIG_TYPE_GUID:
698 			hddp->signature_type = 2;
699 			memcpy(hddp->partition_signature, &desc->guid_sig,
700 			       sizeof(hddp->partition_signature));
701 			break;
702 		}
703 
704 		buf = &hddp[1];
705 	}
706 
707 	return buf;
708 }
709 
710 /*
711  * Create a device path for a block device or one of its partitions.
712  *
713  * @buf		buffer to which the device path is written
714  * @desc	block device descriptor
715  * @part	partition number, 0 identifies a block device
716  */
717 static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
718 {
719 #ifdef CONFIG_BLK
720 	{
721 		struct udevice *dev;
722 		int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
723 
724 		if (ret)
725 			dev = desc->bdev->parent;
726 		buf = dp_fill(buf, dev);
727 	}
728 #else
729 	/*
730 	 * We *could* make a more accurate path, by looking at if_type
731 	 * and handling all the different cases like we do for non-
732 	 * legacy (i.e. CONFIG_BLK=y) case. But most important thing
733 	 * is just to have a unique device-path for if_type+devnum.
734 	 * So map things to a fictitious USB device.
735 	 */
736 	struct efi_device_path_usb *udp;
737 
738 	memcpy(buf, &ROOT, sizeof(ROOT));
739 	buf += sizeof(ROOT);
740 
741 	udp = buf;
742 	udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
743 	udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
744 	udp->dp.length = sizeof(*udp);
745 	udp->parent_port_number = desc->if_type;
746 	udp->usb_interface = desc->devnum;
747 	buf = &udp[1];
748 #endif
749 
750 	if (part == 0) /* the actual disk, not a partition */
751 		return buf;
752 
753 	return dp_part_node(buf, desc, part);
754 }
755 
756 /* Construct a device-path from a partition on a block device: */
757 struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
758 {
759 	void *buf, *start;
760 
761 	start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));
762 	if (!buf)
763 		return NULL;
764 
765 	buf = dp_part_fill(buf, desc, part);
766 
767 	*((struct efi_device_path *)buf) = END;
768 
769 	return start;
770 }
771 
772 /*
773  * Create a device node for a block device partition.
774  *
775  * @buf		buffer to which the device path is written
776  * @desc	block device descriptor
777  * @part	partition number, 0 identifies a block device
778  */
779 struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
780 {
781 	efi_uintn_t dpsize;
782 	void *buf;
783 
784 	if (desc->part_type == PART_TYPE_ISO)
785 		dpsize = sizeof(struct efi_device_path_cdrom_path);
786 	else
787 		dpsize = sizeof(struct efi_device_path_hard_drive_path);
788 	buf = dp_alloc(dpsize);
789 
790 	dp_part_node(buf, desc, part);
791 
792 	return buf;
793 }
794 
795 /* convert path to an UEFI style path (i.e. DOS style backslashes and UTF-16) */
796 static void path_to_uefi(u16 *uefi, const char *path)
797 {
798 	while (*path) {
799 		char c = *(path++);
800 		if (c == '/')
801 			c = '\\';
802 		*(uefi++) = c;
803 	}
804 	*uefi = '\0';
805 }
806 
807 /*
808  * If desc is NULL, this creates a path with only the file component,
809  * otherwise it creates a full path with both device and file components
810  */
811 struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
812 		const char *path)
813 {
814 	struct efi_device_path_file_path *fp;
815 	void *buf, *start;
816 	unsigned dpsize = 0, fpsize;
817 
818 	if (desc)
819 		dpsize = dp_part_size(desc, part);
820 
821 	fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
822 	dpsize += fpsize;
823 
824 	start = buf = dp_alloc(dpsize + sizeof(END));
825 	if (!buf)
826 		return NULL;
827 
828 	if (desc)
829 		buf = dp_part_fill(buf, desc, part);
830 
831 	/* add file-path: */
832 	fp = buf;
833 	fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
834 	fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
835 	fp->dp.length = fpsize;
836 	path_to_uefi(fp->str, path);
837 	buf += fpsize;
838 
839 	*((struct efi_device_path *)buf) = END;
840 
841 	return start;
842 }
843 
844 #ifdef CONFIG_NET
845 struct efi_device_path *efi_dp_from_eth(void)
846 {
847 #ifndef CONFIG_DM_ETH
848 	struct efi_device_path_mac_addr *ndp;
849 #endif
850 	void *buf, *start;
851 	unsigned dpsize = 0;
852 
853 	assert(eth_get_dev());
854 
855 #ifdef CONFIG_DM_ETH
856 	dpsize += dp_size(eth_get_dev());
857 #else
858 	dpsize += sizeof(ROOT);
859 	dpsize += sizeof(*ndp);
860 #endif
861 
862 	start = buf = dp_alloc(dpsize + sizeof(END));
863 	if (!buf)
864 		return NULL;
865 
866 #ifdef CONFIG_DM_ETH
867 	buf = dp_fill(buf, eth_get_dev());
868 #else
869 	memcpy(buf, &ROOT, sizeof(ROOT));
870 	buf += sizeof(ROOT);
871 
872 	ndp = buf;
873 	ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
874 	ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
875 	ndp->dp.length = sizeof(*ndp);
876 	ndp->if_type = 1; /* Ethernet */
877 	memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
878 	buf = &ndp[1];
879 #endif
880 
881 	*((struct efi_device_path *)buf) = END;
882 
883 	return start;
884 }
885 #endif
886 
887 /* Construct a device-path for memory-mapped image */
888 struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
889 					uint64_t start_address,
890 					uint64_t end_address)
891 {
892 	struct efi_device_path_memory *mdp;
893 	void *buf, *start;
894 
895 	start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
896 	if (!buf)
897 		return NULL;
898 
899 	mdp = buf;
900 	mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
901 	mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
902 	mdp->dp.length = sizeof(*mdp);
903 	mdp->memory_type = memory_type;
904 	mdp->start_address = start_address;
905 	mdp->end_address = end_address;
906 	buf = &mdp[1];
907 
908 	*((struct efi_device_path *)buf) = END;
909 
910 	return start;
911 }
912 
913 /*
914  * Helper to split a full device path (containing both device and file
915  * parts) into it's constituent parts.
916  */
917 efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
918 				    struct efi_device_path **device_path,
919 				    struct efi_device_path **file_path)
920 {
921 	struct efi_device_path *p, *dp, *fp;
922 
923 	*device_path = NULL;
924 	*file_path = NULL;
925 	dp = efi_dp_dup(full_path);
926 	if (!dp)
927 		return EFI_OUT_OF_RESOURCES;
928 	p = dp;
929 	while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
930 		p = efi_dp_next(p);
931 		if (!p)
932 			return EFI_OUT_OF_RESOURCES;
933 	}
934 	fp = efi_dp_dup(p);
935 	if (!fp)
936 		return EFI_OUT_OF_RESOURCES;
937 	p->type = DEVICE_PATH_TYPE_END;
938 	p->sub_type = DEVICE_PATH_SUB_TYPE_END;
939 	p->length = sizeof(*p);
940 
941 	*device_path = dp;
942 	*file_path = fp;
943 	return EFI_SUCCESS;
944 }
945 
946 efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
947 			      const char *path,
948 			      struct efi_device_path **device,
949 			      struct efi_device_path **file)
950 {
951 	int is_net;
952 	struct blk_desc *desc = NULL;
953 	disk_partition_t fs_partition;
954 	int part = 0;
955 	char filename[32] = { 0 }; /* dp->str is u16[32] long */
956 	char *s;
957 
958 	if (path && !file)
959 		return EFI_INVALID_PARAMETER;
960 
961 	is_net = !strcmp(dev, "Net");
962 	if (!is_net) {
963 		part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
964 					       1);
965 		if (part < 0)
966 			return EFI_INVALID_PARAMETER;
967 
968 		if (device)
969 			*device = efi_dp_from_part(desc, part);
970 	} else {
971 #ifdef CONFIG_NET
972 		if (device)
973 			*device = efi_dp_from_eth();
974 #endif
975 	}
976 
977 	if (!path)
978 		return EFI_SUCCESS;
979 
980 	if (!is_net) {
981 		/* Add leading / to fs paths, because they're absolute */
982 		snprintf(filename, sizeof(filename), "/%s", path);
983 	} else {
984 		snprintf(filename, sizeof(filename), "%s", path);
985 	}
986 	/* DOS style file path: */
987 	s = filename;
988 	while ((s = strchr(s, '/')))
989 		*s++ = '\\';
990 	*file = efi_dp_from_file(((!is_net && device) ? desc : NULL),
991 				 part, filename);
992 
993 	return EFI_SUCCESS;
994 }
995