diff --git a/src/avrdude.1 b/src/avrdude.1 index 5d90c4fc..54f44d52 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -1405,10 +1405,24 @@ On writing to flash do not store the application input filename (nor a title). .It Ar nodate On writing to flash do not store the application input filename (nor a title) and no date either. +.It Ar nostore +On writing to flash do not store metadata except the metadata code byte +0xff saying there are no metadata. In particular, no data store frame is +programmed. .It Ar nometadata -On writing to flash do not store any metadata. The full flash below the -bootloader is available for the application. In particular, no data store -frame is programmed. +Do not support any metadata. The full flash besides the bootloader is +available for the application. If the application is smaller than the +available space then a metadata code byte 0xff is stored nevertheless to +indicate there are no further metadata available. In absence of +-xnometadata, the default for the urclock programmer is to write as much +metadata (filename, data and store information) as the size of the +uploaded application and the other extended options allow. The subtle +difference between -xnometadata and -xnostore is that the latter always +explicitly stores in flash that no further metadata are available, so that +a such prepared flash can always be queried with +.Nm +-xshowall. In contrast to this, it cannot be guaranteed that a -xshowall +query on flash prepared with -xnometadata yields useful results. .It Ar delay= Add a ms delay after reset. This can be useful if a board takes a particularly long time to exit from external reset. can be negative, diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index a37a6d82..b74ce613 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -1166,10 +1166,24 @@ On writing to flash do not store the application input filename (nor a title). @item @samp{nodate} On writing to flash do not store the application input filename (nor a title) and no date either. -@item @samp{nometadata} -On writing to flash do not store any metadata. The full flash below the -bootloader is available for the application. In particular, no data store +@item @samp{nostore} +On writing to flash do not store metadata except the metadata code byte +@code{0xff} saying there are no metadata. In particular, no data store frame is programmed. +@item @samp{nometadata} +Do not support any metadata. The full flash besides the bootloader is +available for the application. If the application is smaller than the +available space then a metadata code byte @code{0xff} is stored +nevertheless to indicate there are no further metadata available. In +absence of @code{-xnometadata}, the default for the urclock programmer is +to write as much metadata (filename, data and store information) as the +size of the uploaded application and the other extended options allow. The +subtle difference between @code{-xnometadata} and @code{-xnostore} is that +the latter always explicitly stores in flash that no further metadata are +available, so that a such prepared flash can always be queried with +@code{avrdude -xshowall}. In contrast to this, it cannot be guaranteed +that a @code{-xshowall} query on flash prepared with @code{-xnometadata} +yields useful results. @item @samp{delay=} Add a ms delay after reset. This can be useful if a board takes a particularly long time to exit from external reset. can be negative, diff --git a/src/fileio.c b/src/fileio.c index 482bb3a6..ef90ac4a 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -290,8 +290,8 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec) * by outbuf. The size of outbuf, 'bufsize' is honored; if data would * fall outsize of the memory buffer outbuf, an error is generated. * - * Return the maximum memory address within 'outbuf' that was written. - * If an error occurs, return -1. + * Return the maximum memory address within 'outbuf' that was written + * plus one. If an error occurs, return -1. * * */ static int ihex2b(const char *infile, FILE *inf, diff --git a/src/urclock.c b/src/urclock.c index abd6932a..3f2f6377 100644 --- a/src/urclock.c +++ b/src/urclock.c @@ -315,7 +315,8 @@ typedef struct { restore, // Restore a flash backup exactly as it is trimming the bootloader nofilename, // Don't store application filename when writing the application nodate, // Don't store application filename and no date either - nometadata, // Don't store any metadata at all (implies no store support) + nostore, // Don't store metadata except a flag saying so + nometadata, // Don't support metadata at all delay, // Additional delay [ms] after resetting the board, can be negative strict; // Use strict synchronisation protocol @@ -334,7 +335,7 @@ static int nmeta(int mcode, int flashsize) { // The size of the structure that holds info about metadata (sits just below bootloader) int nheader = 2*(flashsize > (1<<16)? 4: 2) + 1; - return mcode == 0xff? 0: // No metadata at all + return mcode == 0xff? 1: // No metadata except 0xff byte itself saying no further metadata mcode > 1? mcode+6+nheader: // Application filename, app date and structure for pgm store mcode? 6+nheader: // Application date and structure describing pgm store nheader; // Structure describing pgm store @@ -610,16 +611,17 @@ static int set_reset(const PROGRAMMER *pgm, unsigned char *jmptoboot, int vecsz) // Called after the input file has been read for writing or verifying flash static int urclock_flash_readhook(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *flm, - const char *fname, int size) { + const char *fname, int size) { // size is max memory address + 1 int nmdata, maxsize, firstbeg, firstlen; int vecsz = ur.uP.flashsize <= 8192? 2: 4; // Small parts use rjmp, large parts need 4-byte jmp set_date_filename(pgm, fname); - // Record how extensive the metadata should be, given the command line options (default: all) - ur.mcode = ur.nometadata? 0xff: ur.nodate? 0: ur.nofilename? 1: strlen(ur.filename)+1; - nmdata = nmeta(ur.mcode, ur.uP.flashsize); + // Record extent of metadata, given the command line options (default: max possible) + ur.mcode = ur.nometadata || ur.nostore? 0xff: + ur.nodate? 0: ur.nofilename? 1: strlen(ur.filename)+1; + nmdata = ur.nometadata? 0: nmeta(ur.mcode, ur.uP.flashsize); maxsize = ur.pfend+1; @@ -652,21 +654,43 @@ static int urclock_flash_readhook(const PROGRAMMER *pgm, const AVRPART *p, const ur.blstart, ur.blend, flm->size-1); // Check size of uploded application and protect bootloader from being overwritten - if((ur.boothigh && size > ur.pfend+1) || (!ur.boothigh && firstbeg <= ur.blend)) + if((ur.boothigh && size > maxsize) || (!ur.boothigh && firstbeg <= ur.blend)) Return("input [0x%04x, 0x%04x] overlaps bootloader [0x%04x, 0x%04x]", firstbeg, size-1, ur.blstart, ur.blend); - if(nmdata >= nmeta(0, ur.uP.flashsize) && size > ur.pfend+1 - nmeta(0, ur.uP.flashsize)) - Return("input [0x%04x, 0x%04x] overlaps metadata [0x%04x, 0x%04x], consider -xnometadata", - firstbeg, size-1, ur.pfend+1-nmeta(0, ur.uP.flashsize), ur.pfend); + if(size > maxsize) + Return("input [0x%04x, 0x%04x] extends programmable area [0x%04x, 0x%04x]", + firstbeg, size-1, ur.pfstart, ur.pfend); - if(nmdata >= nmeta(1, ur.uP.flashsize) && size > ur.pfend+1 - nmeta(1, ur.uP.flashsize)) - Return("input [0x%04x, 0x%04x] overlaps metadata [0x%04x, 0x%04x], consider -xnodate", - firstbeg, size-1, ur.pfend+1-nmeta(1, ur.uP.flashsize), ur.pfend); + if(!ur.nometadata) { + if(size == maxsize) + Return("input [0x%04x, 0x%04x] overlaps metadata code byte at 0x%04x, consider -xnometadata", + firstbeg, size-1, ur.pfend); - if(size > ur.pfend+1 - nmdata) - Return("input [0x%04x, 0x%04x] overlaps metadata [0x%04x, 0x%04x], consider -xnofilename", - firstbeg, size-1, ur.pfend+1-nmdata, ur.pfend); + if(nmdata >= nmeta(0, ur.uP.flashsize) && size > maxsize - nmeta(0, ur.uP.flashsize)) { + pmsg_warning("input [0x%04x, 0x%04x] overlaps metadata [0x%04x, 0x%04x], selecting -xnostore\n", + firstbeg, size-1, maxsize-nmdata, ur.pfend); + ur.mcode = 0xff; + ur.nostore = 1; + nmdata = 1; + } + + if(nmdata >= nmeta(1, ur.uP.flashsize) && size > maxsize - nmeta(1, ur.uP.flashsize)) { + pmsg_warning("input [0x%04x, 0x%04x] overlaps metadata [0x%04x, 0x%04x], selecting -xnodate\n", + firstbeg, size-1, maxsize-nmdata, ur.pfend); + ur.mcode = 0; + ur.nodate = 1; + nmdata = nmeta(0, ur.uP.flashsize); + } + + if(size > maxsize - nmdata) { + pmsg_warning("input [0x%04x, 0x%04x] overlaps metadata [0x%04x, 0x%04x], selecting -xnofilename\n", + firstbeg, size-1, maxsize-nmdata, ur.pfend); + ur.mcode = 1; + ur.nofilename = 1; + nmdata = nmeta(1, ur.uP.flashsize); + } + } if(!ur.boothigh) goto nopatch; @@ -736,53 +760,56 @@ static int urclock_flash_readhook(const PROGRAMMER *pgm, const AVRPART *p, const nopatch: if(nmdata) { - int32_t nfree = ur.pfend+1 - size; + int32_t nfree = maxsize - size; if(nfree >= nmdata) { - unsigned char *p = flm->buf + ur.pfend+1 - nmdata; + unsigned char *p = flm->buf + maxsize - nmdata; - if(ur.mcode > 1) { // Save filename (ur.mcode cannot be 0xff b/c nmdata is non-zero) - memcpy(p, ur.filename, ur.mcode); - p += ur.mcode; + if(ur.mcode != 0xff) { + if(ur.mcode > 1) { // Save filename + memcpy(p, ur.filename, ur.mcode); + p += ur.mcode; + } + + if(ur.mcode >= 1) { // Save date + *p++ = ur.yyyy; + *p++ = ur.yyyy>>8; + *p++ = ur.mm; + *p++ = ur.dd; + *p++ = ur.hr; + *p++ = ur.mn; + } + + *p++ = size; // Save where the pgm store begins + *p++ = size >> 8; + if(ur.uP.flashsize > (1<<16)) { + *p++ = size >> 16; + *p++ = size >> 24; + } + + nfree -= nmdata; + *p++ = nfree; // Save how much is free + *p++ = nfree >> 8; + if(ur.uP.flashsize > (1<<16)) { + *p++ = nfree >> 16; + *p++ = nfree >> 24; + } } - if(ur.mcode >= 1) { // Save date - *p++ = ur.yyyy; - *p++ = ur.yyyy>>8; - *p++ = ur.mm; - *p++ = ur.dd; - *p++ = ur.hr; - *p++ = ur.mn; - } - - *p++ = size; // Save where the pgm store begins - *p++ = size >> 8; - if(ur.uP.flashsize > (1<<16)) { - *p++ = size >> 16; - *p++ = size >> 24; - } - - nfree -= nmdata; - *p++ = nfree; // Save how much is free - *p++ = nfree >> 8; - if(ur.uP.flashsize > (1<<16)) { - *p++ = nfree >> 16; - *p++ = nfree >> 24; - } - *p++ = ur.mcode; + *p++ = ur.mcode; // Save metadata code // Set tags so metadata get burned onto chip - memset(flm->tags + ur.pfend+1 - nmdata, TAG_ALLOCATED, nmdata); + memset(flm->tags + maxsize - nmdata, TAG_ALLOCATED, nmdata); if(ur.initstore) // Zap the pgm store memset(flm->tags + size, TAG_ALLOCATED, nfree); - size = ur.pfend+1; + size = maxsize; } } - // Storing no metadata: put a 0xff byte just below bootloader - if(size < ur.pfend+1 && nmdata == 0) { + // Storing no metadata? Still put a 0xff byte just below bootloader if there is space + if(size < maxsize && nmdata == 0) { flm->buf[ur.pfend] = 0xff; flm->tags[ur.pfend] = TAG_ALLOCATED; size = ur.pfend+1; @@ -796,7 +823,7 @@ nopatch_nometa: if(ur_readEF(pgm, p, &devmcode, ur.pfend, 1, 'F') == 0) { int devnmeta=nmeta(devmcode, ur.uP.flashsize); for(int addr=ur.pfend+1-devnmeta; addr < ur.pfend+1; addr++) { - if(addr >=0 && addr < flm->size && !(flm->tags[addr] & TAG_ALLOCATED)) { + if(addr >= 0 && addr < flm->size && !(flm->tags[addr] & TAG_ALLOCATED)) { flm->tags[addr] |= TAG_ALLOCATED; flm->buf[addr] = 0xff; } @@ -1523,7 +1550,9 @@ vblvecfound: urbootPutVersion(pgm, ur.desc, v16, rjmpwp); ur.mcode = 0xff; - if(ur.pfend >= nmeta(254, flm->size)) { + int havemetadata = !ur.nometadata; + + if(havemetadata && ur.pfend >= nmeta(254, flm->size)) { int nm = nmeta(1, ur.uP.flashsize); // 6 for date + size of store struct + 1 for mcode byte // Showing properties mostly requires examining the bytes below bootloader for metadata if(ur.showall || (ur.showid && *ur.iddesc && *ur.iddesc != 'E') || ur.showapp || @@ -1540,11 +1569,14 @@ vblvecfound: int nmdata = nmeta(mcode, ur.uP.flashsize); // Check plausibility of metadata header just below bootloader + havemetadata = 0; if(storestart > 0 && storestart == ur.pfend+1-nmdata-storesize) { ur.storestart = storestart; ur.storesize = storesize; ur.mcode = mcode; - if(mcode) { + if(!mcode) { + havemetadata = 1; + } else { int16_t yyyy; int8_t mm, dd, hr, mn; mn = spc[5]; @@ -1562,6 +1594,7 @@ vblvecfound: ur.dd = dd; ur.hr = hr; ur.mn = mn; + havemetadata = 1; if(mcode > 1) { // Copy application name over rc = ur_readEF(pgm, p, spc, ur.pfend+1-nmeta(mcode, ur.uP.flashsize), mcode, 'F'); if(rc < 0) @@ -1577,7 +1610,6 @@ vblvecfound: } } - // Print and exit when option show... was given int first=1; int single = !ur.showall && (!!ur.showid + !!ur.showapp + !!ur.showstore + !!ur.showmeta + @@ -1590,23 +1622,41 @@ vblvecfound: return rc; term_out("%0*lx", 2*ur.idlen, urclockID), first=0; } - if(ur.showdate || ur.showall) - term_out(&" %04d-%02d-%02d %02d.%02d"[first], ur.yyyy, ur.mm, ur.dd, ur.hr, ur.mn), first=0; - if(ur.showfilename || ur.showall) - term_out(&" %s"[first], *ur.filename? ur.filename: ""), first=0; - if(ur.showapp || ur.showall) - term_out(&" %s%d"[first], single || *ur.filename? "": "application ", ur.storestart), first=0; - if(ur.showstore || ur.showall) - term_out(&" %s%d"[first], single? "": "store ", ur.storesize), first=0; - if(ur.showmeta || ur.showall) - term_out(&" %s%d"[first], single? "": "meta ", nmeta(ur.mcode, ur.uP.flashsize)), first=0; - if(ur.showboot || ur.showall) - term_out(&" %s%d"[first], single? "": "boot ", ur.blend>ur.blstart? ur.blend-ur.blstart+1: 0), first=0; - if(ur.showversion || ur.showall) - term_out(&" %s"[first], ur.desc+(*ur.desc==' ')), first=0; + if(havemetadata) { + if(ur.showdate || ur.showall) { + term_out(&" %04d-%02d-%02d %02d.%02d"[first], ur.yyyy, ur.mm, ur.dd, ur.hr, ur.mn); + first=0; + } + if(ur.showfilename || ur.showall) { + term_out(&" %s"[first], *ur.filename? ur.filename: ""); + first=0; + } + if(ur.showapp || ur.showall) { + term_out(&" %s%d"[first], single || *ur.filename? "": "application ", ur.storestart); + first=0; + } + if(ur.showstore || ur.showall) { + term_out(&" %s%d"[first], single? "": "store ", ur.storesize); + first=0; + } + } + if(ur.showmeta || ur.showall) { + int nmdata = havemetadata? nmeta(ur.mcode, ur.uP.flashsize): 0; + term_out(&" %s%d"[first], single? "": "meta ", nmdata); + first=0; + } + if(ur.showboot || ur.showall) { + term_out(&" %s%d"[first], single? "": "boot ", ur.blend>ur.blstart? ur.blend-ur.blstart+1: 0); + first=0; + } + if(ur.showversion || ur.showall) { + term_out(&" %s"[first], ur.desc+(*ur.desc==' ')); + first=0; + } if(ur.showvector || ur.showall) { int vnum = ur.vbllevel? ur.vblvectornum & 0x7f: 0; - term_out(&" vector %d (%s)"[first], vnum, vblvecname(pgm, vnum)), first=0; + term_out(&" vector %d (%s)"[first], vnum, vblvecname(pgm, vnum)); + first=0; } if(ur.showall || ur.showpart) term_out(&" %s"[first], ur.uP.name); @@ -2466,7 +2516,8 @@ static int urclock_parseextparms(const PROGRAMMER *pgm, LISTID extparms) { //@@@ {"copystore", &ur.copystore, NA, "Copy over store on writing to flash"}, {"nofilename", &ur.nofilename, NA, "Do not store filename on writing to flash"}, {"nodate", &ur.nodate, NA, "Do not store application filename and no date either"}, - {"nometadata", &ur.nometadata, NA, "Do not store metadata at all (ie, no store support)"}, + {"nostore", &ur.nostore, NA, "Do not store metadata except a flag saying so"}, + {"nometadata", &ur.nometadata, NA, "Do not support metadata at all"}, {"delay", &ur.delay, ARG, "Add delay [ms] after reset, can be negative"}, {"strict", &ur.strict, NA, "Use strict synchronisation protocol"}, {"help", &help, NA, "Show this help menu and exit"},