blob: ed7214f3a347cac6963f3cb85349a40ba94ba737 [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{
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200551 enum uclass_id uclass_id;
552
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400553 if (!dev || !dev->driver)
554 return buf;
555
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200556 uclass_id = device_get_uclass_id(dev);
557 if (uclass_id != UCLASS_ROOT)
558 buf = dp_fill(buf, dev->parent);
559
560 switch (uclass_id) {
Jan Kiszkaf1389822022-10-14 18:10:06 +0200561#ifdef CONFIG_NETDEVICES
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100562 case UCLASS_ETH: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200563 struct efi_device_path_mac_addr *dp = buf;
Simon Glass95588622020-12-22 19:30:28 -0700564 struct eth_pdata *pdata = dev_get_plat(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100565
566 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
567 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
568 dp->dp.length = sizeof(*dp);
569 memset(&dp->mac, 0, sizeof(dp->mac));
570 /* We only support IPv4 */
571 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
572 /* Ethernet */
573 dp->if_type = 1;
574 return &dp[1];
575 }
576#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100577 case UCLASS_BLK:
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200578 switch (device_get_uclass_id(dev->parent)) {
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100579#ifdef CONFIG_IDE
580 case UCLASS_IDE: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200581 struct efi_device_path_atapi *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700582 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100583
584 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
585 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
586 dp->dp.length = sizeof(*dp);
587 dp->logical_unit_number = desc->devnum;
588 dp->primary_secondary = IDE_BUS(desc->devnum);
589 dp->slave_master = desc->devnum %
590 (CONFIG_SYS_IDE_MAXDEVICE /
591 CONFIG_SYS_IDE_MAXBUS);
592 return &dp[1];
593 }
594#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600595#if defined(CONFIG_SCSI)
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100596 case UCLASS_SCSI: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200597 struct efi_device_path_scsi *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700598 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100599
600 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
601 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
602 dp->dp.length = sizeof(*dp);
603 dp->logical_unit_number = desc->lun;
604 dp->target_id = desc->target;
605 return &dp[1];
606 }
607#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600608#if defined(CONFIG_MMC)
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100609 case UCLASS_MMC: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200610 struct efi_device_path_sd_mmc_path *sddp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700611 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100612
613 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
614 sddp->dp.sub_type = is_sd(desc) ?
615 DEVICE_PATH_SUB_TYPE_MSG_SD :
616 DEVICE_PATH_SUB_TYPE_MSG_MMC;
617 sddp->dp.length = sizeof(*sddp);
Simon Glass75e534b2020-12-16 21:20:07 -0700618 sddp->slot_number = dev_seq(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100619 return &sddp[1];
620 }
621#endif
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200622#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
623 case UCLASS_AHCI: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200624 struct efi_device_path_sata *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700625 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200626
627 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
628 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SATA;
629 dp->dp.length = sizeof(*dp);
630 dp->hba_port = desc->devnum;
631 /* default 0xffff implies no port multiplier */
632 dp->port_multiplier_port = 0xffff;
633 dp->logical_unit_number = desc->lun;
634 return &dp[1];
635 }
636#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200637#if defined(CONFIG_NVME)
638 case UCLASS_NVME: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200639 struct efi_device_path_nvme *dp = buf;
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200640 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 Schuchardt3d347632023-07-21 08:34:18 +0200653 struct efi_device_path_controller *dp = buf;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100654
655 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
656 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CONTROLLER;
657 dp->dp.length = sizeof(*dp);
658 dp->controller_number = desc->lun;
659 return &dp[1];
660 }
661#endif
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200662 default: {
663 /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200664 struct efi_device_path_udevice *dp = buf;
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200665 struct blk_desc *desc = dev_get_uclass_plat(dev);
666
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200667 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
668 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
669 dp->dp.length = sizeof(*dp);
670 memcpy(&dp->guid, &efi_u_boot_guid,
671 sizeof(efi_guid_t));
672 dp->uclass_id = (UCLASS_BLK & 0xffff) |
673 (desc->uclass_id << 16);
674 dp->dev_number = desc->devnum;
675
676 return &dp[1];
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100677 }
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200678 }
Simon Glass222f3cb2021-09-24 18:30:17 -0600679#if defined(CONFIG_MMC)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400680 case UCLASS_MMC: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200681 struct efi_device_path_sd_mmc_path *sddp = buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400682 struct mmc *mmc = mmc_get_mmc_dev(dev);
683 struct blk_desc *desc = mmc_get_blk_desc(mmc);
684
685 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +0100686 sddp->dp.sub_type = is_sd(desc) ?
687 DEVICE_PATH_SUB_TYPE_MSG_SD :
688 DEVICE_PATH_SUB_TYPE_MSG_MMC;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400689 sddp->dp.length = sizeof(*sddp);
Simon Glass75e534b2020-12-16 21:20:07 -0700690 sddp->slot_number = dev_seq(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400691
692 return &sddp[1];
693 }
694#endif
695 case UCLASS_MASS_STORAGE:
696 case UCLASS_USB_HUB: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200697 struct efi_device_path_usb *udp = buf;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100698
699 switch (device_get_uclass_id(dev->parent)) {
700 case UCLASS_USB_HUB: {
701 struct usb_device *udev = dev_get_parent_priv(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400702
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100703 udp->parent_port_number = udev->portnr;
704 break;
705 }
706 default:
707 udp->parent_port_number = 0;
708 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400709 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100710 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400711 udp->dp.length = sizeof(*udp);
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100712 udp->usb_interface = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400713
714 return &udp[1];
715 }
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200716 default: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200717 struct efi_device_path_udevice *vdp = buf;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200718
719 vdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
720 vdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
721 vdp->dp.length = sizeof(*vdp);
722 memcpy(&vdp->guid, &efi_u_boot_guid, sizeof(efi_guid_t));
723 vdp->uclass_id = uclass_id;
724 vdp->dev_number = dev->seq_;
725
726 return &vdp[1];
727 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400728 }
729}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400730
731static unsigned dp_part_size(struct blk_desc *desc, int part)
732{
733 unsigned dpsize;
Simon Glassec209a72022-01-29 14:58:39 -0700734 struct udevice *dev = desc->bdev;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400735
Simon Glass222f3cb2021-09-24 18:30:17 -0600736 dpsize = dp_size(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400737
738 if (part == 0) /* the actual disk, not a partition */
739 return dpsize;
740
741 if (desc->part_type == PART_TYPE_ISO)
742 dpsize += sizeof(struct efi_device_path_cdrom_path);
743 else
744 dpsize += sizeof(struct efi_device_path_hard_drive_path);
745
746 return dpsize;
747}
748
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100749/*
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100750 * Create a device node for a block device partition.
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100751 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200752 * @buf buffer to which the device path is written
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100753 * @desc block device descriptor
754 * @part partition number, 0 identifies a block device
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200755 *
756 * Return: pointer to position after the node
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100757 */
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100758static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400759{
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600760 struct disk_partition info;
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200761 int ret;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400762
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200763 ret = part_get_info(desc, part, &info);
764 if (ret < 0)
765 return buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400766
767 if (desc->part_type == PART_TYPE_ISO) {
768 struct efi_device_path_cdrom_path *cddp = buf;
769
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100770 cddp->boot_entry = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400771 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
772 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
773 cddp->dp.length = sizeof(*cddp);
774 cddp->partition_start = info.start;
Heinrich Schuchardt28dfd1a2019-09-04 13:56:01 +0200775 cddp->partition_size = info.size;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400776
777 buf = &cddp[1];
778 } else {
779 struct efi_device_path_hard_drive_path *hddp = buf;
780
781 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
782 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
783 hddp->dp.length = sizeof(*hddp);
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100784 hddp->partition_number = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400785 hddp->partition_start = info.start;
786 hddp->partition_end = info.size;
787 if (desc->part_type == PART_TYPE_EFI)
788 hddp->partmap_type = 2;
789 else
790 hddp->partmap_type = 1;
Jonathan Gray84b4d702017-11-22 14:18:59 +1100791
792 switch (desc->sig_type) {
793 case SIG_TYPE_NONE:
794 default:
795 hddp->signature_type = 0;
796 memset(hddp->partition_signature, 0,
797 sizeof(hddp->partition_signature));
798 break;
799 case SIG_TYPE_MBR:
800 hddp->signature_type = 1;
801 memset(hddp->partition_signature, 0,
802 sizeof(hddp->partition_signature));
803 memcpy(hddp->partition_signature, &desc->mbr_sig,
804 sizeof(desc->mbr_sig));
805 break;
806 case SIG_TYPE_GUID:
807 hddp->signature_type = 2;
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900808#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
809 /* info.uuid exists only with PARTITION_UUIDS */
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200810 if (uuid_str_to_bin(info.uuid,
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900811 hddp->partition_signature,
812 UUID_STR_FORMAT_GUID)) {
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200813 log_warning(
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900814 "Partition %d: invalid GUID %s\n",
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200815 part, info.uuid);
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900816 }
817#endif
Jonathan Gray84b4d702017-11-22 14:18:59 +1100818 break;
819 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400820
821 buf = &hddp[1];
822 }
823
824 return buf;
825}
826
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100827/*
828 * Create a device path for a block device or one of its partitions.
829 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200830 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100831 * @desc block device descriptor
832 * @part partition number, 0 identifies a block device
833 */
834static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
835{
Simon Glassec209a72022-01-29 14:58:39 -0700836 struct udevice *dev = desc->bdev;
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100837
Simon Glass222f3cb2021-09-24 18:30:17 -0600838 buf = dp_fill(buf, dev);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100839
840 if (part == 0) /* the actual disk, not a partition */
841 return buf;
842
843 return dp_part_node(buf, desc, part);
844}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400845
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200846/* Construct a device-path from a partition on a block device: */
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400847struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
848{
849 void *buf, *start;
850
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100851 start = buf = efi_alloc(dp_part_size(desc, part) + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100852 if (!buf)
853 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400854
855 buf = dp_part_fill(buf, desc, part);
856
857 *((struct efi_device_path *)buf) = END;
858
859 return start;
860}
861
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100862/*
863 * Create a device node for a block device partition.
864 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200865 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100866 * @desc block device descriptor
867 * @part partition number, 0 identifies a block device
868 */
869struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
870{
871 efi_uintn_t dpsize;
872 void *buf;
873
874 if (desc->part_type == PART_TYPE_ISO)
875 dpsize = sizeof(struct efi_device_path_cdrom_path);
876 else
877 dpsize = sizeof(struct efi_device_path_hard_drive_path);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100878 buf = efi_alloc(dpsize);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100879
Heinrich Schuchardte29fbb32022-10-06 13:36:02 +0200880 if (buf)
881 dp_part_node(buf, desc, part);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100882
883 return buf;
884}
885
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200886/**
887 * path_to_uefi() - convert UTF-8 path to an UEFI style path
888 *
889 * Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
890 * separators and UTF-16).
891 *
892 * @src: source buffer
893 * @uefi: target buffer, possibly unaligned
894 */
895static void path_to_uefi(void *uefi, const char *src)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400896{
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200897 u16 *pos = uefi;
898
899 /*
900 * efi_set_bootdev() calls this routine indirectly before the UEFI
901 * subsystem is initialized. So we cannot assume unaligned access to be
902 * enabled.
903 */
904 allow_unaligned();
905
906 while (*src) {
907 s32 code = utf8_get(&src);
908
909 if (code < 0)
910 code = '?';
911 else if (code == '/')
912 code = '\\';
913 utf16_put(code, &pos);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400914 }
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200915 *pos = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400916}
917
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000918/**
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200919 * efi_dp_from_file() - append file path node to device path.
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000920 *
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200921 * @dp: device path or NULL
922 * @path: file path or NULL
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000923 * Return: device path or NULL in case of an error
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400924 */
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200925struct efi_device_path *efi_dp_from_file(const struct efi_device_path *dp,
926 const char *path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400927{
928 struct efi_device_path_file_path *fp;
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200929 void *buf, *pos;
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200930 size_t dpsize, fpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400931
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200932 dpsize = efi_dp_size(dp);
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200933 fpsize = sizeof(struct efi_device_path) +
934 2 * (utf8_utf16_strlen(path) + 1);
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +0900935 if (fpsize > U16_MAX)
936 return NULL;
937
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200938 buf = efi_alloc(dpsize + fpsize + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100939 if (!buf)
940 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400941
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200942 memcpy(buf, dp, dpsize);
943 pos = buf + dpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400944
945 /* add file-path: */
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000946 if (*path) {
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200947 fp = pos;
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000948 fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
949 fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
950 fp->dp.length = (u16)fpsize;
951 path_to_uefi(fp->str, path);
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200952 pos += fpsize;
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000953 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400954
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200955 memcpy(pos, &END, sizeof(END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400956
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200957 return buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400958}
959
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100960struct efi_device_path *efi_dp_from_uart(void)
961{
962 void *buf, *pos;
963 struct efi_device_path_uart *uart;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200964 size_t dpsize = dp_size(dm_root()) + sizeof(*uart) + sizeof(END);
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100965
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100966 buf = efi_alloc(dpsize);
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100967 if (!buf)
968 return NULL;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200969 pos = dp_fill(buf, dm_root());
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100970 uart = pos;
971 uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
972 uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART;
973 uart->dp.length = sizeof(*uart);
974 pos += sizeof(*uart);
975 memcpy(pos, &END, sizeof(END));
976
977 return buf;
978}
979
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +0200980struct efi_device_path __maybe_unused *efi_dp_from_eth(void)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400981{
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400982 void *buf, *start;
983 unsigned dpsize = 0;
984
985 assert(eth_get_dev());
986
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400987 dpsize += dp_size(eth_get_dev());
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400988
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100989 start = buf = efi_alloc(dpsize + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100990 if (!buf)
991 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400992
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400993 buf = dp_fill(buf, eth_get_dev());
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400994
995 *((struct efi_device_path *)buf) = END;
996
997 return start;
998}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400999
Rob Clark18ceba72017-10-10 08:23:06 -04001000/* Construct a device-path for memory-mapped image */
1001struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
1002 uint64_t start_address,
1003 uint64_t end_address)
1004{
1005 struct efi_device_path_memory *mdp;
1006 void *buf, *start;
1007
Heinrich Schuchardt45640252023-03-19 09:20:22 +01001008 start = buf = efi_alloc(sizeof(*mdp) + sizeof(END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001009 if (!buf)
1010 return NULL;
Rob Clark18ceba72017-10-10 08:23:06 -04001011
1012 mdp = buf;
1013 mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
1014 mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
1015 mdp->dp.length = sizeof(*mdp);
1016 mdp->memory_type = memory_type;
1017 mdp->start_address = start_address;
1018 mdp->end_address = end_address;
1019 buf = &mdp[1];
1020
1021 *((struct efi_device_path *)buf) = END;
1022
1023 return start;
1024}
1025
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +01001026/**
1027 * efi_dp_split_file_path() - split of relative file path from device path
1028 *
1029 * Given a device path indicating a file on a device, separate the device
1030 * path in two: the device path of the actual device and the file path
1031 * relative to this device.
1032 *
1033 * @full_path: device path including device and file path
1034 * @device_path: path of the device
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001035 * @file_path: relative path of the file or NULL if there is none
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +01001036 * Return: status code
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001037 */
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001038efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
1039 struct efi_device_path **device_path,
1040 struct efi_device_path **file_path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001041{
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001042 struct efi_device_path *p, *dp, *fp = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001043
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001044 *device_path = NULL;
1045 *file_path = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001046 dp = efi_dp_dup(full_path);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001047 if (!dp)
1048 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001049 p = dp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001050 while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001051 p = efi_dp_next(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001052 if (!p)
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001053 goto out;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001054 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001055 fp = efi_dp_dup(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001056 if (!fp)
1057 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001058 p->type = DEVICE_PATH_TYPE_END;
1059 p->sub_type = DEVICE_PATH_SUB_TYPE_END;
1060 p->length = sizeof(*p);
1061
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001062out:
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001063 *device_path = dp;
1064 *file_path = fp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001065 return EFI_SUCCESS;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001066}
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001067
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001068/**
1069 * efi_dp_from_name() - convert U-Boot device and file path to device path
1070 *
1071 * @dev: U-Boot device, e.g. 'mmc'
1072 * @devnr: U-Boot device number, e.g. 1 for 'mmc:1'
1073 * @path: file path relative to U-Boot device, may be NULL
1074 * @device: pointer to receive device path of the device
1075 * @file: pointer to receive device path for the file
1076 * Return: status code
1077 */
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001078efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
1079 const char *path,
1080 struct efi_device_path **device,
1081 struct efi_device_path **file)
1082{
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001083 struct blk_desc *desc = NULL;
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001084 struct efi_device_path *dp;
Simon Glassc1c4a8f2020-05-10 11:39:57 -06001085 struct disk_partition fs_partition;
Rui Miguel Silva433f15a2022-05-11 10:55:40 +01001086 size_t image_size;
1087 void *image_addr;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001088 int part = 0;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001089
AKASHI Takahiro39844412018-11-05 18:06:40 +09001090 if (path && !file)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001091 return EFI_INVALID_PARAMETER;
1092
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001093 if (!strcmp(dev, "Mem") || !strcmp(dev, "hostfs")) {
Heinrich Schuchardtaecb9e22023-05-12 20:18:10 +02001094 /* loadm command and semihosting */
Rui Miguel Silva433f15a2022-05-11 10:55:40 +01001095 efi_get_image_parameters(&image_addr, &image_size);
1096
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001097 dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
1098 (uintptr_t)image_addr, image_size);
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001099 } else if (IS_ENABLED(CONFIG_NETDEVICES) && !strcmp(dev, "Net")) {
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001100 dp = efi_dp_from_eth();
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001101 } else if (!strcmp(dev, "Uart")) {
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001102 dp = efi_dp_from_uart();
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +01001103 } else {
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001104 part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1105 1);
Patrick Delaunayba7a9502019-04-10 11:02:58 +02001106 if (part < 0 || !desc)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001107 return EFI_INVALID_PARAMETER;
1108
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001109 dp = efi_dp_from_part(desc, part);
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001110 }
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001111 if (device)
1112 *device = dp;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001113
1114 if (!path)
1115 return EFI_SUCCESS;
1116
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +02001117 *file = efi_dp_from_file(dp, path);
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001118 if (!*file)
Heinrich Schuchardtbf0b3a12023-05-13 10:22:21 +02001119 return EFI_OUT_OF_RESOURCES;
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +09001120
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001121 return EFI_SUCCESS;
1122}
Heinrich Schuchardt22c8e082020-08-23 10:49:46 +02001123
1124/**
1125 * efi_dp_check_length() - check length of a device path
1126 *
1127 * @dp: pointer to device path
1128 * @maxlen: maximum length of the device path
1129 * Return:
1130 * * length of the device path if it is less or equal @maxlen
1131 * * -1 if the device path is longer then @maxlen
1132 * * -1 if a device path node has a length of less than 4
1133 * * -EINVAL if maxlen exceeds SSIZE_MAX
1134 */
1135ssize_t efi_dp_check_length(const struct efi_device_path *dp,
1136 const size_t maxlen)
1137{
1138 ssize_t ret = 0;
1139 u16 len;
1140
1141 if (maxlen > SSIZE_MAX)
1142 return -EINVAL;
1143 for (;;) {
1144 len = dp->length;
1145 if (len < 4)
1146 return -1;
1147 ret += len;
1148 if (ret > maxlen)
1149 return -1;
1150 if (dp->type == DEVICE_PATH_TYPE_END &&
1151 dp->sub_type == DEVICE_PATH_SUB_TYPE_END)
1152 return ret;
1153 dp = (const struct efi_device_path *)((const u8 *)dp + len);
1154 }
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001155}
1156
1157/**
1158 * efi_dp_from_lo() - Get the instance of a VenMedia node in a
1159 * multi-instance device path that matches
1160 * a specific GUID. This kind of device paths
1161 * is found in Boot#### options describing an
1162 * initrd location
1163 *
1164 * @lo: EFI_LOAD_OPTION containing a valid device path
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001165 * @guid: guid to search for
1166 *
1167 * Return:
1168 * device path including the VenMedia node or NULL.
1169 * Caller must free the returned value.
1170 */
1171struct
1172efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
Heinrich Schuchardt9979cff2021-10-15 01:31:02 +02001173 const efi_guid_t *guid)
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001174{
1175 struct efi_device_path *fp = lo->file_path;
1176 struct efi_device_path_vendor *vendor;
1177 int lo_len = lo->file_path_length;
1178
1179 for (; lo_len >= sizeof(struct efi_device_path);
1180 lo_len -= fp->length, fp = (void *)fp + fp->length) {
1181 if (lo_len < 0 || efi_dp_check_length(fp, lo_len) < 0)
1182 break;
1183 if (fp->type != DEVICE_PATH_TYPE_MEDIA_DEVICE ||
1184 fp->sub_type != DEVICE_PATH_SUB_TYPE_VENDOR_PATH)
1185 continue;
1186
1187 vendor = (struct efi_device_path_vendor *)fp;
Heinrich Schuchardt9979cff2021-10-15 01:31:02 +02001188 if (!guidcmp(&vendor->guid, guid))
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +02001189 return efi_dp_dup(efi_dp_next(fp));
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001190 }
1191 log_debug("VenMedia(%pUl) not found in %ls\n", &guid, lo->label);
1192
1193 return NULL;
Heinrich Schuchardt22c8e082020-08-23 10:49:46 +02001194}
Masahisa Kojima6460c3e2021-10-26 17:27:25 +09001195
1196/**
1197 * search_gpt_dp_node() - search gpt device path node
1198 *
1199 * @device_path: device path
1200 *
1201 * Return: pointer to the gpt device path node
1202 */
1203struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path)
1204{
1205 struct efi_device_path *dp = device_path;
1206
1207 while (dp) {
1208 if (dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
1209 dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
1210 struct efi_device_path_hard_drive_path *hd_dp =
1211 (struct efi_device_path_hard_drive_path *)dp;
1212
1213 if (hd_dp->partmap_type == PART_FORMAT_GPT &&
1214 hd_dp->signature_type == SIG_TYPE_GUID)
1215 return dp;
1216 }
1217 dp = efi_dp_next(dp);
1218 }
1219
1220 return NULL;
1221}