comparison packages/redboot/current/src/load.c @ 115:6ed91473a1cd ecos-sw-2000-08-21

Merge from eCos master repository on 2000-08-21-22:40:54-BST
author jlarmour
date Fri, 25 Aug 2000 17:32:38 +0000
parents
children bd1a71e3e476
comparison
equal deleted inserted replaced
114:5ad2b71d525e 115:6ed91473a1cd
1 //==========================================================================
2 //
3 // load.c
4 //
5 // RedBoot file/image loader
6 //
7 //==========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Red Hat eCos Public License
12 // Version 1.1 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://www.redhat.com/
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Configurable Operating System,
22 // released September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Red Hat.
25 // Portions created by Red Hat are
26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
27 // All Rights Reserved.
28 // -------------------------------------------
29 //
30 //####COPYRIGHTEND####
31 //==========================================================================
32 //#####DESCRIPTIONBEGIN####
33 //
34 // Author(s): gthomas
35 // Contributors: gthomas
36 // Date: 2000-07-14
37 // Purpose:
38 // Description:
39 //
40 // This code is part of RedBoot (tm).
41 //
42 //####DESCRIPTIONEND####
43 //
44 //==========================================================================
45
46 #include <redboot.h>
47
48 // Exported CLI function
49 RedBoot_cmd("load",
50 "Load a file",
51 "[-raw] [-b <mem_addr>]]",
52 do_load
53 );
54
55 static void
56 load_elf_image(int (*getc)(void))
57 {
58 printf("ELF images not supported\n");
59 }
60
61 //
62 // Scan a string of hex bytes and update the checksum
63 //
64 static long
65 _hex2(int (*getc)(void), int len, long *sum)
66 {
67 int val, byte;
68 char c1, c2;
69
70 val = 0;
71 while (len-- > 0) {
72 c1 = (*getc)();
73 c2 = (*getc)();
74 if (_is_hex(c1) && _is_hex(c2)) {
75 val <<= 8;
76 byte = (_from_hex(c1)<<4) | _from_hex(c2);
77 val |= byte;
78 if (sum) {
79 *sum += byte;
80 }
81 } else {
82 return (-1);
83 }
84 }
85 return (val);
86 }
87
88 //
89 // Process a set of S-records, loading the contents into memory.
90 // Note: if a "base" value is provided, the data will be relocated
91 // relative to that location. Of course, this can only work for
92 // the first section of the data, so if there are non-contiguous
93 // pieces of data, they will end up relocated in the same fashion.
94 // Because of this, "base" probably only makes sense for a set of
95 // data which has only one section, e.g. a ROM image.
96 //
97 #define MAX_LINE 80
98 static void
99 load_srec_image(int (*getc)(void), unsigned long base)
100 {
101 char line[MAX_LINE];
102 char *lp;
103 int c, len;
104 long offset = 0, count, sum, val, cksum;
105 unsigned char *addr, *base_addr;
106 char type;
107 bool first_addr = true;
108 unsigned long addr_offset = 0;
109 unsigned long highest_address = 0;
110 unsigned long lowest_address = 0xFFFFFFFF;
111
112 while ((c = (*getc)()) > 0) {
113 lp = line; len = 0;
114 // Start of line
115 if (c != 'S') {
116 printf("Invalid S-record at offset 0x%lx, input: %c\n",
117 (unsigned long)offset, c);
118 return;
119 }
120 type = (*getc)();
121 offset += 2;
122 sum = 0;
123 if ((count = _hex2(getc, 1, &sum)) < 0) {
124 printf("Bad S-record count at offset 0x%lx\n", (unsigned long)offset);
125 return;
126 }
127 offset += 1;
128 switch (type) {
129 case '0':
130 break;
131 case '1':
132 case '2':
133 case '3':
134 base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum);
135 offset += (type-'1'+2);
136 if (first_addr) {
137 if (base) {
138 addr_offset = (unsigned long)base - (unsigned long)addr;
139 printf("Address offset = %lx\n", (unsigned long)addr_offset);
140 } else {
141 addr_offset = 0;
142 }
143 first_addr = false;
144 }
145 addr += addr_offset;
146 if ((unsigned long)(addr-addr_offset) < lowest_address) {
147 lowest_address = (unsigned long)(addr - addr_offset);
148 }
149 if ((addr < ram_start) || (addr > ram_end)) {
150 printf("Attempt to load S-record data to address: %p [not in RAM]\n", addr);
151 return;
152 }
153 count -= ((type-'1'+2)+1);
154 offset += count;
155 while (count-- > 0) {
156 val = _hex2(getc, 1, &sum);
157 *addr++ = val;
158 }
159 cksum = _hex2(getc, 1, 0);
160 offset += 1;
161 sum = sum & 0xFF;
162 cksum = (~cksum & 0xFF);
163 if (cksum != sum) {
164 printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n",
165 (unsigned long)base_addr, sum, cksum);
166 }
167 if ((unsigned long)(addr-addr_offset) > highest_address) {
168 highest_address = (unsigned long)(addr - addr_offset);
169 }
170 break;
171 case '7':
172 case '8':
173 case '9':
174 addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum);
175 offset += ('9'-type+2);
176 entry_address = (unsigned long *)addr;
177 printf("Entry point: %p, address range: %p-%p\n",
178 entry_address, (void *)lowest_address, (void *)highest_address);
179 return;
180 default:
181 printf("Invalid S-record at offset 0x%lx, type: %x\n",
182 (unsigned long)offset, type);
183 return;
184 }
185 while ((c = (*getc)()) != '\n') offset++;
186 }
187 }
188
189 #define BUF_SIZE 256
190 static struct {
191 int (*fun)(char *, int len, int *err);
192 unsigned char buf[BUF_SIZE];
193 unsigned char *bufp;
194 int avail, len, err;
195 int verbose, tick;
196 } getc_info;
197
198 static int
199 getc(void)
200 {
201 static char spin[] = "|/-\\|-";
202 if (getc_info.avail == 0) {
203 if (getc_info.verbose) {
204 printf("%c\b", spin[getc_info.tick++]);
205 if (getc_info.tick >= sizeof(spin)) {
206 getc_info.tick = 0;
207 }
208 }
209 if (getc_info.len < BUF_SIZE) {
210 // No more data available
211 if (getc_info.verbose) printf("\n");
212 return -1;
213 }
214 getc_info.bufp = getc_info.buf;
215 getc_info.len = (*getc_info.fun)(getc_info.bufp, BUF_SIZE, &getc_info.err);
216 if ((getc_info.avail = getc_info.len) < 0) {
217 if (getc_info.verbose) printf("\n");
218 return -1;
219 }
220 }
221 getc_info.avail--;
222 return *getc_info.bufp++;
223 }
224
225 static void
226 getc_init(int (*fun)(char *, int, int *), int verbose)
227 {
228 getc_info.avail = 0;
229 getc_info.len = BUF_SIZE;
230 getc_info.fun = fun;
231 getc_info.verbose = verbose;
232 getc_info.tick = 0;
233 }
234
235 static void
236 getc_rewind(void)
237 {
238 getc_info.bufp = getc_info.buf;
239 getc_info.avail = getc_info.len;
240 }
241
242 #define MODE_TFTP 0
243 #define MODE_ZMODEM 1
244
245 void
246 do_load(int argc, char *argv[])
247 {
248 int i, res, err;
249 int mode;
250 int verbose = 0;
251 bool raw = false;
252 bool base_addr_set = false;
253 #ifdef CYGPKG_REDBOOT_NETWORKING
254 struct sockaddr_in host;
255 #endif
256 unsigned long base = 0;
257 char type[4];
258 char *filename = 0;
259 char *usage = "usage: load <file_name> [-r] [-v] [-h <host>] [-m {TFTP | ZMODEM}] [-b <base_address>]\n";
260
261 #ifdef CYGPKG_REDBOOT_NETWORKING
262 memset((char *)&host, 0, sizeof(host));
263 host.sin_len = sizeof(host);
264 host.sin_family = AF_INET;
265 host.sin_addr = my_bootp_info.bp_siaddr;
266 host.sin_port = 0;
267 #endif
268 #ifdef CYGPKG_REDBOOT_NETWORKING
269 mode = MODE_TFTP;
270 #else
271 mode = MODE_ZMODEM;
272 #endif
273 for (i = 1; i < argc; i++) {
274 if (argv[i][0] == '-') {
275 // Option
276 switch (argv[i][1]) {
277 case 'v':
278 verbose++;
279 break;
280 case 'r':
281 raw = true;
282 break;
283 #ifdef CYGPKG_REDBOOT_NETWORKING
284 case 'h':
285 if ((i+1) >= argc) {
286 printf("Invalid option: %s\n", argv[i]);
287 printf(usage);
288 return;
289 }
290 if (!inet_aton(argv[i+1], (in_addr_t *)&host)) {
291 printf("Invalid IP address: %s\n", argv[i+1]);
292 return;
293 }
294 i++; // Skip parameter
295 break;
296 #endif
297 case 'm':
298 if ((i+1) >= argc) {
299 printf("Invalid option: %s\n", argv[i]);
300 printf(usage);
301 return;
302 }
303 if (strcmpci(argv[i+1], "zmodem") == 0) {
304 mode = MODE_ZMODEM;
305 #ifdef CYGPKG_REDBOOT_NETWORKING
306 } else if (strcmpci(argv[i+1], "tftp") == 0) {
307 mode = MODE_TFTP;
308 if (!have_net) {
309 printf("TFTP mode requires a working network\n");
310 return;
311 }
312 #endif
313 } else {
314 printf("Invalid 'mode': %s\n", argv[i+1]);
315 return;
316 }
317 i++; // Skip parameter
318 break;
319 case 'b':
320 if ((i+1) >= argc) {
321 printf("Invalid option: %s\n", argv[i]);
322 printf(usage);
323 return;
324 }
325 if (!parse_num(argv[i+1], &base, 0, 0)) {
326 printf("Invalid offset: %s\n", argv[i+1]);
327 printf(usage);
328 return;
329 }
330 base_addr_set = true;
331 i++; // Skip parameter
332 break;
333 default:
334 printf("Invalid option: %s\n", argv[i]);
335 printf(usage);
336 return;
337 }
338 } else {
339 if (filename) {
340 printf("Only one file name allowed\n");
341 printf(usage);
342 return;
343 }
344 filename = argv[i];
345 }
346 }
347 if ((mode == MODE_TFTP) && !filename) {
348 printf("File name missing\n");
349 printf(usage);
350 return;
351 }
352 #ifdef CYGPKG_REDBOOT_NETWORKING
353 if (mode == MODE_TFTP) {
354 res = tftp_stream_open(filename, &host, TFTP_OCTET, &err);
355 if (res < 0) {
356 printf("Can't load '%s': %s\n", filename, tftp_error(err));
357 return;
358 }
359 getc_init(tftp_stream_read, verbose);
360 for (i = 0; i < sizeof(type); i++) {
361 if ((res = getc()) < 0) {
362 err = getc_info.err;
363 break;
364 }
365 type[i] = res;
366 }
367 if (res < 0) {
368 printf("Error reading header via TFTP: %s\n", tftp_error(err));
369 tftp_stream_close(&err);
370 return;
371 }
372 }
373 #endif
374 if (mode == MODE_ZMODEM) {
375 printf("Sorry, zmodem download not yet available\n");
376 return;
377 }
378 getc_rewind(); // Restore header to stream
379 if (raw) {
380 if (!base_addr_set) {
381 printf("Raw load requires a memory address\n");
382 } else {
383 unsigned char *mp = (unsigned char *)base;
384 while ((res = getc()) >= 0) {
385 *mp++ = res;
386 }
387 printf("Raw file loaded %p-%p\n", (void *)base, (void *)mp);
388 }
389 } else {
390 // Treat data as some sort of executable image
391 if (strncmp(&type[1], "ELF", 3) == 0) {
392 load_elf_image(getc);
393 } else if ((type[0] == 'S') &&
394 ((type[1] >= '0') && (type[1] <= '9'))) {
395 load_srec_image(getc, base);
396 } else {
397 printf("Unrecognized image type: %lx\n", *(unsigned long *)type);
398 }
399 }
400 #ifdef CYGPKG_REDBOOT_NETWORKING
401 if (mode == MODE_TFTP) {
402 tftp_stream_close(&err);
403 }
404 #endif
405 return;
406 }