GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / main / cfe_ldr_srec.c
blobf43685e2d85ad364654ba012cf7836c0a4582944
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * SREC Program Loader File: cfe_ldr_srec.c
5 *
6 * This program reads Motorola S-record files into memory
7 *
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
9 *
10 *********************************************************************
12 * Copyright 2000,2001,2002,2003
13 * Broadcom Corporation. All rights reserved.
15 * This software is furnished under license and may be used and
16 * copied only in accordance with the following terms and
17 * conditions. Subject to these conditions, you may download,
18 * copy, install, use, modify and distribute modified or unmodified
19 * copies of this software in source and/or binary form. No title
20 * or ownership is transferred hereby.
22 * 1) Any source code used, modified or distributed must reproduce
23 * and retain this copyright notice and list of conditions
24 * as they appear in the source file.
26 * 2) No right is granted to use any trade name, trademark, or
27 * logo of Broadcom Corporation. The "Broadcom Corporation"
28 * name may not be used to endorse or promote products derived
29 * from this software without the prior written permission of
30 * Broadcom Corporation.
32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44 * THE POSSIBILITY OF SUCH DAMAGE.
45 ********************************************************************* */
46 #ifdef CFG_LDR_SREC
48 #include "lib_types.h"
49 #include "lib_string.h"
50 #include "lib_queue.h"
51 #include "lib_malloc.h"
52 #include "lib_printf.h"
54 #include "cfe_iocb.h"
55 #include "cfe_device.h"
56 #include "cfe_error.h"
57 #include "cfe_devfuncs.h"
59 #include "cfe.h"
60 #include "cfe_fileops.h"
62 #include "cfe_boot.h"
63 #include "cfe_bootblock.h"
65 #include "cfe_loader.h"
67 #include "cfe_mem.h"
69 /* *********************************************************************
70 * Externs
71 ********************************************************************* */
73 static int cfe_srecload(cfe_loadargs_t *la);
75 const cfe_loader_t srecloader = {
76 "srec",
77 cfe_srecload,
78 0};
81 typedef struct linebuf_s {
82 char linebuf[256];
83 int curidx;
84 int buflen;
85 int eof;
86 void *ref;
87 fileio_ctx_t *fsctx;
88 } linebuf_t;
90 #define initlinebuf(b,r,o) (b)->curidx = 0; (b)->buflen = 0; \
91 (b)->eof = 0 ; (b)->ref = r; (b)->fsctx = o
94 /* *********************************************************************
95 * readchar(file)
97 * Read a character from a file. It's kind of like getchar
98 * on "C" FILE devices, but not so fancy.
100 * Input parameters:
101 * file - pointer to a linebuf_t containing reader state
103 * Return value:
104 * character, or -1 if at EOF
105 ********************************************************************* */
107 static int readchar(linebuf_t *file)
109 int ch;
110 int res;
112 if (file->eof) return -1;
114 if (file->curidx == file->buflen) {
115 for (;;) {
116 res = fs_read(file->fsctx,file->ref,(unsigned char *)file->linebuf,sizeof(file->linebuf));
117 if (res < 0) {
118 file->eof = -1;
119 return -1;
121 if (res == 0) continue;
122 file->buflen = res;
123 file->curidx = 0;
124 break;
128 ch = file->linebuf[file->curidx];
129 file->curidx++;
130 return ch;
134 /* *********************************************************************
135 * readline(file,buffer,maxlen)
137 * Read a line of text from a file using our crude file stream
138 * mechanism.
140 * Input parameters:
141 * file - pointer to a linebuf_t containing reader state
142 * buffer - will receive line of text
143 * maxlen - number of bytes that will fit in buffer
145 * Return value:
146 * 0 if ok, else <0 if at EOF
147 ********************************************************************* */
149 static int readline(linebuf_t *file,char *buffer,int maxlen)
151 int ch;
152 char *ptr;
154 ptr = buffer;
155 maxlen--; /* account for terminating null */
157 while (maxlen) {
158 ch = readchar(file);
159 if (ch == -1) return -1;
160 if (ch == 27) return -1; /* ESC */
161 if ((ch == '\n') || (ch == '\r')) break;
162 *ptr++ = (char) ch;
163 maxlen--;
166 *ptr = '\0';
168 return 0;
172 /* *********************************************************************
173 * getxdigit(c)
175 * Convert a hex digit into its numeric equivalent
177 * Input parameters:
178 * c - character
180 * Return value:
181 * value
182 ********************************************************************* */
184 static int getxdigit(char c)
186 if ((c >= '0') && (c <= '9')) return c - '0';
187 if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
188 if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10;
189 return -1;
192 /* *********************************************************************
193 * getbyte(line)
195 * Process two hex digits and return the value
197 * Input parameters:
198 * line - pointer to pointer to characters (updated on exit)
200 * Return value:
201 * byte value, or <0 if bad hex digits
202 ********************************************************************* */
204 static int getbyte(char **line)
206 int res;
207 int c1,c2;
209 c1 = getxdigit(*(*(line)+0));
210 if (c1 < 0) return -1;
212 c2 = getxdigit(*(*(line)+1));
213 if (c2 < 0) return -1;
215 res = (c1*16+c2);
216 (*line) += 2;
218 return res;
222 /* *********************************************************************
223 * procsrec(line,loadaddr,blklen,data)
225 * Process an S-record, reading the data into a local buffer
226 * and returning the block's address.
228 * Input parameters:
229 * line - line of text (s-record line)
230 * loadaddr - will be filled with address where data should go
231 * blklen - will be filled in with size of record
232 * data - points to buffer to receive data
234 * Return value:
235 * <0 if error occured (not an s-record)
236 ********************************************************************* */
238 static int procsrec(char *line,
239 unsigned int *loadaddr,
240 unsigned int *blklen,
241 unsigned char *data)
243 char rectype;
244 unsigned char b;
245 unsigned int len;
246 unsigned int minlen;
247 unsigned int linelen;
248 unsigned int addr;
249 unsigned int chksum;
251 int idx;
252 int ret = 0;
254 addr = 0;
256 if (*line++ != 'S')
257 return -1; /* not an S record */
259 rectype = *line++;
261 minlen = 3; /* type 1 record */
262 switch (rectype) {
263 case '0':
264 break;
267 * data bytes
269 case '3':
270 minlen++;
271 /* fall through */
272 case '2':
273 minlen++;
274 /* fall through */
275 case '1':
276 chksum = 0;
277 linelen = getbyte(&line);
278 if (linelen < minlen) {
279 xprintf("srec: line too short\n");
280 return -1;
282 chksum += (unsigned int)linelen;
285 * There are two address bytes in a type 1 record, and three
286 * in a type 2 record. The high-order byte is first, then
287 * one or two lower-order bytes. Build up the adddress.
289 b = getbyte(&line);
290 chksum += (unsigned int)b;
291 addr = b;
292 b = getbyte(&line);
293 chksum += (unsigned int)b;
294 addr <<= 8;
295 addr += b;
296 if (rectype == '2') {
297 b = getbyte(&line);
298 chksum += (unsigned int)b;
299 addr <<= 8;
300 addr += b;
302 if (rectype == '3') {
303 b = getbyte(&line);
304 chksum += (unsigned int)b;
305 addr <<= 8;
306 addr += b;
307 b = getbyte(&line);
308 chksum += (unsigned int)b;
309 addr <<= 8;
310 addr += b;
313 #if VERBOSE
314 printf("Addr: %08X Len: %3u(0x%x)\n", addr , linelen - minlen,
315 linelen-minlen);
316 #endif
318 *loadaddr = addr;
319 len = linelen - minlen;
320 *blklen = len;
322 for (idx = 0; idx < len; idx++) {
323 b = getbyte(&line);
324 chksum += (unsigned int) b;
325 data[idx] = (unsigned char ) b;
328 b = getbyte(&line);
329 chksum = (~chksum) & 0x000000FF;
330 if (chksum != b) {
331 xprintf("Checksum error in s-record file\n");
332 return -1;
334 ret = 1;
335 break;
337 case '9':
338 linelen = getbyte(&line);
339 b = getbyte(&line);
340 addr = b;
341 b = getbyte(&line);
342 addr <<= 8;
343 addr += b;
344 *loadaddr = addr;
345 ret = -2;
346 break;
348 case '8':
349 linelen = getbyte(&line);
350 b = getbyte(&line);
351 addr = b;
352 b = getbyte(&line);
353 addr <<= 8;
354 addr += b;
355 b = getbyte(&line);
356 addr <<= 8;
357 addr += b;
358 *loadaddr = addr;
359 ret = -2;
360 break;
362 case '7':
363 linelen = getbyte(&line);
364 b = getbyte(&line);
365 addr = b;
366 b = getbyte(&line);
367 addr <<= 8;
368 addr += b;
369 b = getbyte(&line);
370 addr <<= 8;
371 addr += b;
372 b = getbyte(&line);
373 addr <<= 8;
374 addr += b;
375 *loadaddr = addr;
376 ret = -2;
377 break;
379 default:
380 xprintf("Unknown S-record type: %c\n",rectype);
381 return -1;
382 break;
385 return ret;
389 /* *********************************************************************
390 * cfe_srecload(la)
392 * Read an s-record file
394 * Input parameters:
395 * la - loader args
397 * Return value:
398 * 0 if ok, else error code
399 ********************************************************************* */
400 static int cfe_srecload(cfe_loadargs_t *la)
402 int res;
403 fileio_ctx_t *fsctx;
404 void *ref;
405 int devinfo;
406 int serial = FALSE;
407 unsigned int loadaddr = 0;
408 unsigned int blklen = 0;
409 linebuf_t lb;
410 char line[256];
411 uint8_t data[256];
412 int cnt;
413 unsigned int specaddr; /* current address if loading to a special address */
414 int specflg; /* true if in "special address" mode */
415 int firstrec = 1; /* true if we have not seen the first record */
418 * We might want to know something about the boot device.
421 devinfo = la->la_device ? cfe_getdevinfo(la->la_device) : 0;
424 * Figure out if we're loading to a "special address". This lets
425 * us load S-records into a temporary buffer, ignoring the
426 * addresses in the records (but using them so we'll know where
427 * they go relative to each other
430 specflg = (la->la_flags & LOADFLG_SPECADDR) ? 1 : 0;
431 specaddr = 0;
434 * If the device is a serial port, we want to know that.
437 if ((devinfo >= 0) &&
438 ((devinfo & CFE_DEV_MASK) == CFE_DEV_SERIAL)) {
439 serial = TRUE;
443 * Create a file system context
446 res = fs_init(la->la_filesys,&fsctx,la->la_device);
447 if (res != 0) {
448 return res;
452 * Turn on compression if we're doing that.
455 if (la->la_flags & LOADFLG_COMPRESSED) {
456 res = fs_hook(fsctx,"z");
457 if (res != 0) {
458 return res;
463 * Open the boot device
466 res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ);
467 if (res != 0) {
468 fs_uninit(fsctx);
469 return res;
473 initlinebuf(&lb,ref,fsctx);
475 cnt = 0;
476 for (;;) {
478 * Read a line of text
480 res = readline(&lb,line,sizeof(line));
481 if (res < 0) break; /* reached EOF */
484 * Process the S-record. If at EOF, procsrec returns 0.
485 * Invalid s-records returns -1.
488 if (line[0] == 0) continue;
490 res = procsrec(line, &loadaddr, &blklen, data);
492 if (res < 0) break;
495 * Handle "special address" mode. All S-records will be
496 * loaded into a buffer passed by the caller to the loader.
497 * We use the addresses in the S-records to determine
498 * relative placement of the data, keying on the first
499 * S-record in the file.
502 if ((res == 1) && (specflg)) {
503 if (firstrec) {
504 /* First S-record seen sets the base for all that follow */
505 specaddr = loadaddr;
506 firstrec = 0;
508 loadaddr = la->la_address + (intptr_t) (loadaddr - specaddr);
511 cnt++;
513 if (res == 1) {
514 if (!cfe_arena_loadcheck((intptr_t)loadaddr, blklen)) {
515 xprintf("Invalid address: %P\n", loadaddr);
516 res = -1;
517 break;
519 memcpy((uint8_t *)(intptr_t)(signed)loadaddr, data, blklen);
524 * We're done with the file.
527 fs_close(fsctx,ref);
528 fs_uninit(fsctx);
531 * Say something cute on the LEDs.
532 * Don't do this for every s-record, because if logging the LED
533 * changes out the serial port, that can take a Long Time. Just
534 * goes to show: too much cuteness is a _very_ bad thing.
536 xsprintf(line,"%04d",cnt);
537 cfe_ledstr(line);
539 if (res == -2) {
540 la->la_entrypt = (intptr_t)(signed)loadaddr;
541 res = 0;
544 return res;
547 #endif /* CFG_LDR_SREC */