diff --git a/ChangeLog b/ChangeLog index a0bf033e..7f42c7fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2021-11-12 Joerg Wunsch + + Submitted by Martino Facchin: + patch #9110: Let reserved fuse bits to be read as *don't care* + * avr.c (compare_memory_masked): New function + * libavrdude.h: declare compare_memory_masked(); also, insist on C99 + so is required now + * main.c: Use compare_memory_masked() in safemode comparisons + 2021-11-11 Joerg Wunsch Submitted by Joseph Coffland: diff --git a/NEWS b/NEWS index 4875ddbd..791d9750 100644 --- a/NEWS +++ b/NEWS @@ -104,6 +104,7 @@ Current: patch #9697: Add iseavrprog support patch #10017: uspasp / tpi: Automatically clear configuration byte (fuse) before writing it patch #8957: Allow reading prodsig memory from stk500v2 on xmega devices + patch #9110: Let reserved fuse bits to be read as *don't care* * Internals: - New avrdude.conf keyword "family_id", used to verify SIB attributes diff --git a/avr.c b/avr.c index 0f2ae79a..4091b497 100644 --- a/avr.c +++ b/avr.c @@ -1063,6 +1063,30 @@ int avr_signature(PROGRAMMER * pgm, AVRPART * p) return 0; } +static uint8_t get_fuse_bitmask(AVRMEM * m) { + uint8_t bitmask_r = 0; + uint8_t bitmask_w = 0; + int i; + + if (!m || m->size > 1) { + // not a fuse, compare bytes directly + return 0xFF; + } + + // For fuses, only compare bytes that are actually written *and* read. + for (i = 0; i < 32; i++) { + if (m->op[AVR_OP_WRITE]->bit[i].type == AVR_CMDBIT_INPUT) + bitmask_w |= (1 << m->op[AVR_OP_WRITE]->bit[i].bitno); + if (m->op[AVR_OP_READ]->bit[i].type == AVR_CMDBIT_OUTPUT) + bitmask_r |= (1 << m->op[AVR_OP_READ]->bit[i].bitno); + } + return bitmask_r & bitmask_w; +} + +int compare_memory_masked(AVRMEM * m, uint8_t b1, uint8_t b2) { + uint8_t bitmask = get_fuse_bitmask(m); + return (b1 & bitmask) != (b2 & bitmask); +} /* * Verify the memory buffer of p with that of v. The byte range of v, @@ -1109,11 +1133,30 @@ int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size) for (i=0; itags[i] & TAG_ALLOCATED) != 0 && buf1[i] != buf2[i]) { - avrdude_message(MSG_INFO, "%s: verification error, first mismatch at byte 0x%04x\n" - "%s0x%02x != 0x%02x\n", - progname, i, - progbuf, buf1[i], buf2[i]); - return -1; + uint8_t bitmask = get_fuse_bitmask(a); + if((buf1[i] & bitmask) != (buf2[i] & bitmask)) { + // Mismatch is not just in unused bits + avrdude_message(MSG_INFO, "%s: verification error, first mismatch at byte 0x%04x\n" + "%s0x%02x != 0x%02x\n", + progname, i, + progbuf, buf1[i], buf2[i]); + return -1; + } else { + // Mismatch is only in unused bits + if ((buf1[i] | bitmask) != 0xff) { + // Programmer returned unused bits as 0, must be the part/programmer + avrdude_message(MSG_INFO, "%s: WARNING: ignoring mismatch in unused bits of \"%s\"\n" + "%s(0x%02x != 0x%02x). To prevent this warning fix the part\n" + "%sor programmer definition in the config file.\n", + progname, memtype, progbuf, buf1[i], buf2[i], progbuf); + } else { + // Programmer returned unused bits as 1, must be the user + avrdude_message(MSG_INFO, "%s: WARNING: ignoring mismatch in unused bits of \"%s\"\n" + "%s(0x%02x != 0x%02x). To prevent this warning set unused bits\n" + "%sto 1 when writing (double check with your datasheet first).\n", + progname, memtype, progbuf, buf1[i], buf2[i], progbuf); + } + } } } diff --git a/libavrdude.h b/libavrdude.h index b80ad797..1f0b7fcd 100644 --- a/libavrdude.h +++ b/libavrdude.h @@ -33,11 +33,7 @@ #include typedef uint32_t pinmask_t; #else -#if UINT_MAX >= 0xFFFFFFFF -typedef unsigned int pinmask_t; -#else -typedef unsigned long pinmask_t; -#endif +#error Need a C99 capable compiler #endif @@ -342,6 +338,9 @@ typedef void (*walk_avrparts_cb)(const char *name, const char *desc, void *cookie); void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie); void sort_avrparts(LISTID avrparts); + +int compare_memory_masked(AVRMEM * m, uint8_t buf1, uint8_t buf2); + #ifdef __cplusplus } #endif diff --git a/main.c b/main.c index aa91ae16..0dd9d7ad 100644 --- a/main.c +++ b/main.c @@ -1300,8 +1300,11 @@ int main(int argc, char * argv []) } } + AVRMEM * m; + /* Now check what fuses are against what they should be */ - if (safemodeafter_fuse != safemode_fuse) { + m = avr_locate_mem(p, "fuse"); + if (compare_memory_masked(m, safemodeafter_fuse, safemode_fuse)) { fuses_updated = 1; avrdude_message(MSG_INFO, "%s: safemode: fuse changed! Was %x, and is now %x\n", progname, safemode_fuse, safemodeafter_fuse); @@ -1329,7 +1332,8 @@ int main(int argc, char * argv []) } /* Now check what fuses are against what they should be */ - if (safemodeafter_lfuse != safemode_lfuse) { + m = avr_locate_mem(p, "lfuse"); + if (compare_memory_masked(m, safemodeafter_lfuse, safemode_lfuse)) { fuses_updated = 1; avrdude_message(MSG_INFO, "%s: safemode: lfuse changed! Was %x, and is now %x\n", progname, safemode_lfuse, safemodeafter_lfuse); @@ -1357,7 +1361,8 @@ int main(int argc, char * argv []) } /* Now check what fuses are against what they should be */ - if (safemodeafter_hfuse != safemode_hfuse) { + m = avr_locate_mem(p, "hfuse"); + if (compare_memory_masked(m, safemodeafter_hfuse, safemode_hfuse)) { fuses_updated = 1; avrdude_message(MSG_INFO, "%s: safemode: hfuse changed! Was %x, and is now %x\n", progname, safemode_hfuse, safemodeafter_hfuse); @@ -1382,7 +1387,8 @@ int main(int argc, char * argv []) } /* Now check what fuses are against what they should be */ - if (safemodeafter_efuse != safemode_efuse) { + m = avr_locate_mem(p, "efuse"); + if (compare_memory_masked(m, safemodeafter_efuse, safemode_efuse)) { fuses_updated = 1; avrdude_message(MSG_INFO, "%s: safemode: efuse changed! Was %x, and is now %x\n", progname, safemode_efuse, safemodeafter_efuse); @@ -1410,7 +1416,7 @@ int main(int argc, char * argv []) avrdude_message(MSG_INFO, "%s: safemode: ", progname); if (failures == 0) { avrdude_message(MSG_INFO, "Fuses OK (E:%02X, H:%02X, L:%02X)\n", - safemode_efuse, safemode_hfuse, safemode_lfuse); + safemodeafter_efuse, safemodeafter_hfuse, safemodeafter_lfuse); } else { avrdude_message(MSG_INFO, "Fuses not recovered, sorry\n");