Handle n_page_erase in urclock for parts t441, t841 and t1634

This commit is contained in:
Stefan Rueger 2022-11-11 01:33:42 +00:00
parent 6e3a99be87
commit b178deef5f
No known key found for this signature in database
GPG Key ID: B0B4F1FD86B1EC55
3 changed files with 85 additions and 64 deletions

View File

@ -71,7 +71,7 @@
# prog_modes = PM_<i/f> {| PM_<i/f>} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE # prog_modes = PM_<i/f> {| PM_<i/f>} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE
# mcuid = <num>; # unique id in 0..2039 for 8-bit AVRs # mcuid = <num>; # unique id in 0..2039 for 8-bit AVRs
# n_interrupts = <num>; # number of interrupts, used for vector bootloaders # n_interrupts = <num>; # number of interrupts, used for vector bootloaders
# n_page_erase = <num>; # if set, number of pages erased during NVM erase # n_page_erase = <num>; # if set, number of pages erased during SPM erase
# hvupdi_variant = <num> ; # numeric -1 (n/a) or 0..2 # hvupdi_variant = <num> ; # numeric -1 (n/a) or 0..2
# devicecode = <num> ; # deprecated, use stk500_devcode # devicecode = <num> ; # deprecated, use stk500_devcode
# stk500_devcode = <num> ; # numeric # stk500_devcode = <num> ; # numeric

View File

@ -1860,7 +1860,7 @@ part
prog_modes = PM_<i/f> @{| PM_<i/f>@} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE prog_modes = PM_<i/f> @{| PM_<i/f>@} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE
mcuid = <num>; # unique id in 0..2039 for 8-bit AVRs mcuid = <num>; # unique id in 0..2039 for 8-bit AVRs
n_interrupts = <num>; # number of interrupts, used for vector bootloaders n_interrupts = <num>; # number of interrupts, used for vector bootloaders
n_page_erase = <num>; # if set, number of pages erased during NVM erase n_page_erase = <num>; # if set, number of pages erased during SPM erase
hvupdi_variant = <num> ; # numeric -1 (n/a) or 0..2 hvupdi_variant = <num> ; # numeric -1 (n/a) or 0..2
devicecode = <num> ; # deprecated, use stk500_devcode devicecode = <num> ; # deprecated, use stk500_devcode
stk500_devcode = <num> ; # numeric stk500_devcode = <num> ; # numeric

View File

@ -757,55 +757,8 @@ nopatch_nometa:
ur.emulate_ce = 0; ur.emulate_ce = 0;
} }
if(!ur.done_ce) { // Unless chip erase was just issued (where all mem is 0xff)
if((ur.urprotocol && !(ur.urfeatures & UB_FLASH_LL_NOR)) ||
ur.bloptiversion ||
(ur.blurversion && ur.blurversion < 076)) {
int ai, addr, nset; // Ensure that vector bootloaders have correct r/jmp at address 0
// Scan the memory for pages with unset bytes and read these bytes from current chip flash
uint8_t spc[2048];
for(addr = 0; addr < maxsize; addr += ur.uP.pagesize) {
// How many bytes are set in this page?
for(ai = addr, nset = 0; ai < addr + ur.uP.pagesize; ai++)
if(flm->tags[ai] & TAG_ALLOCATED)
nset++;
// Holes in this page that needs writing? read them in from the chip
if(nset && nset != ur.uP.pagesize) {
// Identify a covering interval for all holes in page
int istart, isize;
// Lowest address with unset byte
for(ai = addr; flm->tags[ai] & TAG_ALLOCATED; ai++)
continue;
istart = ai;
// Highest address with unset byte
for(ai = addr + ur.uP.pagesize - 1; flm->tags[ai] & TAG_ALLOCATED; ai--)
continue;
isize = ai - istart + 1;
if(isize < 1 || isize > (int) sizeof spc) // Should not happen
Return("isize=%d out of range (enlarge spc[] and recompile)", isize);
if(ur_readEF(pgm, p, spc, istart, isize, 'F') == 0) {
for(ai = istart; ai < istart + isize; ai++)
if(!(flm->tags[ai] & TAG_ALLOCATED))
flm->buf[ai] = spc[ai-istart];
} else {
pmsg_notice2("cannot read flash [0x%04x, 0x%04x] to pad page bytes\n",
istart, istart+isize-1);
}
}
}
}
}
ur.done_ce = 0; // From now on can no longer rely on being deleted
// Last, but not least: ensure that vector bootloaders have correct r/jmp at address 0
if(ur.blstart && ur.vbllevel==1) { if(ur.blstart && ur.vbllevel==1) {
int rc, set=0; int rc, set=0;
for(int i=0; i < vecsz; i++) for(int i=0; i < vecsz; i++)
@ -829,24 +782,10 @@ nopatch_nometa:
if((rc = ur_readEF(pgm, p, device, 0, vecsz, 'F')) < 0) if((rc = ur_readEF(pgm, p, device, 0, vecsz, 'F')) < 0)
return rc; return rc;
int changed = 0;
for(int i=0; i < vecsz; i++) { for(int i=0; i < vecsz; i++) {
if((flm->tags[i] & TAG_ALLOCATED? flm->buf[i]: device[i]) != jmptoboot[i]) { if((flm->tags[i] & TAG_ALLOCATED? flm->buf[i]: device[i]) != jmptoboot[i]) {
flm->buf[i] = jmptoboot[i]; flm->buf[i] = jmptoboot[i];
flm->tags[i] |= TAG_ALLOCATED; flm->tags[i] |= TAG_ALLOCATED;
changed = 1;
}
}
// If reset vector patched, ensure to fill in the holes in rest of page
if(changed && flm->page_size > vecsz && flm->page_size <= sizeof device) {
pmsg_warning("patching reset vector to protect vector bootloader\n");
if((rc = ur_readEF(pgm, p, device+vecsz, vecsz, flm->page_size - vecsz, 'F')) < 0)
return rc;
for(int i=vecsz; i < flm->page_size; i++) {
if(!(flm->tags[i] & TAG_ALLOCATED)) {
flm->buf[i] = jmptoboot[i];
flm->tags[i] |= TAG_ALLOCATED;
}
} }
} }
} else { // Flash not readable: patch reset vector } else { // Flash not readable: patch reset vector
@ -870,6 +809,88 @@ nopatch_nometa:
} }
} }
// Effective page size, can be 4*pagesize for 4-page erase parts
int pgsize = p->n_page_erase > 0? p->n_page_erase*ur.uP.pagesize: ur.uP.pagesize;
if((pgsize & (pgsize-1)) || pgsize < 1 || pgsize > maxsize || maxsize % pgsize)
Return("effective page size %d implausible for size %d below bootloader", pgsize, maxsize);
if(!ur.done_ce) { // Unless chip erase was just issued (where all mem is 0xff)
if((ur.urprotocol && !(ur.urfeatures & UB_FLASH_LL_NOR)) || !ur.urprotocol) {
// Scan the memory for eff pages with unset bytes and read these bytes from device flash
int ai, npe, addr, nset;
uint8_t spc[2048];
for(addr = 0; addr < maxsize; addr += pgsize) {
// How many bytes are set in this effective page?
for(ai = addr, nset = 0; ai < addr + pgsize; ai++)
if(flm->tags[ai] & TAG_ALLOCATED)
nset++;
// Holes in this page that needs writing? read them in from the chip
if(nset && nset != pgsize) {
for(npe=0; npe < pgsize/ur.uP.pagesize; npe++) {
// Identify a covering interval for all holes in page
int istart, isize, beg, end;
beg = addr + npe*ur.uP.pagesize;
end = beg + ur.uP.pagesize;
// Lowest address with unset byte (there might be none)
for(ai = beg; ai < end; ai++)
if(!(flm->tags[ai] & TAG_ALLOCATED))
break;
istart = ai;
if(istart < end) {
// Highest address with unset byte
for(ai = end - 1; ai >= istart; ai--)
if(!(flm->tags[ai] & TAG_ALLOCATED))
break;
isize = ai - istart + 1;
if(isize < 1 || isize > (int) sizeof spc) // Should not happen
Return("isize=%d out of range (enlarge spc[] and recompile)", isize);
if(ur_readEF(pgm, p, spc, istart, isize, 'F') == 0) {
pmsg_debug("padding [0x%04x, 0x%04x]\n", istart, istart+isize-1);
for(ai = istart; ai < istart + isize; ai++)
if(!(flm->tags[ai] & TAG_ALLOCATED)) {
flm->tags[ai] |= TAG_ALLOCATED;
flm->buf[ai] = spc[ai-istart];
}
} else {
pmsg_notice2("cannot read flash [0x%04x, 0x%04x] to pad page bytes\n",
istart, istart+isize-1);
}
}
}
}
}
}
}
ur.done_ce = 0; // From now on can no longer rely on being deleted
// Fill remaining holes (chip was erased, could not be read or memory looks like NOR memory)
int ai, addr, nset;
for(addr = 0; addr < maxsize; addr += pgsize) {
for(ai = addr, nset = 0; ai < addr + pgsize; ai++)
if(flm->tags[ai] & TAG_ALLOCATED)
nset++;
if(nset && nset != pgsize) { // Page has holes: fill them
pmsg_debug("0xff padding page addr 0x%04d\n", addr);
for(ai = addr, nset = 0; ai < addr + pgsize; ai++)
if(!(flm->tags[ai] & TAG_ALLOCATED)) {
flm->tags[ai] |= TAG_ALLOCATED;
flm->buf[ai] = 0xff;
}
}
}
return size; return size;
} }