uboot/common/spl/spl_fit.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2016 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 */
   6
   7#include <common.h>
   8#include <errno.h>
   9#include <image.h>
  10#include <linux/libfdt.h>
  11#include <spl.h>
  12
  13#ifndef CONFIG_SYS_BOOTM_LEN
  14#define CONFIG_SYS_BOOTM_LEN    (64 << 20)
  15#endif
  16
  17/**
  18 * spl_fit_get_image_name(): By using the matching configuration subnode,
  19 * retrieve the name of an image, specified by a property name and an index
  20 * into that.
  21 * @fit:        Pointer to the FDT blob.
  22 * @images:     Offset of the /images subnode.
  23 * @type:       Name of the property within the configuration subnode.
  24 * @index:      Index into the list of strings in this property.
  25 * @outname:    Name of the image
  26 *
  27 * Return:      0 on success, or a negative error number
  28 */
  29static int spl_fit_get_image_name(const void *fit, int images,
  30                                  const char *type, int index,
  31                                  char **outname)
  32{
  33        const char *name, *str;
  34        __maybe_unused int node;
  35        int conf_node;
  36        int len, i;
  37
  38        conf_node = fit_find_config_node(fit);
  39        if (conf_node < 0) {
  40#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
  41                printf("No matching DT out of these options:\n");
  42                for (node = fdt_first_subnode(fit, conf_node);
  43                     node >= 0;
  44                     node = fdt_next_subnode(fit, node)) {
  45                        name = fdt_getprop(fit, node, "description", &len);
  46                        printf("   %s\n", name);
  47                }
  48#endif
  49                return conf_node;
  50        }
  51
  52        name = fdt_getprop(fit, conf_node, type, &len);
  53        if (!name) {
  54                debug("cannot find property '%s': %d\n", type, len);
  55                return -EINVAL;
  56        }
  57
  58        str = name;
  59        for (i = 0; i < index; i++) {
  60                str = strchr(str, '\0') + 1;
  61                if (!str || (str - name >= len)) {
  62                        debug("no string for index %d\n", index);
  63                        return -E2BIG;
  64                }
  65        }
  66
  67        *outname = (char *)str;
  68        return 0;
  69}
  70
  71/**
  72 * spl_fit_get_image_node(): By using the matching configuration subnode,
  73 * retrieve the name of an image, specified by a property name and an index
  74 * into that.
  75 * @fit:        Pointer to the FDT blob.
  76 * @images:     Offset of the /images subnode.
  77 * @type:       Name of the property within the configuration subnode.
  78 * @index:      Index into the list of strings in this property.
  79 *
  80 * Return:      the node offset of the respective image node or a negative
  81 *              error number.
  82 */
  83static int spl_fit_get_image_node(const void *fit, int images,
  84                                  const char *type, int index)
  85{
  86        char *str;
  87        int err;
  88        int node;
  89
  90        err = spl_fit_get_image_name(fit, images, type, index, &str);
  91        if (err)
  92                return err;
  93
  94        debug("%s: '%s'\n", type, str);
  95
  96        node = fdt_subnode_offset(fit, images, str);
  97        if (node < 0) {
  98                debug("cannot find image node '%s': %d\n", str, node);
  99                return -EINVAL;
 100        }
 101
 102        return node;
 103}
 104
 105static int get_aligned_image_offset(struct spl_load_info *info, int offset)
 106{
 107        /*
 108         * If it is a FS read, get the first address before offset which is
 109         * aligned to ARCH_DMA_MINALIGN. If it is raw read return the
 110         * block number to which offset belongs.
 111         */
 112        if (info->filename)
 113                return offset & ~(ARCH_DMA_MINALIGN - 1);
 114
 115        return offset / info->bl_len;
 116}
 117
 118static int get_aligned_image_overhead(struct spl_load_info *info, int offset)
 119{
 120        /*
 121         * If it is a FS read, get the difference between the offset and
 122         * the first address before offset which is aligned to
 123         * ARCH_DMA_MINALIGN. If it is raw read return the offset within the
 124         * block.
 125         */
 126        if (info->filename)
 127                return offset & (ARCH_DMA_MINALIGN - 1);
 128
 129        return offset % info->bl_len;
 130}
 131
 132static int get_aligned_image_size(struct spl_load_info *info, int data_size,
 133                                  int offset)
 134{
 135        data_size = data_size + get_aligned_image_overhead(info, offset);
 136
 137        if (info->filename)
 138                return data_size;
 139
 140        return (data_size + info->bl_len - 1) / info->bl_len;
 141}
 142
 143#ifdef CONFIG_SPL_FPGA_SUPPORT
 144__weak int spl_load_fpga_image(struct spl_load_info *info, size_t length,
 145                               int nr_sectors, int sector_offset)
 146{
 147        return 0;
 148}
 149#endif
 150
 151/**
 152 * spl_load_fit_image(): load the image described in a certain FIT node
 153 * @info:       points to information about the device to load data from
 154 * @sector:     the start sector of the FIT image on the device
 155 * @fit:        points to the flattened device tree blob describing the FIT
 156 *              image
 157 * @base_offset: the beginning of the data area containing the actual
 158 *              image data, relative to the beginning of the FIT
 159 * @node:       offset of the DT node describing the image to load (relative
 160 *              to @fit)
 161 * @image_info: will be filled with information about the loaded image
 162 *              If the FIT node does not contain a "load" (address) property,
 163 *              the image gets loaded to the address pointed to by the
 164 *              load_addr member in this struct.
 165 *
 166 * Return:      0 on success or a negative error number.
 167 */
 168static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
 169                              void *fit, ulong base_offset, int node,
 170                              struct spl_image_info *image_info)
 171{
 172        int offset, sector_offset;
 173        size_t length;
 174        int len;
 175        ulong size;
 176        ulong load_addr, load_ptr;
 177        void *src;
 178        ulong overhead;
 179        int nr_sectors;
 180        int align_len = ARCH_DMA_MINALIGN - 1;
 181        uint8_t image_comp = -1, type = -1;
 182        const void *data;
 183        bool external_data = false;
 184
 185        if (IS_ENABLED(CONFIG_SPL_FPGA_SUPPORT) ||
 186            (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP))) {
 187                if (fit_image_get_type(fit, node, &type))
 188                        puts("Cannot get image type.\n");
 189                else
 190                        debug("%s ", genimg_get_type_name(type));
 191        }
 192
 193        if (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP)) {
 194                if (fit_image_get_comp(fit, node, &image_comp))
 195                        puts("Cannot get image compression format.\n");
 196                else
 197                        debug("%s ", genimg_get_comp_name(image_comp));
 198        }
 199
 200        if (fit_image_get_load(fit, node, &load_addr))
 201                load_addr = image_info->load_addr;
 202
 203        if (!fit_image_get_data_position(fit, node, &offset)) {
 204                external_data = true;
 205        } else if (!fit_image_get_data_offset(fit, node, &offset)) {
 206                offset += base_offset;
 207                external_data = true;
 208        }
 209
 210        if (external_data) {
 211                /* External data */
 212                if (fit_image_get_data_size(fit, node, &len))
 213                        return -ENOENT;
 214
 215                load_ptr = (load_addr + align_len) & ~align_len;
 216                length = len;
 217
 218                overhead = get_aligned_image_overhead(info, offset);
 219                nr_sectors = get_aligned_image_size(info, length, offset);
 220                sector_offset = sector + get_aligned_image_offset(info, offset);
 221
 222#ifdef CONFIG_SPL_FPGA_SUPPORT
 223                if (type == IH_TYPE_FPGA) {
 224                        return spl_load_fpga_image(info, length, nr_sectors,
 225                                                   sector_offset);
 226                }
 227#endif
 228
 229                if (info->read(info, sector_offset,
 230                               nr_sectors, (void *)load_ptr) != nr_sectors)
 231                        return -EIO;
 232
 233                debug("External data: dst=%lx, offset=%x, size=%lx\n",
 234                      load_ptr, offset, (unsigned long)length);
 235                src = (void *)load_ptr + overhead;
 236        } else {
 237                /* Embedded data */
 238                if (fit_image_get_data(fit, node, &data, &length)) {
 239                        puts("Cannot get image data/size\n");
 240                        return -ENOENT;
 241                }
 242                debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
 243                      (unsigned long)length);
 244                src = (void *)data;
 245        }
 246
 247#ifdef CONFIG_SPL_FIT_SIGNATURE
 248        printf("## Checking hash(es) for Image %s ... ",
 249               fit_get_name(fit, node, NULL));
 250        if (!fit_image_verify_with_data(fit, node,
 251                                         src, length))
 252                return -EPERM;
 253        puts("OK\n");
 254#endif
 255
 256#ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
 257        board_fit_image_post_process(&src, &length);
 258#endif
 259
 260        if (IS_ENABLED(CONFIG_SPL_OS_BOOT)      &&
 261            IS_ENABLED(CONFIG_SPL_GZIP)         &&
 262            image_comp == IH_COMP_GZIP          &&
 263            type == IH_TYPE_KERNEL) {
 264                size = length;
 265                if (gunzip((void *)load_addr, CONFIG_SYS_BOOTM_LEN,
 266                           src, &size)) {
 267                        puts("Uncompressing error\n");
 268                        return -EIO;
 269                }
 270                length = size;
 271        } else {
 272                memcpy((void *)load_addr, src, length);
 273        }
 274
 275        if (image_info) {
 276                image_info->load_addr = load_addr;
 277                image_info->size = length;
 278                image_info->entry_point = fdt_getprop_u32(fit, node, "entry");
 279        }
 280
 281        return 0;
 282}
 283
 284static int spl_fit_append_fdt(struct spl_image_info *spl_image,
 285                              struct spl_load_info *info, ulong sector,
 286                              void *fit, int images, ulong base_offset)
 287{
 288        struct spl_image_info image_info;
 289        int node, ret;
 290
 291        /* Figure out which device tree the board wants to use */
 292        node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0);
 293        if (node < 0) {
 294                debug("%s: cannot find FDT node\n", __func__);
 295                return node;
 296        }
 297
 298        /*
 299         * Read the device tree and place it after the image.
 300         * Align the destination address to ARCH_DMA_MINALIGN.
 301         */
 302        image_info.load_addr = spl_image->load_addr + spl_image->size;
 303        ret = spl_load_fit_image(info, sector, fit, base_offset, node,
 304                                 &image_info);
 305
 306        if (ret < 0)
 307                return ret;
 308
 309        /* Make the load-address of the FDT available for the SPL framework */
 310        spl_image->fdt_addr = (void *)image_info.load_addr;
 311#if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY)
 312        /* Try to make space, so we can inject details on the loadables */
 313        ret = fdt_shrink_to_minimum(spl_image->fdt_addr, 8192);
 314#endif
 315
 316        return ret;
 317}
 318
 319static int spl_fit_record_loadable(const void *fit, int images, int index,
 320                                   void *blob, struct spl_image_info *image)
 321{
 322        int ret = 0;
 323#if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY)
 324        char *name;
 325        int node;
 326
 327        ret = spl_fit_get_image_name(fit, images, "loadables",
 328                                     index, &name);
 329        if (ret < 0)
 330                return ret;
 331
 332        node = spl_fit_get_image_node(fit, images, "loadables", index);
 333
 334        ret = fdt_record_loadable(blob, index, name, image->load_addr,
 335                                  image->size, image->entry_point,
 336                                  fdt_getprop(fit, node, "type", NULL),
 337                                  fdt_getprop(fit, node, "os", NULL));
 338#endif
 339        return ret;
 340}
 341
 342static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os)
 343{
 344#if CONFIG_IS_ENABLED(FIT_IMAGE_TINY)
 345        return -ENOTSUPP;
 346#else
 347        return fit_image_get_os(fit, noffset, os);
 348#endif
 349}
 350
 351int spl_load_simple_fit(struct spl_image_info *spl_image,
 352                        struct spl_load_info *info, ulong sector, void *fit)
 353{
 354        int sectors;
 355        ulong size;
 356        unsigned long count;
 357        struct spl_image_info image_info;
 358        int node = -1;
 359        int images, ret;
 360        int base_offset, align_len = ARCH_DMA_MINALIGN - 1;
 361        int index = 0;
 362
 363        /*
 364         * For FIT with external data, figure out where the external images
 365         * start. This is the base for the data-offset properties in each
 366         * image.
 367         */
 368        size = fdt_totalsize(fit);
 369        size = (size + 3) & ~3;
 370        base_offset = (size + 3) & ~3;
 371
 372        /*
 373         * So far we only have one block of data from the FIT. Read the entire
 374         * thing, including that first block, placing it so it finishes before
 375         * where we will load the image.
 376         *
 377         * Note that we will load the image such that its first byte will be
 378         * at the load address. Since that byte may be part-way through a
 379         * block, we may load the image up to one block before the load
 380         * address. So take account of that here by subtracting an addition
 381         * block length from the FIT start position.
 382         *
 383         * In fact the FIT has its own load address, but we assume it cannot
 384         * be before CONFIG_SYS_TEXT_BASE.
 385         *
 386         * For FIT with data embedded, data is loaded as part of FIT image.
 387         * For FIT with external data, data is not loaded in this step.
 388         */
 389        fit = (void *)((CONFIG_SYS_TEXT_BASE - size - info->bl_len -
 390                        align_len) & ~align_len);
 391        sectors = get_aligned_image_size(info, size, 0);
 392        count = info->read(info, sector, sectors, fit);
 393        debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n",
 394              sector, sectors, fit, count);
 395        if (count == 0)
 396                return -EIO;
 397
 398        /* find the node holding the images information */
 399        images = fdt_path_offset(fit, FIT_IMAGES_PATH);
 400        if (images < 0) {
 401                debug("%s: Cannot find /images node: %d\n", __func__, images);
 402                return -1;
 403        }
 404
 405#ifdef CONFIG_SPL_FPGA_SUPPORT
 406        node = spl_fit_get_image_node(fit, images, "fpga", 0);
 407        if (node >= 0) {
 408                /* Load the image and set up the spl_image structure */
 409                ret = spl_load_fit_image(info, sector, fit, base_offset, node,
 410                                         spl_image);
 411                if (ret) {
 412                        printf("%s: Cannot load the FPGA: %i\n", __func__, ret);
 413                        return ret;
 414                }
 415                puts("FPGA image loaded from FIT\n");
 416                node = -1;
 417        }
 418#endif
 419
 420        /*
 421         * Find the U-Boot image using the following search order:
 422         *   - start at 'firmware' (e.g. an ARM Trusted Firmware)
 423         *   - fall back 'kernel' (e.g. a Falcon-mode OS boot
 424         *   - fall back to using the first 'loadables' entry
 425         */
 426        if (node < 0)
 427                node = spl_fit_get_image_node(fit, images, FIT_FIRMWARE_PROP,
 428                                              0);
 429#ifdef CONFIG_SPL_OS_BOOT
 430        if (node < 0)
 431                node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0);
 432#endif
 433        if (node < 0) {
 434                debug("could not find firmware image, trying loadables...\n");
 435                node = spl_fit_get_image_node(fit, images, "loadables", 0);
 436                /*
 437                 * If we pick the U-Boot image from "loadables", start at
 438                 * the second image when later loading additional images.
 439                 */
 440                index = 1;
 441        }
 442        if (node < 0) {
 443                debug("%s: Cannot find u-boot image node: %d\n",
 444                      __func__, node);
 445                return -1;
 446        }
 447
 448        /* Load the image and set up the spl_image structure */
 449        ret = spl_load_fit_image(info, sector, fit, base_offset, node,
 450                                 spl_image);
 451        if (ret)
 452                return ret;
 453
 454        /*
 455         * For backward compatibility, we treat the first node that is
 456         * as a U-Boot image, if no OS-type has been declared.
 457         */
 458        if (!spl_fit_image_get_os(fit, node, &spl_image->os))
 459                debug("Image OS is %s\n", genimg_get_os_name(spl_image->os));
 460#if !defined(CONFIG_SPL_OS_BOOT)
 461        else
 462                spl_image->os = IH_OS_U_BOOT;
 463#endif
 464
 465        /*
 466         * Booting a next-stage U-Boot may require us to append the FDT.
 467         * We allow this to fail, as the U-Boot image might embed its FDT.
 468         */
 469        if (spl_image->os == IH_OS_U_BOOT)
 470                spl_fit_append_fdt(spl_image, info, sector, fit,
 471                                   images, base_offset);
 472
 473        /* Now check if there are more images for us to load */
 474        for (; ; index++) {
 475                uint8_t os_type = IH_OS_INVALID;
 476
 477                node = spl_fit_get_image_node(fit, images, "loadables", index);
 478                if (node < 0)
 479                        break;
 480
 481                ret = spl_load_fit_image(info, sector, fit, base_offset, node,
 482                                         &image_info);
 483                if (ret < 0)
 484                        continue;
 485
 486                if (!spl_fit_image_get_os(fit, node, &os_type))
 487                        debug("Loadable is %s\n", genimg_get_os_name(os_type));
 488
 489                if (os_type == IH_OS_U_BOOT) {
 490                        spl_fit_append_fdt(&image_info, info, sector,
 491                                           fit, images, base_offset);
 492                        spl_image->fdt_addr = image_info.fdt_addr;
 493                }
 494
 495                /*
 496                 * If the "firmware" image did not provide an entry point,
 497                 * use the first valid entry point from the loadables.
 498                 */
 499                if (spl_image->entry_point == FDT_ERROR &&
 500                    image_info.entry_point != FDT_ERROR)
 501                        spl_image->entry_point = image_info.entry_point;
 502
 503                /* Record our loadables into the FDT */
 504                if (spl_image->fdt_addr)
 505                        spl_fit_record_loadable(fit, images, index,
 506                                                spl_image->fdt_addr,
 507                                                &image_info);
 508        }
 509
 510        /*
 511         * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's
 512         * Makefile will set it to 0 and it will end up as the entry point
 513         * here. What it actually means is: use the load address.
 514         */
 515        if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0)
 516                spl_image->entry_point = spl_image->load_addr;
 517
 518        return 0;
 519}
 520