diff options
author | Hung-Te Lin <hungte@chromium.org> | 2013-01-29 09:45:12 +0800 |
---|---|---|
committer | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2013-02-05 22:27:08 +0100 |
commit | f56c73f1e1c2b13c7b2b989fc44358138394cc68 (patch) | |
tree | f0596bf829f52361e73dbd99efb6a58a8f743c6e /util | |
parent | 215d1d7c9b8fdd94582bdec711e98111d1db5bb7 (diff) |
cbfstool: Use cbfs_image API for "create" command.
Usage Changes: To support platforms with different memory layout, "create" takes
two extra optional parameters:
"-b": base address (or offset) for bootblock. When omitted, put bootblock in
end of ROM (x86 style).
"-H": header offset. When omitted, put header right before bootblock,
and update a top-aligned virtual address reference in end of ROM.
Example: (can be found in ARM MAkefile):
cbfstool coreboot.rom create -m armv7 -s 4096K -B bootblock.bin \
-a 64 -b 0x0000 -H 0x2040 -o 0x5000
Verified to boot on ARM (Snow) and X86 (QEMU).
Change-Id: Ida2a9e32f9a459787b577db5e6581550d9d7017b
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: http://review.coreboot.org/2214
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'util')
-rw-r--r-- | util/cbfstool/cbfs_image.c | 88 | ||||
-rw-r--r-- | util/cbfstool/cbfs_image.h | 16 | ||||
-rw-r--r-- | util/cbfstool/cbfstool.c | 69 |
3 files changed, 169 insertions, 4 deletions
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c index 2f38cec0b4..83e8a9d1fd 100644 --- a/util/cbfstool/cbfs_image.c +++ b/util/cbfstool/cbfs_image.c @@ -130,6 +130,94 @@ static int cbfs_fix_legacy_size(struct cbfs_image *image) { return 0; } +int cbfs_image_create(struct cbfs_image *image, + uint32_t arch, + size_t size, + uint32_t align, + struct buffer *bootblock, + int32_t bootblock_offset, + int32_t header_offset, + int32_t entries_offset) +{ + struct cbfs_header *header; + struct cbfs_file *entry; + uint32_t cbfs_len; + + DEBUG("cbfs_image_create: bootblock=0x%x+0x%zx, " + "header=0x%x+0x%zx, entries_offset=0x%x\n", + bootblock_offset, bootblock->size, + header_offset, sizeof(*header), entries_offset); + + if (buffer_create(&image->buffer, size, "(new)") != 0) + return -1; + image->header = NULL; + memset(image->buffer.data, CBFS_CONTENT_DEFAULT_VALUE, size); + + // Adjust legcay top-aligned address to ROM offset. + if (IS_TOP_ALIGNED_ADDRESS(entries_offset)) + entries_offset += (int32_t)size; + if (IS_TOP_ALIGNED_ADDRESS(bootblock_offset)) + bootblock_offset += (int32_t)size; + if (IS_TOP_ALIGNED_ADDRESS(header_offset)) + header_offset += (int32_t) size; + + DEBUG("cbfs_create_image: (real offset) bootblock=0x%x, " + "header=0x%x, entries_offset=0x%x\n", + bootblock_offset, header_offset, entries_offset); + + if (align == 0) + align = 64; // default align size. + + // Prepare bootblock + if (bootblock_offset + bootblock->size > size) { + ERROR("Bootblock (0x%x+0x%zx) exceed ROM size (0x%zx)\n", + bootblock_offset, bootblock->size, size); + return -1; + } + memcpy(image->buffer.data + bootblock_offset, bootblock->data, + bootblock->size); + + // Prepare header + if (header_offset + sizeof(*header) > size) { + ERROR("Header (0x%x+0x%zx) exceed ROM size (0x%zx)\n", + header_offset, sizeof(*header), size); + return -1; + } + header = (struct cbfs_header *)(image->buffer.data + header_offset); + image->header = header; + header->magic = htonl(CBFS_HEADER_MAGIC); + header->version = htonl(CBFS_HEADER_VERSION); + header->romsize = htonl(size); + header->bootblocksize = htonl(bootblock->size); + header->align = htonl(align); + header->offset = htonl(entries_offset); + header->architecture = htonl(arch); + + // Prepare entries + if (align_up(entries_offset, align) != entries_offset) { + ERROR("Offset (0x%x) must be aligned to 0x%x.\n", + entries_offset, align); + return -1; + } + if (entries_offset + sizeof(*entry) > size) { + ERROR("Offset (0x%x+0x%zx) exceed ROM size(0x%zx)\n", + entries_offset, sizeof(*entry), size); + return -1; + } + entry = (struct cbfs_file *)(image->buffer.data + entries_offset); + // To calculate available length, find + // e = min(bootblock, header, size) where e > entries_offset. + cbfs_len = size; + if (bootblock_offset > entries_offset && bootblock_offset < cbfs_len) + cbfs_len = bootblock_offset; + if (header_offset > entries_offset && header_offset < cbfs_len) + cbfs_len = header_offset; + cbfs_len -= entries_offset + align; + cbfs_create_empty_entry(image, entry, cbfs_len, ""); + LOG("Created CBFS image (capacity = %d bytes)\n", cbfs_len); + return 0; +} + int cbfs_image_from_file(struct cbfs_image *image, const char *filename) { if (buffer_from_file(&image->buffer, filename) != 0) return -1; diff --git a/util/cbfstool/cbfs_image.h b/util/cbfstool/cbfs_image.h index d99bee851e..5e1c87109d 100644 --- a/util/cbfstool/cbfs_image.h +++ b/util/cbfstool/cbfs_image.h @@ -22,6 +22,8 @@ #include "common.h" #include "cbfs.h" +#define IS_TOP_ALIGNED_ADDRESS(x) ((uint32_t)(x) > 0x80000000) + /* CBFS image processing */ struct cbfs_image { @@ -29,6 +31,20 @@ struct cbfs_image { struct cbfs_header *header; }; +/* Creates an empty CBFS image by given size, and description to its content + * (bootblock, align, header location, starting offset of CBFS entries. + * The output image will contain a valid cbfs_header, with one cbfs_file + * entry with type CBFS_COMPONENT_NULL, with max available size. + * Returns 0 on success, otherwise none-zero. */ +int cbfs_image_create(struct cbfs_image *image, + uint32_t arch, + size_t size, + uint32_t align, + struct buffer *bootblock, + int32_t bootblock_offset, + int32_t header_offset, + int32_t entries_offset); + /* Loads a CBFS image from file. Returns 0 on success, otherwise non-zero. */ int cbfs_image_from_file(struct cbfs_image *image, const char *filename); diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c index 98f6b62ee7..2aa1df01eb 100644 --- a/util/cbfstool/cbfstool.c +++ b/util/cbfstool/cbfstool.c @@ -43,7 +43,10 @@ static struct param { char *bootblock; uint32_t type; uint32_t baseaddress; + uint32_t baseaddress_assigned; uint32_t loadaddress; + uint32_t headeroffset; + uint32_t headeroffset_assigned; uint32_t entrypoint; uint32_t size; uint32_t alignment; @@ -343,23 +346,72 @@ static int cbfs_remove(void) static int cbfs_create(void) { + struct cbfs_image image; + struct buffer bootblock; + if (param.size == 0) { ERROR("You need to specify a valid -s/--size.\n"); return 1; } if (!param.bootblock) { - ERROR("You need to specify -b/--bootblock.\n"); + ERROR("You need to specify -B/--bootblock.\n"); return 1; } + // TODO Remove arch or pack into param. if (arch == CBFS_ARCHITECTURE_UNKNOWN) { ERROR("You need to specify -m/--machine arch\n"); return 1; } - return create_cbfs_image(param.cbfs_name, param.size, param.bootblock, - param.alignment, param.offset); + if (buffer_from_file(&bootblock, param.bootblock) != 0) { + return 1; + } + + // Setup default boot offset and header offset. + if (!param.baseaddress_assigned) { + // put boot block before end of ROM. + param.baseaddress = param.size - bootblock.size; + DEBUG("bootblock in end of ROM.\n"); + } + if (!param.headeroffset_assigned) { + // Put header before bootblock, and make a reference in end of + // bootblock. + param.headeroffset = ( + param.baseaddress - + sizeof(struct cbfs_header)); + if (bootblock.size >= sizeof(uint32_t)) { + // TODO this only works for 32b top-aligned system now... + uint32_t ptr = param.headeroffset - param.size; + uint32_t *sig = (uint32_t *)(bootblock.data + + bootblock.size - + sizeof(ptr)); + *sig = ptr; + DEBUG("CBFS header reference in end of bootblock.\n"); + } + } + + if (cbfs_image_create(&image, + arch, + param.size, + param.alignment, + &bootblock, + param.baseaddress, + param.headeroffset, + param.offset) != 0) { + ERROR("Failed to create %s.\n", param.cbfs_name); + return 1; + } + buffer_delete(&bootblock); + + if (cbfs_image_write_file(&image, param.cbfs_name) != 0) { + ERROR("Failed to write %s.\n", param.cbfs_name); + cbfs_image_delete(&image); + return 1; + } + cbfs_image_delete(&image); + return 0; } static int cbfs_locate(void) @@ -458,7 +510,7 @@ static const struct command commands[] = { {"add-stage", "f:n:t:c:b:vh?", cbfs_add_stage}, {"add-flat-binary", "f:n:l:e:c:b:vh?", cbfs_add_flat_binary}, {"remove", "n:vh?", cbfs_remove}, - {"create", "s:B:a:o:m:vh?", cbfs_create}, + {"create", "s:B:b:H:a:o:m:vh?", cbfs_create}, {"locate", "f:n:a:Tvh?", cbfs_locate}, {"print", "vh?", cbfs_print}, {"extract", "n:f:vh?", cbfs_extract}, @@ -579,6 +631,10 @@ int main(int argc, char **argv) break; case 'b': param.baseaddress = strtoul(optarg, NULL, 0); + // baseaddress may be zero on non-x86, so we + // need an explicit "baseaddress_assigned". + param.baseaddress = strtoul(optarg, NULL, 0); + param.baseaddress_assigned = 1; break; case 'l': param.loadaddress = strtoul(optarg, NULL, 0); @@ -598,6 +654,11 @@ int main(int argc, char **argv) case 'B': param.bootblock = optarg; break; + case 'H': + param.headeroffset = strtoul( + optarg, NULL, 0); + param.headeroffset_assigned = 1; + break; case 'a': param.alignment = strtoul(optarg, NULL, 0); break; |