image: Introduce fit_image_load() to load images from FITs
At present code to load an image from a FIT is duplicated in the three places where it is needed (kernel, fdt, ramdisk). The differences between these different code copies is fairly minor. Create a new function in the fit code which can handle any of the requirements of those cases. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
2434c66da0
commit
782cfbb259
@ -31,6 +31,9 @@
|
||||
#include <time.h>
|
||||
#else
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <asm/io.h>
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
#endif /* !USE_HOSTCC*/
|
||||
|
||||
#include <bootstage.h>
|
||||
@ -1448,6 +1451,22 @@ void fit_conf_print(const void *fit, int noffset, const char *p)
|
||||
printf("%s FDT: %s\n", p, uname);
|
||||
}
|
||||
|
||||
int fit_image_select(const void *fit, int rd_noffset, int verify)
|
||||
{
|
||||
fit_image_print(fit, rd_noffset, " ");
|
||||
|
||||
if (verify) {
|
||||
puts(" Verifying Hash Integrity ... ");
|
||||
if (!fit_image_verify(fit, rd_noffset)) {
|
||||
puts("Bad Data Hash\n");
|
||||
return -EACCES;
|
||||
}
|
||||
puts("OK\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_check_ramdisk - verify FIT format ramdisk subimage
|
||||
* @fit_hdr: pointer to the FIT ramdisk header
|
||||
@ -1490,3 +1509,215 @@ int fit_check_ramdisk(const void *fit, int rd_noffset, uint8_t arch,
|
||||
bootstage_mark(BOOTSTAGE_ID_FIT_RD_CHECK_ALL_OK);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fit_get_node_from_config(bootm_headers_t *images, const char *prop_name,
|
||||
ulong addr)
|
||||
{
|
||||
int cfg_noffset;
|
||||
void *fit_hdr;
|
||||
int noffset;
|
||||
|
||||
debug("* %s: using config '%s' from image at 0x%08lx\n",
|
||||
prop_name, images->fit_uname_cfg, addr);
|
||||
|
||||
/* Check whether configuration has this property defined */
|
||||
fit_hdr = map_sysmem(addr, 0);
|
||||
cfg_noffset = fit_conf_get_node(fit_hdr, images->fit_uname_cfg);
|
||||
if (cfg_noffset < 0) {
|
||||
debug("* %s: no such config\n", prop_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
noffset = fit_conf_get_prop_node(fit_hdr, cfg_noffset, prop_name);
|
||||
if (noffset < 0) {
|
||||
debug("* %s: no '%s' in config\n", prop_name, prop_name);
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
||||
return noffset;
|
||||
}
|
||||
|
||||
int fit_image_load(bootm_headers_t *images, const char *prop_name, ulong addr,
|
||||
const char **fit_unamep, const char *fit_uname_config,
|
||||
int arch, int image_type, int bootstage_id,
|
||||
enum fit_load_op load_op, ulong *datap, ulong *lenp)
|
||||
{
|
||||
int cfg_noffset, noffset;
|
||||
const char *fit_uname;
|
||||
const void *fit;
|
||||
const void *buf;
|
||||
size_t size;
|
||||
int type_ok, os_ok;
|
||||
ulong load, data, len;
|
||||
int ret;
|
||||
|
||||
fit = map_sysmem(addr, 0);
|
||||
fit_uname = fit_unamep ? *fit_unamep : NULL;
|
||||
printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
|
||||
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT);
|
||||
if (!fit_check_format(fit)) {
|
||||
printf("Bad FIT %s image format!\n", prop_name);
|
||||
bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK);
|
||||
if (fit_uname) {
|
||||
/* get ramdisk component image node offset */
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_UNIT_NAME);
|
||||
noffset = fit_image_get_node(fit, fit_uname);
|
||||
} else {
|
||||
/*
|
||||
* no image node unit name, try to get config
|
||||
* node first. If config unit node name is NULL
|
||||
* fit_conf_get_node() will try to find default config node
|
||||
*/
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_NO_UNIT_NAME);
|
||||
if (IMAGE_ENABLE_BEST_MATCH && !fit_uname_config) {
|
||||
cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob());
|
||||
} else {
|
||||
cfg_noffset = fit_conf_get_node(fit,
|
||||
fit_uname_config);
|
||||
}
|
||||
if (cfg_noffset < 0) {
|
||||
puts("Could not find configuration node\n");
|
||||
bootstage_error(bootstage_id +
|
||||
BOOTSTAGE_SUB_NO_UNIT_NAME);
|
||||
return -ENOENT;
|
||||
}
|
||||
fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
|
||||
printf(" Using '%s' configuration\n", fit_uname_config);
|
||||
if (image_type == IH_TYPE_KERNEL) {
|
||||
/* Remember (and possibly verify) this config */
|
||||
images->fit_uname_cfg = fit_uname_config;
|
||||
if (IMAGE_ENABLE_VERIFY && images->verify) {
|
||||
puts(" Verifying Hash Integrity ... ");
|
||||
if (!fit_config_verify(fit, cfg_noffset)) {
|
||||
puts("Bad Data Hash\n");
|
||||
bootstage_error(bootstage_id +
|
||||
BOOTSTAGE_SUB_HASH);
|
||||
return -EACCES;
|
||||
}
|
||||
puts("OK\n");
|
||||
}
|
||||
bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG);
|
||||
}
|
||||
|
||||
noffset = fit_conf_get_prop_node(fit, cfg_noffset,
|
||||
prop_name);
|
||||
fit_uname = fit_get_name(fit, noffset, NULL);
|
||||
}
|
||||
if (noffset < 0) {
|
||||
puts("Could not find subimage node\n");
|
||||
bootstage_error(bootstage_id + BOOTSTAGE_SUB_SUBNODE);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
printf(" Trying '%s' %s subimage\n", fit_uname, prop_name);
|
||||
|
||||
ret = fit_image_select(fit, noffset, images->verify);
|
||||
if (ret) {
|
||||
bootstage_error(bootstage_id + BOOTSTAGE_SUB_HASH);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
|
||||
if (!fit_image_check_target_arch(fit, noffset)) {
|
||||
puts("Unsupported Architecture\n");
|
||||
bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
if (image_type == IH_TYPE_FLATDT &&
|
||||
!fit_image_check_comp(fit, noffset, IH_COMP_NONE)) {
|
||||
puts("FDT image is compressed");
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
|
||||
type_ok = fit_image_check_type(fit, noffset, image_type) ||
|
||||
(image_type == IH_TYPE_KERNEL &&
|
||||
fit_image_check_type(fit, noffset,
|
||||
IH_TYPE_KERNEL_NOLOAD));
|
||||
os_ok = image_type == IH_TYPE_FLATDT ||
|
||||
fit_image_check_os(fit, noffset, IH_OS_LINUX);
|
||||
if (!type_ok || !os_ok) {
|
||||
printf("No Linux %s %s Image\n", genimg_get_arch_name(arch),
|
||||
genimg_get_type_name(image_type));
|
||||
bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK);
|
||||
|
||||
/* get image data address and length */
|
||||
if (fit_image_get_data(fit, noffset, &buf, &size)) {
|
||||
printf("Could not find %s subimage data!\n", prop_name);
|
||||
bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA);
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
len = (ulong)size;
|
||||
|
||||
/* verify that image data is a proper FDT blob */
|
||||
if (image_type == IH_TYPE_FLATDT && fdt_check_header((char *)buf)) {
|
||||
puts("Subimage data is not a FDT");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK);
|
||||
|
||||
/*
|
||||
* Work-around for eldk-4.2 which gives this warning if we try to
|
||||
* case in the unmap_sysmem() call:
|
||||
* warning: initialization discards qualifiers from pointer target type
|
||||
*/
|
||||
{
|
||||
void *vbuf = (void *)buf;
|
||||
|
||||
data = map_to_sysmem(vbuf);
|
||||
}
|
||||
|
||||
if (load_op == FIT_LOAD_IGNORED) {
|
||||
/* Don't load */
|
||||
} else if (fit_image_get_load(fit, noffset, &load)) {
|
||||
if (load_op == FIT_LOAD_REQUIRED) {
|
||||
printf("Can't get %s subimage load address!\n",
|
||||
prop_name);
|
||||
bootstage_error(bootstage_id + BOOTSTAGE_SUB_LOAD);
|
||||
return -EBADF;
|
||||
}
|
||||
} else {
|
||||
ulong image_start, image_end;
|
||||
ulong load_end;
|
||||
void *dst;
|
||||
|
||||
/*
|
||||
* move image data to the load address,
|
||||
* make sure we don't overwrite initial image
|
||||
*/
|
||||
image_start = addr;
|
||||
image_end = addr + fit_get_size(fit);
|
||||
|
||||
load_end = load + len;
|
||||
if (image_type != IH_TYPE_KERNEL &&
|
||||
load < image_end && load_end > image_start) {
|
||||
printf("Error: %s overwritten\n", prop_name);
|
||||
return -EXDEV;
|
||||
}
|
||||
|
||||
printf(" Loading %s from 0x%08lx to 0x%08lx\n",
|
||||
prop_name, data, load);
|
||||
|
||||
dst = map_sysmem(load, len);
|
||||
memmove(dst, buf, len);
|
||||
data = load;
|
||||
}
|
||||
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD);
|
||||
|
||||
*datap = data;
|
||||
*lenp = len;
|
||||
if (fit_unamep)
|
||||
*fit_unamep = (char *)fit_uname;
|
||||
|
||||
return noffset;
|
||||
}
|
||||
|
@ -402,6 +402,13 @@ void genimg_print_size(uint32_t size);
|
||||
#endif
|
||||
void genimg_print_time(time_t timestamp);
|
||||
|
||||
/* What to do with a image load address ('load = <> 'in the FIT) */
|
||||
enum fit_load_op {
|
||||
FIT_LOAD_IGNORED, /* Ignore load address */
|
||||
FIT_LOAD_OPTIONAL, /* Can be provided, but optional */
|
||||
FIT_LOAD_REQUIRED, /* Must be provided */
|
||||
};
|
||||
|
||||
#ifndef USE_HOSTCC
|
||||
/* Image format types, returned by _get_format() routine */
|
||||
#define IMAGE_FORMAT_INVALID 0x00
|
||||
@ -415,6 +422,68 @@ ulong genimg_get_image(ulong img_addr);
|
||||
int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
|
||||
uint8_t arch, ulong *rd_start, ulong *rd_end);
|
||||
|
||||
/**
|
||||
* fit_image_load() - load an image from a FIT
|
||||
*
|
||||
* This deals with all aspects of loading an image from a FIT, including
|
||||
* selecting the right image based on configuration, verifying it, printing
|
||||
* out progress messages, checking the type/arch/os and optionally copying it
|
||||
* to the right load address.
|
||||
*
|
||||
* @param images Boot images structure
|
||||
* @param prop_name Property name to look up (FIT_..._PROP)
|
||||
* @param addr Address of FIT in memory
|
||||
* @param fit_unamep On entry this is the requested image name
|
||||
* (e.g. "kernel@1") or NULL to use the default. On exit
|
||||
* points to the selected image name
|
||||
* @param fit_uname_config Requested configuration name, or NULL for the
|
||||
* default
|
||||
* @param arch Expected architecture (IH_ARCH_...)
|
||||
* @param image_type Required image type (IH_TYPE_...). If this is
|
||||
* IH_TYPE_KERNEL then we allow IH_TYPE_KERNEL_NOLOAD
|
||||
* also.
|
||||
* @param bootstage_id ID of starting bootstage to use for progress updates.
|
||||
* This will be added to the BOOTSTAGE_SUB values when
|
||||
* calling bootstage_mark()
|
||||
* @param load_op Decribes what to do with the load address
|
||||
* @param datap Returns address of loaded image
|
||||
* @param lenp Returns length of loaded image
|
||||
*/
|
||||
int fit_image_load(bootm_headers_t *images, const char *prop_name, ulong addr,
|
||||
const char **fit_unamep, const char *fit_uname_config,
|
||||
int arch, int image_type, int bootstage_id,
|
||||
enum fit_load_op load_op, ulong *datap, ulong *lenp);
|
||||
|
||||
/**
|
||||
* fit_get_node_from_config() - Look up an image a FIT by type
|
||||
*
|
||||
* This looks in the selected conf@ node (images->fit_uname_cfg) for a
|
||||
* particular image type (e.g. "kernel") and then finds the image that is
|
||||
* referred to.
|
||||
*
|
||||
* For example, for something like:
|
||||
*
|
||||
* images {
|
||||
* kernel@1 {
|
||||
* ...
|
||||
* };
|
||||
* };
|
||||
* configurations {
|
||||
* conf@1 {
|
||||
* kernel = "kernel@1";
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* the function will return the node offset of the kernel@1 node, assuming
|
||||
* that conf@1 is the chosen configuration.
|
||||
*
|
||||
* @param images Boot images structure
|
||||
* @param prop_name Property name to look up (FIT_..._PROP)
|
||||
* @param addr Address of FIT in memory
|
||||
*/
|
||||
int fit_get_node_from_config(bootm_headers_t *images, const char *prop_name,
|
||||
ulong addr);
|
||||
|
||||
int boot_get_fdt(int flag, int argc, char * const argv[],
|
||||
bootm_headers_t *images, char **of_flat_tree, ulong *of_size);
|
||||
void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob);
|
||||
@ -697,6 +766,7 @@ int fit_set_timestamp(void *fit, int noffset, time_t timestamp);
|
||||
int fit_add_verification_data(void *fit);
|
||||
|
||||
int fit_image_verify(const void *fit, int noffset);
|
||||
int fit_config_verify(const void *fit, int conf_noffset);
|
||||
int fit_all_image_verify(const void *fit);
|
||||
int fit_image_check_os(const void *fit, int noffset, uint8_t os);
|
||||
int fit_image_check_arch(const void *fit, int noffset, uint8_t arch);
|
||||
@ -732,12 +802,35 @@ int fit_check_ramdisk(const void *fit, int os_noffset,
|
||||
int calculate_hash(const void *data, int data_len, const char *algo,
|
||||
uint8_t *value, int *value_len);
|
||||
|
||||
#ifndef USE_HOSTCC
|
||||
/*
|
||||
* At present we only support verification on the device
|
||||
*/
|
||||
#if defined(CONFIG_FIT_SIGNATURE)
|
||||
# ifdef USE_HOSTCC
|
||||
# define IMAGE_ENABLE_VERIFY 0
|
||||
#else
|
||||
# define IMAGE_ENABLE_VERIFY 1
|
||||
# endif
|
||||
#else
|
||||
# define IMAGE_ENABLE_VERIFY 0
|
||||
#endif
|
||||
|
||||
#ifdef USE_HOSTCC
|
||||
# define gd_fdt_blob() NULL
|
||||
#else
|
||||
# define gd_fdt_blob() (gd->fdt_blob)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FIT_BEST_MATCH
|
||||
#define IMAGE_ENABLE_BEST_MATCH 1
|
||||
#else
|
||||
#define IMAGE_ENABLE_BEST_MATCH 0
|
||||
#endif
|
||||
|
||||
static inline int fit_image_check_target_arch(const void *fdt, int node)
|
||||
{
|
||||
return fit_image_check_arch(fdt, node, IH_ARCH_DEFAULT);
|
||||
}
|
||||
#endif /* USE_HOSTCC */
|
||||
|
||||
#ifdef CONFIG_FIT_VERBOSE
|
||||
#define fit_unsupported(msg) printf("! %s:%d " \
|
||||
|
Loading…
Reference in New Issue
Block a user