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