diff options
-rw-r--r-- | util/cbfstool/cbfs_image.c | 82 | ||||
-rw-r--r-- | util/cbfstool/cbfs_image.h | 4 | ||||
-rw-r--r-- | util/cbfstool/cbfstool.c | 36 |
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; |