mirror of
https://github.com/openwrt/openwrt.git
synced 2025-03-29 07:06:20 +00:00
firmware-utils: bcm4908img: replace size with offset
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 <rafal@milecki.pl> Signed-off-by: maurerr <mariusd84@gmail.com>
This commit is contained in:
parent
8ca92c342a
commit
b730d743cc
@ -64,11 +64,21 @@ struct bcm4908img_tail {
|
|||||||
uint32_t flags;
|
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 {
|
struct bcm4908img_info {
|
||||||
size_t file_size;
|
size_t file_size;
|
||||||
size_t vendor_header_size; /* Vendor header size */
|
size_t cferom_offset;
|
||||||
size_t cferom_size;
|
size_t bootfs_offset;
|
||||||
uint32_t crc32; /* Calculated checksum */
|
uint32_t crc32; /* Calculated checksum */
|
||||||
struct bcm4908img_tail tail;
|
struct bcm4908img_tail tail;
|
||||||
};
|
};
|
||||||
@ -200,10 +210,11 @@ static int bcm4908img_calc_crc32(FILE *fp, struct bcm4908img_info *info) {
|
|||||||
size_t length;
|
size_t length;
|
||||||
size_t bytes;
|
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;
|
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) {
|
while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) {
|
||||||
info->crc32 = bcm4908img_crc32(info->crc32, buf, bytes);
|
info->crc32 = bcm4908img_crc32(info->crc32, buf, bytes);
|
||||||
length -= bytes;
|
length -= bytes;
|
||||||
@ -263,14 +274,16 @@ static int bcm4908img_parse(FILE *fp, struct bcm4908img_info *info) {
|
|||||||
}
|
}
|
||||||
chk = (void *)buf;
|
chk = (void *)buf;
|
||||||
if (be32_to_cpu(chk->magic) == 0x2a23245e)
|
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) {
|
for (info->bootfs_offset = info->cferom_offset;
|
||||||
if (fseek(fp, info->vendor_header_size + info->cferom_size, SEEK_SET)) {
|
info->bootfs_offset < info->file_size;
|
||||||
|
info->bootfs_offset += 0x20000) {
|
||||||
|
if (fseek(fp, info->bootfs_offset, SEEK_SET)) {
|
||||||
err = -errno;
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
if (fread(&tmp16, 1, sizeof(tmp16), fp) != sizeof(tmp16)) {
|
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)
|
if (be16_to_cpu(tmp16) == 0x8519)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (info->vendor_header_size + info->cferom_size >= info->file_size) {
|
if (info->bootfs_offset >= info->file_size) {
|
||||||
fprintf(stderr, "Failed to find cferom size (no bootfs found)\n");
|
fprintf(stderr, "Failed to find bootfs offset\n");
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CRC32 */
|
/* 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;
|
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) {
|
while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) {
|
||||||
info->crc32 = bcm4908img_crc32(info->crc32, buf, bytes);
|
info->crc32 = bcm4908img_crc32(info->crc32, buf, bytes);
|
||||||
length -= bytes;
|
length -= bytes;
|
||||||
@ -349,8 +363,9 @@ static int bcm4908img_info(int argc, char **argv) {
|
|||||||
goto err_close;
|
goto err_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Vendor header length:\t%zu\n", info.vendor_header_size);
|
if (info.bootfs_offset != info.cferom_offset)
|
||||||
printf("cferom size:\t0x%zx\n", info.cferom_size);
|
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);
|
printf("Checksum:\t0x%08x\n", info.crc32);
|
||||||
|
|
||||||
err_close:
|
err_close:
|
||||||
@ -537,14 +552,14 @@ static int bcm4908img_extract(int argc, char **argv) {
|
|||||||
|
|
||||||
if (!strcmp(type, "cferom")) {
|
if (!strcmp(type, "cferom")) {
|
||||||
offset = 0;
|
offset = 0;
|
||||||
length = info.cferom_size;
|
length = info.bootfs_offset - offset;
|
||||||
if (!length) {
|
if (!length) {
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
fprintf(stderr, "This BCM4908 image doesn't contain cferom\n");
|
fprintf(stderr, "This BCM4908 image doesn't contain cferom\n");
|
||||||
goto err_close;
|
goto err_close;
|
||||||
}
|
}
|
||||||
} else if (!strcmp(type, "firmware")) {
|
} 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);
|
length = info.file_size - offset - sizeof(struct bcm4908img_tail);
|
||||||
} else {
|
} else {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
@ -648,7 +663,7 @@ static int bcm4908img_bootfs_ls(FILE *fp, struct bcm4908img_info *info) {
|
|||||||
size_t bytes;
|
size_t bytes;
|
||||||
int err = 0;
|
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];
|
char name[FILENAME_MAX + 1];
|
||||||
|
|
||||||
if (fseek(fp, offset, SEEK_SET)) {
|
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;
|
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];
|
char name[FILENAME_MAX];
|
||||||
uint32_t crc32;
|
uint32_t crc32;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user