Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2016 Alexander Graf * Copyright 2023 Google LLC */ #define LOG_CATEGORY LOGC_EFI #include <blk.h> #include <bootflow.h> #include <dm.h> #include <efi.h> #include <efi_device_path.h> #include <efi_loader.h> #include <malloc.h> #include <mapmem.h> #include <net-common.h> /** * calculate_paths() - Calculate the device and image patch from strings * * @dev: device, e.g. "MMC" * @devnr: number of the device, e.g. "1:2" * @path: path to file loaded * @device_pathp: returns EFI device path * @image_pathp: returns EFI image path * Return: EFI_SUCCESS on success, else error code */ efi_status_t calculate_paths(const char *dev, const char *devnr, const char *path, struct efi_device_path **device_pathp, struct efi_device_path **image_pathp) { struct efi_device_path *image, *device; efi_status_t ret; #if IS_ENABLED(CONFIG_NETDEVICES) && IS_ENABLED(CONFIG_EFI_LOADER) if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) { ret = efi_net_new_dp(dev, devnr, eth_get_dev()); if (ret != EFI_SUCCESS) return ret; } #endif log_debug("dev '%s' devnr '%s' path '%s'\n", dev, devnr, path); ret = efi_dp_from_name(dev, devnr, path, &device, &image); if (ret != EFI_SUCCESS) return ret; if (image) { /* FIXME: image should not contain device */ struct efi_device_path *image_tmp = image; efi_dp_split_file_path(image, &device, &image); efi_free_pool(image_tmp); } *device_pathp = device; *image_pathp = image; log_debug("- boot device %pD\n", device); if (image) log_debug("- image %pD\n", image); return EFI_SUCCESS; } /** * calc_dev_name() - Calculate the device name to give to EFI * * If not supported, this shows an error. * * Return name, or NULL if not supported */ static const char *calc_dev_name(struct bootflow *bflow) { const struct udevice *media_dev; media_dev = dev_get_parent(bflow->dev); log_debug("bflow->dev='%s', media_dev='%s', uclass_id=%d\n", bflow->dev->name, media_dev->name, device_get_uclass_id(media_dev)); if (!bflow->blk) { if (device_get_uclass_id(media_dev) == UCLASS_ETH) return "Net"; log_err("Cannot boot EFI app on media '%s'\n", dev_get_uclass_name(media_dev)); return NULL; } if (device_get_uclass_id(media_dev) == UCLASS_MASS_STORAGE) return "usb"; if (device_get_uclass_id(media_dev) == UCLASS_EFI_MEDIA) return "efi"; return blk_get_uclass_name(device_get_uclass_id(media_dev)); } efi_status_t efi_bootflow_run(struct bootflow *bflow) { struct efi_device_path *device, *image; const struct udevice *media_dev; struct blk_desc *desc = NULL; const char *dev_name; char devnum_str[9]; efi_status_t ret; void *fdt; media_dev = dev_get_parent(bflow->dev); if (bflow->blk) { desc = dev_get_uclass_plat(bflow->blk); snprintf(devnum_str, sizeof(devnum_str), "%x:%x", desc ? desc->devnum : dev_seq(media_dev), bflow->part); } else { *devnum_str = '\0'; } dev_name = calc_dev_name(bflow); log_debug("dev_name '%s' devnum_str '%s' fname '%s' media_dev '%s'\n", dev_name, devnum_str, bflow->fname, media_dev->name); if (!dev_name) return EFI_UNSUPPORTED; ret = calculate_paths(dev_name, devnum_str, bflow->fname, &device, &image); if (ret) return EFI_UNSUPPORTED; if (bflow->flags & BOOTFLOWF_USE_BUILTIN_FDT) { log_debug("Booting with built-in fdt\n"); fdt = EFI_FDT_USE_INTERNAL; } else { log_debug("Booting with external fdt\n"); fdt = map_sysmem(bflow->fdt_addr, 0); } ret = efi_binary_run_dp(bflow->buf, bflow->size, fdt, NULL, 0, device, image); return ret; } |