1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * EFI device path from u-boot device-model mapping
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) Copyright 2017 Rob Clark
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <blk.h>
11*4882a593Smuzhiyun #include <dm.h>
12*4882a593Smuzhiyun #include <usb.h>
13*4882a593Smuzhiyun #include <mmc.h>
14*4882a593Smuzhiyun #include <efi_loader.h>
15*4882a593Smuzhiyun #include <inttypes.h>
16*4882a593Smuzhiyun #include <part.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /* template END node: */
19*4882a593Smuzhiyun static const struct efi_device_path END = {
20*4882a593Smuzhiyun .type = DEVICE_PATH_TYPE_END,
21*4882a593Smuzhiyun .sub_type = DEVICE_PATH_SUB_TYPE_END,
22*4882a593Smuzhiyun .length = sizeof(END),
23*4882a593Smuzhiyun };
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define U_BOOT_GUID \
26*4882a593Smuzhiyun EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \
27*4882a593Smuzhiyun 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /* template ROOT node: */
30*4882a593Smuzhiyun static const struct efi_device_path_vendor ROOT = {
31*4882a593Smuzhiyun .dp = {
32*4882a593Smuzhiyun .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
33*4882a593Smuzhiyun .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
34*4882a593Smuzhiyun .length = sizeof(ROOT),
35*4882a593Smuzhiyun },
36*4882a593Smuzhiyun .guid = U_BOOT_GUID,
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun
dp_alloc(size_t sz)39*4882a593Smuzhiyun static void *dp_alloc(size_t sz)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun void *buf;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) != EFI_SUCCESS)
44*4882a593Smuzhiyun return NULL;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun return buf;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /*
50*4882a593Smuzhiyun * Iterate to next block in device-path, terminating (returning NULL)
51*4882a593Smuzhiyun * at /End* node.
52*4882a593Smuzhiyun */
efi_dp_next(const struct efi_device_path * dp)53*4882a593Smuzhiyun struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun if (dp == NULL)
56*4882a593Smuzhiyun return NULL;
57*4882a593Smuzhiyun if (dp->type == DEVICE_PATH_TYPE_END)
58*4882a593Smuzhiyun return NULL;
59*4882a593Smuzhiyun dp = ((void *)dp) + dp->length;
60*4882a593Smuzhiyun if (dp->type == DEVICE_PATH_TYPE_END)
61*4882a593Smuzhiyun return NULL;
62*4882a593Smuzhiyun return (struct efi_device_path *)dp;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun * Compare two device-paths, stopping when the shorter of the two hits
67*4882a593Smuzhiyun * an End* node. This is useful to, for example, compare a device-path
68*4882a593Smuzhiyun * representing a device with one representing a file on the device, or
69*4882a593Smuzhiyun * a device with a parent device.
70*4882a593Smuzhiyun */
efi_dp_match(struct efi_device_path * a,struct efi_device_path * b)71*4882a593Smuzhiyun int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun while (1) {
74*4882a593Smuzhiyun int ret;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun ret = memcmp(&a->length, &b->length, sizeof(a->length));
77*4882a593Smuzhiyun if (ret)
78*4882a593Smuzhiyun return ret;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun ret = memcmp(a, b, a->length);
81*4882a593Smuzhiyun if (ret)
82*4882a593Smuzhiyun return ret;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun a = efi_dp_next(a);
85*4882a593Smuzhiyun b = efi_dp_next(b);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (!a || !b)
88*4882a593Smuzhiyun return 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /*
94*4882a593Smuzhiyun * See UEFI spec (section 3.1.2, about short-form device-paths..
95*4882a593Smuzhiyun * tl;dr: we can have a device-path that starts with a USB WWID
96*4882a593Smuzhiyun * or USB Class node, and a few other cases which don't encode
97*4882a593Smuzhiyun * the full device path with bus hierarchy:
98*4882a593Smuzhiyun *
99*4882a593Smuzhiyun * - MESSAGING:USB_WWID
100*4882a593Smuzhiyun * - MESSAGING:USB_CLASS
101*4882a593Smuzhiyun * - MEDIA:FILE_PATH
102*4882a593Smuzhiyun * - MEDIA:HARD_DRIVE
103*4882a593Smuzhiyun * - MESSAGING:URI
104*4882a593Smuzhiyun */
shorten_path(struct efi_device_path * dp)105*4882a593Smuzhiyun static struct efi_device_path *shorten_path(struct efi_device_path *dp)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun while (dp) {
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..
110*4882a593Smuzhiyun * in practice fallback.efi just uses MEDIA:HARD_DRIVE
111*4882a593Smuzhiyun * so not sure when we would see these other cases.
112*4882a593Smuzhiyun */
113*4882a593Smuzhiyun if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||
114*4882a593Smuzhiyun EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
115*4882a593Smuzhiyun EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
116*4882a593Smuzhiyun return dp;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun dp = efi_dp_next(dp);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun return dp;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
find_obj(struct efi_device_path * dp,bool short_path,struct efi_device_path ** rem)124*4882a593Smuzhiyun static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
125*4882a593Smuzhiyun struct efi_device_path **rem)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun struct efi_object *efiobj;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun list_for_each_entry(efiobj, &efi_obj_list, link) {
130*4882a593Smuzhiyun int i;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
133*4882a593Smuzhiyun struct efi_handler *handler = &efiobj->protocols[i];
134*4882a593Smuzhiyun struct efi_device_path *obj_dp;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun if (!handler->guid)
137*4882a593Smuzhiyun break;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (guidcmp(handler->guid, &efi_guid_device_path))
140*4882a593Smuzhiyun continue;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun obj_dp = handler->protocol_interface;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun do {
145*4882a593Smuzhiyun if (efi_dp_match(dp, obj_dp) == 0) {
146*4882a593Smuzhiyun if (rem) {
147*4882a593Smuzhiyun *rem = ((void *)dp) +
148*4882a593Smuzhiyun efi_dp_size(obj_dp);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun return efiobj;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun obj_dp = shorten_path(efi_dp_next(obj_dp));
154*4882a593Smuzhiyun } while (short_path && obj_dp);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return NULL;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun /*
163*4882a593Smuzhiyun * Find an efiobj from device-path, if 'rem' is not NULL, returns the
164*4882a593Smuzhiyun * remaining part of the device path after the matched object.
165*4882a593Smuzhiyun */
efi_dp_find_obj(struct efi_device_path * dp,struct efi_device_path ** rem)166*4882a593Smuzhiyun struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
167*4882a593Smuzhiyun struct efi_device_path **rem)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun struct efi_object *efiobj;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun efiobj = find_obj(dp, false, rem);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun if (!efiobj)
174*4882a593Smuzhiyun efiobj = find_obj(dp, true, rem);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun return efiobj;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* return size not including End node: */
efi_dp_size(const struct efi_device_path * dp)180*4882a593Smuzhiyun unsigned efi_dp_size(const struct efi_device_path *dp)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun unsigned sz = 0;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun while (dp) {
185*4882a593Smuzhiyun sz += dp->length;
186*4882a593Smuzhiyun dp = efi_dp_next(dp);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return sz;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
efi_dp_dup(const struct efi_device_path * dp)192*4882a593Smuzhiyun struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun struct efi_device_path *ndp;
195*4882a593Smuzhiyun unsigned sz = efi_dp_size(dp) + sizeof(END);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun if (!dp)
198*4882a593Smuzhiyun return NULL;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun ndp = dp_alloc(sz);
201*4882a593Smuzhiyun memcpy(ndp, dp, sz);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun return ndp;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
efi_dp_append(const struct efi_device_path * dp1,const struct efi_device_path * dp2)206*4882a593Smuzhiyun struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
207*4882a593Smuzhiyun const struct efi_device_path *dp2)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun struct efi_device_path *ret;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (!dp1) {
212*4882a593Smuzhiyun ret = efi_dp_dup(dp2);
213*4882a593Smuzhiyun } else if (!dp2) {
214*4882a593Smuzhiyun ret = efi_dp_dup(dp1);
215*4882a593Smuzhiyun } else {
216*4882a593Smuzhiyun /* both dp1 and dp2 are non-null */
217*4882a593Smuzhiyun unsigned sz1 = efi_dp_size(dp1);
218*4882a593Smuzhiyun unsigned sz2 = efi_dp_size(dp2);
219*4882a593Smuzhiyun void *p = dp_alloc(sz1 + sz2 + sizeof(END));
220*4882a593Smuzhiyun memcpy(p, dp1, sz1);
221*4882a593Smuzhiyun memcpy(p + sz1, dp2, sz2);
222*4882a593Smuzhiyun memcpy(p + sz1 + sz2, &END, sizeof(END));
223*4882a593Smuzhiyun ret = p;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun return ret;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
efi_dp_append_node(const struct efi_device_path * dp,const struct efi_device_path * node)229*4882a593Smuzhiyun struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
230*4882a593Smuzhiyun const struct efi_device_path *node)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun struct efi_device_path *ret;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun if (!node && !dp) {
235*4882a593Smuzhiyun ret = efi_dp_dup(&END);
236*4882a593Smuzhiyun } else if (!node) {
237*4882a593Smuzhiyun ret = efi_dp_dup(dp);
238*4882a593Smuzhiyun } else if (!dp) {
239*4882a593Smuzhiyun unsigned sz = node->length;
240*4882a593Smuzhiyun void *p = dp_alloc(sz + sizeof(END));
241*4882a593Smuzhiyun memcpy(p, node, sz);
242*4882a593Smuzhiyun memcpy(p + sz, &END, sizeof(END));
243*4882a593Smuzhiyun ret = p;
244*4882a593Smuzhiyun } else {
245*4882a593Smuzhiyun /* both dp and node are non-null */
246*4882a593Smuzhiyun unsigned sz = efi_dp_size(dp);
247*4882a593Smuzhiyun void *p = dp_alloc(sz + node->length + sizeof(END));
248*4882a593Smuzhiyun memcpy(p, dp, sz);
249*4882a593Smuzhiyun memcpy(p + sz, node, node->length);
250*4882a593Smuzhiyun memcpy(p + sz + node->length, &END, sizeof(END));
251*4882a593Smuzhiyun ret = p;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun return ret;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun #ifdef CONFIG_DM
258*4882a593Smuzhiyun /* size of device-path not including END node for device and all parents
259*4882a593Smuzhiyun * up to the root device.
260*4882a593Smuzhiyun */
dp_size(struct udevice * dev)261*4882a593Smuzhiyun static unsigned dp_size(struct udevice *dev)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun if (!dev || !dev->driver)
264*4882a593Smuzhiyun return sizeof(ROOT);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun switch (dev->driver->id) {
267*4882a593Smuzhiyun case UCLASS_ROOT:
268*4882a593Smuzhiyun case UCLASS_SIMPLE_BUS:
269*4882a593Smuzhiyun /* stop traversing parents at this point: */
270*4882a593Smuzhiyun return sizeof(ROOT);
271*4882a593Smuzhiyun case UCLASS_MMC:
272*4882a593Smuzhiyun return dp_size(dev->parent) +
273*4882a593Smuzhiyun sizeof(struct efi_device_path_sd_mmc_path);
274*4882a593Smuzhiyun case UCLASS_MASS_STORAGE:
275*4882a593Smuzhiyun case UCLASS_USB_HUB:
276*4882a593Smuzhiyun return dp_size(dev->parent) +
277*4882a593Smuzhiyun sizeof(struct efi_device_path_usb_class);
278*4882a593Smuzhiyun default:
279*4882a593Smuzhiyun /* just skip over unknown classes: */
280*4882a593Smuzhiyun return dp_size(dev->parent);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
dp_fill(void * buf,struct udevice * dev)284*4882a593Smuzhiyun static void *dp_fill(void *buf, struct udevice *dev)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun if (!dev || !dev->driver)
287*4882a593Smuzhiyun return buf;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun switch (dev->driver->id) {
290*4882a593Smuzhiyun case UCLASS_ROOT:
291*4882a593Smuzhiyun case UCLASS_SIMPLE_BUS: {
292*4882a593Smuzhiyun /* stop traversing parents at this point: */
293*4882a593Smuzhiyun struct efi_device_path_vendor *vdp = buf;
294*4882a593Smuzhiyun *vdp = ROOT;
295*4882a593Smuzhiyun return &vdp[1];
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
298*4882a593Smuzhiyun case UCLASS_MMC: {
299*4882a593Smuzhiyun struct efi_device_path_sd_mmc_path *sddp =
300*4882a593Smuzhiyun dp_fill(buf, dev->parent);
301*4882a593Smuzhiyun struct mmc *mmc = mmc_get_mmc_dev(dev);
302*4882a593Smuzhiyun struct blk_desc *desc = mmc_get_blk_desc(mmc);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
305*4882a593Smuzhiyun sddp->dp.sub_type = (desc->if_type == IF_TYPE_MMC) ?
306*4882a593Smuzhiyun DEVICE_PATH_SUB_TYPE_MSG_MMC :
307*4882a593Smuzhiyun DEVICE_PATH_SUB_TYPE_MSG_SD;
308*4882a593Smuzhiyun sddp->dp.length = sizeof(*sddp);
309*4882a593Smuzhiyun sddp->slot_number = dev->seq;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return &sddp[1];
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun #endif
314*4882a593Smuzhiyun case UCLASS_MASS_STORAGE:
315*4882a593Smuzhiyun case UCLASS_USB_HUB: {
316*4882a593Smuzhiyun struct efi_device_path_usb_class *udp =
317*4882a593Smuzhiyun dp_fill(buf, dev->parent);
318*4882a593Smuzhiyun struct usb_device *udev = dev_get_parent_priv(dev);
319*4882a593Smuzhiyun struct usb_device_descriptor *desc = &udev->descriptor;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
322*4882a593Smuzhiyun udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
323*4882a593Smuzhiyun udp->dp.length = sizeof(*udp);
324*4882a593Smuzhiyun udp->vendor_id = desc->idVendor;
325*4882a593Smuzhiyun udp->product_id = desc->idProduct;
326*4882a593Smuzhiyun udp->device_class = desc->bDeviceClass;
327*4882a593Smuzhiyun udp->device_subclass = desc->bDeviceSubClass;
328*4882a593Smuzhiyun udp->device_protocol = desc->bDeviceProtocol;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun return &udp[1];
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun default:
333*4882a593Smuzhiyun debug("unhandled device class: %s (%u)\n",
334*4882a593Smuzhiyun dev->name, dev->driver->id);
335*4882a593Smuzhiyun return dp_fill(buf, dev->parent);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /* Construct a device-path from a device: */
efi_dp_from_dev(struct udevice * dev)340*4882a593Smuzhiyun struct efi_device_path *efi_dp_from_dev(struct udevice *dev)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun void *buf, *start;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun start = buf = dp_alloc(dp_size(dev) + sizeof(END));
345*4882a593Smuzhiyun buf = dp_fill(buf, dev);
346*4882a593Smuzhiyun *((struct efi_device_path *)buf) = END;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun return start;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun #endif
351*4882a593Smuzhiyun
dp_part_size(struct blk_desc * desc,int part)352*4882a593Smuzhiyun static unsigned dp_part_size(struct blk_desc *desc, int part)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun unsigned dpsize;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun #ifdef CONFIG_BLK
357*4882a593Smuzhiyun dpsize = dp_size(desc->bdev->parent);
358*4882a593Smuzhiyun #else
359*4882a593Smuzhiyun dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
360*4882a593Smuzhiyun #endif
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (part == 0) /* the actual disk, not a partition */
363*4882a593Smuzhiyun return dpsize;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun if (desc->part_type == PART_TYPE_ISO)
366*4882a593Smuzhiyun dpsize += sizeof(struct efi_device_path_cdrom_path);
367*4882a593Smuzhiyun else
368*4882a593Smuzhiyun dpsize += sizeof(struct efi_device_path_hard_drive_path);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun return dpsize;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
dp_part_fill(void * buf,struct blk_desc * desc,int part)373*4882a593Smuzhiyun static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun disk_partition_t info;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun #ifdef CONFIG_BLK
378*4882a593Smuzhiyun buf = dp_fill(buf, desc->bdev->parent);
379*4882a593Smuzhiyun #else
380*4882a593Smuzhiyun /*
381*4882a593Smuzhiyun * We *could* make a more accurate path, by looking at if_type
382*4882a593Smuzhiyun * and handling all the different cases like we do for non-
383*4882a593Smuzhiyun * legacy (ie CONFIG_BLK=y) case. But most important thing
384*4882a593Smuzhiyun * is just to have a unique device-path for if_type+devnum.
385*4882a593Smuzhiyun * So map things to a fictional USB device:
386*4882a593Smuzhiyun */
387*4882a593Smuzhiyun struct efi_device_path_usb *udp;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun memcpy(buf, &ROOT, sizeof(ROOT));
390*4882a593Smuzhiyun buf += sizeof(ROOT);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun udp = buf;
393*4882a593Smuzhiyun udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
394*4882a593Smuzhiyun udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
395*4882a593Smuzhiyun udp->dp.length = sizeof(*udp);
396*4882a593Smuzhiyun udp->parent_port_number = desc->if_type;
397*4882a593Smuzhiyun udp->usb_interface = desc->devnum;
398*4882a593Smuzhiyun buf = &udp[1];
399*4882a593Smuzhiyun #endif
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (part == 0) /* the actual disk, not a partition */
402*4882a593Smuzhiyun return buf;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun part_get_info(desc, part, &info);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun if (desc->part_type == PART_TYPE_ISO) {
407*4882a593Smuzhiyun struct efi_device_path_cdrom_path *cddp = buf;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun cddp->boot_entry = part - 1;
410*4882a593Smuzhiyun cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
411*4882a593Smuzhiyun cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
412*4882a593Smuzhiyun cddp->dp.length = sizeof(*cddp);
413*4882a593Smuzhiyun cddp->partition_start = info.start;
414*4882a593Smuzhiyun cddp->partition_end = info.size;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun buf = &cddp[1];
417*4882a593Smuzhiyun } else {
418*4882a593Smuzhiyun struct efi_device_path_hard_drive_path *hddp = buf;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
421*4882a593Smuzhiyun hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
422*4882a593Smuzhiyun hddp->dp.length = sizeof(*hddp);
423*4882a593Smuzhiyun hddp->partition_number = part - 1;
424*4882a593Smuzhiyun hddp->partition_start = info.start;
425*4882a593Smuzhiyun hddp->partition_end = info.size;
426*4882a593Smuzhiyun if (desc->part_type == PART_TYPE_EFI)
427*4882a593Smuzhiyun hddp->partmap_type = 2;
428*4882a593Smuzhiyun else
429*4882a593Smuzhiyun hddp->partmap_type = 1;
430*4882a593Smuzhiyun hddp->signature_type = desc->sig_type;
431*4882a593Smuzhiyun if (hddp->signature_type != 0)
432*4882a593Smuzhiyun memcpy(hddp->partition_signature, &desc->guid_sig,
433*4882a593Smuzhiyun sizeof(hddp->partition_signature));
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun buf = &hddp[1];
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun return buf;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /* Construct a device-path from a partition on a blk device: */
efi_dp_from_part(struct blk_desc * desc,int part)443*4882a593Smuzhiyun struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun void *buf, *start;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun buf = dp_part_fill(buf, desc, part);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun *((struct efi_device_path *)buf) = END;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun return start;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */
path_to_uefi(u16 * uefi,const char * path)457*4882a593Smuzhiyun static void path_to_uefi(u16 *uefi, const char *path)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun while (*path) {
460*4882a593Smuzhiyun char c = *(path++);
461*4882a593Smuzhiyun if (c == '/')
462*4882a593Smuzhiyun c = '\\';
463*4882a593Smuzhiyun *(uefi++) = c;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun *uefi = '\0';
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun /*
469*4882a593Smuzhiyun * If desc is NULL, this creates a path with only the file component,
470*4882a593Smuzhiyun * otherwise it creates a full path with both device and file components
471*4882a593Smuzhiyun */
efi_dp_from_file(struct blk_desc * desc,int part,const char * path)472*4882a593Smuzhiyun struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
473*4882a593Smuzhiyun const char *path)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun struct efi_device_path_file_path *fp;
476*4882a593Smuzhiyun void *buf, *start;
477*4882a593Smuzhiyun unsigned dpsize = 0, fpsize;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun if (desc)
480*4882a593Smuzhiyun dpsize = dp_part_size(desc, part);
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
483*4882a593Smuzhiyun dpsize += fpsize;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun start = buf = dp_alloc(dpsize + sizeof(END));
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun if (desc)
488*4882a593Smuzhiyun buf = dp_part_fill(buf, desc, part);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /* add file-path: */
491*4882a593Smuzhiyun fp = buf;
492*4882a593Smuzhiyun fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
493*4882a593Smuzhiyun fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
494*4882a593Smuzhiyun fp->dp.length = fpsize;
495*4882a593Smuzhiyun path_to_uefi(fp->str, path);
496*4882a593Smuzhiyun buf += fpsize;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun *((struct efi_device_path *)buf) = END;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun return start;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun #ifdef CONFIG_NET
efi_dp_from_eth(void)504*4882a593Smuzhiyun struct efi_device_path *efi_dp_from_eth(void)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun struct efi_device_path_mac_addr *ndp;
507*4882a593Smuzhiyun void *buf, *start;
508*4882a593Smuzhiyun unsigned dpsize = 0;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun assert(eth_get_dev());
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun #ifdef CONFIG_DM_ETH
513*4882a593Smuzhiyun dpsize += dp_size(eth_get_dev());
514*4882a593Smuzhiyun #else
515*4882a593Smuzhiyun dpsize += sizeof(ROOT);
516*4882a593Smuzhiyun #endif
517*4882a593Smuzhiyun dpsize += sizeof(*ndp);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun start = buf = dp_alloc(dpsize + sizeof(END));
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun #ifdef CONFIG_DM_ETH
522*4882a593Smuzhiyun buf = dp_fill(buf, eth_get_dev());
523*4882a593Smuzhiyun #else
524*4882a593Smuzhiyun memcpy(buf, &ROOT, sizeof(ROOT));
525*4882a593Smuzhiyun buf += sizeof(ROOT);
526*4882a593Smuzhiyun #endif
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun ndp = buf;
529*4882a593Smuzhiyun ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
530*4882a593Smuzhiyun ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
531*4882a593Smuzhiyun ndp->dp.length = sizeof(*ndp);
532*4882a593Smuzhiyun memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
533*4882a593Smuzhiyun buf = &ndp[1];
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun *((struct efi_device_path *)buf) = END;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun return start;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun #endif
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /*
542*4882a593Smuzhiyun * Helper to split a full device path (containing both device and file
543*4882a593Smuzhiyun * parts) into it's constituent parts.
544*4882a593Smuzhiyun */
efi_dp_split_file_path(struct efi_device_path * full_path,struct efi_device_path ** device_path,struct efi_device_path ** file_path)545*4882a593Smuzhiyun void efi_dp_split_file_path(struct efi_device_path *full_path,
546*4882a593Smuzhiyun struct efi_device_path **device_path,
547*4882a593Smuzhiyun struct efi_device_path **file_path)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun struct efi_device_path *p, *dp, *fp;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun dp = efi_dp_dup(full_path);
552*4882a593Smuzhiyun p = dp;
553*4882a593Smuzhiyun while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH))
554*4882a593Smuzhiyun p = efi_dp_next(p);
555*4882a593Smuzhiyun fp = efi_dp_dup(p);
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun p->type = DEVICE_PATH_TYPE_END;
558*4882a593Smuzhiyun p->sub_type = DEVICE_PATH_SUB_TYPE_END;
559*4882a593Smuzhiyun p->length = sizeof(*p);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun *device_path = dp;
562*4882a593Smuzhiyun *file_path = fp;
563*4882a593Smuzhiyun }
564