mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-16 01:44:34 +00:00

read could be a negative error value but size in spl_image is unsigned so when they are compared read is used as if it's a unsigned value and if it's negative it'll most likely be bigger than size and the result will be true and _spl_load() will return 0 to the caller. This results in the caller to _spl_load() not seeing that an error happened as it should and continuing as if the load was completed when it might not have been. Check if read is negative and return it's value if it is before comparing against size in spl_image. Signed-off-by: Daniel Palmer <daniel@0x0f.com> Reviewed-by: Simon Glass <sjg@chromium.org>
148 lines
4.9 KiB
C
148 lines
4.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/*
|
|
* Copyright (C) Sean Anderson <seanga2@gmail.com>
|
|
*/
|
|
#ifndef _SPL_LOAD_H_
|
|
#define _SPL_LOAD_H_
|
|
|
|
#include <image.h>
|
|
#include <imx_container.h>
|
|
#include <mapmem.h>
|
|
#include <spl.h>
|
|
|
|
static inline int _spl_load(struct spl_image_info *spl_image,
|
|
const struct spl_boot_device *bootdev,
|
|
struct spl_load_info *info, size_t size,
|
|
size_t offset)
|
|
{
|
|
struct legacy_img_hdr *header =
|
|
spl_get_load_buffer(-sizeof(*header), sizeof(*header));
|
|
ulong base_offset, image_offset, overhead;
|
|
int read, ret;
|
|
|
|
read = info->read(info, offset, ALIGN(sizeof(*header),
|
|
spl_get_bl_len(info)), header);
|
|
if (read < (int)sizeof(*header))
|
|
return -EIO;
|
|
|
|
if (image_get_magic(header) == FDT_MAGIC) {
|
|
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL)) {
|
|
void *buf;
|
|
|
|
/*
|
|
* In order to support verifying images in the FIT, we
|
|
* need to load the whole FIT into memory. Try and
|
|
* guess how much we need to load by using the total
|
|
* size. This will fail for FITs with external data,
|
|
* but there's not much we can do about that.
|
|
*/
|
|
if (!size)
|
|
size = round_up(fdt_totalsize(header), 4);
|
|
buf = map_sysmem(CONFIG_SYS_LOAD_ADDR, size);
|
|
read = info->read(info, offset,
|
|
ALIGN(size, spl_get_bl_len(info)),
|
|
buf);
|
|
if (read < size)
|
|
return -EIO;
|
|
|
|
return spl_parse_image_header(spl_image, bootdev, buf);
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT))
|
|
return spl_load_simple_fit(spl_image, info, offset,
|
|
header);
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) &&
|
|
valid_container_hdr((void *)header))
|
|
return spl_load_imx_container(spl_image, info, offset);
|
|
|
|
if (IS_ENABLED(CONFIG_SPL_LZMA) &&
|
|
image_get_magic(header) == IH_MAGIC &&
|
|
image_get_comp(header) == IH_COMP_LZMA) {
|
|
spl_image->flags |= SPL_COPY_PAYLOAD_ONLY;
|
|
ret = spl_parse_image_header(spl_image, bootdev, header);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return spl_load_legacy_lzma(spl_image, info, offset);
|
|
}
|
|
|
|
ret = spl_parse_image_header(spl_image, bootdev, header);
|
|
if (ret)
|
|
return ret;
|
|
|
|
base_offset = spl_image->offset;
|
|
/* Only NOR sets this flag. */
|
|
if (IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) &&
|
|
spl_image->flags & SPL_COPY_PAYLOAD_ONLY)
|
|
base_offset += sizeof(*header);
|
|
image_offset = ALIGN_DOWN(base_offset, spl_get_bl_len(info));
|
|
overhead = base_offset - image_offset;
|
|
size = ALIGN(spl_image->size + overhead, spl_get_bl_len(info));
|
|
|
|
read = info->read(info, offset + image_offset, size,
|
|
map_sysmem(spl_image->load_addr - overhead, size));
|
|
|
|
if (read < 0)
|
|
return read;
|
|
|
|
return read < spl_image->size ? -EIO : 0;
|
|
}
|
|
|
|
/*
|
|
* Although spl_load results in size reduction for callers, this is generally
|
|
* not enough to counteract the bloat if there is only one caller. The core
|
|
* problem is that the compiler can't optimize across translation units. The
|
|
* general solution to this is CONFIG_LTO, but that is not available on all
|
|
* architectures. Perform a pseudo-LTO just for this function by declaring it
|
|
* inline if there is one caller, and extern otherwise.
|
|
*/
|
|
#define SPL_LOAD_USERS \
|
|
IS_ENABLED(CONFIG_SPL_BLK_FS) + \
|
|
IS_ENABLED(CONFIG_SPL_FS_EXT4) + \
|
|
IS_ENABLED(CONFIG_SPL_FS_FAT) + \
|
|
IS_ENABLED(CONFIG_SPL_SYS_MMCSD_RAW_MODE) + \
|
|
(IS_ENABLED(CONFIG_SPL_NAND_SUPPORT) && !IS_ENABLED(CONFIG_SPL_UBI)) + \
|
|
IS_ENABLED(CONFIG_SPL_NET) + \
|
|
IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) + \
|
|
IS_ENABLED(CONFIG_SPL_SEMIHOSTING) + \
|
|
IS_ENABLED(CONFIG_SPL_SPI_LOAD) + \
|
|
0
|
|
|
|
#if SPL_LOAD_USERS > 1
|
|
/**
|
|
* spl_load() - Parse a header and load the image
|
|
* @spl_image: Image data which will be filled in by this function
|
|
* @bootdev: The device to load from
|
|
* @info: Describes how to load additional information from @bootdev. At the
|
|
* minimum, read() and bl_len must be populated.
|
|
* @size: The size of the image, in bytes, if it is known in advance. Some boot
|
|
* devices (such as filesystems) know how big an image is before parsing
|
|
* the header. If 0, then the size will be determined from the header.
|
|
* @offset: The offset from the start of @bootdev, in bytes. This should have
|
|
* the offset @header was loaded from. It will be added to any offsets
|
|
* passed to @info->read().
|
|
*
|
|
* This function determines the image type (FIT, legacy, i.MX, raw, etc), calls
|
|
* the appropriate parsing function, determines the load address, and the loads
|
|
* the image from storage. It is designed to replace ad-hoc image loading which
|
|
* may not support all image types (especially when config options are
|
|
* involved).
|
|
*
|
|
* Return: 0 on success, or a negative error on failure
|
|
*/
|
|
int spl_load(struct spl_image_info *spl_image,
|
|
const struct spl_boot_device *bootdev, struct spl_load_info *info,
|
|
size_t size, size_t offset);
|
|
#else
|
|
static inline int spl_load(struct spl_image_info *spl_image,
|
|
const struct spl_boot_device *bootdev,
|
|
struct spl_load_info *info, size_t size,
|
|
size_t offset)
|
|
{
|
|
return _spl_load(spl_image, bootdev, info, size, offset);
|
|
}
|
|
#endif
|
|
|
|
#endif /* _SPL_LOAD_H_ */
|