New Upstream Release - 0xffff

Ready changes

Summary

Merged new upstream version: 0.10 (was: 0.9).

Resulting package

Built on 2022-03-14T20:06 (took 1m51s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases 0xffff-dbgsymapt install -t fresh-releases 0xffff

Lintian Result

Diff

diff --git a/TODO b/TODO
index 292b372..fbf0f2d 100644
--- a/TODO
+++ b/TODO
@@ -5,7 +5,6 @@ cold-flash:
  * Detect device from asic id
 
 disk:
- * Support for flashing mmc images
  * Badblock checking
 
 fiasco:
@@ -15,7 +14,6 @@ image:
  * Support for Harmattan images
 
 local:
- * Support for flashing (on device)
  * Write versions
  * Badblock checking
 
diff --git a/config.mk b/config.mk
index b3bbcb7..ec685de 100644
--- a/config.mk
+++ b/config.mk
@@ -1,4 +1,4 @@
-VERSION = 0.9
+VERSION = 0.10
 PREFIX = /usr/local
 
 # NetBSD stuff
diff --git a/debian/changelog b/debian/changelog
index 0e16c0f..98a6775 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+0xffff (0.10-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 14 Mar 2022 20:04:33 -0000
+
 0xffff (0.9-1) unstable; urgency=medium
 
   [ Debian Janitor ]
diff --git a/doc/dumping b/doc/dumping
index 4a629cd..b7e9cdf 100644
--- a/doc/dumping
+++ b/doc/dumping
@@ -30,11 +30,10 @@ Technical details:
 For dumping mtd partition is used tool nanddump. Here is example how to dump
 kernel image without padding to file zImage:
 
- $ nanddump -o -b -s 0x00000800 -l 0x001FF800 -f zImage /dev/mtd2
+ $ nanddump --omitoob -s 0x00000800 -l 0x001FF800 -f zImage /dev/mtd2
 
 Params means:
--o - "Omit oob data"
--b - "Omit bad blocks"
+--omitoob - "Omit oob data"
 -s - "Start address"
 -l - "Length"
 -f - "Output file"
diff --git a/doc/fiasco b/doc/fiasco
index 941a2da..674c693 100644
--- a/doc/fiasco
+++ b/doc/fiasco
@@ -38,24 +38,64 @@ IMAGE
 
    1 byte = 0x54    --  signature
    1 byte           --  number of subsection blocks
-                        (start of data block)
-   1 byte           --  type of subsection block (data - always 0x2e)
-   1 byte           --  length of subsection block (data - always 25)
-   3 bytes          --  unknown (always 0x01 0x01 0x00)
-   2 bytes          --  checksum for the image contents (xorpair) (big endian)
-  12 bytes          --  image name type (first byte is FF if is the last image)
-   4 bytes          --  length of image data (big endian)
-   4 bytes          --  unknown (always 0x00 0x00 0x00 0x00)
-                        (end of data block)
              block {
    1 byte           --  type of subsection block
-                          '1' - version
-                          '2' - device & hw revisions (size of device is 16, hw revision 8)
-                          '3' - layout
-                          '4' - unknown
-                          '/' - unknown
+                          0x2E - file data
+                          0x2F - partition info
+                          0x31 - version
+                          0x32 - device & hw revisions (size of device is 16, hw revision 8)
+                          0x33 - layout
+                          0x34 - image data part block (one block for one data part)
    1 byte           --  length of subsection block
    N bytes          --  subsection block data
              }
-   1 byte           --  unknown (0x00 is accepted, maybe end of subsections?)
+   1 byte           --  checksum of subsection data without signature (0xFF - xorpair)
    N bytes          --  image data
+
+
+FILE DATA BLOCK
+
+   1 byte           --  asic index (always APE - 0x01)
+   1 byte           --  device type (always NAND - 0x01)
+   1 byte           --  device index (always 0x00)
+   2 bytes          --  checksum for the image contents (xorpair) (big endian)
+  12 bytes          --  image name type (first byte is FF if is the last image)
+   4 bytes          --  length of image data (big endian)
+   4 bytes          --  load address of image data (big endian, unused always zero)
+
+
+PARTITION INFO BLOCK
+
+   N bytes          --  unknown
+
+
+IMAGE DATA PART BLOCK
+
+   4 bytes          --  unknown (always 0x00 0x00 0x00 0x00)
+   4 bytes          --  offset (big endian)
+   4 bytes          --  unknown (always 0x00 0x00 0x00 0x00)
+   4 bytes          --  size (big endian)
+   N bytes          --  partition name (prefix) in layout (may be omitted)
+
+
+LAYOUT DATA BLOCK
+
+   N bytes of text data, e.g.:
+
+mmc {
+        name = "internal";
+        partition {
+                fs_type = "vfat";
+                prefix = "mydocs";
+                no_create = true;
+        }
+        partition {
+                size = 2048;
+                fs_type = "ext3";
+                prefix = "home";
+        }
+        partition {
+                size = 768;
+                fs_type = "swap";
+        }
+}
diff --git a/src/device.c b/src/device.c
index db2c6a7..0a7820a 100644
--- a/src/device.c
+++ b/src/device.c
@@ -184,9 +184,11 @@ char ** device_list_alloc_to_bufs(const struct device_list * device_list) {
 			continue;
 		}
 
-		for ( i = 0; device_first->hwrevs[i] != -1; ++i )
-			if ( device_first->hwrevs[i] >= 0 && device_first->hwrevs[i] <= 9999 )
-				++local;
+		if ( device_first->hwrevs ) {
+			for ( i = 0; device_first->hwrevs[i] != -1; ++i )
+				if ( device_first->hwrevs[i] >= 0 && device_first->hwrevs[i] <= 9999 )
+					++local;
+		}
 
 		size += (1+16+(MAX_HWREVS+1)*8)*(local/MAX_HWREVS+1);
 		count += local/MAX_HWREVS;
@@ -215,7 +217,7 @@ char ** device_list_alloc_to_bufs(const struct device_list * device_list) {
 			continue;
 		}
 
-		while ( device_first->hwrevs[i+1] != -1 ) {
+		do {
 
 			uint8_t len = 0;
 			ret[j] = ++last_ptr;
@@ -228,7 +230,7 @@ char ** device_list_alloc_to_bufs(const struct device_list * device_list) {
 
 			for ( k = 0; k < MAX_HWREVS; ++k ) {
 
-				if ( device_first->hwrevs[i+1] == -1 )
+				if ( ! device_first->hwrevs || device_first->hwrevs[i+1] == -1 )
 					break;
 
 				++i;
@@ -246,7 +248,7 @@ char ** device_list_alloc_to_bufs(const struct device_list * device_list) {
 
 			++j;
 
-		}
+		} while ( device_first->hwrevs && device_first->hwrevs[i+1] != -1 );
 
 		device_first = device_first->next;
 
diff --git a/src/disk.c b/src/disk.c
index 38fbb09..41d1823 100644
--- a/src/disk.c
+++ b/src/disk.c
@@ -118,7 +118,7 @@ int disk_open_dev(int maj, int min, int partition, int readonly) {
 
 		blkdev[len] = 0;
 
-		fd = open(blkdev, (readonly ? O_RDONLY : O_RDWR) | O_EXCL | O_NONBLOCK);
+		fd = open(blkdev, ((simulate || readonly) ? O_RDONLY : O_RDWR) | O_EXCL | O_NONBLOCK);
 		if ( fd < 0 ) {
 			ERROR_INFO("Cannot open block device %s", blkdev);
 			return -1;
@@ -144,13 +144,13 @@ int disk_open_dev(int maj, int min, int partition, int readonly) {
 			ERROR("Block device name is too long");
 			return -1;
 		}
-		fd = open(blkdev, (readonly ? O_RDONLY : O_RDWR) | O_EXCL);
+		fd = open(blkdev, ((simulate || readonly) ? O_RDONLY : O_RDWR) | O_EXCL);
 		if ( fd < 0 && errno == ENOENT ) {
 			if ( snprintf(blkdev+len, sizeof(blkdev)-len, "%d", partition) >= (int)(sizeof(blkdev)-len) ) {
 				ERROR("Block device name is too long");
 				return -1;
 			}
-			fd = open(blkdev, (readonly ? O_RDONLY : O_RDWR) | O_EXCL);
+			fd = open(blkdev, ((simulate || readonly) ? O_RDONLY : O_RDWR) | O_EXCL);
 		}
 		if ( fd < 0 && errno == ENOENT ) {
 			blkdev[len] = 0;
@@ -201,7 +201,7 @@ int disk_open_dev(int maj, int min, int partition, int readonly) {
 
 int disk_dump_dev(int fd, const char * file) {
 
-	int fd2;
+	int fd2 = -1;
 	int ret;
 	char * path;
 	uint64_t blksize;
@@ -253,11 +253,15 @@ int disk_dump_dev(int fd, const char * file) {
 		return -1;
 	}
 
-	fd2 = creat(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	if ( ! simulate ) {
+
+		fd2 = creat(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+		if ( fd2 < 0 ) {
+			ERROR_INFO("Cannot create file %s", file);
+			return -1;
+		}
 
-	if ( fd2 < 0 ) {
-		ERROR_INFO("Cannot create file %s", file);
-		return -1;
 	}
 
 	sent = 0;
@@ -272,29 +276,89 @@ int disk_dump_dev(int fd, const char * file) {
 			break;
 		if ( size < 0 ) {
 			PRINTF_ERROR("Reading from block device failed");
-			close(fd2);
+			if ( ! simulate )
+				close(fd2);
 			return -1;
 		}
-		if ( write(fd2, global_buf, size) != size ) {
-			PRINTF_ERROR("Dumping image failed");
-			close(fd2);
-			return -1;
+		if ( ! simulate ) {
+			if ( write(fd2, global_buf, size) != size ) {
+				PRINTF_ERROR("Dumping image failed");
+				close(fd2);
+				return -1;
+			}
 		}
 		sent += size;
 		printf_progressbar(sent, blksize);
 	}
 
-	close(fd2);
+	if ( ! simulate )
+		close(fd2);
 	return 0;
 
 }
 
-int disk_flash_dev(int fd, const char * file) {
+int disk_flash_dev(int fd, struct image * image) {
 
-	ERROR("Not implemented yet");
-	(void)fd;
-	(void)file;
-	return -1;
+	uint64_t blksize;
+	size_t need, sent;
+	ssize_t size;
+
+	if ( image->type != IMAGE_MMC )
+		ERROR_RETURN("Only mmc images are supported", -1);
+
+	printf("Writing image to block device...\n");
+
+#ifdef __linux__
+
+	if ( ioctl(fd, BLKGETSIZE64, &blksize) != 0 ) {
+		ERROR_INFO("Cannot get size of block device");
+		return -1;
+	}
+
+#else
+
+	blksize = lseek(fd, 0, SEEK_END);
+	if ( (off_t)blksize == (off_t)-1 ) {
+		ERROR_INFO("Cannot get size of block device");
+		return -1;
+	}
+
+	if ( lseek(fd, 0, SEEK_SET) == (off_t)-1 ) {
+		ERROR_INFO("Cannot seek to begin of block device");
+		return -1;
+	}
+
+#endif
+
+	if ( blksize == 0 )
+		ERROR_RETURN("Block device has zero size", -1);
+
+	if ( image->size > blksize )
+		ERROR_RETURN("Image is too big", -1);
+
+	sent = 0;
+	printf_progressbar(0, image->size);
+
+	while ( sent < image->size ) {
+		need = image->size - sent;
+		if ( need > sizeof(global_buf) )
+			need = sizeof(global_buf);
+		size = image_read(image, global_buf, need);
+		if ( size == 0 ) {
+			PRINTF_ERROR("Failed to read image");
+			return -1;
+		}
+		if ( ! simulate ) {
+			if ( write(fd, global_buf, size) != size ) {
+				PRINTF_ERROR("Writing image failed");
+				return -1;
+			}
+		}
+		sent += size;
+		printf_progressbar(sent, image->size);
+	}
+
+	return 0;
 
 }
 
@@ -412,16 +476,14 @@ int disk_init(struct usb_device_info * dev) {
 		maj2 = tmp;
 	}
 
-	/* TODO: change 1 to 0 when disk_flash_dev will be implemented */
-
 	/* RX-51, RM-680 and RM-696 export MyDocs in first usb device and just first partion, so host system see whole device without MBR table */
 	if ( dev->device == DEVICE_RX_51 || dev->device == DEVICE_RM_680 || dev->device == DEVICE_RM_696 )
-		fd = disk_open_dev(maj1, min1, -1, 1);
+		fd = disk_open_dev(maj1, min1, -1, simulate ? 1 : 0);
 	/* Other devices can export SD card as first partition and export whole mmc device, so host system will see MBR table */
 	else if ( maj2 != -1 && min2 != -1 )
-		fd = disk_open_dev(maj2, min2, 1, 1);
+		fd = disk_open_dev(maj2, min2, 1, simulate ? 1 : 0);
 	else
-		fd = disk_open_dev(maj1, min1, 1, 1);
+		fd = disk_open_dev(maj1, min1, 1, simulate ? 1 : 0);
 
 	if ( fd < 0 )
 		return -1;
@@ -454,10 +516,16 @@ enum device disk_get_device(struct usb_device_info * dev) {
 
 int disk_flash_image(struct usb_device_info * dev, struct image * image) {
 
-	ERROR("Not implemented yet");
-	(void)dev;
-	(void)image;
-	return -1;
+	int ret;
+
+	printf("Flash image:\n");
+	image_print_info(image);
+
+	ret = disk_flash_dev(dev->data, image);
+	if ( ret == 0 )
+		printf("Done\n");
+
+	return ret;
 
 }
 
diff --git a/src/disk.h b/src/disk.h
index 15eb127..f6e3930 100644
--- a/src/disk.h
+++ b/src/disk.h
@@ -30,7 +30,7 @@ enum device disk_get_device(struct usb_device_info * dev);
 
 int disk_open_dev(int maj, int min, int partition, int readonly);
 int disk_dump_dev(int fd, const char * file);
-int disk_flash_dev(int fd, const char * file);
+int disk_flash_dev(int fd, struct image * image);
 
 int disk_flash_image(struct usb_device_info * dev, struct image * image);
 int disk_dump_image(struct usb_device_info * dev, enum image_type image, const char * file);
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;
 
 	}
diff --git a/src/image.c b/src/image.c
index b78633b..fef124e 100644
--- a/src/image.c
+++ b/src/image.c
@@ -100,7 +100,7 @@ static void image_missing_values_from_name(struct image * image, const char * na
 }
 
 /* format: type-device:hwrevs_version */
-char * image_name_alloc_from_values(struct image * image) {
+char * image_name_alloc_from_values(struct image * image, int part_num) {
 
 	char * name;
 	char * ptr;
@@ -108,6 +108,8 @@ char * image_name_alloc_from_values(struct image * image) {
 	size_t length;
 	const char * type;
 	const char * device;
+	struct image_part * part;
+	int i;
 
 	type = image_type_to_string(image->type);
 
@@ -124,6 +126,14 @@ char * image_name_alloc_from_values(struct image * image) {
 	else
 		hwrevs = NULL;
 
+	part = image->parts;
+
+	if ( part && ( !part->next || part_num < 0 ) )
+		part = NULL;
+
+	for ( i = 0; i < part_num && part; i++ )
+		part = part->next;
+
 	length = 1 + strlen(type);
 
 	if ( device )
@@ -132,6 +142,10 @@ char * image_name_alloc_from_values(struct image * image) {
 		length += 1 + strlen(hwrevs);
 	if ( image->version )
 		length += 1 + strlen(image->version);
+	if ( part )
+		length += 4 + 3; /* 3 <= strlen(part_num) */
+	if ( part && part->name )
+		length += 1 + strlen(part->name);
 
 	name = calloc(1, length);
 	if ( ! name ) {
@@ -149,13 +163,19 @@ char * image_name_alloc_from_values(struct image * image) {
 	if ( image->version )
 		ptr += sprintf(ptr, "_%s", image->version);
 
+	if ( part ) {
+		ptr += sprintf(ptr, "_part%d", part_num+1);
+		if ( part->name )
+			ptr += sprintf(ptr, "_%s", part->name);
+	}
+
 	free(hwrevs);
 
 	return name;
 
 }
 
-static int image_append(struct image * image, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) {
+static int image_append(struct image * image, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
 
 	enum image_type detected_type;
 
@@ -210,6 +230,8 @@ static int image_append(struct image * image, const char * type, const char * de
 	else
 		image->layout = NULL;
 
+	image->parts = parts;
+
 	return 0;
 
 }
@@ -244,7 +266,7 @@ static struct image * image_alloc(void) {
 
 }
 
-struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) {
+struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
 
 	int fd;
 
@@ -254,11 +276,11 @@ struct image * image_alloc_from_file(const char * file, const char * type, const
 		return NULL;
 	}
 
-	return image_alloc_from_fd(fd, file, type, device, hwrevs, version, layout);
+	return image_alloc_from_fd(fd, file, type, device, hwrevs, version, layout, parts);
 
 }
 
-struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) {
+struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
 
 	off_t offset;
 	struct image * image = image_alloc();
@@ -291,7 +313,7 @@ struct image * image_alloc_from_fd(int fd, const char * orig_filename, const cha
 		return NULL;
 	}
 
-	if ( image_append(image, type, device, hwrevs, version, layout) < 0 )
+	if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 )
 		return NULL;
 
 	if ( ( ! type || ! type[0] ) && ( ! device || ! device[0] ) && ( ! hwrevs || ! hwrevs[0] ) && ( ! version || ! version[0] ) )
@@ -303,7 +325,7 @@ struct image * image_alloc_from_fd(int fd, const char * orig_filename, const cha
 
 }
 
-struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout) {
+struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
 
 	struct image * image = image_alloc();
 	if ( ! image )
@@ -315,7 +337,7 @@ struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, ui
 	image->offset = offset;
 	image->cur = 0;
 
-	if ( image_append(image, type, device, hwrevs, version, layout) < 0 )
+	if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 )
 		return NULL;
 
 	if ( ! noverify && image->hash != hash ) {
@@ -347,6 +369,13 @@ void image_free(struct image * image) {
 		image->devices = next;
 	}
 
+	while ( image->parts ) {
+		struct image_part * next = image->parts->next;
+		free(image->parts->name);
+		free(image->parts);
+		image->parts = next;
+	}
+
 	free(image->version);
 	free(image->layout);
 	free(image->orig_filename);
@@ -516,6 +545,9 @@ static const char * image_types[] = {
 	[IMAGE_CMT_2ND] = "cmt-2nd",
 	[IMAGE_CMT_ALGO] = "cmt-algo",
 	[IMAGE_CMT_MCUSW] = "cmt-mcusw",
+	[IMAGE_1ST] = "1st",
+	[IMAGE_CERT_SW] = "cert-sw",
+	[IMAGE_APE_ALGO] = "ape-algo",
 };
 
 enum image_type image_type_from_data(struct image * image) {
diff --git a/src/image.h b/src/image.h
index 42111bf..824c8ad 100644
--- a/src/image.h
+++ b/src/image.h
@@ -37,9 +37,19 @@ enum image_type {
 	IMAGE_CMT_2ND,
 	IMAGE_CMT_ALGO,
 	IMAGE_CMT_MCUSW,
+	IMAGE_1ST,
+	IMAGE_CERT_SW,
+	IMAGE_APE_ALGO,
 	IMAGE_COUNT,
 };
 
+struct image_part {
+	struct image_part * next;
+	uint32_t offset;
+	uint32_t size;
+	char * name;
+};
+
 struct image {
 	enum image_type type;
 	struct device_list * devices;
@@ -47,6 +57,7 @@ struct image {
 	char * layout;
 	uint16_t hash;
 	uint32_t size;
+	struct image_part * parts;
 
 	int fd;
 	int is_shared_fd;
@@ -63,9 +74,9 @@ struct image_list {
 	struct image_list * next;
 };
 
-struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout);
-struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout);
-struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout);
+struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
+struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
+struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
 void image_free(struct image * image);
 void image_seek(struct image * image, size_t whence);
 size_t image_read(struct image * image, void * buf, size_t count);
@@ -76,7 +87,7 @@ void image_list_unlink(struct image_list * list);
 
 uint16_t image_hash_from_data(struct image * image);
 enum image_type image_type_from_data(struct image * image);
-char * image_name_alloc_from_values(struct image * image);
+char * image_name_alloc_from_values(struct image * image, int part_num);
 enum image_type image_type_from_string(const char * type);
 const char * image_type_to_string(enum image_type type);
 int image_hwrev_is_valid(struct image * image, int16_t hwrev);
diff --git a/src/local.c b/src/local.c
index 3813910..eed2c2a 100644
--- a/src/local.c
+++ b/src/local.c
@@ -19,6 +19,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <signal.h>
 
 #include <sys/statvfs.h>
 #include <sys/types.h>
@@ -198,14 +199,6 @@ enum device local_get_device(void) {
 
 }
 
-int local_flash_image(struct image * image) {
-
-	ERROR("Not implemented yet");
-	(void)image;
-	return -1;
-
-}
-
 static int local_nanddump(const char * file, int mtd, int offset, int length) {
 
 	struct statvfs buf;
@@ -227,15 +220,18 @@ static int local_nanddump(const char * file, int mtd, int offset, int length) {
 		return 1;
 	}
 
-	size = snprintf(NULL, 0, "nanddump -o -b -s %d -l %d -f %s /dev/mtd%dro", offset, length, file, mtd);
+	size = snprintf(NULL, 0, "nanddump --omitoob -s %d -l %d -f %s /dev/mtd%d", offset, length, file, mtd);
 
 	command = malloc(size+1);
 	if ( ! command )
 		return 1;
 
-	snprintf(command, size+1, "nanddump -o -b -s %d -l %d -f %s /dev/mtd%dro", offset, length, file, mtd);
+	snprintf(command, size+1, "nanddump --omitoob -s %d -l %d -f %s /dev/mtd%d", offset, length, file, mtd);
 
-	ret = system(command);
+	if ( ! simulate )
+		ret = system(command);
+	else
+		ret = 0;
 
 	free(command);
 
@@ -243,52 +239,77 @@ static int local_nanddump(const char * file, int mtd, int offset, int length) {
 
 }
 
-struct nanddump_args {
-	int valid;
-	int mtd;
-	int offset;
-	int length;
+static FILE * local_nandwrite(int mtd, int offset) {
+
+	char * command;
+	FILE * stream;
+	size_t size;
+
+	size = snprintf(NULL, 0, "nandwrite -a -s %d -p /dev/mtd%d -", offset, mtd);
+
+	command = malloc(size+1);
+	if ( ! command )
+		return NULL;
+
+	snprintf(command, size+1, "nandwrite -a -s %d -p /dev/mtd%d -", offset, mtd);
+
+	if ( ! simulate )
+		stream = popen(command, "w");
+	else
+		stream = NULL;
+
+	free(command);
+
+	return stream;
+
+}
+
+struct nandpart_args {
+	unsigned int mtd;
+	unsigned int offset;
+	unsigned int length;
+	unsigned int header;
 };
 
-static struct nanddump_args nanddump_rx51[] = {
-	[IMAGE_XLOADER]   = { 1, 0, 0x00000000, 0x00004000 },
-	[IMAGE_SECONDARY] = { 1, 0, 0x00004000, 0x0001C000 },
-	[IMAGE_KERNEL]    = { 1, 3, 0x00000800, 0x001FF800 },
-	[IMAGE_INITFS]    = { 1, 4, 0x00000000, 0x00200000 },
-	[IMAGE_ROOTFS]    = { 1, 5, 0x00000000, 0x0fb40000 },
+static struct nandpart_args nandpart_rx51[] = {
+	[IMAGE_XLOADER]   = { 0, 0x00000000, 0x00004000, 0x00000000 },
+	[IMAGE_SECONDARY] = { 0, 0x00004000, 0x0001C000, 0x00000000 },
+	[IMAGE_KERNEL]    = { 3, 0x00000000, 0x00200000, 0x00000800 },
+	[IMAGE_INITFS]    = { 4, 0x00000000, 0x00200000, 0x00000000 },
+	[IMAGE_ROOTFS]    = { 5, 0x00000000, 0x0fb40000, 0x00000000 },
 };
 
 /* FIXME: Is this table correct? */
-static struct nanddump_args nanddump_rx4x[] = {
-	[IMAGE_XLOADER]   = { 1, 0, 0x00000200, 0x00003E00 },
-	[IMAGE_SECONDARY] = { 1, 0, 0x00004000, 0x0001C000 },
-	[IMAGE_KERNEL]    = { 1, 2, 0x00000800, 0x0021F800 },
-	[IMAGE_INITFS]    = { 1, 3, 0x00000000, 0x00400000 },
-	[IMAGE_ROOTFS]    = { 1, 4, 0x00000000, 0x0f960000 },
+static struct nandpart_args nandpart_rx4x[] = {
+	[IMAGE_XLOADER]   = { 0, 0x00000200, 0x00003E00, 0x00000000 },
+	[IMAGE_SECONDARY] = { 0, 0x00004000, 0x0001C000, 0x00000000 },
+	[IMAGE_KERNEL]    = { 2, 0x00000000, 0x00220000, 0x00000800 },
+	[IMAGE_INITFS]    = { 3, 0x00000000, 0x00400000, 0x00000000 },
+	[IMAGE_ROOTFS]    = { 4, 0x00000000, 0x0f960000, 0x00000000 },
 };
 
 /* FIXME: Is this table correct? */
-static struct nanddump_args nanddump_old[] = {
-	[IMAGE_XLOADER]   = { 1, 0, 0x00000200, 0x00003E00 },
-	[IMAGE_SECONDARY] = { 1, 0, 0x00004000, 0x0001C000 },
-	[IMAGE_KERNEL]    = { 1, 2, 0x00000800, 0x001FF800 },
-	[IMAGE_INITFS]    = { 1, 3, 0x00000000, 0x00200000 },
-	[IMAGE_ROOTFS]    = { 1, 4, 0x00000000, 0x0fb80000 },
+static struct nandpart_args nandpart_old[] = {
+	[IMAGE_XLOADER]   = { 0, 0x00000200, 0x00003E00, 0x00000000 },
+	[IMAGE_SECONDARY] = { 0, 0x00004000, 0x0001C000, 0x00000000 },
+	[IMAGE_KERNEL]    = { 2, 0x00000000, 0x00200000, 0x00000800 },
+	[IMAGE_INITFS]    = { 3, 0x00000000, 0x00200000, 0x00000000 },
+	[IMAGE_ROOTFS]    = { 4, 0x00000000, 0x0fb80000, 0x00000000 },
 };
 
-struct nanddump_device {
+struct nand_device {
 	size_t count;
-	struct nanddump_args * args;
+	struct nandpart_args * args;
 };
 
-#define NANDDUMP(device, array) [device] = { .count = sizeof(array)/sizeof(array[0]), .args = array }
+#define NAND_DEVICE(device, array) [device] = { .count = sizeof(array)/sizeof(array[0]), .args = array }
 
-static struct nanddump_device nanddump[] = {
-	NANDDUMP(DEVICE_SU_18, nanddump_old),
-	NANDDUMP(DEVICE_RX_34, nanddump_old),
-	NANDDUMP(DEVICE_RX_44, nanddump_rx4x),
-	NANDDUMP(DEVICE_RX_48, nanddump_rx4x),
-	NANDDUMP(DEVICE_RX_51, nanddump_rx51),
+static struct nand_device nand_device[] = {
+	NAND_DEVICE(DEVICE_SU_18, nandpart_old),
+	NAND_DEVICE(DEVICE_RX_34, nandpart_old),
+	NAND_DEVICE(DEVICE_RX_44, nandpart_rx4x),
+	NAND_DEVICE(DEVICE_RX_48, nandpart_rx4x),
+	NAND_DEVICE(DEVICE_RX_51, nandpart_rx51),
 };
 
 #undef NANDDUMP
@@ -380,10 +401,13 @@ static void local_find_internal_mydocs(int * maj, int * min) {
 
 int local_dump_image(enum image_type image, const char * file) {
 
+	unsigned char buf[20];
 	int ret = -1;
 	int fd = -1;
+	int header = 0;
 	unsigned char * addr = NULL;
-	off_t nlen, len;
+	off_t nlen = (off_t)-1;
+	off_t len;
 	int align;
 	int maj, min;
 
@@ -415,17 +439,49 @@ int local_dump_image(enum image_type image, const char * file) {
 
 	} else {
 
-		if ( device >= sizeof(nanddump)/sizeof(nanddump[0]) ) {
+		if ( device >= sizeof(nand_device)/sizeof(nand_device[0]) ) {
 			ERROR("Unsupported device");
 			goto clean;
 		}
 
-		if ( image >= nanddump[device].count ) {
+		if ( image >= nand_device[device].count ) {
 			ERROR("Unsupported image type: %s", image_type_to_string(image));
 			goto clean;
 		}
 
-		ret = local_nanddump(file, nanddump[device].args[image].mtd, nanddump[device].args[image].offset, nanddump[device].args[image].length);
+		header = nand_device[device].args[image].header;
+
+		if ( header > 0 ) {
+
+			ret = local_nanddump(file, nand_device[device].args[image].mtd, nand_device[device].args[image].offset, header);
+			if ( ret != 0 ) {
+				if ( ! simulate )
+					unlink(file);
+				ret = -1;
+				goto clean;
+			}
+
+			if ( ! simulate ) {
+
+				fd = open(file, O_RDONLY);
+				if ( fd >= 0 ) {
+					if ( read(fd, buf, 20) == 20 ) {
+						if ( memcmp(buf, "NOLO!img\x02\x00\x00\x00\x00\x00\x00\x00", 16) == 0 )
+							nlen = ((unsigned int)buf[16] << 0) | ((unsigned int)buf[17] << 8) | ((unsigned int)buf[18] << 16) | ((unsigned int)buf[19] << 24);
+						else if ( memcmp(buf, "NOLO img", 8) == 0 )
+							nlen = ((unsigned int)buf[8] << 0) | ((unsigned int)buf[9] << 8) | ((unsigned int)buf[10] << 16) | ((unsigned int)buf[11] << 24);
+					}
+					close(fd);
+					fd = -1;
+				}
+
+				unlink(file);
+
+			}
+
+		}
+
+		ret = local_nanddump(file, nand_device[device].args[image].mtd, nand_device[device].args[image].offset + header, nand_device[device].args[image].length - header);
 
 	}
 
@@ -434,6 +490,9 @@ int local_dump_image(enum image_type image, const char * file) {
 		goto clean;
 	}
 
+	if ( simulate )
+		goto clean;
+
 	fd = open(file, O_RDWR);
 	if ( fd < 0 )
 		goto clean;
@@ -442,31 +501,35 @@ int local_dump_image(enum image_type image, const char * file) {
 	if ( len == (off_t)-1 || len == 0 )
 		goto clean;
 
-	addr = (unsigned char *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+	if ( header <= 0 || nlen == (off_t)-1 ) {
 
-	if ( addr == MAP_FAILED )
-		addr = NULL;
+		addr = (unsigned char *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
 
-	if ( ! addr )
-		goto clean;
+		if ( addr == MAP_FAILED )
+			addr = NULL;
 
-	for ( nlen = len; nlen > 0; --nlen )
-		if ( addr[nlen-1] != 0xFF )
-			break;
+		if ( ! addr )
+			goto clean;
 
-	for ( ; nlen > 0; --nlen )
-		if ( addr[nlen-1] != 0x00 )
-			break;
+		for ( nlen = len; nlen > 0; --nlen )
+			if ( addr[nlen-1] != 0xFF )
+				break;
 
-	if ( image == IMAGE_MMC )
-		align = 8;
-	else
-		align = 7;
+		for ( ; nlen > 0; --nlen )
+			if ( addr[nlen-1] != 0x00 )
+				break;
 
-	if ( ( nlen & ( ( 1ULL << align ) - 1 ) ) != 0 )
-		nlen = ((nlen >> align) + 1) << align;
+		if ( image == IMAGE_MMC )
+			align = 8;
+		else
+			align = 7;
 
-	if ( nlen == 0 ) {
+		if ( ( nlen & ( ( 1ULL << align ) - 1 ) ) != 0 )
+			nlen = ((nlen >> align) + 1) << align;
+
+	}
+
+	if ( header <= 0 && nlen == 0 ) {
 		printf("File %s is empty, removing it...\n", file);
 		unlink(file);
 	} else if ( nlen != len ) {
@@ -487,6 +550,153 @@ clean:
 
 }
 
+int local_flash_image(struct image * image) {
+
+	unsigned char buf[0x20000];
+	unsigned int remaining, size;
+	void (*sighandler)(int);
+	int min, maj, fd;
+	FILE * stream;
+	int ret;
+
+	printf("Flash image:\n");
+	image_print_info(image);
+
+	if ( image->type == IMAGE_MMC ) {
+
+		maj = -1;
+		min = -1;
+
+		local_find_internal_mydocs(&maj, &min);
+		if ( maj == -1 || min == -1 )
+			ERROR_RETURN("Cannot find MyDocs mmc device: Slot 'internal' was not found", -1);
+
+		VERBOSE("Detected internal MyDocs mmc device: major=%d minor=%d\n", maj, min);
+
+		fd = disk_open_dev(maj, min, 1, simulate ? 1 : 0);
+		if ( fd < 0 )
+			ERROR_RETURN("Cannot open MyDocs mmc device in /dev/", -1);
+
+		ret = disk_flash_dev(fd, image);
+
+		close(fd);
+
+	} else {
+
+		if ( device >= sizeof(nand_device)/sizeof(nand_device[0]) )
+			ERROR_RETURN("Unsupported device", -1);
+
+		if ( image->type >= nand_device[device].count ) {
+			ERROR("Unsupported image type: %s", image_type_to_string(image->type));
+			return -1;
+		}
+
+		if ( image->size > nand_device[device].args[image->type].length - nand_device[device].args[image->type].header )
+			ERROR_RETURN("Image is too big", -1);
+
+		printf("Using nandwrite for flashing %s image...\n", image_type_to_string(image->type));
+
+		stream = local_nandwrite(nand_device[device].args[image->type].mtd, nand_device[device].args[image->type].offset);
+		if ( ! simulate && ! stream )
+			ERROR_RETURN("Cannot start nandwrite process", -1);
+
+		ret = 0;
+		sighandler = signal(SIGPIPE, SIG_IGN);
+
+		/* Write NOLO!img or NOLO img header with size */
+		if ( nand_device[device].args[image->type].header > 0 ) {
+			if ( device == DEVICE_RX_51 ) {
+				memcpy(buf, "NOLO!img\x02\x00\x00\x00\x00\x00\x00\x00", 16);
+				buf[16] = (image->size >>  0) & 0xFF;
+				buf[17] = (image->size >>  8) & 0xFF;
+				buf[18] = (image->size >> 16) & 0xFF;
+				buf[19] = (image->size >> 24) & 0xFF;
+				size = 20;
+			} else {
+				memcpy(buf, "NOLO img", 8);
+				buf[ 8] = (image->size >>  0) & 0xFF;
+				buf[ 9] = (image->size >>  8) & 0xFF;
+				buf[10] = (image->size >> 16) & 0xFF;
+				buf[11] = (image->size >> 24) & 0xFF;
+				size = 12;
+			}
+
+			if ( ! simulate ) {
+				if ( fwrite(buf, size, 1, stream) != 1 ) {
+					ret = -1;
+					goto clean;
+				}
+			}
+
+			memset(buf, 0, sizeof(buf));
+			remaining = nand_device[device].args[image->type].header - size;
+			while ( remaining > 0 ) {
+				size = remaining < sizeof(buf) ? remaining : sizeof(buf);
+				if ( ! simulate ) {
+					if ( fwrite(buf, size, 1, stream) != 1 ) {
+						ret = -1;
+						goto clean;
+					}
+				}
+				remaining -= size;
+			}
+		}
+
+		/* Write image data */
+		image_seek(image, 0);
+		remaining = image->size;
+		while ( remaining > 0 ) {
+			size = remaining < sizeof(buf) ? remaining : sizeof(buf);
+			size = image_read(image, buf, size);
+			if ( size == 0 ) {
+				ERROR("Failed to read image");
+				ret = -1;
+				goto clean;
+			}
+			if ( ! simulate ) {
+				if ( fwrite(buf, size, 1, stream) != 1 ) {
+					ret = -1;
+					goto clean;
+				}
+			}
+			remaining -= size;
+		}
+
+		/* Write filler zeros to clear previous data */
+		memset(buf, 0, sizeof(buf));
+		remaining = nand_device[device].args[image->type].length - (image->size + nand_device[device].args[image->type].header);
+		while ( remaining > 0 ) {
+			size = remaining < sizeof(buf) ? remaining : sizeof(buf);
+			if ( ! simulate ) {
+				if ( fwrite(buf, size, 1, stream) != 1 ) {
+					ret = -1;
+					goto clean;
+				}
+			}
+			remaining -= size;
+		}
+
+clean:
+		if ( ! simulate ) {
+			if ( ret == 0 )
+				ret = pclose(stream);
+			else
+				pclose(stream);
+		}
+
+		signal(SIGPIPE, sighandler);
+
+		if ( ret != 0 )
+			ERROR("Flashing failed");
+	}
+
+	if ( ret == 0 )
+		printf("Done\n");
+
+	return ret;
+
+}
+
 int local_check_badblocks(const char * device) {
 
 	ERROR("Not implemented yet");
diff --git a/src/main.c b/src/main.c
index 6c64e6e..5a1cc35 100644
--- a/src/main.c
+++ b/src/main.c
@@ -143,7 +143,7 @@ int simulate;
 int noverify;
 int verbose;
 
-/* arg = [[[dev:[hw:]]ver:]type:]file[%%lay] */
+/* arg = [[[dev:[hw:]]ver:]type:]file[%file2%file3...%lay] */
 static void parse_image_arg(char * arg, struct image_list ** image_first) {
 
 	struct stat st;
@@ -154,14 +154,16 @@ static void parse_image_arg(char * arg, struct image_list ** image_first) {
 	char * hwrevs;
 	char * version;
 	char * layout;
+	char * parts;
 	char * layout_file;
+	char * ptr;
 	int fd;
 
 	/* First check if arg is file, then try to parse arg format */
 	fd = open(arg, O_RDONLY);
 	if ( fd >= 0 ) {
 		if ( fstat(fd, &st) == 0 && !S_ISDIR(st.st_mode) ) {
-			image = image_alloc_from_fd(fd, arg, NULL, NULL, NULL, NULL, NULL);
+			image = image_alloc_from_fd(fd, arg, NULL, NULL, NULL, NULL, NULL, NULL);
 			if ( ! image ) {
 				ERROR("Cannot load image file %s", arg);
 				exit(1);
@@ -175,9 +177,15 @@ static void parse_image_arg(char * arg, struct image_list ** image_first) {
 		exit(1);
 	}
 
-	layout_file = strchr(arg, '%');
-	if ( layout_file )
-		*(layout_file++) = 0;
+	parts = strchr(arg, '%');
+	if ( parts )
+		*(parts++) = 0;
+
+	layout_file = parts;
+	if ( layout_file ) {
+		while ( ( ptr = strchr(layout_file, '%') ) )
+			layout_file = ptr+1;
+	}
 
 	type = NULL;
 	device = NULL;
@@ -237,7 +245,9 @@ static void parse_image_arg(char * arg, struct image_list ** image_first) {
 		close(fd);
 	}
 
-	image = image_alloc_from_file(file, type, device, hwrevs, version, layout);
+	/* TODO: alloc parts */
+
+	image = image_alloc_from_file(file, type, device, hwrevs, version, layout, NULL);
 
 	if ( layout )
 		free(layout);
@@ -426,6 +436,8 @@ int main(int argc, char **argv) {
 	int i;
 	char buf[512];
 	char * ptr = NULL;
+	char * ptr1 = NULL;
+	char * ptr2 = NULL;
 	char * tmp = NULL;
 
 	char nolo_ver[512];
@@ -1036,9 +1048,9 @@ int main(int argc, char **argv) {
 			/* filter images by device & hwrev */
 			if ( detected_device )
 				filter_images_by_device(dev->detected_device, &image_first);
-			if ( detected_hwrev )
+			if ( detected_hwrev > 0 )
 				filter_images_by_hwrev(dev->detected_hwrev, &image_first);
-			if ( fiasco_in && ( detected_device || detected_hwrev ) )
+			if ( fiasco_in && ( detected_device || detected_hwrev > 0 ) )
 				fiasco_in->first = image_first;
 
 			/* set kernel and initfs images for loading */
@@ -1096,7 +1108,7 @@ int main(int argc, char **argv) {
 			if ( dev_load ) {
 				if ( image_kernel ) {
 					ret = dev_load_image(dev, image_kernel->image);
-					if ( ret < 0 )
+					if ( ret == -EAGAIN )
 						goto again;
 
 					if ( image_kernel == image_first )
@@ -1110,7 +1122,7 @@ int main(int argc, char **argv) {
 
 				if ( image_initfs ) {
 					ret = dev_load_image(dev, image_initfs->image);
-					if ( ret < 0 )
+					if ( ret == -EAGAIN )
 						goto again;
 
 					if ( image_initfs == image_first )
@@ -1129,7 +1141,7 @@ int main(int argc, char **argv) {
 				while ( image_ptr ) {
 					struct image_list * next = image_ptr->next;
 					ret = dev_flash_image(dev, image_ptr->image);
-					if ( ret < 0 )
+					if ( ret == -EAGAIN )
 						goto again;
 
 					if ( image_ptr == image_first )
@@ -1265,7 +1277,8 @@ int main(int argc, char **argv) {
 						continue;
 
 					buf[0] = 0;
-					snprintf(buf, sizeof(buf), "%hd", dev->detected_hwrev);
+					if ( dev->detected_hwrev > 0 )
+						snprintf(buf, sizeof(buf), "%hd", dev->detected_hwrev);
 
 					switch ( i ) {
 						case IMAGE_2ND:
@@ -1295,7 +1308,9 @@ int main(int argc, char **argv) {
 							break;
 					}
 
-					image_dump = image_alloc_from_file(image_tmp_name(i), image_type_to_string(i), device_to_string(dev->detected_device), buf, ptr, NULL);
+					/* TODO: add support for dumping mmc layout and also other mmc partitions as image data parts */
+
+					image_dump = image_alloc_from_file(image_tmp_name(i), image_type_to_string(i), device_to_string(dev->detected_device), buf, ptr, NULL, NULL);
 
 					if ( ! image_dump )
 						continue;
@@ -1366,7 +1381,20 @@ int main(int argc, char **argv) {
 					}
 
 					buf[0] = 0;
-					snprintf(buf, sizeof(buf), "%s-%s:%hd_%s", image_type_to_string(i), device_to_string(dev->detected_device), dev->detected_hwrev, ptr);
+					snprintf(buf, sizeof(buf), "%s", image_type_to_string(i));
+					ptr1 = buf + strlen(buf);
+
+					if ( dev->detected_device ) {
+						snprintf(ptr1, sizeof(buf)-(ptr1-buf), "-%s", device_to_string(dev->detected_device));
+						ptr1 += strlen(ptr1);
+					}
+
+					if ( dev->detected_hwrev > 0 )
+						snprintf(ptr1, sizeof(buf)-(ptr1-buf), ":%hd", dev->detected_hwrev);
+					ptr2 = ptr1 + strlen(ptr1);
+
+					if ( ptr && ptr[0] )
+						snprintf(ptr2, sizeof(buf)-(ptr2-buf), "_%s", ptr);
 
 					rename_ret = rename(image_tmp_name(i), buf);
 					rename_errno = errno;
@@ -1381,13 +1409,21 @@ int main(int argc, char **argv) {
 						errno = rename_errno;
 						ERROR_INFO("Renaming failed");
 
-						buf[0] = 0;
-						snprintf(buf, sizeof(buf), "%s-%s_%s", image_type_to_string(i), device_to_string(dev->detected_device), ptr);
+						*ptr2 = 0;
 						printf("Trying to rename %s image file to %s...\n", image_type_to_string(i), buf);
 
-						if ( rename(image_tmp_name(i), buf) < 0 )
+						if ( rename(image_tmp_name(i), buf) < 0 ) {
+
 							ERROR_INFO("Renaming failed");
 
+							*ptr1 = 0;
+							printf("Trying to rename %s image file to %s...\n", image_type_to_string(i), buf);
+
+							if ( rename(image_tmp_name(i), buf) < 0 )
+								ERROR_INFO("Renaming failed");
+
+						}
+
 					}
 
 				}
diff --git a/src/mkii.c b/src/mkii.c
index e50637e..51045f6 100644
--- a/src/mkii.c
+++ b/src/mkii.c
@@ -213,14 +213,18 @@ int mkii_flash_image(struct usb_device_info * dev, struct image * image) {
 	msg1 = (struct mkii_message *)buf1;
 	ptr = msg->data;
 
-	/* Signature */
-	memcpy(ptr, "\x2E\x19\x01\x01", 4);
-	ptr += 4;
+	/* File data header */
+	memcpy(ptr, "\x2E", 1);
+	ptr += 1;
 
-	/* Space */
-	memcpy(ptr, "\x00", 1);
+	/* Length of file data */
+	memcpy(ptr, "\x19", 1);
 	ptr += 1;
 
+	/* File data (ignored): asic index: APE (0x01), device type: NAND (0x01), device index: 0 */
+	memcpy(ptr, "\x01\x01\x00", 3);
+	ptr += 3;
+
 	/* Hash */
 	hash = htons(image->hash);
 	memcpy(ptr, &hash, 2);
@@ -239,7 +243,7 @@ int mkii_flash_image(struct usb_device_info * dev, struct image * image) {
 	memcpy(ptr, &size, 4);
 	ptr += 4;
 
-	/* Space */
+	/* Load address (ignored) */
 	memcpy(ptr, "\x00\x00\x00\x00", 4);
 	ptr += 4;
 
diff --git a/src/nolo.c b/src/nolo.c
index c30eb77..0684145 100644
--- a/src/nolo.c
+++ b/src/nolo.c
@@ -269,14 +269,18 @@ static int nolo_send_image(struct usb_device_info * dev, struct image * image, i
 
 	ptr = buf;
 
-	/* Signature */
-	memcpy(ptr, "\x2E\x19\x01\x01", 4);
-	ptr += 4;
+	/* File data header */
+	memcpy(ptr, "\x2E", 1);
+	ptr += 1;
 
-	/* Space */
-	memcpy(ptr, "\x00", 1);
+	/* Length of file data */
+	memcpy(ptr, "\x19", 1);
 	ptr += 1;
 
+	/* File data (ignored by NOLO): asic index: APE (0x01), device type: NAND (0x01), device index: 0 */
+	memcpy(ptr, "\x01\x01\x00", 3);
+	ptr += 3;
+
 	/* Hash */
 	hash = htons(image->hash);
 	memcpy(ptr, &hash, 2);
@@ -295,7 +299,7 @@ static int nolo_send_image(struct usb_device_info * dev, struct image * image, i
 	memcpy(ptr, &size, 4);
 	ptr += 4;
 
-	/* Space */
+	/* Load address (ignored by NOLO) */
 	memcpy(ptr, "\x00\x00\x00\x00", 4);
 	ptr += 4;
 

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/debug/.build-id/06/900790009b4eb14bc7ff2041a3c10ee300f6a2.debug

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/debug/.build-id/e3/332ae3f9be3169c1dd288a972abee02bba5e12.debug

Control files of package 0xffff: lines which differ (wdiff format)

  • Depends: libc6 (>= 2.34), 2.33), libusb-0.1-4 (>= 2:0.1.12)

Control files of package 0xffff-dbgsym: lines which differ (wdiff format)

  • Build-Ids: e3332ae3f9be3169c1dd288a972abee02bba5e12 06900790009b4eb14bc7ff2041a3c10ee300f6a2

More details

Full run details