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 | // SPDX-License-Identifier: GPL-2.0+ /* * Bootmethod for distro boot via EFI * * Copyright 2021 Google LLC * Written by Simon Glass <sjg@chromium.org> */ #define LOG_CATEGORY LOGC_EFI #include <efi_device_path.h> #include <efi_loader.h> #include <env.h> #include <errno.h> #include <log.h> #include <string.h> #include <vsprintf.h> /** * efi_get_distro_fdt_name() - get the filename for reading the .dtb file * * @fname: buffer for filename * @size: buffer size * @seq: sequence number, to cycle through options (0=first) * * Returns: * 0 on success, * -ENOENT if the "fdtfile" env var does not exist, * -EINVAL if there are no more options, * -EALREADY if the control FDT should be used */ int efi_get_distro_fdt_name(char *fname, int size, int seq) { const char *fdt_fname; const char *prefix; /* select the prefix */ switch (seq) { case 0: /* this is the default */ prefix = "/dtb"; break; case 1: prefix = ""; break; case 2: prefix = "/dtb/current"; break; case 3: prefix = "/dtbs"; break; default: return log_msg_ret("pref", -EINVAL); } fdt_fname = env_get("fdtfile"); if (fdt_fname) { snprintf(fname, size, "%s/%s", prefix, fdt_fname); log_debug("Using device tree: %s\n", fname); } else if (IS_ENABLED(CONFIG_OF_HAS_PRIOR_STAGE)) { strcpy(fname, "<prior>"); return log_msg_ret("pref", -EALREADY); /* Use this fallback only for 32-bit ARM */ } else if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_ARM64)) { const char *soc = env_get("soc"); const char *board = env_get("board"); const char *boardver = env_get("boardver"); /* cf the code in label_boot() which seems very complex */ snprintf(fname, size, "%s/%s%s%s%s.dtb", prefix, soc ? soc : "", soc ? "-" : "", board ? board : "", boardver ? boardver : ""); log_debug("Using default device tree: %s\n", fname); } else { return log_msg_ret("env", -ENOENT); } return 0; } /** * efi_load_distro_fdt() - load distro device-tree * * @handle: handle of loaded image * @fdt: on return device-tree, must be freed via efi_free_pages() * @fdt_size: buffer size */ void efi_load_distro_fdt(efi_handle_t handle, void **fdt, efi_uintn_t *fdt_size) { struct efi_device_path *dp; efi_status_t ret; struct efi_handler *handler; struct efi_loaded_image *loaded_image; efi_handle_t device; *fdt = NULL; /* Get boot device from loaded image protocol */ ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler); if (ret != EFI_SUCCESS) return; loaded_image = handler->protocol_interface; device = loaded_image->device_handle; /* Get device path of boot device */ ret = efi_search_protocol(device, &efi_guid_device_path, &handler); if (ret != EFI_SUCCESS) return; dp = handler->protocol_interface; /* Try the various available names */ for (int seq = 0; ; ++seq) { struct efi_device_path *file; char buf[255]; if (efi_get_distro_fdt_name(buf, sizeof(buf), seq)) break; file = efi_dp_from_file(dp, buf); if (!file) break; ret = efi_load_image_from_path(true, file, fdt, fdt_size); efi_free_pool(file); if (ret == EFI_SUCCESS) { log_debug("Fdt %pD loaded\n", file); break; } } } |