1 /*
2 main.c - vrflash main
3 Copyright (C) 2001 Jeff Carneal
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "config.h"
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <signal.h>
28 #include "main.h"
29 #include "xmodem.h"
30 #include "etxack.h"
31 #include "port.h"
32 #include "progress.h"
33 #include "vrerror.h"
34 #include "vrfile.h"
35
36 const char *versionstr =
37 "vrflash: 0.24 - 2002/10/30 - Copyright 2001 Jeff Carneal <jeff@apex.net>";
38 int do_portlog = 0;
39 extern VRFILE *first;
40
41 int
main(int argc,char ** argv)42 main (int argc, char **argv)
43 {
44 int fd = 0;
45 int ret = 0;
46 int argval = 0;
47 int logfile_fd = 0;
48 int i = 0;
49 char serialport[SMBUFSIZE];
50 char buffer[BUFSIZE];
51 char cmdline[BUFSIZE];
52 char *restore =
53 "$linux console=ttyS0,115200 init=/sbin/restore_defaults\r";
54 long filesize = 0;
55 VRFILE *cur = NULL;
56 CONFIG conf;
57 extern PM pmeter;
58 extern char *optarg;
59 extern int optind;
60
61 memset (buffer, 0, BUFSIZE);
62 memset (serialport, 0, SMBUFSIZE);
63 logfile_fd = 0;
64
65 /*
66 * Initialize config values
67 */
68 memset (&conf, 0, sizeof (CONFIG));
69 conf.chkpmon = 1;
70 conf.xmodemload = 1;
71 conf.chkromsize = 1;
72 conf.chkkernsize = 1;
73
74 /*
75 * Save command line for logging
76 */
77 memset (cmdline, 0, BUFSIZE);
78 cmdline[0] = '\n';
79 for (i = 0; i < argc; i++)
80 {
81 if ((strlen (cmdline) + strlen (argv[i])) < BUFSIZE)
82 sprintf (cmdline, "%s %s", cmdline, argv[i]);
83 }
84
85 while ((argval = getopt (argc, argv, "hlrs:t:vCDRX")) != EOF)
86 {
87 switch (argval)
88 {
89 case 'h':
90 case 'v':
91 usage ();
92 break;
93 case 'l':
94 do_portlog = 1;
95 if (!
96 (logfile_fd =
97 open (LOGFILE, O_CREAT | O_TRUNC | O_WRONLY,
98 0644)))
99 {
100 fprintf (stderr,
101 "Warning: can't open %s for writing\n",
102 LOGFILE);
103 }
104 else
105 {
106 write (logfile_fd, versionstr,
107 strlen (versionstr));
108 write (logfile_fd, cmdline, strlen (cmdline));
109 write (logfile_fd, "\n\n", 2);
110 close (logfile_fd);
111 }
112 break;
113 case 'r':
114 conf.restart = 1;
115 break;
116 case 's':
117 conf.ttyport = strdup (optarg);
118 break;
119 case 't':
120 conf.tmpdir = strdup (optarg);
121 break;
122 case 'C':
123 conf.chkromsize = 0;
124 conf.chkkernsize = 0;
125 break;
126 case 'D':
127 conf.chkpmon = 0;
128 break;
129 case 'R':
130 conf.restore_defaults = 1;
131 break;
132 case 'X':
133 conf.xmodemload = 0;
134 break;
135 }
136 }
137
138 if (conf.ttyport)
139 snprintf (serialport, SMBUFSIZE, "/dev/%s", conf.ttyport);
140 else
141 snprintf (serialport, SMBUFSIZE, "/dev/ttyS0");
142
143 argc -= optind;
144 argv += optind;
145
146 if ((argc < 2) && (!conf.restore_defaults))
147 {
148 usage ();
149 }
150
151 fprintf (stderr, "\n");
152 /*
153 * Create the list of files/offsets
154 * we need to transfer
155 */
156 while (argv[0])
157 {
158 if (!argv[1])
159 {
160 vr_error ("Error: no offset specified for '%s'\n",
161 argv[0]);
162 }
163 /*
164 * Create and initialize
165 * each new file struct
166 */
167 cur = (VRFILE *) malloc (sizeof (VRFILE));
168 if (!cur)
169 vr_error ("Error: out of memory");
170 memset (cur, 0, sizeof (VRFILE));
171
172 cur->filename = strdup (argv[0]);
173
174 if (strncmp (argv[1], "kernel", 6) == 0)
175 {
176 cur->offset = 0x0;
177 }
178 else if (strncmp (argv[1], "pmon", 4) == 0)
179 {
180 cur->offset = 0xc00000;
181 }
182 else if ((strncmp (argv[1], "romdisk", 7) == 0) ||
183 (strncmp (argv[1], "rootdisk", 8) == 0))
184 {
185 cur->offset = 0x200000;
186 }
187 else if (strncmp (argv[1], "cramfs", 6) == 0)
188 {
189 cur->offset = 0x100000;
190 }
191 else if (strncmp (argv[1], "0x", 2) == 0)
192 {
193 argv[1] += 2;
194 cur->offset = axtoi (argv[1]);
195 }
196 else
197 {
198 cur->offset = axtoi (argv[1]);
199 }
200
201 vrfile_chk (cur, &conf);
202 vrfile_add (cur);
203
204 argv += 2;
205 }
206 /* Debug Only
207 * vrfile_list();
208 * exit(1);
209 */
210
211 /*
212 * Check for PMON overwrite
213 */
214 if (conf.chkpmon)
215 check_pmon ();
216
217 /*
218 * Open the serial port
219 */
220 fprintf (stderr, "Opening serial port...");
221 if ((fd = port_open (serialport)) < 0)
222 {
223 vr_error ("Error: Unable to open port '%s'", serialport);
224 }
225 fprintf (stderr, "done\n");
226 port_init (fd);
227
228 /*
229 * Wait here for first character
230 * from the serial port.
231 */
232 fprintf (stderr, "Waiting for input from port (CTRL-C to exit)...");
233 port_send (fd, "\r", 1, NOPORTLOG);
234 while (read (fd, buffer, 1) == 0) ;
235 fprintf (stderr, "done\n\n");
236
237 for (cur = first; cur; cur = cur->next)
238 {
239
240 /*
241 * Clear port and find PMON prompt
242 */
243 port_getpmon (fd, buffer);
244
245 if (conf.xmodemload)
246 {
247 fprintf (stderr, "Sending etxack start command...");
248 port_send (fd, "load\r", 5, PORTLOG);
249 fprintf (stderr, "done\n");
250
251 port_readflush (fd);
252 fprintf (stderr,
253 "Starting etxack send (xmodem-load)...");
254 ex_sendfile (fd);
255 fprintf (stderr, "done\n\n");
256
257 conf.xmodemload = 0;
258 port_getpmon (fd, buffer);
259 }
260
261 fprintf (stderr, "Sending xmodem start command...");
262 port_send (fd, "g -e a0080274\r", 14, PORTLOG);
263 fprintf (stderr, "done\n");
264
265 fprintf (stderr, "Starting xmodem send - %s...\n",
266 cur->filename);
267 filesize = xmodem_sendfile (cur->filename, fd);
268
269 port_getpmon (fd, buffer);
270
271 /*
272 * Issue flash command
273 */
274 filesize = SECTOR_ALIGN (filesize);
275 fprintf (stderr, "Sending flash command...");
276 snprintf (buffer, BUFSIZE, "flash 80090000 %lx %lx\r",
277 filesize, cur->offset);
278 port_send (fd, buffer, strlen (buffer), PORTLOG);
279 port_readflush (fd);
280 port_send (fd, "y\r", 2, PORTLOG);
281 fprintf (stderr, "done\n");
282
283 /*
284 * Setup progress meter for flash
285 */
286 memset (&pmeter, 0, sizeof (PM));
287 gettimeofday (&pmeter.start, NULL);
288 pmeter.totalkbytes = (int) filesize / 1024;
289 pm_showmeter (PM_START);
290
291 while ((ret = port_readline (fd, buffer)) != -1)
292 {
293 if (strstr (buffer, "Programming block"))
294 {
295 /* vr3 sector size 0x20000 */
296 pmeter.bytesdone += 131072;
297 if (pmeter.bytesdone > filesize)
298 pmeter.bytesdone = filesize;
299 pm_showmeter (PM_UPDATE);
300 }
301 else if (strstr (buffer, "Error"))
302 {
303 fprintf (stderr, "\nWARNING: '%s'\n",
304 buffer);
305 }
306 else if (strstr (buffer, prompt1))
307 {
308 break;
309 }
310 else if (strstr (buffer, prompt2))
311 {
312 break;
313 }
314 }
315 if (ret == -1)
316 vr_error ("Error: timeout reading from port");
317
318 pm_showmeter (PM_END);
319 } /* for(cur=first; cur; cur=cur->next) */
320
321 port_getpmon (fd, buffer);
322
323 if (conf.restore_defaults)
324 {
325 // Code added by Sean Barnes for sdram PMON
326 fprintf (stderr, "Unzipping kernel...");
327 port_send (fd, "unzip\r", strlen ("unzip\r"), PORTLOG);
328 while ((ret = port_readline (fd, buffer)) != -1)
329 {
330 if (strstr (buffer, prompt1))
331 {
332 break;
333 }
334 else if (strstr (buffer, prompt2))
335 {
336 break;
337 }
338 }
339 fprintf (stderr, "done\n");
340
341 fprintf (stderr, "Restoring defaults...\n");
342 port_send (fd, restore, strlen (restore), PORTLOG);
343 while ((ret = port_readline (fd, buffer)) != -1)
344 {
345 fprintf (stderr, "%s\n", buffer);
346 if (strstr (buffer, "Hard reset"))
347 {
348 break;
349 }
350 }
351 fprintf (stderr, "\nvrflash completed\n");
352 }
353 else if (conf.restart)
354 {
355 // Code added by Sean Barnes for sdram PMON
356 fprintf (stderr, "Unzipping kernel...");
357 port_send (fd, "unzip\r", strlen ("unzip\r"), PORTLOG);
358 while ((ret = port_readline (fd, buffer)) != -1)
359 {
360 if (strstr (buffer, prompt1))
361 {
362 break;
363 }
364 else if (strstr (buffer, prompt2))
365 {
366 break;
367 }
368 }
369 fprintf (stderr, "done\n");
370
371 fprintf (stderr, "Restarting system...");
372 port_send (fd, "$linux\r", 7, PORTLOG);
373 fprintf (stderr, "done\n");
374 }
375
376 close (fd);
377
378 vrfile_cleanup (0);
379 return 0;
380 }
381
382
383 void
usage(void)384 usage (void)
385 {
386 fprintf (stderr, "\n %s\n", versionstr);
387 fprintf (stderr,
388 "\n Usage: vrflash [OPTIONS] <file> <kernel|romdisk|cramfs|pmon|0xOffset> \n");
389 fprintf (stderr,
390 " [ -l ] -- "
391 "Capture input/output to ./capture.log\n");
392 fprintf (stderr,
393 " [ -r ] -- "
394 "Restart VR3 after loading\n");
395 fprintf (stderr,
396 " [ -R ] -- "
397 "Restore defaults after flash\n");
398 fprintf (stderr,
399 " [ -s <serial port> ] -- "
400 "Serial port. Default == ttyS0\n");
401 fprintf (stderr,
402 " [ -t <temp dir> ] -- "
403 "Temp dir for split files. Default==/tmp\n");
404 fprintf (stderr,
405 " [ -v (or -h) ] -- " "Version and usage (this)\n");
406 fprintf (stderr,
407 " [ -C ] -- "
408 "Disable kernel/romdisk size check (expert-only!)\n");
409 fprintf (stderr,
410 " [ -D ] -- "
411 "Disable PMON overwrite check (expert-only!)\n");
412 fprintf (stderr,
413 " [ -X ] -- "
414 "Do not load xmodem-load.srec\n\n");
415 exit (1);
416 }
417
418 /*
419 * I boosted this from a borland.com example
420 * My version worked but was ugly...stepped on.
421 * Kudos to the bad mother that came up with this
422 */
423 long
axtoi(char * str)424 axtoi (char *str)
425 {
426 int n = 0;
427 int m = 0;
428 int count;
429 long intValue = 0;
430 int digit[10];
431 char *ptr;
432
433 ptr = str;
434 if (!strncmp (str, "0x", 2))
435 ptr += 2;
436
437 while (ptr && (ptr[n]) && (n < 10))
438 {
439 if (ptr[n] > 0x29 && ptr[n] < 0x40) /* if 0 to 9 */
440 digit[n] = ptr[n] & 0x0f;
441 else if (ptr[n] >= 'a' && ptr[n] <= 'f') /* if a to f */
442 digit[n] = (ptr[n] & 0x0f) + 9;
443 else if (ptr[n] >= 'A' && ptr[n] <= 'F') /* if A to F */
444 digit[n] = (ptr[n] & 0x0f) + 9;
445 else
446 vr_error ("Error: invalid offset '%s'", str);
447 n++;
448 }
449 count = n;
450 m = n - 1;
451 n = 0;
452 while (n < count)
453 {
454 /*
455 * digit[n] is value of hex digit at position n
456 * (m << 2) is the number of positions to shift
457 * OR the bits into return value
458 */
459 intValue = intValue | (digit[n] << (m << 2));
460 m--;
461 n++;
462 }
463 return (intValue);
464 }
465
466
467 int
check_pmon(void)468 check_pmon (void)
469 {
470 VRFILE *cur;
471 int writesize;
472 long i;
473
474 /*
475 * * PMON ([bf]c00000-[bf]c7ffff)
476 */
477
478 /*
479 * I check every 64k instead of
480 * every byte now. Since PMON occupies
481 * 320K, I feel that's pretty safe
482 */
483 for (cur = first; cur; cur = cur->next)
484 {
485 writesize = SECTOR_ALIGN (cur->size);
486 for (i = cur->offset; i < writesize + cur->offset;
487 i += 0x10000)
488 {
489 /*fprintf(stderr, "Checking (0x%lx, 0x%lx)\n", writesize+cur->offset, i); */
490 if ((i >= 0xc00000) && (i <= 0xc7ffff))
491 {
492 vr_error ("Warning: PMON overwrite detected by '%s'. Aborting. (0x%lx)\n", cur->filename);
493 }
494 }
495 /*
496 * Check last byte to be flashed
497 * separately. Just in case a few bytes
498 * slip in under the 0x10000 radar
499 */
500 i = writesize + cur->offset - 1;
501 /*fprintf(stderr, "Checking (0x%lx, 0x%lx)\n", writesize+cur->offset, i); */
502 if ((i >= 0xc00000) && (i <= 0xc7ffff))
503 {
504 vr_error ("Warning: PMON overwrite detected by '%s'. Aborting.\n", cur->filename);
505 }
506 }
507 return 0;
508 }
509