Compare commits
26 Commits
cherry-e44
...
ramdisk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87ff7df6a6 | ||
|
|
38f96198de | ||
|
|
a56029dca7 | ||
|
|
db9df43e39 | ||
|
|
a02307aaab | ||
|
|
013d05ff79 | ||
|
|
b1f69b13ca | ||
|
|
313a765e97 | ||
|
|
1004d2bf1f | ||
|
|
4facf75881 | ||
|
|
a2d18c32af | ||
|
|
f8bcbbf43c | ||
|
|
796610f8d8 | ||
|
|
653a7864bd | ||
|
|
900fcec548 | ||
|
|
0f7ec21254 | ||
|
|
a682393bc0 | ||
|
|
fb7bd18c21 | ||
|
|
0fe2fb8bbc | ||
|
|
4e10991148 | ||
|
|
ffd5339e9e | ||
|
|
08cd4b94f0 | ||
|
|
ac06e52d77 | ||
|
|
24da9b60d5 | ||
|
|
c01d679c78 | ||
|
|
8e90172e19 |
@@ -48,6 +48,7 @@ obj-$(CONFIG_$(PHASE_)UPL_WRITE) += upl_write.o
|
||||
obj-$(CONFIG_$(PHASE_)OF_LIBFDT) += image-fdt.o
|
||||
obj-$(CONFIG_$(PHASE_)FIT_SIGNATURE) += fdt_region.o
|
||||
obj-$(CONFIG_$(PHASE_)FIT) += image-fit.o
|
||||
obj-$(CONFIG_$(PHASE_)FIT_PRINT) += fit_print.o
|
||||
obj-$(CONFIG_$(PHASE_)MULTI_DTB_FIT) += boot_fit.o common_fit.o
|
||||
obj-$(CONFIG_$(PHASE_)IMAGE_PRE_LOAD) += image-pre-load.o
|
||||
obj-$(CONFIG_$(PHASE_)IMAGE_SIGN_INFO) += image-sig.o
|
||||
|
||||
494
boot/fit_print.c
Normal file
494
boot/fit_print.c
Normal file
@@ -0,0 +1,494 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2013, Google Inc.
|
||||
*
|
||||
* (C) Copyright 2008 Semihalf
|
||||
*
|
||||
* (C) Copyright 2000-2006
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY LOGC_BOOT
|
||||
|
||||
#ifdef USE_HOSTCC
|
||||
#include "mkimage.h"
|
||||
#include <time.h>
|
||||
#include <linux/libfdt.h>
|
||||
#else
|
||||
#include <linux/compiler.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#endif
|
||||
|
||||
#include <image.h>
|
||||
#include <u-boot/crc.h>
|
||||
|
||||
/**
|
||||
* fit_print_init() - initialize FIT print context
|
||||
* @ctx: pointer to FIT print context to initialize
|
||||
* @fit: pointer to the FIT format image header
|
||||
*
|
||||
* This initializes a fit_print_ctx structure with the given FIT image.
|
||||
*/
|
||||
void fit_print_init(struct fit_print_ctx *ctx, const void *fit)
|
||||
{
|
||||
ctx->fit = fit;
|
||||
ctx->indent = IMAGE_INDENT;
|
||||
ctx->tab = 20;
|
||||
}
|
||||
|
||||
/**
|
||||
* emit_type() - print a label with indentation and padding
|
||||
* @ctx: pointer to FIT print context
|
||||
* @type: type prefix (e.g., "Hash" or "Sign")
|
||||
* @label: label suffix (e.g., "algo" or "value")
|
||||
*
|
||||
* Prints the indentation from the context, followed by two spaces, the type,
|
||||
* a space, the label, a colon, and padding to align values to ctx->tab.
|
||||
*/
|
||||
static void emit_type(struct fit_print_ctx *ctx, const char *type,
|
||||
const char *label)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = printf("%*s%s %s:", ctx->indent, "", type, label);
|
||||
printf("%*s", ctx->tab - len, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* emit_label() - print a label with indentation and padding
|
||||
* @ctx: pointer to FIT print context
|
||||
* @type: type prefix (e.g., "Hash" or "Sign")
|
||||
* @label: label suffix (e.g., "algo" or "value")
|
||||
*
|
||||
* Prints the indentation from the context, followed by two spaces, a space,
|
||||
* the label, a colon, and padding to align values to ctx->tab.
|
||||
*/
|
||||
static void emit_label(struct fit_print_ctx *ctx, const char *label)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = printf("%*s%s%c", ctx->indent, "", label, *label ? ':' : ' ');
|
||||
printf("%*s", ctx->tab - len, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* emit_label_val() - print a label with value
|
||||
* @ctx: pointer to FIT print context
|
||||
* @label: label string (e.g., "Type" or "OS")
|
||||
* @val: value string to print after the label
|
||||
*
|
||||
* Prints the indentation, label with padding to ctx->tab, and the value
|
||||
* followed by a newline. This is a convenience function that combines
|
||||
* emit_label() and printf() for simple label-value pairs.
|
||||
*/
|
||||
static void emit_label_val(struct fit_print_ctx *ctx, const char *label,
|
||||
const char *val)
|
||||
{
|
||||
emit_label(ctx, label);
|
||||
printf("%s\n", val);
|
||||
}
|
||||
|
||||
/**
|
||||
* emit_prop() - print a property if it exists
|
||||
* @ctx: pointer to FIT print context
|
||||
* @noffset: offset of the node containing the property
|
||||
* @prop: property name to get and print
|
||||
* @label: label string to use when printing
|
||||
*
|
||||
* Gets a property from the specified node and prints it with the given label
|
||||
* only if the property exists. This is a convenience function for optional
|
||||
* properties that should only be printed when present.
|
||||
*/
|
||||
static void emit_prop(struct fit_print_ctx *ctx, int noffset,
|
||||
const char *prop, const char *label)
|
||||
{
|
||||
const char *val;
|
||||
|
||||
val = fdt_getprop(ctx->fit, noffset, prop, NULL);
|
||||
if (val)
|
||||
emit_label_val(ctx, label, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* emit_timestamp() - print a timestamp
|
||||
* @ctx: pointer to FIT print context
|
||||
* @noffset: offset of the node containing the timestamp
|
||||
* @label: label string to use when printing
|
||||
*
|
||||
* Gets the timestamp from the specified node and prints it with the given
|
||||
* label. If the timestamp is not available, prints "unavailable" instead.
|
||||
* This is a convenience function for printing FIT timestamps.
|
||||
*/
|
||||
static void emit_timestamp(struct fit_print_ctx *ctx, int noffset,
|
||||
const char *label)
|
||||
{
|
||||
time_t timestamp;
|
||||
|
||||
if (!IMAGE_ENABLE_TIMESTAMP)
|
||||
return;
|
||||
emit_label(ctx, label);
|
||||
if (fit_get_timestamp(ctx->fit, noffset, ×tamp))
|
||||
printf("unavailable\n");
|
||||
else
|
||||
genimg_print_time(timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* emit_stringlist() - print a stringlist property
|
||||
* @ctx: pointer to FIT print context
|
||||
* @noffset: offset of the node containing the property
|
||||
* @prop: property name to get and print
|
||||
* @label: label string to use when printing
|
||||
*
|
||||
* Gets a stringlist property from the specified node and prints each string
|
||||
* with the given label. The first string shows the label, subsequent strings
|
||||
* are indented to align with the first value. If the property doesn't exist,
|
||||
* nothing is printed.
|
||||
*/
|
||||
static void emit_stringlist(struct fit_print_ctx *ctx, int noffset,
|
||||
const char *prop, const char *label)
|
||||
{
|
||||
const char *val;
|
||||
int i;
|
||||
|
||||
for (i = 0;
|
||||
val = fdt_stringlist_get(ctx->fit, noffset, prop, i, NULL), val;
|
||||
i++)
|
||||
emit_label_val(ctx, i ? "" : label, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* emit_desc() - print a description
|
||||
* @ctx: pointer to FIT print context
|
||||
* @noffset: offset of the node containing the description
|
||||
* @label: label string to use when printing
|
||||
*
|
||||
* Gets the description from the specified node and prints it with the given
|
||||
* label. If the description is not available, prints "unavailable" instead.
|
||||
* This is a convenience function for printing FIT descriptions.
|
||||
*/
|
||||
static void emit_desc(struct fit_print_ctx *ctx, int noffset,
|
||||
const char *label)
|
||||
{
|
||||
const char *desc;
|
||||
int ret;
|
||||
|
||||
ret = fit_get_desc(ctx->fit, noffset, &desc);
|
||||
emit_label_val(ctx, label, ret ? "unavailable" : desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* emit_addr() - print an address property
|
||||
* @ctx: pointer to FIT print context
|
||||
* @label: label string to use when printing
|
||||
* @addr: address value to print
|
||||
* @valid: true if the address is valid, false to print "unavailable"
|
||||
*
|
||||
* Prints an address with the given label. If valid is false, prints
|
||||
* "unavailable" instead of the address value.
|
||||
*/
|
||||
static void emit_addr(struct fit_print_ctx *ctx, const char *label, ulong addr,
|
||||
bool valid)
|
||||
{
|
||||
emit_label(ctx, label);
|
||||
if (valid)
|
||||
printf("0x%08lx\n", addr);
|
||||
else
|
||||
printf("unavailable\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_image_print_data() - prints out the hash node details
|
||||
* @ctx: pointer to FIT print context
|
||||
* @noffset: offset of the hash node
|
||||
* @type: Type of information to print ("hash" or "sign")
|
||||
*
|
||||
* fit_image_print_data() lists properties for the processed hash node
|
||||
*
|
||||
* This function avoid using puts() since it prints a newline on the host
|
||||
* but does not in U-Boot.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
static void fit_image_print_data(struct fit_print_ctx *ctx, int noffset,
|
||||
const char *type)
|
||||
{
|
||||
const char *keyname, *padding, *algo;
|
||||
int p = ctx->indent;
|
||||
const void *fit = ctx->fit;
|
||||
int value_len, ret, i;
|
||||
uint8_t *value;
|
||||
|
||||
debug("%s node: '%s'\n", type, fit_get_name(fit, noffset));
|
||||
emit_type(ctx, type, "algo");
|
||||
if (fit_image_hash_get_algo(fit, noffset, &algo)) {
|
||||
printf("invalid/unsupported\n");
|
||||
return;
|
||||
}
|
||||
printf("%s", algo);
|
||||
keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
|
||||
if (keyname)
|
||||
printf(":%s", keyname);
|
||||
printf("\n");
|
||||
|
||||
padding = fdt_getprop(fit, noffset, "padding", NULL);
|
||||
if (padding)
|
||||
printf("%*s%s padding: %s\n", p, "", type, padding);
|
||||
|
||||
ret = fit_image_hash_get_value(fit, noffset, &value, &value_len);
|
||||
emit_type(ctx, type, "value");
|
||||
if (ret) {
|
||||
printf("unavailable\n");
|
||||
} else {
|
||||
for (i = 0; i < value_len; i++)
|
||||
printf("%02x", value[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
debug("%s len: %d\n", type, value_len);
|
||||
|
||||
/* Signatures have a time stamp */
|
||||
if (IMAGE_ENABLE_TIMESTAMP && keyname)
|
||||
emit_timestamp(ctx, noffset, "Timestamp");
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_image_print_verification_data() - prints out the hash/signature details
|
||||
* @ctx: pointer to FIT print context
|
||||
* @noffset: offset of the hash or signature node
|
||||
*
|
||||
* This lists properties for the processed hash node
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
static void fit_image_print_verification_data(struct fit_print_ctx *ctx,
|
||||
int noffset)
|
||||
{
|
||||
const void *fit = ctx->fit;
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* Check subnode name, must be equal to "hash" or "signature".
|
||||
* Multiple hash/signature nodes require unique unit node
|
||||
* names, e.g. hash-1, hash-2, signature-1, signature-2, etc.
|
||||
*/
|
||||
name = fit_get_name(fit, noffset);
|
||||
if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME)))
|
||||
fit_image_print_data(ctx, noffset, "Hash");
|
||||
else if (!strncmp(name, FIT_SIG_NODENAME, strlen(FIT_SIG_NODENAME)))
|
||||
fit_image_print_data(ctx, noffset, "Sign");
|
||||
}
|
||||
|
||||
/**
|
||||
* process_subnodes() - process and print verification data for all subnodes
|
||||
* @ctx: pointer to FIT print context
|
||||
* @parent: parent node offset
|
||||
*
|
||||
* Iterates through all direct child nodes of the parent and prints their
|
||||
* verification data (hash/signature information).
|
||||
*/
|
||||
static void process_subnodes(struct fit_print_ctx *ctx, int parent)
|
||||
{
|
||||
const void *fit = ctx->fit;
|
||||
int noffset;
|
||||
|
||||
fdt_for_each_subnode(noffset, fit, parent)
|
||||
fit_image_print_verification_data(ctx, noffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_image_print - prints out the FIT component image details
|
||||
* @ctx: pointer to FIT print context
|
||||
* @image_noffset: offset of the component image node
|
||||
* @p: pointer to prefix string
|
||||
*
|
||||
* fit_image_print() lists all mandatory properties for the processed component
|
||||
* image. If present, hash nodes are printed out as well. Load
|
||||
* address for images of type firmware is also printed out. Since the load
|
||||
* address is not mandatory for firmware images, it will be output as
|
||||
* "unavailable" when not present.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
void fit_image_print(struct fit_print_ctx *ctx, int image_noffset)
|
||||
{
|
||||
const void *fit = ctx->fit;
|
||||
uint8_t type, arch, os, comp = IH_COMP_NONE;
|
||||
size_t size;
|
||||
ulong load, entry;
|
||||
const void *data;
|
||||
int ret;
|
||||
|
||||
/* Mandatory properties */
|
||||
emit_desc(ctx, image_noffset, "Description");
|
||||
|
||||
emit_timestamp(ctx, 0, "Created");
|
||||
|
||||
fit_image_get_type(fit, image_noffset, &type);
|
||||
emit_label_val(ctx, "Type", genimg_get_type_name(type));
|
||||
|
||||
fit_image_get_comp(fit, image_noffset, &comp);
|
||||
emit_label_val(ctx, "Compression", genimg_get_comp_name(comp));
|
||||
|
||||
ret = fit_image_get_data(fit, image_noffset, &data, &size);
|
||||
|
||||
if (!tools_build()) {
|
||||
emit_label(ctx, "Data Start");
|
||||
if (ret) {
|
||||
printf("unavailable\n");
|
||||
} else {
|
||||
void *vdata = (void *)data;
|
||||
|
||||
printf("0x%08lx\n", (ulong)map_to_sysmem(vdata));
|
||||
}
|
||||
}
|
||||
|
||||
emit_label(ctx, "Data Size");
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
genimg_print_size(size);
|
||||
|
||||
/* Remaining, type dependent properties */
|
||||
bool loadable = type == IH_TYPE_KERNEL || type == IH_TYPE_STANDALONE ||
|
||||
type == IH_TYPE_RAMDISK;
|
||||
|
||||
if (loadable || type == IH_TYPE_FIRMWARE || type == IH_TYPE_FLATDT) {
|
||||
fit_image_get_arch(fit, image_noffset, &arch);
|
||||
emit_label_val(ctx, "Architecture", genimg_get_arch_name(arch));
|
||||
}
|
||||
|
||||
if (loadable || type == IH_TYPE_FIRMWARE) {
|
||||
fit_image_get_os(fit, image_noffset, &os);
|
||||
emit_label_val(ctx, "OS", genimg_get_os_name(os));
|
||||
}
|
||||
|
||||
if (loadable || type == IH_TYPE_FIRMWARE || type == IH_TYPE_FPGA ||
|
||||
type == IH_TYPE_FLATDT) {
|
||||
ret = fit_image_get_load(fit, image_noffset, &load);
|
||||
if (type != IH_TYPE_FLATDT || !ret)
|
||||
emit_addr(ctx, "Load Address", load, !ret);
|
||||
}
|
||||
|
||||
if (loadable) {
|
||||
ret = fit_image_get_entry(fit, image_noffset, &entry);
|
||||
emit_addr(ctx, "Entry Point", entry, !ret);
|
||||
}
|
||||
|
||||
/* Process all hash subnodes of the component image node */
|
||||
process_subnodes(ctx, image_noffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_conf_print - prints out the FIT configuration details
|
||||
* @ctx: pointer to FIT print context
|
||||
* @noffset: offset of the configuration node
|
||||
*
|
||||
* fit_conf_print() lists all mandatory properties for the processed
|
||||
* configuration node.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
static void fit_conf_print(struct fit_print_ctx *ctx, int noffset)
|
||||
{
|
||||
const void *fit = ctx->fit;
|
||||
const char *uname;
|
||||
|
||||
/* Mandatory properties */
|
||||
emit_desc(ctx, noffset, "Description");
|
||||
|
||||
uname = fdt_getprop(fit, noffset, FIT_KERNEL_PROP, NULL);
|
||||
emit_label_val(ctx, "Kernel", uname ?: "unavailable");
|
||||
|
||||
/* Optional properties */
|
||||
emit_prop(ctx, noffset, FIT_RAMDISK_PROP, "Init Ramdisk");
|
||||
emit_prop(ctx, noffset, FIT_FIRMWARE_PROP, "Firmware");
|
||||
emit_stringlist(ctx, noffset, FIT_FDT_PROP, "FDT");
|
||||
emit_prop(ctx, noffset, FIT_FPGA_PROP, "FPGA");
|
||||
emit_stringlist(ctx, noffset, FIT_LOADABLE_PROP, "Loadables");
|
||||
emit_stringlist(ctx, noffset, FIT_COMPATIBLE_PROP, "Compatible");
|
||||
|
||||
/* Process all hash subnodes of the component configuration node */
|
||||
process_subnodes(ctx, noffset);
|
||||
}
|
||||
|
||||
void fit_print(struct fit_print_ctx *ctx)
|
||||
{
|
||||
const void *fit = ctx->fit;
|
||||
int p = ctx->indent;
|
||||
char *uname;
|
||||
int images_noffset;
|
||||
int confs_noffset;
|
||||
int noffset;
|
||||
int count;
|
||||
|
||||
/* Root node properties */
|
||||
emit_desc(ctx, 0, "FIT description");
|
||||
|
||||
emit_timestamp(ctx, 0, "Created");
|
||||
|
||||
/* Find images parent node offset */
|
||||
images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
|
||||
if (images_noffset < 0) {
|
||||
printf("Can't find images parent node '%s' (%s)\n",
|
||||
FIT_IMAGES_PATH, fdt_strerror(images_noffset));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process its subnodes, print out component images details */
|
||||
count = 0;
|
||||
fdt_for_each_subnode(noffset, fit, images_noffset) {
|
||||
/*
|
||||
* Direct child node of the images parent node,
|
||||
* i.e. component image node.
|
||||
*/
|
||||
printf("%*s Image %u (%s)\n", p, "", count++,
|
||||
fit_get_name(fit, noffset));
|
||||
|
||||
ctx->indent += 2;
|
||||
fit_image_print(ctx, noffset);
|
||||
ctx->indent -= 2;
|
||||
}
|
||||
|
||||
/* Find configurations parent node offset */
|
||||
confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
|
||||
if (confs_noffset < 0) {
|
||||
debug("Can't get configurations parent node '%s' (%s)\n",
|
||||
FIT_CONFS_PATH, fdt_strerror(confs_noffset));
|
||||
return;
|
||||
}
|
||||
|
||||
/* get default configuration unit name from default property */
|
||||
uname = (char *)fdt_getprop(fit, confs_noffset, FIT_DEFAULT_PROP, NULL);
|
||||
if (uname)
|
||||
printf("%*s Default Configuration: '%s'\n", p, "", uname);
|
||||
|
||||
/* Process its subnodes, print out configurations details */
|
||||
count = 0;
|
||||
fdt_for_each_subnode(noffset, fit, confs_noffset) {
|
||||
/*
|
||||
* Direct child node of the configurations parent node,
|
||||
* i.e. configuration node.
|
||||
*/
|
||||
printf("%*s Configuration %u (%s)\n", p, "", count++,
|
||||
fit_get_name(fit, noffset));
|
||||
|
||||
ctx->indent += 2;
|
||||
fit_conf_print(ctx, noffset);
|
||||
ctx->indent -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void fit_print_contents(const void *fit)
|
||||
{
|
||||
struct fit_print_ctx ctx;
|
||||
|
||||
fit_print_init(&ctx, fit);
|
||||
fit_print(&ctx);
|
||||
}
|
||||
@@ -76,7 +76,7 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info,
|
||||
char *algo_name;
|
||||
int ret;
|
||||
|
||||
node_name = fit_get_name(fit, image_noffset, NULL);
|
||||
node_name = fit_get_name(fit, image_noffset);
|
||||
if (!node_name) {
|
||||
printf("Can't get node name\n");
|
||||
return -1;
|
||||
|
||||
@@ -145,7 +145,7 @@ static int fit_image_verify_sig(const void *fit, int image_noffset,
|
||||
|
||||
/* Process all hash subnodes of the component image node */
|
||||
fdt_for_each_subnode(noffset, fit, image_noffset) {
|
||||
const char *name = fit_get_name(fit, noffset, NULL);
|
||||
const char *name = fit_get_name(fit, noffset);
|
||||
|
||||
/*
|
||||
* We don't support this since libfdt considers names with the
|
||||
@@ -178,8 +178,8 @@ static int fit_image_verify_sig(const void *fit, int image_noffset,
|
||||
|
||||
error:
|
||||
printf(" error!\n%s for '%s' hash node in '%s' image node\n",
|
||||
err_msg, fit_get_name(fit, noffset, NULL),
|
||||
fit_get_name(fit, image_noffset, NULL));
|
||||
err_msg, fit_get_name(fit, noffset),
|
||||
fit_get_name(fit, image_noffset));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ int fit_image_verify_required_sigs(const void *fit, int image_noffset,
|
||||
key_blob, noffset);
|
||||
if (ret) {
|
||||
printf("Failed to verify required signature '%s'\n",
|
||||
fit_get_name(key_blob, noffset, NULL));
|
||||
fit_get_name(key_blob, noffset));
|
||||
return ret;
|
||||
}
|
||||
verify_count++;
|
||||
@@ -277,10 +277,10 @@ static int fit_config_check_sig(const void *fit, int noffset, int conf_noffset,
|
||||
char path[200];
|
||||
int count;
|
||||
|
||||
config_name = fit_get_name(fit, conf_noffset, NULL);
|
||||
config_name = fit_get_name(fit, conf_noffset);
|
||||
debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, key_blob,
|
||||
fit_get_name(fit, noffset, NULL),
|
||||
fit_get_name(key_blob, required_keynode, NULL));
|
||||
fit_get_name(fit, noffset),
|
||||
fit_get_name(key_blob, required_keynode));
|
||||
*err_msgp = NULL;
|
||||
if (fit_image_setup_verify(&info, fit, noffset, key_blob,
|
||||
required_keynode, err_msgp))
|
||||
@@ -421,7 +421,7 @@ static int fit_config_verify_key(const void *fit, int conf_noffset,
|
||||
|
||||
/* Process all hash subnodes of the component conf node */
|
||||
fdt_for_each_subnode(noffset, fit, conf_noffset) {
|
||||
const char *name = fit_get_name(fit, noffset, NULL);
|
||||
const char *name = fit_get_name(fit, noffset);
|
||||
|
||||
if (!strncmp(name, FIT_SIG_NODENAME,
|
||||
strlen(FIT_SIG_NODENAME))) {
|
||||
@@ -448,8 +448,8 @@ static int fit_config_verify_key(const void *fit, int conf_noffset,
|
||||
|
||||
error:
|
||||
printf(" error!\n%s for '%s' hash node in '%s' config node\n",
|
||||
err_msg, fit_get_name(fit, noffset, NULL),
|
||||
fit_get_name(fit, conf_noffset, NULL));
|
||||
err_msg, fit_get_name(fit, noffset),
|
||||
fit_get_name(fit, conf_noffset));
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ error:
|
||||
static int fit_config_verify_required_keys(const void *fit, int conf_noffset,
|
||||
const void *key_blob)
|
||||
{
|
||||
const char *name = fit_get_name(fit, conf_noffset, NULL);
|
||||
const char *name = fit_get_name(fit, conf_noffset);
|
||||
int noffset;
|
||||
int key_node;
|
||||
int verified = 0;
|
||||
@@ -525,7 +525,7 @@ static int fit_config_verify_required_keys(const void *fit, int conf_noffset,
|
||||
if (ret) {
|
||||
if (reqd_policy_all) {
|
||||
printf("Failed to verify required signature '%s'\n",
|
||||
fit_get_name(key_blob, noffset, NULL));
|
||||
fit_get_name(key_blob, noffset));
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
|
||||
442
boot/image-fit.c
442
boot/image-fit.c
@@ -148,7 +148,7 @@ static void fit_get_debug(const void *fit, int noffset,
|
||||
char *prop_name, int err)
|
||||
{
|
||||
debug("Can't get '%s' property from FIT 0x%08lx, node: offset %d, name %s (%s)\n",
|
||||
prop_name, (ulong)fit, noffset, fit_get_name(fit, noffset, NULL),
|
||||
prop_name, (ulong)fit, noffset, fit_get_name(fit, noffset),
|
||||
fdt_strerror(err));
|
||||
}
|
||||
|
||||
@@ -179,423 +179,6 @@ int fit_get_subimage_count(const void *fit, int images_noffset)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_image_print_data() - prints out the hash node details
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @noffset: offset of the hash node
|
||||
* @p: pointer to prefix string
|
||||
* @type: Type of information to print ("hash" or "sign")
|
||||
*
|
||||
* fit_image_print_data() lists properties for the processed hash node
|
||||
*
|
||||
* This function avoid using puts() since it prints a newline on the host
|
||||
* but does not in U-Boot.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
static void fit_image_print_data(const void *fit, int noffset, const char *p,
|
||||
const char *type)
|
||||
{
|
||||
const char *keyname;
|
||||
uint8_t *value;
|
||||
int value_len;
|
||||
const char *algo;
|
||||
const char *padding;
|
||||
bool required;
|
||||
int ret, i;
|
||||
|
||||
debug("%s %s node: '%s'\n", p, type,
|
||||
fit_get_name(fit, noffset, NULL));
|
||||
printf("%s %s algo: ", p, type);
|
||||
if (fit_image_hash_get_algo(fit, noffset, &algo)) {
|
||||
printf("invalid/unsupported\n");
|
||||
return;
|
||||
}
|
||||
printf("%s", algo);
|
||||
keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
|
||||
required = fdt_getprop(fit, noffset, FIT_KEY_REQUIRED, NULL) != NULL;
|
||||
if (keyname)
|
||||
printf(":%s", keyname);
|
||||
if (required)
|
||||
printf(" (required)");
|
||||
printf("\n");
|
||||
|
||||
padding = fdt_getprop(fit, noffset, "padding", NULL);
|
||||
if (padding)
|
||||
printf("%s %s padding: %s\n", p, type, padding);
|
||||
|
||||
ret = fit_image_hash_get_value(fit, noffset, &value,
|
||||
&value_len);
|
||||
printf("%s %s value: ", p, type);
|
||||
if (ret) {
|
||||
printf("unavailable\n");
|
||||
} else {
|
||||
for (i = 0; i < value_len; i++)
|
||||
printf("%02x", value[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
debug("%s %s len: %d\n", p, type, value_len);
|
||||
|
||||
/* Signatures have a time stamp */
|
||||
if (IMAGE_ENABLE_TIMESTAMP && keyname) {
|
||||
time_t timestamp;
|
||||
|
||||
printf("%s Timestamp: ", p);
|
||||
if (fit_get_timestamp(fit, noffset, ×tamp))
|
||||
printf("unavailable\n");
|
||||
else
|
||||
genimg_print_time(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_image_print_verification_data() - prints out the hash/signature details
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @noffset: offset of the hash or signature node
|
||||
* @p: pointer to prefix string
|
||||
*
|
||||
* This lists properties for the processed hash node
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
static void fit_image_print_verification_data(const void *fit, int noffset,
|
||||
const char *p)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* Check subnode name, must be equal to "hash" or "signature".
|
||||
* Multiple hash/signature nodes require unique unit node
|
||||
* names, e.g. hash-1, hash-2, signature-1, signature-2, etc.
|
||||
*/
|
||||
name = fit_get_name(fit, noffset, NULL);
|
||||
if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) {
|
||||
fit_image_print_data(fit, noffset, p, "Hash");
|
||||
} else if (!strncmp(name, FIT_SIG_NODENAME,
|
||||
strlen(FIT_SIG_NODENAME))) {
|
||||
fit_image_print_data(fit, noffset, p, "Sign");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_conf_print - prints out the FIT configuration details
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @noffset: offset of the configuration node
|
||||
* @p: pointer to prefix string
|
||||
*
|
||||
* fit_conf_print() lists all mandatory properties for the processed
|
||||
* configuration node.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
static void fit_conf_print(const void *fit, int noffset, const char *p)
|
||||
{
|
||||
const char *uname, *desc;
|
||||
int ret, ndepth, i;
|
||||
|
||||
/* Mandatory properties */
|
||||
ret = fit_get_desc(fit, noffset, &desc);
|
||||
printf("%s Description: ", p);
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
printf("%s\n", desc);
|
||||
|
||||
uname = fdt_getprop(fit, noffset, FIT_KERNEL_PROP, NULL);
|
||||
printf("%s Kernel: ", p);
|
||||
if (!uname)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
printf("%s\n", uname);
|
||||
|
||||
/* Optional properties */
|
||||
uname = fdt_getprop(fit, noffset, FIT_RAMDISK_PROP, NULL);
|
||||
if (uname)
|
||||
printf("%s Init Ramdisk: %s\n", p, uname);
|
||||
|
||||
uname = fdt_getprop(fit, noffset, FIT_FIRMWARE_PROP, NULL);
|
||||
if (uname)
|
||||
printf("%s Firmware: %s\n", p, uname);
|
||||
|
||||
for (i = 0;
|
||||
uname = fdt_stringlist_get(fit, noffset, FIT_FDT_PROP,
|
||||
i, NULL), uname;
|
||||
i++) {
|
||||
if (!i)
|
||||
printf("%s FDT: ", p);
|
||||
else
|
||||
printf("%s ", p);
|
||||
printf("%s\n", uname);
|
||||
}
|
||||
|
||||
uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL);
|
||||
if (uname)
|
||||
printf("%s FPGA: %s\n", p, uname);
|
||||
|
||||
/* Print out all of the specified loadables */
|
||||
for (i = 0;
|
||||
uname = fdt_stringlist_get(fit, noffset, FIT_LOADABLE_PROP,
|
||||
i, NULL), uname;
|
||||
i++) {
|
||||
if (!i)
|
||||
printf("%s Loadables: ", p);
|
||||
else
|
||||
printf("%s ", p);
|
||||
printf("%s\n", uname);
|
||||
}
|
||||
|
||||
/* Show the list of compatible strings */
|
||||
for (i = 0; uname = fdt_stringlist_get(fit, noffset,
|
||||
FIT_COMPATIBLE_PROP, i, NULL), uname; i++) {
|
||||
if (!i)
|
||||
printf("%s Compatible: ", p);
|
||||
else
|
||||
printf("%s ", p);
|
||||
printf("%s\n", uname);
|
||||
}
|
||||
|
||||
/* Process all hash subnodes of the component configuration node */
|
||||
for (ndepth = 0, noffset = fdt_next_node(fit, noffset, &ndepth);
|
||||
(noffset >= 0) && (ndepth > 0);
|
||||
noffset = fdt_next_node(fit, noffset, &ndepth)) {
|
||||
if (ndepth == 1) {
|
||||
/* Direct child node of the component configuration node */
|
||||
fit_image_print_verification_data(fit, noffset, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_print_contents - prints out the contents of the FIT format image
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @p: pointer to prefix string
|
||||
*
|
||||
* fit_print_contents() formats a multi line FIT image contents description.
|
||||
* The routine prints out FIT image properties (root node level) followed by
|
||||
* the details of each component image.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
void fit_print_contents(const void *fit)
|
||||
{
|
||||
const char *desc;
|
||||
char *uname;
|
||||
int images_noffset;
|
||||
int confs_noffset;
|
||||
int noffset;
|
||||
int ndepth;
|
||||
int count = 0;
|
||||
int ret;
|
||||
const char *p;
|
||||
time_t timestamp;
|
||||
|
||||
if (!CONFIG_IS_ENABLED(FIT_PRINT))
|
||||
return;
|
||||
|
||||
/* Indent string is defined in header image.h */
|
||||
p = IMAGE_INDENT_STRING;
|
||||
|
||||
/* Root node properties */
|
||||
ret = fit_get_desc(fit, 0, &desc);
|
||||
printf("%sFIT description: ", p);
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
printf("%s\n", desc);
|
||||
|
||||
if (IMAGE_ENABLE_TIMESTAMP) {
|
||||
ret = fit_get_timestamp(fit, 0, ×tamp);
|
||||
printf("%sCreated: ", p);
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
genimg_print_time(timestamp);
|
||||
}
|
||||
|
||||
/* Find images parent node offset */
|
||||
images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
|
||||
if (images_noffset < 0) {
|
||||
printf("Can't find images parent node '%s' (%s)\n",
|
||||
FIT_IMAGES_PATH, fdt_strerror(images_noffset));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process its subnodes, print out component images details */
|
||||
for (ndepth = 0, count = 0,
|
||||
noffset = fdt_next_node(fit, images_noffset, &ndepth);
|
||||
(noffset >= 0) && (ndepth > 0);
|
||||
noffset = fdt_next_node(fit, noffset, &ndepth)) {
|
||||
if (ndepth == 1) {
|
||||
/*
|
||||
* Direct child node of the images parent node,
|
||||
* i.e. component image node.
|
||||
*/
|
||||
printf("%s Image %u (%s)\n", p, count++,
|
||||
fit_get_name(fit, noffset, NULL));
|
||||
|
||||
fit_image_print(fit, noffset, p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Find configurations parent node offset */
|
||||
confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
|
||||
if (confs_noffset < 0) {
|
||||
debug("Can't get configurations parent node '%s' (%s)\n",
|
||||
FIT_CONFS_PATH, fdt_strerror(confs_noffset));
|
||||
return;
|
||||
}
|
||||
|
||||
/* get default configuration unit name from default property */
|
||||
uname = (char *)fdt_getprop(fit, noffset, FIT_DEFAULT_PROP, NULL);
|
||||
if (uname)
|
||||
printf("%s Default Configuration: '%s'\n", p, uname);
|
||||
|
||||
/* Process its subnodes, print out configurations details */
|
||||
for (ndepth = 0, count = 0,
|
||||
noffset = fdt_next_node(fit, confs_noffset, &ndepth);
|
||||
(noffset >= 0) && (ndepth > 0);
|
||||
noffset = fdt_next_node(fit, noffset, &ndepth)) {
|
||||
if (ndepth == 1) {
|
||||
/*
|
||||
* Direct child node of the configurations parent node,
|
||||
* i.e. configuration node.
|
||||
*/
|
||||
printf("%s Configuration %u (%s)\n", p, count++,
|
||||
fit_get_name(fit, noffset, NULL));
|
||||
|
||||
fit_conf_print(fit, noffset, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_image_print - prints out the FIT component image details
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @image_noffset: offset of the component image node
|
||||
* @p: pointer to prefix string
|
||||
*
|
||||
* fit_image_print() lists all mandatory properties for the processed component
|
||||
* image. If present, hash nodes are printed out as well. Load
|
||||
* address for images of type firmware is also printed out. Since the load
|
||||
* address is not mandatory for firmware images, it will be output as
|
||||
* "unavailable" when not present.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
void fit_image_print(const void *fit, int image_noffset, const char *p)
|
||||
{
|
||||
uint8_t type, arch, os, comp = IH_COMP_NONE;
|
||||
const char *desc;
|
||||
size_t size;
|
||||
ulong load, entry;
|
||||
const void *data;
|
||||
int noffset;
|
||||
int ndepth;
|
||||
int ret;
|
||||
|
||||
if (!CONFIG_IS_ENABLED(FIT_PRINT))
|
||||
return;
|
||||
|
||||
/* Mandatory properties */
|
||||
ret = fit_get_desc(fit, image_noffset, &desc);
|
||||
printf("%s Description: ", p);
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
printf("%s\n", desc);
|
||||
|
||||
if (IMAGE_ENABLE_TIMESTAMP) {
|
||||
time_t timestamp;
|
||||
|
||||
ret = fit_get_timestamp(fit, 0, ×tamp);
|
||||
printf("%s Created: ", p);
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
genimg_print_time(timestamp);
|
||||
}
|
||||
|
||||
fit_image_get_type(fit, image_noffset, &type);
|
||||
printf("%s Type: %s\n", p, genimg_get_type_name(type));
|
||||
|
||||
fit_image_get_comp(fit, image_noffset, &comp);
|
||||
printf("%s Compression: %s\n", p, genimg_get_comp_name(comp));
|
||||
|
||||
ret = fit_image_get_data(fit, image_noffset, &data, &size);
|
||||
|
||||
if (!tools_build()) {
|
||||
printf("%s Data Start: ", p);
|
||||
if (ret) {
|
||||
printf("unavailable\n");
|
||||
} else {
|
||||
void *vdata = (void *)data;
|
||||
|
||||
printf("0x%08lx\n", (ulong)map_to_sysmem(vdata));
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s Data Size: ", p);
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
genimg_print_size(size);
|
||||
|
||||
/* Remaining, type dependent properties */
|
||||
if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
|
||||
(type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE) ||
|
||||
(type == IH_TYPE_FLATDT)) {
|
||||
fit_image_get_arch(fit, image_noffset, &arch);
|
||||
printf("%s Architecture: %s\n", p, genimg_get_arch_name(arch));
|
||||
}
|
||||
|
||||
if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_RAMDISK) ||
|
||||
(type == IH_TYPE_FIRMWARE)) {
|
||||
fit_image_get_os(fit, image_noffset, &os);
|
||||
printf("%s OS: %s\n", p, genimg_get_os_name(os));
|
||||
}
|
||||
|
||||
if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
|
||||
(type == IH_TYPE_FIRMWARE) || (type == IH_TYPE_RAMDISK) ||
|
||||
(type == IH_TYPE_FPGA)) {
|
||||
ret = fit_image_get_load(fit, image_noffset, &load);
|
||||
printf("%s Load Address: ", p);
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
printf("0x%08lx\n", load);
|
||||
}
|
||||
|
||||
/* optional load address for FDT */
|
||||
if (type == IH_TYPE_FLATDT && !fit_image_get_load(fit, image_noffset, &load))
|
||||
printf("%s Load Address: 0x%08lx\n", p, load);
|
||||
|
||||
if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) ||
|
||||
(type == IH_TYPE_RAMDISK)) {
|
||||
ret = fit_image_get_entry(fit, image_noffset, &entry);
|
||||
printf("%s Entry Point: ", p);
|
||||
if (ret)
|
||||
printf("unavailable\n");
|
||||
else
|
||||
printf("0x%08lx\n", entry);
|
||||
}
|
||||
|
||||
/* Process all hash subnodes of the component image node */
|
||||
for (ndepth = 0, noffset = fdt_next_node(fit, image_noffset, &ndepth);
|
||||
(noffset >= 0) && (ndepth > 0);
|
||||
noffset = fdt_next_node(fit, noffset, &ndepth)) {
|
||||
if (ndepth == 1) {
|
||||
/* Direct child node of the component image node */
|
||||
fit_image_print_verification_data(fit, noffset, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fit_get_desc(const void *fit, int noffset, const char **descp)
|
||||
{
|
||||
const char *desc;
|
||||
@@ -1215,7 +798,7 @@ int fit_set_timestamp(void *fit, int noffset, time_t timestamp)
|
||||
sizeof(uint32_t));
|
||||
if (ret) {
|
||||
debug("Can't set '%s' property for '%s' node (%s)\n",
|
||||
FIT_TIMESTAMP_PROP, fit_get_name(fit, noffset, NULL),
|
||||
FIT_TIMESTAMP_PROP, fit_get_name(fit, noffset),
|
||||
fdt_strerror(ret));
|
||||
return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -1;
|
||||
}
|
||||
@@ -1352,7 +935,7 @@ int fit_image_verify_with_data(const void *fit, int image_noffset,
|
||||
|
||||
/* Process all hash subnodes of the component image node */
|
||||
fdt_for_each_subnode(noffset, fit, image_noffset) {
|
||||
const char *name = fit_get_name(fit, noffset, NULL);
|
||||
const char *name = fit_get_name(fit, noffset);
|
||||
|
||||
/*
|
||||
* Check subnode name, must be equal to "hash".
|
||||
@@ -1393,8 +976,8 @@ int fit_image_verify_with_data(const void *fit, int image_noffset,
|
||||
|
||||
error:
|
||||
printf(" error!\n%s for '%s' hash node in '%s' image node\n",
|
||||
err_msg, fit_get_name(fit, noffset, NULL),
|
||||
fit_get_name(fit, image_noffset, NULL));
|
||||
err_msg, fit_get_name(fit, noffset),
|
||||
fit_get_name(fit, image_noffset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1413,7 +996,7 @@ error:
|
||||
*/
|
||||
int fit_image_verify(const void *fit, int image_noffset)
|
||||
{
|
||||
const char *name = fit_get_name(fit, image_noffset, NULL);
|
||||
const char *name = fit_get_name(fit, image_noffset);
|
||||
const void *data;
|
||||
size_t size;
|
||||
char *err_msg = "";
|
||||
@@ -1437,7 +1020,7 @@ int fit_image_verify(const void *fit, int image_noffset)
|
||||
|
||||
err:
|
||||
printf("error!\n%s in '%s' image node\n", err_msg,
|
||||
fit_get_name(fit, image_noffset, NULL));
|
||||
fit_get_name(fit, image_noffset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1480,7 +1063,7 @@ int fit_all_image_verify(const void *fit)
|
||||
* i.e. component image node.
|
||||
*/
|
||||
printf(" Hash(es) for Image %u (%s): ", count,
|
||||
fit_get_name(fit, noffset, NULL));
|
||||
fit_get_name(fit, noffset));
|
||||
count++;
|
||||
|
||||
if (!fit_image_verify(fit, noffset))
|
||||
@@ -1972,7 +1555,10 @@ int fit_get_data_conf_prop(const void *fit, const char *prop_name,
|
||||
|
||||
static int print_and_verify(const void *fit, int rd_noffset, int verify)
|
||||
{
|
||||
fit_image_print(fit, rd_noffset, " ");
|
||||
struct fit_print_ctx ctx;
|
||||
|
||||
fit_print_init(&ctx, fit);
|
||||
fit_image_print(&ctx, rd_noffset);
|
||||
|
||||
if (verify) {
|
||||
puts(" Verifying Hash Integrity ... ");
|
||||
@@ -2127,7 +1713,7 @@ static int select_from_config(const void *fit, struct bootm_headers *images,
|
||||
return -ENOPKG;
|
||||
}
|
||||
|
||||
*fit_unamep = fit_get_name(fit, noffset, NULL);
|
||||
*fit_unamep = fit_get_name(fit, noffset);
|
||||
|
||||
return noffset;
|
||||
}
|
||||
@@ -2639,7 +2225,7 @@ int boot_get_fdt_fit(struct bootm_headers *images, ulong addr,
|
||||
if (i < count) {
|
||||
noffset = fit_conf_get_prop_node_index(fit, cfg_noffset,
|
||||
FIT_FDT_PROP, i);
|
||||
uname = fit_get_name(fit, noffset, NULL);
|
||||
uname = fit_get_name(fit, noffset);
|
||||
uconfig = NULL;
|
||||
} else {
|
||||
if (!next_config)
|
||||
|
||||
@@ -255,7 +255,7 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
|
||||
if (fit_image_get_load(fit, node, &load_addr)) {
|
||||
if (!image_info->load_addr) {
|
||||
printf("Can't load %s: No load address and no buffer\n",
|
||||
fit_get_name(fit, node, NULL));
|
||||
fit_get_name(fit, node));
|
||||
return -ENOBUFS;
|
||||
}
|
||||
load_addr = image_info->load_addr;
|
||||
@@ -281,7 +281,7 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
|
||||
/* Dont bother to copy 0 byte data, but warn, though */
|
||||
if (!len) {
|
||||
log_warning("%s: Skip load '%s': image size is 0!\n",
|
||||
__func__, fit_get_name(fit, node, NULL));
|
||||
__func__, fit_get_name(fit, node));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
|
||||
|
||||
if (CONFIG_IS_ENABLED(FIT_SIGNATURE)) {
|
||||
printf("## Checking hash(es) for Image %s ... ",
|
||||
fit_get_name(fit, node, NULL));
|
||||
fit_get_name(fit, node));
|
||||
if (!fit_image_verify_with_data(fit, node, gd_fdt_blob(), src,
|
||||
length))
|
||||
return -EPERM;
|
||||
@@ -489,12 +489,12 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
|
||||
(void *)image_info.load_addr);
|
||||
if (ret) {
|
||||
pr_err("failed to apply DT overlay %s\n",
|
||||
fit_get_name(ctx->fit, node, NULL));
|
||||
fit_get_name(ctx->fit, node));
|
||||
break;
|
||||
}
|
||||
|
||||
debug("%s: DT overlay %s applied\n", __func__,
|
||||
fit_get_name(ctx->fit, node, NULL));
|
||||
fit_get_name(ctx->fit, node));
|
||||
}
|
||||
free(tmpbuffer);
|
||||
if (ret)
|
||||
@@ -720,7 +720,7 @@ static int spl_simple_fit_parse(struct spl_fit_info *ctx)
|
||||
|
||||
if (IS_ENABLED(CONFIG_SPL_FIT_SIGNATURE)) {
|
||||
printf("## Checking hash(es) for config %s ... ",
|
||||
fit_get_name(ctx->fit, ctx->conf_node, NULL));
|
||||
fit_get_name(ctx->fit, ctx->conf_node));
|
||||
if (fit_config_verify(ctx->fit, ctx->conf_node))
|
||||
return -EPERM;
|
||||
puts("OK\n");
|
||||
|
||||
@@ -278,7 +278,7 @@ got_update_file:
|
||||
if (ndepth != 1)
|
||||
goto next_node;
|
||||
|
||||
fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
|
||||
fit_image_name = (char *)fit_get_name(fit, noffset);
|
||||
printf("Processing update '%s' :", fit_image_name);
|
||||
|
||||
if (!fit_image_verify(fit, noffset)) {
|
||||
@@ -354,7 +354,7 @@ int fit_update(const void *fit)
|
||||
if (ndepth != 1)
|
||||
goto next_node;
|
||||
|
||||
fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
|
||||
fit_image_name = (char *)fit_get_name(fit, noffset);
|
||||
printf("Processing update '%s' :", fit_image_name);
|
||||
|
||||
if (!fit_image_verify(fit, noffset)) {
|
||||
|
||||
@@ -613,7 +613,7 @@ static int first_loading_rbf_to_buffer(struct udevice *dev,
|
||||
images_noffset = fit_conf_get_prop_node_index(buffer_p,
|
||||
confs_noffset,
|
||||
FIT_FPGA_PROP, i);
|
||||
uname = fit_get_name(buffer_p, images_noffset, NULL);
|
||||
uname = fit_get_name(buffer_p, images_noffset);
|
||||
if (uname) {
|
||||
debug("FPGA: %s\n", uname);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ struct fdt_region;
|
||||
#include <sys/types.h>
|
||||
#include <linux/kconfig.h>
|
||||
|
||||
#define IMAGE_INDENT 0
|
||||
#define IMAGE_INDENT_STRING ""
|
||||
#define BIT(nr) (1UL << (nr))
|
||||
|
||||
@@ -37,6 +38,7 @@ struct fdt_region;
|
||||
#include <linker_lists.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define IMAGE_INDENT 3
|
||||
#define IMAGE_INDENT_STRING " "
|
||||
|
||||
#endif /* USE_HOSTCC */
|
||||
@@ -1198,8 +1200,70 @@ int fit_parse_subimage(const char *spec, ulong addr_curr,
|
||||
ulong *addr, const char **image_name);
|
||||
|
||||
int fit_get_subimage_count(const void *fit, int images_noffset);
|
||||
|
||||
/**
|
||||
* struct fit_print_ctx - context for FIT printing
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @indent: indentation level for printing
|
||||
* @tab: amount of space to tab out for the label
|
||||
*/
|
||||
struct fit_print_ctx {
|
||||
const void *fit;
|
||||
int indent;
|
||||
int tab;
|
||||
};
|
||||
|
||||
/**
|
||||
* fit_print_init() - initialize FIT print context
|
||||
* @ctx: pointer to FIT print context to initialize
|
||||
* @fit: pointer to the FIT format image header
|
||||
*
|
||||
* This initializes a fit_print_ctx structure with the given FIT image.
|
||||
*/
|
||||
void fit_print_init(struct fit_print_ctx *ctx, const void *fit);
|
||||
|
||||
/**
|
||||
* fit_print() - prints out the contents of the FIT format image
|
||||
* @ctx: pointer to FIT print context
|
||||
*
|
||||
* fit_print() formats a multi line FIT image contents description.
|
||||
* The routine prints out FIT image properties (root node level) followed by
|
||||
* the details of each component image.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
void fit_print(struct fit_print_ctx *ctx);
|
||||
|
||||
/**
|
||||
* fit_print_contents() - prints out the contents of the FIT format image
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @p: pointer to prefix string
|
||||
*
|
||||
* fit_print_contents() formats a multi line FIT image contents description.
|
||||
* The routine prints out FIT image properties (root node level) followed by
|
||||
* the details of each component image.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
void fit_print_contents(const void *fit);
|
||||
void fit_image_print(const void *fit, int noffset, const char *p);
|
||||
|
||||
/**
|
||||
* fit_image_print - prints out the FIT component image details
|
||||
* @ctx: pointer to FIT print context
|
||||
* @image_noffset: offset of the component image node
|
||||
*
|
||||
* fit_image_print() lists all mandatory properties for the processed component
|
||||
* image. If present, hash nodes are printed out as well. Load
|
||||
* address for images of type firmware is also printed out. Since the load
|
||||
* address is not mandatory for firmware images, it will be output as
|
||||
* "unavailable" when not present.
|
||||
*
|
||||
* returns:
|
||||
* no returned results
|
||||
*/
|
||||
void fit_image_print(struct fit_print_ctx *ctx, int noffset);
|
||||
|
||||
/**
|
||||
* fit_get_end - get FIT image size
|
||||
@@ -1225,15 +1289,15 @@ ulong fit_get_end(const void *fit);
|
||||
/**
|
||||
* fit_get_name - get FIT node name
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @noffset: node offset
|
||||
*
|
||||
* returns:
|
||||
* NULL, on error
|
||||
* pointer to node name, on success
|
||||
*/
|
||||
static inline const char *fit_get_name(const void *fit_hdr,
|
||||
int noffset, int *len)
|
||||
static inline const char *fit_get_name(const void *fit_hdr, int noffset)
|
||||
{
|
||||
return fdt_get_name(fit_hdr, noffset, len);
|
||||
return fdt_get_name(fit_hdr, noffset, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
ifdef CONFIG_UT_BOOTSTD
|
||||
obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o
|
||||
obj-$(CONFIG_FIT) += image.o
|
||||
obj-$(CONFIG_$(PHASE_)FIT_PRINT) += fit_print.o
|
||||
obj-$(CONFIG_BLK_LUKS) += luks.o
|
||||
|
||||
obj-$(CONFIG_EXPO) += expo.o expo_common.o
|
||||
|
||||
191
test/boot/fit_print.c
Normal file
191
test/boot/fit_print.c
Normal file
@@ -0,0 +1,191 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Test for FIT image printing
|
||||
*
|
||||
* Copyright 2025 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <image.h>
|
||||
#include <mapmem.h>
|
||||
#include <os.h>
|
||||
#include <test/ut.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include "bootstd_common.h"
|
||||
|
||||
/* Test fit_print_contents() output */
|
||||
static int test_fit_print(struct unit_test_state *uts)
|
||||
{
|
||||
char fname[256];
|
||||
void *fit;
|
||||
void *buf;
|
||||
ulong addr;
|
||||
int size;
|
||||
|
||||
/* Load the FIT created by the Python test */
|
||||
ut_assertok(os_persistent_file(fname, sizeof(fname), "test-fit.fit"));
|
||||
ut_assertok(os_read_file(fname, &buf, &size));
|
||||
|
||||
/* Copy to address 0x10000 and print from there */
|
||||
addr = 0x10000;
|
||||
fit = map_sysmem(addr, size);
|
||||
memcpy(fit, buf, size);
|
||||
|
||||
/* Print it and check output line by line */
|
||||
console_record_reset_enable();
|
||||
fit_print_contents(fit);
|
||||
|
||||
/* Check every line of output */
|
||||
ut_assert_nextline(" FIT description: Test FIT image for printing");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Image 0 (kernel)");
|
||||
ut_assert_nextline(" Description: Test kernel");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Type: Kernel Image");
|
||||
ut_assert_nextline(" Compression: gzip compressed");
|
||||
ut_assert_nextline(" Data Start: 0x000100c4");
|
||||
ut_assert_nextline(" Data Size: 327 Bytes = 327 Bytes");
|
||||
ut_assert_nextline(" Architecture: Sandbox");
|
||||
ut_assert_nextline(" OS: Linux");
|
||||
ut_assert_nextline(" Load Address: 0x01000000");
|
||||
ut_assert_nextline(" Entry Point: 0x01000000");
|
||||
ut_assert_nextline(" Hash algo: sha256");
|
||||
ut_assert_nextline(" Hash value: fad998b94ef12fdac0c347915d8b9b6069a4011399e1a2097638a2cb33244cee");
|
||||
ut_assert_nextline(" Image 1 (ramdisk)");
|
||||
ut_assert_nextline(" Description: Test ramdisk");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Type: RAMDisk Image");
|
||||
ut_assert_nextline(" Compression: uncompressed");
|
||||
ut_assert_nextline(" Data Start: 0x00010304");
|
||||
ut_assert_nextline(" Data Size: 301 Bytes = 301 Bytes");
|
||||
ut_assert_nextline(" Architecture: Sandbox");
|
||||
ut_assert_nextline(" OS: Linux");
|
||||
ut_assert_nextline(" Load Address: 0x02000000");
|
||||
ut_assert_nextline(" Entry Point: unavailable");
|
||||
ut_assert_nextline(" Hash algo: sha256");
|
||||
ut_assert_nextline(" Hash value: 53e2a65d92ad890dcd89d83a1f95ad6b8206e0e4889548b035062fc494e7f655");
|
||||
ut_assert_nextline(" Image 2 (fdt-1)");
|
||||
ut_assert_nextline(" Description: Test FDT 1");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Type: Flat Device Tree");
|
||||
ut_assert_nextline(" Compression: uncompressed");
|
||||
ut_assert_nextline(" Data Start: 0x00010518");
|
||||
ut_assert_nextline(" Data Size: 161 Bytes = 161 Bytes");
|
||||
ut_assert_nextline(" Architecture: Sandbox");
|
||||
ut_assert_nextline(" Hash algo: sha256");
|
||||
ut_assert_nextline(" Hash value: 1264bc4619a1162736fdca8e63e44a1b009fbeaaa259c356b555b91186257ffb");
|
||||
ut_assert_nextline(" Image 3 (fdt-2)");
|
||||
ut_assert_nextline(" Description: Test FDT 2");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Type: Flat Device Tree");
|
||||
ut_assert_nextline(" Compression: uncompressed");
|
||||
ut_assert_nextline(" Data Start: 0x0001067c");
|
||||
ut_assert_nextline(" Data Size: 161 Bytes = 161 Bytes");
|
||||
ut_assert_nextline(" Architecture: Sandbox");
|
||||
ut_assert_nextline(" Hash algo: sha256");
|
||||
ut_assert_nextline(" Hash value: 3a07e37c76dd48c2a17927981f0959758ac6fd0d649e2032143c5afeea9a98a4");
|
||||
ut_assert_nextline(" Image 4 (firmware-1)");
|
||||
ut_assert_nextline(" Description: Test Firmware 1");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Type: Firmware");
|
||||
ut_assert_nextline(" Compression: uncompressed");
|
||||
ut_assert_nextline(" Data Start: 0x000107e8");
|
||||
ut_assert_nextline(" Data Size: 3891 Bytes = 3.8 KiB");
|
||||
ut_assert_nextline(" Architecture: Sandbox");
|
||||
ut_assert_nextline(" OS: Unknown OS");
|
||||
ut_assert_nextline(" Load Address: unavailable");
|
||||
ut_assert_nextline(" Hash algo: sha256");
|
||||
ut_assert_nextline(" Hash value: 53f1358540a556282764ceaf2912e701d2e25902a6b069b329e57e3c59148414");
|
||||
ut_assert_nextline(" Image 5 (firmware-2)");
|
||||
ut_assert_nextline(" Description: Test Firmware 2");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Type: Firmware");
|
||||
ut_assert_nextline(" Compression: uncompressed");
|
||||
ut_assert_nextline(" Data Start: 0x000117e8");
|
||||
ut_assert_nextline(" Data Size: 3891 Bytes = 3.8 KiB");
|
||||
ut_assert_nextline(" Architecture: Sandbox");
|
||||
ut_assert_nextline(" OS: Unknown OS");
|
||||
ut_assert_nextline(" Load Address: unavailable");
|
||||
ut_assert_nextline(" Hash algo: sha256");
|
||||
ut_assert_nextline(" Hash value: 6a12ac2283f3c9605113b5c2287e983da5671d8d0015381009d75169526676f1");
|
||||
ut_assert_nextline(" Image 6 (fpga)");
|
||||
ut_assert_nextline(" Description: Test FPGA");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Type: FPGA Image");
|
||||
ut_assert_nextline(" Compression: uncompressed");
|
||||
ut_assert_nextline(" Data Start: 0x000127e0");
|
||||
ut_assert_nextline(" Data Size: 4291 Bytes = 4.2 KiB");
|
||||
ut_assert_nextline(" Load Address: unavailable");
|
||||
ut_assert_nextline(" Hash algo: sha256");
|
||||
ut_assert_nextline(" Hash value: 2f588e50e95abc7f9d6afd1d5b3f2bf285cccd55efcf52f47a975dbff3265622");
|
||||
ut_assert_nextline(" Image 7 (script)");
|
||||
ut_assert_nextline(" Description: unavailable");
|
||||
ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Type: Script");
|
||||
ut_assert_nextline(" Compression: uncompressed");
|
||||
ut_assert_nextline(" Data Start: 0x0001394c");
|
||||
ut_assert_nextline(" Data Size: 3791 Bytes = 3.7 KiB");
|
||||
ut_assert_nextline(" Hash algo: invalid/unsupported");
|
||||
ut_assert_nextline(" Default Configuration: 'conf-1'");
|
||||
ut_assert_nextline(" Configuration 0 (conf-1)");
|
||||
ut_assert_nextline(" Description: Test configuration");
|
||||
ut_assert_nextline(" Kernel: kernel");
|
||||
ut_assert_nextline(" Init Ramdisk: ramdisk");
|
||||
ut_assert_nextline(" FDT: fdt-1");
|
||||
ut_assert_nextline(" Compatible: vendor,board-1.0");
|
||||
ut_assert_nextline(" vendor,board");
|
||||
ut_assert_nextline(" Sign algo: sha256,rsa2048:test-key");
|
||||
ut_assert_nextline(" Sign padding: pkcs-1.5");
|
||||
ut_assert_nextlinen(" Sign value: c20f64d9bf79ddb0b1a6");
|
||||
ut_assert_nextline(" Timestamp: 2009-02-13 23:31:30 UTC");
|
||||
ut_assert_nextline(" Configuration 1 (conf-2)");
|
||||
ut_assert_nextline(" Description: Alternate configuration");
|
||||
ut_assert_nextline(" Kernel: kernel");
|
||||
ut_assert_nextline(" FDT: fdt-1");
|
||||
ut_assert_nextline(" fdt-2");
|
||||
ut_assert_nextline(" FPGA: fpga");
|
||||
ut_assert_nextline(" Loadables: firmware-1");
|
||||
ut_assert_nextline(" firmware-2");
|
||||
ut_assert_nextline(" Compatible: vendor,board-2.0");
|
||||
ut_assert_nextline(" Configuration 2 (conf-3)");
|
||||
ut_assert_nextline(" Description: unavailable");
|
||||
ut_assert_nextline(" Kernel: unavailable");
|
||||
ut_assert_nextline(" Loadables: script");
|
||||
ut_assert_console_end();
|
||||
|
||||
os_free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BOOTSTD_TEST(test_fit_print, UTF_CONSOLE);
|
||||
|
||||
/* Test fit_print_contents() with missing FIT description */
|
||||
static int test_fit_print_no_desc(struct unit_test_state *uts)
|
||||
{
|
||||
char fname[256];
|
||||
void *fit;
|
||||
void *buf;
|
||||
ulong addr;
|
||||
int size;
|
||||
|
||||
/* Load the FIT created by the Python test (which deleted description) */
|
||||
ut_assertok(os_persistent_file(fname, sizeof(fname), "test-fit-nodesc.fit"));
|
||||
ut_assertok(os_read_file(fname, &buf, &size));
|
||||
|
||||
/* Copy to address 0x10000 and print from there */
|
||||
addr = 0x10000;
|
||||
fit = map_sysmem(addr, size);
|
||||
memcpy(fit, buf, size);
|
||||
|
||||
/* Print it and check just the first line */
|
||||
console_record_reset_enable();
|
||||
fit_print_contents(fit);
|
||||
|
||||
/* Check the first line shows unavailable */
|
||||
ut_assert_nextline(" FIT description: unavailable");
|
||||
|
||||
os_free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BOOTSTD_TEST(test_fit_print_no_desc, UTF_CONSOLE);
|
||||
270
test/py/tests/test_fit_print.py
Normal file
270
test/py/tests/test_fit_print.py
Normal file
@@ -0,0 +1,270 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2025, Google Inc.
|
||||
|
||||
"""Test for FIT image printing"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import shutil
|
||||
import utils
|
||||
import fit_util
|
||||
|
||||
# ITS for testing FIT printing with hashes, ramdisk, and multiple configs
|
||||
PRINT_ITS = '''
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
description = "Test FIT image for printing";
|
||||
#address-cells = <1>;
|
||||
|
||||
images {
|
||||
kernel {
|
||||
description = "Test kernel";
|
||||
data = /incbin/("%(kernel)s");
|
||||
type = "kernel";
|
||||
arch = "sandbox";
|
||||
os = "linux";
|
||||
compression = "gzip";
|
||||
load = <0x1000000>;
|
||||
entry = <0x1000000>;
|
||||
hash-1 {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
ramdisk {
|
||||
description = "Test ramdisk";
|
||||
data = /incbin/("%(ramdisk)s");
|
||||
type = "ramdisk";
|
||||
arch = "sandbox";
|
||||
os = "linux";
|
||||
compression = "none";
|
||||
load = <0x2000000>;
|
||||
hash-1 {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
fdt-1 {
|
||||
description = "Test FDT 1";
|
||||
data = /incbin/("%(fdt1)s");
|
||||
type = "flat_dt";
|
||||
arch = "sandbox";
|
||||
compression = "none";
|
||||
hash-1 {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
fdt-2 {
|
||||
description = "Test FDT 2";
|
||||
data = /incbin/("%(fdt2)s");
|
||||
type = "flat_dt";
|
||||
arch = "sandbox";
|
||||
compression = "none";
|
||||
hash-1 {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
firmware-1 {
|
||||
description = "Test Firmware 1";
|
||||
data = /incbin/("%(firmware1)s");
|
||||
type = "firmware";
|
||||
arch = "sandbox";
|
||||
compression = "none";
|
||||
hash-1 {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
firmware-2 {
|
||||
description = "Test Firmware 2";
|
||||
data = /incbin/("%(firmware2)s");
|
||||
type = "firmware";
|
||||
arch = "sandbox";
|
||||
compression = "none";
|
||||
hash-1 {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
fpga {
|
||||
description = "Test FPGA";
|
||||
data = /incbin/("%(fpga)s");
|
||||
type = "fpga";
|
||||
arch = "sandbox";
|
||||
compression = "none";
|
||||
hash-1 {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
script {
|
||||
data = /incbin/("%(script)s");
|
||||
type = "script";
|
||||
compression = "none";
|
||||
hash-1 {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
};
|
||||
configurations {
|
||||
default = "conf-1";
|
||||
conf-1 {
|
||||
description = "Test configuration";
|
||||
kernel = "kernel";
|
||||
fdt = "fdt-1";
|
||||
ramdisk = "ramdisk";
|
||||
compatible = "vendor,board-1.0", "vendor,board";
|
||||
signature {
|
||||
algo = "sha256,rsa2048";
|
||||
padding = "pkcs-1.5";
|
||||
key-name-hint = "test-key";
|
||||
sign-images = "fdt-1", "kernel", "ramdisk";
|
||||
};
|
||||
};
|
||||
conf-2 {
|
||||
description = "Alternate configuration";
|
||||
kernel = "kernel";
|
||||
fdt = "fdt-1", "fdt-2";
|
||||
fpga = "fpga";
|
||||
loadables = "firmware-1", "firmware-2";
|
||||
compatible = "vendor,board-2.0";
|
||||
};
|
||||
conf-3 {
|
||||
loadables = "script";
|
||||
};
|
||||
};
|
||||
};
|
||||
'''
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('fit')
|
||||
@pytest.mark.buildconfigspec('fit_print')
|
||||
@pytest.mark.requiredtool('dtc')
|
||||
@pytest.mark.requiredtool('openssl')
|
||||
def test_fit_print(ubman):
|
||||
"""Test fit_print_contents() via C unit test"""
|
||||
mkimage = os.path.join(ubman.config.build_dir, 'tools/mkimage')
|
||||
|
||||
# Create test files (make kernel ~6.3K)
|
||||
kernel = fit_util.make_kernel(ubman, 'test-kernel.bin',
|
||||
'kernel with some extra test data')
|
||||
|
||||
# Compress the kernel (with -n to avoid timestamps for reproducibility)
|
||||
kernel_gz = kernel + '.gz'
|
||||
utils.run_and_log(ubman, ['gzip', '-f', '-n', '-k', kernel])
|
||||
|
||||
fdt1 = fit_util.make_dtb(ubman, '''
|
||||
/dts-v1/;
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
model = "Test FDT 1";
|
||||
};
|
||||
''', 'test-fdt-1')
|
||||
fdt2 = fit_util.make_dtb(ubman, '''
|
||||
/dts-v1/;
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
model = "Test FDT 2";
|
||||
};
|
||||
''', 'test-fdt-2')
|
||||
firmware1 = fit_util.make_kernel(ubman, 'test-firmware-1.bin', 'firmware 1')
|
||||
firmware2 = fit_util.make_kernel(ubman, 'test-firmware-2.bin', 'firmware 2')
|
||||
fpga = fit_util.make_kernel(ubman, 'test-fpga.bin', 'fpga bitstream')
|
||||
ramdisk = fit_util.make_kernel(ubman, 'test-ramdisk.bin', 'ramdisk')
|
||||
script = fit_util.make_kernel(ubman, 'test-script.bin', 'echo test')
|
||||
|
||||
# Compress the ramdisk (with -n to avoid timestamps for reproducibility)
|
||||
ramdisk_gz = ramdisk + '.gz'
|
||||
utils.run_and_log(ubman, ['gzip', '-f', '-n', '-k', ramdisk])
|
||||
|
||||
# Create FIT image with fixed timestamp for reproducible output
|
||||
params = {
|
||||
'kernel': kernel_gz,
|
||||
'fdt1': fdt1,
|
||||
'fdt2': fdt2,
|
||||
'firmware1': firmware1,
|
||||
'firmware2': firmware2,
|
||||
'fpga': fpga,
|
||||
'ramdisk': ramdisk_gz,
|
||||
'script': script,
|
||||
}
|
||||
env = os.environ.copy()
|
||||
env['SOURCE_DATE_EPOCH'] = '1234567890' # 2009-02-13 23:31:30 UTC
|
||||
fit = fit_util.make_fname(ubman, 'test-fit.fit')
|
||||
its = fit_util.make_its(ubman, PRINT_ITS, params)
|
||||
utils.run_and_log(ubman, [mkimage, '-f', its, fit], env=env)
|
||||
|
||||
# Use a fixed RSA key pair for reproducible signatures
|
||||
tmpdir = ubman.config.result_dir + '/'
|
||||
|
||||
# Fixed 2048-bit RSA private key for testing (for reproducible signatures)
|
||||
key_pem = '''-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDU18AB+xpQw+GX
|
||||
mywzH4nsEIECgLVnBTNaAnE4XSIqbiviZetumBP6Ib2W+0OIOn8/hIh3UnzzyWIP
|
||||
aRus94CVfFQPqwhi6/M9ptL7N7lCXq9DwQ0EY55GquwoO9jZnnDsCSU76jgKg+Nc
|
||||
dsbvprfFDxBjkrLBfdEgzJtNUaJnUCd58RG8sII7EOP4JTGnXn2wVTsKYcTmr8y6
|
||||
bOZTUQfsYj9BGFTbskkLYj1RJ6Dpzk4yBqyUn4fUYhfqsAHwlJs/64Byx2m7J7Ia
|
||||
rfp49NkqgOFlTvDzKnecxGt4pmgEA+4MtRxUFDliZ/bG3TvG/xNlXvWaHp9DG05u
|
||||
4h9jy2NPAgMBAAECggEAAMZKOheeWGXmF8WmSwdV2qiSt54dSuMvdSfmHpTkL3BY
|
||||
M4o4aZ4fEH138ak3bTL9TI9gacLAlqiIdVLmGWKLMsARlD8EmEuQhoxpXyWsRGwQ
|
||||
yjfVIst0A4DSvDC/kMctVQaRfp7TFmK1fJwoDC44o/xyjFI32VFqZeqotAbUhvi3
|
||||
gIYvP5Q4Kvbaq9aZNURqazJHuEVD9LpwbnroUd4cBrcorstJzaDmTIyb5swLX+IX
|
||||
FjMOVtHtBDKOG9Ce1wlEOXZtSsoZtAEgkd1IQYBCTBUDkxPdx+ZKPdfT4aKWX3S4
|
||||
WQ65lDEGAnplMmetFRV+k9NNJvEia9JoX/SJqhUWGQKBgQD1/rffQZnFWqGM2dD1
|
||||
CEkXpCN23xAEaZjQtuIhPMBWEWufAPZhyZSbq3eLjcqSS5mzU8B+n1c9Zxw6r0qM
|
||||
BXlcUftreFPKvEXeyp1YWh7loxHiVVuasp2lEDx4arwUrI61XtAaixUb9Opxxj/x
|
||||
UDrY5cj7BIRhrkDZtnor/EbRaQKBgQDdf9pymbbxRmHHFGERSzo6/gbr1GRK9fUA
|
||||
ZNrzfBM5Sdvmm2aKgYd7hIKhOgeKIkS858gEOsRw75x6nvlrjZvFZGIfetXXxaN9
|
||||
c6Uqq/f6rTRUTB9/SqvMgKZMuJ2SFms8I1nbxSE/PMD0T6TRbhjaFoZwZP42HVsM
|
||||
wAN2Oiq/9wKBgQC7sQHyYkdFgYVJxtfcXdoHI8G7bS73buqeNSwMWCIYiWooA7/5
|
||||
lKjCre2kmSc6wFwhq4FwG3ug6g9r51tlwrd6bUL8GO81/LkC6G1tgDWa2PVIUAB4
|
||||
5FfMHbtF1Ypz68VnNVRrLDuK/S/0Z2NaZ/C+lXTnseaf8Sih9Mz6yp3uIQKBgBc4
|
||||
61cuhH6hSWkM2uxsPaunrGQXPXiadthWupnifUV5V+PCkSqeT+0ERInQwq+Zzikc
|
||||
B91hp+zLQlWcyzuaeiVk0+DHCRp5Lx3c/QkPRI10kVLxNDAtTPvA1S6gAG0rioyg
|
||||
jDA9Z7Hwla5Hl1kZuONMj0XDYN+djkk07Gf9yzObAoGAbiS3mRID0pLFhWR1L64h
|
||||
NlRJpZjsHNRPd0WFVxXnJRzZxkStoTwL2BhPtG3Xx1ReIkNVCxlu1Dk0rLLKl1nj
|
||||
4B/X9Qu6aejXnOsbqp1/JBXYxD8l5B2yg5//wz18um/SOSagpAPeH4i/V3NxOup5
|
||||
S0n8gbs0Ht/ZckLk8mPclbk=
|
||||
-----END PRIVATE KEY-----'''
|
||||
|
||||
with open(tmpdir + 'test-key.key', 'w') as f:
|
||||
f.write(key_pem)
|
||||
|
||||
utils.run_and_log(ubman,
|
||||
f'openssl req -batch -new -x509 -key {tmpdir}test-key.key '
|
||||
f'-out {tmpdir}test-key.crt')
|
||||
|
||||
# Create a dummy DTB for the public key
|
||||
dtb = fit_util.make_fname(ubman, 'test-key.dtb')
|
||||
utils.run_and_log(ubman, ['dtc', '-I', 'dts', '-O', 'dtb', '-o', dtb],
|
||||
stdin=b'/dts-v1/; / { };')
|
||||
|
||||
# Sign the FIT configuration (use env for reproducible timestamp)
|
||||
utils.run_and_log(ubman, [mkimage, '-F', '-k', tmpdir, '-K', dtb,
|
||||
'-r', fit, '-c', 'Configuration signing'], env=env)
|
||||
|
||||
# Delete the algo property from script's hash-1 node to test invalid/unsupported algo
|
||||
utils.run_and_log(ubman, ['fdtput', '-t', 's', fit, '/images/script/hash-1', 'algo', ''])
|
||||
utils.run_and_log(ubman, ['fdtput', '-d', fit, '/images/script/hash-1', 'algo'])
|
||||
|
||||
# Copy to persistent directory with known name
|
||||
persistent_fit = os.path.join(ubman.config.persistent_data_dir,
|
||||
'test-fit.fit')
|
||||
shutil.copy(fit, persistent_fit)
|
||||
|
||||
# Run the C test which will load and verify this FIT
|
||||
ubman.run_command('ut -f bootstd test_fit_print')
|
||||
result = ubman.run_command('echo $?')
|
||||
assert '0' == result
|
||||
|
||||
# Test missing FIT description by deleting it and checking the output
|
||||
fit_no_desc = fit_util.make_fname(ubman, 'test-fit-nodesc.fit')
|
||||
shutil.copy(fit, fit_no_desc)
|
||||
utils.run_and_log(ubman, ['fdtput', '-d', fit_no_desc, '/', 'description'])
|
||||
|
||||
persistent_fit_no_desc = os.path.join(ubman.config.persistent_data_dir,
|
||||
'test-fit-nodesc.fit')
|
||||
shutil.copy(fit_no_desc, persistent_fit_no_desc)
|
||||
|
||||
# Run a second C test to check the missing description
|
||||
ubman.run_command('ut -f bootstd test_fit_print_no_desc')
|
||||
result = ubman.run_command('echo $?')
|
||||
assert '0' == result
|
||||
@@ -72,6 +72,7 @@ hostprogs-y += file2include
|
||||
endif
|
||||
|
||||
FIT_OBJS-y := fit_common.o fit_image.o image-host.o generated/boot/image-fit.o
|
||||
FIT_OBJS-$(CONFIG_FIT_PRINT) += generated/boot/fit_print.o
|
||||
FIT_SIG_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := image-sig-host.o generated/boot/image-fit-sig.o
|
||||
FIT_CIPHER_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := generated/boot/image-cipher.o
|
||||
|
||||
|
||||
@@ -940,10 +940,10 @@ static int fit_extract_contents(void *ptr, struct imgtool *itl)
|
||||
int ndepth;
|
||||
const void *fit = ptr;
|
||||
int count = 0;
|
||||
const char *p;
|
||||
int p;
|
||||
|
||||
/* Indent string is defined in header image.h */
|
||||
p = IMAGE_INDENT_STRING;
|
||||
/* Indent value is defined in header image.h */
|
||||
p = 5;
|
||||
|
||||
/* Find images parent node offset */
|
||||
images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
|
||||
@@ -971,10 +971,13 @@ static int fit_extract_contents(void *ptr, struct imgtool *itl)
|
||||
* i.e. component image node.
|
||||
*/
|
||||
if (itl->pflag == count) {
|
||||
printf("Extracted:\n%s Image %u (%s)\n", p,
|
||||
count, fit_get_name(fit, noffset, NULL));
|
||||
struct fit_print_ctx ctx;
|
||||
|
||||
fit_image_print(fit, noffset, p);
|
||||
printf("Extracted:\n%*s Image %u (%s)\n", p, "",
|
||||
count, fit_get_name(fit, noffset));
|
||||
|
||||
fit_print_init(&ctx, fit);
|
||||
fit_image_print(&ctx, noffset);
|
||||
|
||||
return fit_image_extract(fit, noffset,
|
||||
itl->outfile);
|
||||
|
||||
@@ -98,7 +98,7 @@ int main(int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("NAME: %s\n", fit_get_name(fit_blob, nodeoffset, NULL));
|
||||
printf("NAME: %s\n", fit_get_name(fit_blob, nodeoffset));
|
||||
printf("LEN: %d\n", len);
|
||||
printf("OFF: %d\n", (int)(nodep - fit_blob));
|
||||
(void) munmap((void *)fit_blob, fsbuf.st_size);
|
||||
|
||||
@@ -46,7 +46,7 @@ static int fit_set_hash_value(void *fit, int noffset, uint8_t *value,
|
||||
ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Can't set hash '%s' property for '%s' node(%s)\n",
|
||||
FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
|
||||
FIT_VALUE_PROP, fit_get_name(fit, noffset),
|
||||
fdt_strerror(ret));
|
||||
return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ static int fit_image_process_hash(void *fit, const char *image_name,
|
||||
const char *algo;
|
||||
int ret;
|
||||
|
||||
node_name = fit_get_name(fit, noffset, NULL);
|
||||
node_name = fit_get_name(fit, noffset);
|
||||
|
||||
if (fit_image_hash_get_algo(fit, noffset, &algo)) {
|
||||
fprintf(stderr,
|
||||
@@ -176,7 +176,7 @@ static int fit_image_setup_sig(struct image_sign_info *info,
|
||||
const char *node_name;
|
||||
const char *padding_name;
|
||||
|
||||
node_name = fit_get_name(fit, noffset, NULL);
|
||||
node_name = fit_get_name(fit, noffset);
|
||||
if (!algo_name) {
|
||||
if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
|
||||
fprintf(stderr,
|
||||
@@ -247,7 +247,7 @@ static int fit_image_process_sig(const char *keydir, const char *keyfile,
|
||||
engine_id, algo_name))
|
||||
return -1;
|
||||
|
||||
node_name = fit_get_name(fit, noffset, NULL);
|
||||
node_name = fit_get_name(fit, noffset);
|
||||
region.data = data;
|
||||
region.size = size;
|
||||
ret = info.crypto->sign(&info, ®ion, 1, &value, &value_len);
|
||||
@@ -585,7 +585,7 @@ int fit_image_cipher_data(const char *keydir, void *keydest,
|
||||
int cipher_node_offset, len;
|
||||
|
||||
/* Get image name */
|
||||
image_name = fit_get_name(fit, image_noffset, NULL);
|
||||
image_name = fit_get_name(fit, image_noffset);
|
||||
if (!image_name) {
|
||||
fprintf(stderr, "Can't get image name\n");
|
||||
return -1;
|
||||
@@ -677,7 +677,7 @@ int fit_image_add_verification_data(const char *keydir, const char *keyfile,
|
||||
return -1;
|
||||
}
|
||||
|
||||
image_name = fit_get_name(fit, image_noffset, NULL);
|
||||
image_name = fit_get_name(fit, image_noffset);
|
||||
|
||||
/* Process all hash subnodes of the component image node */
|
||||
for (noffset = fdt_first_subnode(fit, image_noffset);
|
||||
@@ -691,7 +691,7 @@ int fit_image_add_verification_data(const char *keydir, const char *keyfile,
|
||||
* Multiple hash nodes require unique unit node
|
||||
* names, e.g. hash-1, hash-2, signature-1, etc.
|
||||
*/
|
||||
node_name = fit_get_name(fit, noffset, NULL);
|
||||
node_name = fit_get_name(fit, noffset);
|
||||
if (!strncmp(node_name, FIT_HASH_NODENAME,
|
||||
strlen(FIT_HASH_NODENAME))) {
|
||||
ret = fit_image_process_hash(fit, image_name, noffset,
|
||||
@@ -809,7 +809,7 @@ static int fit_config_add_hash(const void *fit, int image_noffset,
|
||||
for (noffset = fdt_first_subnode(fit, image_noffset);
|
||||
noffset >= 0;
|
||||
noffset = fdt_next_subnode(fit, noffset)) {
|
||||
const char *name = fit_get_name(fit, noffset, NULL);
|
||||
const char *name = fit_get_name(fit, noffset);
|
||||
|
||||
if (strncmp(name, FIT_HASH_NODENAME,
|
||||
strlen(FIT_HASH_NODENAME)))
|
||||
@@ -884,8 +884,8 @@ static int fit_config_get_hash_list(const void *fit, int conf_noffset,
|
||||
int image_count;
|
||||
int ret, len;
|
||||
|
||||
conf_name = fit_get_name(fit, conf_noffset, NULL);
|
||||
sig_name = fit_get_name(fit, sig_offset, NULL);
|
||||
conf_name = fit_get_name(fit, conf_noffset);
|
||||
sig_name = fit_get_name(fit, sig_offset);
|
||||
|
||||
/*
|
||||
* Build a list of nodes we need to hash. We always need the root
|
||||
@@ -991,8 +991,8 @@ static int fit_config_get_regions(const void *fit, int conf_noffset,
|
||||
char *region_prop;
|
||||
int ret, len;
|
||||
|
||||
conf_name = fit_get_name(fit, conf_noffset, NULL);
|
||||
sig_name = fit_get_name(fit, sig_offset, NULL);
|
||||
conf_name = fit_get_name(fit, conf_noffset);
|
||||
sig_name = fit_get_name(fit, sig_offset);
|
||||
debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
|
||||
|
||||
/* Get a list of nodes we want to hash */
|
||||
@@ -1084,7 +1084,7 @@ static int fit_config_process_sig(const char *keydir, const char *keyfile,
|
||||
uint value_len;
|
||||
int ret;
|
||||
|
||||
node_name = fit_get_name(fit, noffset, NULL);
|
||||
node_name = fit_get_name(fit, noffset);
|
||||
if (fit_config_get_regions(fit, conf_noffset, noffset, ®ion,
|
||||
®ion_count, ®ion_prop,
|
||||
®ion_proplen))
|
||||
@@ -1148,7 +1148,7 @@ static int fit_config_add_verification_data(const char *keydir,
|
||||
const char *conf_name;
|
||||
int noffset;
|
||||
|
||||
conf_name = fit_get_name(fit, conf_noffset, NULL);
|
||||
conf_name = fit_get_name(fit, conf_noffset);
|
||||
|
||||
/* Process all hash subnodes of the configuration node */
|
||||
for (noffset = fdt_first_subnode(fit, conf_noffset);
|
||||
@@ -1157,7 +1157,7 @@ static int fit_config_add_verification_data(const char *keydir,
|
||||
const char *node_name;
|
||||
int ret = 0;
|
||||
|
||||
node_name = fit_get_name(fit, noffset, NULL);
|
||||
node_name = fit_get_name(fit, noffset);
|
||||
if (!strncmp(node_name, FIT_SIG_NODENAME,
|
||||
strlen(FIT_SIG_NODENAME))) {
|
||||
ret = fit_config_process_sig(keydir, keyfile, keydest,
|
||||
|
||||
Reference in New Issue
Block a user