2 #define F_CPU 1000000UL /* 1 Mhz-Takt; hier richtigen Wert eintragen */
6 #include "../misc/iofixes.h"
7 #include "../firmware/spminterface.h"
8 #include "usbasploader.h"
10 // activate updaters full set of features
11 #ifndef CONFIG_UPDATER_REDUCEWRITES
12 #define CONFIG_UPDATER_REDUCEWRITES
15 #ifndef CONFIG_UPDATER_CLEANMEMCLEAR
16 #define CONFIG_UPDATER_CLEANMEMCLEAR
20 #include <avr/interrupt.h>
23 #include <avr/pgmspace.h>
27 #include <util/delay.h>
30 #define updater_pagefillcode ((1<<SPMEN))
31 #define updater_pageerasecode ((1<<PGERS) | (1<<SPMEN))
32 #define updater_pagewritecode ((1<<PGWRT) | (1<<SPMEN))
35 #include "../firmware/bootloaderconfig.h"
36 #if !HAVE_SPMINTEREFACE
37 #error "bootloader does not support updating itself! (HAVE_SPMINTEREFACE)"
40 // helpful definitions and makros ////
42 #ifndef NEW_BOOTLOADER_ADDRESS
43 #error "where should the new bootloader be positioned?"
48 #if (NEW_BOOTLOADER_ADDRESS != (funcaddr___bootloader__do_spm-(funcaddr___bootloader__do_spm % SPM_PAGESIZE)))
49 #warning the new bootloader seems to be located elsewhere, than the current one!
52 #ifndef NEW_SPM_ADDRESS
53 #warning I do not know where new "bootloader__do_spm" is located - assuming "NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE)"
54 #define NEW_SPM_ADDRESS (NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE))
57 // TEMP_SPM supports up to 4 pages for "bootloader__do_spm"...
58 #define TEMP_SPM_NUMPAGE 4
59 #define TEMP_SPM_BLKSIZE (TEMP_SPM_NUMPAGE*SPM_PAGESIZE)
60 #ifndef TEMP_SPM_PAGEADR
61 #warning "TEMP_SPM_PAGEADR" is not defined explicitly - will choose END OF FLASH !
62 #define TEMP_SPM_PAGEADR ((FLASHEND+1) - TEMP_SPM_BLKSIZE)
64 #define TEMP_SPM_ADDRESS ((TEMP_SPM_PAGEADR) + (funcaddr___bootloader__do_spm % SPM_PAGESIZE))
67 #if (NEW_SPM_ADDRESS == funcaddr___bootloader__do_spm)
68 #define new_do_spm do_spm
70 void new_do_spm(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
) {
71 __do_spm_Ex(flash_byteaddress
, spmcrval
, dataword
, NEW_SPM_ADDRESS
>> 1);
75 void temp_do_spm(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
) {
76 __do_spm_Ex(flash_byteaddress
, spmcrval
, dataword
, TEMP_SPM_ADDRESS
>> 1);
81 // some important consistency checks ////
83 //check if "NEW_BOOTLOADER_ADDRESS" is page-aligned
84 #if (NEW_BOOTLOADER_ADDRESS % SPM_PAGESIZE != 0)
85 #error "NEW_BOOTLOADER_ADDRESS" is not aligned to pages!
88 //check, if NEW_SPM_ADDRESS is an even address
89 #if ((NEW_SPM_ADDRESS % 2) != 0)
90 #error NEW_SPM_ADDRESS must be an even address, since it contains executable code!
95 //check, if TEMP_SPM somehow overlaps with old SPM
96 #if (((TEMP_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE) >= funcaddr___bootloader__do_spm) && (TEMP_SPM_ADDRESS <= (funcaddr___bootloader__do_spm + TEMP_SPM_BLKSIZE + SPM_PAGESIZE)))
97 #error TEMP_SPM_ADDRESS overlaps "funcaddr___bootloader__do_spm"!
100 //check, if TEMP_SPM somehow overlaps with new SPM
101 #if (((TEMP_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE) >= NEW_SPM_ADDRESS) && (TEMP_SPM_ADDRESS <= (NEW_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE)))
102 #error TEMP_SPM_ADDRESS overlaps "NEW_SPM_ADDRESS"!
105 //check, if TEMP_SPM_ADDRESS is an even address
106 #if ((TEMP_SPM_ADDRESS % 2) != 0)
107 #error TEMP_SPM_ADDRESS must be an even address, since it contains executable code!
110 //check, if TEMP_SPM_ADDRESS fits into flash
111 #if ((TEMP_SPM_PAGEADR + TEMP_SPM_BLKSIZE) > (FLASHEND+1))
112 #error TEMP_SPM_ADDRESS exceeds flashend!
115 //check if size too low
116 #if (SIZEOF_new_firmware <= (TEMP_SPM_BLKSIZE + (NEW_SPM_ADDRESS - NEW_BOOTLOADER_ADDRESS)))
117 #error empty firmware!
120 //check if size too high
121 #if (SIZEOF_new_firmware > ((FLASHEND+1)-NEW_BOOTLOADER_ADDRESS))
122 #error firmware too big! firmware does not fit into flash memory!
128 * in this case a near address
130 typedef uint32_t mypgm_addr_t
;
131 typedef void (*mypgm_spminterface
)(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
);
134 # define FULLCORRECTFLASHADDRESS(addr) (((mypgm_addr_t)(addr)) | (((mypgm_addr_t)FLASHADDRESS) & ((mypgm_addr_t)0xffff0000)))
135 # define mymemcpy_PF mymemcpy_PF_far
136 void *mymemcpy_PF_far (void *dest
, mypgm_addr_t src
, size_t n
) {
137 uint8_t *pagedata
= (void*)dest
;
138 mypgm_addr_t pageaddr
= src
;
142 pagedata
[i
]=pgm_read_byte_far(pageaddr
);
149 # define FULLCORRECTFLASHADDRESS(addr) (addr)
150 # define mymemcpy_PF memcpy_PF
154 size_t mypgm_readpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
) {
155 size_t result
= (bufferbytesize
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
;
156 size_t pagesize
= result
>> 1;
157 uint16_t *pagedata
= (void*)buffer
;
158 mypgm_addr_t pageaddr
= byteaddress
- (byteaddress
% SPM_PAGESIZE
);
161 for (i
=0;i
<pagesize
;i
+=1) {
162 pagedata
[i
]=pgm_read_word_far(pageaddr
);
169 // replace it somehow with "memcpy_PF" in order to save some ops...
170 size_t mypgm_readpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
) {
171 size_t result
= (bufferbytesize
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
;
172 mypgm_addr_t pageaddr
= byteaddress
- (byteaddress
% SPM_PAGESIZE
);
174 mymemcpy_PF((void*)buffer
, (uint_farptr_t
)pageaddr
, result
);
180 #ifdef CONFIG_UPDATER_REDUCEWRITES
181 size_t mypgm_WRITEpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
, mypgm_spminterface spmfunc
) {
182 size_t result
= (bufferbytesize
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
;
183 size_t pagesize
= result
>> 1;
184 uint16_t *pagedata
= (void*)buffer
;
185 mypgm_addr_t pageaddr_bakup
= byteaddress
- (byteaddress
% SPM_PAGESIZE
);
186 mypgm_addr_t pageaddr
= pageaddr_bakup
;
188 uint8_t changed
=0, needs_erase
=0;
192 // just check, if page needs a rewrite or an erase...
193 for (i
=0;i
<pagesize
;i
+=1) {
194 #if (FLASHEND > 65535)
195 deeword
=pgm_read_word_far(pageaddr
);
197 deeword
=pgm_read_word(pageaddr
);
200 if (deeword
!= pagedata
[i
]) changed
=1;
211 * ==> /(/x * y) ==> x + /y
213 deeword
|= ~pagedata
[i
];
214 if ((~deeword
) != 0) needs_erase
=1;
222 //do a page-erase, ATTANTION: flash only can be erased a limited number of times !
223 spmfunc(pageaddr_bakup
, updater_pageerasecode
, 0);
226 // from now on, the page is assumed empty !! (hopefully our code is located somewhere else!)
227 // now, fill the tempoary buffer
228 // ATTANTION: see comment on "do_spm" !
229 pageaddr
= pageaddr_bakup
;
230 for (i
=0;i
<pagesize
;i
+=1) {
231 spmfunc(pageaddr
, updater_pagefillcode
, pagedata
[i
]);
235 // so, now finally write the page to the FLASH
236 spmfunc(pageaddr_bakup
, updater_pagewritecode
, 0);
238 // no change - no write...
246 size_t mypgm_WRITEpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
, mypgm_spminterface spmfunc
) {
247 size_t result
= (bufferbytesize
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
;
248 size_t pagesize
= result
>> 1;
249 uint16_t *pagedata
= (void*)buffer
;
250 mypgm_addr_t pageaddr_bakup
= byteaddress
- (byteaddress
% SPM_PAGESIZE
);
251 mypgm_addr_t pageaddr
= pageaddr_bakup
;
255 //do a page-erase, ATTANTION: flash only can be erased a limited number of times !
256 spmfunc(pageaddr_bakup
, updater_pageerasecode
, 0);
258 // from now on, the page is assumed empty !! (hopefully our code is located somewhere else!)
259 // now, fill the tempoary buffer
260 // ATTANTION: see comment on "do_spm" !
261 pageaddr
= pageaddr_bakup
;
262 for (i
=0;i
<pagesize
;i
+=1) {
263 spmfunc(pageaddr
, updater_pagefillcode
, pagedata
[i
]);
267 // so, now finally write the page to the FLASH
268 spmfunc(pageaddr_bakup
, updater_pagewritecode
, 0);
274 #if defined(UPDATECRC32)
275 #include "crccheck.c"
278 // #pragma GCC diagnostic ignored "-Wno-pointer-to-int-cast"
281 #if defined(UPDATECRC32)
285 uint8_t buffer
[SPM_PAGESIZE
];
290 #if defined(UPDATECRC32)
291 // check if new firmware-image is corrupted
293 for (i
=0;i
<SIZEOF_new_firmware
;i
+=1) {
294 #if (FLASHEND > 65535)
295 crcval
= update_crc_32(crcval
, pgm_read_byte_far(FULLCORRECTFLASHADDRESS(&new_firmware
[i
])));
297 crcval
= update_crc_32(crcval
, pgm_read_byte(FULLCORRECTFLASHADDRESS(&new_firmware
[i
])));
302 // allow to change the firmware
303 if (crcval
== ((uint32_t)UPDATECRC32
)) {
306 // check if firmware would change...
308 for (i
=0;i
<SIZEOF_new_firmware
;i
+=2) {
310 #if (FLASHEND > 65535)
311 a
=pgm_read_word_far(FULLCORRECTFLASHADDRESS(&new_firmware
[i
]));
312 b
=pgm_read_word_far(NEW_BOOTLOADER_ADDRESS
+i
);
314 a
=pgm_read_word(FULLCORRECTFLASHADDRESS(&new_firmware
[i
]));
315 b
=pgm_read_word(NEW_BOOTLOADER_ADDRESS
+i
);
325 // need to change the firmware...
329 // copy the current "bootloader__do_spm" to tempoary position via std. "bootloader__do_spm"
330 for (i
=0;i
<TEMP_SPM_BLKSIZE
;i
+=SPM_PAGESIZE
) {
331 mypgm_WRITEpage(TEMP_SPM_PAGEADR
+i
, buffer
, mypgm_readpage(funcaddr___bootloader__do_spm
+i
, buffer
, sizeof(buffer
)), do_spm
);
335 // start updating the firmware to "NEW_BOOTLOADER_ADDRESS" until at least "TEMP_SPM_BLKSIZE"-bytes after "NEW_SPM_ADDRESS" were written
336 // therefore use the tempoary "bootloader__do_spm" (since we most probably will overwrite the default do_spm)
337 for (i
=0;;i
+=SPM_PAGESIZE
) {
338 #ifdef CONFIG_UPDATER_CLEANMEMCLEAR
339 memset((void*)buffer
, 0xff, sizeof(buffer
));
341 mymemcpy_PF((void*)buffer
, (uint_farptr_t
)(FULLCORRECTFLASHADDRESS(&new_firmware
[i
])), ((SIZEOF_new_firmware
-i
)>sizeof(buffer
))?
sizeof(buffer
):(SIZEOF_new_firmware
-i
));
343 mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS
+i
, buffer
, sizeof(buffer
), temp_do_spm
);
345 if ((NEW_BOOTLOADER_ADDRESS
+i
) > (NEW_SPM_ADDRESS
+TEMP_SPM_BLKSIZE
)) break;
349 // continue writeing the new_firmware after "NEW_SPM_ADDRESS+TEMP_SPM_BLKSIZE" this time use the "new_do_spm"
350 for (;i
<SIZEOF_new_firmware
;i
+=SPM_PAGESIZE
) {
351 #ifdef CONFIG_UPDATER_CLEANMEMCLEAR
352 memset((void*)buffer
, 0xff, sizeof(buffer
));
354 mymemcpy_PF((void*)buffer
, (uint_farptr_t
)(FULLCORRECTFLASHADDRESS(&new_firmware
[i
])), ((SIZEOF_new_firmware
-i
)>sizeof(buffer
))?
sizeof(buffer
):(SIZEOF_new_firmware
-i
));
356 mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS
+i
, buffer
, sizeof(buffer
), new_do_spm
);
364 #if defined(UPDATECRC32)