summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/cbfstool/cbfs_image.c82
-rw-r--r--util/cbfstool/cbfs_image.h4
-rw-r--r--util/cbfstool/cbfstool.c36
3 files changed, 122 insertions, 0 deletions
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index 621a35d16f..9df2030679 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -294,6 +294,88 @@ int cbfs_image_from_file(struct cbfs_image *image,
return 0;
}
+int cbfs_copy_instance(struct cbfs_image *image, size_t copy_offset,
+ size_t copy_size)
+{
+ struct cbfs_file *src_entry, *dst_entry;
+ struct cbfs_header *copy_header;
+ size_t align, entry_offset;
+ ssize_t last_entry_size;
+
+ size_t header_offset, header_end;
+ size_t cbfs_offset, cbfs_end;
+ size_t copy_end = copy_offset + copy_size;
+
+ align = htonl(image->header->align);
+
+ header_offset = (char *)image->header - image->buffer.data;
+ header_end = header_offset + sizeof(image->header);
+
+ cbfs_offset = htonl(image->header->offset);
+ cbfs_end = htonl(image->header->romsize);
+
+ if (copy_end > image->buffer.size) {
+ ERROR("Copy offset out of range: [%zx:%zx)\n",
+ copy_offset, copy_end);
+ return 1;
+ }
+
+ /* Range check requested copy region with header and source cbfs. */
+ if ((copy_offset >= header_offset && copy_offset < header_end) ||
+ (copy_end >= header_offset && copy_end <= header_end)) {
+ ERROR("New image would overlap old header.\n");
+ }
+
+ if ((copy_offset >= cbfs_offset && copy_offset < cbfs_end) ||
+ (copy_end >= cbfs_offset && copy_end <= cbfs_end)) {
+ ERROR("New image would overlap old one.\n");
+ return 1;
+ }
+
+ /* This will work, let's create a copy. */
+ copy_header = (struct cbfs_header *)(image->buffer.data + copy_offset);
+ *copy_header = *image->header;
+
+ copy_header->bootblocksize = 0;
+ /* Romsize is a misnomer. It's the absolute limit of cbfs content.*/
+ copy_header->romsize = htonl(copy_end);
+ entry_offset = align_up(copy_offset + sizeof(*copy_header), align);
+ copy_header->offset = htonl(entry_offset);
+ dst_entry = (struct cbfs_file *)(image->buffer.data + entry_offset);
+
+ /* Copy non-empty files */
+ for (src_entry = cbfs_find_first_entry(image);
+ src_entry && cbfs_is_valid_entry(image, src_entry);
+ src_entry = cbfs_find_next_entry(image, src_entry)) {
+ size_t entry_size;
+
+ if ((src_entry->type == htonl(CBFS_COMPONENT_NULL)) ||
+ (src_entry->type == htonl(CBFS_COMPONENT_DELETED)))
+ continue;
+
+ entry_size = htonl(src_entry->len) + htonl(src_entry->offset);
+ memcpy(dst_entry, src_entry, entry_size);
+ dst_entry = (struct cbfs_file *)(
+ (uintptr_t)dst_entry + align_up(entry_size, align));
+
+ if (((char *)dst_entry - image->buffer.data) >= copy_end) {
+ ERROR("Ran out of room in copy region.\n");
+ return 1;
+ }
+ }
+
+ /* Last entry size is all the room above it. */
+ last_entry_size = copy_end - ((char *)dst_entry - image->buffer.data)
+ - cbfs_calculate_file_header_size("");
+
+ if (last_entry_size < 0)
+ WARN("No room to create the last entry!\n")
+ else
+ cbfs_create_empty_entry(image, dst_entry, last_entry_size, "");
+
+ return 0;
+}
+
int cbfs_image_write_file(struct cbfs_image *image, const char *filename)
{
assert(image && image->buffer.data);
diff --git a/util/cbfstool/cbfs_image.h b/util/cbfstool/cbfs_image.h
index 2c1be3da1c..1e5a99f16a 100644
--- a/util/cbfstool/cbfs_image.h
+++ b/util/cbfstool/cbfs_image.h
@@ -55,6 +55,10 @@ int cbfs_image_create(struct cbfs_image *image,
int cbfs_image_from_file(struct cbfs_image *image,
const char *filename, uint32_t offset);
+/* Create a duplicate CBFS image. Returns 0 on success, otherwise non-zero. */
+int cbfs_copy_instance(struct cbfs_image *image, size_t copy_offset,
+ size_t copy_size);
+
/* Writes a CBFS image into file. Returns 0 on success, otherwise non-zero. */
int cbfs_image_write_file(struct cbfs_image *image, const char *filename);
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index 20e5e0c78a..3ccc78610d 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -47,6 +47,8 @@ static struct param {
uint32_t baseaddress;
uint32_t baseaddress_assigned;
uint32_t loadaddress;
+ uint32_t copyoffset;
+ uint32_t copyoffset_assigned;
uint32_t headeroffset;
uint32_t headeroffset_assigned;
uint32_t entrypoint;
@@ -550,6 +552,32 @@ static int cbfs_update_fit(void)
return ret;
}
+static int cbfs_copy(void)
+{
+ struct cbfs_image image;
+
+ if (!param.copyoffset_assigned) {
+ ERROR("You need to specify -D/--copy_offset.\n");
+ return 1;
+ }
+
+ if (!param.size) {
+ ERROR("You need to specify -s/--size.\n");
+ return 1;
+ }
+
+ if (cbfs_image_from_file(&image, param.cbfs_name,
+ param.headeroffset) != 0)
+ return 1;
+
+ if (cbfs_copy_instance(&image, param.copyoffset, param.size))
+ return 1;
+
+ /* Save the new image. */
+ return buffer_write_file(&image.buffer, param.cbfs_name);
+
+}
+
static const struct command commands[] = {
{"add", "H;f:n:t:b:vh?", cbfs_add},
{"add-payload", "H:f:n:t:c:b:vh?C:I:", cbfs_add_payload},
@@ -557,6 +585,7 @@ static const struct command commands[] = {
{"add-flat-binary", "H:f:n:l:e:c:b:vh?", cbfs_add_flat_binary},
{"add-int", "H:i:n:b:vh?", cbfs_add_integer},
{"remove", "H:n:vh?", cbfs_remove},
+ {"copy", "H:D:s:", cbfs_copy},
{"create", "s:B:b:H:a:o:m:vh?", cbfs_create},
{"locate", "H:f:n:P:a:Tvh?", cbfs_locate},
{"print", "H:vh?", cbfs_print},
@@ -571,6 +600,7 @@ static struct option long_options[] = {
{"base-address", required_argument, 0, 'b' },
{"load-address", required_argument, 0, 'l' },
{"top-aligned", required_argument, 0, 'T' },
+ {"copy-offset", required_argument, 0, 'D' },
{"entry-point", required_argument, 0, 'e' },
{"size", required_argument, 0, 's' },
{"bootblock", required_argument, 0, 'B' },
@@ -616,6 +646,9 @@ static void usage(char *name)
"Add a raw 64-bit integer value\n"
" remove -n NAME "
"Remove a component\n"
+ " copy -D new_header_offset -s region size \\\n"
+ " [-H source header offset] "
+ "Create a copy (duplicate) cbfs instance\n"
" create -s size -m ARCH [-B bootblock] [-b bootblock offset] \\\n"
" [-o CBFS offset] [-H header offset] [-a align] "
"Create a ROM file\n"
@@ -722,6 +755,9 @@ int main(int argc, char **argv)
optarg, NULL, 0);
param.headeroffset_assigned = 1;
break;
+ case 'D':
+ param.copyoffset = strtoul(optarg, NULL, 0);
+ param.copyoffset_assigned = 1;
case 'a':
param.alignment = strtoul(optarg, NULL, 0);
break;