diff miscutil/mokosrec2bin.c @ 412:a5dab452be0d

mokosrec2bin utility imported from the old freecalypso-reveng tree, header comments changed for new understanding and new usage in forward rather than reverse engineering
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 25 Oct 2018 19:23:35 +0000
parents
children d00ffedacab5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/miscutil/mokosrec2bin.c	Thu Oct 25 19:23:35 2018 +0000
@@ -0,0 +1,231 @@
+/*
+ * GSM device firmwares that are built with TI's TMS470 toolchain in TI's
+ * canonical way come out in TI's *.m0 format produced by TI's hex470 tool.
+ * TI's *.m0 is a variant of the classic S-record format from Motorola,
+ * but the specific variant depends on the -memwidth and -romwidth options
+ * with which the hex470 tool is run.
+ *
+ * In TI's canonical architecture (as opposed to Mot/Compal's heavily modified
+ * version) this hex470 tool is run with -memwidth 16 -romwidth 16 options,
+ * and the *.m0 file comes out in the format variant which we have nicknamed
+ * "moko-style" after its most famous user.  This variant is a byte-reversed
+ * S-record format in that each 16-bit word is byte-reversed relative to the
+ * native byte order of the ARM7 processor.  (This strange byte order actually
+ * makes some sense if one views the image as a long array of 16-bit hex
+ * values; 16 bits is the width of the flash memory on Calypso GSM devices and
+ * thus the natural unit size for flash programming.)
+ *
+ * The present mokosrec2bin utility converts these "moko-style" S-record files
+ * to straight binary, a conversion that includes flipping the order of bytes.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+
+char *infname;
+FILE *inf, *outf;
+u_char fillbyte;
+char srecbuf[80];
+u_char srecbin[40];
+int lineno, state;
+u_long lastaddr;
+
+u_char header[6] = {0x06, 0x00, 0x00, 'H', 'D', 'R'};
+
+decode_hex_byte(s)
+	char *s;
+{
+	register int u, l;
+
+	if (!isxdigit(s[0]) || !isxdigit(s[1]))
+		return(-1);
+	if (isdigit(s[0]))
+		u = s[0] - '0';
+	else if (isupper(s[0]))
+		u = s[0] - 'A' + 10;
+	else
+		u = s[0] - 'a' + 10;
+	if (isdigit(s[1]))
+		l = s[1] - '0';
+	else if (isupper(s[1]))
+		l = s[1] - 'A' + 10;
+	else
+		l = s[1] - 'a' + 10;
+	return((u << 4) | l);
+}
+
+srec2bin()
+{
+	register int i, l, b;
+
+	l = decode_hex_byte(srecbuf + 2);
+	if (l < 1) {
+		fprintf(stderr, "%s line %d: S-record length octet is bad\n",
+			infname, lineno);
+		exit(1);
+	}
+	srecbin[0] = l;
+	if (l > 35) {
+		fprintf(stderr,
+			"%s line %d: S-record is longer than expected\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (i = 1; i <= l; i++) {
+		b = decode_hex_byte(srecbuf + i*2 + 2);
+		if (b < 0) {
+			fprintf(stderr, "%s line %d: hex decode error\n",
+				infname, lineno);
+			exit(1);
+		}
+		srecbin[i] = b;
+	}
+	return(0);
+}
+
+srec_cksum()
+{
+	u_char accum;
+	register int i, len;
+
+	len = srecbin[0] + 1;
+	accum = 0;
+	for (i = 0; i < len; i++)
+		accum += srecbin[i];
+	if (accum != 0xFF) {
+		fprintf(stderr, "%s line %d: bad checksum\n", infname, lineno);
+		exit(1);
+	}
+	return(0);
+}
+
+main(argc, argv)
+	char **argv;
+{
+	register int i;
+	u_long curaddr;
+	int datalen;
+
+	if (argc < 3 || argc > 4) {
+usage:		fprintf(stderr, "usage: %s input.m0 output.bin [fill-byte]\n",
+			argv[0]);
+		exit(1);
+	}
+	infname = argv[1];
+	inf = fopen(infname, "r");
+	if (!inf) {
+		perror(infname);
+		exit(1);
+	}
+	if (argc > 3) {
+		i = decode_hex_byte(argv[3]);
+		if (i >= 0)
+			fillbyte = i;
+		else
+			goto usage;
+	} else
+		fillbyte = 0;
+
+	state = 0;
+	for (lineno = 1; ; lineno++) {
+		if (!fgets(srecbuf, sizeof srecbuf, inf)) {
+			fprintf(stderr, "%s: premature EOF\n", infname);
+			exit(1);
+		}
+		if (srecbuf[0] != 'S') {
+			fprintf(stderr, "%s line %d: not an S-record\n",
+				infname, lineno);
+			exit(1);
+		}
+		switch (srecbuf[1]) {
+		case '0':
+			if (state == 0)
+				break;
+			else
+				goto badtype;
+		case '3':
+			if (state == 0)
+				goto badtype;
+			else
+				break;
+		case '7':
+			if (state == 2)
+				break;
+			else
+				goto badtype;
+		default:
+		badtype:
+			fprintf(stderr,
+				"%s line %d: S-record type unexpected\n",
+				infname, lineno);
+			exit(1);
+		}
+		srec2bin();
+		srec_cksum();
+		if (state == 0) {
+			if (bcmp(srecbin, header, 6)) {
+				fprintf(stderr, "%s: expected header missing\n",
+					infname);
+				exit(1);
+			}
+			state = 1;
+			continue;
+		}
+		switch (srecbuf[1]) {
+		case '3':
+			if (srecbin[0] < 6) {
+				fprintf(stderr,
+					"%s line %d: S3 record is too short\n",
+					infname, lineno);
+				exit(1);
+			}
+			curaddr = (srecbin[1] << 24) | (srecbin[2] << 16) |
+				  (srecbin[3] << 8) | srecbin[4];
+			if (curaddr & 1) {
+				fprintf(stderr, "%s line %d: odd address\n",
+					infname, lineno);
+				exit(1);
+			}
+			datalen = srecbin[0] - 5;
+			if (datalen & 1) {
+				fprintf(stderr, "%s line %d: odd data length\n",
+					infname, lineno);
+				exit(1);
+			}
+			if (state < 2) {
+				outf = fopen(argv[2], "w");
+				if (!outf) {
+					perror(argv[2]);
+					exit(1);
+				}
+				state = 2;
+				lastaddr = 0;
+			}
+			if (curaddr < lastaddr) {
+				fprintf(stderr,
+					"%s line %d: address going backwards\n",
+					infname, lineno);
+				exit(1);
+			}
+			while (lastaddr < curaddr) {
+				putc(fillbyte, outf);
+				lastaddr++;
+			}
+			for (i = 0; i < datalen; i += 2) {
+				putc(srecbin[i + 6], outf);
+				putc(srecbin[i + 5], outf);
+			}
+			lastaddr = curaddr + datalen;
+			continue;
+		case '7':
+			fclose(outf);
+			exit(0);
+		default:
+			abort();
+		}
+	}
+}