FreeCalypso > hg > freecalypso-tools
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 411:8b8e723f5699 | 412:a5dab452be0d |
|---|---|
| 1 /* | |
| 2 * GSM device firmwares that are built with TI's TMS470 toolchain in TI's | |
| 3 * canonical way come out in TI's *.m0 format produced by TI's hex470 tool. | |
| 4 * TI's *.m0 is a variant of the classic S-record format from Motorola, | |
| 5 * but the specific variant depends on the -memwidth and -romwidth options | |
| 6 * with which the hex470 tool is run. | |
| 7 * | |
| 8 * In TI's canonical architecture (as opposed to Mot/Compal's heavily modified | |
| 9 * version) this hex470 tool is run with -memwidth 16 -romwidth 16 options, | |
| 10 * and the *.m0 file comes out in the format variant which we have nicknamed | |
| 11 * "moko-style" after its most famous user. This variant is a byte-reversed | |
| 12 * S-record format in that each 16-bit word is byte-reversed relative to the | |
| 13 * native byte order of the ARM7 processor. (This strange byte order actually | |
| 14 * makes some sense if one views the image as a long array of 16-bit hex | |
| 15 * values; 16 bits is the width of the flash memory on Calypso GSM devices and | |
| 16 * thus the natural unit size for flash programming.) | |
| 17 * | |
| 18 * The present mokosrec2bin utility converts these "moko-style" S-record files | |
| 19 * to straight binary, a conversion that includes flipping the order of bytes. | |
| 20 */ | |
| 21 | |
| 22 #include <sys/types.h> | |
| 23 #include <stdio.h> | |
| 24 #include <ctype.h> | |
| 25 #include <string.h> | |
| 26 #include <strings.h> | |
| 27 #include <stdlib.h> | |
| 28 | |
| 29 char *infname; | |
| 30 FILE *inf, *outf; | |
| 31 u_char fillbyte; | |
| 32 char srecbuf[80]; | |
| 33 u_char srecbin[40]; | |
| 34 int lineno, state; | |
| 35 u_long lastaddr; | |
| 36 | |
| 37 u_char header[6] = {0x06, 0x00, 0x00, 'H', 'D', 'R'}; | |
| 38 | |
| 39 decode_hex_byte(s) | |
| 40 char *s; | |
| 41 { | |
| 42 register int u, l; | |
| 43 | |
| 44 if (!isxdigit(s[0]) || !isxdigit(s[1])) | |
| 45 return(-1); | |
| 46 if (isdigit(s[0])) | |
| 47 u = s[0] - '0'; | |
| 48 else if (isupper(s[0])) | |
| 49 u = s[0] - 'A' + 10; | |
| 50 else | |
| 51 u = s[0] - 'a' + 10; | |
| 52 if (isdigit(s[1])) | |
| 53 l = s[1] - '0'; | |
| 54 else if (isupper(s[1])) | |
| 55 l = s[1] - 'A' + 10; | |
| 56 else | |
| 57 l = s[1] - 'a' + 10; | |
| 58 return((u << 4) | l); | |
| 59 } | |
| 60 | |
| 61 srec2bin() | |
| 62 { | |
| 63 register int i, l, b; | |
| 64 | |
| 65 l = decode_hex_byte(srecbuf + 2); | |
| 66 if (l < 1) { | |
| 67 fprintf(stderr, "%s line %d: S-record length octet is bad\n", | |
| 68 infname, lineno); | |
| 69 exit(1); | |
| 70 } | |
| 71 srecbin[0] = l; | |
| 72 if (l > 35) { | |
| 73 fprintf(stderr, | |
| 74 "%s line %d: S-record is longer than expected\n", | |
| 75 infname, lineno); | |
| 76 exit(1); | |
| 77 } | |
| 78 for (i = 1; i <= l; i++) { | |
| 79 b = decode_hex_byte(srecbuf + i*2 + 2); | |
| 80 if (b < 0) { | |
| 81 fprintf(stderr, "%s line %d: hex decode error\n", | |
| 82 infname, lineno); | |
| 83 exit(1); | |
| 84 } | |
| 85 srecbin[i] = b; | |
| 86 } | |
| 87 return(0); | |
| 88 } | |
| 89 | |
| 90 srec_cksum() | |
| 91 { | |
| 92 u_char accum; | |
| 93 register int i, len; | |
| 94 | |
| 95 len = srecbin[0] + 1; | |
| 96 accum = 0; | |
| 97 for (i = 0; i < len; i++) | |
| 98 accum += srecbin[i]; | |
| 99 if (accum != 0xFF) { | |
| 100 fprintf(stderr, "%s line %d: bad checksum\n", infname, lineno); | |
| 101 exit(1); | |
| 102 } | |
| 103 return(0); | |
| 104 } | |
| 105 | |
| 106 main(argc, argv) | |
| 107 char **argv; | |
| 108 { | |
| 109 register int i; | |
| 110 u_long curaddr; | |
| 111 int datalen; | |
| 112 | |
| 113 if (argc < 3 || argc > 4) { | |
| 114 usage: fprintf(stderr, "usage: %s input.m0 output.bin [fill-byte]\n", | |
| 115 argv[0]); | |
| 116 exit(1); | |
| 117 } | |
| 118 infname = argv[1]; | |
| 119 inf = fopen(infname, "r"); | |
| 120 if (!inf) { | |
| 121 perror(infname); | |
| 122 exit(1); | |
| 123 } | |
| 124 if (argc > 3) { | |
| 125 i = decode_hex_byte(argv[3]); | |
| 126 if (i >= 0) | |
| 127 fillbyte = i; | |
| 128 else | |
| 129 goto usage; | |
| 130 } else | |
| 131 fillbyte = 0; | |
| 132 | |
| 133 state = 0; | |
| 134 for (lineno = 1; ; lineno++) { | |
| 135 if (!fgets(srecbuf, sizeof srecbuf, inf)) { | |
| 136 fprintf(stderr, "%s: premature EOF\n", infname); | |
| 137 exit(1); | |
| 138 } | |
| 139 if (srecbuf[0] != 'S') { | |
| 140 fprintf(stderr, "%s line %d: not an S-record\n", | |
| 141 infname, lineno); | |
| 142 exit(1); | |
| 143 } | |
| 144 switch (srecbuf[1]) { | |
| 145 case '0': | |
| 146 if (state == 0) | |
| 147 break; | |
| 148 else | |
| 149 goto badtype; | |
| 150 case '3': | |
| 151 if (state == 0) | |
| 152 goto badtype; | |
| 153 else | |
| 154 break; | |
| 155 case '7': | |
| 156 if (state == 2) | |
| 157 break; | |
| 158 else | |
| 159 goto badtype; | |
| 160 default: | |
| 161 badtype: | |
| 162 fprintf(stderr, | |
| 163 "%s line %d: S-record type unexpected\n", | |
| 164 infname, lineno); | |
| 165 exit(1); | |
| 166 } | |
| 167 srec2bin(); | |
| 168 srec_cksum(); | |
| 169 if (state == 0) { | |
| 170 if (bcmp(srecbin, header, 6)) { | |
| 171 fprintf(stderr, "%s: expected header missing\n", | |
| 172 infname); | |
| 173 exit(1); | |
| 174 } | |
| 175 state = 1; | |
| 176 continue; | |
| 177 } | |
| 178 switch (srecbuf[1]) { | |
| 179 case '3': | |
| 180 if (srecbin[0] < 6) { | |
| 181 fprintf(stderr, | |
| 182 "%s line %d: S3 record is too short\n", | |
| 183 infname, lineno); | |
| 184 exit(1); | |
| 185 } | |
| 186 curaddr = (srecbin[1] << 24) | (srecbin[2] << 16) | | |
| 187 (srecbin[3] << 8) | srecbin[4]; | |
| 188 if (curaddr & 1) { | |
| 189 fprintf(stderr, "%s line %d: odd address\n", | |
| 190 infname, lineno); | |
| 191 exit(1); | |
| 192 } | |
| 193 datalen = srecbin[0] - 5; | |
| 194 if (datalen & 1) { | |
| 195 fprintf(stderr, "%s line %d: odd data length\n", | |
| 196 infname, lineno); | |
| 197 exit(1); | |
| 198 } | |
| 199 if (state < 2) { | |
| 200 outf = fopen(argv[2], "w"); | |
| 201 if (!outf) { | |
| 202 perror(argv[2]); | |
| 203 exit(1); | |
| 204 } | |
| 205 state = 2; | |
| 206 lastaddr = 0; | |
| 207 } | |
| 208 if (curaddr < lastaddr) { | |
| 209 fprintf(stderr, | |
| 210 "%s line %d: address going backwards\n", | |
| 211 infname, lineno); | |
| 212 exit(1); | |
| 213 } | |
| 214 while (lastaddr < curaddr) { | |
| 215 putc(fillbyte, outf); | |
| 216 lastaddr++; | |
| 217 } | |
| 218 for (i = 0; i < datalen; i += 2) { | |
| 219 putc(srecbin[i + 6], outf); | |
| 220 putc(srecbin[i + 5], outf); | |
| 221 } | |
| 222 lastaddr = curaddr + datalen; | |
| 223 continue; | |
| 224 case '7': | |
| 225 fclose(outf); | |
| 226 exit(0); | |
| 227 default: | |
| 228 abort(); | |
| 229 } | |
| 230 } | |
| 231 } |
