comparison 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
comparison
equal deleted inserted replaced
8:99ae5bf8cab5 9:1fb47f5b597a
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 = 0xFF;
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 }