Commit 4cc35f88 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev

start over

parent 11a59314
/*
* (C) Copyright 2008 Semihalf
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __FDT_HOST_H__
#define __FDT_HOST_H__
/* Make sure to include u-boot version of libfdt include files */
#include "../include/libfdt.h"
#include "../include/fdt_support.h"
/**
* fdt_remove_unused_strings() - Remove any unused strings from an FDT
*
* This creates a new device tree in @new with unused strings removed. The
* called can then use fdt_pack() to minimise the space consumed.
*
* @old: Old device tree blog
* @new: Place to put new device tree blob, which must be as large as
* @old
* @return
* 0, on success
* -FDT_ERR_BADOFFSET, corrupt device tree
* -FDT_ERR_NOSPACE, out of space, which should not happen unless there
* is something very wrong with the device tree input
*/
int fdt_remove_unused_strings(const void *old, void *new);
int fit_check_sign(const void *working_fdt, const void *key);
#endif /* __FDT_HOST_H__ */
/*
* Copyright (c) 2013, Google Inc.
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*
* Perform a grep of an FDT either displaying the source subset or producing
* a new .dtb subset which can be used as required.
*/
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fdt_host.h"
#include "libfdt_internal.h"
/* Define DEBUG to get some debugging output on stderr */
#ifdef DEBUG
#define debug(a, b...) fprintf(stderr, a, ## b)
#else
#define debug(a, b...)
#endif
/* A linked list of values we are grepping for */
struct value_node {
int type; /* Types this value matches (FDT_IS... mask) */
int include; /* 1 to include matches, 0 to exclude */
const char *string; /* String to match */
struct value_node *next; /* Pointer to next node, or NULL */
};
/* Output formats we support */
enum output_t {
OUT_DTS, /* Device tree source */
OUT_DTB, /* Valid device tree binary */
OUT_BIN, /* Fragment of .dtb, for hashing */
};
/* Holds information which controls our output and options */
struct display_info {
enum output_t output; /* Output format */
int add_aliases; /* Add aliases node to output */
int all; /* Display all properties/nodes */
int colour; /* Display output in ANSI colour */
int region_list; /* Output a region list */
int flags; /* Flags (FDT_REG_...) */
int list_strings; /* List strings in string table */
int show_offset; /* Show offset */
int show_addr; /* Show address */
int header; /* Output an FDT header */
int diff; /* Show +/- diff markers */
int include_root; /* Include the root node and all properties */
int remove_strings; /* Remove unused strings */
int show_dts_version; /* Put '/dts-v1/;' on the first line */
int types_inc; /* Mask of types that we include (FDT_IS...) */
int types_exc; /* Mask of types that we exclude (FDT_IS...) */
int invert; /* Invert polarity of match */
struct value_node *value_head; /* List of values to match */
const char *output_fname; /* Output filename */
FILE *fout; /* File to write dts/dtb output */
};
static void report_error(const char *where, int err)
{
fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
}
/* Supported ANSI colours */
enum {
COL_BLACK,
COL_RED,
COL_GREEN,
COL_YELLOW,
COL_BLUE,
COL_MAGENTA,
COL_CYAN,
COL_WHITE,
COL_NONE = -1,
};
/**
* print_ansi_colour() - Print out the ANSI sequence for a colour
*
* @fout: Output file
* @col: Colour to output (COL_...), or COL_NONE to reset colour
*/
static void print_ansi_colour(FILE *fout, int col)
{
if (col == COL_NONE)
fprintf(fout, "\033[0m");
else
fprintf(fout, "\033[1;%dm", col + 30);
}
/**
* value_add() - Add a new value to our list of things to grep for
*
* @disp: Display structure, holding info about our options
* @headp: Pointer to header pointer of list
* @type: Type of this value (FDT_IS_...)
* @include: 1 if we want to include matches, 0 to exclude
* @str: String value to match
*/
static int value_add(struct display_info *disp, struct value_node **headp,
int type, int include, const char *str)
{
struct value_node *node;
/*
* Keep track of which types we are excluding/including. We don't
* allow both including and excluding things, because it doesn't make
* sense. 'Including' means that everything not mentioned is
* excluded. 'Excluding' means that everything not mentioned is
* included. So using the two together would be meaningless.
*/
if (include)
disp->types_inc |= type;
else
disp->types_exc |= type;
if (disp->types_inc & disp->types_exc & type) {
fprintf(stderr,
"Cannot use both include and exclude for '%s'\n", str);
return -1;
}
str = strdup(str);
node = malloc(sizeof(*node));
if (!str || !node) {
fprintf(stderr, "Out of memory\n");
return -1;
}
node->next = *headp;
node->type = type;
node->include = include;
node->string = str;
*headp = node;
return 0;
}
static bool util_is_printable_string(const void *data, int len)
{
const char *s = data;
const char *ss, *se;
/* zero length is not */
if (len == 0)
return 0;
/* must terminate with zero */
if (s[len - 1] != '\0')
return 0;
se = s + len;
while (s < se) {
ss = s;
while (s < se && *s && isprint((unsigned char)*s))
s++;
/* not zero, or not done yet */
if (*s != '\0' || s == ss)
return 0;
s++;
}
return 1;
}
static void utilfdt_print_data(const char *data, int len)
{
int i;
const char *p = data;
const char *s;
/* no data, don't print */
if (len == 0)
return;
if (util_is_printable_string(data, len)) {
printf(" = ");
s = data;
do {
printf("\"%s\"", s);
s += strlen(s) + 1;
if (s < data + len)
printf(", ");
} while (s < data + len);
} else if ((len % 4) == 0) {
const uint32_t *cell = (const uint32_t *)data;
printf(" = <");
for (i = 0, len /= 4; i < len; i++)
printf("0x%08x%s", fdt32_to_cpu(cell[i]),
i < (len - 1) ? " " : "");
printf(">");
} else {
printf(" = [");
for (i = 0; i < len; i++)
printf("%02x%s", *p++, i < len - 1 ? " " : "");
printf("]");
}
}
/**
* display_fdt_by_regions() - Display regions of an FDT source
*
* This dumps an FDT as source, but only certain regions of it. This is the
* final stage of the grep - we have a list of regions we want to display,
* and this function displays them.
*
* @disp: Display structure, holding info about our options
* @blob: FDT blob to display
* @region: List of regions to display
* @count: Number of regions
*/
static int display_fdt_by_regions(struct display_info *disp, const void *blob,
struct fdt_region region[], int count)
{
struct fdt_region *reg = region, *reg_end = region + count;
uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
int base = fdt_off_dt_struct(blob);
int version = fdt_version(blob);
int offset, nextoffset;
int tag, depth, shift;
FILE *f = disp->fout;
uint64_t addr, size;
int in_region;
int file_ofs;
int i;
if (disp->show_dts_version)
fprintf(f, "/dts-v1/;\n");
if (disp->header) {
fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
fdt_totalsize(blob));
fprintf(f, "// off_dt_struct:\t0x%x\n",
fdt_off_dt_struct(blob));
fprintf(f, "// off_dt_strings:\t0x%x\n",
fdt_off_dt_strings(blob));
fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
fprintf(f, "// version:\t\t%d\n", version);
fprintf(f, "// last_comp_version:\t%d\n",
fdt_last_comp_version(blob));
if (version >= 2) {
fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
fdt_boot_cpuid_phys(blob));
}
if (version >= 3) {
fprintf(f, "// size_dt_strings:\t0x%x\n",
fdt_size_dt_strings(blob));
}
if (version >= 17) {
fprintf(f, "// size_dt_struct:\t0x%x\n",
fdt_size_dt_struct(blob));
}
fprintf(f, "\n");
}
if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
const struct fdt_reserve_entry *p_rsvmap;
p_rsvmap = (const struct fdt_reserve_entry *)
((const char *)blob + off_mem_rsvmap);
for (i = 0; ; i++) {
addr = fdt64_to_cpu(p_rsvmap[i].address);
size = fdt64_to_cpu(p_rsvmap[i].size);
if (addr == 0 && size == 0)
break;
fprintf(f, "/memreserve/ %llx %llx;\n",
(unsigned long long)addr,
(unsigned long long)size);
}
}
depth = 0;
nextoffset = 0;
shift = 4; /* 4 spaces per indent */
do {
const struct fdt_property *prop;
const char *name;
int show;
int len;
offset = nextoffset;
/*
* Work out the file offset of this offset, and decide
* whether it is in the region list or not
*/
file_ofs = base + offset;
if (reg < reg_end && file_ofs >= reg->offset + reg->size)
reg++;
in_region = reg < reg_end && file_ofs >= reg->offset &&
file_ofs < reg->offset + reg->size;
tag = fdt_next_tag(blob, offset, &nextoffset);
if (tag == FDT_END)
break;
show = in_region || disp->all;
if (show && disp->diff)
fprintf(f, "%c", in_region ? '+' : '-');
if (!show) {
/* Do this here to avoid 'if (show)' in every 'case' */
if (tag == FDT_BEGIN_NODE)
depth++;
else if (tag == FDT_END_NODE)
depth--;
continue;
}
if (tag != FDT_END) {
if (disp->show_addr)
fprintf(f, "%4x: ", file_ofs);
if (disp->show_offset)
fprintf(f, "%4x: ", file_ofs - base);
}
/* Green means included, red means excluded */
if (disp->colour)
print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
switch (tag) {
case FDT_PROP:
prop = fdt_get_property_by_offset(blob, offset, NULL);
name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
fprintf(f, "%*s%s", depth * shift, "", name);
utilfdt_print_data(prop->data,
fdt32_to_cpu(prop->len));
fprintf(f, ";");
break;
case FDT_NOP:
fprintf(f, "%*s// [NOP]", depth * shift, "");
break;
case FDT_BEGIN_NODE:
name = fdt_get_name(blob, offset, &len);
fprintf(f, "%*s%s {", depth++ * shift, "",
*name ? name : "/");
break;
case FDT_END_NODE:
fprintf(f, "%*s};", --depth * shift, "");
break;
}
/* Reset colour back to normal before end of line */
if (disp->colour)
print_ansi_colour(f, COL_NONE);
fprintf(f, "\n");
} while (1);
/* Print a list of strings if requested */
if (disp->list_strings) {
const char *str;
int str_base = fdt_off_dt_strings(blob);
for (offset = 0; offset < fdt_size_dt_strings(blob);
offset += strlen(str) + 1) {
str = fdt_string(blob, offset);
int len = strlen(str) + 1;
int show;
/* Only print strings that are in the region */
file_ofs = str_base + offset;
in_region = reg < reg_end &&
file_ofs >= reg->offset &&
file_ofs + len < reg->offset +
reg->size;
show = in_region || disp->all;
if (show && disp->diff)
printf("%c", in_region ? '+' : '-');
if (disp->show_addr)
printf("%4x: ", file_ofs);
if (disp->show_offset)
printf("%4x: ", offset);
printf("%s\n", str);
}
}
return 0;
}
/**
* dump_fdt_regions() - Dump regions of an FDT as binary data
*
* This dumps an FDT as binary, but only certain regions of it. This is the
* final stage of the grep - we have a list of regions we want to dump,
* and this function dumps them.
*
* The output of this function may or may not be a valid FDT. To ensure it
* is, these disp->flags must be set:
*
* FDT_REG_SUPERNODES: ensures that subnodes are preceded by their
* parents. Without this option, fragments of subnode data may be
* output without the supernodes above them. This is useful for
* hashing but cannot produce a valid FDT.
* FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
* Without this none of the properties will have names
* FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
* without this.
*
* @disp: Display structure, holding info about our options
* @blob: FDT blob to display
* @region: List of regions to display
* @count: Number of regions
* @out: Output destination
*/
static int dump_fdt_regions(struct display_info *disp, const void *blob,
struct fdt_region region[], int count, char *out)
{
struct fdt_header *fdt;
int size, struct_start;
int ptr;
int i;
/* Set up a basic header (even if we don't actually write it) */
fdt = (struct fdt_header *)out;
memset(fdt, '\0', sizeof(*fdt));
fdt_set_magic(fdt, FDT_MAGIC);
struct_start = FDT_ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry));
fdt_set_off_mem_rsvmap(fdt, struct_start);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
/*
* Calculate the total size of the regions we are writing out. The
* first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
* is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
* is set.
*/
for (i = size = 0; i < count; i++)
size += region[i].size;
/* Bring in the mem_rsvmap section from the old file if requested */
if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
struct_start += region[0].size;
size -= region[0].size;
}
fdt_set_off_dt_struct(fdt, struct_start);
/* Update the header to have the correct offsets/sizes */
if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
int str_size;
str_size = region[count - 1].size;
fdt_set_size_dt_struct(fdt, size - str_size);
fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
fdt_set_size_dt_strings(fdt, str_size);
fdt_set_totalsize(fdt, struct_start + size);
}
/* Write the header if required */
ptr = 0;
if (disp->header) {
ptr = sizeof(*fdt);
while (ptr < fdt_off_mem_rsvmap(fdt))
out[ptr++] = '\0';
}
/* Output all the nodes including any mem_rsvmap/string table */
for (i = 0; i < count; i++) {
struct fdt_region *reg = &region[i];
memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
ptr += reg->size;
}
return ptr;
}
/**
* show_region_list() - Print out a list of regions
*
* The list includes the region offset (absolute offset from start of FDT
* blob in bytes) and size
*
* @reg: List of regions to print
* @count: Number of regions
*/
static void show_region_list(struct fdt_region *reg, int count)
{
int i;
printf("Regions: %d\n", count);
for (i = 0; i < count; i++, reg++) {
printf("%d: %-10x %-10x\n", i, reg->offset,
reg->offset + reg->size);
}
}
static int check_type_include(void *priv, int type, const char *data, int size)
{
struct display_info *disp = priv;
struct value_node *val;
int match, none_match = FDT_IS_ANY;
/* If none of our conditions mention this type, we know nothing */
debug("type=%x, data=%s\n", type, data ? data : "(null)");
if (!((disp->types_inc | disp->types_exc) & type)) {
debug(" - not in any condition\n");
return -1;
}
/*
* Go through the list of conditions. For inclusive conditions, we
* return 1 at the first match. For exclusive conditions, we must
* check that there are no matches.
*/
if (data) {
for (val = disp->value_head; val; val = val->next) {
if (!(type & val->type))
continue;
match = fdt_stringlist_contains(data, size,
val->string);
debug(" - val->type=%x, str='%s', match=%d\n",
val->type, val->string, match);
if (match && val->include) {
debug(" - match inc %s\n", val->string);
return 1;
}
if (match)
none_match &= ~val->type;
}
}
/*
* If this is an exclusive condition, and nothing matches, then we
* should return 1.
*/
if ((type & disp->types_exc) && (none_match & type)) {
debug(" - match exc\n");
/*
* Allow FDT_IS_COMPAT to make the final decision in the
* case where there is no specific type
*/
if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
debug(" - supressed exc node\n");
return -1;
}
return 1;
}
/*
* Allow FDT_IS_COMPAT to make the final decision in the
* case where there is no specific type (inclusive)
*/
if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
return -1;
debug(" - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
disp->types_inc, disp->types_exc, none_match);
return 0;
}
/**
* h_include() - Include handler function for fdt_find_regions()
*
* This function decides whether to include or exclude a node, property or
* compatible string. The function is defined by fdt_find_regions().
*
* The algorithm is documented in the code - disp->invert is 0 for normal
* operation, and 1 to invert the sense of all matches.
*
* See
*/
static int h_include(void *priv, const void *fdt, int offset, int type,
const char *data, int size)
{
struct display_info *disp = priv;
int inc, len;
inc = check_type_include(priv, type, data, size);
if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
return 1;
/*
* If the node name does not tell us anything, check the
* compatible string
*/
if (inc == -1 && type == FDT_IS_NODE) {
debug(" - checking compatible2\n");
data = fdt_getprop(fdt, offset, "compatible", &len);
inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
}
/* If we still have no idea, check for properties in the node */
if (inc != 1 && type == FDT_IS_NODE &&
(disp->types_inc & FDT_NODE_HAS_PROP)) {
debug(" - checking node '%s'\n",
fdt_get_name(fdt, offset, NULL));
for (offset = fdt_first_property_offset(fdt, offset);
offset > 0 && inc != 1;
offset = fdt_next_property_offset(fdt, offset)) {
const struct fdt_property *prop;
const char *str;
prop = fdt_get_property_by_offset(fdt, offset, NULL);
if (!prop)
continue;
str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
strlen(str));
}
if (inc == -1)
inc = 0;
}
switch (inc) {
case 1:
inc = !disp->invert;
break;
case 0:
inc = disp->invert;
break;
}
debug(" - returning %d\n", inc);
return inc;
}
static int h_cmp_region(const void *v1, const void *v2)
{
const struct fdt_region *region1 = v1, *region2 = v2;
return region1->offset - region2->offset;
}
static int fdtgrep_find_regions(const void *fdt,
int (*include_func)(void *priv, const void *fdt, int offset,
int type, const char *data, int size),
struct display_info *disp, struct fdt_region *region,
int max_regions, char *path, int path_len, int flags)
{
struct fdt_region_state state;
int count;
int ret;
count = 0;
ret = fdt_first_region(fdt, include_func, disp,
&region[count++], path, path_len,
disp->flags, &state);
while (ret == 0) {
ret = fdt_next_region(fdt, include_func, disp,
count < max_regions ? &region[count] : NULL,
path, path_len, disp->flags, &state);
if (!ret)
count++;
}
if (ret && ret != -FDT_ERR_NOTFOUND)
return ret;
/* Find all the aliases and add those regions back in */
if (disp->add_aliases && count < max_regions) {
int new_count;
new_count = fdt_add_alias_regions(fdt, region, count,
max_regions, &state);
if (new_count == -FDT_ERR_NOTFOUND) {
/* No alias node found */
} else if (new_count < 0) {
return new_count;
} else if (new_count <= max_regions) {
/*
* The alias regions will now be at the end of the list.
* Sort the regions by offset to get things into the
* right order
*/
count = new_count;
qsort(region, count, sizeof(struct fdt_region),
h_cmp_region);
}
}
return count;
}
int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
{
int fd = 0; /* assume stdin */
char *buf = NULL;
off_t bufsize = 1024, offset = 0;
int ret = 0;
*buffp = NULL;
if (strcmp(filename, "-") != 0) {
fd = open(filename, O_RDONLY);
if (fd < 0)
return errno;
}
/* Loop until we have read everything */
buf = malloc(bufsize);
if (!buf)
return -ENOMEM;
do {
/* Expand the buffer to hold the next chunk */
if (offset == bufsize) {
bufsize *= 2;
buf = realloc(buf, bufsize);
if (!buf)
return -ENOMEM;
}
ret = read(fd, &buf[offset], bufsize - offset);
if (ret < 0) {
ret = errno;
break;
}
offset += ret;
} while (ret != 0);
/* Clean up, including closing stdin; return errno on error */
close(fd);
if (ret)
free(buf);
else
*buffp = buf;
*len = bufsize;
return ret;
}
int utilfdt_read_err(const char *filename, char **buffp)
{
off_t len;
return utilfdt_read_err_len(filename, buffp, &len);
}
char *utilfdt_read_len(const char *filename, off_t *len)
{
char *buff;
int ret = utilfdt_read_err_len(filename, &buff, len);
if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
strerror(ret));
return NULL;
}
/* Successful read */
return buff;
}
char *utilfdt_read(const char *filename)
{
off_t len;
return utilfdt_read_len(filename, &len);
}
/**
* Run the main fdtgrep operation, given a filename and valid arguments
*
* @param disp Display information / options
* @param filename Filename of blob file
* @param return 0 if ok, -ve on error
*/
static int do_fdtgrep(struct display_info *disp, const char *filename)
{
struct fdt_region *region;
int max_regions;
int count = 100;
char path[1024];
char *blob;
int i, ret;
blob = utilfdt_read(filename);
if (!blob)
return -1;
ret = fdt_check_header(blob);
if (ret) {
fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
return ret;
}
/* Allow old files, but they are untested */
if (fdt_version(blob) < 17 && disp->value_head) {
fprintf(stderr,
"Warning: fdtgrep does not fully support version %d files\n",
fdt_version(blob));
}
/*
* We do two passes, since we don't know how many regions we need.
* The first pass will count the regions, but if it is too many,
* we do another pass to actually record them.
*/
for (i = 0; i < 3; i++) {
region = malloc(count * sizeof(struct fdt_region));
if (!region) {
fprintf(stderr, "Out of memory for %d regions\n",
count);
return -1;
}
max_regions = count;
count = fdtgrep_find_regions(blob,
h_include, disp,
region, max_regions, path, sizeof(path),
disp->flags);
if (count < 0) {
report_error("fdt_find_regions", count);
return -1;
}
if (count <= max_regions)
break;
free(region);
}
/* Optionally print a list of regions */
if (disp->region_list)
show_region_list(region, count);
/* Output either source .dts or binary .dtb */
if (disp->output == OUT_DTS) {
ret = display_fdt_by_regions(disp, blob, region, count);
} else {
void *fdt;
/* Allow reserved memory section to expand slightly */
int size = fdt_totalsize(blob) + 16;
fdt = malloc(size);
if (!fdt) {
fprintf(stderr, "Out_of_memory\n");
ret = -1;
goto err;
}
size = dump_fdt_regions(disp, blob, region, count, fdt);
if (disp->remove_strings) {
void *out;
out = malloc(size);
if (!out) {
fprintf(stderr, "Out_of_memory\n");
ret = -1;
goto err;
}
ret = fdt_remove_unused_strings(fdt, out);
if (ret < 0) {
fprintf(stderr,
"Failed to remove unused strings: err=%d\n",
ret);
goto err;
}
free(fdt);
fdt = out;
ret = fdt_pack(fdt);
if (ret < 0) {
fprintf(stderr, "Failed to pack: err=%d\n",
ret);
goto err;
}
size = fdt_totalsize(fdt);
}
if (size != fwrite(fdt, 1, size, disp->fout)) {
fprintf(stderr, "Write failure, %d bytes\n", size);
free(fdt);
ret = 1;
goto err;
}
free(fdt);
}
err:
free(blob);
free(region);
return ret;
}
static const char usage_synopsis[] =
"fdtgrep - extract portions from device tree\n"
"\n"
"Usage:\n"
" fdtgrep <options> <dt file>|-\n\n"
"Output formats are:\n"
"\tdts - device tree soure text\n"
"\tdtb - device tree blob (sets -Hmt automatically)\n"
"\tbin - device tree fragment (may not be a valid .dtb)";
/* Helper for usage_short_opts string constant */
#define USAGE_COMMON_SHORT_OPTS "hV"
/* Helper for aligning long_opts array */
#define a_argument required_argument
/* Helper for usage_long_opts option array */
#define USAGE_COMMON_LONG_OPTS \
{"help", no_argument, NULL, 'h'}, \
{"version", no_argument, NULL, 'V'}, \
{NULL, no_argument, NULL, 0x0}
/* Helper for usage_opts_help array */
#define USAGE_COMMON_OPTS_HELP \
"Print this help and exit", \
"Print version and exit", \
NULL
/* Helper for getopt case statements */
#define case_USAGE_COMMON_FLAGS \
case 'h': usage(NULL); \
case 'V': util_version(); \
case '?': usage("unknown option");
static const char usage_short_opts[] =
"haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
USAGE_COMMON_SHORT_OPTS;
static struct option const usage_long_opts[] = {
{"show-address", no_argument, NULL, 'a'},
{"colour", no_argument, NULL, 'A'},
{"include-node-with-prop", a_argument, NULL, 'b'},
{"include-compat", a_argument, NULL, 'c'},
{"exclude-compat", a_argument, NULL, 'C'},
{"diff", no_argument, NULL, 'd'},
{"enter-node", no_argument, NULL, 'e'},
{"show-offset", no_argument, NULL, 'f'},
{"include-match", a_argument, NULL, 'g'},
{"exclude-match", a_argument, NULL, 'G'},
{"show-header", no_argument, NULL, 'H'},
{"show-version", no_argument, NULL, 'I'},
{"list-regions", no_argument, NULL, 'l'},
{"list-strings", no_argument, NULL, 'L'},
{"include-mem", no_argument, NULL, 'm'},
{"include-node", a_argument, NULL, 'n'},
{"exclude-node", a_argument, NULL, 'N'},
{"include-prop", a_argument, NULL, 'p'},
{"exclude-prop", a_argument, NULL, 'P'},
{"remove-strings", no_argument, NULL, 'r'},
{"include-root", no_argument, NULL, 'R'},
{"show-subnodes", no_argument, NULL, 's'},
{"skip-supernodes", no_argument, NULL, 'S'},
{"show-stringtab", no_argument, NULL, 't'},
{"show-aliases", no_argument, NULL, 'T'},
{"out", a_argument, NULL, 'o'},
{"out-format", a_argument, NULL, 'O'},
{"invert-match", no_argument, NULL, 'v'},
USAGE_COMMON_LONG_OPTS,
};
static const char * const usage_opts_help[] = {
"Display address",
"Show all nodes/tags, colour those that match",
"Include contains containing property",
"Compatible nodes to include in grep",
"Compatible nodes to exclude in grep",
"Diff: Mark matching nodes with +, others with -",
"Enter direct subnode names of matching nodes",
"Display offset",
"Node/property/compatible string to include in grep",
"Node/property/compatible string to exclude in grep",
"Output a header",
"Put \"/dts-v1/;\" on first line of dts output",
"Output a region list",
"List strings in string table",
"Include mem_rsvmap section in binary output",
"Node to include in grep",
"Node to exclude in grep",
"Property to include in grep",
"Property to exclude in grep",
"Remove unused strings from string table",
"Include root node and all properties",
"Show all subnodes matching nodes",
"Don't include supernodes of matching nodes",
"Include string table in binary output",
"Include matching aliases in output",
"-o <output file>",
"-O <output format>",
"Invert the sense of matching (select non-matching lines)",
USAGE_COMMON_OPTS_HELP
};
/**
* Call getopt_long() with standard options
*
* Since all util code runs getopt in the same way, provide a helper.
*/
#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
usage_long_opts, NULL)
void util_usage(const char *errmsg, const char *synopsis,
const char *short_opts, struct option const long_opts[],
const char * const opts_help[])
{
FILE *fp = errmsg ? stderr : stdout;
const char a_arg[] = "<arg>";
size_t a_arg_len = strlen(a_arg) + 1;
size_t i;
int optlen;
fprintf(fp,
"Usage: %s\n"
"\n"
"Options: -[%s]\n", synopsis, short_opts);
/* prescan the --long opt length to auto-align */
optlen = 0;
for (i = 0; long_opts[i].name; ++i) {
/* +1 is for space between --opt and help text */
int l = strlen(long_opts[i].name) + 1;
if (long_opts[i].has_arg == a_argument)
l += a_arg_len;
if (optlen < l)
optlen = l;
}
for (i = 0; long_opts[i].name; ++i) {
/* helps when adding new applets or options */
assert(opts_help[i] != NULL);
/* first output the short flag if it has one */
if (long_opts[i].val > '~')
fprintf(fp, " ");
else
fprintf(fp, " -%c, ", long_opts[i].val);
/* then the long flag */
if (long_opts[i].has_arg == no_argument) {
fprintf(fp, "--%-*s", optlen, long_opts[i].name);
} else {
fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
(int)(optlen - strlen(long_opts[i].name) -
a_arg_len), "");
}
/* finally the help text */
fprintf(fp, "%s\n", opts_help[i]);
}
if (errmsg) {
fprintf(fp, "\nError: %s\n", errmsg);
exit(EXIT_FAILURE);
} else {
exit(EXIT_SUCCESS);
}
}
/**
* Show usage and exit
*
* If you name all your usage variables with usage_xxx, then you can call this
* help macro rather than expanding all arguments yourself.
*
* @param errmsg If non-NULL, an error message to display
*/
#define usage(errmsg) \
util_usage(errmsg, usage_synopsis, usage_short_opts, \
usage_long_opts, usage_opts_help)
void util_version(void)
{
printf("Version: %s\n", "(U-Boot)");
exit(0);
}
static void scan_args(struct display_info *disp, int argc, char *argv[])
{
int opt;
while ((opt = util_getopt_long()) != EOF) {
int type = 0;
int inc = 1;
switch (opt) {
case_USAGE_COMMON_FLAGS
case 'a':
disp->show_addr = 1;
break;
case 'A':
disp->all = 1;
break;
case 'b':
type = FDT_NODE_HAS_PROP;
break;
case 'C':
inc = 0;
/* no break */
case 'c':
type = FDT_IS_COMPAT;
break;
case 'd':
disp->diff = 1;
break;
case 'e':
disp->flags |= FDT_REG_DIRECT_SUBNODES;
break;
case 'f':
disp->show_offset = 1;
break;
case 'G':
inc = 0;
/* no break */
case 'g':
type = FDT_ANY_GLOBAL;
break;
case 'H':
disp->header = 1;
break;
case 'l':
disp->region_list = 1;
break;
case 'L':
disp->list_strings = 1;
break;
case 'm':
disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
break;
case 'N':
inc = 0;
/* no break */
case 'n':
type = FDT_IS_NODE;
break;
case 'o':
disp->output_fname = optarg;
break;
case 'O':
if (!strcmp(optarg, "dtb"))
disp->output = OUT_DTB;
else if (!strcmp(optarg, "dts"))
disp->output = OUT_DTS;
else if (!strcmp(optarg, "bin"))
disp->output = OUT_BIN;
else
usage("Unknown output format");
break;
case 'P':
inc = 0;
/* no break */
case 'p':
type = FDT_IS_PROP;
break;
case 'r':
disp->remove_strings = 1;
break;
case 'R':
disp->include_root = 1;
break;
case 's':
disp->flags |= FDT_REG_ALL_SUBNODES;
break;
case 'S':
disp->flags &= ~FDT_REG_SUPERNODES;
break;
case 't':
disp->flags |= FDT_REG_ADD_STRING_TAB;
break;
case 'T':
disp->add_aliases = 1;
break;
case 'v':
disp->invert = 1;
break;
case 'I':
disp->show_dts_version = 1;
break;
}
if (type && value_add(disp, &disp->value_head, type, inc,
optarg))
usage("Cannot add value");
}
if (disp->invert && disp->types_exc)
usage("-v has no meaning when used with 'exclude' conditions");
}
int main(int argc, char *argv[])
{
char *filename = NULL;
struct display_info disp;
int ret;
/* set defaults */
memset(&disp, '\0', sizeof(disp));
disp.flags = FDT_REG_SUPERNODES; /* Default flags */
scan_args(&disp, argc, argv);
/* Show matched lines in colour if we can */
disp.colour = disp.all && isatty(0);
/* Any additional arguments can match anything, just like -g */
while (optind < argc - 1) {
if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
argv[optind++]))
usage("Cannot add value");
}
if (optind < argc)
filename = argv[optind++];
if (!filename)
usage("Missing filename");
/* If a valid .dtb is required, set flags to ensure we get one */
if (disp.output == OUT_DTB) {
disp.header = 1;
disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
}
if (disp.output_fname) {
disp.fout = fopen(disp.output_fname, "w");
if (!disp.fout)
usage("Cannot open output file");
} else {
disp.fout = stdout;
}
/* Run the grep and output the results */
ret = do_fdtgrep(&disp, filename);
if (disp.output_fname)
fclose(disp.fout);
if (ret)
return 1;
return 0;
}
/*
* (C) Copyright 2014
* DENX Software Engineering
* Heiko Schocher <hs@denx.de>
*
* Based on:
* (C) Copyright 2008 Semihalf
*
* (C) Copyright 2000-2004
* DENX Software Engineering
* Wolfgang Denk, wd@denx.de
*
* Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
* FIT image specific code abstracted from mkimage.c
* some functions added to address abstraction
*
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include "mkimage.h"
#include "fit_common.h"
#include <image.h>
#include <u-boot/crc.h>
void usage(char *cmdname)
{
fprintf(stderr, "Usage: %s -f fit file -k key file\n"
" -f ==> set fit file which should be checked'\n"
" -k ==> set key file which contains the key'\n",
cmdname);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
int ffd = -1;
int kfd = -1;
struct stat fsbuf;
struct stat ksbuf;
void *fit_blob;
char *fdtfile = NULL;
char *keyfile = NULL;
char cmdname[256];
int ret;
void *key_blob;
int c;
strncpy(cmdname, *argv, sizeof(cmdname) - 1);
cmdname[sizeof(cmdname) - 1] = '\0';
while ((c = getopt(argc, argv, "f:k:")) != -1)
switch (c) {
case 'f':
fdtfile = optarg;
break;
case 'k':
keyfile = optarg;
break;
default:
usage(cmdname);
break;
}
if (!fdtfile) {
fprintf(stderr, "%s: Missing fdt file\n", *argv);
usage(*argv);
}
if (!keyfile) {
fprintf(stderr, "%s: Missing key file\n", *argv);
usage(*argv);
}
ffd = mmap_fdt(cmdname, fdtfile, 0, &fit_blob, &fsbuf, false);
if (ffd < 0)
return EXIT_FAILURE;
kfd = mmap_fdt(cmdname, keyfile, 0, &key_blob, &ksbuf, false);
if (kfd < 0)
return EXIT_FAILURE;
image_set_host_blob(key_blob);
ret = fit_check_sign(fit_blob, key_blob);
if (!ret) {
ret = EXIT_SUCCESS;
fprintf(stderr, "Signature check OK\n");
} else {
ret = EXIT_FAILURE;
fprintf(stderr, "Signature check Bad (error %d)\n", ret);
}
(void) munmap((void *)fit_blob, fsbuf.st_size);
(void) munmap((void *)key_blob, ksbuf.st_size);
close(ffd);
close(kfd);
exit(ret);
}
/*
* (C) Copyright 2014
* DENX Software Engineering
* Heiko Schocher <hs@denx.de>
*
* (C) Copyright 2008 Semihalf
*
* (C) Copyright 2000-2004
* DENX Software Engineering
* Wolfgang Denk, wd@denx.de
*
* Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
* FIT image specific code abstracted from mkimage.c
* some functions added to address abstraction
*
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include "imagetool.h"
#include "mkimage.h"
#include "fit_common.h"
#include <image.h>
#include <u-boot/crc.h>
int fit_verify_header(unsigned char *ptr, int image_size,
struct image_tool_params *params)
{
return fdt_check_header(ptr);
}
int fit_check_image_types(uint8_t type)
{
if (type == IH_TYPE_FLATDT)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}
int mmap_fdt(const char *cmdname, const char *fname, size_t size_inc,
void **blobp, struct stat *sbuf, bool delete_on_error)
{
void *ptr;
int fd;
/* Load FIT blob into memory (we need to write hashes/signatures) */
fd = open(fname, O_RDWR | O_BINARY);
if (fd < 0) {
fprintf(stderr, "%s: Can't open %s: %s\n",
cmdname, fname, strerror(errno));
goto err;
}
if (fstat(fd, sbuf) < 0) {
fprintf(stderr, "%s: Can't stat %s: %s\n",
cmdname, fname, strerror(errno));
goto err;
}
if (size_inc) {
sbuf->st_size += size_inc;
if (ftruncate(fd, sbuf->st_size)) {
fprintf(stderr, "%s: Can't expand %s: %s\n",
cmdname, fname, strerror(errno));
goto err;
}
}
errno = 0;
ptr = mmap(0, sbuf->st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if ((ptr == MAP_FAILED) || (errno != 0)) {
fprintf(stderr, "%s: Can't read %s: %s\n",
cmdname, fname, strerror(errno));
goto err;
}
/* check if ptr has a valid blob */
if (fdt_check_header(ptr)) {
fprintf(stderr, "%s: Invalid FIT blob\n", cmdname);
goto err;
}
/* expand if needed */
if (size_inc) {
int ret;
ret = fdt_open_into(ptr, ptr, sbuf->st_size);
if (ret) {
fprintf(stderr, "%s: Cannot expand FDT: %s\n",
cmdname, fdt_strerror(ret));
goto err;
}
}
*blobp = ptr;
return fd;
err:
if (fd >= 0)
close(fd);
if (delete_on_error)
unlink(fname);
return -1;
}
/*
* (C) Copyright 2014
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _FIT_COMMON_H_
#define _FIT_COMMON_H_
#include "imagetool.h"
#include "mkimage.h"
#include <image.h>
int fit_verify_header(unsigned char *ptr, int image_size,
struct image_tool_params *params);
int fit_check_image_types(uint8_t type);
/**
* Map an FDT into memory, optionally increasing its size
*
* @cmdname: Tool name (for displaying with error messages)
* @fname: Filename containing FDT
* @size_inc: Amount to increase size by (0 = leave it alone)
* @blobp: Returns pointer to FDT blob
* @sbuf: File status information is stored here
* @delete_on_error: true to delete the file if we get an error
* @return 0 if OK, -1 on error.
*/
int mmap_fdt(const char *cmdname, const char *fname, size_t size_inc,
void **blobp, struct stat *sbuf, bool delete_on_error);
#endif /* _FIT_COMMON_H_ */
/*
* (C) Copyright 2008 Semihalf
*
* (C) Copyright 2000-2004
* DENX Software Engineering
* Wolfgang Denk, wd@denx.de
*
* Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
* FIT image specific code abstracted from mkimage.c
* some functions added to address abstraction
*
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include "imagetool.h"
#include "fit_common.h"
#include "mkimage.h"
#include <image.h>
#include <stdarg.h>
#include <version.h>
#include <u-boot/crc.h>
static image_header_t header;
static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
const char *tmpfile)
{
int tfd, destfd = 0;
void *dest_blob = NULL;
off_t destfd_size = 0;
struct stat sbuf;
void *ptr;
int ret = 0;
tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true);
if (tfd < 0)
return -EIO;
if (params->keydest) {
struct stat dest_sbuf;
destfd = mmap_fdt(params->cmdname, params->keydest, size_inc,
&dest_blob, &dest_sbuf, false);
if (destfd < 0) {
ret = -EIO;
goto err_keydest;
}
destfd_size = dest_sbuf.st_size;
}
/* for first image creation, add a timestamp at offset 0 i.e., root */
if (params->datafile) {
time_t time = imagetool_get_source_date(params, sbuf.st_mtime);
ret = fit_set_timestamp(ptr, 0, time);
}
if (!ret) {
ret = fit_add_verification_data(params->keydir, dest_blob, ptr,
params->comment,
params->require_keys,
params->engine_id);
}
if (dest_blob) {
munmap(dest_blob, destfd_size);
close(destfd);
}
err_keydest:
munmap(ptr, sbuf.st_size);
close(tfd);
return ret;
}
/**
* fit_calc_size() - Calculate the approximate size of the FIT we will generate
*/
static int fit_calc_size(struct image_tool_params *params)
{
struct content_info *cont;
int size, total_size;
size = imagetool_get_filesize(params, params->datafile);
if (size < 0)
return -1;
total_size = size;
if (params->fit_ramdisk) {
size = imagetool_get_filesize(params, params->fit_ramdisk);
if (size < 0)
return -1;
total_size += size;
}
for (cont = params->content_head; cont; cont = cont->next) {
size = imagetool_get_filesize(params, cont->fname);
if (size < 0)
return -1;
/* Add space for properties */
total_size += size + 300;
}
/* Add plenty of space for headers, properties, nodes, etc. */
total_size += 4096;
return total_size;
}
static int fdt_property_file(struct image_tool_params *params,
void *fdt, const char *name, const char *fname)
{
struct stat sbuf;
void *ptr;
int ret;
int fd;
fd = open(fname, O_RDWR | O_BINARY);
if (fd < 0) {
fprintf(stderr, "%s: Can't open %s: %s\n",
params->cmdname, fname, strerror(errno));
return -1;
}
if (fstat(fd, &sbuf) < 0) {
fprintf(stderr, "%s: Can't stat %s: %s\n",
params->cmdname, fname, strerror(errno));
goto err;
}
ret = fdt_property_placeholder(fdt, "data", sbuf.st_size, &ptr);
if (ret)
goto err;
ret = read(fd, ptr, sbuf.st_size);
if (ret != sbuf.st_size) {
fprintf(stderr, "%s: Can't read %s: %s\n",
params->cmdname, fname, strerror(errno));
goto err;
}
close(fd);
return 0;
err:
close(fd);
return -1;
}
static int fdt_property_strf(void *fdt, const char *name, const char *fmt, ...)
{
char str[100];
va_list ptr;
va_start(ptr, fmt);
vsnprintf(str, sizeof(str), fmt, ptr);
va_end(ptr);
return fdt_property_string(fdt, name, str);
}
static void get_basename(char *str, int size, const char *fname)
{
const char *p, *start, *end;
int len;
/*
* Use the base name as the 'name' field. So for example:
*
* "arch/arm/dts/sun7i-a20-bananapro.dtb"
* becomes "sun7i-a20-bananapro"
*/
p = strrchr(fname, '/');
start = p ? p + 1 : fname;
p = strrchr(fname, '.');
end = p ? p : fname + strlen(fname);
len = end - start;
if (len >= size)
len = size - 1;
memcpy(str, start, len);
str[len] = '\0';
}
/**
* fit_write_images() - Write out a list of images to the FIT
*
* We always include the main image (params->datafile). If there are device
* tree files, we include an fdt- node for each of those too.
*/
static int fit_write_images(struct image_tool_params *params, char *fdt)
{
struct content_info *cont;
const char *typename;
char str[100];
int upto;
int ret;
fdt_begin_node(fdt, "images");
/* First the main image */
typename = genimg_get_type_short_name(params->fit_image_type);
snprintf(str, sizeof(str), "%s-1", typename);
fdt_begin_node(fdt, str);
fdt_property_string(fdt, "description", params->imagename);
fdt_property_string(fdt, "type", typename);
fdt_property_string(fdt, "arch",
genimg_get_arch_short_name(params->arch));
fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os));
fdt_property_string(fdt, "compression",
genimg_get_comp_short_name(params->comp));
fdt_property_u32(fdt, "load", params->addr);
fdt_property_u32(fdt, "entry", params->ep);
/*
* Put data last since it is large. SPL may only load the first part
* of the DT, so this way it can access all the above fields.
*/
ret = fdt_property_file(params, fdt, "data", params->datafile);
if (ret)
return ret;
fdt_end_node(fdt);
/* Now the device tree files if available */
upto = 0;
for (cont = params->content_head; cont; cont = cont->next) {
if (cont->type != IH_TYPE_FLATDT)
continue;
snprintf(str, sizeof(str), "%s-%d", FIT_FDT_PROP, ++upto);
fdt_begin_node(fdt, str);
get_basename(str, sizeof(str), cont->fname);
fdt_property_string(fdt, "description", str);
ret = fdt_property_file(params, fdt, "data", cont->fname);
if (ret)
return ret;
fdt_property_string(fdt, "type", typename);
fdt_property_string(fdt, "arch",
genimg_get_arch_short_name(params->arch));
fdt_property_string(fdt, "compression",
genimg_get_comp_short_name(IH_COMP_NONE));
fdt_end_node(fdt);
}
/* And a ramdisk file if available */
if (params->fit_ramdisk) {
fdt_begin_node(fdt, FIT_RAMDISK_PROP "-1");
fdt_property_string(fdt, "type", FIT_RAMDISK_PROP);
fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os));
ret = fdt_property_file(params, fdt, "data", params->fit_ramdisk);
if (ret)
return ret;
fdt_end_node(fdt);
}
fdt_end_node(fdt);
return 0;
}
/**
* fit_write_configs() - Write out a list of configurations to the FIT
*
* If there are device tree files, we include a configuration for each, which
* selects the main image (params->datafile) and its corresponding device
* tree file.
*
* Otherwise we just create a configuration with the main image in it.
*/
static void fit_write_configs(struct image_tool_params *params, char *fdt)
{
struct content_info *cont;
const char *typename;
char str[100];
int upto;
fdt_begin_node(fdt, "configurations");
fdt_property_string(fdt, "default", "conf-1");
upto = 0;
for (cont = params->content_head; cont; cont = cont->next) {
if (cont->type != IH_TYPE_FLATDT)
continue;
typename = genimg_get_type_short_name(cont->type);
snprintf(str, sizeof(str), "conf-%d", ++upto);
fdt_begin_node(fdt, str);
get_basename(str, sizeof(str), cont->fname);
fdt_property_string(fdt, "description", str);
typename = genimg_get_type_short_name(params->fit_image_type);
snprintf(str, sizeof(str), "%s-1", typename);
fdt_property_string(fdt, typename, str);
if (params->fit_ramdisk)
fdt_property_string(fdt, FIT_RAMDISK_PROP,
FIT_RAMDISK_PROP "-1");
snprintf(str, sizeof(str), FIT_FDT_PROP "-%d", upto);
fdt_property_string(fdt, FIT_FDT_PROP, str);
fdt_end_node(fdt);
}
if (!upto) {
fdt_begin_node(fdt, "conf-1");
typename = genimg_get_type_short_name(params->fit_image_type);
snprintf(str, sizeof(str), "%s-1", typename);
fdt_property_string(fdt, typename, str);
if (params->fit_ramdisk)
fdt_property_string(fdt, FIT_RAMDISK_PROP,
FIT_RAMDISK_PROP "-1");
fdt_end_node(fdt);
}
fdt_end_node(fdt);
}
static int fit_build_fdt(struct image_tool_params *params, char *fdt, int size)
{
int ret;
ret = fdt_create(fdt, size);
if (ret)
return ret;
fdt_finish_reservemap(fdt);
fdt_begin_node(fdt, "");
fdt_property_strf(fdt, "description",
"%s image with one or more FDT blobs",
genimg_get_type_name(params->fit_image_type));
fdt_property_strf(fdt, "creator", "U-Boot mkimage %s", PLAIN_VERSION);
fdt_property_u32(fdt, "#address-cells", 1);
ret = fit_write_images(params, fdt);
if (ret)
return ret;
fit_write_configs(params, fdt);
fdt_end_node(fdt);
ret = fdt_finish(fdt);
if (ret)
return ret;
return fdt_totalsize(fdt);
}
static int fit_build(struct image_tool_params *params, const char *fname)
{
char *buf;
int size;
int ret;
int fd;
size = fit_calc_size(params);
if (size < 0)
return -1;
buf = malloc(size);
if (!buf) {
fprintf(stderr, "%s: Out of memory (%d bytes)\n",
params->cmdname, size);
return -1;
}
ret = fit_build_fdt(params, buf, size);
if (ret < 0) {
fprintf(stderr, "%s: Failed to build FIT image\n",
params->cmdname);
goto err_buf;
}
size = ret;
fd = open(fname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (fd < 0) {
fprintf(stderr, "%s: Can't open %s: %s\n",
params->cmdname, fname, strerror(errno));
goto err_buf;
}
ret = write(fd, buf, size);
if (ret != size) {
fprintf(stderr, "%s: Can't write %s: %s\n",
params->cmdname, fname, strerror(errno));
goto err;
}
close(fd);
free(buf);
return 0;
err:
close(fd);
err_buf:
free(buf);
return -1;
}
/**
* fit_extract_data() - Move all data outside the FIT
*
* This takes a normal FIT file and removes all the 'data' properties from it.
* The data is placed in an area after the FIT so that it can be accessed
* using an offset into that area. The 'data' properties turn into
* 'data-offset' properties.
*
* This function cannot cope with FITs with 'data-offset' properties. All
* data must be in 'data' properties on entry.
*/
static int fit_extract_data(struct image_tool_params *params, const char *fname)
{
void *buf;
int buf_ptr;
int fit_size, new_size;
int fd;
struct stat sbuf;
void *fdt;
int ret;
int images;
int node;
fd = mmap_fdt(params->cmdname, fname, 0, &fdt, &sbuf, false);
if (fd < 0)
return -EIO;
fit_size = fdt_totalsize(fdt);
/* Allocate space to hold the image data we will extract */
buf = malloc(fit_size);
if (!buf) {
ret = -ENOMEM;
goto err_munmap;
}
buf_ptr = 0;
images = fdt_path_offset(fdt, FIT_IMAGES_PATH);
if (images < 0) {
debug("%s: Cannot find /images node: %d\n", __func__, images);
ret = -EINVAL;
goto err_munmap;
}
for (node = fdt_first_subnode(fdt, images);
node >= 0;
node = fdt_next_subnode(fdt, node)) {
const char *data;
int len;
data = fdt_getprop(fdt, node, "data", &len);
if (!data)
continue;
memcpy(buf + buf_ptr, data, len);
debug("Extracting data size %x\n", len);
ret = fdt_delprop(fdt, node, "data");
if (ret) {
ret = -EPERM;
goto err_munmap;
}
if (params->external_offset > 0) {
/* An external offset positions the data absolutely. */
fdt_setprop_u32(fdt, node, "data-position",
params->external_offset + buf_ptr);
} else {
fdt_setprop_u32(fdt, node, "data-offset", buf_ptr);
}
fdt_setprop_u32(fdt, node, "data-size", len);
buf_ptr += (len + 3) & ~3;
}
/* Pack the FDT and place the data after it */
fdt_pack(fdt);
debug("Size reduced from %x to %x\n", fit_size, fdt_totalsize(fdt));
debug("External data size %x\n", buf_ptr);
new_size = fdt_totalsize(fdt);
new_size = (new_size + 3) & ~3;
munmap(fdt, sbuf.st_size);
if (ftruncate(fd, new_size)) {
debug("%s: Failed to truncate file: %s\n", __func__,
strerror(errno));
ret = -EIO;
goto err;
}
/* Check if an offset for the external data was set. */
if (params->external_offset > 0) {
if (params->external_offset < new_size) {
debug("External offset %x overlaps FIT length %x",
params->external_offset, new_size);
ret = -EINVAL;
goto err;
}
new_size = params->external_offset;
}
if (lseek(fd, new_size, SEEK_SET) < 0) {
debug("%s: Failed to seek to end of file: %s\n", __func__,
strerror(errno));
ret = -EIO;
goto err;
}
if (write(fd, buf, buf_ptr) != buf_ptr) {
debug("%s: Failed to write external data to file %s\n",
__func__, strerror(errno));
ret = -EIO;
goto err;
}
free(buf);
close(fd);
return 0;
err_munmap:
munmap(fdt, sbuf.st_size);
err:
if (buf)
free(buf);
close(fd);
return ret;
}
static int fit_import_data(struct image_tool_params *params, const char *fname)
{
void *fdt, *old_fdt;
int fit_size, new_size, size, data_base;
int fd;
struct stat sbuf;
int ret;
int images;
int node;
fd = mmap_fdt(params->cmdname, fname, 0, &old_fdt, &sbuf, false);
if (fd < 0)
return -EIO;
fit_size = fdt_totalsize(old_fdt);
data_base = (fit_size + 3) & ~3;
/* Allocate space to hold the new FIT */
size = sbuf.st_size + 16384;
fdt = malloc(size);
if (!fdt) {
fprintf(stderr, "%s: Failed to allocate memory (%d bytes)\n",
__func__, size);
ret = -ENOMEM;
goto err_has_fd;
}
ret = fdt_open_into(old_fdt, fdt, size);
if (ret) {
debug("%s: Failed to expand FIT: %s\n", __func__,
fdt_strerror(errno));
ret = -EINVAL;
goto err_has_fd;
}
images = fdt_path_offset(fdt, FIT_IMAGES_PATH);
if (images < 0) {
debug("%s: Cannot find /images node: %d\n", __func__, images);
ret = -EINVAL;
goto err_has_fd;
}
for (node = fdt_first_subnode(fdt, images);
node >= 0;
node = fdt_next_subnode(fdt, node)) {
int buf_ptr;
int len;
buf_ptr = fdtdec_get_int(fdt, node, "data-offset", -1);
len = fdtdec_get_int(fdt, node, "data-size", -1);
if (buf_ptr == -1 || len == -1)
continue;
debug("Importing data size %x\n", len);
ret = fdt_setprop(fdt, node, "data", fdt + data_base + buf_ptr,
len);
if (ret) {
debug("%s: Failed to write property: %s\n", __func__,
fdt_strerror(ret));
ret = -EINVAL;
goto err_has_fd;
}
}
/* Close the old fd so we can re-use it. */
close(fd);
/* Pack the FDT and place the data after it */
fdt_pack(fdt);
new_size = fdt_totalsize(fdt);
debug("Size expanded from %x to %x\n", fit_size, new_size);
fd = open(fname, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (fd < 0) {
fprintf(stderr, "%s: Can't open %s: %s\n",
params->cmdname, fname, strerror(errno));
ret = -EIO;
goto err_no_fd;
}
if (write(fd, fdt, new_size) != new_size) {
debug("%s: Failed to write external data to file %s\n",
__func__, strerror(errno));
ret = -EIO;
goto err_has_fd;
}
ret = 0;
err_has_fd:
close(fd);
err_no_fd:
munmap(old_fdt, sbuf.st_size);
free(fdt);
return ret;
}
/**
* fit_handle_file - main FIT file processing function
*
* fit_handle_file() runs dtc to convert .its to .itb, includes
* binary data, updates timestamp property and calculates hashes.
*
* datafile - .its file
* imagefile - .itb file
*
* returns:
* only on success, otherwise calls exit (EXIT_FAILURE);
*/
static int fit_handle_file(struct image_tool_params *params)
{
char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
size_t size_inc;
int ret;
/* Flattened Image Tree (FIT) format handling */
debug ("FIT format handling\n");
/* call dtc to include binary properties into the tmp file */
if (strlen (params->imagefile) +
strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) {
fprintf (stderr, "%s: Image file name (%s) too long, "
"can't create tmpfile",
params->imagefile, params->cmdname);
return (EXIT_FAILURE);
}
sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
/* We either compile the source file, or use the existing FIT image */
if (params->auto_its) {
if (fit_build(params, tmpfile)) {
fprintf(stderr, "%s: failed to build FIT\n",
params->cmdname);
return EXIT_FAILURE;
}
*cmd = '\0';
} else if (params->datafile) {
/* dtc -I dts -O dtb -p 500 datafile > tmpfile */
snprintf(cmd, sizeof(cmd), "%s %s \"%s\" > \"%s\"",
MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
debug("Trying to execute \"%s\"\n", cmd);
} else {
snprintf(cmd, sizeof(cmd), "cp \"%s\" \"%s\"",
params->imagefile, tmpfile);
}
if (*cmd && system(cmd) == -1) {
fprintf (stderr, "%s: system(%s) failed: %s\n",
params->cmdname, cmd, strerror(errno));
goto err_system;
}
/* Move the data so it is internal to the FIT, if needed */
ret = fit_import_data(params, tmpfile);
if (ret)
goto err_system;
/*
* Set hashes for images in the blob. Unfortunately we may need more
* space in either FDT, so keep trying until we succeed.
*
* Note: this is pretty inefficient for signing, since we must
* calculate the signature every time. It would be better to calculate
* all the data and then store it in a separate step. However, this
* would be considerably more complex to implement. Generally a few
* steps of this loop is enough to sign with several keys.
*/
for (size_inc = 0; size_inc < 64 * 1024; size_inc += 1024) {
ret = fit_add_file_data(params, size_inc, tmpfile);
if (!ret || ret != -ENOSPC)
break;
}
if (ret) {
fprintf(stderr, "%s Can't add hashes to FIT blob: %d\n",
params->cmdname, ret);
goto err_system;
}
/* Move the data so it is external to the FIT, if requested */
if (params->external_data) {
ret = fit_extract_data(params, tmpfile);
if (ret)
goto err_system;
}
if (rename (tmpfile, params->imagefile) == -1) {
fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
params->cmdname, tmpfile, params->imagefile,
strerror (errno));
unlink (tmpfile);
unlink (params->imagefile);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
err_system:
unlink(tmpfile);
return -1;
}
/**
* fit_image_extract - extract a FIT component image
* @fit: pointer to the FIT format image header
* @image_noffset: offset of the component image node
* @file_name: name of the file to store the FIT sub-image
*
* returns:
* zero in case of success or a negative value if fail.
*/
static int fit_image_extract(
const void *fit,
int image_noffset,
const char *file_name)
{
const void *file_data;
size_t file_size = 0;
/* get the "data" property of component at offset "image_noffset" */
fit_image_get_data(fit, image_noffset, &file_data, &file_size);
/* save the "file_data" into the file specified by "file_name" */
return imagetool_save_subimage(file_name, (ulong) file_data, file_size);
}
/**
* fit_extract_contents - retrieve a sub-image component from the FIT image
* @ptr: pointer to the FIT format image header
* @params: command line parameters
*
* returns:
* zero in case of success or a negative value if fail.
*/
static int fit_extract_contents(void *ptr, struct image_tool_params *params)
{
int images_noffset;
int noffset;
int ndepth;
const void *fit = ptr;
int count = 0;
const char *p;
/* Indent string is defined in header image.h */
p = IMAGE_INDENT_STRING;
if (!fit_check_format(fit)) {
printf("Bad FIT image format\n");
return -1;
}
/* 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 -1;
}
/* Avoid any overrun */
count = fit_get_subimage_count(fit, images_noffset);
if ((params->pflag < 0) || (count <= params->pflag)) {
printf("No such component at '%d'\n", params->pflag);
return -1;
}
/* Process its subnodes, extract the desired component from image */
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.
*/
if (params->pflag == count) {
printf("Extracted:\n%s Image %u (%s)\n", p,
count, fit_get_name(fit, noffset, NULL));
fit_image_print(fit, noffset, p);
return fit_image_extract(fit, noffset,
params->outfile);
}
count++;
}
}
return 0;
}
static int fit_check_params(struct image_tool_params *params)
{
if (params->auto_its)
return 0;
return ((params->dflag && (params->fflag || params->lflag)) ||
(params->fflag && (params->dflag || params->lflag)) ||
(params->lflag && (params->dflag || params->fflag)));
}
U_BOOT_IMAGE_TYPE(
fitimage,
"FIT Image support",
sizeof(image_header_t),
(void *)&header,
fit_check_params,
fit_verify_header,
fit_print_contents,
NULL,
fit_extract_contents,
fit_check_image_types,
fit_handle_file,
NULL /* FIT images use DTB header */
);
/*
* (C) Copyright 2014
* DENX Software Engineering
* Heiko Schocher <hs@denx.de>
*
* fit_info: print the offset and the len of a property from
* node in a fit file.
*
* Based on:
* (C) Copyright 2008 Semihalf
*
* (C) Copyright 2000-2004
* DENX Software Engineering
* Wolfgang Denk, wd@denx.de
*
* Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
* FIT image specific code abstracted from mkimage.c
* some functions added to address abstraction
*
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include "mkimage.h"
#include "fit_common.h"
#include <image.h>
#include <u-boot/crc.h>
void usage(char *cmdname)
{
fprintf(stderr, "Usage: %s -f fit file -n node -p property\n"
" -f ==> set fit file which is used'\n"
" -n ==> set node name'\n"
" -p ==> set property name'\n",
cmdname);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
int ffd = -1;
struct stat fsbuf;
void *fit_blob;
int len;
int nodeoffset; /* node offset from libfdt */
const void *nodep; /* property node pointer */
char *fdtfile = NULL;
char *nodename = NULL;
char *propertyname = NULL;
char cmdname[256];
int c;
strncpy(cmdname, *argv, sizeof(cmdname) - 1);
cmdname[sizeof(cmdname) - 1] = '\0';
while ((c = getopt(argc, argv, "f:n:p:")) != -1)
switch (c) {
case 'f':
fdtfile = optarg;
break;
case 'n':
nodename = optarg;
break;
case 'p':
propertyname = optarg;
break;
default:
usage(cmdname);
break;
}
if (!fdtfile) {
fprintf(stderr, "%s: Missing fdt file\n", *argv);
usage(*argv);
}
if (!nodename) {
fprintf(stderr, "%s: Missing node name\n", *argv);
usage(*argv);
}
if (!propertyname) {
fprintf(stderr, "%s: Missing property name\n", *argv);
usage(*argv);
}
ffd = mmap_fdt(cmdname, fdtfile, 0, &fit_blob, &fsbuf, false);
if (ffd < 0) {
printf("Could not open %s\n", fdtfile);
exit(EXIT_FAILURE);
}
nodeoffset = fdt_path_offset(fit_blob, nodename);
if (nodeoffset < 0) {
printf("%s not found.", nodename);
exit(EXIT_FAILURE);
}
nodep = fdt_getprop(fit_blob, nodeoffset, propertyname, &len);
if (len == 0) {
printf("len == 0 %s\n", propertyname);
exit(EXIT_FAILURE);
}
printf("NAME: %s\n", fit_get_name(fit_blob, nodeoffset, NULL));
printf("LEN: %d\n", len);
printf("OFF: %d\n", (int)(nodep - fit_blob));
(void) munmap((void *)fit_blob, fsbuf.st_size);
close(ffd);
exit(EXIT_SUCCESS);
}
/*
* (C) Copyright 2013
*
* Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _IMAGETOOL_H_
#define _IMAGETOOL_H_
#include "os_support.h"
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <u-boot/sha1.h>
#include "fdt_host.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define IH_ARCH_DEFAULT IH_ARCH_INVALID
/* Information about a file that needs to be placed into the FIT */
struct content_info {
struct content_info *next;
int type; /* File type (IH_TYPE_...) */
const char *fname;
};
/*
* This structure defines all such variables those are initialized by
* mkimage and dumpimage main core and need to be referred by image
* type specific functions
*/
struct image_tool_params {
int dflag;
int eflag;
int fflag;
int iflag;
int lflag;
int pflag;
int vflag;
int xflag;
int skipcpy;
int os;
int arch;
int type;
int comp;
char *dtc;
unsigned int addr;
unsigned int ep;
char *imagename;
char *imagename2;
char *datafile;
char *imagefile;
char *cmdname;
const char *outfile; /* Output filename */
const char *keydir; /* Directory holding private keys */
const char *keydest; /* Destination .dtb for public key */
const char *comment; /* Comment to add to signature node */
int require_keys; /* 1 to mark signing keys as 'required' */
int file_size; /* Total size of output file */
int orig_file_size; /* Original size for file before padding */
bool auto_its; /* Automatically create the .its file */
int fit_image_type; /* Image type to put into the FIT */
char *fit_ramdisk; /* Ramdisk file to include */
struct content_info *content_head; /* List of files to include */
struct content_info *content_tail;
bool external_data; /* Store data outside the FIT */
bool quiet; /* Don't output text in normal operation */
unsigned int external_offset; /* Add padding to external data */
const char *engine_id; /* Engine to use for signing */
};
/*
* image type specific variables and callback functions
*/
struct image_type_params {
/* name is an identification tag string for added support */
char *name;
/*
* header size is local to the specific image type to be supported,
* mkimage core treats this as number of bytes
*/
uint32_t header_size;
/* Image type header pointer */
void *hdr;
/*
* There are several arguments that are passed on the command line
* and are registered as flags in image_tool_params structure.
* This callback function can be used to check the passed arguments
* are in-lined with the image type to be supported
*
* Returns 1 if parameter check is successful
*/
int (*check_params) (struct image_tool_params *);
/*
* This function is used by list command (i.e. mkimage -l <filename>)
* image type verification code must be put here
*
* Returns 0 if image header verification is successful
* otherwise, returns respective negative error codes
*/
int (*verify_header) (unsigned char *, int, struct image_tool_params *);
/* Prints image information abstracting from image header */
void (*print_header) (const void *);
/*
* The header or image contents need to be set as per image type to
* be generated using this callback function.
* further output file post processing (for ex. checksum calculation,
* padding bytes etc..) can also be done in this callback function.
*/
void (*set_header) (void *, struct stat *, int,
struct image_tool_params *);
/*
* This function is used by the command to retrieve a component
* (sub-image) from the image (i.e. dumpimage -i <image> -p <position>
* <sub-image-name>).
* Thus the code to extract a file from an image must be put here.
*
* Returns 0 if the file was successfully retrieved from the image,
* or a negative value on error.
*/
int (*extract_subimage)(void *, struct image_tool_params *);
/*
* Some image generation support for ex (default image type) supports
* more than one type_ids, this callback function is used to check
* whether input (-T <image_type>) is supported by registered image
* generation/list low level code
*/
int (*check_image_type) (uint8_t);
/* This callback function will be executed if fflag is defined */
int (*fflag_handle) (struct image_tool_params *);
/*
* This callback function will be executed for variable size record
* It is expected to build this header in memory and return its length
* and a pointer to it by using image_type_params.header_size and
* image_type_params.hdr. The return value shall indicate if an
* additional padding should be used when copying the data image
* by returning the padding length.
*/
int (*vrec_header) (struct image_tool_params *,
struct image_type_params *);
};
/**
* imagetool_get_type() - find the image type params for a given image type
*
* It scans all registers image type supports
* checks the input type for each supported image type
*
* if successful,
* returns respective image_type_params pointer if success
* if input type_id is not supported by any of image_type_support
* returns NULL
*/
struct image_type_params *imagetool_get_type(int type);
/*
* imagetool_verify_print_header() - verifies the image header
*
* Scan registered image types and verify the image_header for each
* supported image type. If verification is successful, this prints
* the respective header.
*
* @return 0 on success, negative if input image format does not match with
* any of supported image types
*/
int imagetool_verify_print_header(
void *ptr,
struct stat *sbuf,
struct image_type_params *tparams,
struct image_tool_params *params);
/**
* imagetool_save_subimage - store data into a file
* @file_name: name of the destination file
* @file_data: data to be written
* @file_len: the amount of data to store
*
* imagetool_save_subimage() store file_len bytes of data pointed by file_data
* into the file name by file_name.
*
* returns:
* zero in case of success or a negative value if fail.
*/
int imagetool_save_subimage(
const char *file_name,
ulong file_data,
ulong file_len);
/**
* imagetool_get_filesize() - Utility function to obtain the size of a file
*
* This function prints a message if an error occurs, showing the error that
* was obtained.
*
* @params: mkimage parameters
* @fname: filename to check
* @return size of file, or -ve value on error
*/
int imagetool_get_filesize(struct image_tool_params *params, const char *fname);
/**
* imagetool_get_source_date() - Get timestamp for build output.
*
* Gets a timestamp for embedding it in a build output. If set
* SOURCE_DATE_EPOCH is used. Else the given fallback value is returned. Prints
* an error message if SOURCE_DATE_EPOCH contains an invalid value and returns
* 0.
*
* @params: mkimage parameters
* @fallback: timestamp to use if SOURCE_DATE_EPOCH isn't set
* @return timestamp based on SOURCE_DATE_EPOCH
*/
time_t imagetool_get_source_date(
struct image_tool_params *params,
time_t fallback);
/*
* There is a c file associated with supported image type low level code
* for ex. default_image.c, fit_image.c
*/
void pbl_load_uboot(int fd, struct image_tool_params *mparams);
#define ___cat(a, b) a ## b
#define __cat(a, b) ___cat(a, b)
/* we need some special handling for this host tool running eventually on
* Darwin. The Mach-O section handling is a bit different than ELF section
* handling. The differnces in detail are:
* a) we have segments which have sections
* b) we need a API call to get the respective section symbols */
#if defined(__MACH__)
#include <mach-o/getsect.h>
#define INIT_SECTION(name) do { \
unsigned long name ## _len; \
char *__cat(pstart_, name) = getsectdata("__TEXT", \
#name, &__cat(name, _len)); \
char *__cat(pstop_, name) = __cat(pstart_, name) + \
__cat(name, _len); \
__cat(__start_, name) = (void *)__cat(pstart_, name); \
__cat(__stop_, name) = (void *)__cat(pstop_, name); \
} while (0)
#define SECTION(name) __attribute__((section("__TEXT, " #name)))
struct image_type_params **__start_image_type, **__stop_image_type;
#else
#define INIT_SECTION(name) /* no-op for ELF */
#define SECTION(name) __attribute__((section(#name)))
/* We construct a table of pointers in an ELF section (pointers generally
* go unpadded by gcc). ld creates boundary syms for us. */
extern struct image_type_params *__start_image_type[], *__stop_image_type[];
#endif /* __MACH__ */
#if !defined(__used)
# if __GNUC__ == 3 && __GNUC_MINOR__ < 3
# define __used __attribute__((__unused__))
# else
# define __used __attribute__((__used__))
# endif
#endif
#define U_BOOT_IMAGE_TYPE( \
_id, \
_name, \
_header_size, \
_header, \
_check_params, \
_verify_header, \
_print_header, \
_set_header, \
_extract_subimage, \
_check_image_type, \
_fflag_handle, \
_vrec_header \
) \
static struct image_type_params __cat(image_type_, _id) = \
{ \
.name = _name, \
.header_size = _header_size, \
.hdr = _header, \
.check_params = _check_params, \
.verify_header = _verify_header, \
.print_header = _print_header, \
.set_header = _set_header, \
.extract_subimage = _extract_subimage, \
.check_image_type = _check_image_type, \
.fflag_handle = _fflag_handle, \
.vrec_header = _vrec_header \
}; \
static struct image_type_params *SECTION(image_type) __used \
__cat(image_type_ptr_, _id) = &__cat(image_type_, _id)
#endif /* _IMAGETOOL_H_ */
/*
* (C) Copyright 2000-2004
* DENX Software Engineering
* Wolfgang Denk, wd@denx.de
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _MKIIMAGE_H_
#define _MKIIMAGE_H_
#include "os_support.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <u-boot/sha1.h>
#include "fdt_host.h"
#include "imagetool.h"
#undef MKIMAGE_DEBUG
#ifdef MKIMAGE_DEBUG
#define debug(fmt,args...) printf (fmt ,##args)
#else
#define debug(fmt,args...)
#endif /* MKIMAGE_DEBUG */
static inline void *map_sysmem(ulong paddr, unsigned long len)
{
return (void *)(uintptr_t)paddr;
}
static inline ulong map_to_sysmem(void *ptr)
{
return (ulong)(uintptr_t)ptr;
}
#define MKIMAGE_TMPFILE_SUFFIX ".tmp"
#define MKIMAGE_MAX_TMPFILE_LEN 256
#define MKIMAGE_DEFAULT_DTC_OPTIONS "-I dts -O dtb -p 500"
#define MKIMAGE_MAX_DTC_CMDLINE_LEN 512
#endif /* _MKIIMAGE_H_ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment