firmware-utils: bcm4908img: support extracting bootfs & rootfs
authorRafał Miłecki <rafal@milecki.pl>
Mon, 5 Apr 2021 17:30:06 +0000 (19:30 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Thu, 8 Apr 2021 11:16:12 +0000 (13:16 +0200)
It's required for upgrading firmware using single partitions instead of
just blindly writing whole image.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
(cherry picked from commit e33957c241abf8f0dbf5f3713058d126fb4599b4)

tools/firmware-utils/src/bcm4908img.c

index ac76bd1c618649b0a98b9085fdbea1d26e5f5bda..51c06041d6c1f15c0bff78025c1b9c5188e15ee3 100644 (file)
@@ -54,6 +54,8 @@
 #define WFI_FLAG_HAS_PMC               0x1
 #define WFI_FLAG_SUPPORTS_BTRM         0x2
 
+#define UBI_EC_HDR_MAGIC               0x55424923
+
 static int debug;
 
 struct bcm4908img_tail {
@@ -79,6 +81,7 @@ struct bcm4908img_info {
        size_t file_size;
        size_t cferom_offset;
        size_t bootfs_offset;
+       size_t rootfs_offset;
        uint32_t crc32;                 /* Calculated checksum */
        struct bcm4908img_tail tail;
 };
@@ -298,6 +301,31 @@ static int bcm4908img_parse(FILE *fp, struct bcm4908img_info *info) {
                return -EPROTO;
        }
 
+       for (info->rootfs_offset = info->bootfs_offset;
+            info->rootfs_offset < info->file_size;
+            info->rootfs_offset += 0x20000) {
+               uint32_t magic;
+
+               if (fseek(fp, info->rootfs_offset, SEEK_SET)) {
+                       err = -errno;
+                       fprintf(stderr, "Failed to fseek: %d\n", err);
+                       return err;
+               }
+
+               bytes = fread(&magic, 1, sizeof(magic), fp);
+               if (bytes != sizeof(magic)) {
+                       fprintf(stderr, "Failed to read %zu bytes\n", sizeof(magic));
+                       return -EIO;
+               }
+
+               if (be32_to_cpu(magic) == UBI_EC_HDR_MAGIC)
+                       break;
+       }
+       if (info->rootfs_offset >= info->file_size) {
+               fprintf(stderr, "Failed to find rootfs offset\n");
+               return -EPROTO;
+       }
+
        /* CRC32 */
 
        /* Start with cferom (or bootfs) - skip vendor header */
@@ -366,6 +394,7 @@ static int bcm4908img_info(int argc, char **argv) {
        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("rootfs offset:\t0x%zx\n", info.rootfs_offset);
        printf("Checksum:\t0x%08x\n", info.crc32);
 
 err_close:
@@ -558,6 +587,12 @@ static int bcm4908img_extract(int argc, char **argv) {
                        fprintf(stderr, "This BCM4908 image doesn't contain cferom\n");
                        goto err_close;
                }
+       } else if (!strcmp(type, "bootfs")) {
+               offset = info.bootfs_offset;
+               length = info.rootfs_offset - offset;
+       } else if (!strcmp(type, "rootfs")) {
+               offset = info.rootfs_offset;
+               length = info.file_size - offset - sizeof(struct bcm4908img_tail);
        } else if (!strcmp(type, "firmware")) {
                offset = info.bootfs_offset;
                length = info.file_size - offset - sizeof(struct bcm4908img_tail);