/************************************************************* * File: mon/sload.c * Purpose: S-record loader * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970303 Removed duplicate globals * 970303 Switched chksum to static. * 970901 Added getNextSloadAdr(). Needed for sdtf cmd. * 970919 Changed getNextSloadAdr to getHighLoadAdr for BSO. Also * changed code to make nextaddr be highest addr, not last. * 970920 Added msgs for illegal loads. * 980404 Added DL_MFLAG * 981212 Accept but ignore S5 recs (ghs) */ #include #include #include #include /* * Useful S-records for testing purposes: * S0030000FC * S309900200001234567860 * S7058002000073 * */ static int chksum; static ADDR nextaddr; char recbuf[MAXREC]; static int datarec(char *p,ADDR offset,int *pLen,int flags); /************************************************************* * sload(rec,offset,pLen,pFlags) * load Motorola S-records * returns: * -1 on error * 0 at end * N for data records (N = bytes transferred) */ int sload(char *rec,ADDR offset,int *pLen,int *pFlags) { int len,x,flags; flags = *pFlags; *pLen = 0; len = 0; if(rec[0] == 'S') { if (rec[1] >= '7' && rec[1] <= '9') { if (flags&DL_MFLAG) ; /* don't set entry address */ else if (!endrec(rec,offset,flags)) return(0); else return(-1); } else if (rec[1] == 'D') { flags |= DL_DFLAG; *pFlags = flags; if (regChain) /* 970920 */ printf("ERROR: Reset controller before reloading driver.\n"); } else if (rec[1] == '4') { if (dlsym(rec,(flags&DL_AFLAG)?0:offset,flags)) return(-1); } else if (rec[1] >= '1' && rec[1] <= '3') { if (!regChain && !(flags&DL_DFLAG)) /* 970920 */ printf("ERROR: Load driver first.\n"); else if (flags&DL_MFLAG) ; /* don't load memory */ else if (x=datarec(rec,offset,&len,flags)) return(x); } else if (rec[1] == '0') return(1); else if (rec[1] == '5') ; /* accept but ignore S5 recs (ghs) */ else return(-1); } else return(-1); if (len >= 0) { *pLen = len; return(1); } else return(-1); } /************************************************************* * datarec(p,offset,pLen,flags) * handle an S-record data record * There are two very-similar versions of this routine. This * one has 4 arguments. */ static int datarec(char *p,ADDR offset,int *pLen,int flags) { int len,i,cs; ADDR addr; Ulong v; *pLen = 0; chksum = 0; if (!gethex(&len,&p[2],2)) return(-1); chksum += len; if (len*2 != strlen(p)-4) return(-2); i = 4; addr = 0; switch (p[1]) { case '3' : if (!gethex(&v,&p[i],2)) return(-1); addr = (addr<<8)+v; chksum += v; i += 2; /* fall thru */ case '2' : if (!gethex(&v,&p[i],2)) return(-1); addr = (addr<<8)+v; chksum += v; i += 2; /* fall thru */ case '1' : if (!gethex(&v,&p[i],2)) return(-1); addr = (addr<<8)+v; chksum += v; if (!gethex(&v,&p[i+2],2)) return(-1); addr = (addr<<8)+v; chksum += v; break; default : return(-3); } #if 0 /* This stuff is to implement input files under PMON. It is not clear * whether something like this is possible under IMON. For the moment * I have disabled it. */ if (flags&DL_TFLAG) { if (getGpr(7) == 0) { topClientMem -= addr; putGpr(29,clienttos()); tbase = topClientMem-addr; putGpr(7,topClientMem); } addr += tbase; } else addr += offset; #else addr += offset; #endif p = &p[i+4]; len -= (i/2)+1; /* substract address and chksum fields from length */ for (i=0;i nextaddr) nextaddr = addr; return(0); } /************************************************************* * writec(fd,ch) */ writec(fd,ch) int fd; Uchar ch; { write(fd,&ch,1); } /************************************************************* * dlsym(p,offset,flags) * handle S4 records, i.e., symbols */ int dlsym(Uchar *p,ADDR offset,int flags) { Uchar val; ADDR adr; int len,csum; Uchar name[LINESZ],*t; /* S4LLAAAAAAAANNNNNNNN,AAAAAAAANNNNNN,AAAAAAAANNNNNNNNNN,CC LL=length AAAAAAAA=addr NNNN,=name CC=checksum */ if (flags&DL_DFLAG) return(0); /* ignore syms if loading a driver */ p += 2; /* skip past S4 */ if (!gethex(&len,p,2)) return(1); p += 2; /* skip past length */ for (;len > 2;) { if (!gethex(&adr,p,8)) return(2); p += 8; /* skip past addr */ len -= 8; t = (Uchar *)strchr(p,','); if (t == 0) return(1); strNcpy(name,p,t-p); len -= t-p; if (!newsym(name,adr+offset)) return(3); p = t+1; } if (!gethex(&csum,p,2)) return(4); /* csum neither generated nor checked */ return(0); } /************************************************************* * endrec(p,offset,flags) * handle the S-record termination record */ int endrec(Uchar *p,ADDR offset,int flags) { ADDR adr; switch (p[1]) { case '7' : if (!gethex(&adr,&p[4],8)) return(-1); break; case '8' : if (!gethex(&adr,&p[4],6)) return(-1); break; case '9' : if (!gethex(&adr,&p[4],4)) return(-1); break; } if (!(flags&DL_DFLAG)) putPc(adr+offset); return(0); } /************************************************************* * ADDR getHighLoadAdr() */ ADDR getHighLoadAdr() { return nextaddr; }