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>
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index 2f38cec..83e8a9d 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -130,6 +130,94 @@
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 d99bee8..5e1c871 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_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 98f6b62..2aa1df0 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -43,7 +43,10 @@
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_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 @@
{"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 @@
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 @@
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;