1 /* 2 * Copyright (C) 2016 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <errno.h> 10 #include <image.h> 11 #include <libfdt.h> 12 #include <spl.h> 13 14 /** 15 * spl_fit_get_image_node(): By using the matching configuration subnode, 16 * retrieve the name of an image, specified by a property name and an index 17 * into that. 18 * @fit: Pointer to the FDT blob. 19 * @images: Offset of the /images subnode. 20 * @type: Name of the property within the configuration subnode. 21 * @index: Index into the list of strings in this property. 22 * 23 * Return: the node offset of the respective image node or a negative 24 * error number. 25 */ 26 static int spl_fit_get_image_node(const void *fit, int images, 27 const char *type, int index) 28 { 29 const char *name, *str; 30 int node, conf_node; 31 int len, i; 32 33 conf_node = fit_find_config_node(fit); 34 if (conf_node < 0) { 35 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT 36 printf("No matching DT out of these options:\n"); 37 for (node = fdt_first_subnode(fit, conf_node); 38 node >= 0; 39 node = fdt_next_subnode(fit, node)) { 40 name = fdt_getprop(fit, node, "description", &len); 41 printf(" %s\n", name); 42 } 43 #endif 44 return conf_node; 45 } 46 47 name = fdt_getprop(fit, conf_node, type, &len); 48 if (!name) { 49 debug("cannot find property '%s': %d\n", type, len); 50 return -EINVAL; 51 } 52 53 str = name; 54 for (i = 0; i < index; i++) { 55 str = strchr(str, '\0') + 1; 56 if (!str || (str - name >= len)) { 57 debug("no string for index %d\n", index); 58 return -E2BIG; 59 } 60 } 61 62 debug("%s: '%s'\n", type, str); 63 node = fdt_subnode_offset(fit, images, str); 64 if (node < 0) { 65 debug("cannot find image node '%s': %d\n", str, node); 66 return -EINVAL; 67 } 68 69 return node; 70 } 71 72 static int get_aligned_image_offset(struct spl_load_info *info, int offset) 73 { 74 /* 75 * If it is a FS read, get the first address before offset which is 76 * aligned to ARCH_DMA_MINALIGN. If it is raw read return the 77 * block number to which offset belongs. 78 */ 79 if (info->filename) 80 return offset & ~(ARCH_DMA_MINALIGN - 1); 81 82 return offset / info->bl_len; 83 } 84 85 static int get_aligned_image_overhead(struct spl_load_info *info, int offset) 86 { 87 /* 88 * If it is a FS read, get the difference between the offset and 89 * the first address before offset which is aligned to 90 * ARCH_DMA_MINALIGN. If it is raw read return the offset within the 91 * block. 92 */ 93 if (info->filename) 94 return offset & (ARCH_DMA_MINALIGN - 1); 95 96 return offset % info->bl_len; 97 } 98 99 static int get_aligned_image_size(struct spl_load_info *info, int data_size, 100 int offset) 101 { 102 data_size = data_size + get_aligned_image_overhead(info, offset); 103 104 if (info->filename) 105 return data_size; 106 107 return (data_size + info->bl_len - 1) / info->bl_len; 108 } 109 110 /** 111 * spl_load_fit_image(): load the image described in a certain FIT node 112 * @info: points to information about the device to load data from 113 * @sector: the start sector of the FIT image on the device 114 * @fit: points to the flattened device tree blob describing the FIT 115 * image 116 * @base_offset: the beginning of the data area containing the actual 117 * image data, relative to the beginning of the FIT 118 * @node: offset of the DT node describing the image to load (relative 119 * to @fit) 120 * @image_info: will be filled with information about the loaded image 121 * If the FIT node does not contain a "load" (address) property, 122 * the image gets loaded to the address pointed to by the 123 * load_addr member in this struct. 124 * 125 * Return: 0 on success or a negative error number. 126 */ 127 static int spl_load_fit_image(struct spl_load_info *info, ulong sector, 128 void *fit, ulong base_offset, int node, 129 struct spl_image_info *image_info) 130 { 131 ulong offset; 132 size_t length; 133 ulong load_addr, load_ptr; 134 void *src; 135 ulong overhead; 136 int nr_sectors; 137 int align_len = ARCH_DMA_MINALIGN - 1; 138 139 offset = fdt_getprop_u32(fit, node, "data-offset"); 140 if (offset == FDT_ERROR) 141 return -ENOENT; 142 offset += base_offset; 143 length = fdt_getprop_u32(fit, node, "data-size"); 144 if (length == FDT_ERROR) 145 return -ENOENT; 146 load_addr = fdt_getprop_u32(fit, node, "load"); 147 if (load_addr == FDT_ERROR && image_info) 148 load_addr = image_info->load_addr; 149 load_ptr = (load_addr + align_len) & ~align_len; 150 151 overhead = get_aligned_image_overhead(info, offset); 152 nr_sectors = get_aligned_image_size(info, length, offset); 153 154 if (info->read(info, sector + get_aligned_image_offset(info, offset), 155 nr_sectors, (void*)load_ptr) != nr_sectors) 156 return -EIO; 157 debug("image: dst=%lx, offset=%lx, size=%lx\n", load_ptr, offset, 158 (unsigned long)length); 159 160 src = (void *)load_ptr + overhead; 161 #ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS 162 board_fit_image_post_process(&src, &length); 163 #endif 164 165 memcpy((void*)load_addr, src, length); 166 167 if (image_info) { 168 image_info->load_addr = load_addr; 169 image_info->size = length; 170 image_info->entry_point = fdt_getprop_u32(fit, node, "entry"); 171 } 172 173 return 0; 174 } 175 176 int spl_load_simple_fit(struct spl_image_info *spl_image, 177 struct spl_load_info *info, ulong sector, void *fit) 178 { 179 int sectors; 180 ulong size; 181 unsigned long count; 182 struct spl_image_info image_info; 183 int node, images, ret; 184 int base_offset, align_len = ARCH_DMA_MINALIGN - 1; 185 int index = 0; 186 187 /* 188 * Figure out where the external images start. This is the base for the 189 * data-offset properties in each image. 190 */ 191 size = fdt_totalsize(fit); 192 size = (size + 3) & ~3; 193 base_offset = (size + 3) & ~3; 194 195 /* 196 * So far we only have one block of data from the FIT. Read the entire 197 * thing, including that first block, placing it so it finishes before 198 * where we will load the image. 199 * 200 * Note that we will load the image such that its first byte will be 201 * at the load address. Since that byte may be part-way through a 202 * block, we may load the image up to one block before the load 203 * address. So take account of that here by subtracting an addition 204 * block length from the FIT start position. 205 * 206 * In fact the FIT has its own load address, but we assume it cannot 207 * be before CONFIG_SYS_TEXT_BASE. 208 */ 209 fit = (void *)((CONFIG_SYS_TEXT_BASE - size - info->bl_len - 210 align_len) & ~align_len); 211 sectors = get_aligned_image_size(info, size, 0); 212 count = info->read(info, sector, sectors, fit); 213 debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n", 214 sector, sectors, fit, count); 215 if (count == 0) 216 return -EIO; 217 218 /* find the node holding the images information */ 219 images = fdt_path_offset(fit, FIT_IMAGES_PATH); 220 if (images < 0) { 221 debug("%s: Cannot find /images node: %d\n", __func__, images); 222 return -1; 223 } 224 225 /* find the U-Boot image */ 226 node = spl_fit_get_image_node(fit, images, "firmware", 0); 227 if (node < 0) { 228 debug("could not find firmware image, trying loadables...\n"); 229 node = spl_fit_get_image_node(fit, images, "loadables", 0); 230 /* 231 * If we pick the U-Boot image from "loadables", start at 232 * the second image when later loading additional images. 233 */ 234 index = 1; 235 } 236 if (node < 0) { 237 debug("%s: Cannot find u-boot image node: %d\n", 238 __func__, node); 239 return -1; 240 } 241 242 /* Load the image and set up the spl_image structure */ 243 ret = spl_load_fit_image(info, sector, fit, base_offset, node, 244 spl_image); 245 if (ret) 246 return ret; 247 248 spl_image->os = IH_OS_U_BOOT; 249 250 /* Figure out which device tree the board wants to use */ 251 node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0); 252 if (node < 0) { 253 debug("%s: cannot find FDT node\n", __func__); 254 return node; 255 } 256 257 /* 258 * Read the device tree and place it after the image. 259 * Align the destination address to ARCH_DMA_MINALIGN. 260 */ 261 image_info.load_addr = spl_image->load_addr + spl_image->size; 262 ret = spl_load_fit_image(info, sector, fit, base_offset, node, 263 &image_info); 264 if (ret < 0) 265 return ret; 266 267 /* Now check if there are more images for us to load */ 268 for (; ; index++) { 269 node = spl_fit_get_image_node(fit, images, "loadables", index); 270 if (node < 0) 271 break; 272 273 ret = spl_load_fit_image(info, sector, fit, base_offset, node, 274 &image_info); 275 if (ret < 0) 276 continue; 277 278 /* 279 * If the "firmware" image did not provide an entry point, 280 * use the first valid entry point from the loadables. 281 */ 282 if (spl_image->entry_point == FDT_ERROR && 283 image_info.entry_point != FDT_ERROR) 284 spl_image->entry_point = image_info.entry_point; 285 } 286 287 /* 288 * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's 289 * Makefile will set it to 0 and it will end up as the entry point 290 * here. What it actually means is: use the load address. 291 */ 292 if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0) 293 spl_image->entry_point = spl_image->load_addr; 294 295 return 0; 296 } 297