blob: 5b050fa17c50345b13a0effad530d01a51acbc22 [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 <common.h>
11#include <blk.h>
12#include <dm.h>
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +020013#include <dm/root.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glass274e0b02020-05-10 11:39:56 -060015#include <net.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040016#include <usb.h>
17#include <mmc.h>
Patrick Wildta3ca37e2019-10-03 16:24:17 +020018#include <nvme.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040019#include <efi_loader.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040020#include <part.h>
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +020021#include <uuid.h>
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +020022#include <asm-generic/unaligned.h>
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +090023#include <linux/compat.h> /* U16_MAX */
Rob Clarkf90cb9f2017-09-13 18:05:28 -040024
25/* template END node: */
Masahisa Kojima97bd9da2022-06-19 13:55:59 +090026const struct efi_device_path END = {
Rob Clarkf90cb9f2017-09-13 18:05:28 -040027 .type = DEVICE_PATH_TYPE_END,
28 .sub_type = DEVICE_PATH_SUB_TYPE_END,
29 .length = sizeof(END),
30};
31
Simon Glass222f3cb2021-09-24 18:30:17 -060032#if defined(CONFIG_MMC)
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +010033/*
34 * Determine if an MMC device is an SD card.
35 *
36 * @desc block device descriptor
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010037 * Return: true if the device is an SD card
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +010038 */
39static bool is_sd(struct blk_desc *desc)
40{
41 struct mmc *mmc = find_mmc_device(desc->devnum);
42
43 if (!mmc)
44 return false;
45
46 return IS_SD(mmc) != 0U;
47}
48#endif
49
Rob Clarkf90cb9f2017-09-13 18:05:28 -040050/*
51 * Iterate to next block in device-path, terminating (returning NULL)
52 * at /End* node.
53 */
54struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
55{
56 if (dp == NULL)
57 return NULL;
58 if (dp->type == DEVICE_PATH_TYPE_END)
59 return NULL;
60 dp = ((void *)dp) + dp->length;
61 if (dp->type == DEVICE_PATH_TYPE_END)
62 return NULL;
63 return (struct efi_device_path *)dp;
64}
65
66/*
67 * Compare two device-paths, stopping when the shorter of the two hits
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +020068 * an End* node. This is useful to, for example, compare a device-path
Rob Clarkf90cb9f2017-09-13 18:05:28 -040069 * representing a device with one representing a file on the device, or
70 * a device with a parent device.
71 */
Heinrich Schuchardt753e2482017-10-26 19:25:48 +020072int efi_dp_match(const struct efi_device_path *a,
73 const struct efi_device_path *b)
Rob Clarkf90cb9f2017-09-13 18:05:28 -040074{
75 while (1) {
76 int ret;
77
78 ret = memcmp(&a->length, &b->length, sizeof(a->length));
79 if (ret)
80 return ret;
81
82 ret = memcmp(a, b, a->length);
83 if (ret)
84 return ret;
85
86 a = efi_dp_next(a);
87 b = efi_dp_next(b);
88
89 if (!a || !b)
90 return 0;
91 }
92}
93
Heinrich Schuchardt24f0e6a2022-02-26 12:10:10 +010094/**
95 * efi_dp_shorten() - shorten device-path
96 *
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +020097 * When creating a short boot option we want to use a device-path that is
98 * independent of the location where the block device is plugged in.
Rob Clarkf90cb9f2017-09-13 18:05:28 -040099 *
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +0200100 * UsbWwi() nodes contain a serial number, hard drive paths a partition
101 * UUID. Both should be unique.
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200102 *
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +0200103 * See UEFI spec, section 3.1.2 for "short-form device path".
Heinrich Schuchardt24f0e6a2022-02-26 12:10:10 +0100104 *
Heinrich Schuchardtdb17dbc2022-03-21 08:26:48 +0100105 * @dp: original device-path
Heinrich Schuchardt24f0e6a2022-02-26 12:10:10 +0100106 * @Return: shortened device-path or NULL
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400107 */
Heinrich Schuchardt24f0e6a2022-02-26 12:10:10 +0100108struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400109{
110 while (dp) {
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +0200111 if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_WWI) ||
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400112 EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
113 EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
114 return dp;
115
116 dp = efi_dp_next(dp);
117 }
118
119 return dp;
120}
121
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100122/**
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100123 * find_handle() - find handle by device path and installed protocol
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100124 *
125 * If @rem is provided, the handle with the longest partial match is returned.
126 *
127 * @dp: device path to search
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100128 * @guid: GUID of protocol that must be installed on path or NULL
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100129 * @short_path: use short form device path for matching
130 * @rem: pointer to receive remaining device path
131 * Return: matching handle
132 */
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100133static efi_handle_t find_handle(struct efi_device_path *dp,
134 const efi_guid_t *guid, bool short_path,
135 struct efi_device_path **rem)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400136{
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100137 efi_handle_t handle, best_handle = NULL;
138 efi_uintn_t len, best_len = 0;
139
140 len = efi_dp_instance_size(dp);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400141
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100142 list_for_each_entry(handle, &efi_obj_list, link) {
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100143 struct efi_handler *handler;
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100144 struct efi_device_path *dp_current;
145 efi_uintn_t len_current;
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100146 efi_status_t ret;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400147
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100148 if (guid) {
149 ret = efi_search_protocol(handle, guid, &handler);
150 if (ret != EFI_SUCCESS)
151 continue;
152 }
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100153 ret = efi_search_protocol(handle, &efi_guid_device_path,
154 &handler);
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100155 if (ret != EFI_SUCCESS)
156 continue;
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100157 dp_current = handler->protocol_interface;
158 if (short_path) {
159 dp_current = efi_dp_shorten(dp_current);
160 if (!dp_current)
161 continue;
162 }
163 len_current = efi_dp_instance_size(dp_current);
164 if (rem) {
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100165 if (len_current > len)
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100166 continue;
167 } else {
168 if (len_current != len)
169 continue;
170 }
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100171 if (memcmp(dp_current, dp, len_current))
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100172 continue;
173 if (!rem)
174 return handle;
175 if (len_current > best_len) {
176 best_len = len_current;
177 best_handle = handle;
178 *rem = (void*)((u8 *)dp + len_current);
179 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400180 }
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100181 return best_handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400182}
183
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100184/**
185 * efi_dp_find_obj() - find handle by device path
186 *
187 * If @rem is provided, the handle with the longest partial match is returned.
188 *
189 * @dp: device path to search
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100190 * @guid: GUID of protocol that must be installed on path or NULL
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100191 * @rem: pointer to receive remaining device path
192 * Return: matching handle
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400193 */
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100194efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100195 const efi_guid_t *guid,
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100196 struct efi_device_path **rem)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400197{
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100198 efi_handle_t handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400199
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100200 handle = find_handle(dp, guid, false, rem);
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100201 if (!handle)
202 /* Match short form device path */
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100203 handle = find_handle(dp, guid, true, rem);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400204
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100205 return handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400206}
207
Heinrich Schuchardt0976f8b2018-01-19 20:24:49 +0100208/*
209 * Determine the last device path node that is not the end node.
210 *
211 * @dp device path
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100212 * Return: last node before the end node if it exists
Heinrich Schuchardt0976f8b2018-01-19 20:24:49 +0100213 * otherwise NULL
214 */
215const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
216{
217 struct efi_device_path *ret;
218
219 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
220 return NULL;
221 while (dp) {
222 ret = (struct efi_device_path *)dp;
223 dp = efi_dp_next(dp);
224 }
225 return ret;
226}
227
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200228/* get size of the first device path instance excluding end node */
229efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400230{
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200231 efi_uintn_t sz = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400232
Heinrich Schuchardt01d48ed2018-04-16 07:59:07 +0200233 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
234 return 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400235 while (dp) {
236 sz += dp->length;
237 dp = efi_dp_next(dp);
238 }
239
240 return sz;
241}
242
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200243/* get size of multi-instance device path excluding end node */
244efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
245{
246 const struct efi_device_path *p = dp;
247
248 if (!p)
249 return 0;
250 while (p->type != DEVICE_PATH_TYPE_END ||
251 p->sub_type != DEVICE_PATH_SUB_TYPE_END)
252 p = (void *)p + p->length;
253
254 return (void *)p - (void *)dp;
255}
256
257/* copy multi-instance device path */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400258struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
259{
260 struct efi_device_path *ndp;
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200261 size_t sz = efi_dp_size(dp) + sizeof(END);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400262
263 if (!dp)
264 return NULL;
265
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100266 ndp = efi_alloc(sz);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100267 if (!ndp)
268 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400269 memcpy(ndp, dp, sz);
270
271 return ndp;
272}
273
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200274/**
275 * efi_dp_append_or_concatenate() - Append or concatenate two device paths.
276 * Concatenated device path will be separated
277 * by a sub-type 0xff end node
278 *
279 * @dp1: First device path
280 * @dp2: Second device path
281 * @concat: If true the two device paths will be concatenated and separated
282 * by an end of entrire device path sub-type 0xff end node.
283 * If true the second device path will be appended to the first and
284 * terminated by an end node
285 *
286 * Return:
287 * concatenated device path or NULL. Caller must free the returned value
288 */
289static struct
290efi_device_path *efi_dp_append_or_concatenate(const struct efi_device_path *dp1,
291 const struct efi_device_path *dp2,
292 bool concat)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400293{
294 struct efi_device_path *ret;
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200295 size_t end_size = sizeof(END);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400296
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200297 if (concat)
298 end_size = 2 * sizeof(END);
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200299 if (!dp1 && !dp2) {
300 /* return an end node */
301 ret = efi_dp_dup(&END);
302 } else if (!dp1) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400303 ret = efi_dp_dup(dp2);
304 } else if (!dp2) {
305 ret = efi_dp_dup(dp1);
306 } else {
307 /* both dp1 and dp2 are non-null */
308 unsigned sz1 = efi_dp_size(dp1);
309 unsigned sz2 = efi_dp_size(dp2);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100310 void *p = efi_alloc(sz1 + sz2 + end_size);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100311 if (!p)
312 return NULL;
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200313 ret = p;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400314 memcpy(p, dp1, sz1);
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200315 p += sz1;
316
317 if (concat) {
318 memcpy(p, &END, sizeof(END));
319 p += sizeof(END);
320 }
321
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200322 /* the end node of the second device path has to be retained */
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200323 memcpy(p, dp2, sz2);
324 p += sz2;
325 memcpy(p, &END, sizeof(END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400326 }
327
328 return ret;
329}
330
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200331/**
332 * efi_dp_append() - Append a device to an existing device path.
333 *
334 * @dp1: First device path
335 * @dp2: Second device path
336 *
337 * Return:
338 * concatenated device path or NULL. Caller must free the returned value
339 */
340struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
341 const struct efi_device_path *dp2)
342{
343 return efi_dp_append_or_concatenate(dp1, dp2, false);
344}
345
346/**
347 * efi_dp_concat() - Concatenate 2 device paths. The final device path will
348 * contain two device paths separated by and end node (0xff).
349 *
350 * @dp1: First device path
351 * @dp2: Second device path
352 *
353 * Return:
354 * concatenated device path or NULL. Caller must free the returned value
355 */
356struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
357 const struct efi_device_path *dp2)
358{
359 return efi_dp_append_or_concatenate(dp1, dp2, true);
360}
361
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400362struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
363 const struct efi_device_path *node)
364{
365 struct efi_device_path *ret;
366
367 if (!node && !dp) {
368 ret = efi_dp_dup(&END);
369 } else if (!node) {
370 ret = efi_dp_dup(dp);
371 } else if (!dp) {
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200372 size_t sz = node->length;
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100373 void *p = efi_alloc(sz + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100374 if (!p)
375 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400376 memcpy(p, node, sz);
377 memcpy(p + sz, &END, sizeof(END));
378 ret = p;
379 } else {
380 /* both dp and node are non-null */
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200381 size_t sz = efi_dp_size(dp);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100382 void *p = efi_alloc(sz + node->length + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100383 if (!p)
384 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400385 memcpy(p, dp, sz);
386 memcpy(p + sz, node, node->length);
387 memcpy(p + sz + node->length, &END, sizeof(END));
388 ret = p;
389 }
390
391 return ret;
392}
393
Heinrich Schuchardtb41c8e22018-04-16 07:59:05 +0200394struct efi_device_path *efi_dp_create_device_node(const u8 type,
395 const u8 sub_type,
396 const u16 length)
397{
398 struct efi_device_path *ret;
399
Heinrich Schuchardtc96c5942019-04-23 00:51:01 +0200400 if (length < sizeof(struct efi_device_path))
401 return NULL;
402
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100403 ret = efi_alloc(length);
Heinrich Schuchardtb41c8e22018-04-16 07:59:05 +0200404 if (!ret)
405 return ret;
406 ret->type = type;
407 ret->sub_type = sub_type;
408 ret->length = length;
409 return ret;
410}
411
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200412struct efi_device_path *efi_dp_append_instance(
413 const struct efi_device_path *dp,
414 const struct efi_device_path *dpi)
415{
416 size_t sz, szi;
417 struct efi_device_path *p, *ret;
418
419 if (!dpi)
420 return NULL;
421 if (!dp)
422 return efi_dp_dup(dpi);
423 sz = efi_dp_size(dp);
424 szi = efi_dp_instance_size(dpi);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100425 p = efi_alloc(sz + szi + 2 * sizeof(END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200426 if (!p)
427 return NULL;
428 ret = p;
429 memcpy(p, dp, sz + sizeof(END));
430 p = (void *)p + sz;
431 p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
432 p = (void *)p + sizeof(END);
433 memcpy(p, dpi, szi);
434 p = (void *)p + szi;
435 memcpy(p, &END, sizeof(END));
436 return ret;
437}
438
439struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
440 efi_uintn_t *size)
441{
442 size_t sz;
443 struct efi_device_path *p;
444
445 if (size)
446 *size = 0;
447 if (!dp || !*dp)
448 return NULL;
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200449 sz = efi_dp_instance_size(*dp);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100450 p = efi_alloc(sz + sizeof(END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200451 if (!p)
452 return NULL;
453 memcpy(p, *dp, sz + sizeof(END));
454 *dp = (void *)*dp + sz;
455 if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
456 *dp = (void *)*dp + sizeof(END);
457 else
458 *dp = NULL;
459 if (size)
460 *size = sz + sizeof(END);
461 return p;
462}
463
464bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
465{
466 const struct efi_device_path *p = dp;
467
468 if (!p)
469 return false;
470 while (p->type != DEVICE_PATH_TYPE_END)
471 p = (void *)p + p->length;
472 return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
473}
474
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400475/* size of device-path not including END node for device and all parents
476 * up to the root device.
477 */
Heinrich Schuchardtc22d9e32019-11-10 02:16:33 +0100478__maybe_unused static unsigned int dp_size(struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400479{
480 if (!dev || !dev->driver)
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200481 return sizeof(struct efi_device_path_udevice);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400482
Simon Glass56ada7b2022-01-29 14:58:38 -0700483 switch (device_get_uclass_id(dev)) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400484 case UCLASS_ROOT:
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400485 /* stop traversing parents at this point: */
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200486 return sizeof(struct efi_device_path_udevice);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100487 case UCLASS_ETH:
488 return dp_size(dev->parent) +
489 sizeof(struct efi_device_path_mac_addr);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100490 case UCLASS_BLK:
491 switch (dev->parent->uclass->uc_drv->id) {
492#ifdef CONFIG_IDE
493 case UCLASS_IDE:
494 return dp_size(dev->parent) +
495 sizeof(struct efi_device_path_atapi);
496#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600497#if defined(CONFIG_SCSI)
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100498 case UCLASS_SCSI:
499 return dp_size(dev->parent) +
500 sizeof(struct efi_device_path_scsi);
501#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600502#if defined(CONFIG_MMC)
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100503 case UCLASS_MMC:
504 return dp_size(dev->parent) +
505 sizeof(struct efi_device_path_sd_mmc_path);
506#endif
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200507#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
508 case UCLASS_AHCI:
509 return dp_size(dev->parent) +
510 sizeof(struct efi_device_path_sata);
511#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200512#if defined(CONFIG_NVME)
513 case UCLASS_NVME:
514 return dp_size(dev->parent) +
515 sizeof(struct efi_device_path_nvme);
516#endif
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100517#ifdef CONFIG_USB
518 case UCLASS_MASS_STORAGE:
519 return dp_size(dev->parent)
520 + sizeof(struct efi_device_path_controller);
521#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100522 default:
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200523 /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
524 return dp_size(dev->parent) +
525 sizeof(struct efi_device_path_udevice);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100526 }
Simon Glass222f3cb2021-09-24 18:30:17 -0600527#if defined(CONFIG_MMC)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400528 case UCLASS_MMC:
529 return dp_size(dev->parent) +
530 sizeof(struct efi_device_path_sd_mmc_path);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100531#endif
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400532 case UCLASS_MASS_STORAGE:
533 case UCLASS_USB_HUB:
534 return dp_size(dev->parent) +
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100535 sizeof(struct efi_device_path_usb);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400536 default:
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200537 return dp_size(dev->parent) +
538 sizeof(struct efi_device_path_udevice);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400539 }
540}
541
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100542/*
543 * Recursively build a device path.
544 *
545 * @buf pointer to the end of the device path
546 * @dev device
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100547 * Return: pointer to the end of the device path
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100548 */
Heinrich Schuchardtc22d9e32019-11-10 02:16:33 +0100549__maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400550{
551 if (!dev || !dev->driver)
552 return buf;
553
Simon Glass56ada7b2022-01-29 14:58:38 -0700554 switch (device_get_uclass_id(dev)) {
Jan Kiszkaf1389822022-10-14 18:10:06 +0200555#ifdef CONFIG_NETDEVICES
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100556 case UCLASS_ETH: {
557 struct efi_device_path_mac_addr *dp =
558 dp_fill(buf, dev->parent);
Simon Glass95588622020-12-22 19:30:28 -0700559 struct eth_pdata *pdata = dev_get_plat(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100560
561 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
562 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
563 dp->dp.length = sizeof(*dp);
564 memset(&dp->mac, 0, sizeof(dp->mac));
565 /* We only support IPv4 */
566 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
567 /* Ethernet */
568 dp->if_type = 1;
569 return &dp[1];
570 }
571#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100572 case UCLASS_BLK:
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200573 switch (device_get_uclass_id(dev->parent)) {
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100574#ifdef CONFIG_IDE
575 case UCLASS_IDE: {
576 struct efi_device_path_atapi *dp =
577 dp_fill(buf, dev->parent);
Simon Glass71fa5b42020-12-03 16:55:18 -0700578 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100579
580 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
581 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
582 dp->dp.length = sizeof(*dp);
583 dp->logical_unit_number = desc->devnum;
584 dp->primary_secondary = IDE_BUS(desc->devnum);
585 dp->slave_master = desc->devnum %
586 (CONFIG_SYS_IDE_MAXDEVICE /
587 CONFIG_SYS_IDE_MAXBUS);
588 return &dp[1];
589 }
590#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600591#if defined(CONFIG_SCSI)
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100592 case UCLASS_SCSI: {
593 struct efi_device_path_scsi *dp =
594 dp_fill(buf, dev->parent);
Simon Glass71fa5b42020-12-03 16:55:18 -0700595 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100596
597 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
598 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
599 dp->dp.length = sizeof(*dp);
600 dp->logical_unit_number = desc->lun;
601 dp->target_id = desc->target;
602 return &dp[1];
603 }
604#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600605#if defined(CONFIG_MMC)
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100606 case UCLASS_MMC: {
607 struct efi_device_path_sd_mmc_path *sddp =
608 dp_fill(buf, dev->parent);
Simon Glass71fa5b42020-12-03 16:55:18 -0700609 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100610
611 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
612 sddp->dp.sub_type = is_sd(desc) ?
613 DEVICE_PATH_SUB_TYPE_MSG_SD :
614 DEVICE_PATH_SUB_TYPE_MSG_MMC;
615 sddp->dp.length = sizeof(*sddp);
Simon Glass75e534b2020-12-16 21:20:07 -0700616 sddp->slot_number = dev_seq(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100617 return &sddp[1];
618 }
619#endif
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200620#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
621 case UCLASS_AHCI: {
622 struct efi_device_path_sata *dp =
623 dp_fill(buf, dev->parent);
Simon Glass71fa5b42020-12-03 16:55:18 -0700624 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200625
626 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
627 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SATA;
628 dp->dp.length = sizeof(*dp);
629 dp->hba_port = desc->devnum;
630 /* default 0xffff implies no port multiplier */
631 dp->port_multiplier_port = 0xffff;
632 dp->logical_unit_number = desc->lun;
633 return &dp[1];
634 }
635#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200636#if defined(CONFIG_NVME)
637 case UCLASS_NVME: {
638 struct efi_device_path_nvme *dp =
639 dp_fill(buf, dev->parent);
640 u32 ns_id;
641
642 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
643 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_NVME;
644 dp->dp.length = sizeof(*dp);
645 nvme_get_namespace_id(dev, &ns_id, dp->eui64);
646 memcpy(&dp->ns_id, &ns_id, sizeof(ns_id));
647 return &dp[1];
648 }
649#endif
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100650#if defined(CONFIG_USB)
651 case UCLASS_MASS_STORAGE: {
Heinrich Schuchardt232c9db2023-04-01 07:21:55 +0200652 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100653 struct efi_device_path_controller *dp =
654 dp_fill(buf, dev->parent);
655
656 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
657 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CONTROLLER;
658 dp->dp.length = sizeof(*dp);
659 dp->controller_number = desc->lun;
660 return &dp[1];
661 }
662#endif
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200663 default: {
664 /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
665 struct efi_device_path_udevice *dp;
666 struct blk_desc *desc = dev_get_uclass_plat(dev);
667
668 dp = dp_fill(buf, dev->parent);
669 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
670 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
671 dp->dp.length = sizeof(*dp);
672 memcpy(&dp->guid, &efi_u_boot_guid,
673 sizeof(efi_guid_t));
674 dp->uclass_id = (UCLASS_BLK & 0xffff) |
675 (desc->uclass_id << 16);
676 dp->dev_number = desc->devnum;
677
678 return &dp[1];
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100679 }
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200680 }
Simon Glass222f3cb2021-09-24 18:30:17 -0600681#if defined(CONFIG_MMC)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400682 case UCLASS_MMC: {
683 struct efi_device_path_sd_mmc_path *sddp =
684 dp_fill(buf, dev->parent);
685 struct mmc *mmc = mmc_get_mmc_dev(dev);
686 struct blk_desc *desc = mmc_get_blk_desc(mmc);
687
688 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +0100689 sddp->dp.sub_type = is_sd(desc) ?
690 DEVICE_PATH_SUB_TYPE_MSG_SD :
691 DEVICE_PATH_SUB_TYPE_MSG_MMC;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400692 sddp->dp.length = sizeof(*sddp);
Simon Glass75e534b2020-12-16 21:20:07 -0700693 sddp->slot_number = dev_seq(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400694
695 return &sddp[1];
696 }
697#endif
698 case UCLASS_MASS_STORAGE:
699 case UCLASS_USB_HUB: {
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100700 struct efi_device_path_usb *udp = dp_fill(buf, dev->parent);
701
702 switch (device_get_uclass_id(dev->parent)) {
703 case UCLASS_USB_HUB: {
704 struct usb_device *udev = dev_get_parent_priv(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400705
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100706 udp->parent_port_number = udev->portnr;
707 break;
708 }
709 default:
710 udp->parent_port_number = 0;
711 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400712 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100713 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400714 udp->dp.length = sizeof(*udp);
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100715 udp->usb_interface = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400716
717 return &udp[1];
718 }
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200719 default: {
720 struct efi_device_path_udevice *vdp;
721 enum uclass_id uclass_id = device_get_uclass_id(dev);
722
723 if (uclass_id == UCLASS_ROOT)
724 vdp = buf;
725 else
726 vdp = dp_fill(buf, dev->parent);
727
728 vdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
729 vdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
730 vdp->dp.length = sizeof(*vdp);
731 memcpy(&vdp->guid, &efi_u_boot_guid, sizeof(efi_guid_t));
732 vdp->uclass_id = uclass_id;
733 vdp->dev_number = dev->seq_;
734
735 return &vdp[1];
736 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400737 }
738}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400739
740static unsigned dp_part_size(struct blk_desc *desc, int part)
741{
742 unsigned dpsize;
Simon Glassec209a72022-01-29 14:58:39 -0700743 struct udevice *dev = desc->bdev;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400744
Simon Glass222f3cb2021-09-24 18:30:17 -0600745 dpsize = dp_size(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400746
747 if (part == 0) /* the actual disk, not a partition */
748 return dpsize;
749
750 if (desc->part_type == PART_TYPE_ISO)
751 dpsize += sizeof(struct efi_device_path_cdrom_path);
752 else
753 dpsize += sizeof(struct efi_device_path_hard_drive_path);
754
755 return dpsize;
756}
757
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100758/*
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100759 * Create a device node for a block device partition.
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100760 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200761 * @buf buffer to which the device path is written
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100762 * @desc block device descriptor
763 * @part partition number, 0 identifies a block device
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200764 *
765 * Return: pointer to position after the node
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100766 */
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100767static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400768{
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600769 struct disk_partition info;
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200770 int ret;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400771
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200772 ret = part_get_info(desc, part, &info);
773 if (ret < 0)
774 return buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400775
776 if (desc->part_type == PART_TYPE_ISO) {
777 struct efi_device_path_cdrom_path *cddp = buf;
778
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100779 cddp->boot_entry = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400780 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
781 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
782 cddp->dp.length = sizeof(*cddp);
783 cddp->partition_start = info.start;
Heinrich Schuchardt28dfd1a2019-09-04 13:56:01 +0200784 cddp->partition_size = info.size;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400785
786 buf = &cddp[1];
787 } else {
788 struct efi_device_path_hard_drive_path *hddp = buf;
789
790 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
791 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
792 hddp->dp.length = sizeof(*hddp);
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100793 hddp->partition_number = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400794 hddp->partition_start = info.start;
795 hddp->partition_end = info.size;
796 if (desc->part_type == PART_TYPE_EFI)
797 hddp->partmap_type = 2;
798 else
799 hddp->partmap_type = 1;
Jonathan Gray84b4d702017-11-22 14:18:59 +1100800
801 switch (desc->sig_type) {
802 case SIG_TYPE_NONE:
803 default:
804 hddp->signature_type = 0;
805 memset(hddp->partition_signature, 0,
806 sizeof(hddp->partition_signature));
807 break;
808 case SIG_TYPE_MBR:
809 hddp->signature_type = 1;
810 memset(hddp->partition_signature, 0,
811 sizeof(hddp->partition_signature));
812 memcpy(hddp->partition_signature, &desc->mbr_sig,
813 sizeof(desc->mbr_sig));
814 break;
815 case SIG_TYPE_GUID:
816 hddp->signature_type = 2;
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900817#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
818 /* info.uuid exists only with PARTITION_UUIDS */
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200819 if (uuid_str_to_bin(info.uuid,
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900820 hddp->partition_signature,
821 UUID_STR_FORMAT_GUID)) {
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200822 log_warning(
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900823 "Partition %d: invalid GUID %s\n",
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200824 part, info.uuid);
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900825 }
826#endif
Jonathan Gray84b4d702017-11-22 14:18:59 +1100827 break;
828 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400829
830 buf = &hddp[1];
831 }
832
833 return buf;
834}
835
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100836/*
837 * Create a device path for a block device or one of its partitions.
838 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200839 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100840 * @desc block device descriptor
841 * @part partition number, 0 identifies a block device
842 */
843static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
844{
Simon Glassec209a72022-01-29 14:58:39 -0700845 struct udevice *dev = desc->bdev;
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100846
Simon Glass222f3cb2021-09-24 18:30:17 -0600847 buf = dp_fill(buf, dev);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100848
849 if (part == 0) /* the actual disk, not a partition */
850 return buf;
851
852 return dp_part_node(buf, desc, part);
853}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400854
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200855/* Construct a device-path from a partition on a block device: */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400856struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
857{
858 void *buf, *start;
859
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100860 start = buf = efi_alloc(dp_part_size(desc, part) + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100861 if (!buf)
862 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400863
864 buf = dp_part_fill(buf, desc, part);
865
866 *((struct efi_device_path *)buf) = END;
867
868 return start;
869}
870
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100871/*
872 * Create a device node for a block device partition.
873 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200874 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100875 * @desc block device descriptor
876 * @part partition number, 0 identifies a block device
877 */
878struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
879{
880 efi_uintn_t dpsize;
881 void *buf;
882
883 if (desc->part_type == PART_TYPE_ISO)
884 dpsize = sizeof(struct efi_device_path_cdrom_path);
885 else
886 dpsize = sizeof(struct efi_device_path_hard_drive_path);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100887 buf = efi_alloc(dpsize);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100888
Heinrich Schuchardte29fbb32022-10-06 13:36:02 +0200889 if (buf)
890 dp_part_node(buf, desc, part);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100891
892 return buf;
893}
894
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200895/**
896 * path_to_uefi() - convert UTF-8 path to an UEFI style path
897 *
898 * Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
899 * separators and UTF-16).
900 *
901 * @src: source buffer
902 * @uefi: target buffer, possibly unaligned
903 */
904static void path_to_uefi(void *uefi, const char *src)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400905{
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200906 u16 *pos = uefi;
907
908 /*
909 * efi_set_bootdev() calls this routine indirectly before the UEFI
910 * subsystem is initialized. So we cannot assume unaligned access to be
911 * enabled.
912 */
913 allow_unaligned();
914
915 while (*src) {
916 s32 code = utf8_get(&src);
917
918 if (code < 0)
919 code = '?';
920 else if (code == '/')
921 code = '\\';
922 utf16_put(code, &pos);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400923 }
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200924 *pos = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400925}
926
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000927/**
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200928 * efi_dp_from_file() - append file path node to device path.
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000929 *
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200930 * @dp: device path or NULL
931 * @path: file path or NULL
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000932 * Return: device path or NULL in case of an error
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400933 */
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200934struct efi_device_path *efi_dp_from_file(const struct efi_device_path *dp,
935 const char *path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400936{
937 struct efi_device_path_file_path *fp;
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200938 void *buf, *pos;
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200939 size_t dpsize, fpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400940
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200941 dpsize = efi_dp_size(dp);
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200942 fpsize = sizeof(struct efi_device_path) +
943 2 * (utf8_utf16_strlen(path) + 1);
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +0900944 if (fpsize > U16_MAX)
945 return NULL;
946
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200947 buf = efi_alloc(dpsize + fpsize + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100948 if (!buf)
949 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400950
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200951 memcpy(buf, dp, dpsize);
952 pos = buf + dpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400953
954 /* add file-path: */
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000955 if (*path) {
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200956 fp = pos;
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000957 fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
958 fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
959 fp->dp.length = (u16)fpsize;
960 path_to_uefi(fp->str, path);
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200961 pos += fpsize;
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000962 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400963
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200964 memcpy(pos, &END, sizeof(END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400965
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200966 return buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400967}
968
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100969struct efi_device_path *efi_dp_from_uart(void)
970{
971 void *buf, *pos;
972 struct efi_device_path_uart *uart;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200973 size_t dpsize = dp_size(dm_root()) + sizeof(*uart) + sizeof(END);
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100974
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100975 buf = efi_alloc(dpsize);
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100976 if (!buf)
977 return NULL;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200978 pos = dp_fill(buf, dm_root());
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100979 uart = pos;
980 uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
981 uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART;
982 uart->dp.length = sizeof(*uart);
983 pos += sizeof(*uart);
984 memcpy(pos, &END, sizeof(END));
985
986 return buf;
987}
988
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +0200989struct efi_device_path __maybe_unused *efi_dp_from_eth(void)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400990{
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400991 void *buf, *start;
992 unsigned dpsize = 0;
993
994 assert(eth_get_dev());
995
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400996 dpsize += dp_size(eth_get_dev());
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400997
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100998 start = buf = efi_alloc(dpsize + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100999 if (!buf)
1000 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001001
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001002 buf = dp_fill(buf, eth_get_dev());
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001003
1004 *((struct efi_device_path *)buf) = END;
1005
1006 return start;
1007}
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001008
Rob Clark18ceba72017-10-10 08:23:06 -04001009/* Construct a device-path for memory-mapped image */
1010struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
1011 uint64_t start_address,
1012 uint64_t end_address)
1013{
1014 struct efi_device_path_memory *mdp;
1015 void *buf, *start;
1016
Heinrich Schuchardt45640252023-03-19 09:20:22 +01001017 start = buf = efi_alloc(sizeof(*mdp) + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001018 if (!buf)
1019 return NULL;
Rob Clark18ceba72017-10-10 08:23:06 -04001020
1021 mdp = buf;
1022 mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
1023 mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
1024 mdp->dp.length = sizeof(*mdp);
1025 mdp->memory_type = memory_type;
1026 mdp->start_address = start_address;
1027 mdp->end_address = end_address;
1028 buf = &mdp[1];
1029
1030 *((struct efi_device_path *)buf) = END;
1031
1032 return start;
1033}
1034
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +01001035/**
1036 * efi_dp_split_file_path() - split of relative file path from device path
1037 *
1038 * Given a device path indicating a file on a device, separate the device
1039 * path in two: the device path of the actual device and the file path
1040 * relative to this device.
1041 *
1042 * @full_path: device path including device and file path
1043 * @device_path: path of the device
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001044 * @file_path: relative path of the file or NULL if there is none
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +01001045 * Return: status code
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001046 */
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001047efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
1048 struct efi_device_path **device_path,
1049 struct efi_device_path **file_path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001050{
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001051 struct efi_device_path *p, *dp, *fp = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001052
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001053 *device_path = NULL;
1054 *file_path = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001055 dp = efi_dp_dup(full_path);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001056 if (!dp)
1057 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001058 p = dp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001059 while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001060 p = efi_dp_next(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001061 if (!p)
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001062 goto out;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001063 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001064 fp = efi_dp_dup(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001065 if (!fp)
1066 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001067 p->type = DEVICE_PATH_TYPE_END;
1068 p->sub_type = DEVICE_PATH_SUB_TYPE_END;
1069 p->length = sizeof(*p);
1070
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001071out:
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001072 *device_path = dp;
1073 *file_path = fp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001074 return EFI_SUCCESS;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001075}
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001076
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001077/**
1078 * efi_dp_from_name() - convert U-Boot device and file path to device path
1079 *
1080 * @dev: U-Boot device, e.g. 'mmc'
1081 * @devnr: U-Boot device number, e.g. 1 for 'mmc:1'
1082 * @path: file path relative to U-Boot device, may be NULL
1083 * @device: pointer to receive device path of the device
1084 * @file: pointer to receive device path for the file
1085 * Return: status code
1086 */
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001087efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
1088 const char *path,
1089 struct efi_device_path **device,
1090 struct efi_device_path **file)
1091{
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001092 struct blk_desc *desc = NULL;
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001093 struct efi_device_path *dp;
Simon Glassc1c4a8f2020-05-10 11:39:57 -06001094 struct disk_partition fs_partition;
Rui Miguel Silva433f15a2022-05-11 10:55:40 +01001095 size_t image_size;
1096 void *image_addr;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001097 int part = 0;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001098
AKASHI Takahiro39844412018-11-05 18:06:40 +09001099 if (path && !file)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001100 return EFI_INVALID_PARAMETER;
1101
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001102 if (!strcmp(dev, "Mem") || !strcmp(dev, "hostfs")) {
Heinrich Schuchardtaecb9e22023-05-12 20:18:10 +02001103 /* loadm command and semihosting */
Rui Miguel Silva433f15a2022-05-11 10:55:40 +01001104 efi_get_image_parameters(&image_addr, &image_size);
1105
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001106 dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
1107 (uintptr_t)image_addr, image_size);
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001108 } else if (IS_ENABLED(CONFIG_NETDEVICES) && !strcmp(dev, "Net")) {
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001109 dp = efi_dp_from_eth();
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001110 } else if (!strcmp(dev, "Uart")) {
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001111 dp = efi_dp_from_uart();
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +01001112 } else {
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001113 part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1114 1);
Patrick Delaunayba7a9502019-04-10 11:02:58 +02001115 if (part < 0 || !desc)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001116 return EFI_INVALID_PARAMETER;
1117
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001118 dp = efi_dp_from_part(desc, part);
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001119 }
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001120 if (device)
1121 *device = dp;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001122
1123 if (!path)
1124 return EFI_SUCCESS;
1125
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +02001126 *file = efi_dp_from_file(dp, path);
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001127 if (!*file)
Heinrich Schuchardtbf0b3a12023-05-13 10:22:21 +02001128 return EFI_OUT_OF_RESOURCES;
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +09001129
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001130 return EFI_SUCCESS;
1131}
Heinrich Schuchardt22c8e082020-08-23 10:49:46 +02001132
1133/**
1134 * efi_dp_check_length() - check length of a device path
1135 *
1136 * @dp: pointer to device path
1137 * @maxlen: maximum length of the device path
1138 * Return:
1139 * * length of the device path if it is less or equal @maxlen
1140 * * -1 if the device path is longer then @maxlen
1141 * * -1 if a device path node has a length of less than 4
1142 * * -EINVAL if maxlen exceeds SSIZE_MAX
1143 */
1144ssize_t efi_dp_check_length(const struct efi_device_path *dp,
1145 const size_t maxlen)
1146{
1147 ssize_t ret = 0;
1148 u16 len;
1149
1150 if (maxlen > SSIZE_MAX)
1151 return -EINVAL;
1152 for (;;) {
1153 len = dp->length;
1154 if (len < 4)
1155 return -1;
1156 ret += len;
1157 if (ret > maxlen)
1158 return -1;
1159 if (dp->type == DEVICE_PATH_TYPE_END &&
1160 dp->sub_type == DEVICE_PATH_SUB_TYPE_END)
1161 return ret;
1162 dp = (const struct efi_device_path *)((const u8 *)dp + len);
1163 }
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001164}
1165
1166/**
1167 * efi_dp_from_lo() - Get the instance of a VenMedia node in a
1168 * multi-instance device path that matches
1169 * a specific GUID. This kind of device paths
1170 * is found in Boot#### options describing an
1171 * initrd location
1172 *
1173 * @lo: EFI_LOAD_OPTION containing a valid device path
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001174 * @guid: guid to search for
1175 *
1176 * Return:
1177 * device path including the VenMedia node or NULL.
1178 * Caller must free the returned value.
1179 */
1180struct
1181efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
Heinrich Schuchardt9979cff2021-10-15 01:31:02 +02001182 const efi_guid_t *guid)
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001183{
1184 struct efi_device_path *fp = lo->file_path;
1185 struct efi_device_path_vendor *vendor;
1186 int lo_len = lo->file_path_length;
1187
1188 for (; lo_len >= sizeof(struct efi_device_path);
1189 lo_len -= fp->length, fp = (void *)fp + fp->length) {
1190 if (lo_len < 0 || efi_dp_check_length(fp, lo_len) < 0)
1191 break;
1192 if (fp->type != DEVICE_PATH_TYPE_MEDIA_DEVICE ||
1193 fp->sub_type != DEVICE_PATH_SUB_TYPE_VENDOR_PATH)
1194 continue;
1195
1196 vendor = (struct efi_device_path_vendor *)fp;
Heinrich Schuchardt9979cff2021-10-15 01:31:02 +02001197 if (!guidcmp(&vendor->guid, guid))
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +02001198 return efi_dp_dup(efi_dp_next(fp));
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001199 }
1200 log_debug("VenMedia(%pUl) not found in %ls\n", &guid, lo->label);
1201
1202 return NULL;
Heinrich Schuchardt22c8e082020-08-23 10:49:46 +02001203}
Masahisa Kojima6460c3e2021-10-26 17:27:25 +09001204
1205/**
1206 * search_gpt_dp_node() - search gpt device path node
1207 *
1208 * @device_path: device path
1209 *
1210 * Return: pointer to the gpt device path node
1211 */
1212struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path)
1213{
1214 struct efi_device_path *dp = device_path;
1215
1216 while (dp) {
1217 if (dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
1218 dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
1219 struct efi_device_path_hard_drive_path *hd_dp =
1220 (struct efi_device_path_hard_drive_path *)dp;
1221
1222 if (hd_dp->partmap_type == PART_FORMAT_GPT &&
1223 hd_dp->signature_type == SIG_TYPE_GUID)
1224 return dp;
1225 }
1226 dp = efi_dp_next(dp);
1227 }
1228
1229 return NULL;
1230}