/* main.c - vrflash main Copyright (C) 2001 Jeff Carneal This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include "main.h" #include "xmodem.h" #include "etxack.h" #include "port.h" #include "progress.h" #include "vrerror.h" #include "vrfile.h" char *versionstr = "vrflash: 0.20 - 2001/04/18 - Jeff Carneal "; int do_portlog=0; extern VRFILE *first; int main(int argc, char **argv) { int fd=0; int ret=0; int argval=0; int logfile_fd=0; int i=0; char serialport[SMBUFSIZE]; char buffer[BUFSIZE]; char cmdline[BUFSIZE]; char *restore = "$linux console=ttyS0,115200 init=/sbin/restore_defaults\r"; long filesize = 0; VRFILE *cur=NULL; CONFIG conf; extern PM pmeter; extern char *optarg; extern int optind; memset(buffer,0,BUFSIZE); memset(serialport,0,SMBUFSIZE); logfile_fd = 0; /* * Initialize config values */ memset(&conf,0,sizeof(CONFIG)); conf.chkpmon = 1; conf.xmodemload = 1; conf.chkromsize = 1; conf.chkkernsize = 1; /* * Save command line for logging */ memset(cmdline, 0, BUFSIZE); cmdline[0] = '\n'; for(i=0; ifilename = strdup(argv[0]); if(strncmp(argv[1],"kernel",6)==0) { cur->offset = 0x0; } else if((strncmp(argv[1],"romdisk",6)==0) || (strncmp(argv[1],"rootdisk",8)==0)){ cur->offset = 0x200000; } else if(strncmp(argv[1], "0x",2)==0) { argv[1]+=2; cur->offset = axtoi(argv[1]); } else { cur->offset = axtoi(argv[1]); } vrfile_chk(cur, &conf); vrfile_add(cur); argv += 2; } /* Debug Only vrfile_list(); exit(1); */ /* * Check for PMON overwrite */ if(conf.chkpmon) check_pmon(); /* * Open the serial port */ fprintf(stderr, "Opening serial port..."); if((fd = port_open(serialport)) < 0) { vr_error("Error: Unable to open port '%s'", serialport); } fprintf(stderr, "done\n"); port_init(fd); /* * Wait here for first character * from the serial port. */ fprintf(stderr, "Waiting for input from port (CTRL-C to exit)..."); port_send(fd, "\r", 1, NOPORTLOG); while(read(fd,buffer,1)==0); fprintf(stderr, "done\n\n"); for(cur=first; cur; cur=cur->next) { /* * Clear port and find PMON prompt */ port_getpmon(fd, buffer); if(conf.xmodemload) { fprintf(stderr, "Sending etxack start command..."); port_send(fd, "load\r", 5, PORTLOG); fprintf(stderr, "done\n"); port_readflush(fd); fprintf(stderr, "Starting etxack send (xmodem-load)..."); ex_sendfile(fd); fprintf(stderr, "done\n\n"); conf.xmodemload = 0; port_getpmon(fd, buffer); } fprintf(stderr, "Sending xmodem start command..."); port_send(fd, "g -e a0080274\r", 14, PORTLOG); fprintf(stderr, "done\n"); fprintf(stderr, "Starting xmodem send - %s...\n", cur->filename); filesize = xmodem_sendfile(cur->filename, fd); port_getpmon(fd, buffer); /* * Issue flash command */ filesize = SECTOR_ALIGN(filesize); fprintf(stderr, "Sending flash command..."); snprintf(buffer, BUFSIZE, "flash 80090000 %lx %lx\r", filesize, cur->offset); port_send(fd, buffer, strlen(buffer), PORTLOG); port_readflush(fd); port_send(fd, "y\r", 2, PORTLOG); fprintf(stderr, "done\n"); /* * Setup progress meter for flash */ memset(&pmeter,0,sizeof(PM)); gettimeofday(&pmeter.start, NULL); pmeter.totalkbytes = (int)filesize/1024; pm_showmeter(PM_START); while((ret = port_readline(fd, buffer))!=-1) { if(strstr(buffer, "Programming block")) { /* vr3 sector size 0x20000 */ pmeter.bytesdone += 131072; if(pmeter.bytesdone > filesize) pmeter.bytesdone = filesize; pm_showmeter(PM_UPDATE); } else if(strstr(buffer, "Error")) { fprintf(stderr, "\nWARNING: '%s'\n", buffer); } else if(strstr(buffer, "PMON> ")) { break; } } if(ret == -1) vr_error("Error: timeout reading from port"); pm_showmeter(PM_END); } /* for(cur=first; cur; cur=cur->next) */ port_getpmon(fd, buffer); if(conf.restore_defaults) { fprintf(stderr, "Restoring defaults...\n"); port_send(fd, restore, strlen(restore), PORTLOG); while((ret = port_readline(fd, buffer))!=-1) { fprintf(stderr, "%s\n", buffer); if(strstr(buffer, "Hard reset")) { break; } } fprintf(stderr, "\nvrflash completed\n"); } else if(conf.restart) { fprintf(stderr, "Restarting system..."); port_send(fd, "$linux\r", 7, PORTLOG); fprintf(stderr, "done\n"); } close(fd); vrfile_cleanup(0); return 0; } void usage(void) { fprintf(stderr, "\n %s\n", versionstr); fprintf(stderr, "\n Usage: vrflash [OPTIONS] \n"); fprintf(stderr, " [ -l ] -- " "Capture input/output to ./capture.log\n"); fprintf(stderr, " [ -r ] -- " "Restart VR3 after loading\n"); fprintf(stderr, " [ -s ] -- " "Serial port. Default == ttyS0\n"); fprintf(stderr, " [ -t ] -- " "Temp dir for split files. Default==/tmp\n"); fprintf(stderr, " [ -v (or -h) ] -- " "Version and usage (this)\n"); fprintf(stderr, " [ -C ] -- " "Disable kernel/romdisk size check (expert-only!)\n"); fprintf(stderr, " [ -D ] -- " "Disable PMON overwrite check (expert-only!)\n"); fprintf(stderr, " [ -R ] -- " "Restore defaults after flash\n"); fprintf(stderr, " [ -X ] -- " "Do not load xmodem-load.srec\n\n"); exit(1); } /* * I boosted this from a borland.com example * My version worked but was ugly...stepped on. * Kudos to the bad mother that came up with this */ long axtoi(char *str) { int n = 0; int m = 0; int count; long intValue = 0; int digit[10]; char *ptr; ptr = str; if(!strncmp(str, "0x",2)) ptr+=2; while(ptr && (ptr[n]) && (n<10)) { if (ptr[n] > 0x29 && ptr[n] < 0x40 ) /* if 0 to 9 */ digit[n] = ptr[n] & 0x0f; else if (ptr[n] >='a' && ptr[n] <= 'f') /* if a to f */ digit[n] = (ptr[n] & 0x0f) + 9; else if (ptr[n] >='A' && ptr[n] <= 'F') /* if A to F */ digit[n] = (ptr[n] & 0x0f) + 9; else vr_error("Error: invalid offset '%s'", str); n++; } count = n; m = n - 1; n = 0; while(n < count) { /* * digit[n] is value of hex digit at position n * (m << 2) is the number of positions to shift * OR the bits into return value */ intValue = intValue | (digit[n] << (m << 2)); m--; n++; } return (intValue); } int check_pmon(void) { VRFILE *cur; int writesize; long i; /* * PMON ([bf]c00000-[bf]c7ffff) */ /* * I check every 64k instead of * every byte now. Since PMON occupies * 320K, I feel that's pretty safe */ for(cur=first; cur; cur=cur->next) { writesize = SECTOR_ALIGN(cur->size); for(i=cur->offset; ioffset; i+=0x10000) { /*fprintf(stderr, "Checking (0x%lx, 0x%lx)\n", writesize+cur->offset, i);*/ if((i>=0xc00000) && (i<=0xc7ffff)) { vr_error("Warning: PMON overwrite detected by '%s'. Aborting. (0x%lx)\n", cur->filename); } } /* * Check last byte to be flashed * separately. Just in case a few bytes * slip in under the 0x10000 radar */ i = writesize + cur->offset - 1; /*fprintf(stderr, "Checking (0x%lx, 0x%lx)\n", writesize+cur->offset, i);*/ if((i>=0xc00000) && (i<=0xc7ffff)) { vr_error("Warning: PMON overwrite detected by '%s'. Aborting.\n", cur->filename); } } return 0; }