diff --git a/optiboot/bootloaders/optiboot/Makefile b/optiboot/bootloaders/optiboot/Makefile index c9779b3..4ccc676 100644 --- a/optiboot/bootloaders/optiboot/Makefile +++ b/optiboot/bootloaders/optiboot/Makefile @@ -236,6 +236,15 @@ endif # Test platforms # Virtual boot block test +virboot8: TARGET = atmega8 +virboot8: MCU_TARGET = atmega8 +virboot8: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' +virboot8: AVR_FREQ ?= 16000000L +virboot8: LDSECTIONS = -Wl,--section-start=.text=0x1c00 -Wl,--section-start=.version=0x1ffe +virboot8: $(PROGRAM)_virboot8.hex +virboot8: $(PROGRAM)_virboot8.lst + + virboot328: TARGET = atmega328 virboot328: MCU_TARGET = atmega328p virboot328: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' diff --git a/optiboot/bootloaders/optiboot/optiboot.c b/optiboot/bootloaders/optiboot/optiboot.c index 3554d9e..432e32f 100644 --- a/optiboot/bootloaders/optiboot/optiboot.c +++ b/optiboot/bootloaders/optiboot/optiboot.c @@ -388,25 +388,41 @@ void appStart(uint8_t rstFlags) __attribute__ ((naked)); /* These definitions are NOT zero initialised, but that doesn't matter */ /* This allows us to drop the zero init code, saving us memory */ #define buff ((uint8_t*)(RAMSTART)) + +/* Virtual boot partition support */ #ifdef VIRTUAL_BOOT_PARTITION #define rstVect0_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+4)) #define rstVect1_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+5)) -#define wdtVect0_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+6)) -#define wdtVect1_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+7)) +#define saveVect0_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+6)) +#define saveVect1_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+7)) +// Vector to save original reset jump - SPM Ready is least probably used +#if defined (SPM_RDY_vect_num) +#define save_vect_num (SPM_RDY_vect_num) +#elif defined (SPM_READY_vect_num) +#define save_vect_num (SPM_READY_vect_num) +#else +#error Cant find SPM interrupt vector for this CPU +#endif +// check if it's on the same page (code assumes that) +#if (SPM_PAGESIZE <= save_vect_num) +#error Save vector not in the same page as reset! +#endif #if FLASHEND > 8192 // AVRs with more than 8k of flash have 4-byte vectors, and use jmp. +// We save only 16 bits of address, so devices with more than 128KB +// may behave wrong for upper part of address space. #define rstVect0 2 #define rstVect1 3 -#define wdtVect0 (WDT_vect_num*4+2) -#define wdtVect1 (WDT_vect_num*4+3) -#define appstart_vec (WDT_vect_num*2) +#define saveVect0 (save_vect_num*4+2) +#define saveVect1 (save_vect_num*4+3) +#define appstart_vec (save_vect_num*2) #else // AVRs with up to 8k of flash have 2-byte vectors, and use rjmp. #define rstVect0 0 #define rstVect1 1 -#define wdtVect0 (WDT_vect_num*2) -#define wdtVect1 (WDT_vect_num*2+1) -#define appstart_vec (WDT_vect_num) +#define saveVect0 (save_vect_num*2) +#define saveVect1 (save_vect_num*2+1) +#define appstart_vec (save_vect_num) #endif #else #define appstart_vec (0) @@ -561,6 +577,7 @@ int main(void) { #if FLASHEND > 8192 /* * AVR with 4-byte ISR Vectors and "jmp" + * WARNING: this works only up to 128KB flash! */ if (address == 0) { // This is the reset vector page. We need to live-patch the @@ -569,14 +586,15 @@ int main(void) { // Save jmp targets (for "Verify") rstVect0_sav = buff[rstVect0]; rstVect1_sav = buff[rstVect1]; - wdtVect0_sav = buff[wdtVect0]; - wdtVect1_sav = buff[wdtVect1]; + saveVect0_sav = buff[saveVect0]; + saveVect1_sav = buff[saveVect1]; - // Move RESET jmp target to WDT vector - buff[wdtVect0] = rstVect0_sav; - buff[wdtVect1] = rstVect1_sav; + // Move RESET jmp target to 'save' vector + buff[saveVect0] = rstVect0_sav; + buff[saveVect1] = rstVect1_sav; // Add jump to bootloader at RESET vector + // WARNING: this works as long as 'main' is in first section buff[rstVect0] = ((uint16_t)main) & 0xFF; buff[rstVect1] = ((uint16_t)main) >> 8; } @@ -589,22 +607,23 @@ int main(void) { // This is the reset vector page. We need to live-patch // the code so the bootloader runs first. // - // Move RESET vector to WDT vector + // Move RESET vector to 'save' vector // Save jmp targets (for "Verify") rstVect0_sav = buff[rstVect0]; rstVect1_sav = buff[rstVect1]; - wdtVect0_sav = buff[wdtVect0]; - wdtVect1_sav = buff[wdtVect1]; + saveVect0_sav = buff[saveVect0]; + saveVect1_sav = buff[saveVect1]; // Instruction is a relative jump (rjmp), so recalculate. - uint16_t vect=rstVect0_sav+(rstVect1_sav<<8); - vect -= WDT_vect_num; - // Move RESET jmp target to WDT vector - buff[wdtVect0] = vect & 0xff; - buff[wdtVect1] = vect >> 8; + uint16_t vect=(rstVect0_sav & 0xff) | ((rstVect1_sav & 0x0f)<<8); //calculate 12b displacement + vect = (vect-save_vect_num) & 0x0fff; //substract 'save' interrupt position and wrap around 4096 + // Move RESET jmp target to 'save' vector + buff[saveVect0] = vect & 0xff; + buff[saveVect1] = (vect >> 8) | 0xc0; // // Add rjump to bootloader at RESET vector - buff[0] = (((uint16_t)main) & 0xFFF) & 0xFF; // rjmp 0x1d00 instruction - buff[1] = ((((uint16_t)main) & 0xFFF) >> 8) | 0xC0; + vect = ((uint16_t)main) &0x0fff; //WARNIG: this works as long as 'main' is in first section + buff[0] = vect & 0xFF; // rjmp 0x1c00 instruction + buff[1] = (vect >> 8) | 0xC0; } #endif // FLASHEND #endif // VBP @@ -812,7 +831,7 @@ void appStart(uint8_t rstFlags) { // Note that appstart_vec is defined so that this works with either // real or virtual boot partitions. __asm__ __volatile__ ( - // Jump to WDT or RST vector + // Jump to 'save' or RST vector "ldi r30,%[rstvec]\n" "clr r31\n" "ijmp\n"::[rstvec] "M"(appstart_vec) @@ -905,8 +924,8 @@ static inline void read_mem(uint8_t memtype, uint16_t address, pagelen_t length) // Undo vector patch in bottom page so verify passes if (address == rstVect0) ch = rstVect0_sav; else if (address == rstVect1) ch = rstVect1_sav; - else if (address == wdtVect0) ch = wdtVect0_sav; - else if (address == wdtVect1) ch = wdtVect1_sav; + else if (address == saveVect0) ch = saveVect0_sav; + else if (address == saveVect1) ch = saveVect1_sav; else ch = pgm_read_byte_near(address); address++; #elif defined(RAMPZ)