blob: 76ab2d82886a1f1a72eae8199f0e24b84a6d88ed [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Rob Clarkf90cb9f2017-09-13 18:05:28 -04002/*
3 * EFI device path from u-boot device-model mapping
4 *
5 * (C) Copyright 2017 Rob Clark
Rob Clarkf90cb9f2017-09-13 18:05:28 -04006 */
7
8#include <common.h>
9#include <blk.h>
10#include <dm.h>
Simon Glass274e0b02020-05-10 11:39:56 -060011#include <net.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040012#include <usb.h>
13#include <mmc.h>
Patrick Wildta3ca37e2019-10-03 16:24:17 +020014#include <nvme.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040015#include <efi_loader.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040016#include <part.h>
AKASHI Takahiro659a6262019-09-12 13:52:35 +090017#include <sandboxblockdev.h>
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +020018#include <asm-generic/unaligned.h>
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +090019#include <linux/compat.h> /* U16_MAX */
Rob Clarkf90cb9f2017-09-13 18:05:28 -040020
AKASHI Takahiro659a6262019-09-12 13:52:35 +090021#ifdef CONFIG_SANDBOX
22const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
23#endif
24
Rob Clarkf90cb9f2017-09-13 18:05:28 -040025/* template END node: */
26static const struct efi_device_path END = {
27 .type = DEVICE_PATH_TYPE_END,
28 .sub_type = DEVICE_PATH_SUB_TYPE_END,
29 .length = sizeof(END),
30};
31
Rob Clarkf90cb9f2017-09-13 18:05:28 -040032/* template ROOT node: */
33static const struct efi_device_path_vendor ROOT = {
34 .dp = {
35 .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
36 .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
37 .length = sizeof(ROOT),
38 },
39 .guid = U_BOOT_GUID,
40};
41
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +010042#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
43/*
44 * Determine if an MMC device is an SD card.
45 *
46 * @desc block device descriptor
47 * @return true if the device is an SD card
48 */
49static bool is_sd(struct blk_desc *desc)
50{
51 struct mmc *mmc = find_mmc_device(desc->devnum);
52
53 if (!mmc)
54 return false;
55
56 return IS_SD(mmc) != 0U;
57}
58#endif
59
Rob Clarkf90cb9f2017-09-13 18:05:28 -040060static void *dp_alloc(size_t sz)
61{
62 void *buf;
63
Heinrich Schuchardt468bf972018-01-19 20:24:37 +010064 if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) !=
65 EFI_SUCCESS) {
66 debug("EFI: ERROR: out of memory in %s\n", __func__);
Rob Clarkf90cb9f2017-09-13 18:05:28 -040067 return NULL;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +010068 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -040069
Patrick Wildtacf7bee2018-03-25 19:54:03 +020070 memset(buf, 0, sz);
Rob Clarkf90cb9f2017-09-13 18:05:28 -040071 return buf;
72}
73
74/*
75 * Iterate to next block in device-path, terminating (returning NULL)
76 * at /End* node.
77 */
78struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
79{
80 if (dp == NULL)
81 return NULL;
82 if (dp->type == DEVICE_PATH_TYPE_END)
83 return NULL;
84 dp = ((void *)dp) + dp->length;
85 if (dp->type == DEVICE_PATH_TYPE_END)
86 return NULL;
87 return (struct efi_device_path *)dp;
88}
89
90/*
91 * Compare two device-paths, stopping when the shorter of the two hits
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +020092 * an End* node. This is useful to, for example, compare a device-path
Rob Clarkf90cb9f2017-09-13 18:05:28 -040093 * representing a device with one representing a file on the device, or
94 * a device with a parent device.
95 */
Heinrich Schuchardt753e2482017-10-26 19:25:48 +020096int efi_dp_match(const struct efi_device_path *a,
97 const struct efi_device_path *b)
Rob Clarkf90cb9f2017-09-13 18:05:28 -040098{
99 while (1) {
100 int ret;
101
102 ret = memcmp(&a->length, &b->length, sizeof(a->length));
103 if (ret)
104 return ret;
105
106 ret = memcmp(a, b, a->length);
107 if (ret)
108 return ret;
109
110 a = efi_dp_next(a);
111 b = efi_dp_next(b);
112
113 if (!a || !b)
114 return 0;
115 }
116}
117
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400118/*
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200119 * We can have device paths that start with a USB WWID or a USB Class node,
120 * and a few other cases which don't encode the full device path with bus
121 * hierarchy:
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400122 *
123 * - MESSAGING:USB_WWID
124 * - MESSAGING:USB_CLASS
125 * - MEDIA:FILE_PATH
126 * - MEDIA:HARD_DRIVE
127 * - MESSAGING:URI
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200128 *
129 * See UEFI spec (section 3.1.2, about short-form device-paths)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400130 */
131static struct efi_device_path *shorten_path(struct efi_device_path *dp)
132{
133 while (dp) {
134 /*
135 * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..
136 * in practice fallback.efi just uses MEDIA:HARD_DRIVE
137 * so not sure when we would see these other cases.
138 */
139 if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||
140 EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
141 EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
142 return dp;
143
144 dp = efi_dp_next(dp);
145 }
146
147 return dp;
148}
149
150static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
151 struct efi_device_path **rem)
152{
153 struct efi_object *efiobj;
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200154 efi_uintn_t dp_size = efi_dp_instance_size(dp);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400155
156 list_for_each_entry(efiobj, &efi_obj_list, link) {
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100157 struct efi_handler *handler;
158 struct efi_device_path *obj_dp;
159 efi_status_t ret;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400160
Heinrich Schuchardtadb50d02018-09-26 05:27:55 +0200161 ret = efi_search_protocol(efiobj,
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100162 &efi_guid_device_path, &handler);
163 if (ret != EFI_SUCCESS)
164 continue;
165 obj_dp = handler->protocol_interface;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400166
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100167 do {
168 if (efi_dp_match(dp, obj_dp) == 0) {
169 if (rem) {
Alexander Graff9360fb2017-12-11 14:29:46 +0100170 /*
171 * Allow partial matches, but inform
172 * the caller.
173 */
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100174 *rem = ((void *)dp) +
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200175 efi_dp_instance_size(obj_dp);
Alexander Graff9360fb2017-12-11 14:29:46 +0100176 return efiobj;
177 } else {
178 /* Only return on exact matches */
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200179 if (efi_dp_instance_size(obj_dp) ==
180 dp_size)
Alexander Graff9360fb2017-12-11 14:29:46 +0100181 return efiobj;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400182 }
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100183 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400184
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100185 obj_dp = shorten_path(efi_dp_next(obj_dp));
186 } while (short_path && obj_dp);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400187 }
188
189 return NULL;
190}
191
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400192/*
193 * Find an efiobj from device-path, if 'rem' is not NULL, returns the
194 * remaining part of the device path after the matched object.
195 */
196struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
197 struct efi_device_path **rem)
198{
199 struct efi_object *efiobj;
200
Alexander Graff9360fb2017-12-11 14:29:46 +0100201 /* Search for an exact match first */
202 efiobj = find_obj(dp, false, NULL);
203
204 /* Then for a fuzzy match */
205 if (!efiobj)
206 efiobj = find_obj(dp, false, rem);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400207
Alexander Graff9360fb2017-12-11 14:29:46 +0100208 /* And now for a fuzzy short match */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400209 if (!efiobj)
210 efiobj = find_obj(dp, true, rem);
211
212 return efiobj;
213}
214
Heinrich Schuchardt0976f8b2018-01-19 20:24:49 +0100215/*
216 * Determine the last device path node that is not the end node.
217 *
218 * @dp device path
219 * @return last node before the end node if it exists
220 * otherwise NULL
221 */
222const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
223{
224 struct efi_device_path *ret;
225
226 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
227 return NULL;
228 while (dp) {
229 ret = (struct efi_device_path *)dp;
230 dp = efi_dp_next(dp);
231 }
232 return ret;
233}
234
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200235/* get size of the first device path instance excluding end node */
236efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400237{
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200238 efi_uintn_t sz = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400239
Heinrich Schuchardt01d48ed2018-04-16 07:59:07 +0200240 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
241 return 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400242 while (dp) {
243 sz += dp->length;
244 dp = efi_dp_next(dp);
245 }
246
247 return sz;
248}
249
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200250/* get size of multi-instance device path excluding end node */
251efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
252{
253 const struct efi_device_path *p = dp;
254
255 if (!p)
256 return 0;
257 while (p->type != DEVICE_PATH_TYPE_END ||
258 p->sub_type != DEVICE_PATH_SUB_TYPE_END)
259 p = (void *)p + p->length;
260
261 return (void *)p - (void *)dp;
262}
263
264/* copy multi-instance device path */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400265struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
266{
267 struct efi_device_path *ndp;
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200268 size_t sz = efi_dp_size(dp) + sizeof(END);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400269
270 if (!dp)
271 return NULL;
272
273 ndp = dp_alloc(sz);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100274 if (!ndp)
275 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400276 memcpy(ndp, dp, sz);
277
278 return ndp;
279}
280
281struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
282 const struct efi_device_path *dp2)
283{
284 struct efi_device_path *ret;
285
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200286 if (!dp1 && !dp2) {
287 /* return an end node */
288 ret = efi_dp_dup(&END);
289 } else if (!dp1) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400290 ret = efi_dp_dup(dp2);
291 } else if (!dp2) {
292 ret = efi_dp_dup(dp1);
293 } else {
294 /* both dp1 and dp2 are non-null */
295 unsigned sz1 = efi_dp_size(dp1);
296 unsigned sz2 = efi_dp_size(dp2);
297 void *p = dp_alloc(sz1 + sz2 + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100298 if (!p)
299 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400300 memcpy(p, dp1, sz1);
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200301 /* the end node of the second device path has to be retained */
302 memcpy(p + sz1, dp2, sz2 + sizeof(END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400303 ret = p;
304 }
305
306 return ret;
307}
308
309struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
310 const struct efi_device_path *node)
311{
312 struct efi_device_path *ret;
313
314 if (!node && !dp) {
315 ret = efi_dp_dup(&END);
316 } else if (!node) {
317 ret = efi_dp_dup(dp);
318 } else if (!dp) {
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200319 size_t sz = node->length;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400320 void *p = dp_alloc(sz + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100321 if (!p)
322 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400323 memcpy(p, node, sz);
324 memcpy(p + sz, &END, sizeof(END));
325 ret = p;
326 } else {
327 /* both dp and node are non-null */
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200328 size_t sz = efi_dp_size(dp);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400329 void *p = dp_alloc(sz + node->length + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100330 if (!p)
331 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400332 memcpy(p, dp, sz);
333 memcpy(p + sz, node, node->length);
334 memcpy(p + sz + node->length, &END, sizeof(END));
335 ret = p;
336 }
337
338 return ret;
339}
340
Heinrich Schuchardtb41c8e22018-04-16 07:59:05 +0200341struct efi_device_path *efi_dp_create_device_node(const u8 type,
342 const u8 sub_type,
343 const u16 length)
344{
345 struct efi_device_path *ret;
346
Heinrich Schuchardtc96c5942019-04-23 00:51:01 +0200347 if (length < sizeof(struct efi_device_path))
348 return NULL;
349
Heinrich Schuchardtb41c8e22018-04-16 07:59:05 +0200350 ret = dp_alloc(length);
351 if (!ret)
352 return ret;
353 ret->type = type;
354 ret->sub_type = sub_type;
355 ret->length = length;
356 return ret;
357}
358
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200359struct efi_device_path *efi_dp_append_instance(
360 const struct efi_device_path *dp,
361 const struct efi_device_path *dpi)
362{
363 size_t sz, szi;
364 struct efi_device_path *p, *ret;
365
366 if (!dpi)
367 return NULL;
368 if (!dp)
369 return efi_dp_dup(dpi);
370 sz = efi_dp_size(dp);
371 szi = efi_dp_instance_size(dpi);
372 p = dp_alloc(sz + szi + 2 * sizeof(END));
373 if (!p)
374 return NULL;
375 ret = p;
376 memcpy(p, dp, sz + sizeof(END));
377 p = (void *)p + sz;
378 p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
379 p = (void *)p + sizeof(END);
380 memcpy(p, dpi, szi);
381 p = (void *)p + szi;
382 memcpy(p, &END, sizeof(END));
383 return ret;
384}
385
386struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
387 efi_uintn_t *size)
388{
389 size_t sz;
390 struct efi_device_path *p;
391
392 if (size)
393 *size = 0;
394 if (!dp || !*dp)
395 return NULL;
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200396 sz = efi_dp_instance_size(*dp);
397 p = dp_alloc(sz + sizeof(END));
398 if (!p)
399 return NULL;
400 memcpy(p, *dp, sz + sizeof(END));
401 *dp = (void *)*dp + sz;
402 if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
403 *dp = (void *)*dp + sizeof(END);
404 else
405 *dp = NULL;
406 if (size)
407 *size = sz + sizeof(END);
408 return p;
409}
410
411bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
412{
413 const struct efi_device_path *p = dp;
414
415 if (!p)
416 return false;
417 while (p->type != DEVICE_PATH_TYPE_END)
418 p = (void *)p + p->length;
419 return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
420}
421
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400422#ifdef CONFIG_DM
423/* size of device-path not including END node for device and all parents
424 * up to the root device.
425 */
Heinrich Schuchardtc22d9e32019-11-10 02:16:33 +0100426__maybe_unused static unsigned int dp_size(struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400427{
428 if (!dev || !dev->driver)
429 return sizeof(ROOT);
430
431 switch (dev->driver->id) {
432 case UCLASS_ROOT:
433 case UCLASS_SIMPLE_BUS:
434 /* stop traversing parents at this point: */
435 return sizeof(ROOT);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100436 case UCLASS_ETH:
437 return dp_size(dev->parent) +
438 sizeof(struct efi_device_path_mac_addr);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100439#ifdef CONFIG_BLK
440 case UCLASS_BLK:
441 switch (dev->parent->uclass->uc_drv->id) {
442#ifdef CONFIG_IDE
443 case UCLASS_IDE:
444 return dp_size(dev->parent) +
445 sizeof(struct efi_device_path_atapi);
446#endif
447#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
448 case UCLASS_SCSI:
449 return dp_size(dev->parent) +
450 sizeof(struct efi_device_path_scsi);
451#endif
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100452#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
453 case UCLASS_MMC:
454 return dp_size(dev->parent) +
455 sizeof(struct efi_device_path_sd_mmc_path);
456#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200457#if defined(CONFIG_NVME)
458 case UCLASS_NVME:
459 return dp_size(dev->parent) +
460 sizeof(struct efi_device_path_nvme);
461#endif
AKASHI Takahiro659a6262019-09-12 13:52:35 +0900462#ifdef CONFIG_SANDBOX
463 case UCLASS_ROOT:
464 /*
465 * Sandbox's host device will be represented
466 * as vendor device with extra one byte for
467 * device number
468 */
469 return dp_size(dev->parent)
470 + sizeof(struct efi_device_path_vendor) + 1;
471#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100472 default:
473 return dp_size(dev->parent);
474 }
475#endif
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100476#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400477 case UCLASS_MMC:
478 return dp_size(dev->parent) +
479 sizeof(struct efi_device_path_sd_mmc_path);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100480#endif
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400481 case UCLASS_MASS_STORAGE:
482 case UCLASS_USB_HUB:
483 return dp_size(dev->parent) +
484 sizeof(struct efi_device_path_usb_class);
485 default:
486 /* just skip over unknown classes: */
487 return dp_size(dev->parent);
488 }
489}
490
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100491/*
492 * Recursively build a device path.
493 *
494 * @buf pointer to the end of the device path
495 * @dev device
496 * @return pointer to the end of the device path
497 */
Heinrich Schuchardtc22d9e32019-11-10 02:16:33 +0100498__maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400499{
500 if (!dev || !dev->driver)
501 return buf;
502
503 switch (dev->driver->id) {
504 case UCLASS_ROOT:
505 case UCLASS_SIMPLE_BUS: {
506 /* stop traversing parents at this point: */
507 struct efi_device_path_vendor *vdp = buf;
508 *vdp = ROOT;
509 return &vdp[1];
510 }
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100511#ifdef CONFIG_DM_ETH
512 case UCLASS_ETH: {
513 struct efi_device_path_mac_addr *dp =
514 dp_fill(buf, dev->parent);
515 struct eth_pdata *pdata = dev->platdata;
516
517 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
518 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
519 dp->dp.length = sizeof(*dp);
520 memset(&dp->mac, 0, sizeof(dp->mac));
521 /* We only support IPv4 */
522 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
523 /* Ethernet */
524 dp->if_type = 1;
525 return &dp[1];
526 }
527#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100528#ifdef CONFIG_BLK
529 case UCLASS_BLK:
530 switch (dev->parent->uclass->uc_drv->id) {
AKASHI Takahiro659a6262019-09-12 13:52:35 +0900531#ifdef CONFIG_SANDBOX
532 case UCLASS_ROOT: {
533 /* stop traversing parents at this point: */
Heinrich Schuchardt1e3beaf2020-05-06 01:28:08 +0200534 struct efi_device_path_vendor *dp;
AKASHI Takahiro659a6262019-09-12 13:52:35 +0900535 struct blk_desc *desc = dev_get_uclass_platdata(dev);
536
537 dp_fill(buf, dev->parent);
538 dp = buf;
539 ++dp;
540 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
541 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
542 dp->dp.length = sizeof(*dp) + 1;
543 memcpy(&dp->guid, &efi_guid_host_dev,
544 sizeof(efi_guid_t));
545 dp->vendor_data[0] = desc->devnum;
546 return &dp->vendor_data[1];
547 }
548#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100549#ifdef CONFIG_IDE
550 case UCLASS_IDE: {
551 struct efi_device_path_atapi *dp =
552 dp_fill(buf, dev->parent);
553 struct blk_desc *desc = dev_get_uclass_platdata(dev);
554
555 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
556 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
557 dp->dp.length = sizeof(*dp);
558 dp->logical_unit_number = desc->devnum;
559 dp->primary_secondary = IDE_BUS(desc->devnum);
560 dp->slave_master = desc->devnum %
561 (CONFIG_SYS_IDE_MAXDEVICE /
562 CONFIG_SYS_IDE_MAXBUS);
563 return &dp[1];
564 }
565#endif
566#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
567 case UCLASS_SCSI: {
568 struct efi_device_path_scsi *dp =
569 dp_fill(buf, dev->parent);
570 struct blk_desc *desc = dev_get_uclass_platdata(dev);
571
572 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
573 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
574 dp->dp.length = sizeof(*dp);
575 dp->logical_unit_number = desc->lun;
576 dp->target_id = desc->target;
577 return &dp[1];
578 }
579#endif
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100580#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
581 case UCLASS_MMC: {
582 struct efi_device_path_sd_mmc_path *sddp =
583 dp_fill(buf, dev->parent);
584 struct blk_desc *desc = dev_get_uclass_platdata(dev);
585
586 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
587 sddp->dp.sub_type = is_sd(desc) ?
588 DEVICE_PATH_SUB_TYPE_MSG_SD :
589 DEVICE_PATH_SUB_TYPE_MSG_MMC;
590 sddp->dp.length = sizeof(*sddp);
591 sddp->slot_number = dev->seq;
592 return &sddp[1];
593 }
594#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200595#if defined(CONFIG_NVME)
596 case UCLASS_NVME: {
597 struct efi_device_path_nvme *dp =
598 dp_fill(buf, dev->parent);
599 u32 ns_id;
600
601 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
602 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_NVME;
603 dp->dp.length = sizeof(*dp);
604 nvme_get_namespace_id(dev, &ns_id, dp->eui64);
605 memcpy(&dp->ns_id, &ns_id, sizeof(ns_id));
606 return &dp[1];
607 }
608#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100609 default:
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100610 debug("%s(%u) %s: unhandled parent class: %s (%u)\n",
611 __FILE__, __LINE__, __func__,
612 dev->name, dev->parent->uclass->uc_drv->id);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100613 return dp_fill(buf, dev->parent);
614 }
615#endif
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400616#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 mmc *mmc = mmc_get_mmc_dev(dev);
621 struct blk_desc *desc = mmc_get_blk_desc(mmc);
622
623 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +0100624 sddp->dp.sub_type = is_sd(desc) ?
625 DEVICE_PATH_SUB_TYPE_MSG_SD :
626 DEVICE_PATH_SUB_TYPE_MSG_MMC;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400627 sddp->dp.length = sizeof(*sddp);
628 sddp->slot_number = dev->seq;
629
630 return &sddp[1];
631 }
632#endif
633 case UCLASS_MASS_STORAGE:
634 case UCLASS_USB_HUB: {
635 struct efi_device_path_usb_class *udp =
636 dp_fill(buf, dev->parent);
637 struct usb_device *udev = dev_get_parent_priv(dev);
638 struct usb_device_descriptor *desc = &udev->descriptor;
639
640 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
641 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
642 udp->dp.length = sizeof(*udp);
643 udp->vendor_id = desc->idVendor;
644 udp->product_id = desc->idProduct;
645 udp->device_class = desc->bDeviceClass;
646 udp->device_subclass = desc->bDeviceSubClass;
647 udp->device_protocol = desc->bDeviceProtocol;
648
649 return &udp[1];
650 }
651 default:
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100652 debug("%s(%u) %s: unhandled device class: %s (%u)\n",
653 __FILE__, __LINE__, __func__,
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400654 dev->name, dev->driver->id);
655 return dp_fill(buf, dev->parent);
656 }
657}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400658#endif
659
660static unsigned dp_part_size(struct blk_desc *desc, int part)
661{
662 unsigned dpsize;
663
664#ifdef CONFIG_BLK
Heinrich Schuchardt3a615c82017-12-11 12:56:43 +0100665 {
666 struct udevice *dev;
667 int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
668
669 if (ret)
670 dev = desc->bdev->parent;
671 dpsize = dp_size(dev);
672 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400673#else
674 dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
675#endif
676
677 if (part == 0) /* the actual disk, not a partition */
678 return dpsize;
679
680 if (desc->part_type == PART_TYPE_ISO)
681 dpsize += sizeof(struct efi_device_path_cdrom_path);
682 else
683 dpsize += sizeof(struct efi_device_path_hard_drive_path);
684
685 return dpsize;
686}
687
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100688/*
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100689 * Create a device node for a block device partition.
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100690 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200691 * @buf buffer to which the device path is written
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100692 * @desc block device descriptor
693 * @part partition number, 0 identifies a block device
694 */
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100695static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400696{
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600697 struct disk_partition info;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400698
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400699 part_get_info(desc, part, &info);
700
701 if (desc->part_type == PART_TYPE_ISO) {
702 struct efi_device_path_cdrom_path *cddp = buf;
703
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100704 cddp->boot_entry = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400705 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
706 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
707 cddp->dp.length = sizeof(*cddp);
708 cddp->partition_start = info.start;
Heinrich Schuchardt28dfd1a2019-09-04 13:56:01 +0200709 cddp->partition_size = info.size;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400710
711 buf = &cddp[1];
712 } else {
713 struct efi_device_path_hard_drive_path *hddp = buf;
714
715 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
716 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
717 hddp->dp.length = sizeof(*hddp);
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100718 hddp->partition_number = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400719 hddp->partition_start = info.start;
720 hddp->partition_end = info.size;
721 if (desc->part_type == PART_TYPE_EFI)
722 hddp->partmap_type = 2;
723 else
724 hddp->partmap_type = 1;
Jonathan Gray84b4d702017-11-22 14:18:59 +1100725
726 switch (desc->sig_type) {
727 case SIG_TYPE_NONE:
728 default:
729 hddp->signature_type = 0;
730 memset(hddp->partition_signature, 0,
731 sizeof(hddp->partition_signature));
732 break;
733 case SIG_TYPE_MBR:
734 hddp->signature_type = 1;
735 memset(hddp->partition_signature, 0,
736 sizeof(hddp->partition_signature));
737 memcpy(hddp->partition_signature, &desc->mbr_sig,
738 sizeof(desc->mbr_sig));
739 break;
740 case SIG_TYPE_GUID:
741 hddp->signature_type = 2;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400742 memcpy(hddp->partition_signature, &desc->guid_sig,
743 sizeof(hddp->partition_signature));
Jonathan Gray84b4d702017-11-22 14:18:59 +1100744 break;
745 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400746
747 buf = &hddp[1];
748 }
749
750 return buf;
751}
752
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100753/*
754 * Create a device path for a block device or one of its partitions.
755 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200756 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100757 * @desc block device descriptor
758 * @part partition number, 0 identifies a block device
759 */
760static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
761{
762#ifdef CONFIG_BLK
763 {
764 struct udevice *dev;
765 int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
766
767 if (ret)
768 dev = desc->bdev->parent;
769 buf = dp_fill(buf, dev);
770 }
771#else
772 /*
773 * We *could* make a more accurate path, by looking at if_type
774 * and handling all the different cases like we do for non-
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200775 * legacy (i.e. CONFIG_BLK=y) case. But most important thing
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100776 * is just to have a unique device-path for if_type+devnum.
777 * So map things to a fictitious USB device.
778 */
779 struct efi_device_path_usb *udp;
780
781 memcpy(buf, &ROOT, sizeof(ROOT));
782 buf += sizeof(ROOT);
783
784 udp = buf;
785 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
786 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
787 udp->dp.length = sizeof(*udp);
788 udp->parent_port_number = desc->if_type;
789 udp->usb_interface = desc->devnum;
790 buf = &udp[1];
791#endif
792
793 if (part == 0) /* the actual disk, not a partition */
794 return buf;
795
796 return dp_part_node(buf, desc, part);
797}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400798
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200799/* Construct a device-path from a partition on a block device: */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400800struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
801{
802 void *buf, *start;
803
804 start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100805 if (!buf)
806 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400807
808 buf = dp_part_fill(buf, desc, part);
809
810 *((struct efi_device_path *)buf) = END;
811
812 return start;
813}
814
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100815/*
816 * Create a device node for a block device partition.
817 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200818 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100819 * @desc block device descriptor
820 * @part partition number, 0 identifies a block device
821 */
822struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
823{
824 efi_uintn_t dpsize;
825 void *buf;
826
827 if (desc->part_type == PART_TYPE_ISO)
828 dpsize = sizeof(struct efi_device_path_cdrom_path);
829 else
830 dpsize = sizeof(struct efi_device_path_hard_drive_path);
831 buf = dp_alloc(dpsize);
832
833 dp_part_node(buf, desc, part);
834
835 return buf;
836}
837
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200838/**
839 * path_to_uefi() - convert UTF-8 path to an UEFI style path
840 *
841 * Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
842 * separators and UTF-16).
843 *
844 * @src: source buffer
845 * @uefi: target buffer, possibly unaligned
846 */
847static void path_to_uefi(void *uefi, const char *src)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400848{
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200849 u16 *pos = uefi;
850
851 /*
852 * efi_set_bootdev() calls this routine indirectly before the UEFI
853 * subsystem is initialized. So we cannot assume unaligned access to be
854 * enabled.
855 */
856 allow_unaligned();
857
858 while (*src) {
859 s32 code = utf8_get(&src);
860
861 if (code < 0)
862 code = '?';
863 else if (code == '/')
864 code = '\\';
865 utf16_put(code, &pos);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400866 }
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200867 *pos = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400868}
869
870/*
871 * If desc is NULL, this creates a path with only the file component,
872 * otherwise it creates a full path with both device and file components
873 */
874struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
875 const char *path)
876{
877 struct efi_device_path_file_path *fp;
878 void *buf, *start;
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +0900879 size_t dpsize = 0, fpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400880
881 if (desc)
882 dpsize = dp_part_size(desc, part);
883
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200884 fpsize = sizeof(struct efi_device_path) +
885 2 * (utf8_utf16_strlen(path) + 1);
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +0900886 if (fpsize > U16_MAX)
887 return NULL;
888
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400889 dpsize += fpsize;
890
891 start = buf = dp_alloc(dpsize + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100892 if (!buf)
893 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400894
895 if (desc)
896 buf = dp_part_fill(buf, desc, part);
897
898 /* add file-path: */
899 fp = buf;
900 fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
901 fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +0900902 fp->dp.length = (u16)fpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400903 path_to_uefi(fp->str, path);
904 buf += fpsize;
905
906 *((struct efi_device_path *)buf) = END;
907
908 return start;
909}
910
Joe Hershberger5277a972018-04-13 15:26:39 -0500911#ifdef CONFIG_NET
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400912struct efi_device_path *efi_dp_from_eth(void)
913{
Alexander Grafc4e983f2018-03-15 17:33:38 +0100914#ifndef CONFIG_DM_ETH
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400915 struct efi_device_path_mac_addr *ndp;
Alexander Grafc4e983f2018-03-15 17:33:38 +0100916#endif
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400917 void *buf, *start;
918 unsigned dpsize = 0;
919
920 assert(eth_get_dev());
921
922#ifdef CONFIG_DM_ETH
923 dpsize += dp_size(eth_get_dev());
924#else
925 dpsize += sizeof(ROOT);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400926 dpsize += sizeof(*ndp);
Alexander Grafc4e983f2018-03-15 17:33:38 +0100927#endif
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400928
929 start = buf = dp_alloc(dpsize + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100930 if (!buf)
931 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400932
933#ifdef CONFIG_DM_ETH
934 buf = dp_fill(buf, eth_get_dev());
935#else
936 memcpy(buf, &ROOT, sizeof(ROOT));
937 buf += sizeof(ROOT);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400938
939 ndp = buf;
940 ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
941 ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
942 ndp->dp.length = sizeof(*ndp);
Alexander Grafc4e983f2018-03-15 17:33:38 +0100943 ndp->if_type = 1; /* Ethernet */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400944 memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
945 buf = &ndp[1];
Alexander Grafc4e983f2018-03-15 17:33:38 +0100946#endif
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400947
948 *((struct efi_device_path *)buf) = END;
949
950 return start;
951}
952#endif
953
Rob Clark18ceba72017-10-10 08:23:06 -0400954/* Construct a device-path for memory-mapped image */
955struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
956 uint64_t start_address,
957 uint64_t end_address)
958{
959 struct efi_device_path_memory *mdp;
960 void *buf, *start;
961
962 start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100963 if (!buf)
964 return NULL;
Rob Clark18ceba72017-10-10 08:23:06 -0400965
966 mdp = buf;
967 mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
968 mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
969 mdp->dp.length = sizeof(*mdp);
970 mdp->memory_type = memory_type;
971 mdp->start_address = start_address;
972 mdp->end_address = end_address;
973 buf = &mdp[1];
974
975 *((struct efi_device_path *)buf) = END;
976
977 return start;
978}
979
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +0100980/**
981 * efi_dp_split_file_path() - split of relative file path from device path
982 *
983 * Given a device path indicating a file on a device, separate the device
984 * path in two: the device path of the actual device and the file path
985 * relative to this device.
986 *
987 * @full_path: device path including device and file path
988 * @device_path: path of the device
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +0200989 * @file_path: relative path of the file or NULL if there is none
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +0100990 * Return: status code
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400991 */
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100992efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
993 struct efi_device_path **device_path,
994 struct efi_device_path **file_path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400995{
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +0200996 struct efi_device_path *p, *dp, *fp = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400997
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100998 *device_path = NULL;
999 *file_path = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001000 dp = efi_dp_dup(full_path);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001001 if (!dp)
1002 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001003 p = dp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001004 while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001005 p = efi_dp_next(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001006 if (!p)
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001007 goto out;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001008 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001009 fp = efi_dp_dup(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001010 if (!fp)
1011 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001012 p->type = DEVICE_PATH_TYPE_END;
1013 p->sub_type = DEVICE_PATH_SUB_TYPE_END;
1014 p->length = sizeof(*p);
1015
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001016out:
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001017 *device_path = dp;
1018 *file_path = fp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001019 return EFI_SUCCESS;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001020}
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001021
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001022/**
1023 * efi_dp_from_name() - convert U-Boot device and file path to device path
1024 *
1025 * @dev: U-Boot device, e.g. 'mmc'
1026 * @devnr: U-Boot device number, e.g. 1 for 'mmc:1'
1027 * @path: file path relative to U-Boot device, may be NULL
1028 * @device: pointer to receive device path of the device
1029 * @file: pointer to receive device path for the file
1030 * Return: status code
1031 */
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001032efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
1033 const char *path,
1034 struct efi_device_path **device,
1035 struct efi_device_path **file)
1036{
1037 int is_net;
1038 struct blk_desc *desc = NULL;
Simon Glassc1c4a8f2020-05-10 11:39:57 -06001039 struct disk_partition fs_partition;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001040 int part = 0;
1041 char filename[32] = { 0 }; /* dp->str is u16[32] long */
1042 char *s;
1043
AKASHI Takahiro39844412018-11-05 18:06:40 +09001044 if (path && !file)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001045 return EFI_INVALID_PARAMETER;
1046
1047 is_net = !strcmp(dev, "Net");
1048 if (!is_net) {
1049 part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1050 1);
Patrick Delaunayba7a9502019-04-10 11:02:58 +02001051 if (part < 0 || !desc)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001052 return EFI_INVALID_PARAMETER;
1053
AKASHI Takahiro39844412018-11-05 18:06:40 +09001054 if (device)
1055 *device = efi_dp_from_part(desc, part);
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001056 } else {
1057#ifdef CONFIG_NET
AKASHI Takahiro39844412018-11-05 18:06:40 +09001058 if (device)
1059 *device = efi_dp_from_eth();
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001060#endif
1061 }
1062
1063 if (!path)
1064 return EFI_SUCCESS;
1065
Heinrich Schuchardt7d698072019-02-23 11:20:23 +01001066 snprintf(filename, sizeof(filename), "%s", path);
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001067 /* DOS style file path: */
1068 s = filename;
1069 while ((s = strchr(s, '/')))
1070 *s++ = '\\';
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001071 *file = efi_dp_from_file(is_net ? NULL : desc, part, filename);
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001072
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001073 if (!*file)
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +09001074 return EFI_INVALID_PARAMETER;
1075
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001076 return EFI_SUCCESS;
1077}