FreeCalypso > hg > fc-tourmaline
diff helpers/mokosrec2bin.c @ 9:1fb47f5b597a
helpers: import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 07:01:13 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/helpers/mokosrec2bin.c Fri Oct 16 07:01:13 2020 +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 = 0xFF; + + 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(); + } + } +}