blob: 7ae14f342396ad2235e8b9b8edffb139d5451dc0 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Rob Clarkb66c60d2017-09-13 18:05:28 -04002/*
3 * EFI device path from u-boot device-model mapping
4 *
5 * (C) Copyright 2017 Rob Clark
Rob Clarkb66c60d2017-09-13 18:05:28 -04006 */
7
8#include <common.h>
9#include <blk.h>
10#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Simon Glass90526e92020-05-10 11:39:56 -060012#include <net.h>
Rob Clarkb66c60d2017-09-13 18:05:28 -040013#include <usb.h>
14#include <mmc.h>
Patrick Wildtf2d247d2019-10-03 16:24:17 +020015#include <nvme.h>
Rob Clarkb66c60d2017-09-13 18:05:28 -040016#include <efi_loader.h>
Rob Clarkb66c60d2017-09-13 18:05:28 -040017#include <part.h>
AKASHI Takahiro23ad52f2019-09-12 13:52:35 +090018#include <sandboxblockdev.h>
Heinrich Schuchardt046fe7b2019-07-14 19:26:47 +020019#include <asm-generic/unaligned.h>
AKASHI Takahiro08c51ff2019-10-09 16:19:52 +090020#include <linux/compat.h> /* U16_MAX */
Rob Clarkb66c60d2017-09-13 18:05:28 -040021
AKASHI Takahiro23ad52f2019-09-12 13:52:35 +090022#ifdef CONFIG_SANDBOX
23const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
24#endif
Heinrich Schuchardt19ecced2020-05-20 22:39:35 +020025#ifdef CONFIG_VIRTIO_BLK
26const efi_guid_t efi_guid_virtio_dev = U_BOOT_VIRTIO_DEV_GUID;
27#endif
AKASHI Takahiro23ad52f2019-09-12 13:52:35 +090028
Rob Clarkb66c60d2017-09-13 18:05:28 -040029/* template END node: */
30static const struct efi_device_path END = {
31 .type = DEVICE_PATH_TYPE_END,
32 .sub_type = DEVICE_PATH_SUB_TYPE_END,
33 .length = sizeof(END),
34};
35
Rob Clarkb66c60d2017-09-13 18:05:28 -040036/* template ROOT node: */
37static const struct efi_device_path_vendor ROOT = {
38 .dp = {
39 .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
40 .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
41 .length = sizeof(ROOT),
42 },
43 .guid = U_BOOT_GUID,
44};
45
Heinrich Schuchardt66b051d2017-12-11 12:56:39 +010046#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
47/*
48 * Determine if an MMC device is an SD card.
49 *
50 * @desc block device descriptor
51 * @return true if the device is an SD card
52 */
53static bool is_sd(struct blk_desc *desc)
54{
55 struct mmc *mmc = find_mmc_device(desc->devnum);
56
57 if (!mmc)
58 return false;
59
60 return IS_SD(mmc) != 0U;
61}
62#endif
63
Rob Clarkb66c60d2017-09-13 18:05:28 -040064static void *dp_alloc(size_t sz)
65{
66 void *buf;
67
Heinrich Schuchardt04298682018-01-19 20:24:37 +010068 if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) !=
69 EFI_SUCCESS) {
70 debug("EFI: ERROR: out of memory in %s\n", __func__);
Rob Clarkb66c60d2017-09-13 18:05:28 -040071 return NULL;
Heinrich Schuchardt04298682018-01-19 20:24:37 +010072 }
Rob Clarkb66c60d2017-09-13 18:05:28 -040073
Patrick Wildteab2dc32018-03-25 19:54:03 +020074 memset(buf, 0, sz);
Rob Clarkb66c60d2017-09-13 18:05:28 -040075 return buf;
76}
77
78/*
79 * Iterate to next block in device-path, terminating (returning NULL)
80 * at /End* node.
81 */
82struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
83{
84 if (dp == NULL)
85 return NULL;
86 if (dp->type == DEVICE_PATH_TYPE_END)
87 return NULL;
88 dp = ((void *)dp) + dp->length;
89 if (dp->type == DEVICE_PATH_TYPE_END)
90 return NULL;
91 return (struct efi_device_path *)dp;
92}
93
94/*
95 * Compare two device-paths, stopping when the shorter of the two hits
Heinrich Schuchardteb3bc8b2018-10-17 21:55:24 +020096 * an End* node. This is useful to, for example, compare a device-path
Rob Clarkb66c60d2017-09-13 18:05:28 -040097 * representing a device with one representing a file on the device, or
98 * a device with a parent device.
99 */
Heinrich Schuchardtff401d32017-10-26 19:25:48 +0200100int efi_dp_match(const struct efi_device_path *a,
101 const struct efi_device_path *b)
Rob Clarkb66c60d2017-09-13 18:05:28 -0400102{
103 while (1) {
104 int ret;
105
106 ret = memcmp(&a->length, &b->length, sizeof(a->length));
107 if (ret)
108 return ret;
109
110 ret = memcmp(a, b, a->length);
111 if (ret)
112 return ret;
113
114 a = efi_dp_next(a);
115 b = efi_dp_next(b);
116
117 if (!a || !b)
118 return 0;
119 }
120}
121
Rob Clarkb66c60d2017-09-13 18:05:28 -0400122/*
Heinrich Schuchardteb3bc8b2018-10-17 21:55:24 +0200123 * We can have device paths that start with a USB WWID or a USB Class node,
124 * and a few other cases which don't encode the full device path with bus
125 * hierarchy:
Rob Clarkb66c60d2017-09-13 18:05:28 -0400126 *
127 * - MESSAGING:USB_WWID
128 * - MESSAGING:USB_CLASS
129 * - MEDIA:FILE_PATH
130 * - MEDIA:HARD_DRIVE
131 * - MESSAGING:URI
Heinrich Schuchardteb3bc8b2018-10-17 21:55:24 +0200132 *
133 * See UEFI spec (section 3.1.2, about short-form device-paths)
Rob Clarkb66c60d2017-09-13 18:05:28 -0400134 */
135static struct efi_device_path *shorten_path(struct efi_device_path *dp)
136{
137 while (dp) {
138 /*
139 * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..
140 * in practice fallback.efi just uses MEDIA:HARD_DRIVE
141 * so not sure when we would see these other cases.
142 */
143 if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||
144 EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
145 EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
146 return dp;
147
148 dp = efi_dp_next(dp);
149 }
150
151 return dp;
152}
153
154static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
155 struct efi_device_path **rem)
156{
157 struct efi_object *efiobj;
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200158 efi_uintn_t dp_size = efi_dp_instance_size(dp);
Rob Clarkb66c60d2017-09-13 18:05:28 -0400159
160 list_for_each_entry(efiobj, &efi_obj_list, link) {
Heinrich Schuchardt72292ab2017-11-26 14:05:16 +0100161 struct efi_handler *handler;
162 struct efi_device_path *obj_dp;
163 efi_status_t ret;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400164
Heinrich Schuchardtfae01182018-09-26 05:27:55 +0200165 ret = efi_search_protocol(efiobj,
Heinrich Schuchardt72292ab2017-11-26 14:05:16 +0100166 &efi_guid_device_path, &handler);
167 if (ret != EFI_SUCCESS)
168 continue;
169 obj_dp = handler->protocol_interface;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400170
Heinrich Schuchardt72292ab2017-11-26 14:05:16 +0100171 do {
172 if (efi_dp_match(dp, obj_dp) == 0) {
173 if (rem) {
Alexander Graf905cb9e2017-12-11 14:29:46 +0100174 /*
175 * Allow partial matches, but inform
176 * the caller.
177 */
Heinrich Schuchardt72292ab2017-11-26 14:05:16 +0100178 *rem = ((void *)dp) +
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200179 efi_dp_instance_size(obj_dp);
Alexander Graf905cb9e2017-12-11 14:29:46 +0100180 return efiobj;
181 } else {
182 /* Only return on exact matches */
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200183 if (efi_dp_instance_size(obj_dp) ==
184 dp_size)
Alexander Graf905cb9e2017-12-11 14:29:46 +0100185 return efiobj;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400186 }
Heinrich Schuchardt72292ab2017-11-26 14:05:16 +0100187 }
Rob Clarkb66c60d2017-09-13 18:05:28 -0400188
Heinrich Schuchardt72292ab2017-11-26 14:05:16 +0100189 obj_dp = shorten_path(efi_dp_next(obj_dp));
190 } while (short_path && obj_dp);
Rob Clarkb66c60d2017-09-13 18:05:28 -0400191 }
192
193 return NULL;
194}
195
Rob Clarkb66c60d2017-09-13 18:05:28 -0400196/*
197 * Find an efiobj from device-path, if 'rem' is not NULL, returns the
198 * remaining part of the device path after the matched object.
199 */
200struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
201 struct efi_device_path **rem)
202{
203 struct efi_object *efiobj;
204
Alexander Graf905cb9e2017-12-11 14:29:46 +0100205 /* Search for an exact match first */
206 efiobj = find_obj(dp, false, NULL);
Rob Clarkb66c60d2017-09-13 18:05:28 -0400207
Alexander Graf905cb9e2017-12-11 14:29:46 +0100208 /* Then for a fuzzy match */
209 if (!efiobj)
210 efiobj = find_obj(dp, false, rem);
211
212 /* And now for a fuzzy short match */
Rob Clarkb66c60d2017-09-13 18:05:28 -0400213 if (!efiobj)
214 efiobj = find_obj(dp, true, rem);
215
216 return efiobj;
217}
218
Heinrich Schuchardt65436f92018-01-19 20:24:49 +0100219/*
220 * Determine the last device path node that is not the end node.
221 *
222 * @dp device path
223 * @return last node before the end node if it exists
224 * otherwise NULL
225 */
226const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
227{
228 struct efi_device_path *ret;
229
230 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
231 return NULL;
232 while (dp) {
233 ret = (struct efi_device_path *)dp;
234 dp = efi_dp_next(dp);
235 }
236 return ret;
237}
238
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200239/* get size of the first device path instance excluding end node */
240efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
Rob Clarkb66c60d2017-09-13 18:05:28 -0400241{
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200242 efi_uintn_t sz = 0;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400243
Heinrich Schuchardtadb57512018-04-16 07:59:07 +0200244 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
245 return 0;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400246 while (dp) {
247 sz += dp->length;
248 dp = efi_dp_next(dp);
249 }
250
251 return sz;
252}
253
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200254/* get size of multi-instance device path excluding end node */
255efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
256{
257 const struct efi_device_path *p = dp;
258
259 if (!p)
260 return 0;
261 while (p->type != DEVICE_PATH_TYPE_END ||
262 p->sub_type != DEVICE_PATH_SUB_TYPE_END)
263 p = (void *)p + p->length;
264
265 return (void *)p - (void *)dp;
266}
267
268/* copy multi-instance device path */
Rob Clarkb66c60d2017-09-13 18:05:28 -0400269struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
270{
271 struct efi_device_path *ndp;
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200272 size_t sz = efi_dp_size(dp) + sizeof(END);
Rob Clarkb66c60d2017-09-13 18:05:28 -0400273
274 if (!dp)
275 return NULL;
276
277 ndp = dp_alloc(sz);
Heinrich Schuchardt04298682018-01-19 20:24:37 +0100278 if (!ndp)
279 return NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400280 memcpy(ndp, dp, sz);
281
282 return ndp;
283}
284
285struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
286 const struct efi_device_path *dp2)
287{
288 struct efi_device_path *ret;
289
Heinrich Schuchardt07836342018-04-16 07:59:06 +0200290 if (!dp1 && !dp2) {
291 /* return an end node */
292 ret = efi_dp_dup(&END);
293 } else if (!dp1) {
Rob Clarkb66c60d2017-09-13 18:05:28 -0400294 ret = efi_dp_dup(dp2);
295 } else if (!dp2) {
296 ret = efi_dp_dup(dp1);
297 } else {
298 /* both dp1 and dp2 are non-null */
299 unsigned sz1 = efi_dp_size(dp1);
300 unsigned sz2 = efi_dp_size(dp2);
301 void *p = dp_alloc(sz1 + sz2 + sizeof(END));
Heinrich Schuchardt04298682018-01-19 20:24:37 +0100302 if (!p)
303 return NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400304 memcpy(p, dp1, sz1);
Heinrich Schuchardt07836342018-04-16 07:59:06 +0200305 /* the end node of the second device path has to be retained */
306 memcpy(p + sz1, dp2, sz2 + sizeof(END));
Rob Clarkb66c60d2017-09-13 18:05:28 -0400307 ret = p;
308 }
309
310 return ret;
311}
312
313struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
314 const struct efi_device_path *node)
315{
316 struct efi_device_path *ret;
317
318 if (!node && !dp) {
319 ret = efi_dp_dup(&END);
320 } else if (!node) {
321 ret = efi_dp_dup(dp);
322 } else if (!dp) {
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200323 size_t sz = node->length;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400324 void *p = dp_alloc(sz + sizeof(END));
Heinrich Schuchardt04298682018-01-19 20:24:37 +0100325 if (!p)
326 return NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400327 memcpy(p, node, sz);
328 memcpy(p + sz, &END, sizeof(END));
329 ret = p;
330 } else {
331 /* both dp and node are non-null */
Heinrich Schuchardtf6dd3f32018-04-16 07:59:08 +0200332 size_t sz = efi_dp_size(dp);
Rob Clarkb66c60d2017-09-13 18:05:28 -0400333 void *p = dp_alloc(sz + node->length + sizeof(END));
Heinrich Schuchardt04298682018-01-19 20:24:37 +0100334 if (!p)
335 return NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400336 memcpy(p, dp, sz);
337 memcpy(p + sz, node, node->length);
338 memcpy(p + sz + node->length, &END, sizeof(END));
339 ret = p;
340 }
341
342 return ret;
343}
344
Heinrich Schuchardt211314c2018-04-16 07:59:05 +0200345struct efi_device_path *efi_dp_create_device_node(const u8 type,
346 const u8 sub_type,
347 const u16 length)
348{
349 struct efi_device_path *ret;
350
Heinrich Schuchardt7d1e4b72019-04-23 00:51:01 +0200351 if (length < sizeof(struct efi_device_path))
352 return NULL;
353
Heinrich Schuchardt211314c2018-04-16 07:59:05 +0200354 ret = dp_alloc(length);
355 if (!ret)
356 return ret;
357 ret->type = type;
358 ret->sub_type = sub_type;
359 ret->length = length;
360 return ret;
361}
362
Heinrich Schuchardt3acef5d2018-04-16 07:59:09 +0200363struct efi_device_path *efi_dp_append_instance(
364 const struct efi_device_path *dp,
365 const struct efi_device_path *dpi)
366{
367 size_t sz, szi;
368 struct efi_device_path *p, *ret;
369
370 if (!dpi)
371 return NULL;
372 if (!dp)
373 return efi_dp_dup(dpi);
374 sz = efi_dp_size(dp);
375 szi = efi_dp_instance_size(dpi);
376 p = dp_alloc(sz + szi + 2 * sizeof(END));
377 if (!p)
378 return NULL;
379 ret = p;
380 memcpy(p, dp, sz + sizeof(END));
381 p = (void *)p + sz;
382 p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
383 p = (void *)p + sizeof(END);
384 memcpy(p, dpi, szi);
385 p = (void *)p + szi;
386 memcpy(p, &END, sizeof(END));
387 return ret;
388}
389
390struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
391 efi_uintn_t *size)
392{
393 size_t sz;
394 struct efi_device_path *p;
395
396 if (size)
397 *size = 0;
398 if (!dp || !*dp)
399 return NULL;
Heinrich Schuchardt3acef5d2018-04-16 07:59:09 +0200400 sz = efi_dp_instance_size(*dp);
401 p = dp_alloc(sz + sizeof(END));
402 if (!p)
403 return NULL;
404 memcpy(p, *dp, sz + sizeof(END));
405 *dp = (void *)*dp + sz;
406 if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
407 *dp = (void *)*dp + sizeof(END);
408 else
409 *dp = NULL;
410 if (size)
411 *size = sz + sizeof(END);
412 return p;
413}
414
415bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
416{
417 const struct efi_device_path *p = dp;
418
419 if (!p)
420 return false;
421 while (p->type != DEVICE_PATH_TYPE_END)
422 p = (void *)p + p->length;
423 return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
424}
425
Rob Clarkb66c60d2017-09-13 18:05:28 -0400426#ifdef CONFIG_DM
427/* size of device-path not including END node for device and all parents
428 * up to the root device.
429 */
Heinrich Schuchardt246e6012019-11-10 02:16:33 +0100430__maybe_unused static unsigned int dp_size(struct udevice *dev)
Rob Clarkb66c60d2017-09-13 18:05:28 -0400431{
432 if (!dev || !dev->driver)
433 return sizeof(ROOT);
434
435 switch (dev->driver->id) {
436 case UCLASS_ROOT:
437 case UCLASS_SIMPLE_BUS:
438 /* stop traversing parents at this point: */
439 return sizeof(ROOT);
Heinrich Schuchardt9dfd84d2018-01-20 21:02:18 +0100440 case UCLASS_ETH:
441 return dp_size(dev->parent) +
442 sizeof(struct efi_device_path_mac_addr);
Heinrich Schuchardtaf3106a2017-12-11 12:56:44 +0100443#ifdef CONFIG_BLK
444 case UCLASS_BLK:
445 switch (dev->parent->uclass->uc_drv->id) {
446#ifdef CONFIG_IDE
447 case UCLASS_IDE:
448 return dp_size(dev->parent) +
449 sizeof(struct efi_device_path_atapi);
450#endif
451#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
452 case UCLASS_SCSI:
453 return dp_size(dev->parent) +
454 sizeof(struct efi_device_path_scsi);
455#endif
Heinrich Schuchardt9dfd84d2018-01-20 21:02:18 +0100456#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
457 case UCLASS_MMC:
458 return dp_size(dev->parent) +
459 sizeof(struct efi_device_path_sd_mmc_path);
460#endif
Heinrich Schuchardtbf3bcef2020-05-20 23:12:02 +0200461#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
462 case UCLASS_AHCI:
463 return dp_size(dev->parent) +
464 sizeof(struct efi_device_path_sata);
465#endif
Patrick Wildtf2d247d2019-10-03 16:24:17 +0200466#if defined(CONFIG_NVME)
467 case UCLASS_NVME:
468 return dp_size(dev->parent) +
469 sizeof(struct efi_device_path_nvme);
470#endif
AKASHI Takahiro23ad52f2019-09-12 13:52:35 +0900471#ifdef CONFIG_SANDBOX
472 case UCLASS_ROOT:
473 /*
474 * Sandbox's host device will be represented
475 * as vendor device with extra one byte for
476 * device number
477 */
478 return dp_size(dev->parent)
479 + sizeof(struct efi_device_path_vendor) + 1;
480#endif
Heinrich Schuchardt19ecced2020-05-20 22:39:35 +0200481#ifdef CONFIG_VIRTIO_BLK
482 case UCLASS_VIRTIO:
483 /*
484 * Virtio devices will be represented as a vendor
485 * device node with an extra byte for the device
486 * number.
487 */
488 return dp_size(dev->parent)
489 + sizeof(struct efi_device_path_vendor) + 1;
490#endif
Heinrich Schuchardtaf3106a2017-12-11 12:56:44 +0100491 default:
492 return dp_size(dev->parent);
493 }
494#endif
Heinrich Schuchardt9dfd84d2018-01-20 21:02:18 +0100495#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
Rob Clarkb66c60d2017-09-13 18:05:28 -0400496 case UCLASS_MMC:
497 return dp_size(dev->parent) +
498 sizeof(struct efi_device_path_sd_mmc_path);
Heinrich Schuchardt9dfd84d2018-01-20 21:02:18 +0100499#endif
Rob Clarkb66c60d2017-09-13 18:05:28 -0400500 case UCLASS_MASS_STORAGE:
501 case UCLASS_USB_HUB:
502 return dp_size(dev->parent) +
503 sizeof(struct efi_device_path_usb_class);
504 default:
505 /* just skip over unknown classes: */
506 return dp_size(dev->parent);
507 }
508}
509
Heinrich Schuchardtaf3106a2017-12-11 12:56:44 +0100510/*
511 * Recursively build a device path.
512 *
513 * @buf pointer to the end of the device path
514 * @dev device
515 * @return pointer to the end of the device path
516 */
Heinrich Schuchardt246e6012019-11-10 02:16:33 +0100517__maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
Rob Clarkb66c60d2017-09-13 18:05:28 -0400518{
519 if (!dev || !dev->driver)
520 return buf;
521
522 switch (dev->driver->id) {
523 case UCLASS_ROOT:
524 case UCLASS_SIMPLE_BUS: {
525 /* stop traversing parents at this point: */
526 struct efi_device_path_vendor *vdp = buf;
527 *vdp = ROOT;
528 return &vdp[1];
529 }
Heinrich Schuchardt9dfd84d2018-01-20 21:02:18 +0100530#ifdef CONFIG_DM_ETH
531 case UCLASS_ETH: {
532 struct efi_device_path_mac_addr *dp =
533 dp_fill(buf, dev->parent);
534 struct eth_pdata *pdata = dev->platdata;
535
536 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
537 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
538 dp->dp.length = sizeof(*dp);
539 memset(&dp->mac, 0, sizeof(dp->mac));
540 /* We only support IPv4 */
541 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
542 /* Ethernet */
543 dp->if_type = 1;
544 return &dp[1];
545 }
546#endif
Heinrich Schuchardtaf3106a2017-12-11 12:56:44 +0100547#ifdef CONFIG_BLK
548 case UCLASS_BLK:
549 switch (dev->parent->uclass->uc_drv->id) {
AKASHI Takahiro23ad52f2019-09-12 13:52:35 +0900550#ifdef CONFIG_SANDBOX
551 case UCLASS_ROOT: {
552 /* stop traversing parents at this point: */
Heinrich Schuchardt549b79e2020-05-06 01:28:08 +0200553 struct efi_device_path_vendor *dp;
AKASHI Takahiro23ad52f2019-09-12 13:52:35 +0900554 struct blk_desc *desc = dev_get_uclass_platdata(dev);
555
556 dp_fill(buf, dev->parent);
557 dp = buf;
558 ++dp;
559 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
560 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
561 dp->dp.length = sizeof(*dp) + 1;
562 memcpy(&dp->guid, &efi_guid_host_dev,
563 sizeof(efi_guid_t));
564 dp->vendor_data[0] = desc->devnum;
565 return &dp->vendor_data[1];
566 }
567#endif
Heinrich Schuchardt19ecced2020-05-20 22:39:35 +0200568#ifdef CONFIG_VIRTIO_BLK
569 case UCLASS_VIRTIO: {
570 struct efi_device_path_vendor *dp;
571 struct blk_desc *desc = dev_get_uclass_platdata(dev);
572
573 dp_fill(buf, dev->parent);
574 dp = buf;
575 ++dp;
576 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
577 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
578 dp->dp.length = sizeof(*dp) + 1;
579 memcpy(&dp->guid, &efi_guid_virtio_dev,
580 sizeof(efi_guid_t));
581 dp->vendor_data[0] = desc->devnum;
582 return &dp->vendor_data[1];
583 }
584#endif
Heinrich Schuchardtaf3106a2017-12-11 12:56:44 +0100585#ifdef CONFIG_IDE
586 case UCLASS_IDE: {
587 struct efi_device_path_atapi *dp =
588 dp_fill(buf, dev->parent);
589 struct blk_desc *desc = dev_get_uclass_platdata(dev);
590
591 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
592 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
593 dp->dp.length = sizeof(*dp);
594 dp->logical_unit_number = desc->devnum;
595 dp->primary_secondary = IDE_BUS(desc->devnum);
596 dp->slave_master = desc->devnum %
597 (CONFIG_SYS_IDE_MAXDEVICE /
598 CONFIG_SYS_IDE_MAXBUS);
599 return &dp[1];
600 }
601#endif
602#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
603 case UCLASS_SCSI: {
604 struct efi_device_path_scsi *dp =
605 dp_fill(buf, dev->parent);
606 struct blk_desc *desc = dev_get_uclass_platdata(dev);
607
608 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
609 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
610 dp->dp.length = sizeof(*dp);
611 dp->logical_unit_number = desc->lun;
612 dp->target_id = desc->target;
613 return &dp[1];
614 }
615#endif
Heinrich Schuchardt9dfd84d2018-01-20 21:02:18 +0100616#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
617 case UCLASS_MMC: {
618 struct efi_device_path_sd_mmc_path *sddp =
619 dp_fill(buf, dev->parent);
620 struct blk_desc *desc = dev_get_uclass_platdata(dev);
621
622 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
623 sddp->dp.sub_type = is_sd(desc) ?
624 DEVICE_PATH_SUB_TYPE_MSG_SD :
625 DEVICE_PATH_SUB_TYPE_MSG_MMC;
626 sddp->dp.length = sizeof(*sddp);
627 sddp->slot_number = dev->seq;
628 return &sddp[1];
629 }
630#endif
Heinrich Schuchardtbf3bcef2020-05-20 23:12:02 +0200631#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
632 case UCLASS_AHCI: {
633 struct efi_device_path_sata *dp =
634 dp_fill(buf, dev->parent);
635 struct blk_desc *desc = dev_get_uclass_platdata(dev);
636
637 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
638 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SATA;
639 dp->dp.length = sizeof(*dp);
640 dp->hba_port = desc->devnum;
641 /* default 0xffff implies no port multiplier */
642 dp->port_multiplier_port = 0xffff;
643 dp->logical_unit_number = desc->lun;
644 return &dp[1];
645 }
646#endif
Patrick Wildtf2d247d2019-10-03 16:24:17 +0200647#if defined(CONFIG_NVME)
648 case UCLASS_NVME: {
649 struct efi_device_path_nvme *dp =
650 dp_fill(buf, dev->parent);
651 u32 ns_id;
652
653 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
654 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_NVME;
655 dp->dp.length = sizeof(*dp);
656 nvme_get_namespace_id(dev, &ns_id, dp->eui64);
657 memcpy(&dp->ns_id, &ns_id, sizeof(ns_id));
658 return &dp[1];
659 }
660#endif
Heinrich Schuchardtaf3106a2017-12-11 12:56:44 +0100661 default:
Heinrich Schuchardt9dfd84d2018-01-20 21:02:18 +0100662 debug("%s(%u) %s: unhandled parent class: %s (%u)\n",
663 __FILE__, __LINE__, __func__,
664 dev->name, dev->parent->uclass->uc_drv->id);
Heinrich Schuchardtaf3106a2017-12-11 12:56:44 +0100665 return dp_fill(buf, dev->parent);
666 }
667#endif
Rob Clarkb66c60d2017-09-13 18:05:28 -0400668#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
669 case UCLASS_MMC: {
670 struct efi_device_path_sd_mmc_path *sddp =
671 dp_fill(buf, dev->parent);
672 struct mmc *mmc = mmc_get_mmc_dev(dev);
673 struct blk_desc *desc = mmc_get_blk_desc(mmc);
674
675 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt66b051d2017-12-11 12:56:39 +0100676 sddp->dp.sub_type = is_sd(desc) ?
677 DEVICE_PATH_SUB_TYPE_MSG_SD :
678 DEVICE_PATH_SUB_TYPE_MSG_MMC;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400679 sddp->dp.length = sizeof(*sddp);
680 sddp->slot_number = dev->seq;
681
682 return &sddp[1];
683 }
684#endif
685 case UCLASS_MASS_STORAGE:
686 case UCLASS_USB_HUB: {
687 struct efi_device_path_usb_class *udp =
688 dp_fill(buf, dev->parent);
689 struct usb_device *udev = dev_get_parent_priv(dev);
690 struct usb_device_descriptor *desc = &udev->descriptor;
691
692 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
693 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
694 udp->dp.length = sizeof(*udp);
695 udp->vendor_id = desc->idVendor;
696 udp->product_id = desc->idProduct;
697 udp->device_class = desc->bDeviceClass;
698 udp->device_subclass = desc->bDeviceSubClass;
699 udp->device_protocol = desc->bDeviceProtocol;
700
701 return &udp[1];
702 }
703 default:
Heinrich Schuchardt9dfd84d2018-01-20 21:02:18 +0100704 debug("%s(%u) %s: unhandled device class: %s (%u)\n",
705 __FILE__, __LINE__, __func__,
Rob Clarkb66c60d2017-09-13 18:05:28 -0400706 dev->name, dev->driver->id);
707 return dp_fill(buf, dev->parent);
708 }
709}
Rob Clarkb66c60d2017-09-13 18:05:28 -0400710#endif
711
712static unsigned dp_part_size(struct blk_desc *desc, int part)
713{
714 unsigned dpsize;
715
716#ifdef CONFIG_BLK
Heinrich Schuchardt2bc61b82017-12-11 12:56:43 +0100717 {
718 struct udevice *dev;
719 int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
720
721 if (ret)
722 dev = desc->bdev->parent;
723 dpsize = dp_size(dev);
724 }
Rob Clarkb66c60d2017-09-13 18:05:28 -0400725#else
726 dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
727#endif
728
729 if (part == 0) /* the actual disk, not a partition */
730 return dpsize;
731
732 if (desc->part_type == PART_TYPE_ISO)
733 dpsize += sizeof(struct efi_device_path_cdrom_path);
734 else
735 dpsize += sizeof(struct efi_device_path_hard_drive_path);
736
737 return dpsize;
738}
739
Heinrich Schuchardtbde6bfe2017-12-11 12:56:42 +0100740/*
Heinrich Schuchardt98d48bd2018-01-19 20:24:46 +0100741 * Create a device node for a block device partition.
Heinrich Schuchardtbde6bfe2017-12-11 12:56:42 +0100742 *
Heinrich Schuchardteb3bc8b2018-10-17 21:55:24 +0200743 * @buf buffer to which the device path is written
Heinrich Schuchardtbde6bfe2017-12-11 12:56:42 +0100744 * @desc block device descriptor
745 * @part partition number, 0 identifies a block device
746 */
Heinrich Schuchardt98d48bd2018-01-19 20:24:46 +0100747static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
Rob Clarkb66c60d2017-09-13 18:05:28 -0400748{
Simon Glass05289792020-05-10 11:39:57 -0600749 struct disk_partition info;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400750
Rob Clarkb66c60d2017-09-13 18:05:28 -0400751 part_get_info(desc, part, &info);
752
753 if (desc->part_type == PART_TYPE_ISO) {
754 struct efi_device_path_cdrom_path *cddp = buf;
755
Heinrich Schuchardt7b982f02017-12-11 12:56:40 +0100756 cddp->boot_entry = part;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400757 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
758 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
759 cddp->dp.length = sizeof(*cddp);
760 cddp->partition_start = info.start;
Heinrich Schuchardtd0384d52019-09-04 13:56:01 +0200761 cddp->partition_size = info.size;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400762
763 buf = &cddp[1];
764 } else {
765 struct efi_device_path_hard_drive_path *hddp = buf;
766
767 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
768 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
769 hddp->dp.length = sizeof(*hddp);
Heinrich Schuchardt7b982f02017-12-11 12:56:40 +0100770 hddp->partition_number = part;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400771 hddp->partition_start = info.start;
772 hddp->partition_end = info.size;
773 if (desc->part_type == PART_TYPE_EFI)
774 hddp->partmap_type = 2;
775 else
776 hddp->partmap_type = 1;
Jonathan Grayb6e9e092017-11-22 14:18:59 +1100777
778 switch (desc->sig_type) {
779 case SIG_TYPE_NONE:
780 default:
781 hddp->signature_type = 0;
782 memset(hddp->partition_signature, 0,
783 sizeof(hddp->partition_signature));
784 break;
785 case SIG_TYPE_MBR:
786 hddp->signature_type = 1;
787 memset(hddp->partition_signature, 0,
788 sizeof(hddp->partition_signature));
789 memcpy(hddp->partition_signature, &desc->mbr_sig,
790 sizeof(desc->mbr_sig));
791 break;
792 case SIG_TYPE_GUID:
793 hddp->signature_type = 2;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400794 memcpy(hddp->partition_signature, &desc->guid_sig,
795 sizeof(hddp->partition_signature));
Jonathan Grayb6e9e092017-11-22 14:18:59 +1100796 break;
797 }
Rob Clarkb66c60d2017-09-13 18:05:28 -0400798
799 buf = &hddp[1];
800 }
801
802 return buf;
803}
804
Heinrich Schuchardt98d48bd2018-01-19 20:24:46 +0100805/*
806 * Create a device path for a block device or one of its partitions.
807 *
Heinrich Schuchardteb3bc8b2018-10-17 21:55:24 +0200808 * @buf buffer to which the device path is written
Heinrich Schuchardt98d48bd2018-01-19 20:24:46 +0100809 * @desc block device descriptor
810 * @part partition number, 0 identifies a block device
811 */
812static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
813{
814#ifdef CONFIG_BLK
815 {
816 struct udevice *dev;
817 int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
818
819 if (ret)
820 dev = desc->bdev->parent;
821 buf = dp_fill(buf, dev);
822 }
823#else
824 /*
825 * We *could* make a more accurate path, by looking at if_type
826 * and handling all the different cases like we do for non-
Heinrich Schuchardteb3bc8b2018-10-17 21:55:24 +0200827 * legacy (i.e. CONFIG_BLK=y) case. But most important thing
Heinrich Schuchardt98d48bd2018-01-19 20:24:46 +0100828 * is just to have a unique device-path for if_type+devnum.
829 * So map things to a fictitious USB device.
830 */
831 struct efi_device_path_usb *udp;
832
833 memcpy(buf, &ROOT, sizeof(ROOT));
834 buf += sizeof(ROOT);
835
836 udp = buf;
837 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
838 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
839 udp->dp.length = sizeof(*udp);
840 udp->parent_port_number = desc->if_type;
841 udp->usb_interface = desc->devnum;
842 buf = &udp[1];
843#endif
844
845 if (part == 0) /* the actual disk, not a partition */
846 return buf;
847
848 return dp_part_node(buf, desc, part);
849}
Rob Clarkb66c60d2017-09-13 18:05:28 -0400850
Heinrich Schuchardteb3bc8b2018-10-17 21:55:24 +0200851/* Construct a device-path from a partition on a block device: */
Rob Clarkb66c60d2017-09-13 18:05:28 -0400852struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
853{
854 void *buf, *start;
855
856 start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));
Heinrich Schuchardt04298682018-01-19 20:24:37 +0100857 if (!buf)
858 return NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400859
860 buf = dp_part_fill(buf, desc, part);
861
862 *((struct efi_device_path *)buf) = END;
863
864 return start;
865}
866
Heinrich Schuchardt98d48bd2018-01-19 20:24:46 +0100867/*
868 * Create a device node for a block device partition.
869 *
Heinrich Schuchardteb3bc8b2018-10-17 21:55:24 +0200870 * @buf buffer to which the device path is written
Heinrich Schuchardt98d48bd2018-01-19 20:24:46 +0100871 * @desc block device descriptor
872 * @part partition number, 0 identifies a block device
873 */
874struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
875{
876 efi_uintn_t dpsize;
877 void *buf;
878
879 if (desc->part_type == PART_TYPE_ISO)
880 dpsize = sizeof(struct efi_device_path_cdrom_path);
881 else
882 dpsize = sizeof(struct efi_device_path_hard_drive_path);
883 buf = dp_alloc(dpsize);
884
885 dp_part_node(buf, desc, part);
886
887 return buf;
888}
889
Heinrich Schuchardt046fe7b2019-07-14 19:26:47 +0200890/**
891 * path_to_uefi() - convert UTF-8 path to an UEFI style path
892 *
893 * Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
894 * separators and UTF-16).
895 *
896 * @src: source buffer
897 * @uefi: target buffer, possibly unaligned
898 */
899static void path_to_uefi(void *uefi, const char *src)
Rob Clarkb66c60d2017-09-13 18:05:28 -0400900{
Heinrich Schuchardt046fe7b2019-07-14 19:26:47 +0200901 u16 *pos = uefi;
902
903 /*
904 * efi_set_bootdev() calls this routine indirectly before the UEFI
905 * subsystem is initialized. So we cannot assume unaligned access to be
906 * enabled.
907 */
908 allow_unaligned();
909
910 while (*src) {
911 s32 code = utf8_get(&src);
912
913 if (code < 0)
914 code = '?';
915 else if (code == '/')
916 code = '\\';
917 utf16_put(code, &pos);
Rob Clarkb66c60d2017-09-13 18:05:28 -0400918 }
Heinrich Schuchardt046fe7b2019-07-14 19:26:47 +0200919 *pos = 0;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400920}
921
922/*
923 * If desc is NULL, this creates a path with only the file component,
924 * otherwise it creates a full path with both device and file components
925 */
926struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
927 const char *path)
928{
929 struct efi_device_path_file_path *fp;
930 void *buf, *start;
AKASHI Takahiro08c51ff2019-10-09 16:19:52 +0900931 size_t dpsize = 0, fpsize;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400932
933 if (desc)
934 dpsize = dp_part_size(desc, part);
935
Heinrich Schuchardt046fe7b2019-07-14 19:26:47 +0200936 fpsize = sizeof(struct efi_device_path) +
937 2 * (utf8_utf16_strlen(path) + 1);
AKASHI Takahiro08c51ff2019-10-09 16:19:52 +0900938 if (fpsize > U16_MAX)
939 return NULL;
940
Rob Clarkb66c60d2017-09-13 18:05:28 -0400941 dpsize += fpsize;
942
943 start = buf = dp_alloc(dpsize + sizeof(END));
Heinrich Schuchardt04298682018-01-19 20:24:37 +0100944 if (!buf)
945 return NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400946
947 if (desc)
948 buf = dp_part_fill(buf, desc, part);
949
950 /* add file-path: */
951 fp = buf;
952 fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
953 fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
AKASHI Takahiro08c51ff2019-10-09 16:19:52 +0900954 fp->dp.length = (u16)fpsize;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400955 path_to_uefi(fp->str, path);
956 buf += fpsize;
957
958 *((struct efi_device_path *)buf) = END;
959
960 return start;
961}
962
Joe Hershberger092f2f32018-04-13 15:26:39 -0500963#ifdef CONFIG_NET
Rob Clarkb66c60d2017-09-13 18:05:28 -0400964struct efi_device_path *efi_dp_from_eth(void)
965{
Alexander Graff9cfad12018-03-15 17:33:38 +0100966#ifndef CONFIG_DM_ETH
Rob Clarkb66c60d2017-09-13 18:05:28 -0400967 struct efi_device_path_mac_addr *ndp;
Alexander Graff9cfad12018-03-15 17:33:38 +0100968#endif
Rob Clarkb66c60d2017-09-13 18:05:28 -0400969 void *buf, *start;
970 unsigned dpsize = 0;
971
972 assert(eth_get_dev());
973
974#ifdef CONFIG_DM_ETH
975 dpsize += dp_size(eth_get_dev());
976#else
977 dpsize += sizeof(ROOT);
Rob Clarkb66c60d2017-09-13 18:05:28 -0400978 dpsize += sizeof(*ndp);
Alexander Graff9cfad12018-03-15 17:33:38 +0100979#endif
Rob Clarkb66c60d2017-09-13 18:05:28 -0400980
981 start = buf = dp_alloc(dpsize + sizeof(END));
Heinrich Schuchardt04298682018-01-19 20:24:37 +0100982 if (!buf)
983 return NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -0400984
985#ifdef CONFIG_DM_ETH
986 buf = dp_fill(buf, eth_get_dev());
987#else
988 memcpy(buf, &ROOT, sizeof(ROOT));
989 buf += sizeof(ROOT);
Rob Clarkb66c60d2017-09-13 18:05:28 -0400990
991 ndp = buf;
992 ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
993 ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
994 ndp->dp.length = sizeof(*ndp);
Alexander Graff9cfad12018-03-15 17:33:38 +0100995 ndp->if_type = 1; /* Ethernet */
Rob Clarkb66c60d2017-09-13 18:05:28 -0400996 memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
997 buf = &ndp[1];
Alexander Graff9cfad12018-03-15 17:33:38 +0100998#endif
Rob Clarkb66c60d2017-09-13 18:05:28 -0400999
1000 *((struct efi_device_path *)buf) = END;
1001
1002 return start;
1003}
1004#endif
1005
Rob Clarkbf192732017-10-10 08:23:06 -04001006/* Construct a device-path for memory-mapped image */
1007struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
1008 uint64_t start_address,
1009 uint64_t end_address)
1010{
1011 struct efi_device_path_memory *mdp;
1012 void *buf, *start;
1013
1014 start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001015 if (!buf)
1016 return NULL;
Rob Clarkbf192732017-10-10 08:23:06 -04001017
1018 mdp = buf;
1019 mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
1020 mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
1021 mdp->dp.length = sizeof(*mdp);
1022 mdp->memory_type = memory_type;
1023 mdp->start_address = start_address;
1024 mdp->end_address = end_address;
1025 buf = &mdp[1];
1026
1027 *((struct efi_device_path *)buf) = END;
1028
1029 return start;
1030}
1031
Heinrich Schuchardtcaf6d2f2019-02-04 12:49:43 +01001032/**
1033 * efi_dp_split_file_path() - split of relative file path from device path
1034 *
1035 * Given a device path indicating a file on a device, separate the device
1036 * path in two: the device path of the actual device and the file path
1037 * relative to this device.
1038 *
1039 * @full_path: device path including device and file path
1040 * @device_path: path of the device
AKASHI Takahirof86076d2019-04-16 17:39:26 +02001041 * @file_path: relative path of the file or NULL if there is none
Heinrich Schuchardtcaf6d2f2019-02-04 12:49:43 +01001042 * Return: status code
Rob Clarkb66c60d2017-09-13 18:05:28 -04001043 */
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001044efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
1045 struct efi_device_path **device_path,
1046 struct efi_device_path **file_path)
Rob Clarkb66c60d2017-09-13 18:05:28 -04001047{
AKASHI Takahirof86076d2019-04-16 17:39:26 +02001048 struct efi_device_path *p, *dp, *fp = NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -04001049
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001050 *device_path = NULL;
1051 *file_path = NULL;
Rob Clarkb66c60d2017-09-13 18:05:28 -04001052 dp = efi_dp_dup(full_path);
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001053 if (!dp)
1054 return EFI_OUT_OF_RESOURCES;
Rob Clarkb66c60d2017-09-13 18:05:28 -04001055 p = dp;
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001056 while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
Rob Clarkb66c60d2017-09-13 18:05:28 -04001057 p = efi_dp_next(p);
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001058 if (!p)
AKASHI Takahirof86076d2019-04-16 17:39:26 +02001059 goto out;
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001060 }
Rob Clarkb66c60d2017-09-13 18:05:28 -04001061 fp = efi_dp_dup(p);
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001062 if (!fp)
1063 return EFI_OUT_OF_RESOURCES;
Rob Clarkb66c60d2017-09-13 18:05:28 -04001064 p->type = DEVICE_PATH_TYPE_END;
1065 p->sub_type = DEVICE_PATH_SUB_TYPE_END;
1066 p->length = sizeof(*p);
1067
AKASHI Takahirof86076d2019-04-16 17:39:26 +02001068out:
Rob Clarkb66c60d2017-09-13 18:05:28 -04001069 *device_path = dp;
1070 *file_path = fp;
Heinrich Schuchardt04298682018-01-19 20:24:37 +01001071 return EFI_SUCCESS;
Rob Clarkb66c60d2017-09-13 18:05:28 -04001072}
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001073
Heinrich Schuchardtcab6f062019-10-30 20:13:24 +01001074/**
1075 * efi_dp_from_name() - convert U-Boot device and file path to device path
1076 *
1077 * @dev: U-Boot device, e.g. 'mmc'
1078 * @devnr: U-Boot device number, e.g. 1 for 'mmc:1'
1079 * @path: file path relative to U-Boot device, may be NULL
1080 * @device: pointer to receive device path of the device
1081 * @file: pointer to receive device path for the file
1082 * Return: status code
1083 */
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001084efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
1085 const char *path,
1086 struct efi_device_path **device,
1087 struct efi_device_path **file)
1088{
1089 int is_net;
1090 struct blk_desc *desc = NULL;
Simon Glass05289792020-05-10 11:39:57 -06001091 struct disk_partition fs_partition;
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001092 int part = 0;
1093 char filename[32] = { 0 }; /* dp->str is u16[32] long */
1094 char *s;
1095
AKASHI Takahiro2419b162018-11-05 18:06:40 +09001096 if (path && !file)
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001097 return EFI_INVALID_PARAMETER;
1098
1099 is_net = !strcmp(dev, "Net");
1100 if (!is_net) {
1101 part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1102 1);
Patrick Delaunay74f5baa2019-04-10 11:02:58 +02001103 if (part < 0 || !desc)
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001104 return EFI_INVALID_PARAMETER;
1105
AKASHI Takahiro2419b162018-11-05 18:06:40 +09001106 if (device)
1107 *device = efi_dp_from_part(desc, part);
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001108 } else {
1109#ifdef CONFIG_NET
AKASHI Takahiro2419b162018-11-05 18:06:40 +09001110 if (device)
1111 *device = efi_dp_from_eth();
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001112#endif
1113 }
1114
1115 if (!path)
1116 return EFI_SUCCESS;
1117
Heinrich Schuchardt30a231d2019-02-23 11:20:23 +01001118 snprintf(filename, sizeof(filename), "%s", path);
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001119 /* DOS style file path: */
1120 s = filename;
1121 while ((s = strchr(s, '/')))
1122 *s++ = '\\';
Heinrich Schuchardtcab6f062019-10-30 20:13:24 +01001123 *file = efi_dp_from_file(is_net ? NULL : desc, part, filename);
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001124
Heinrich Schuchardtcab6f062019-10-30 20:13:24 +01001125 if (!*file)
AKASHI Takahiro08c51ff2019-10-09 16:19:52 +09001126 return EFI_INVALID_PARAMETER;
1127
AKASHI Takahirof1589ff2018-10-17 16:32:03 +09001128 return EFI_SUCCESS;
1129}