cbfstool: Add support for hashes as file metadata
They allow optimizing a verification of a whole CBFS image by only dealing with the headers (assuming you choose to trust the hash algorithm(s)). The format allows for multiple hashes for a single file, and cbfstool can handle them, but right now it can't generate such headers. Loosely based on Sol's work in http://review.coreboot.org/#/c/10147/, but using the compatible file attribute format. vboot is now a hard dependency of the build process, but we import it into the tree for quite a while now. Change-Id: I9f14f30537d676ce209ad612e7327c6f4810b313 Signed-off-by: Patrick Georgi <patrick@georgi-clan.de> Reviewed-on: http://review.coreboot.org/11767 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
committed by
Patrick Georgi
parent
44853371f1
commit
89f20340d5
@@ -15,6 +15,11 @@ cbfsobj += lzma.o
|
|||||||
cbfsobj += LzFind.o
|
cbfsobj += LzFind.o
|
||||||
cbfsobj += LzmaDec.o
|
cbfsobj += LzmaDec.o
|
||||||
cbfsobj += LzmaEnc.o
|
cbfsobj += LzmaEnc.o
|
||||||
|
# CRYPTOLIB
|
||||||
|
cbfsobj += 2sha_utility.o
|
||||||
|
cbfsobj += 2sha1.o
|
||||||
|
cbfsobj += 2sha256.o
|
||||||
|
cbfsobj += 2sha512.o
|
||||||
# FMAP
|
# FMAP
|
||||||
cbfsobj += fmap.o
|
cbfsobj += fmap.o
|
||||||
cbfsobj += kv_pair.o
|
cbfsobj += kv_pair.o
|
||||||
@@ -51,6 +56,9 @@ TOOLCPPFLAGS += -I$(top)/util/cbfstool/flashmap
|
|||||||
TOOLCPPFLAGS += -I$(top)/util/cbfstool
|
TOOLCPPFLAGS += -I$(top)/util/cbfstool
|
||||||
TOOLCPPFLAGS += -I$(objutil)/cbfstool
|
TOOLCPPFLAGS += -I$(objutil)/cbfstool
|
||||||
TOOLCPPFLAGS += -I$(top)/src/commonlib/include
|
TOOLCPPFLAGS += -I$(top)/src/commonlib/include
|
||||||
|
TOOLCPPFLAGS += -DNEED_VB2_SHA_LIBRARY
|
||||||
|
TOOLCPPFLAGS += -I$(top)/3rdparty/vboot/firmware/include
|
||||||
|
TOOLCPPFLAGS += -I$(top)/3rdparty/vboot/firmware/2lib/include
|
||||||
TOOLLDFLAGS ?=
|
TOOLLDFLAGS ?=
|
||||||
|
|
||||||
ifeq ($(shell uname -s | cut -c-7 2>/dev/null), MINGW32)
|
ifeq ($(shell uname -s | cut -c-7 2>/dev/null), MINGW32)
|
||||||
@@ -77,6 +85,10 @@ $(objutil)/cbfstool/%.o: $(top)/util/cbfstool/lzma/C/%.c
|
|||||||
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
|
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
|
||||||
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
|
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(objutil)/cbfstool/%.o: $(top)/3rdparty/vboot/firmware/2lib/%.c
|
||||||
|
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
|
||||||
|
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(objutil)/cbfstool/cbfstool: $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
|
$(objutil)/cbfstool/cbfstool: $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
|
||||||
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
|
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
|
||||||
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
|
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
|
||||||
@@ -97,6 +109,9 @@ $(objutil)/cbfstool/fmd_scanner.o: TOOLCFLAGS += -Wno-redundant-decls
|
|||||||
$(objutil)/cbfstool/fmd_scanner.o: TOOLCFLAGS += -Wno-unused-function
|
$(objutil)/cbfstool/fmd_scanner.o: TOOLCFLAGS += -Wno-unused-function
|
||||||
# Tolerate lzma sdk warnings
|
# Tolerate lzma sdk warnings
|
||||||
$(objutil)/cbfstool/LzmaEnc.o: TOOLCFLAGS += -Wno-sign-compare -Wno-cast-qual
|
$(objutil)/cbfstool/LzmaEnc.o: TOOLCFLAGS += -Wno-sign-compare -Wno-cast-qual
|
||||||
|
# Tolerate vboot warnings
|
||||||
|
$(objutil)/cbfstool/2sha_utility.o: TOOLCFLAGS += -Wno-sign-compare
|
||||||
|
$(objutil)/cbfstool/2sha1.o: TOOLCFLAGS += -Wno-cast-qual
|
||||||
|
|
||||||
$(objutil)/cbfstool/fmd.o: $(objutil)/cbfstool/fmd_parser.h
|
$(objutil)/cbfstool/fmd.o: $(objutil)/cbfstool/fmd_parser.h
|
||||||
$(objutil)/cbfstool/fmd.o: $(objutil)/cbfstool/fmd_scanner.h
|
$(objutil)/cbfstool/fmd.o: $(objutil)/cbfstool/fmd_scanner.h
|
||||||
|
@@ -19,8 +19,11 @@
|
|||||||
#ifndef __CBFS_H
|
#ifndef __CBFS_H
|
||||||
#define __CBFS_H
|
#define __CBFS_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <vb2_api.h>
|
||||||
|
|
||||||
/* cbfstool will fail when trying to build a cbfs_file header that's larger
|
/* cbfstool will fail when trying to build a cbfs_file header that's larger
|
||||||
* than MAX_CBFS_FILE_HEADER_BUFFER. 1K should give plenty of room. */
|
* than MAX_CBFS_FILE_HEADER_BUFFER. 1K should give plenty of room. */
|
||||||
#define MAX_CBFS_FILE_HEADER_BUFFER 1024
|
#define MAX_CBFS_FILE_HEADER_BUFFER 1024
|
||||||
@@ -107,6 +110,7 @@ struct cbfs_file_attribute {
|
|||||||
#define CBFS_FILE_ATTR_TAG_UNUSED 0
|
#define CBFS_FILE_ATTR_TAG_UNUSED 0
|
||||||
#define CBFS_FILE_ATTR_TAG_UNUSED2 0xffffffff
|
#define CBFS_FILE_ATTR_TAG_UNUSED2 0xffffffff
|
||||||
#define CBFS_FILE_ATTR_TAG_COMPRESSION 0x42435a4c
|
#define CBFS_FILE_ATTR_TAG_COMPRESSION 0x42435a4c
|
||||||
|
#define CBFS_FILE_ATTR_TAG_HASH 0x68736148
|
||||||
|
|
||||||
struct cbfs_file_attr_compression {
|
struct cbfs_file_attr_compression {
|
||||||
uint32_t tag;
|
uint32_t tag;
|
||||||
@@ -116,6 +120,14 @@ struct cbfs_file_attr_compression {
|
|||||||
uint32_t decompressed_size;
|
uint32_t decompressed_size;
|
||||||
} __PACKED;
|
} __PACKED;
|
||||||
|
|
||||||
|
struct cbfs_file_attr_hash {
|
||||||
|
uint32_t tag;
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t hash_type;
|
||||||
|
/* hash_data is len - sizeof(struct) bytes */
|
||||||
|
uint8_t hash_data[];
|
||||||
|
} __PACKED;
|
||||||
|
|
||||||
struct cbfs_stage {
|
struct cbfs_stage {
|
||||||
uint32_t compression;
|
uint32_t compression;
|
||||||
uint64_t entry;
|
uint64_t entry;
|
||||||
@@ -203,6 +215,23 @@ static struct typedesc_t filetypes[] unused = {
|
|||||||
{CBFS_COMPONENT_NULL, "null"}
|
{CBFS_COMPONENT_NULL, "null"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct typedesc_t types_cbfs_hash[] unused = {
|
||||||
|
{VB2_HASH_INVALID, "none"},
|
||||||
|
{VB2_HASH_SHA1, "sha1"},
|
||||||
|
{VB2_HASH_SHA256, "sha256"},
|
||||||
|
{VB2_HASH_SHA512, "sha512"},
|
||||||
|
{0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t widths_cbfs_hash[] unused = {
|
||||||
|
[VB2_HASH_INVALID] = 0,
|
||||||
|
[VB2_HASH_SHA1] = 20,
|
||||||
|
[VB2_HASH_SHA256] = 32,
|
||||||
|
[VB2_HASH_SHA512] = 64,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CBFS_NUM_SUPPORTED_HASHES ARRAY_SIZE(widths_cbfs_hash)
|
||||||
|
|
||||||
#define CBFS_SUBHEADER(_p) ( (void *) ((((uint8_t *) (_p)) + ntohl((_p)->offset))) )
|
#define CBFS_SUBHEADER(_p) ( (void *) ((((uint8_t *) (_p)) + ntohl((_p)->offset))) )
|
||||||
|
|
||||||
/* cbfs_image.c */
|
/* cbfs_image.c */
|
||||||
|
@@ -85,6 +85,16 @@ int cbfs_parse_comp_algo(const char *name)
|
|||||||
return lookup_type_by_name(types_cbfs_compression, name);
|
return lookup_type_by_name(types_cbfs_compression, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *get_hash_attr_name(uint16_t hash_type)
|
||||||
|
{
|
||||||
|
return lookup_name_by_type(types_cbfs_hash, hash_type, "(invalid)");
|
||||||
|
}
|
||||||
|
|
||||||
|
int cbfs_parse_hash_algo(const char *name)
|
||||||
|
{
|
||||||
|
return lookup_type_by_name(types_cbfs_hash, name);
|
||||||
|
}
|
||||||
|
|
||||||
/* CBFS image */
|
/* CBFS image */
|
||||||
|
|
||||||
size_t cbfs_calculate_file_header_size(const char *name)
|
size_t cbfs_calculate_file_header_size(const char *name)
|
||||||
@@ -173,6 +183,24 @@ static int cbfs_file_get_compression_info(struct cbfs_file *entry,
|
|||||||
return compression;
|
return compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct cbfs_file_attr_hash *cbfs_file_get_next_hash(
|
||||||
|
struct cbfs_file *entry, struct cbfs_file_attr_hash *cur)
|
||||||
|
{
|
||||||
|
struct cbfs_file_attribute *attr = (struct cbfs_file_attribute *)cur;
|
||||||
|
if (attr == NULL) {
|
||||||
|
attr = cbfs_file_first_attr(entry);
|
||||||
|
if (attr == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_HASH)
|
||||||
|
return (struct cbfs_file_attr_hash *)attr;
|
||||||
|
}
|
||||||
|
while ((attr = cbfs_file_next_attr(entry, attr)) != NULL) {
|
||||||
|
if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_HASH)
|
||||||
|
return (struct cbfs_file_attr_hash *)attr;
|
||||||
|
};
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void cbfs_get_header(struct cbfs_header *header, void *src)
|
void cbfs_get_header(struct cbfs_header *header, void *src)
|
||||||
{
|
{
|
||||||
struct buffer outheader;
|
struct buffer outheader;
|
||||||
@@ -813,6 +841,31 @@ int cbfs_print_entry_info(struct cbfs_image *image, struct cbfs_file *entry,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cbfs_file_attr_hash *hash = NULL;
|
||||||
|
while ((hash = cbfs_file_get_next_hash(entry, hash)) != NULL) {
|
||||||
|
unsigned int hash_type = ntohl(hash->hash_type);
|
||||||
|
if (hash_type > CBFS_NUM_SUPPORTED_HASHES) {
|
||||||
|
fprintf(fp, "invalid hash type %d\n", hash_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size_t hash_len = widths_cbfs_hash[hash_type];
|
||||||
|
char *hash_str = bintohex(hash->hash_data, hash_len);
|
||||||
|
uint8_t local_hash[hash_len];
|
||||||
|
if (vb2_digest_buffer(CBFS_SUBHEADER(entry),
|
||||||
|
ntohl(entry->len), hash_type, local_hash,
|
||||||
|
hash_len) != VB2_SUCCESS) {
|
||||||
|
fprintf(fp, "failed to hash '%s'\n", name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int valid = memcmp(local_hash, hash->hash_data, hash_len) == 0;
|
||||||
|
const char *valid_str = valid ? "valid" : "invalid";
|
||||||
|
|
||||||
|
fprintf(fp, " hash %s:%s %s\n",
|
||||||
|
get_hash_attr_name(hash_type),
|
||||||
|
hash_str, valid_str);
|
||||||
|
free(hash_str);
|
||||||
|
}
|
||||||
|
|
||||||
if (!verbose)
|
if (!verbose)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -1129,6 +1182,32 @@ struct cbfs_file_attribute *cbfs_add_file_attr(struct cbfs_file *header,
|
|||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cbfs_add_file_hash(struct cbfs_file *header, struct buffer *buffer,
|
||||||
|
enum vb2_hash_algorithm hash_type)
|
||||||
|
{
|
||||||
|
if (hash_type >= CBFS_NUM_SUPPORTED_HASHES)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
unsigned hash_size = widths_cbfs_hash[hash_type];
|
||||||
|
if (hash_size == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct cbfs_file_attr_hash *attrs =
|
||||||
|
(struct cbfs_file_attr_hash *)cbfs_add_file_attr(header,
|
||||||
|
CBFS_FILE_ATTR_TAG_HASH,
|
||||||
|
sizeof(struct cbfs_file_attr_hash) + hash_size);
|
||||||
|
|
||||||
|
if (attrs == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
attrs->hash_type = htonl(hash_type);
|
||||||
|
if (vb2_digest_buffer(buffer_get(buffer), buffer_size(buffer),
|
||||||
|
hash_type, attrs->hash_data, hash_size) != VB2_SUCCESS)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Finds a place to hold whole data in same memory page. */
|
/* Finds a place to hold whole data in same memory page. */
|
||||||
static int is_in_same_page(uint32_t start, uint32_t size, uint32_t page)
|
static int is_in_same_page(uint32_t start, uint32_t size, uint32_t page)
|
||||||
{
|
{
|
||||||
|
@@ -36,6 +36,10 @@ struct cbfs_image {
|
|||||||
* enum comp_algo if it's supported, or a number < 0 otherwise. */
|
* enum comp_algo if it's supported, or a number < 0 otherwise. */
|
||||||
int cbfs_parse_comp_algo(const char *name);
|
int cbfs_parse_comp_algo(const char *name);
|
||||||
|
|
||||||
|
/* Given the string name of a hash algorithm, return the corresponding
|
||||||
|
* id if it's supported, or a number < 0 otherwise. */
|
||||||
|
int cbfs_parse_hash_algo(const char *name);
|
||||||
|
|
||||||
/* Given a pointer, serialize the header from host-native byte format
|
/* Given a pointer, serialize the header from host-native byte format
|
||||||
* to cbfs format, i.e. big-endian. */
|
* to cbfs format, i.e. big-endian. */
|
||||||
void cbfs_put_header(void *dest, const struct cbfs_header *header);
|
void cbfs_put_header(void *dest, const struct cbfs_header *header);
|
||||||
@@ -184,4 +188,10 @@ struct cbfs_file_attribute *cbfs_file_next_attr(struct cbfs_file *file,
|
|||||||
struct cbfs_file_attribute *cbfs_add_file_attr(struct cbfs_file *header,
|
struct cbfs_file_attribute *cbfs_add_file_attr(struct cbfs_file *header,
|
||||||
uint32_t tag,
|
uint32_t tag,
|
||||||
uint32_t size);
|
uint32_t size);
|
||||||
|
|
||||||
|
/* Adds an extended attribute to header, containing a hash of buffer's data of
|
||||||
|
* the type specified by hash_type.
|
||||||
|
* Returns 0 on success, -1 on error. */
|
||||||
|
int cbfs_add_file_hash(struct cbfs_file *header, struct buffer *buffer,
|
||||||
|
enum vb2_hash_algorithm hash_type);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -76,6 +76,7 @@ static struct param {
|
|||||||
bool stage_xip;
|
bool stage_xip;
|
||||||
int fit_empty_entries;
|
int fit_empty_entries;
|
||||||
enum comp_algo compression;
|
enum comp_algo compression;
|
||||||
|
enum vb2_hash_algorithm hash;
|
||||||
/* for linux payloads */
|
/* for linux payloads */
|
||||||
char *initrd;
|
char *initrd;
|
||||||
char *cmdline;
|
char *cmdline;
|
||||||
@@ -83,6 +84,7 @@ static struct param {
|
|||||||
/* All variables not listed are initialized as zero. */
|
/* All variables not listed are initialized as zero. */
|
||||||
.arch = CBFS_ARCHITECTURE_UNKNOWN,
|
.arch = CBFS_ARCHITECTURE_UNKNOWN,
|
||||||
.compression = CBFS_COMPRESS_NONE,
|
.compression = CBFS_COMPRESS_NONE,
|
||||||
|
.hash = VB2_HASH_INVALID,
|
||||||
.headeroffset = ~0,
|
.headeroffset = ~0,
|
||||||
.region_name = SECTION_NAME_PRIMARY_CBFS,
|
.region_name = SECTION_NAME_PRIMARY_CBFS,
|
||||||
};
|
};
|
||||||
@@ -327,6 +329,14 @@ static int cbfs_add_component(const char *filename,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (param.hash != VB2_HASH_INVALID)
|
||||||
|
if (cbfs_add_file_hash(header, &buffer, param.hash) == -1) {
|
||||||
|
ERROR("couldn't add hash for '%s'\n", name);
|
||||||
|
free(header);
|
||||||
|
buffer_delete(&buffer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_TOP_ALIGNED_ADDRESS(offset))
|
if (IS_TOP_ALIGNED_ADDRESS(offset))
|
||||||
offset = convert_to_from_top_aligned(param.image_region,
|
offset = convert_to_from_top_aligned(param.image_region,
|
||||||
-offset);
|
-offset);
|
||||||
@@ -882,11 +892,11 @@ static int cbfs_copy(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct command commands[] = {
|
static const struct command commands[] = {
|
||||||
{"add", "H:r:f:n:t:c:b:a:vh?", cbfs_add, true, true},
|
{"add", "H:r:f:n:t:c:b:a:vA:h?", cbfs_add, true, true},
|
||||||
{"add-flat-binary", "H:r:f:n:l:e:c:b:vh?", cbfs_add_flat_binary, true,
|
{"add-flat-binary", "H:r:f:n:l:e:c:b:vA:h?", cbfs_add_flat_binary, true,
|
||||||
true},
|
true},
|
||||||
{"add-payload", "H:r:f:n:t:c:b:C:I:vh?", cbfs_add_payload, true, true},
|
{"add-payload", "H:r:f:n:t:c:b:C:I:vA:h?", cbfs_add_payload, true, true},
|
||||||
{"add-stage", "a:H:r:f:n:t:c:b:P:S:yvh?", cbfs_add_stage, true, true},
|
{"add-stage", "a:H:r:f:n:t:c:b:P:S:yvA:h?", cbfs_add_stage, true, true},
|
||||||
{"add-int", "H:r:i:n:b:vh?", cbfs_add_integer, true, true},
|
{"add-int", "H:r:i:n:b:vh?", cbfs_add_integer, true, true},
|
||||||
{"add-master-header", "H:r:vh?", cbfs_add_master_header, true, true},
|
{"add-master-header", "H:r:vh?", cbfs_add_master_header, true, true},
|
||||||
{"copy", "H:D:s:h?", cbfs_copy, true, true},
|
{"copy", "H:D:s:h?", cbfs_copy, true, true},
|
||||||
@@ -914,6 +924,7 @@ static struct option long_options[] = {
|
|||||||
{"fill-upward", no_argument, 0, 'u' },
|
{"fill-upward", no_argument, 0, 'u' },
|
||||||
{"flashmap", required_argument, 0, 'M' },
|
{"flashmap", required_argument, 0, 'M' },
|
||||||
{"fmap-regions", required_argument, 0, 'r' },
|
{"fmap-regions", required_argument, 0, 'r' },
|
||||||
|
{"hash-algorithm",required_argument, 0, 'A' },
|
||||||
{"header-offset", required_argument, 0, 'H' },
|
{"header-offset", required_argument, 0, 'H' },
|
||||||
{"help", no_argument, 0, 'h' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{"ignore-sec", required_argument, 0, 'S' },
|
{"ignore-sec", required_argument, 0, 'S' },
|
||||||
@@ -997,18 +1008,18 @@ static void usage(char *name)
|
|||||||
" -v Provide verbose output\n"
|
" -v Provide verbose output\n"
|
||||||
" -h Display this help message\n\n"
|
" -h Display this help message\n\n"
|
||||||
"COMMANDs:\n"
|
"COMMANDs:\n"
|
||||||
" add [-r image,regions] -f FILE -n NAME -t TYPE \\\n"
|
" add [-r image,regions] -f FILE -n NAME -t TYPE [-A hash] \\\n"
|
||||||
" [-c compression] [-b base-address | -a alignment] "
|
" [-c compression] [-b base-address | -a alignment] "
|
||||||
"Add a component\n"
|
"Add a component\n"
|
||||||
" add-payload [-r image,regions] -f FILE -n NAME \\\n"
|
" add-payload [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
|
||||||
" [-c compression] [-b base-address] "
|
" [-c compression] [-b base-address] "
|
||||||
"Add a payload to the ROM\n"
|
"Add a payload to the ROM\n"
|
||||||
" (linux specific: [-C cmdline] [-I initrd])\n"
|
" (linux specific: [-C cmdline] [-I initrd])\n"
|
||||||
" add-stage [-r image,regions] -f FILE -n NAME \\\n"
|
" add-stage [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
|
||||||
" [-c compression] [-b base] [-S section-to-ignore] "
|
" [-c compression] [-b base] [-S section-to-ignore] "
|
||||||
" [-a alignment] [-y|--xip] [-P page-size]"
|
" [-a alignment] [-y|--xip] [-P page-size]"
|
||||||
"Add a stage to the ROM\n"
|
"Add a stage to the ROM\n"
|
||||||
" add-flat-binary [-r image,regions] -f FILE -n NAME \\\n"
|
" add-flat-binary [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
|
||||||
" -l load-address -e entry-point [-c compression] \\\n"
|
" -l load-address -e entry-point [-c compression] \\\n"
|
||||||
" [-b base] "
|
" [-b base] "
|
||||||
"Add a 32bit flat mode binary\n"
|
"Add a 32bit flat mode binary\n"
|
||||||
@@ -1132,6 +1143,17 @@ int main(int argc, char **argv)
|
|||||||
optarg);
|
optarg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'A': {
|
||||||
|
int algo = cbfs_parse_hash_algo(optarg);
|
||||||
|
if (algo >= 0)
|
||||||
|
param.hash = algo;
|
||||||
|
else {
|
||||||
|
ERROR("Unknown hash algorithm '%s'.\n",
|
||||||
|
optarg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'M':
|
case 'M':
|
||||||
param.fmap = optarg;
|
param.fmap = optarg;
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user