From cbf8ac82c6e4aea62510ffe10dee85eb8a79e2fb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 6 Apr 2021 01:06:52 +0200 Subject: [PATCH] firmware-utils: bcm4908img: replace size with offset MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit It's much easier to operate on BCM4908 image data with absolute offset of each section stored. It doesn't require summing sizes over and over. Signed-off-by: Rafał Miłecki (cherry picked from commit 5314cab729b743d3b8b08db4e01c3095017f4e68) --- tools/firmware-utils/src/bcm4908img.c | 55 +++++++++++++++++---------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/tools/firmware-utils/src/bcm4908img.c b/tools/firmware-utils/src/bcm4908img.c index 536056d42a..ac76bd1c61 100644 --- a/tools/firmware-utils/src/bcm4908img.c +++ b/tools/firmware-utils/src/bcm4908img.c @@ -64,11 +64,21 @@ struct bcm4908img_tail { uint32_t flags; }; -/* Info about BCM4908 image */ +/** + * struct bcm4908img_info - info about BCM4908 image + * + * Standard BCM4908 image consists of: + * 1. (Optional) vedor header + * 2. (Optional) cferom + * 3. bootfs ─┐ + * 4. padding ├─ firmware + * 5. rootfs ─┘ + * 6. BCM4908 tail + */ struct bcm4908img_info { size_t file_size; - size_t vendor_header_size; /* Vendor header size */ - size_t cferom_size; + size_t cferom_offset; + size_t bootfs_offset; uint32_t crc32; /* Calculated checksum */ struct bcm4908img_tail tail; }; @@ -200,10 +210,11 @@ static int bcm4908img_calc_crc32(FILE *fp, struct bcm4908img_info *info) { size_t length; size_t bytes; - fseek(fp, info->vendor_header_size, SEEK_SET); + /* Start with cferom (or bootfs) - skip vendor header */ + fseek(fp, info->cferom_offset, SEEK_SET); info->crc32 = 0xffffffff; - length = info->file_size - info->vendor_header_size - sizeof(struct bcm4908img_tail); + length = info->file_size - info->cferom_offset - sizeof(struct bcm4908img_tail); while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) { info->crc32 = bcm4908img_crc32(info->crc32, buf, bytes); length -= bytes; @@ -263,14 +274,16 @@ static int bcm4908img_parse(FILE *fp, struct bcm4908img_info *info) { } chk = (void *)buf; if (be32_to_cpu(chk->magic) == 0x2a23245e) - info->vendor_header_size = be32_to_cpu(chk->header_len); + info->cferom_offset = be32_to_cpu(chk->header_len); - /* Sizes */ + /* Offsets */ - for (; info->vendor_header_size + info->cferom_size <= info->file_size; info->cferom_size += 0x20000) { - if (fseek(fp, info->vendor_header_size + info->cferom_size, SEEK_SET)) { + for (info->bootfs_offset = info->cferom_offset; + info->bootfs_offset < info->file_size; + info->bootfs_offset += 0x20000) { + if (fseek(fp, info->bootfs_offset, SEEK_SET)) { err = -errno; - fprintf(stderr, "Failed to fseek to the 0x%zx\n", info->cferom_size); + fprintf(stderr, "Failed to fseek to the 0x%zx\n", info->bootfs_offset); return err; } if (fread(&tmp16, 1, sizeof(tmp16), fp) != sizeof(tmp16)) { @@ -280,17 +293,18 @@ static int bcm4908img_parse(FILE *fp, struct bcm4908img_info *info) { if (be16_to_cpu(tmp16) == 0x8519) break; } - if (info->vendor_header_size + info->cferom_size >= info->file_size) { - fprintf(stderr, "Failed to find cferom size (no bootfs found)\n"); + if (info->bootfs_offset >= info->file_size) { + fprintf(stderr, "Failed to find bootfs offset\n"); return -EPROTO; } /* CRC32 */ - fseek(fp, info->vendor_header_size, SEEK_SET); + /* Start with cferom (or bootfs) - skip vendor header */ + fseek(fp, info->cferom_offset, SEEK_SET); info->crc32 = 0xffffffff; - length = info->file_size - info->vendor_header_size - sizeof(*tail); + length = info->file_size - info->cferom_offset - sizeof(*tail); while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) { info->crc32 = bcm4908img_crc32(info->crc32, buf, bytes); length -= bytes; @@ -349,8 +363,9 @@ static int bcm4908img_info(int argc, char **argv) { goto err_close; } - printf("Vendor header length:\t%zu\n", info.vendor_header_size); - printf("cferom size:\t0x%zx\n", info.cferom_size); + if (info.bootfs_offset != info.cferom_offset) + printf("cferom offset:\t%zu\n", info.cferom_offset); + printf("bootfs offset:\t0x%zx\n", info.bootfs_offset); printf("Checksum:\t0x%08x\n", info.crc32); err_close: @@ -537,14 +552,14 @@ static int bcm4908img_extract(int argc, char **argv) { if (!strcmp(type, "cferom")) { offset = 0; - length = info.cferom_size; + length = info.bootfs_offset - offset; if (!length) { err = -ENOENT; fprintf(stderr, "This BCM4908 image doesn't contain cferom\n"); goto err_close; } } else if (!strcmp(type, "firmware")) { - offset = info.vendor_header_size + info.cferom_size; + offset = info.bootfs_offset; length = info.file_size - offset - sizeof(struct bcm4908img_tail); } else { err = -EINVAL; @@ -648,7 +663,7 @@ static int bcm4908img_bootfs_ls(FILE *fp, struct bcm4908img_info *info) { size_t bytes; int err = 0; - for (offset = info->vendor_header_size + info->cferom_size; ; offset += (je32_to_cpu(node.totlen) + 0x03) & ~0x03) { + for (offset = info->bootfs_offset; ; offset += (je32_to_cpu(node.totlen) + 0x03) & ~0x03) { char name[FILENAME_MAX + 1]; if (fseek(fp, offset, SEEK_SET)) { @@ -719,7 +734,7 @@ static int bcm4908img_bootfs_mv(FILE *fp, struct bcm4908img_info *info, int argc return -EINVAL; } - for (offset = info->vendor_header_size + info->cferom_size; ; offset += (je32_to_cpu(node.totlen) + 0x03) & ~0x03) { + for (offset = info->bootfs_offset; ; offset += (je32_to_cpu(node.totlen) + 0x03) & ~0x03) { char name[FILENAME_MAX]; uint32_t crc32; -- 2.30.2