1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * SREC Program Loader File: cfe_ldr_srec.c
6 * This program reads Motorola S-record files into memory
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
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 ********************************************************************* */
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"
55 #include "cfe_device.h"
56 #include "cfe_error.h"
57 #include "cfe_devfuncs.h"
60 #include "cfe_fileops.h"
63 #include "cfe_bootblock.h"
65 #include "cfe_loader.h"
69 /* *********************************************************************
71 ********************************************************************* */
73 static int cfe_srecload(cfe_loadargs_t
*la
);
75 const cfe_loader_t srecloader
= {
81 typedef struct linebuf_s
{
90 #define initlinebuf(b,r,o) (b)->curidx = 0; (b)->buflen = 0; \
91 (b)->eof = 0 ; (b)->ref = r; (b)->fsctx = o
94 /* *********************************************************************
97 * Read a character from a file. It's kind of like getchar
98 * on "C" FILE devices, but not so fancy.
101 * file - pointer to a linebuf_t containing reader state
104 * character, or -1 if at EOF
105 ********************************************************************* */
107 static int readchar(linebuf_t
*file
)
112 if (file
->eof
) return -1;
114 if (file
->curidx
== file
->buflen
) {
116 res
= fs_read(file
->fsctx
,file
->ref
,(unsigned char *)file
->linebuf
,sizeof(file
->linebuf
));
121 if (res
== 0) continue;
128 ch
= file
->linebuf
[file
->curidx
];
134 /* *********************************************************************
135 * readline(file,buffer,maxlen)
137 * Read a line of text from a file using our crude file stream
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
146 * 0 if ok, else <0 if at EOF
147 ********************************************************************* */
149 static int readline(linebuf_t
*file
,char *buffer
,int maxlen
)
155 maxlen
--; /* account for terminating null */
159 if (ch
== -1) return -1;
160 if (ch
== 27) return -1; /* ESC */
161 if ((ch
== '\n') || (ch
== '\r')) break;
172 /* *********************************************************************
175 * Convert a hex digit into its numeric equivalent
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;
192 /* *********************************************************************
195 * Process two hex digits and return the value
198 * line - pointer to pointer to characters (updated on exit)
201 * byte value, or <0 if bad hex digits
202 ********************************************************************* */
204 static int getbyte(char **line
)
209 c1
= getxdigit(*(*(line
)+0));
210 if (c1
< 0) return -1;
212 c2
= getxdigit(*(*(line
)+1));
213 if (c2
< 0) return -1;
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.
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
235 * <0 if error occured (not an s-record)
236 ********************************************************************* */
238 static int procsrec(char *line
,
239 unsigned int *loadaddr
,
240 unsigned int *blklen
,
247 unsigned int linelen
;
257 return -1; /* not an S record */
261 minlen
= 3; /* type 1 record */
277 linelen
= getbyte(&line
);
278 if (linelen
< minlen
) {
279 xprintf("srec: line too short\n");
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.
290 chksum
+= (unsigned int)b
;
293 chksum
+= (unsigned int)b
;
296 if (rectype
== '2') {
298 chksum
+= (unsigned int)b
;
302 if (rectype
== '3') {
304 chksum
+= (unsigned int)b
;
308 chksum
+= (unsigned int)b
;
314 printf("Addr: %08X Len: %3u(0x%x)\n", addr
, linelen
- minlen
,
319 len
= linelen
- minlen
;
322 for (idx
= 0; idx
< len
; idx
++) {
324 chksum
+= (unsigned int) b
;
325 data
[idx
] = (unsigned char ) b
;
329 chksum
= (~chksum
) & 0x000000FF;
331 xprintf("Checksum error in s-record file\n");
338 linelen
= getbyte(&line
);
349 linelen
= getbyte(&line
);
363 linelen
= getbyte(&line
);
380 xprintf("Unknown S-record type: %c\n",rectype
);
389 /* *********************************************************************
392 * Read an s-record file
398 * 0 if ok, else error code
399 ********************************************************************* */
400 static int cfe_srecload(cfe_loadargs_t
*la
)
407 unsigned int loadaddr
= 0;
408 unsigned int blklen
= 0;
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;
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
)) {
443 * Create a file system context
446 res
= fs_init(la
->la_filesys
,&fsctx
,la
->la_device
);
452 * Turn on compression if we're doing that.
455 if (la
->la_flags
& LOADFLG_COMPRESSED
) {
456 res
= fs_hook(fsctx
,"z");
463 * Open the boot device
466 res
= fs_open(fsctx
,&ref
,la
->la_filename
,FILE_MODE_READ
);
473 initlinebuf(&lb
,ref
,fsctx
);
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
);
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
)) {
504 /* First S-record seen sets the base for all that follow */
508 loadaddr
= la
->la_address
+ (intptr_t) (loadaddr
- specaddr
);
514 if (!cfe_arena_loadcheck((intptr_t)loadaddr
, blklen
)) {
515 xprintf("Invalid address: %P\n", loadaddr
);
519 memcpy((uint8_t *)(intptr_t)(signed)loadaddr
, data
, blklen
);
524 * We're done with the file.
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
);
540 la
->la_entrypt
= (intptr_t)(signed)loadaddr
;
547 #endif /* CFG_LDR_SREC */