changeset 215:d69f7512e3c1

Pirelli: documented and verified the checksum scheme used for the factory block
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 25 Dec 2016 23:48:16 +0000
parents 6b40617d00e6
children 4b97cf9a90f0
files .hgignore miscprog/Makefile miscprog/pircksum2.c pirelli/flash2-chksum
diffstat 4 files changed, 152 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Jul 26 23:32:17 2016 +0000
+++ b/.hgignore	Sun Dec 25 23:48:16 2016 +0000
@@ -34,6 +34,7 @@
 ^miscprog/memwrite-grep$
 ^miscprog/mokosrec2bin$
 ^miscprog/pircksum$
+^miscprog/pircksum2$
 ^miscprog/pirimei$
 ^miscprog/rfcap-grep$
 
--- a/miscprog/Makefile	Tue Jul 26 23:32:17 2016 +0000
+++ b/miscprog/Makefile	Sun Dec 25 23:48:16 2016 +0000
@@ -1,7 +1,7 @@
 CC=	gcc
 CFLAGS=	-O2
 STD=	atsc calextract factdiff grokdsn memwrite-grep mokosrec2bin pircksum \
-	rfcap-grep
+	pircksum2 rfcap-grep
 CRYPTO=	imeibrute pirimei
 PROGS=	${STD} ${CRYPTO}
 
@@ -21,6 +21,7 @@
 memwrite-grep:	memwrite-grep.c
 mokosrec2bin:	mokosrec2bin.c
 pircksum:	pircksum.c
+pircksum2:	pircksum2.c
 pirimei:	pirimei.c
 rfcap-grep:	rfcap-grep.c
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/miscprog/pircksum2.c	Sun Dec 25 23:48:16 2016 +0000
@@ -0,0 +1,116 @@
+/*
+ * This program verifies the correctness of the understanding described in the
+ * ../pirelli/flash2-chksum write-up.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <endian.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+char *image_filename;
+u_char *image_map, *endrec;
+unsigned imgsize, max_imgsize;
+
+open_and_map_file()
+{
+	int fd;
+	struct stat st;
+
+	fd = open(image_filename, O_RDONLY);
+	if (fd < 0) {
+		perror(image_filename);
+		exit(1);
+	}
+	fstat(fd, &st);
+	if (!S_ISREG(st.st_mode)) {
+		fprintf(stderr, "error: %s is not a regular file\n",
+			image_filename);
+		exit(1);
+	}
+	if (st.st_size != 0x10000 && st.st_size != 0x360000) {
+		fprintf(stderr, "error: %s has an unexpected size\n",
+			image_filename);
+		exit(1);
+	}
+	max_imgsize = st.st_size - 12;
+	image_map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (image_map == MAP_FAILED) {
+		perror("mmap");
+		exit(1);
+	}
+	close(fd);
+	endrec = image_map + max_imgsize;
+	return 0;
+}
+
+verify_chksum1()
+{
+	uint16_t sum, ref;
+	unsigned offset;
+
+	sum = 0;
+	for (offset = 0; offset + 1 < imgsize; offset += 2)
+		sum += le16toh(*(uint16_t *)(image_map + offset));
+	if (imgsize & 1)
+		sum += image_map[offset];
+	ref = le16toh(*(uint16_t *)(endrec + 8));
+	if (sum == ref) {
+		printf("Checksum 1 matches (%04X)\n", sum);
+		return 0;
+	} else {
+		printf("Checksum 1 FAILED: computed %04X, stored %04X\n",
+			sum, ref);
+		return 1;
+	}
+}
+
+verify_chksum2()
+{
+	uint16_t sum, ref;
+	unsigned offset;
+
+	sum = 0;
+	for (offset = 0; offset < 10; offset += 2)
+		sum += le16toh(*(uint16_t *)(endrec + offset));
+	ref = le16toh(*(uint16_t *)(endrec + 10));
+	if (sum == ref) {
+		printf("Checksum 2 matches (%04X)\n", sum);
+		return 0;
+	} else {
+		printf("Checksum 2 FAILED: computed %04X, stored %04X\n",
+			sum, ref);
+		return 1;
+	}
+}
+
+main(argc, argv)
+	char **argv;
+{
+	int stat1, stat2;
+
+	if (argc != 2) {
+		fprintf(stderr, "usage: %s image-filename\n", argv[0]);
+		exit(1);
+	}
+	image_filename = argv[1];
+	open_and_map_file();
+	if (le32toh(*(uint32_t *)endrec) != 0x12345678) {
+		printf("Error: 0x12345678 signature missing\n");
+		exit(1);
+	}
+	imgsize = le32toh(*(uint32_t *)(endrec + 4));
+	if (imgsize < 1 || imgsize > max_imgsize) {
+		printf("Error: bogus image size of 0x%x bytes\n", imgsize);
+		exit(1);
+	}
+	printf("Image size: 0x%x bytes\n", imgsize);
+	stat1 = verify_chksum1();
+	stat2 = verify_chksum2();
+	exit(stat1 || stat2);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pirelli/flash2-chksum	Sun Dec 25 23:48:16 2016 +0000
@@ -0,0 +1,33 @@
+Pirelli's flash usage scheme allocates 3 "magic" areas in the flash2 bank:
+
+offset 0x480000 thru 0x7DFFFF: staging area for high-level fw updates
+offset 0x7E0000 thru 0x7EFFFF: fw update control/state structure
+offset 0x7F0000 thru 0x7FFFFF: factory record with IMEI and RF calibration
+
+The image or record stored in each of these "magic" areas ends with the
+following 12-byte signature and checksum structure:
+
+Offset[1]	Type[2]		Contains
+xxFFF4		32-bit word	0x12345678
+xxFFF8		32-bit word	Length of the fw update image or factory or
+				fw update state record
+xxFFFC		16-bit word	Checksum 1
+xxFFFE		16-bit word	Checksum 2
+
+[1] The offset is from the beginning of the flash partition in question, the
+    xx digits will be 35 in the case of the 0x360000 byte fw update staging
+    area partition or 00 in the case of the two 64 KiB sectors.
+
+[2] All 16-bit and 32-bit values are in little-endian byte order.
+
+Checksum computation
+====================
+
+The checksum is computed in two stages.  First all 16-bit words in the main
+body of the image (using the image length from the xxFFF8 word) are added
+together as a ripple-carry sum, and this 16-bit sum is written into the 0xFFFC
+word.  Then the 5 16-bit words from xxFFF4 through xxFFFC (inclusive) are added
+together (again as a ripple-carry sum), and this sum is written into the xxFFFE
+word.  Remember the little-endian byte order throughout!
+
+The ../miscprog/pircksum2.c program verifies this checksum computation scheme.