diff options
Diffstat (limited to 'src/fiasco.c')
-rw-r--r-- | src/fiasco.c | 298 |
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; } |