blob: 9de3b95d073b201b60a76e9d00cfcc9f10e08dd0 [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
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +02008#define LOG_CATEGORY LOGC_EFI
9
Rob Clarkf90cb9f2017-09-13 18:05:28 -040010#include <blk.h>
11#include <dm.h>
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +020012#include <dm/root.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Simon Glass274e0b02020-05-10 11:39:56 -060014#include <net.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040015#include <usb.h>
16#include <mmc.h>
Patrick Wildta3ca37e2019-10-03 16:24:17 +020017#include <nvme.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040018#include <efi_loader.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040019#include <part.h>
Caleb Connolly29cab7c2024-08-30 13:34:37 +010020#include <u-boot/uuid.h>
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +020021#include <asm-generic/unaligned.h>
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +090022#include <linux/compat.h> /* U16_MAX */
Rob Clarkf90cb9f2017-09-13 18:05:28 -040023
24/* template END node: */
Masahisa Kojima97bd9da2022-06-19 13:55:59 +090025const struct efi_device_path END = {
Rob Clarkf90cb9f2017-09-13 18:05:28 -040026 .type = DEVICE_PATH_TYPE_END,
27 .sub_type = DEVICE_PATH_SUB_TYPE_END,
28 .length = sizeof(END),
29};
30
Simon Glass222f3cb2021-09-24 18:30:17 -060031#if defined(CONFIG_MMC)
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +010032/*
33 * Determine if an MMC device is an SD card.
34 *
35 * @desc block device descriptor
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010036 * Return: true if the device is an SD card
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +010037 */
38static bool is_sd(struct blk_desc *desc)
39{
40 struct mmc *mmc = find_mmc_device(desc->devnum);
41
42 if (!mmc)
43 return false;
44
45 return IS_SD(mmc) != 0U;
46}
47#endif
48
Rob Clarkf90cb9f2017-09-13 18:05:28 -040049/*
50 * Iterate to next block in device-path, terminating (returning NULL)
51 * at /End* node.
52 */
53struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
54{
55 if (dp == NULL)
56 return NULL;
57 if (dp->type == DEVICE_PATH_TYPE_END)
58 return NULL;
59 dp = ((void *)dp) + dp->length;
60 if (dp->type == DEVICE_PATH_TYPE_END)
61 return NULL;
62 return (struct efi_device_path *)dp;
63}
64
65/*
66 * Compare two device-paths, stopping when the shorter of the two hits
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +020067 * an End* node. This is useful to, for example, compare a device-path
Rob Clarkf90cb9f2017-09-13 18:05:28 -040068 * representing a device with one representing a file on the device, or
69 * a device with a parent device.
70 */
Heinrich Schuchardt753e2482017-10-26 19:25:48 +020071int efi_dp_match(const struct efi_device_path *a,
72 const struct efi_device_path *b)
Rob Clarkf90cb9f2017-09-13 18:05:28 -040073{
74 while (1) {
75 int ret;
76
77 ret = memcmp(&a->length, &b->length, sizeof(a->length));
78 if (ret)
79 return ret;
80
81 ret = memcmp(a, b, a->length);
82 if (ret)
83 return ret;
84
85 a = efi_dp_next(a);
86 b = efi_dp_next(b);
87
88 if (!a || !b)
89 return 0;
90 }
91}
92
Heinrich Schuchardt24f0e6a2022-02-26 12:10:10 +010093/**
94 * efi_dp_shorten() - shorten device-path
95 *
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +020096 * When creating a short boot option we want to use a device-path that is
97 * independent of the location where the block device is plugged in.
Rob Clarkf90cb9f2017-09-13 18:05:28 -040098 *
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +020099 * UsbWwi() nodes contain a serial number, hard drive paths a partition
100 * UUID. Both should be unique.
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200101 *
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +0200102 * See UEFI spec, section 3.1.2 for "short-form device path".
Heinrich Schuchardt24f0e6a2022-02-26 12:10:10 +0100103 *
Heinrich Schuchardtdb17dbc2022-03-21 08:26:48 +0100104 * @dp: original device-path
Heinrich Schuchardt2e670852024-04-26 12:09:38 +0200105 * Return: shortened device-path or NULL
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400106 */
Heinrich Schuchardt24f0e6a2022-02-26 12:10:10 +0100107struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400108{
109 while (dp) {
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +0200110 if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_WWI) ||
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400111 EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
112 EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
113 return dp;
114
115 dp = efi_dp_next(dp);
116 }
117
118 return dp;
119}
120
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100121/**
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100122 * find_handle() - find handle by device path and installed protocol
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100123 *
124 * If @rem is provided, the handle with the longest partial match is returned.
125 *
126 * @dp: device path to search
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100127 * @guid: GUID of protocol that must be installed on path or NULL
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100128 * @short_path: use short form device path for matching
129 * @rem: pointer to receive remaining device path
130 * Return: matching handle
131 */
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100132static efi_handle_t find_handle(struct efi_device_path *dp,
133 const efi_guid_t *guid, bool short_path,
134 struct efi_device_path **rem)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400135{
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100136 efi_handle_t handle, best_handle = NULL;
137 efi_uintn_t len, best_len = 0;
138
139 len = efi_dp_instance_size(dp);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400140
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100141 list_for_each_entry(handle, &efi_obj_list, link) {
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100142 struct efi_handler *handler;
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100143 struct efi_device_path *dp_current;
144 efi_uintn_t len_current;
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100145 efi_status_t ret;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400146
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100147 if (guid) {
148 ret = efi_search_protocol(handle, guid, &handler);
149 if (ret != EFI_SUCCESS)
150 continue;
151 }
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100152 ret = efi_search_protocol(handle, &efi_guid_device_path,
153 &handler);
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100154 if (ret != EFI_SUCCESS)
155 continue;
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100156 dp_current = handler->protocol_interface;
157 if (short_path) {
158 dp_current = efi_dp_shorten(dp_current);
159 if (!dp_current)
160 continue;
161 }
162 len_current = efi_dp_instance_size(dp_current);
163 if (rem) {
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100164 if (len_current > len)
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100165 continue;
166 } else {
167 if (len_current != len)
168 continue;
169 }
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100170 if (memcmp(dp_current, dp, len_current))
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100171 continue;
172 if (!rem)
173 return handle;
174 if (len_current > best_len) {
175 best_len = len_current;
176 best_handle = handle;
177 *rem = (void*)((u8 *)dp + len_current);
178 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400179 }
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100180 return best_handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400181}
182
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100183/**
184 * efi_dp_find_obj() - find handle by device path
185 *
186 * If @rem is provided, the handle with the longest partial match is returned.
187 *
188 * @dp: device path to search
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100189 * @guid: GUID of protocol that must be installed on path or NULL
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100190 * @rem: pointer to receive remaining device path
191 * Return: matching handle
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400192 */
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100193efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100194 const efi_guid_t *guid,
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100195 struct efi_device_path **rem)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400196{
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100197 efi_handle_t handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400198
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100199 handle = find_handle(dp, guid, false, rem);
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100200 if (!handle)
201 /* Match short form device path */
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100202 handle = find_handle(dp, guid, true, rem);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400203
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100204 return handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400205}
206
Heinrich Schuchardt0976f8b2018-01-19 20:24:49 +0100207/*
208 * Determine the last device path node that is not the end node.
209 *
210 * @dp device path
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100211 * Return: last node before the end node if it exists
Heinrich Schuchardt0976f8b2018-01-19 20:24:49 +0100212 * otherwise NULL
213 */
214const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
215{
216 struct efi_device_path *ret;
217
218 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
219 return NULL;
220 while (dp) {
221 ret = (struct efi_device_path *)dp;
222 dp = efi_dp_next(dp);
223 }
224 return ret;
225}
226
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200227/* get size of the first device path instance excluding end node */
228efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400229{
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200230 efi_uintn_t sz = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400231
Heinrich Schuchardt01d48ed2018-04-16 07:59:07 +0200232 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
233 return 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400234 while (dp) {
235 sz += dp->length;
236 dp = efi_dp_next(dp);
237 }
238
239 return sz;
240}
241
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200242/* get size of multi-instance device path excluding end node */
243efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
244{
245 const struct efi_device_path *p = dp;
246
247 if (!p)
248 return 0;
249 while (p->type != DEVICE_PATH_TYPE_END ||
250 p->sub_type != DEVICE_PATH_SUB_TYPE_END)
251 p = (void *)p + p->length;
252
253 return (void *)p - (void *)dp;
254}
255
256/* copy multi-instance device path */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400257struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
258{
259 struct efi_device_path *ndp;
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200260 size_t sz = efi_dp_size(dp) + sizeof(END);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400261
262 if (!dp)
263 return NULL;
264
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100265 ndp = efi_alloc(sz);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100266 if (!ndp)
267 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400268 memcpy(ndp, dp, sz);
269
270 return ndp;
271}
272
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200273/**
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200274 * efi_dp_concat() - Concatenate two device paths and add and terminate them
275 * with an end node.
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200276 *
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200277 * @dp1: First device path
278 * @dp2: Second device path
Heinrich Schuchardtf8de0092024-05-24 14:54:26 +0200279 * @split_end_node:
280 * * 0 to concatenate
281 * * 1 to concatenate with end node added as separator
282 * * size of dp1 excluding last end node to concatenate with end node as
283 * separator in case dp1 contains an end node
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200284 *
285 * Return:
286 * concatenated device path or NULL. Caller must free the returned value
287 */
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200288struct
289efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
290 const struct efi_device_path *dp2,
Heinrich Schuchardtf8de0092024-05-24 14:54:26 +0200291 size_t split_end_node)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400292{
293 struct efi_device_path *ret;
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200294 size_t end_size;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400295
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200296 if (!dp1 && !dp2) {
297 /* return an end node */
298 ret = efi_dp_dup(&END);
299 } else if (!dp1) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400300 ret = efi_dp_dup(dp2);
301 } else if (!dp2) {
302 ret = efi_dp_dup(dp1);
303 } else {
304 /* both dp1 and dp2 are non-null */
Heinrich Schuchardtf8de0092024-05-24 14:54:26 +0200305 size_t sz1;
306 size_t sz2 = efi_dp_size(dp2);
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200307 void *p;
308
Heinrich Schuchardtf8de0092024-05-24 14:54:26 +0200309 if (split_end_node < sizeof(struct efi_device_path))
310 sz1 = efi_dp_size(dp1);
311 else
312 sz1 = split_end_node;
313
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200314 if (split_end_node)
315 end_size = 2 * sizeof(END);
316 else
317 end_size = sizeof(END);
318 p = efi_alloc(sz1 + sz2 + end_size);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100319 if (!p)
320 return NULL;
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200321 ret = p;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400322 memcpy(p, dp1, sz1);
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200323 p += sz1;
324
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200325 if (split_end_node) {
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200326 memcpy(p, &END, sizeof(END));
327 p += sizeof(END);
328 }
329
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200330 /* the end node of the second device path has to be retained */
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200331 memcpy(p, dp2, sz2);
332 p += sz2;
333 memcpy(p, &END, sizeof(END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400334 }
335
336 return ret;
337}
338
339struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
340 const struct efi_device_path *node)
341{
342 struct efi_device_path *ret;
343
344 if (!node && !dp) {
345 ret = efi_dp_dup(&END);
346 } else if (!node) {
347 ret = efi_dp_dup(dp);
348 } else if (!dp) {
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200349 size_t sz = node->length;
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100350 void *p = efi_alloc(sz + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100351 if (!p)
352 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400353 memcpy(p, node, sz);
354 memcpy(p + sz, &END, sizeof(END));
355 ret = p;
356 } else {
357 /* both dp and node are non-null */
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200358 size_t sz = efi_dp_size(dp);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100359 void *p = efi_alloc(sz + node->length + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100360 if (!p)
361 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400362 memcpy(p, dp, sz);
363 memcpy(p + sz, node, node->length);
364 memcpy(p + sz + node->length, &END, sizeof(END));
365 ret = p;
366 }
367
368 return ret;
369}
370
Heinrich Schuchardtb41c8e22018-04-16 07:59:05 +0200371struct efi_device_path *efi_dp_create_device_node(const u8 type,
372 const u8 sub_type,
373 const u16 length)
374{
375 struct efi_device_path *ret;
376
Heinrich Schuchardtc96c5942019-04-23 00:51:01 +0200377 if (length < sizeof(struct efi_device_path))
378 return NULL;
379
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100380 ret = efi_alloc(length);
Heinrich Schuchardtb41c8e22018-04-16 07:59:05 +0200381 if (!ret)
382 return ret;
383 ret->type = type;
384 ret->sub_type = sub_type;
385 ret->length = length;
386 return ret;
387}
388
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200389struct efi_device_path *efi_dp_append_instance(
390 const struct efi_device_path *dp,
391 const struct efi_device_path *dpi)
392{
393 size_t sz, szi;
394 struct efi_device_path *p, *ret;
395
396 if (!dpi)
397 return NULL;
398 if (!dp)
399 return efi_dp_dup(dpi);
400 sz = efi_dp_size(dp);
401 szi = efi_dp_instance_size(dpi);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100402 p = efi_alloc(sz + szi + 2 * sizeof(END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200403 if (!p)
404 return NULL;
405 ret = p;
406 memcpy(p, dp, sz + sizeof(END));
407 p = (void *)p + sz;
408 p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
409 p = (void *)p + sizeof(END);
410 memcpy(p, dpi, szi);
411 p = (void *)p + szi;
412 memcpy(p, &END, sizeof(END));
413 return ret;
414}
415
416struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
417 efi_uintn_t *size)
418{
419 size_t sz;
420 struct efi_device_path *p;
421
422 if (size)
423 *size = 0;
424 if (!dp || !*dp)
425 return NULL;
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200426 sz = efi_dp_instance_size(*dp);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100427 p = efi_alloc(sz + sizeof(END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200428 if (!p)
429 return NULL;
430 memcpy(p, *dp, sz + sizeof(END));
431 *dp = (void *)*dp + sz;
432 if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
433 *dp = (void *)*dp + sizeof(END);
434 else
435 *dp = NULL;
436 if (size)
437 *size = sz + sizeof(END);
438 return p;
439}
440
441bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
442{
443 const struct efi_device_path *p = dp;
444
445 if (!p)
446 return false;
447 while (p->type != DEVICE_PATH_TYPE_END)
448 p = (void *)p + p->length;
449 return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
450}
451
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400452/* size of device-path not including END node for device and all parents
453 * up to the root device.
454 */
Heinrich Schuchardtc22d9e32019-11-10 02:16:33 +0100455__maybe_unused static unsigned int dp_size(struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400456{
457 if (!dev || !dev->driver)
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200458 return sizeof(struct efi_device_path_udevice);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400459
Simon Glass56ada7b2022-01-29 14:58:38 -0700460 switch (device_get_uclass_id(dev)) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400461 case UCLASS_ROOT:
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400462 /* stop traversing parents at this point: */
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200463 return sizeof(struct efi_device_path_udevice);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100464 case UCLASS_ETH:
465 return dp_size(dev->parent) +
466 sizeof(struct efi_device_path_mac_addr);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100467 case UCLASS_BLK:
468 switch (dev->parent->uclass->uc_drv->id) {
469#ifdef CONFIG_IDE
470 case UCLASS_IDE:
471 return dp_size(dev->parent) +
472 sizeof(struct efi_device_path_atapi);
473#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600474#if defined(CONFIG_SCSI)
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100475 case UCLASS_SCSI:
476 return dp_size(dev->parent) +
477 sizeof(struct efi_device_path_scsi);
478#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600479#if defined(CONFIG_MMC)
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100480 case UCLASS_MMC:
481 return dp_size(dev->parent) +
482 sizeof(struct efi_device_path_sd_mmc_path);
483#endif
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200484#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
485 case UCLASS_AHCI:
486 return dp_size(dev->parent) +
487 sizeof(struct efi_device_path_sata);
488#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200489#if defined(CONFIG_NVME)
490 case UCLASS_NVME:
491 return dp_size(dev->parent) +
492 sizeof(struct efi_device_path_nvme);
493#endif
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100494#ifdef CONFIG_USB
495 case UCLASS_MASS_STORAGE:
496 return dp_size(dev->parent)
497 + sizeof(struct efi_device_path_controller);
498#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100499 default:
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200500 /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
501 return dp_size(dev->parent) +
502 sizeof(struct efi_device_path_udevice);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100503 }
Simon Glass222f3cb2021-09-24 18:30:17 -0600504#if defined(CONFIG_MMC)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400505 case UCLASS_MMC:
506 return dp_size(dev->parent) +
507 sizeof(struct efi_device_path_sd_mmc_path);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100508#endif
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400509 case UCLASS_MASS_STORAGE:
510 case UCLASS_USB_HUB:
511 return dp_size(dev->parent) +
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100512 sizeof(struct efi_device_path_usb);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400513 default:
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200514 return dp_size(dev->parent) +
515 sizeof(struct efi_device_path_udevice);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400516 }
517}
518
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100519/*
520 * Recursively build a device path.
521 *
522 * @buf pointer to the end of the device path
523 * @dev device
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100524 * Return: pointer to the end of the device path
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100525 */
Heinrich Schuchardtc22d9e32019-11-10 02:16:33 +0100526__maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400527{
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200528 enum uclass_id uclass_id;
529
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400530 if (!dev || !dev->driver)
531 return buf;
532
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200533 uclass_id = device_get_uclass_id(dev);
534 if (uclass_id != UCLASS_ROOT)
535 buf = dp_fill(buf, dev->parent);
536
537 switch (uclass_id) {
Jan Kiszkaf1389822022-10-14 18:10:06 +0200538#ifdef CONFIG_NETDEVICES
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100539 case UCLASS_ETH: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200540 struct efi_device_path_mac_addr *dp = buf;
Simon Glass95588622020-12-22 19:30:28 -0700541 struct eth_pdata *pdata = dev_get_plat(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100542
543 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
544 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
545 dp->dp.length = sizeof(*dp);
546 memset(&dp->mac, 0, sizeof(dp->mac));
547 /* We only support IPv4 */
548 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
549 /* Ethernet */
550 dp->if_type = 1;
551 return &dp[1];
552 }
553#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100554 case UCLASS_BLK:
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200555 switch (device_get_uclass_id(dev->parent)) {
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100556#ifdef CONFIG_IDE
557 case UCLASS_IDE: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200558 struct efi_device_path_atapi *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700559 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100560
561 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
562 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
563 dp->dp.length = sizeof(*dp);
564 dp->logical_unit_number = desc->devnum;
565 dp->primary_secondary = IDE_BUS(desc->devnum);
566 dp->slave_master = desc->devnum %
567 (CONFIG_SYS_IDE_MAXDEVICE /
568 CONFIG_SYS_IDE_MAXBUS);
569 return &dp[1];
570 }
571#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600572#if defined(CONFIG_SCSI)
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100573 case UCLASS_SCSI: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200574 struct efi_device_path_scsi *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700575 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100576
577 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
578 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
579 dp->dp.length = sizeof(*dp);
580 dp->logical_unit_number = desc->lun;
581 dp->target_id = desc->target;
582 return &dp[1];
583 }
584#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600585#if defined(CONFIG_MMC)
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100586 case UCLASS_MMC: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200587 struct efi_device_path_sd_mmc_path *sddp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700588 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100589
590 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
591 sddp->dp.sub_type = is_sd(desc) ?
592 DEVICE_PATH_SUB_TYPE_MSG_SD :
593 DEVICE_PATH_SUB_TYPE_MSG_MMC;
594 sddp->dp.length = sizeof(*sddp);
Simon Glass75e534b2020-12-16 21:20:07 -0700595 sddp->slot_number = dev_seq(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100596 return &sddp[1];
597 }
598#endif
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200599#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
600 case UCLASS_AHCI: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200601 struct efi_device_path_sata *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700602 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200603
604 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
605 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SATA;
606 dp->dp.length = sizeof(*dp);
607 dp->hba_port = desc->devnum;
608 /* default 0xffff implies no port multiplier */
609 dp->port_multiplier_port = 0xffff;
610 dp->logical_unit_number = desc->lun;
611 return &dp[1];
612 }
613#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200614#if defined(CONFIG_NVME)
615 case UCLASS_NVME: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200616 struct efi_device_path_nvme *dp = buf;
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200617 u32 ns_id;
618
619 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
620 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_NVME;
621 dp->dp.length = sizeof(*dp);
622 nvme_get_namespace_id(dev, &ns_id, dp->eui64);
623 memcpy(&dp->ns_id, &ns_id, sizeof(ns_id));
624 return &dp[1];
625 }
626#endif
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100627#if defined(CONFIG_USB)
628 case UCLASS_MASS_STORAGE: {
Heinrich Schuchardt232c9db2023-04-01 07:21:55 +0200629 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200630 struct efi_device_path_controller *dp = buf;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100631
632 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
633 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CONTROLLER;
634 dp->dp.length = sizeof(*dp);
635 dp->controller_number = desc->lun;
636 return &dp[1];
637 }
638#endif
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200639 default: {
640 /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200641 struct efi_device_path_udevice *dp = buf;
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200642 struct blk_desc *desc = dev_get_uclass_plat(dev);
643
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200644 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
645 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
646 dp->dp.length = sizeof(*dp);
647 memcpy(&dp->guid, &efi_u_boot_guid,
648 sizeof(efi_guid_t));
649 dp->uclass_id = (UCLASS_BLK & 0xffff) |
650 (desc->uclass_id << 16);
651 dp->dev_number = desc->devnum;
652
653 return &dp[1];
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100654 }
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200655 }
Simon Glass222f3cb2021-09-24 18:30:17 -0600656#if defined(CONFIG_MMC)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400657 case UCLASS_MMC: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200658 struct efi_device_path_sd_mmc_path *sddp = buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400659 struct mmc *mmc = mmc_get_mmc_dev(dev);
660 struct blk_desc *desc = mmc_get_blk_desc(mmc);
661
662 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +0100663 sddp->dp.sub_type = is_sd(desc) ?
664 DEVICE_PATH_SUB_TYPE_MSG_SD :
665 DEVICE_PATH_SUB_TYPE_MSG_MMC;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400666 sddp->dp.length = sizeof(*sddp);
Simon Glass75e534b2020-12-16 21:20:07 -0700667 sddp->slot_number = dev_seq(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400668
669 return &sddp[1];
670 }
671#endif
672 case UCLASS_MASS_STORAGE:
673 case UCLASS_USB_HUB: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200674 struct efi_device_path_usb *udp = buf;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100675
676 switch (device_get_uclass_id(dev->parent)) {
677 case UCLASS_USB_HUB: {
678 struct usb_device *udev = dev_get_parent_priv(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400679
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100680 udp->parent_port_number = udev->portnr;
681 break;
682 }
683 default:
684 udp->parent_port_number = 0;
685 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400686 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100687 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400688 udp->dp.length = sizeof(*udp);
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100689 udp->usb_interface = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400690
691 return &udp[1];
692 }
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200693 default: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200694 struct efi_device_path_udevice *vdp = buf;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200695
696 vdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
697 vdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
698 vdp->dp.length = sizeof(*vdp);
699 memcpy(&vdp->guid, &efi_u_boot_guid, sizeof(efi_guid_t));
700 vdp->uclass_id = uclass_id;
701 vdp->dev_number = dev->seq_;
702
703 return &vdp[1];
704 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400705 }
706}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400707
708static unsigned dp_part_size(struct blk_desc *desc, int part)
709{
710 unsigned dpsize;
Simon Glassec209a72022-01-29 14:58:39 -0700711 struct udevice *dev = desc->bdev;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400712
Simon Glass222f3cb2021-09-24 18:30:17 -0600713 dpsize = dp_size(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400714
715 if (part == 0) /* the actual disk, not a partition */
716 return dpsize;
717
718 if (desc->part_type == PART_TYPE_ISO)
719 dpsize += sizeof(struct efi_device_path_cdrom_path);
720 else
721 dpsize += sizeof(struct efi_device_path_hard_drive_path);
722
723 return dpsize;
724}
725
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100726/*
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100727 * Create a device node for a block device partition.
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100728 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200729 * @buf buffer to which the device path is written
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100730 * @desc block device descriptor
731 * @part partition number, 0 identifies a block device
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200732 *
733 * Return: pointer to position after the node
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100734 */
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100735static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400736{
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600737 struct disk_partition info;
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200738 int ret;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400739
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200740 ret = part_get_info(desc, part, &info);
741 if (ret < 0)
742 return buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400743
744 if (desc->part_type == PART_TYPE_ISO) {
745 struct efi_device_path_cdrom_path *cddp = buf;
746
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100747 cddp->boot_entry = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400748 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
749 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
750 cddp->dp.length = sizeof(*cddp);
751 cddp->partition_start = info.start;
Heinrich Schuchardt28dfd1a2019-09-04 13:56:01 +0200752 cddp->partition_size = info.size;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400753
754 buf = &cddp[1];
755 } else {
756 struct efi_device_path_hard_drive_path *hddp = buf;
757
758 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
759 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
760 hddp->dp.length = sizeof(*hddp);
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100761 hddp->partition_number = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400762 hddp->partition_start = info.start;
763 hddp->partition_end = info.size;
764 if (desc->part_type == PART_TYPE_EFI)
765 hddp->partmap_type = 2;
766 else
767 hddp->partmap_type = 1;
Jonathan Gray84b4d702017-11-22 14:18:59 +1100768
769 switch (desc->sig_type) {
770 case SIG_TYPE_NONE:
771 default:
772 hddp->signature_type = 0;
773 memset(hddp->partition_signature, 0,
774 sizeof(hddp->partition_signature));
775 break;
776 case SIG_TYPE_MBR:
777 hddp->signature_type = 1;
778 memset(hddp->partition_signature, 0,
779 sizeof(hddp->partition_signature));
780 memcpy(hddp->partition_signature, &desc->mbr_sig,
781 sizeof(desc->mbr_sig));
782 break;
783 case SIG_TYPE_GUID:
784 hddp->signature_type = 2;
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900785#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
786 /* info.uuid exists only with PARTITION_UUIDS */
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200787 if (uuid_str_to_bin(info.uuid,
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900788 hddp->partition_signature,
789 UUID_STR_FORMAT_GUID)) {
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200790 log_warning(
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900791 "Partition %d: invalid GUID %s\n",
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200792 part, info.uuid);
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900793 }
794#endif
Jonathan Gray84b4d702017-11-22 14:18:59 +1100795 break;
796 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400797
798 buf = &hddp[1];
799 }
800
801 return buf;
802}
803
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100804/*
805 * Create a device path for a block device or one of its partitions.
806 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200807 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100808 * @desc block device descriptor
809 * @part partition number, 0 identifies a block device
810 */
811static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
812{
Simon Glassec209a72022-01-29 14:58:39 -0700813 struct udevice *dev = desc->bdev;
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100814
Simon Glass222f3cb2021-09-24 18:30:17 -0600815 buf = dp_fill(buf, dev);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100816
817 if (part == 0) /* the actual disk, not a partition */
818 return buf;
819
820 return dp_part_node(buf, desc, part);
821}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400822
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200823/* Construct a device-path from a partition on a block device: */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400824struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
825{
826 void *buf, *start;
827
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100828 start = buf = efi_alloc(dp_part_size(desc, part) + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100829 if (!buf)
830 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400831
832 buf = dp_part_fill(buf, desc, part);
833
834 *((struct efi_device_path *)buf) = END;
835
836 return start;
837}
838
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100839/*
840 * Create a device node for a block device partition.
841 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200842 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100843 * @desc block device descriptor
844 * @part partition number, 0 identifies a block device
845 */
846struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
847{
848 efi_uintn_t dpsize;
849 void *buf;
850
851 if (desc->part_type == PART_TYPE_ISO)
852 dpsize = sizeof(struct efi_device_path_cdrom_path);
853 else
854 dpsize = sizeof(struct efi_device_path_hard_drive_path);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100855 buf = efi_alloc(dpsize);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100856
Heinrich Schuchardte29fbb32022-10-06 13:36:02 +0200857 if (buf)
858 dp_part_node(buf, desc, part);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100859
860 return buf;
861}
862
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200863/**
864 * path_to_uefi() - convert UTF-8 path to an UEFI style path
865 *
866 * Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
867 * separators and UTF-16).
868 *
869 * @src: source buffer
870 * @uefi: target buffer, possibly unaligned
871 */
872static void path_to_uefi(void *uefi, const char *src)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400873{
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200874 u16 *pos = uefi;
875
876 /*
877 * efi_set_bootdev() calls this routine indirectly before the UEFI
878 * subsystem is initialized. So we cannot assume unaligned access to be
879 * enabled.
880 */
881 allow_unaligned();
882
883 while (*src) {
884 s32 code = utf8_get(&src);
885
886 if (code < 0)
887 code = '?';
888 else if (code == '/')
889 code = '\\';
890 utf16_put(code, &pos);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400891 }
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200892 *pos = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400893}
894
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000895/**
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200896 * efi_dp_from_file() - append file path node to device path.
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000897 *
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200898 * @dp: device path or NULL
899 * @path: file path or NULL
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000900 * Return: device path or NULL in case of an error
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400901 */
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200902struct efi_device_path *efi_dp_from_file(const struct efi_device_path *dp,
903 const char *path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400904{
905 struct efi_device_path_file_path *fp;
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200906 void *buf, *pos;
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200907 size_t dpsize, fpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400908
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200909 dpsize = efi_dp_size(dp);
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200910 fpsize = sizeof(struct efi_device_path) +
911 2 * (utf8_utf16_strlen(path) + 1);
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +0900912 if (fpsize > U16_MAX)
913 return NULL;
914
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200915 buf = efi_alloc(dpsize + fpsize + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100916 if (!buf)
917 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400918
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200919 memcpy(buf, dp, dpsize);
920 pos = buf + dpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400921
922 /* add file-path: */
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000923 if (*path) {
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200924 fp = pos;
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000925 fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
926 fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
927 fp->dp.length = (u16)fpsize;
928 path_to_uefi(fp->str, path);
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200929 pos += fpsize;
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000930 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400931
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200932 memcpy(pos, &END, sizeof(END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400933
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200934 return buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400935}
936
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100937struct efi_device_path *efi_dp_from_uart(void)
938{
939 void *buf, *pos;
940 struct efi_device_path_uart *uart;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200941 size_t dpsize = dp_size(dm_root()) + sizeof(*uart) + sizeof(END);
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100942
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100943 buf = efi_alloc(dpsize);
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100944 if (!buf)
945 return NULL;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200946 pos = dp_fill(buf, dm_root());
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100947 uart = pos;
948 uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
949 uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART;
950 uart->dp.length = sizeof(*uart);
951 pos += sizeof(*uart);
952 memcpy(pos, &END, sizeof(END));
953
954 return buf;
955}
956
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +0200957struct efi_device_path __maybe_unused *efi_dp_from_eth(void)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400958{
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400959 void *buf, *start;
960 unsigned dpsize = 0;
961
962 assert(eth_get_dev());
963
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400964 dpsize += dp_size(eth_get_dev());
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400965
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100966 start = buf = efi_alloc(dpsize + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100967 if (!buf)
968 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400969
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400970 buf = dp_fill(buf, eth_get_dev());
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400971
972 *((struct efi_device_path *)buf) = END;
973
974 return start;
975}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400976
Rob Clark18ceba72017-10-10 08:23:06 -0400977/* Construct a device-path for memory-mapped image */
978struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
979 uint64_t start_address,
980 uint64_t end_address)
981{
982 struct efi_device_path_memory *mdp;
983 void *buf, *start;
984
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100985 start = buf = efi_alloc(sizeof(*mdp) + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100986 if (!buf)
987 return NULL;
Rob Clark18ceba72017-10-10 08:23:06 -0400988
989 mdp = buf;
990 mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
991 mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
992 mdp->dp.length = sizeof(*mdp);
993 mdp->memory_type = memory_type;
994 mdp->start_address = start_address;
995 mdp->end_address = end_address;
996 buf = &mdp[1];
997
998 *((struct efi_device_path *)buf) = END;
999
1000 return start;
1001}
1002
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +01001003/**
1004 * efi_dp_split_file_path() - split of relative file path from device path
1005 *
1006 * Given a device path indicating a file on a device, separate the device
1007 * path in two: the device path of the actual device and the file path
1008 * relative to this device.
1009 *
1010 * @full_path: device path including device and file path
1011 * @device_path: path of the device
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001012 * @file_path: relative path of the file or NULL if there is none
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +01001013 * Return: status code
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001014 */
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001015efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
1016 struct efi_device_path **device_path,
1017 struct efi_device_path **file_path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001018{
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001019 struct efi_device_path *p, *dp, *fp = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001020
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001021 *device_path = NULL;
1022 *file_path = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001023 dp = efi_dp_dup(full_path);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001024 if (!dp)
1025 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001026 p = dp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001027 while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001028 p = efi_dp_next(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001029 if (!p)
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001030 goto out;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001031 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001032 fp = efi_dp_dup(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001033 if (!fp)
1034 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001035 p->type = DEVICE_PATH_TYPE_END;
1036 p->sub_type = DEVICE_PATH_SUB_TYPE_END;
1037 p->length = sizeof(*p);
1038
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001039out:
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001040 *device_path = dp;
1041 *file_path = fp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001042 return EFI_SUCCESS;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001043}
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001044
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001045/**
1046 * efi_dp_from_name() - convert U-Boot device and file path to device path
1047 *
1048 * @dev: U-Boot device, e.g. 'mmc'
1049 * @devnr: U-Boot device number, e.g. 1 for 'mmc:1'
1050 * @path: file path relative to U-Boot device, may be NULL
1051 * @device: pointer to receive device path of the device
1052 * @file: pointer to receive device path for the file
1053 * Return: status code
1054 */
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001055efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
1056 const char *path,
1057 struct efi_device_path **device,
1058 struct efi_device_path **file)
1059{
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001060 struct blk_desc *desc = NULL;
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001061 struct efi_device_path *dp;
Simon Glassc1c4a8f2020-05-10 11:39:57 -06001062 struct disk_partition fs_partition;
Rui Miguel Silva433f15a2022-05-11 10:55:40 +01001063 size_t image_size;
1064 void *image_addr;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001065 int part = 0;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001066
AKASHI Takahiro39844412018-11-05 18:06:40 +09001067 if (path && !file)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001068 return EFI_INVALID_PARAMETER;
1069
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +09001070 if (IS_ENABLED(CONFIG_EFI_BINARY_EXEC) &&
1071 (!strcmp(dev, "Mem") || !strcmp(dev, "hostfs"))) {
Heinrich Schuchardtaecb9e22023-05-12 20:18:10 +02001072 /* loadm command and semihosting */
Rui Miguel Silva433f15a2022-05-11 10:55:40 +01001073 efi_get_image_parameters(&image_addr, &image_size);
1074
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001075 dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
1076 (uintptr_t)image_addr, image_size);
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001077 } else if (IS_ENABLED(CONFIG_NETDEVICES) && !strcmp(dev, "Net")) {
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001078 dp = efi_dp_from_eth();
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001079 } else if (!strcmp(dev, "Uart")) {
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001080 dp = efi_dp_from_uart();
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +01001081 } else {
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001082 part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1083 1);
Patrick Delaunayba7a9502019-04-10 11:02:58 +02001084 if (part < 0 || !desc)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001085 return EFI_INVALID_PARAMETER;
1086
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001087 dp = efi_dp_from_part(desc, part);
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001088 }
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001089 if (device)
1090 *device = dp;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001091
1092 if (!path)
1093 return EFI_SUCCESS;
1094
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +02001095 *file = efi_dp_from_file(dp, path);
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001096 if (!*file)
Heinrich Schuchardtbf0b3a12023-05-13 10:22:21 +02001097 return EFI_OUT_OF_RESOURCES;
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +09001098
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001099 return EFI_SUCCESS;
1100}
Heinrich Schuchardt22c8e082020-08-23 10:49:46 +02001101
1102/**
1103 * efi_dp_check_length() - check length of a device path
1104 *
1105 * @dp: pointer to device path
1106 * @maxlen: maximum length of the device path
1107 * Return:
1108 * * length of the device path if it is less or equal @maxlen
1109 * * -1 if the device path is longer then @maxlen
1110 * * -1 if a device path node has a length of less than 4
1111 * * -EINVAL if maxlen exceeds SSIZE_MAX
1112 */
1113ssize_t efi_dp_check_length(const struct efi_device_path *dp,
1114 const size_t maxlen)
1115{
1116 ssize_t ret = 0;
1117 u16 len;
1118
1119 if (maxlen > SSIZE_MAX)
1120 return -EINVAL;
1121 for (;;) {
1122 len = dp->length;
1123 if (len < 4)
1124 return -1;
1125 ret += len;
1126 if (ret > maxlen)
1127 return -1;
1128 if (dp->type == DEVICE_PATH_TYPE_END &&
1129 dp->sub_type == DEVICE_PATH_SUB_TYPE_END)
1130 return ret;
1131 dp = (const struct efi_device_path *)((const u8 *)dp + len);
1132 }
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001133}
1134
1135/**
Heinrich Schuchardt2ca26802024-04-26 16:13:19 +02001136 * efi_dp_from_lo() - get device-path from load option
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001137 *
Heinrich Schuchardt2ca26802024-04-26 16:13:19 +02001138 * The load options in U-Boot may contain multiple concatenated device-paths.
1139 * The first device-path indicates the EFI binary to execute. Subsequent
1140 * device-paths start with a VenMedia node where the GUID identifies the
1141 * function (initrd or fdt).
1142 *
1143 * @lo: EFI load option containing a valid device path
1144 * @guid: GUID identifying device-path or NULL for the EFI binary
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001145 *
1146 * Return:
Heinrich Schuchardt2ca26802024-04-26 16:13:19 +02001147 * device path excluding the matched VenMedia node or NULL.
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001148 * Caller must free the returned value.
1149 */
1150struct
1151efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
Heinrich Schuchardt9979cff2021-10-15 01:31:02 +02001152 const efi_guid_t *guid)
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001153{
1154 struct efi_device_path *fp = lo->file_path;
1155 struct efi_device_path_vendor *vendor;
1156 int lo_len = lo->file_path_length;
1157
Heinrich Schuchardt2ca26802024-04-26 16:13:19 +02001158 if (!guid)
1159 return efi_dp_dup(fp);
1160
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001161 for (; lo_len >= sizeof(struct efi_device_path);
1162 lo_len -= fp->length, fp = (void *)fp + fp->length) {
1163 if (lo_len < 0 || efi_dp_check_length(fp, lo_len) < 0)
1164 break;
1165 if (fp->type != DEVICE_PATH_TYPE_MEDIA_DEVICE ||
1166 fp->sub_type != DEVICE_PATH_SUB_TYPE_VENDOR_PATH)
1167 continue;
1168
1169 vendor = (struct efi_device_path_vendor *)fp;
Heinrich Schuchardt9979cff2021-10-15 01:31:02 +02001170 if (!guidcmp(&vendor->guid, guid))
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +02001171 return efi_dp_dup(efi_dp_next(fp));
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001172 }
1173 log_debug("VenMedia(%pUl) not found in %ls\n", &guid, lo->label);
1174
1175 return NULL;
Heinrich Schuchardt22c8e082020-08-23 10:49:46 +02001176}
Masahisa Kojima6460c3e2021-10-26 17:27:25 +09001177
1178/**
1179 * search_gpt_dp_node() - search gpt device path node
1180 *
1181 * @device_path: device path
1182 *
1183 * Return: pointer to the gpt device path node
1184 */
1185struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path)
1186{
1187 struct efi_device_path *dp = device_path;
1188
1189 while (dp) {
1190 if (dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
1191 dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
1192 struct efi_device_path_hard_drive_path *hd_dp =
1193 (struct efi_device_path_hard_drive_path *)dp;
1194
1195 if (hd_dp->partmap_type == PART_FORMAT_GPT &&
1196 hd_dp->signature_type == SIG_TYPE_GUID)
1197 return dp;
1198 }
1199 dp = efi_dp_next(dp);
1200 }
1201
1202 return NULL;
1203}