summaryrefslogtreecommitdiffstats
path: root/src/fiasco.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fiasco.c')
-rw-r--r--src/fiasco.c298
1 files changed, 226 insertions, 72 deletions
diff --git a/src/fiasco.c b/src/fiasco.c
index caa0a9f..c8b8af5 100644
--- a/src/fiasco.c
+++ b/src/fiasco.c
@@ -34,10 +34,11 @@
#include "image.h"
#include "fiasco.h"
+#define CHECKSUM(checksum, buf, size) do { size_t _i; for ( _i = 0; _i < size; _i++ ) checksum += ((unsigned char *)buf)[_i]; } while (0)
#define FIASCO_READ_ERROR(fiasco, ...) do { ERROR_INFO(__VA_ARGS__); fiasco_free(fiasco); return NULL; } while (0)
#define FIASCO_WRITE_ERROR(file, fd, ...) do { ERROR_INFO_STR(file, __VA_ARGS__); if ( fd >= 0 ) close(fd); return -1; } while (0)
#define READ_OR_FAIL(fiasco, buf, size) do { if ( read(fiasco->fd, buf, size) != size ) { FIASCO_READ_ERROR(fiasco, "Cannot read %d bytes", size); } } while (0)
-#define READ_OR_RETURN(fiasco, buf, size) do { if ( read(fiasco->fd, buf, size) != size ) return fiasco; } while (0)
+#define READ_OR_RETURN(fiasco, checksum, buf, size) do { if ( read(fiasco->fd, buf, size) != size ) return fiasco; CHECKSUM(checksum, buf, size); } while (0)
#define WRITE_OR_FAIL_FREE(file, fd, buf, size, var) do { if ( ! simulate ) { if ( write(fd, buf, size) != (ssize_t)size ) { free(var); FIASCO_WRITE_ERROR(file, fd, "Cannot write %d bytes", size); } } } while (0)
#define WRITE_OR_FAIL(file, fd, buf, size) WRITE_OR_FAIL_FREE(file, fd, buf, size, NULL)
@@ -65,9 +66,16 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
char hwrevs[1024];
char version[257];
char layout[257];
+ uint8_t asicidx;
+ uint8_t devicetype;
+ uint8_t deviceidx;
+ uint8_t checksum;
+ uint32_t address;
uint16_t hash;
off_t offset;
struct image * image;
+ struct image_part * image_part;
+ struct image_part * image_parts;
char hwrev[9];
unsigned char buf[512];
@@ -120,23 +128,41 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
while ( 1 ) {
/* If end of file, return fiasco image */
- READ_OR_RETURN(fiasco, buf, 7);
+ checksum = 0x00;
+ READ_OR_RETURN(fiasco, checksum, buf, 1);
- /* Header of next image */
- if ( ! ( buf[0] == 0x54 && buf[2] == 0x2E && buf[3] == 0x19 && buf[4] == 0x01 && buf[5] == 0x01 && buf[6] == 0x00 ) ) {
+ /* Header of next image (0x54) */
+ if ( buf[0] != 0x54 ) {
ERROR("Invalid next image header");
return fiasco;
}
- count8 = buf[1];
- if ( count8 > 0 )
- --count8;
+ checksum = 0x00;
+
+ READ_OR_RETURN(fiasco, checksum, &count8, 1);
+
+ if ( count8 == 0 ) {
+ ERROR("No section in image header");
+ return fiasco;
+ }
+
+ READ_OR_RETURN(fiasco, checksum, buf, 2);
- READ_OR_RETURN(fiasco, &hash, 2);
+ /* File data section (0x2E) with length of 25 bytes */
+ if ( buf[0] != 0x2E || buf[1] != 25 ) {
+ ERROR("First section in image header is not file data with length of 25 bytes");
+ return fiasco;
+ }
+
+ READ_OR_RETURN(fiasco, checksum, &asicidx, 1);
+ READ_OR_RETURN(fiasco, checksum, &devicetype, 1);
+ READ_OR_RETURN(fiasco, checksum, &deviceidx, 1);
+
+ READ_OR_RETURN(fiasco, checksum, &hash, 2);
hash = ntohs(hash);
memset(type, 0, sizeof(type));
- READ_OR_RETURN(fiasco, type, 12);
+ READ_OR_RETURN(fiasco, checksum, type, 12);
byte = type[0];
if ( byte == 0xFF )
@@ -144,26 +170,35 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
VERBOSE(" %s\n", type);
- READ_OR_RETURN(fiasco, &length, 4);
+ READ_OR_RETURN(fiasco, checksum, &length, 4);
length = ntohl(length);
- /* unknown */
- READ_OR_RETURN(fiasco, buf, 4);
+ /* load address (unused) */
+ READ_OR_RETURN(fiasco, checksum, &address, 4);
+
+ /* end of file data section */
+ --count8;
VERBOSE(" size: %d bytes\n", length);
- VERBOSE(" hash: %#04x\n", hash);
+ VERBOSE(" address: 0x%04x\n", address);
+ VERBOSE(" hash: 0x%04x\n", hash);
+ VERBOSE(" asic idx: %d\n", asicidx);
+ VERBOSE(" device type: %d\n", devicetype);
+ VERBOSE(" device idx: %d\n", deviceidx);
VERBOSE(" subsections: %d\n", count8);
memset(device, 0, sizeof(device));
memset(hwrevs, 0, sizeof(hwrevs));
memset(version, 0, sizeof(version));
memset(layout, 0, sizeof(layout));
+ image_part = NULL;
+ image_parts = NULL;
while ( count8 > 0 ) {
- READ_OR_RETURN(fiasco, &byte, 1);
- READ_OR_RETURN(fiasco, &length8, 1);
- READ_OR_RETURN(fiasco, buf, length8);
+ READ_OR_RETURN(fiasco, checksum, &byte, 1);
+ READ_OR_RETURN(fiasco, checksum, &length8, 1);
+ READ_OR_RETURN(fiasco, checksum, buf, length8);
VERBOSE(" subinfo\n");
VERBOSE(" length: %d\n", length8);
@@ -207,15 +242,55 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
memset(layout, 0, sizeof(layout));
strncpy(layout, (char *)buf, length8);
VERBOSE("layout\n");
+ } else if ( byte == '4' ) {
+ VERBOSE("data part\n");
+ if ( length8 < 16 ) {
+ VERBOSE(" (damaged)\n");
+ } else {
+ if ( image_parts ) {
+ image_part->next = calloc(1, sizeof(struct image_part));
+ if ( ! image_part->next )
+ FIASCO_READ_ERROR(fiasco, "Cannot allocate image");
+ image_part = image_part->next;
+ } else {
+ image_parts = calloc(1, sizeof(struct image_part));
+ if ( ! image_parts )
+ FIASCO_READ_ERROR(fiasco, "Cannot allocate image");
+ image_part = image_parts;
+ }
+ image_part->offset = ntohl(*(uint32_t *)&buf[4]);
+ image_part->size = ntohl(*(uint32_t *)&buf[12]);
+ if ( length8 > 16 ) {
+ image_part->name = calloc(1, length8-16+1);
+ if ( image_part->name )
+ memcpy(image_part->name, &buf[16], length8-16);
+ }
+ VERBOSE(" unknown: 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[0], buf[1], buf[2], buf[3]);
+ VERBOSE(" offset: %u bytes\n", image_part->offset);
+ VERBOSE(" unknown: 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[8], buf[9], buf[10], buf[11]);
+ VERBOSE(" size: %u bytes\n", image_part->size);
+ if ( image_part->name )
+ VERBOSE(" partition name: %s\n", image_part->name);
+ }
} else {
- VERBOSE("unknown ('%c':%#x)\n", byte, byte);
+ int i;
+ VERBOSE("unknown (%#x)\n", byte);
+ VERBOSE(" hexdump:");
+ for ( i = 0; i < length8; i++ ) VERBOSE(" 0x%02x", buf[i]);
+ VERBOSE("\n");
}
--count8;
}
- /* unknown */
- READ_OR_RETURN(fiasco, buf, 1);
+ /* checksum */
+ READ_OR_RETURN(fiasco, checksum, buf, 1);
+ VERBOSE(" subinfo checksum: 0x%02x\n", buf[0]);
+
+ if ( ! noverify && buf[0] != 0x00 && checksum != 0xFF ) {
+ ERROR("Image header subinfo checksum mishmash (counted 0x%02x, got 0x%02x)", (0xFF - checksum + buf[0]) & 0xFF, buf[0]);
+ return fiasco;
+ }
offset = lseek(fiasco->fd, 0, SEEK_CUR);
if ( offset == (off_t)-1 )
@@ -226,7 +301,7 @@ struct fiasco * fiasco_alloc_from_file(const char * file) {
VERBOSE(" hwrevs: %s\n", hwrevs);
VERBOSE(" data at: %#08x\n", (unsigned int)offset);
- image = image_alloc_from_shared_fd(fiasco->fd, length, offset, hash, type, device, hwrevs, version, layout);
+ image = image_alloc_from_shared_fd(fiasco->fd, length, offset, hash, type, device, hwrevs, version, layout, image_parts);
if ( ! image )
FIASCO_READ_ERROR(fiasco, "Cannot allocate image");
@@ -274,10 +349,12 @@ int fiasco_write_to_file(struct fiasco * fiasco, const char * file) {
uint32_t length;
uint16_t hash;
uint8_t length8;
+ uint8_t checksum;
char ** device_hwrevs_bufs;
const char * str;
const char * type;
struct image_list * image_list;
+ struct image_part * image_part;
struct image * image;
unsigned char buf[4096];
@@ -375,32 +452,40 @@ int fiasco_write_to_file(struct fiasco * fiasco, const char * file) {
/* signature */
WRITE_OR_FAIL_FREE(file, fd, "T", 1, device_hwrevs_bufs);
+ checksum = 0x00;
+
/* number of subsections */
- length8 = device_count+1;
+ length8 = device_count+2;
if ( image->version )
++length8;
if ( image->layout )
++length8;
WRITE_OR_FAIL_FREE(file, fd, &length8, 1, device_hwrevs_bufs);
+ CHECKSUM(checksum, &length8, 1);
- /* unknown */
+ /* file data: asic index: APE (0x01), device type: NAND (0x01), device index: 0 */
WRITE_OR_FAIL_FREE(file, fd, "\x2e\x19\x01\x01\x00", 5, device_hwrevs_bufs);
+ CHECKSUM(checksum, "\x2e\x19\x01\x01\x00", 5);
/* checksum */
hash = htons(image->hash);
WRITE_OR_FAIL_FREE(file, fd, &hash, 2, device_hwrevs_bufs);
+ CHECKSUM(checksum, &hash, 2);
/* image type name */
memset(buf, 0, 12);
strncpy((char *)buf, type, 12);
WRITE_OR_FAIL_FREE(file, fd, buf, 12, device_hwrevs_bufs);
+ CHECKSUM(checksum, buf, 12);
/* image size */
size = htonl(image->size);
WRITE_OR_FAIL_FREE(file, fd, &size, 4, device_hwrevs_bufs);
+ CHECKSUM(checksum, &size, 4);
- /* unknown */
+ /* image load address (unused always zero) */
WRITE_OR_FAIL_FREE(file, fd, "\x00\x00\x00\x00", 4, device_hwrevs_bufs);
+ CHECKSUM(checksum, "\x00\x00\x00\x00", 4);
/* append version subsection */
if ( image->version ) {
@@ -408,6 +493,9 @@ int fiasco_write_to_file(struct fiasco * fiasco, const char * file) {
length8 = strlen(image->version)+1; /* +1 for NULL term */
WRITE_OR_FAIL_FREE(file, fd, &length8, 1, device_hwrevs_bufs);
WRITE_OR_FAIL_FREE(file, fd, image->version, length8, device_hwrevs_bufs);
+ CHECKSUM(checksum, "1", 1);
+ CHECKSUM(checksum, &length8, 1);
+ CHECKSUM(checksum, image->version, length8);
}
/* append device & hwrevs subsection */
@@ -416,6 +504,9 @@ int fiasco_write_to_file(struct fiasco * fiasco, const char * file) {
length8 = ((uint8_t *)(device_hwrevs_bufs[i]))[0];
WRITE_OR_FAIL_FREE(file, fd, &length8, 1, device_hwrevs_bufs);
WRITE_OR_FAIL_FREE(file, fd, device_hwrevs_bufs[i]+1, length8, device_hwrevs_bufs);
+ CHECKSUM(checksum, "2", 1);
+ CHECKSUM(checksum, &length8, 1);
+ CHECKSUM(checksum, device_hwrevs_bufs[i]+1, length8);
}
free(device_hwrevs_bufs);
@@ -425,10 +516,47 @@ int fiasco_write_to_file(struct fiasco * fiasco, const char * file) {
length8 = strlen(image->layout);
WRITE_OR_FAIL(file, fd, &length8, 1);
WRITE_OR_FAIL(file, fd, image->layout, length8);
+ CHECKSUM(checksum, "3", 1);
+ CHECKSUM(checksum, &length8, 1);
+ CHECKSUM(checksum, image->layout, length8);
}
- /* dummy byte - end of all subsections */
- WRITE_OR_FAIL(file, fd, "\x00", 1);
+ if ( image->parts ) {
+ /* for each image part append subsection */
+ for ( image_part = image->parts; image_part; image_part = image_part->next ) {
+ WRITE_OR_FAIL(file, fd, "4", 1); /* 4 - image data part */
+ CHECKSUM(checksum, "4", 1);
+ length = 16 + (image_part->name ? strlen(image_part->name) : 0);
+ length8 = length <= UINT8_MAX ? length : UINT8_MAX;
+ WRITE_OR_FAIL(file, fd, &length8, 1);
+ CHECKSUM(checksum, &length8, 1);
+ WRITE_OR_FAIL(file, fd, "\x00\x00\x00\x00", 4); /* unknown */
+ CHECKSUM(checksum, "\x00\x00\x00\x00", 4);
+ size = htonl(image_part->offset);
+ WRITE_OR_FAIL(file, fd, &size, 4);
+ CHECKSUM(checksum, &size, 4);
+ WRITE_OR_FAIL(file, fd, "\x00\x00\x00\x00", 4); /* unknown */
+ CHECKSUM(checksum, "\x00\x00\x00\x00", 4);
+ size = htonl(image_part->size);
+ WRITE_OR_FAIL(file, fd, &size, 4);
+ CHECKSUM(checksum, &size, 4);
+ if ( image_part->name ) {
+ WRITE_OR_FAIL(file, fd, image_part->name, length-16);
+ CHECKSUM(checksum, image_part->name, length-16);
+ }
+ }
+ } else {
+ /* append one image data part subsection */;
+ WRITE_OR_FAIL(file, fd, "4\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 14);
+ CHECKSUM(checksum, "4\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 14);
+ size = htonl(image->size);
+ WRITE_OR_FAIL(file, fd, &size, 4);
+ CHECKSUM(checksum, &size, 4);
+ }
+
+ /* checksum of header */
+ checksum = 0xFF - checksum;
+ WRITE_OR_FAIL(file, fd, &checksum, 1);
printf("Writing image data...\n");
@@ -461,8 +589,10 @@ int fiasco_unpack(struct fiasco * fiasco, const char * dir) {
char * name;
char * layout_name;
struct image * image;
+ struct image_part * image_part;
struct image_list * image_list;
- uint32_t size;
+ uint32_t offset, size, need, total_size, written;
+ int part_num;
char cwd[256];
unsigned char buf[4096];
@@ -489,68 +619,30 @@ int fiasco_unpack(struct fiasco * fiasco, const char * dir) {
while ( image_list ) {
fd = -1;
- name = NULL;
- layout_name = NULL;
image = image_list->image;
- name = image_name_alloc_from_values(image);
- if ( ! name )
- return -1;
-
printf("\n");
printf("Unpacking image...\n");
image_print_info(image);
if ( image->layout ) {
- layout_name = calloc(1, strlen(name) + sizeof(".layout")-1 + 1);
+ name = image_name_alloc_from_values(image, -1);
+ if ( ! name )
+ ALLOC_ERROR_RETURN(-1);
+
+ layout_name = calloc(1, strlen(name) + sizeof("_layout")-1 + 1);
if ( ! layout_name ) {
free(name);
ALLOC_ERROR_RETURN(-1);
}
- sprintf(layout_name, "%s.layout", name);
+ sprintf(layout_name, "%s_layout", name);
+ free(name);
printf(" Layout file: %s\n", layout_name);
- }
-
- printf(" Output file: %s\n", name);
-
- if ( ! simulate ) {
- fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0644);
- if ( fd < 0 ) {
- ERROR_INFO("Cannot create output file %s", name);
- free(name);
- free(layout_name);
- return -1;
- }
- }
-
- image_seek(image, 0);
- while ( 1 ) {
- size = image_read(image, buf, sizeof(buf));
- if ( size == 0 )
- break;
- if ( ! simulate ) {
- if ( write(fd, buf, size) != (ssize_t)size ) {
- ERROR_INFO_STR(name, "Cannot write %d bytes", size);
- close(fd);
- free(name);
- free(layout_name);
- return -1;
- }
- }
- }
-
- free(name);
-
- if ( ! simulate )
- close(fd);
-
- if ( image->layout ) {
-
if ( ! simulate ) {
fd = open(layout_name, O_RDWR|O_CREAT|O_TRUNC, 0644);
if ( fd < 0 ) {
@@ -571,11 +663,73 @@ int fiasco_unpack(struct fiasco * fiasco, const char * dir) {
free(layout_name);
- if ( ! simulate )
+ if ( ! simulate ) {
close(fd);
+ fd = -1;
+ }
}
+ part_num = 0;
+ image_part = image->parts;
+
+ do {
+
+ offset = image_part ? image_part->offset : 0;
+ total_size = image_part ? image_part->size : image->size;
+
+ name = image_name_alloc_from_values(image, image_part ? part_num : -1);
+ if ( ! name )
+ ALLOC_ERROR_RETURN(-1);
+
+ if ( image_part && ( part_num > 0 || image_part->next ) )
+ printf(" Output file part %d: %s\n", part_num+1, name);
+ else
+ printf(" Output file: %s\n", name);
+
+ if ( ! simulate ) {
+ fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ if ( fd < 0 ) {
+ ERROR_INFO("Cannot create output file %s", name);
+ free(name);
+ return -1;
+ }
+ }
+
+ written = 0;
+ image_seek(image, offset);
+ while ( written < total_size ) {
+ need = total_size - written;
+ if ( need > sizeof(buf) )
+ need = sizeof(buf);
+ size = image_read(image, buf, need);
+ if ( size == 0 )
+ break;
+ if ( ! simulate ) {
+ if ( write(fd, buf, size) != (ssize_t)size ) {
+ ERROR_INFO_STR(name, "Cannot write %d bytes", size);
+ close(fd);
+ free(name);
+ return -1;
+ }
+ }
+ written += size;
+ }
+
+ free(name);
+
+ if ( ! simulate ) {
+ close(fd);
+ fd = -1;
+ }
+
+ if ( image_part ) {
+ image_part = image_part->next;
+ part_num++;
+ }
+
+ } while ( image_part );
+
image_list = image_list->next;
}