FreeCalypso > hg > freecalypso-reveng
view mokosrec2bin.c @ 0:cb736d95338d
mokosrec2bin utility written
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Mon, 15 Apr 2013 02:19:54 +0000 |
parents | |
children |
line wrap: on
line source
/* * The *.m0 format in which the Closedmoko firmware images have been * distributed is a form of SREC, but further examination quickly * reveals that the data bytes are swapped: the byte order is neither * the natural little-endian ARM one of the Calypso, nor a word-wise * ARM BE; instead the upper and lower bytes of each 16-bit shortword * are swapped relative to the natural byte/word order of the Calypso * ARM processor. * * Before this Closedmoko firmware can be examined with any of the * standard reverse eng tools (ARM disassemblers or even the good old * strings), it needs to be converted from the weird byte-swapped SREC * format to straight binary in the natural byte order. The present * utility accomplishes that conversion. * * Written by Spacefalcon the Outlaw. */ #include <sys/types.h> #include <stdio.h> #include <ctype.h> #include <strings.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(); } } }