2 #define F_CPU 1000000UL /* 1 Mhz-Takt; hier richtigen Wert eintragen */
5 #include "../firmware/spminterface.h"
6 #include "usbasploader.h"
8 // activate updaters full set of features
9 #ifndef CONFIG_UPDATER_REDUCEWRITES
10 #define CONFIG_UPDATER_REDUCEWRITES
13 #ifndef CONFIG_UPDATER_CLEANMEMCLEAR
14 #define CONFIG_UPDATER_CLEANMEMCLEAR
19 #include <avr/interrupt.h>
22 #include <avr/pgmspace.h>
26 #include <util/delay.h>
29 #define updater_pagefillcode ((1<<SPMEN))
30 #define updater_pageerasecode ((1<<PGERS) | (1<<SPMEN))
31 #define updater_pagewritecode ((1<<PGWRT) | (1<<SPMEN))
34 #include "../firmware/bootloaderconfig.h"
35 #if !HAVE_SPMINTEREFACE
36 #error "bootloader does not support updating itself! (HAVE_SPMINTEREFACE)"
39 // helpful definitions and makros ////
41 #ifndef NEW_BOOTLOADER_ADDRESS
42 #error "where should the new bootloader be positioned?"
47 #if (NEW_BOOTLOADER_ADDRESS != (funcaddr___bootloader__do_spm-(funcaddr___bootloader__do_spm % SPM_PAGESIZE)))
48 #warning the new bootloader seems to be located elsewhere, than the current one!
51 #ifndef NEW_SPM_ADDRESS
52 #warning I do not know where new "bootloader__do_spm" is located - assuming "NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE)"
53 #define NEW_SPM_ADDRESS (NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE))
56 // TEMP_SPM supports up to 4 pages for "bootloader__do_spm"...
57 #define TEMP_SPM_NUMPAGE 4
58 #define TEMP_SPM_BLKSIZE (TEMP_SPM_NUMPAGE*SPM_PAGESIZE)
59 #ifndef TEMP_SPM_PAGEADR
60 #warning "TEMP_SPM_PAGEADR" is not defined explicitly - will choose END OF FLASH !
61 #define TEMP_SPM_PAGEADR ((FLASHEND+1) - TEMP_SPM_BLKSIZE)
63 #define TEMP_SPM_ADDRESS ((TEMP_SPM_PAGEADR) + (funcaddr___bootloader__do_spm % SPM_PAGESIZE))
66 #if (NEW_SPM_ADDRESS == funcaddr___bootloader__do_spm)
67 #define new_do_spm do_spm
69 void new_do_spm(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
) {
70 __do_spm_Ex(flash_byteaddress
, spmcrval
, dataword
, NEW_SPM_ADDRESS
>> 1);
74 void temp_do_spm(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
) {
75 __do_spm_Ex(flash_byteaddress
, spmcrval
, dataword
, TEMP_SPM_ADDRESS
>> 1);
80 // some important consistency checks ////
82 //check if "NEW_BOOTLOADER_ADDRESS" is page-aligned
83 #if (NEW_BOOTLOADER_ADDRESS % SPM_PAGESIZE != 0)
84 #error "NEW_BOOTLOADER_ADDRESS" is not aligned to pages!
87 //check, if NEW_SPM_ADDRESS is an even address
88 #if ((NEW_SPM_ADDRESS % 2) != 0)
89 #error NEW_SPM_ADDRESS must be an even address, since it contains executable code!
94 //check, if TEMP_SPM somehow overlaps with old SPM
95 #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)))
96 #error TEMP_SPM_ADDRESS overlaps "funcaddr___bootloader__do_spm"!
99 //check, if TEMP_SPM somehow overlaps with new SPM
100 #if (((TEMP_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE) >= NEW_SPM_ADDRESS) && (TEMP_SPM_ADDRESS <= (NEW_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE)))
101 #error TEMP_SPM_ADDRESS overlaps "NEW_SPM_ADDRESS"!
104 //check, if TEMP_SPM_ADDRESS is an even address
105 #if ((TEMP_SPM_ADDRESS % 2) != 0)
106 #error TEMP_SPM_ADDRESS must be an even address, since it contains executable code!
109 //check, if TEMP_SPM_ADDRESS fits into flash
110 #if ((TEMP_SPM_PAGEADR + TEMP_SPM_BLKSIZE) > (FLASHEND+1))
111 #error TEMP_SPM_ADDRESS exceeds flashend!
114 //check if size too low
115 #if (SIZEOF_new_firmware <= (TEMP_SPM_BLKSIZE + (NEW_SPM_ADDRESS - NEW_BOOTLOADER_ADDRESS)))
116 #error empty firmware!
119 //check if size too high
120 #if (SIZEOF_new_firmware > ((FLASHEND+1)-NEW_BOOTLOADER_ADDRESS))
121 #error firmware too big! firmware does not fit into flash memory!
127 * in this case a near address
129 typedef uint32_t mypgm_addr_t
;
130 typedef void (*mypgm_spminterface
)(const uint32_t flash_byteaddress
, const uint8_t spmcrval
, const uint16_t dataword
);
133 # define mymemcpy_PF mymemcpy_PF_far
134 void *mymemcpy_PF_far (void *dest
, mypgm_addr_t src
, size_t n
) {
135 uint8_t *pagedata
= (void*)dest
;
136 mypgm_addr_t pageaddr
= src
;
140 pagedata
[i
]=pgm_read_byte_far(pageaddr
);
147 # define mymemcpy_PF memcpy_PF
151 size_t mypgm_readpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
) {
152 size_t result
= (bufferbytesize
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
;
153 size_t pagesize
= result
>> 1;
154 uint16_t *pagedata
= (void*)buffer
;
155 mypgm_addr_t pageaddr
= byteaddress
- (byteaddress
% SPM_PAGESIZE
);
158 for (i
=0;i
<pagesize
;i
+=1) {
159 pagedata
[i
]=pgm_read_word_far(pageaddr
);
166 // replace it somehow with "memcpy_PF" in order to save some ops...
167 size_t mypgm_readpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
) {
168 size_t result
= (bufferbytesize
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
;
169 mypgm_addr_t pageaddr
= byteaddress
- (byteaddress
% SPM_PAGESIZE
);
171 mymemcpy_PF((void*)buffer
, (uint_farptr_t
)pageaddr
, result
);
177 #ifdef CONFIG_UPDATER_REDUCEWRITES
178 size_t mypgm_WRITEpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
, mypgm_spminterface spmfunc
) {
179 size_t result
= (bufferbytesize
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
;
180 size_t pagesize
= result
>> 1;
181 uint16_t *pagedata
= (void*)buffer
;
182 mypgm_addr_t pageaddr_bakup
= byteaddress
- (byteaddress
% SPM_PAGESIZE
);
183 mypgm_addr_t pageaddr
= pageaddr_bakup
;
185 uint8_t changed
=0, needs_erase
=0;
189 // just check, if page needs a rewrite or an erase...
190 for (i
=0;i
<pagesize
;i
+=1) {
191 #if (FLASHEND > 65535)
192 deeword
=pgm_read_word_far(pageaddr
);
194 deeword
=pgm_read_word(pageaddr
);
197 if (deeword
!= pagedata
[i
]) changed
=1;
208 * ==> /(/x * y) ==> x + /y
210 deeword
|= ~pagedata
[i
];
211 if ((~deeword
) != 0) needs_erase
=1;
219 //do a page-erase, ATTANTION: flash only can be erased a limited number of times !
220 spmfunc(pageaddr_bakup
, updater_pageerasecode
, 0);
223 // from now on, the page is assumed empty !! (hopefully our code is located somewhere else!)
224 // now, fill the tempoary buffer
225 // ATTANTION: see comment on "do_spm" !
226 pageaddr
= pageaddr_bakup
;
227 for (i
=0;i
<pagesize
;i
+=1) {
228 spmfunc(pageaddr
, updater_pagefillcode
, pagedata
[i
]);
232 // so, now finally write the page to the FLASH
233 spmfunc(pageaddr_bakup
, updater_pagewritecode
, 0);
235 // no change - no write...
243 size_t mypgm_WRITEpage(const mypgm_addr_t byteaddress
,const void* buffer
, const size_t bufferbytesize
, mypgm_spminterface spmfunc
) {
244 size_t result
= (bufferbytesize
< SPM_PAGESIZE
)?bufferbytesize
:SPM_PAGESIZE
;
245 size_t pagesize
= result
>> 1;
246 uint16_t *pagedata
= (void*)buffer
;
247 mypgm_addr_t pageaddr_bakup
= byteaddress
- (byteaddress
% SPM_PAGESIZE
);
248 mypgm_addr_t pageaddr
= pageaddr_bakup
;
252 //do a page-erase, ATTANTION: flash only can be erased a limited number of times !
253 spmfunc(pageaddr_bakup
, updater_pageerasecode
, 0);
255 // from now on, the page is assumed empty !! (hopefully our code is located somewhere else!)
256 // now, fill the tempoary buffer
257 // ATTANTION: see comment on "do_spm" !
258 pageaddr
= pageaddr_bakup
;
259 for (i
=0;i
<pagesize
;i
+=1) {
260 spmfunc(pageaddr
, updater_pagefillcode
, pagedata
[i
]);
264 // so, now finally write the page to the FLASH
265 spmfunc(pageaddr_bakup
, updater_pagewritecode
, 0);
271 // #pragma GCC diagnostic ignored "-Wno-pointer-to-int-cast"
275 uint8_t buffer
[SPM_PAGESIZE
];
280 // check if firmware would change...
282 for (i
=0;i
<SIZEOF_new_firmware
;i
+=2) {
284 #if (FLASHEND > 65535)
285 a
=pgm_read_word_far((void*)&new_firmware
[i
]);
286 b
=pgm_read_word_far(NEW_BOOTLOADER_ADDRESS
+i
);
288 a
=pgm_read_word((void*)&new_firmware
[i
]);
289 b
=pgm_read_word(NEW_BOOTLOADER_ADDRESS
+i
);
299 // need to change the firmware...
303 // copy the current "bootloader__do_spm" to tempoary position via std. "bootloader__do_spm"
304 for (i
=0;i
<TEMP_SPM_BLKSIZE
;i
+=SPM_PAGESIZE
) {
305 mypgm_WRITEpage(TEMP_SPM_PAGEADR
+i
, buffer
, mypgm_readpage(funcaddr___bootloader__do_spm
+i
, buffer
, sizeof(buffer
)), do_spm
);
309 // start updating the firmware to "NEW_BOOTLOADER_ADDRESS" until at least "TEMP_SPM_BLKSIZE"-bytes after "NEW_SPM_ADDRESS" were written
310 // therefore use the tempoary "bootloader__do_spm" (since we most probably will overwrite the default do_spm)
311 for (i
=0;;i
+=SPM_PAGESIZE
) {
312 #ifdef CONFIG_UPDATER_CLEANMEMCLEAR
313 memset((void*)buffer
, 0xff, sizeof(buffer
));
315 mymemcpy_PF((void*)buffer
, (uint_farptr_t
)((void*)&new_firmware
[i
]), ((SIZEOF_new_firmware
-i
)>sizeof(buffer
))?
sizeof(buffer
):(SIZEOF_new_firmware
-i
));
317 mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS
+i
, buffer
, sizeof(buffer
), temp_do_spm
);
319 if ((NEW_BOOTLOADER_ADDRESS
+i
) > (NEW_SPM_ADDRESS
+TEMP_SPM_BLKSIZE
)) break;
323 // continue writeing the new_firmware after "NEW_SPM_ADDRESS+TEMP_SPM_BLKSIZE" this time use the "new_do_spm"
324 for (;i
<SIZEOF_new_firmware
;i
+=SPM_PAGESIZE
) {
325 #ifdef CONFIG_UPDATER_CLEANMEMCLEAR
326 memset((void*)buffer
, 0xff, sizeof(buffer
));
328 mymemcpy_PF((void*)buffer
, (uint_farptr_t
)((void*)&new_firmware
[i
]), ((SIZEOF_new_firmware
-i
)>sizeof(buffer
))?
sizeof(buffer
):(SIZEOF_new_firmware
-i
));
330 mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS
+i
, buffer
, sizeof(buffer
), new_do_spm
);