blob: b3fb20b2501ec68f68063eab71eb8bde56f7a9f4 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Rob Clarkf90cb9f2017-09-13 18:05:28 -04002/*
3 * EFI device path from u-boot device-model mapping
4 *
5 * (C) Copyright 2017 Rob Clark
Rob Clarkf90cb9f2017-09-13 18:05:28 -04006 */
7
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +02008#define LOG_CATEGORY LOGC_EFI
9
Rob Clarkf90cb9f2017-09-13 18:05:28 -040010#include <blk.h>
11#include <dm.h>
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +020012#include <dm/root.h>
Simon Glass37972f42025-05-24 11:28:21 -060013#include <efi_device_path.h>
Tom Riniefa387d2025-05-21 16:51:19 -060014#include <ide.h>
Simon Glass0f2af882020-05-10 11:40:05 -060015#include <log.h>
Simon Glass274e0b02020-05-10 11:39:56 -060016#include <net.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040017#include <usb.h>
18#include <mmc.h>
Patrick Wildta3ca37e2019-10-03 16:24:17 +020019#include <nvme.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040020#include <efi_loader.h>
Rob Clarkf90cb9f2017-09-13 18:05:28 -040021#include <part.h>
Caleb Connolly29cab7c2024-08-30 13:34:37 +010022#include <u-boot/uuid.h>
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +020023#include <asm-generic/unaligned.h>
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +090024#include <linux/compat.h> /* U16_MAX */
Rob Clarkf90cb9f2017-09-13 18:05:28 -040025
Simon Glassc88552c2025-05-24 11:28:23 -060026/* template EFI_DP_END node: */
27const struct efi_device_path EFI_DP_END = {
Rob Clarkf90cb9f2017-09-13 18:05:28 -040028 .type = DEVICE_PATH_TYPE_END,
29 .sub_type = DEVICE_PATH_SUB_TYPE_END,
Simon Glassc88552c2025-05-24 11:28:23 -060030 .length = sizeof(EFI_DP_END),
Rob Clarkf90cb9f2017-09-13 18:05:28 -040031};
32
Simon Glass222f3cb2021-09-24 18:30:17 -060033#if defined(CONFIG_MMC)
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +010034/*
35 * Determine if an MMC device is an SD card.
36 *
37 * @desc block device descriptor
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010038 * Return: true if the device is an SD card
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +010039 */
40static bool is_sd(struct blk_desc *desc)
41{
42 struct mmc *mmc = find_mmc_device(desc->devnum);
43
44 if (!mmc)
45 return false;
46
47 return IS_SD(mmc) != 0U;
48}
49#endif
50
Rob Clarkf90cb9f2017-09-13 18:05:28 -040051struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
52{
53 if (dp == NULL)
54 return NULL;
55 if (dp->type == DEVICE_PATH_TYPE_END)
56 return NULL;
57 dp = ((void *)dp) + dp->length;
58 if (dp->type == DEVICE_PATH_TYPE_END)
59 return NULL;
60 return (struct efi_device_path *)dp;
61}
62
Heinrich Schuchardt753e2482017-10-26 19:25:48 +020063int efi_dp_match(const struct efi_device_path *a,
64 const struct efi_device_path *b)
Rob Clarkf90cb9f2017-09-13 18:05:28 -040065{
66 while (1) {
67 int ret;
68
69 ret = memcmp(&a->length, &b->length, sizeof(a->length));
70 if (ret)
71 return ret;
72
73 ret = memcmp(a, b, a->length);
74 if (ret)
75 return ret;
76
77 a = efi_dp_next(a);
78 b = efi_dp_next(b);
79
80 if (!a || !b)
81 return 0;
82 }
83}
84
Heinrich Schuchardt24f0e6a2022-02-26 12:10:10 +010085struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
Rob Clarkf90cb9f2017-09-13 18:05:28 -040086{
87 while (dp) {
Heinrich Schuchardta7ffd902023-03-26 12:22:40 +020088 if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_WWI) ||
Rob Clarkf90cb9f2017-09-13 18:05:28 -040089 EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
90 EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
91 return dp;
92
93 dp = efi_dp_next(dp);
94 }
95
96 return dp;
97}
98
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +010099/**
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100100 * find_handle() - find handle by device path and installed protocol
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100101 *
102 * If @rem is provided, the handle with the longest partial match is returned.
103 *
104 * @dp: device path to search
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100105 * @guid: GUID of protocol that must be installed on path or NULL
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100106 * @short_path: use short form device path for matching
107 * @rem: pointer to receive remaining device path
108 * Return: matching handle
109 */
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100110static efi_handle_t find_handle(struct efi_device_path *dp,
111 const efi_guid_t *guid, bool short_path,
112 struct efi_device_path **rem)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400113{
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100114 efi_handle_t handle, best_handle = NULL;
115 efi_uintn_t len, best_len = 0;
116
117 len = efi_dp_instance_size(dp);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400118
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100119 list_for_each_entry(handle, &efi_obj_list, link) {
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100120 struct efi_handler *handler;
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100121 struct efi_device_path *dp_current;
122 efi_uintn_t len_current;
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100123 efi_status_t ret;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400124
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100125 if (guid) {
126 ret = efi_search_protocol(handle, guid, &handler);
127 if (ret != EFI_SUCCESS)
128 continue;
129 }
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100130 ret = efi_search_protocol(handle, &efi_guid_device_path,
131 &handler);
Heinrich Schuchardt6953c102017-11-26 14:05:16 +0100132 if (ret != EFI_SUCCESS)
133 continue;
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100134 dp_current = handler->protocol_interface;
135 if (short_path) {
136 dp_current = efi_dp_shorten(dp_current);
137 if (!dp_current)
138 continue;
139 }
140 len_current = efi_dp_instance_size(dp_current);
141 if (rem) {
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100142 if (len_current > len)
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100143 continue;
144 } else {
145 if (len_current != len)
146 continue;
147 }
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100148 if (memcmp(dp_current, dp, len_current))
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100149 continue;
150 if (!rem)
151 return handle;
152 if (len_current > best_len) {
153 best_len = len_current;
154 best_handle = handle;
155 *rem = (void*)((u8 *)dp + len_current);
156 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400157 }
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100158 return best_handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400159}
160
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100161efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100162 const efi_guid_t *guid,
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100163 struct efi_device_path **rem)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400164{
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100165 efi_handle_t handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400166
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100167 handle = find_handle(dp, guid, false, rem);
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100168 if (!handle)
169 /* Match short form device path */
Heinrich Schuchardt0a04a412022-03-19 06:35:43 +0100170 handle = find_handle(dp, guid, true, rem);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400171
Heinrich Schuchardtad6d5a42022-03-04 08:20:00 +0100172 return handle;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400173}
174
Heinrich Schuchardt0976f8b2018-01-19 20:24:49 +0100175const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
176{
177 struct efi_device_path *ret;
178
179 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
180 return NULL;
181 while (dp) {
182 ret = (struct efi_device_path *)dp;
183 dp = efi_dp_next(dp);
184 }
185 return ret;
186}
187
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200188efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400189{
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200190 efi_uintn_t sz = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400191
Heinrich Schuchardt01d48ed2018-04-16 07:59:07 +0200192 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
193 return 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400194 while (dp) {
195 sz += dp->length;
196 dp = efi_dp_next(dp);
197 }
198
199 return sz;
200}
201
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200202efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
203{
204 const struct efi_device_path *p = dp;
205
206 if (!p)
207 return 0;
208 while (p->type != DEVICE_PATH_TYPE_END ||
209 p->sub_type != DEVICE_PATH_SUB_TYPE_END)
210 p = (void *)p + p->length;
211
212 return (void *)p - (void *)dp;
213}
214
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400215struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
216{
217 struct efi_device_path *ndp;
Simon Glassc88552c2025-05-24 11:28:23 -0600218 size_t sz = efi_dp_size(dp) + sizeof(EFI_DP_END);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400219
220 if (!dp)
221 return NULL;
222
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100223 ndp = efi_alloc(sz);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100224 if (!ndp)
225 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400226 memcpy(ndp, dp, sz);
227
228 return ndp;
229}
230
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200231struct
232efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
233 const struct efi_device_path *dp2,
Heinrich Schuchardtf8de0092024-05-24 14:54:26 +0200234 size_t split_end_node)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400235{
236 struct efi_device_path *ret;
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200237 size_t end_size;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400238
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200239 if (!dp1 && !dp2) {
240 /* return an end node */
Simon Glassc88552c2025-05-24 11:28:23 -0600241 ret = efi_dp_dup(&EFI_DP_END);
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200242 } else if (!dp1) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400243 ret = efi_dp_dup(dp2);
244 } else if (!dp2) {
245 ret = efi_dp_dup(dp1);
246 } else {
247 /* both dp1 and dp2 are non-null */
Heinrich Schuchardtf8de0092024-05-24 14:54:26 +0200248 size_t sz1;
249 size_t sz2 = efi_dp_size(dp2);
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200250 void *p;
251
Heinrich Schuchardtf8de0092024-05-24 14:54:26 +0200252 if (split_end_node < sizeof(struct efi_device_path))
253 sz1 = efi_dp_size(dp1);
254 else
255 sz1 = split_end_node;
256
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200257 if (split_end_node)
Simon Glassc88552c2025-05-24 11:28:23 -0600258 end_size = 2 * sizeof(EFI_DP_END);
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200259 else
Simon Glassc88552c2025-05-24 11:28:23 -0600260 end_size = sizeof(EFI_DP_END);
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200261 p = efi_alloc(sz1 + sz2 + end_size);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100262 if (!p)
263 return NULL;
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200264 ret = p;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400265 memcpy(p, dp1, sz1);
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200266 p += sz1;
267
Ilias Apalodimas5dcefa72024-01-08 10:55:33 +0200268 if (split_end_node) {
Simon Glassc88552c2025-05-24 11:28:23 -0600269 memcpy(p, &EFI_DP_END, sizeof(EFI_DP_END));
270 p += sizeof(EFI_DP_END);
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200271 }
272
Heinrich Schuchardt60b5ab22018-04-16 07:59:06 +0200273 /* the end node of the second device path has to be retained */
Ilias Apalodimas483d28e2021-03-17 21:54:58 +0200274 memcpy(p, dp2, sz2);
275 p += sz2;
Simon Glassc88552c2025-05-24 11:28:23 -0600276 memcpy(p, &EFI_DP_END, sizeof(EFI_DP_END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400277 }
278
279 return ret;
280}
281
282struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
283 const struct efi_device_path *node)
284{
285 struct efi_device_path *ret;
286
287 if (!node && !dp) {
Simon Glassc88552c2025-05-24 11:28:23 -0600288 ret = efi_dp_dup(&EFI_DP_END);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400289 } else if (!node) {
290 ret = efi_dp_dup(dp);
291 } else if (!dp) {
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200292 size_t sz = node->length;
Simon Glassc88552c2025-05-24 11:28:23 -0600293 void *p = efi_alloc(sz + sizeof(EFI_DP_END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100294 if (!p)
295 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400296 memcpy(p, node, sz);
Simon Glassc88552c2025-05-24 11:28:23 -0600297 memcpy(p + sz, &EFI_DP_END, sizeof(EFI_DP_END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400298 ret = p;
299 } else {
300 /* both dp and node are non-null */
Heinrich Schuchardt51ca4f52018-04-16 07:59:08 +0200301 size_t sz = efi_dp_size(dp);
Simon Glassc88552c2025-05-24 11:28:23 -0600302 void *p = efi_alloc(sz + node->length + sizeof(EFI_DP_END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100303 if (!p)
304 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400305 memcpy(p, dp, sz);
306 memcpy(p + sz, node, node->length);
Simon Glassc88552c2025-05-24 11:28:23 -0600307 memcpy(p + sz + node->length, &EFI_DP_END, sizeof(EFI_DP_END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400308 ret = p;
309 }
310
311 return ret;
312}
313
Heinrich Schuchardtb41c8e22018-04-16 07:59:05 +0200314struct efi_device_path *efi_dp_create_device_node(const u8 type,
315 const u8 sub_type,
316 const u16 length)
317{
318 struct efi_device_path *ret;
319
Heinrich Schuchardtc96c5942019-04-23 00:51:01 +0200320 if (length < sizeof(struct efi_device_path))
321 return NULL;
322
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100323 ret = efi_alloc(length);
Heinrich Schuchardtb41c8e22018-04-16 07:59:05 +0200324 if (!ret)
325 return ret;
326 ret->type = type;
327 ret->sub_type = sub_type;
328 ret->length = length;
329 return ret;
330}
331
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200332struct efi_device_path *efi_dp_append_instance(
333 const struct efi_device_path *dp,
334 const struct efi_device_path *dpi)
335{
336 size_t sz, szi;
337 struct efi_device_path *p, *ret;
338
339 if (!dpi)
340 return NULL;
341 if (!dp)
342 return efi_dp_dup(dpi);
343 sz = efi_dp_size(dp);
344 szi = efi_dp_instance_size(dpi);
Simon Glassc88552c2025-05-24 11:28:23 -0600345 p = efi_alloc(sz + szi + 2 * sizeof(EFI_DP_END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200346 if (!p)
347 return NULL;
348 ret = p;
Simon Glassc88552c2025-05-24 11:28:23 -0600349 memcpy(p, dp, sz + sizeof(EFI_DP_END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200350 p = (void *)p + sz;
351 p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
Simon Glassc88552c2025-05-24 11:28:23 -0600352 p = (void *)p + sizeof(EFI_DP_END);
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200353 memcpy(p, dpi, szi);
354 p = (void *)p + szi;
Simon Glassc88552c2025-05-24 11:28:23 -0600355 memcpy(p, &EFI_DP_END, sizeof(EFI_DP_END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200356 return ret;
357}
358
359struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
360 efi_uintn_t *size)
361{
362 size_t sz;
363 struct efi_device_path *p;
364
365 if (size)
366 *size = 0;
367 if (!dp || !*dp)
368 return NULL;
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200369 sz = efi_dp_instance_size(*dp);
Simon Glassc88552c2025-05-24 11:28:23 -0600370 p = efi_alloc(sz + sizeof(EFI_DP_END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200371 if (!p)
372 return NULL;
Simon Glassc88552c2025-05-24 11:28:23 -0600373 memcpy(p, *dp, sz + sizeof(EFI_DP_END));
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200374 *dp = (void *)*dp + sz;
375 if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
Simon Glassc88552c2025-05-24 11:28:23 -0600376 *dp = (void *)*dp + sizeof(EFI_DP_END);
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200377 else
378 *dp = NULL;
379 if (size)
Simon Glassc88552c2025-05-24 11:28:23 -0600380 *size = sz + sizeof(EFI_DP_END);
Heinrich Schuchardtcb0f7ce2018-04-16 07:59:09 +0200381 return p;
382}
383
384bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
385{
386 const struct efi_device_path *p = dp;
387
388 if (!p)
389 return false;
390 while (p->type != DEVICE_PATH_TYPE_END)
391 p = (void *)p + p->length;
392 return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
393}
394
Heinrich Schuchardtc22d9e32019-11-10 02:16:33 +0100395__maybe_unused static unsigned int dp_size(struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400396{
397 if (!dev || !dev->driver)
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200398 return sizeof(struct efi_device_path_udevice);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400399
Simon Glass56ada7b2022-01-29 14:58:38 -0700400 switch (device_get_uclass_id(dev)) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400401 case UCLASS_ROOT:
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400402 /* stop traversing parents at this point: */
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200403 return sizeof(struct efi_device_path_udevice);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100404 case UCLASS_ETH:
405 return dp_size(dev->parent) +
406 sizeof(struct efi_device_path_mac_addr);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100407 case UCLASS_BLK:
408 switch (dev->parent->uclass->uc_drv->id) {
409#ifdef CONFIG_IDE
410 case UCLASS_IDE:
411 return dp_size(dev->parent) +
412 sizeof(struct efi_device_path_atapi);
413#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600414#if defined(CONFIG_SCSI)
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100415 case UCLASS_SCSI:
416 return dp_size(dev->parent) +
417 sizeof(struct efi_device_path_scsi);
418#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600419#if defined(CONFIG_MMC)
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100420 case UCLASS_MMC:
421 return dp_size(dev->parent) +
422 sizeof(struct efi_device_path_sd_mmc_path);
423#endif
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200424#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
425 case UCLASS_AHCI:
426 return dp_size(dev->parent) +
427 sizeof(struct efi_device_path_sata);
428#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200429#if defined(CONFIG_NVME)
430 case UCLASS_NVME:
431 return dp_size(dev->parent) +
432 sizeof(struct efi_device_path_nvme);
433#endif
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100434#ifdef CONFIG_USB
435 case UCLASS_MASS_STORAGE:
436 return dp_size(dev->parent)
437 + sizeof(struct efi_device_path_controller);
438#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100439 default:
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200440 /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
441 return dp_size(dev->parent) +
442 sizeof(struct efi_device_path_udevice);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100443 }
Simon Glass222f3cb2021-09-24 18:30:17 -0600444#if defined(CONFIG_MMC)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400445 case UCLASS_MMC:
446 return dp_size(dev->parent) +
447 sizeof(struct efi_device_path_sd_mmc_path);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100448#endif
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400449 case UCLASS_MASS_STORAGE:
450 case UCLASS_USB_HUB:
451 return dp_size(dev->parent) +
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100452 sizeof(struct efi_device_path_usb);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400453 default:
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200454 return dp_size(dev->parent) +
455 sizeof(struct efi_device_path_udevice);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400456 }
457}
458
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100459/*
460 * Recursively build a device path.
461 *
462 * @buf pointer to the end of the device path
463 * @dev device
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100464 * Return: pointer to the end of the device path
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100465 */
Heinrich Schuchardtc22d9e32019-11-10 02:16:33 +0100466__maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400467{
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200468 enum uclass_id uclass_id;
469
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400470 if (!dev || !dev->driver)
471 return buf;
472
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200473 uclass_id = device_get_uclass_id(dev);
474 if (uclass_id != UCLASS_ROOT)
475 buf = dp_fill(buf, dev->parent);
476
477 switch (uclass_id) {
Jan Kiszkaf1389822022-10-14 18:10:06 +0200478#ifdef CONFIG_NETDEVICES
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100479 case UCLASS_ETH: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200480 struct efi_device_path_mac_addr *dp = buf;
Simon Glass95588622020-12-22 19:30:28 -0700481 struct eth_pdata *pdata = dev_get_plat(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100482
483 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
484 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
485 dp->dp.length = sizeof(*dp);
486 memset(&dp->mac, 0, sizeof(dp->mac));
487 /* We only support IPv4 */
488 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
489 /* Ethernet */
490 dp->if_type = 1;
491 return &dp[1];
492 }
493#endif
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100494 case UCLASS_BLK:
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200495 switch (device_get_uclass_id(dev->parent)) {
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100496#ifdef CONFIG_IDE
497 case UCLASS_IDE: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200498 struct efi_device_path_atapi *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700499 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100500
501 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
502 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
503 dp->dp.length = sizeof(*dp);
504 dp->logical_unit_number = desc->devnum;
505 dp->primary_secondary = IDE_BUS(desc->devnum);
506 dp->slave_master = desc->devnum %
507 (CONFIG_SYS_IDE_MAXDEVICE /
508 CONFIG_SYS_IDE_MAXBUS);
509 return &dp[1];
510 }
511#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600512#if defined(CONFIG_SCSI)
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100513 case UCLASS_SCSI: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200514 struct efi_device_path_scsi *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700515 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100516
517 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
518 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
519 dp->dp.length = sizeof(*dp);
520 dp->logical_unit_number = desc->lun;
521 dp->target_id = desc->target;
522 return &dp[1];
523 }
524#endif
Simon Glass222f3cb2021-09-24 18:30:17 -0600525#if defined(CONFIG_MMC)
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100526 case UCLASS_MMC: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200527 struct efi_device_path_sd_mmc_path *sddp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700528 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100529
530 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
531 sddp->dp.sub_type = is_sd(desc) ?
532 DEVICE_PATH_SUB_TYPE_MSG_SD :
533 DEVICE_PATH_SUB_TYPE_MSG_MMC;
534 sddp->dp.length = sizeof(*sddp);
Simon Glass75e534b2020-12-16 21:20:07 -0700535 sddp->slot_number = dev_seq(dev);
Heinrich Schuchardt1f1d49d2018-01-20 21:02:18 +0100536 return &sddp[1];
537 }
538#endif
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200539#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
540 case UCLASS_AHCI: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200541 struct efi_device_path_sata *dp = buf;
Simon Glass71fa5b42020-12-03 16:55:18 -0700542 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt7bdb6022020-05-20 23:12:02 +0200543
544 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
545 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SATA;
546 dp->dp.length = sizeof(*dp);
547 dp->hba_port = desc->devnum;
548 /* default 0xffff implies no port multiplier */
549 dp->port_multiplier_port = 0xffff;
550 dp->logical_unit_number = desc->lun;
551 return &dp[1];
552 }
553#endif
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200554#if defined(CONFIG_NVME)
555 case UCLASS_NVME: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200556 struct efi_device_path_nvme *dp = buf;
Patrick Wildta3ca37e2019-10-03 16:24:17 +0200557 u32 ns_id;
558
559 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
560 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_NVME;
561 dp->dp.length = sizeof(*dp);
562 nvme_get_namespace_id(dev, &ns_id, dp->eui64);
563 memcpy(&dp->ns_id, &ns_id, sizeof(ns_id));
564 return &dp[1];
565 }
566#endif
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100567#if defined(CONFIG_USB)
568 case UCLASS_MASS_STORAGE: {
Heinrich Schuchardt232c9db2023-04-01 07:21:55 +0200569 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200570 struct efi_device_path_controller *dp = buf;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100571
572 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
573 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CONTROLLER;
574 dp->dp.length = sizeof(*dp);
575 dp->controller_number = desc->lun;
576 return &dp[1];
577 }
578#endif
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200579 default: {
580 /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200581 struct efi_device_path_udevice *dp = buf;
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200582 struct blk_desc *desc = dev_get_uclass_plat(dev);
583
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200584 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
585 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
586 dp->dp.length = sizeof(*dp);
587 memcpy(&dp->guid, &efi_u_boot_guid,
588 sizeof(efi_guid_t));
589 dp->uclass_id = (UCLASS_BLK & 0xffff) |
590 (desc->uclass_id << 16);
591 dp->dev_number = desc->devnum;
592
593 return &dp[1];
Heinrich Schuchardte2dcb9a2017-12-11 12:56:44 +0100594 }
Heinrich Schuchardt8433a5d2023-07-21 00:03:46 +0200595 }
Simon Glass222f3cb2021-09-24 18:30:17 -0600596#if defined(CONFIG_MMC)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400597 case UCLASS_MMC: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200598 struct efi_device_path_sd_mmc_path *sddp = buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400599 struct mmc *mmc = mmc_get_mmc_dev(dev);
600 struct blk_desc *desc = mmc_get_blk_desc(mmc);
601
602 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt7d569db2017-12-11 12:56:39 +0100603 sddp->dp.sub_type = is_sd(desc) ?
604 DEVICE_PATH_SUB_TYPE_MSG_SD :
605 DEVICE_PATH_SUB_TYPE_MSG_MMC;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400606 sddp->dp.length = sizeof(*sddp);
Simon Glass75e534b2020-12-16 21:20:07 -0700607 sddp->slot_number = dev_seq(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400608
609 return &sddp[1];
610 }
611#endif
612 case UCLASS_MASS_STORAGE:
613 case UCLASS_USB_HUB: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200614 struct efi_device_path_usb *udp = buf;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100615
616 switch (device_get_uclass_id(dev->parent)) {
617 case UCLASS_USB_HUB: {
618 struct usb_device *udev = dev_get_parent_priv(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400619
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100620 udp->parent_port_number = udev->portnr;
621 break;
622 }
623 default:
624 udp->parent_port_number = 0;
625 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400626 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100627 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400628 udp->dp.length = sizeof(*udp);
Heinrich Schuchardt25b18d62023-03-19 16:18:09 +0100629 udp->usb_interface = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400630
631 return &udp[1];
632 }
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200633 default: {
Heinrich Schuchardt3d347632023-07-21 08:34:18 +0200634 struct efi_device_path_udevice *vdp = buf;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200635
636 vdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
637 vdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
638 vdp->dp.length = sizeof(*vdp);
639 memcpy(&vdp->guid, &efi_u_boot_guid, sizeof(efi_guid_t));
640 vdp->uclass_id = uclass_id;
641 vdp->dev_number = dev->seq_;
642
643 return &vdp[1];
644 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400645 }
646}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400647
648static unsigned dp_part_size(struct blk_desc *desc, int part)
649{
650 unsigned dpsize;
Simon Glassec209a72022-01-29 14:58:39 -0700651 struct udevice *dev = desc->bdev;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400652
Simon Glass222f3cb2021-09-24 18:30:17 -0600653 dpsize = dp_size(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400654
655 if (part == 0) /* the actual disk, not a partition */
656 return dpsize;
657
658 if (desc->part_type == PART_TYPE_ISO)
659 dpsize += sizeof(struct efi_device_path_cdrom_path);
660 else
661 dpsize += sizeof(struct efi_device_path_hard_drive_path);
662
663 return dpsize;
664}
665
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100666/*
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100667 * Create a device node for a block device partition.
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100668 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200669 * @buf buffer to which the device path is written
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100670 * @desc block device descriptor
671 * @part partition number, 0 identifies a block device
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200672 *
673 * Return: pointer to position after the node
Heinrich Schuchardt8983ffd2017-12-11 12:56:42 +0100674 */
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100675static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400676{
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600677 struct disk_partition info;
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200678 int ret;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400679
Heinrich Schuchardtee69ae12023-05-27 08:18:28 +0200680 ret = part_get_info(desc, part, &info);
681 if (ret < 0)
682 return buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400683
684 if (desc->part_type == PART_TYPE_ISO) {
685 struct efi_device_path_cdrom_path *cddp = buf;
686
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100687 cddp->boot_entry = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400688 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
689 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
690 cddp->dp.length = sizeof(*cddp);
691 cddp->partition_start = info.start;
Heinrich Schuchardt28dfd1a2019-09-04 13:56:01 +0200692 cddp->partition_size = info.size;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400693
694 buf = &cddp[1];
695 } else {
696 struct efi_device_path_hard_drive_path *hddp = buf;
697
698 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
699 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
700 hddp->dp.length = sizeof(*hddp);
Heinrich Schuchardt2aae6db2017-12-11 12:56:40 +0100701 hddp->partition_number = part;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400702 hddp->partition_start = info.start;
703 hddp->partition_end = info.size;
704 if (desc->part_type == PART_TYPE_EFI)
705 hddp->partmap_type = 2;
706 else
707 hddp->partmap_type = 1;
Jonathan Gray84b4d702017-11-22 14:18:59 +1100708
709 switch (desc->sig_type) {
710 case SIG_TYPE_NONE:
711 default:
712 hddp->signature_type = 0;
713 memset(hddp->partition_signature, 0,
714 sizeof(hddp->partition_signature));
715 break;
716 case SIG_TYPE_MBR:
717 hddp->signature_type = 1;
718 memset(hddp->partition_signature, 0,
719 sizeof(hddp->partition_signature));
720 memcpy(hddp->partition_signature, &desc->mbr_sig,
721 sizeof(desc->mbr_sig));
722 break;
723 case SIG_TYPE_GUID:
724 hddp->signature_type = 2;
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900725#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
726 /* info.uuid exists only with PARTITION_UUIDS */
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200727 if (uuid_str_to_bin(info.uuid,
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900728 hddp->partition_signature,
729 UUID_STR_FORMAT_GUID)) {
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200730 log_warning(
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900731 "Partition %d: invalid GUID %s\n",
Alfonso Sánchez-Beatof007a372021-07-15 15:31:42 +0200732 part, info.uuid);
AKASHI Takahiroae18a672022-04-19 10:01:56 +0900733 }
734#endif
Jonathan Gray84b4d702017-11-22 14:18:59 +1100735 break;
736 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400737
738 buf = &hddp[1];
739 }
740
741 return buf;
742}
743
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100744/*
745 * Create a device path for a block device or one of its partitions.
746 *
Heinrich Schuchardtb21f8392018-10-17 21:55:24 +0200747 * @buf buffer to which the device path is written
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100748 * @desc block device descriptor
749 * @part partition number, 0 identifies a block device
750 */
751static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
752{
Simon Glassec209a72022-01-29 14:58:39 -0700753 struct udevice *dev = desc->bdev;
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100754
Simon Glass222f3cb2021-09-24 18:30:17 -0600755 buf = dp_fill(buf, dev);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100756
757 if (part == 0) /* the actual disk, not a partition */
758 return buf;
759
760 return dp_part_node(buf, desc, part);
761}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400762
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400763struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
764{
765 void *buf, *start;
766
Simon Glassc88552c2025-05-24 11:28:23 -0600767 start = efi_alloc(dp_part_size(desc, part) + sizeof(EFI_DP_END));
768 if (!start)
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100769 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400770
Simon Glassc88552c2025-05-24 11:28:23 -0600771 buf = dp_part_fill(start, desc, part);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400772
Simon Glassc88552c2025-05-24 11:28:23 -0600773 *((struct efi_device_path *)buf) = EFI_DP_END;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400774
775 return start;
776}
777
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100778struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
779{
780 efi_uintn_t dpsize;
781 void *buf;
782
783 if (desc->part_type == PART_TYPE_ISO)
784 dpsize = sizeof(struct efi_device_path_cdrom_path);
785 else
786 dpsize = sizeof(struct efi_device_path_hard_drive_path);
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100787 buf = efi_alloc(dpsize);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100788
Heinrich Schuchardte29fbb32022-10-06 13:36:02 +0200789 if (buf)
790 dp_part_node(buf, desc, part);
Heinrich Schuchardt6c6307c2018-01-19 20:24:46 +0100791
792 return buf;
793}
794
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200795/**
796 * path_to_uefi() - convert UTF-8 path to an UEFI style path
797 *
798 * Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
799 * separators and UTF-16).
800 *
801 * @src: source buffer
802 * @uefi: target buffer, possibly unaligned
803 */
804static void path_to_uefi(void *uefi, const char *src)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400805{
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200806 u16 *pos = uefi;
807
808 /*
809 * efi_set_bootdev() calls this routine indirectly before the UEFI
810 * subsystem is initialized. So we cannot assume unaligned access to be
811 * enabled.
812 */
813 allow_unaligned();
814
815 while (*src) {
816 s32 code = utf8_get(&src);
817
818 if (code < 0)
819 code = '?';
820 else if (code == '/')
821 code = '\\';
822 utf16_put(code, &pos);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400823 }
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200824 *pos = 0;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400825}
826
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200827struct efi_device_path *efi_dp_from_file(const struct efi_device_path *dp,
828 const char *path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400829{
830 struct efi_device_path_file_path *fp;
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200831 void *buf, *pos;
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200832 size_t dpsize, fpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400833
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200834 dpsize = efi_dp_size(dp);
Heinrich Schuchardt8d80af82019-07-14 19:26:47 +0200835 fpsize = sizeof(struct efi_device_path) +
836 2 * (utf8_utf16_strlen(path) + 1);
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +0900837 if (fpsize > U16_MAX)
838 return NULL;
839
Simon Glassc88552c2025-05-24 11:28:23 -0600840 buf = efi_alloc(dpsize + fpsize + sizeof(EFI_DP_END));
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100841 if (!buf)
842 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400843
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +0200844 memcpy(buf, dp, dpsize);
845 pos = buf + dpsize;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400846
847 /* add file-path: */
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000848 if (*path) {
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200849 fp = pos;
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000850 fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
851 fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
852 fp->dp.length = (u16)fpsize;
853 path_to_uefi(fp->str, path);
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200854 pos += fpsize;
Heinrich Schuchardtf57eacb2022-06-11 05:22:08 +0000855 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400856
Simon Glassc88552c2025-05-24 11:28:23 -0600857 memcpy(pos, &EFI_DP_END, sizeof(EFI_DP_END));
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400858
Heinrich Schuchardt16eff692023-05-13 10:18:24 +0200859 return buf;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400860}
861
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100862struct efi_device_path *efi_dp_from_uart(void)
863{
864 void *buf, *pos;
865 struct efi_device_path_uart *uart;
Simon Glassc88552c2025-05-24 11:28:23 -0600866 size_t dpsize = dp_size(dm_root()) + sizeof(*uart) + sizeof(EFI_DP_END);
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100867
Heinrich Schuchardt45640252023-03-19 09:20:22 +0100868 buf = efi_alloc(dpsize);
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100869 if (!buf)
870 return NULL;
Heinrich Schuchardt39568fd2023-07-19 06:43:08 +0200871 pos = dp_fill(buf, dm_root());
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100872 uart = pos;
873 uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
874 uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART;
875 uart->dp.length = sizeof(*uart);
876 pos += sizeof(*uart);
Simon Glassc88552c2025-05-24 11:28:23 -0600877 memcpy(pos, &EFI_DP_END, sizeof(EFI_DP_END));
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +0100878
879 return buf;
880}
881
Adriano Cordova1d370312025-03-03 11:13:14 -0300882struct efi_device_path __maybe_unused *efi_dp_from_eth(struct udevice *dev)
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400883{
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400884 void *buf, *start;
885 unsigned dpsize = 0;
886
Adriano Cordova1d370312025-03-03 11:13:14 -0300887 assert(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400888
Adriano Cordova1d370312025-03-03 11:13:14 -0300889 dpsize += dp_size(dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400890
Simon Glassc88552c2025-05-24 11:28:23 -0600891 start = efi_alloc(dpsize + sizeof(EFI_DP_END));
892 if (!start)
Heinrich Schuchardt468bf972018-01-19 20:24:37 +0100893 return NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400894
Simon Glassc88552c2025-05-24 11:28:23 -0600895 buf = dp_fill(start, dev);
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400896
Simon Glassc88552c2025-05-24 11:28:23 -0600897 *((struct efi_device_path *)buf) = EFI_DP_END;
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400898
899 return start;
900}
Rob Clarkf90cb9f2017-09-13 18:05:28 -0400901
Adriano Cordovae9be2da2024-12-04 00:05:18 -0300902/**
903 * efi_dp_from_ipv4() - set device path from IPv4 address
904 *
905 * Set the device path to an ethernet device path as provided by
906 * efi_dp_from_eth() concatenated with a device path of subtype
Simon Glassc88552c2025-05-24 11:28:23 -0600907 * DEVICE_PATH_SUB_TYPE_MSG_IPV4, and an EFI_DP_END node.
Adriano Cordovae9be2da2024-12-04 00:05:18 -0300908 *
909 * @ip: IPv4 local address
910 * @mask: network mask
911 * @srv: IPv4 remote/server address
Adriano Cordova1d370312025-03-03 11:13:14 -0300912 * @dev: net udevice
Adriano Cordovae9be2da2024-12-04 00:05:18 -0300913 * Return: pointer to device path, NULL on error
914 */
915static struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip,
916 struct efi_ipv4_address *mask,
Adriano Cordova1d370312025-03-03 11:13:14 -0300917 struct efi_ipv4_address *srv,
918 struct udevice *dev)
Adriano Cordovae9be2da2024-12-04 00:05:18 -0300919{
920 struct efi_device_path *dp1, *dp2, *pos;
921 struct {
922 struct efi_device_path_ipv4 ipv4dp;
923 struct efi_device_path end;
924 } dp;
925
926 memset(&dp.ipv4dp, 0, sizeof(dp.ipv4dp));
927 dp.ipv4dp.dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
928 dp.ipv4dp.dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_IPV4;
929 dp.ipv4dp.dp.length = sizeof(dp.ipv4dp);
930 dp.ipv4dp.protocol = 6;
931 if (ip)
932 memcpy(&dp.ipv4dp.local_ip_address, ip, sizeof(*ip));
933 if (mask)
934 memcpy(&dp.ipv4dp.subnet_mask, mask, sizeof(*mask));
935 if (srv)
936 memcpy(&dp.ipv4dp.remote_ip_address, srv, sizeof(*srv));
937 pos = &dp.end;
Simon Glassc88552c2025-05-24 11:28:23 -0600938 memcpy(pos, &EFI_DP_END, sizeof(EFI_DP_END));
Adriano Cordovae9be2da2024-12-04 00:05:18 -0300939
Adriano Cordova1d370312025-03-03 11:13:14 -0300940 dp1 = efi_dp_from_eth(dev);
Adriano Cordovae9be2da2024-12-04 00:05:18 -0300941 if (!dp1)
942 return NULL;
943
944 dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)&dp, 0);
945
946 efi_free_pool(dp1);
947
948 return dp2;
949}
950
Adriano Cordova1d370312025-03-03 11:13:14 -0300951struct efi_device_path *efi_dp_from_http(const char *server, struct udevice *dev)
Adriano Cordova4bd5eca2024-12-04 00:05:22 -0300952{
953 struct efi_device_path *dp1, *dp2;
954 struct efi_device_path_uri *uridp;
955 efi_uintn_t uridp_len;
956 char *pos;
957 char tmp[128];
958 struct efi_ipv4_address ip;
959 struct efi_ipv4_address mask;
960
961 if ((server && strlen("http://") + strlen(server) + 1 > sizeof(tmp)) ||
962 (!server && IS_ENABLED(CONFIG_NET_LWIP)))
963 return NULL;
964
Adriano Cordova54674692025-03-03 11:13:15 -0300965 efi_net_get_addr(&ip, &mask, NULL, dev);
Adriano Cordova4bd5eca2024-12-04 00:05:22 -0300966
Adriano Cordova1d370312025-03-03 11:13:14 -0300967 dp1 = efi_dp_from_ipv4(&ip, &mask, NULL, dev);
Adriano Cordova4bd5eca2024-12-04 00:05:22 -0300968 if (!dp1)
969 return NULL;
970
Adriano Cordova1d370312025-03-03 11:13:14 -0300971
Adriano Cordova4bd5eca2024-12-04 00:05:22 -0300972 strcpy(tmp, "http://");
973
974 if (server) {
975 strlcat(tmp, server, sizeof(tmp));
976#if !IS_ENABLED(CONFIG_NET_LWIP)
Tom Rini19687542024-12-04 09:32:28 -0600977 } else {
Adriano Cordova4bd5eca2024-12-04 00:05:22 -0300978 ip_to_string(net_server_ip, tmp + strlen("http://"));
979#endif
980 }
981
982 uridp_len = sizeof(struct efi_device_path) + strlen(tmp) + 1;
Simon Glassc88552c2025-05-24 11:28:23 -0600983 uridp = efi_alloc(uridp_len + sizeof(EFI_DP_END));
Adriano Cordova4bd5eca2024-12-04 00:05:22 -0300984 if (!uridp) {
985 log_err("Out of memory\n");
986 return NULL;
987 }
988 uridp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
989 uridp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_URI;
990 uridp->dp.length = uridp_len;
991 debug("device path: setting uri device path to %s\n", tmp);
992 memcpy(uridp->uri, tmp, strlen(tmp) + 1);
993
994 pos = (char *)uridp + uridp_len;
Simon Glassc88552c2025-05-24 11:28:23 -0600995 memcpy(pos, &EFI_DP_END, sizeof(EFI_DP_END));
Adriano Cordova4bd5eca2024-12-04 00:05:22 -0300996
997 dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)uridp, 0);
998
999 efi_free_pool(uridp);
1000 efi_free_pool(dp1);
1001
1002 return dp2;
1003}
1004
Rob Clark18ceba72017-10-10 08:23:06 -04001005/* Construct a device-path for memory-mapped image */
1006struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
1007 uint64_t start_address,
Moritz Fischerfe61a8b2024-11-04 01:49:34 +00001008 size_t size)
Rob Clark18ceba72017-10-10 08:23:06 -04001009{
1010 struct efi_device_path_memory *mdp;
1011 void *buf, *start;
1012
Simon Glassc88552c2025-05-24 11:28:23 -06001013 start = efi_alloc(sizeof(*mdp) + sizeof(EFI_DP_END));
1014 if (!start)
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001015 return NULL;
Rob Clark18ceba72017-10-10 08:23:06 -04001016
Simon Glassc88552c2025-05-24 11:28:23 -06001017 mdp = start;
Rob Clark18ceba72017-10-10 08:23:06 -04001018 mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
1019 mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
1020 mdp->dp.length = sizeof(*mdp);
1021 mdp->memory_type = memory_type;
1022 mdp->start_address = start_address;
Moritz Fischerfe61a8b2024-11-04 01:49:34 +00001023 mdp->end_address = start_address + size;
Rob Clark18ceba72017-10-10 08:23:06 -04001024 buf = &mdp[1];
1025
Simon Glassc88552c2025-05-24 11:28:23 -06001026 *((struct efi_device_path *)buf) = EFI_DP_END;
Rob Clark18ceba72017-10-10 08:23:06 -04001027
1028 return start;
1029}
1030
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +01001031/**
1032 * efi_dp_split_file_path() - split of relative file path from device path
1033 *
1034 * Given a device path indicating a file on a device, separate the device
1035 * path in two: the device path of the actual device and the file path
1036 * relative to this device.
1037 *
1038 * @full_path: device path including device and file path
1039 * @device_path: path of the device
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001040 * @file_path: relative path of the file or NULL if there is none
Heinrich Schuchardt0d36adc2019-02-04 12:49:43 +01001041 * Return: status code
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001042 */
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001043efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
1044 struct efi_device_path **device_path,
1045 struct efi_device_path **file_path)
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001046{
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001047 struct efi_device_path *p, *dp, *fp = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001048
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001049 *device_path = NULL;
1050 *file_path = NULL;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001051 dp = efi_dp_dup(full_path);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001052 if (!dp)
1053 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001054 p = dp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001055 while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001056 p = efi_dp_next(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001057 if (!p)
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001058 goto out;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001059 }
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001060 fp = efi_dp_dup(p);
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001061 if (!fp)
1062 return EFI_OUT_OF_RESOURCES;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001063 p->type = DEVICE_PATH_TYPE_END;
1064 p->sub_type = DEVICE_PATH_SUB_TYPE_END;
1065 p->length = sizeof(*p);
1066
AKASHI Takahiro9c6531f2019-04-16 17:39:26 +02001067out:
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001068 *device_path = dp;
1069 *file_path = fp;
Heinrich Schuchardt468bf972018-01-19 20:24:37 +01001070 return EFI_SUCCESS;
Rob Clarkf90cb9f2017-09-13 18:05:28 -04001071}
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001072
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001073/**
1074 * efi_dp_from_name() - convert U-Boot device and file path to device path
1075 *
1076 * @dev: U-Boot device, e.g. 'mmc'
1077 * @devnr: U-Boot device number, e.g. 1 for 'mmc:1'
1078 * @path: file path relative to U-Boot device, may be NULL
1079 * @device: pointer to receive device path of the device
1080 * @file: pointer to receive device path for the file
1081 * Return: status code
1082 */
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001083efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
1084 const char *path,
1085 struct efi_device_path **device,
1086 struct efi_device_path **file)
1087{
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001088 struct blk_desc *desc = NULL;
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001089 struct efi_device_path *dp;
Simon Glassc1c4a8f2020-05-10 11:39:57 -06001090 struct disk_partition fs_partition;
Rui Miguel Silva433f15a2022-05-11 10:55:40 +01001091 size_t image_size;
1092 void *image_addr;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001093 int part = 0;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001094
AKASHI Takahiro39844412018-11-05 18:06:40 +09001095 if (path && !file)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001096 return EFI_INVALID_PARAMETER;
1097
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +09001098 if (IS_ENABLED(CONFIG_EFI_BINARY_EXEC) &&
1099 (!strcmp(dev, "Mem") || !strcmp(dev, "hostfs"))) {
Heinrich Schuchardtaecb9e22023-05-12 20:18:10 +02001100 /* loadm command and semihosting */
Rui Miguel Silva433f15a2022-05-11 10:55:40 +01001101 efi_get_image_parameters(&image_addr, &image_size);
1102
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001103 dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
Moritz Fischerfe61a8b2024-11-04 01:49:34 +00001104 (uintptr_t)image_addr, image_size);
Adriano Cordova93cba0f2024-12-04 00:05:23 -03001105 } else if (IS_ENABLED(CONFIG_NETDEVICES) &&
Adriano Cordova54674692025-03-03 11:13:15 -03001106 (!strcmp(dev, "Net") || !strcmp(dev, "Http"))) {
1107 efi_net_dp_from_dev(&dp, eth_get_dev(), false);
Heinrich Schuchardt87b8a712023-05-13 09:55:26 +02001108 } else if (!strcmp(dev, "Uart")) {
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001109 dp = efi_dp_from_uart();
Heinrich Schuchardt77c0da82021-03-19 02:49:54 +01001110 } else {
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001111 part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1112 1);
Patrick Delaunayba7a9502019-04-10 11:02:58 +02001113 if (part < 0 || !desc)
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001114 return EFI_INVALID_PARAMETER;
1115
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001116 dp = efi_dp_from_part(desc, part);
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001117 }
Heinrich Schuchardt7e269a32023-05-13 10:30:43 +02001118 if (device)
1119 *device = dp;
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001120
1121 if (!path)
1122 return EFI_SUCCESS;
1123
Heinrich Schuchardtff08eac2023-05-13 10:36:21 +02001124 *file = efi_dp_from_file(dp, path);
Heinrich Schuchardt6e0a1b42019-10-30 20:13:24 +01001125 if (!*file)
Heinrich Schuchardtbf0b3a12023-05-13 10:22:21 +02001126 return EFI_OUT_OF_RESOURCES;
AKASHI Takahirof1dbbae2019-10-09 16:19:52 +09001127
AKASHI Takahiro035fb012018-10-17 16:32:03 +09001128 return EFI_SUCCESS;
1129}
Heinrich Schuchardt22c8e082020-08-23 10:49:46 +02001130
1131/**
1132 * efi_dp_check_length() - check length of a device path
1133 *
1134 * @dp: pointer to device path
1135 * @maxlen: maximum length of the device path
1136 * Return:
1137 * * length of the device path if it is less or equal @maxlen
1138 * * -1 if the device path is longer then @maxlen
1139 * * -1 if a device path node has a length of less than 4
1140 * * -EINVAL if maxlen exceeds SSIZE_MAX
1141 */
1142ssize_t efi_dp_check_length(const struct efi_device_path *dp,
1143 const size_t maxlen)
1144{
1145 ssize_t ret = 0;
1146 u16 len;
1147
1148 if (maxlen > SSIZE_MAX)
1149 return -EINVAL;
1150 for (;;) {
1151 len = dp->length;
1152 if (len < 4)
1153 return -1;
1154 ret += len;
1155 if (ret > maxlen)
1156 return -1;
1157 if (dp->type == DEVICE_PATH_TYPE_END &&
1158 dp->sub_type == DEVICE_PATH_SUB_TYPE_END)
1159 return ret;
1160 dp = (const struct efi_device_path *)((const u8 *)dp + len);
1161 }
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001162}
1163
1164/**
Heinrich Schuchardt2ca26802024-04-26 16:13:19 +02001165 * efi_dp_from_lo() - get device-path from load option
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001166 *
Heinrich Schuchardt2ca26802024-04-26 16:13:19 +02001167 * The load options in U-Boot may contain multiple concatenated device-paths.
1168 * The first device-path indicates the EFI binary to execute. Subsequent
1169 * device-paths start with a VenMedia node where the GUID identifies the
1170 * function (initrd or fdt).
1171 *
1172 * @lo: EFI load option containing a valid device path
1173 * @guid: GUID identifying device-path or NULL for the EFI binary
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001174 *
1175 * Return:
Heinrich Schuchardt2ca26802024-04-26 16:13:19 +02001176 * device path excluding the matched VenMedia node or NULL.
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001177 * Caller must free the returned value.
1178 */
1179struct
1180efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
Heinrich Schuchardt9979cff2021-10-15 01:31:02 +02001181 const efi_guid_t *guid)
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001182{
1183 struct efi_device_path *fp = lo->file_path;
1184 struct efi_device_path_vendor *vendor;
1185 int lo_len = lo->file_path_length;
1186
Heinrich Schuchardt2ca26802024-04-26 16:13:19 +02001187 if (!guid)
1188 return efi_dp_dup(fp);
1189
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001190 for (; lo_len >= sizeof(struct efi_device_path);
1191 lo_len -= fp->length, fp = (void *)fp + fp->length) {
1192 if (lo_len < 0 || efi_dp_check_length(fp, lo_len) < 0)
1193 break;
1194 if (fp->type != DEVICE_PATH_TYPE_MEDIA_DEVICE ||
1195 fp->sub_type != DEVICE_PATH_SUB_TYPE_VENDOR_PATH)
1196 continue;
1197
1198 vendor = (struct efi_device_path_vendor *)fp;
Heinrich Schuchardt9979cff2021-10-15 01:31:02 +02001199 if (!guidcmp(&vendor->guid, guid))
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +02001200 return efi_dp_dup(efi_dp_next(fp));
Ilias Apalodimas483d28e2021-03-17 21:54:58 +02001201 }
1202 log_debug("VenMedia(%pUl) not found in %ls\n", &guid, lo->label);
1203
1204 return NULL;
Heinrich Schuchardt22c8e082020-08-23 10:49:46 +02001205}
Masahisa Kojima6460c3e2021-10-26 17:27:25 +09001206
1207/**
1208 * search_gpt_dp_node() - search gpt device path node
1209 *
1210 * @device_path: device path
1211 *
1212 * Return: pointer to the gpt device path node
1213 */
1214struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path)
1215{
1216 struct efi_device_path *dp = device_path;
1217
1218 while (dp) {
1219 if (dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
1220 dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
1221 struct efi_device_path_hard_drive_path *hd_dp =
1222 (struct efi_device_path_hard_drive_path *)dp;
1223
1224 if (hd_dp->partmap_type == PART_FORMAT_GPT &&
1225 hd_dp->signature_type == SIG_TYPE_GUID)
1226 return dp;
1227 }
1228 dp = efi_dp_next(dp);
1229 }
1230
1231 return NULL;
1232}