Skip to content

Commit 7eab60d

Browse files
committed
Avoid fail when reading reserved fuse bits
1 parent 1cefe33 commit 7eab60d

File tree

2 files changed

+208
-1
lines changed

2 files changed

+208
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
--- avr.c
2+
+++ avr.c
3+
@@ -1058,6 +1058,33 @@ int avr_signature(PROGRAMMER * pgm, AVRPART * p)
4+
return 0;
5+
}
6+
7+
+uint8_t get_fuse_bitmask(AVRMEM * m) {
8+
+ uint8_t bitmask_r = 0;
9+
+ uint8_t bitmask_w = 0;
10+
+ int i, j;
11+
+ for (i=0; i<AVR_OP_MAX; i++) {
12+
+ if (m->op[i] && strcmp(avr_op_str(i),"READ") == 0) {
13+
+ for (j=7; j>=0; j--) {
14+
+ bitmask_r |= (strcmp(bittype(m->op[i]->bit[j].type), "IGNORE") != 0) << j;
15+
+ }
16+
+ }
17+
+ if (m->op[i] && strcmp(avr_op_str(i),"WRITE") == 0) {
18+
+ for (j=7; j>=0; j--) {
19+
+ bitmask_w |= (strcmp(bittype(m->op[i]->bit[j].type), "VALUE") != 0 &&
20+
+ strcmp(bittype(m->op[i]->bit[j].type), "IGNORE") != 0) << j;
21+
+ }
22+
+ }
23+
+ }
24+
+ return bitmask_r & bitmask_w;
25+
+}
26+
+
27+
+int skip_fuse_memory_masked(AVRMEM * m, unsigned char buf1, unsigned char buf2) {
28+
+ if (m->size > 1) {
29+
+ return 1;
30+
+ }
31+
+ uint8_t bitmask = get_fuse_bitmask(m);
32+
+ return ((buf1 & bitmask) != (buf2 & bitmask));
33+
+}
34+
35+
/*
36+
* Verify the memory buffer of p with that of v. The byte range of v,
37+
@@ -1103,7 +1130,7 @@ int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size)
38+
39+
for (i=0; i<size; i++) {
40+
if ((b->tags[i] & TAG_ALLOCATED) != 0 &&
41+
- buf1[i] != buf2[i]) {
42+
+ (buf1[i] != buf2[i]) && (skip_fuse_memory_masked(a , buf1[i], buf2[i]))) {
43+
avrdude_message(MSG_INFO, "%s: verification error, first mismatch at byte 0x%04x\n"
44+
"%s0x%02x != 0x%02x\n",
45+
progname, i,
46+
--- avrpart.c
47+
+++ avrpart.c
48+
@@ -205,7 +205,7 @@ int avr_get_output_index(OPCODE * op)
49+
}
50+
51+
52+
-static char * avr_op_str(int op)
53+
+char * avr_op_str(int op)
54+
{
55+
switch (op) {
56+
case AVR_OP_READ : return "READ"; break;
57+
@@ -225,7 +225,7 @@ static char * avr_op_str(int op)
58+
}
59+
60+
61+
-static char * bittype(int type)
62+
+char * bittype(int type)
63+
{
64+
switch (type) {
65+
case AVR_CMDBIT_IGNORE : return "IGNORE"; break;
66+
@@ -405,7 +405,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
67+
m->readback[1]);
68+
if (verbose > 4) {
69+
avrdude_message(MSG_TRACE2, "%s Memory Ops:\n"
70+
- "%s Oeration Inst Bit Bit Type Bitno Value\n"
71+
+ "%s Operation Inst Bit Bit Type Bitno Value\n"
72+
"%s ----------- -------- -------- ----- -----\n",
73+
prefix, prefix, prefix);
74+
for (i=0; i<AVR_OP_MAX; i++) {
75+
--- libavrdude.h
76+
+++ libavrdude.h
77+
@@ -297,6 +297,7 @@ typedef struct avrmem {
78+
79+
unsigned char * buf; /* pointer to memory buffer */
80+
unsigned char * tags; /* allocation tags */
81+
+ unsigned char * mask; /* mask tags */
82+
OPCODE * op[AVR_OP_MAX]; /* opcodes */
83+
} AVRMEM;
84+
85+
@@ -337,6 +338,12 @@ typedef void (*walk_avrparts_cb)(const char *name, const char *desc,
86+
void *cookie);
87+
void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie);
88+
void sort_avrparts(LISTID avrparts);
89+
+
90+
+
91+
+char * avr_op_str(int op);
92+
+char * bittype(int type);
93+
+uint8_t get_fuse_bitmask(AVRMEM * m);
94+
+
95+
#ifdef __cplusplus
96+
}
97+
#endif
98+
@@ -818,7 +825,7 @@ amount of times before giving up */
99+
int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, AVRPART * p, int tries);
100+
101+
/* Reads the fuses three times, checking that all readings are the same. This will ensure that the before values aren't in error! */
102+
-int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, PROGRAMMER * pgm, AVRPART * p);
103+
+int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, unsigned char * efuse_mask, PROGRAMMER * pgm, AVRPART * p);
104+
105+
/* This routine will store the current values pointed to by lfuse, hfuse, and efuse into an internal buffer in this routine
106+
when save is set to 1. When save is 0 (or not 1 really) it will copy the values from the internal buffer into the locations
107+
--- main.c
108+
+++ main.c
109+
@@ -344,6 +344,7 @@ int main(int argc, char * argv [])
110+
unsigned char safemode_lfuse = 0xff;
111+
unsigned char safemode_hfuse = 0xff;
112+
unsigned char safemode_efuse = 0xff;
113+
+ unsigned char safemode_efuse_mask = 0xff;
114+
unsigned char safemode_fuse = 0xff;
115+
116+
char * safemode_response;
117+
@@ -1131,7 +1132,7 @@ int main(int argc, char * argv [])
118+
and extended fuse bytes as needed */
119+
120+
rc = safemode_readfuses(&safemode_lfuse, &safemode_hfuse,
121+
- &safemode_efuse, &safemode_fuse, pgm, p);
122+
+ &safemode_efuse, &safemode_fuse, &safemode_efuse_mask, pgm, p);
123+
124+
if (rc != 0) {
125+
126+
@@ -1239,6 +1240,7 @@ int main(int argc, char * argv [])
127+
unsigned char safemodeafter_lfuse = 0xff;
128+
unsigned char safemodeafter_hfuse = 0xff;
129+
unsigned char safemodeafter_efuse = 0xff;
130+
+ unsigned char safemodeafter_efuse_mask = 0xff;
131+
unsigned char safemodeafter_fuse = 0xff;
132+
unsigned char failures = 0;
133+
char yes[1] = {'y'};
134+
@@ -1252,16 +1254,15 @@ int main(int argc, char * argv [])
135+
136+
/* Try reading back fuses, make sure they are reliable to read back */
137+
if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
138+
- &safemodeafter_efuse, &safemodeafter_fuse, pgm, p) != 0) {
139+
+ &safemodeafter_efuse, &safemodeafter_fuse, &safemodeafter_efuse_mask, pgm, p) != 0) {
140+
/* Uh-oh.. try once more to read back fuses */
141+
if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
142+
- &safemodeafter_efuse, &safemodeafter_fuse, pgm, p) != 0) {
143+
+ &safemodeafter_efuse, &safemodeafter_fuse, &safemodeafter_efuse_mask, pgm, p) != 0) {
144+
avrdude_message(MSG_INFO, "%s: safemode: Sorry, reading back fuses was unreliable. "
145+
"I have given up and exited programming mode\n",
146+
progname);
147+
exitrc = 1;
148+
- goto main_exit;
149+
- }
150+
+ goto main_exit; }
151+
}
152+
153+
/* Now check what fuses are against what they should be */
154+
@@ -1346,7 +1347,7 @@ int main(int argc, char * argv [])
155+
}
156+
157+
/* Now check what fuses are against what they should be */
158+
- if (safemodeafter_efuse != safemode_efuse) {
159+
+ if ((safemodeafter_efuse & safemodeafter_efuse_mask) != (safemode_efuse & safemodeafter_efuse_mask)) {
160+
fuses_updated = 1;
161+
avrdude_message(MSG_INFO, "%s: safemode: efuse changed! Was %x, and is now %x\n",
162+
progname, safemode_efuse, safemodeafter_efuse);
163+
--- safemode.c
164+
+++ safemode.c
165+
@@ -75,7 +75,7 @@ int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm,
166+
* same. This will ensure that the before values aren't in error!
167+
*/
168+
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
169+
- unsigned char * efuse, unsigned char * fuse,
170+
+ unsigned char * efuse, unsigned char * fuse, unsigned char * efuse_mask,
171+
PROGRAMMER * pgm, AVRPART * p)
172+
{
173+
174+
@@ -85,12 +85,14 @@ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
175+
unsigned char safemode_lfuse;
176+
unsigned char safemode_hfuse;
177+
unsigned char safemode_efuse;
178+
+ unsigned char safemode_efuse_mask;
179+
unsigned char safemode_fuse;
180+
AVRMEM * m;
181+
182+
safemode_lfuse = *lfuse;
183+
safemode_hfuse = *hfuse;
184+
safemode_efuse = *efuse;
185+
+ safemode_efuse_mask = *efuse_mask;
186+
safemode_fuse = *fuse;
187+
188+
189+
@@ -229,8 +231,10 @@ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
190+
/* Read efuse three times */
191+
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
192+
to generate a verify error */
193+
+
194+
m = avr_locate_mem(p, "efuse");
195+
if (m != NULL) {
196+
+ safemode_efuse_mask = get_fuse_bitmask(m);
197+
fusegood = 0; /* By default fuse is a failure */
198+
if (pgm->read_byte(pgm, p, m, 0, &safemode_efuse) != 0)
199+
{
200+
@@ -272,6 +276,7 @@ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
201+
*lfuse = safemode_lfuse;
202+
*hfuse = safemode_hfuse;
203+
*efuse = safemode_efuse;
204+
+ *efuse_mask = safemode_efuse_mask;
205+
*fuse = safemode_fuse;
206+
207+
return 0;

Diff for: package-avrdude.bash

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# along with this program; if not, write to the Free Software
1616
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1717

18-
OUTPUT_VERSION=6.3-arduino2
18+
OUTPUT_VERSION=6.3.0-arduino4
1919

2020
export OS=`uname -o || uname`
2121
export TARGET_OS=$OS

0 commit comments

Comments
 (0)