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