From: Stephan Baerwolf Date: Tue, 10 Sep 2013 13:35:11 +0000 (+0200) Subject: introduce new feature: BOOTLOADERENTRY_FROMSOFTWARE X-Git-Tag: testing-head~27 X-Git-Url: http://git.linex4red.de/pub/USBaspLoader.git/commitdiff_plain/fdd80449610db4cccc152e17b04cdb51de578a61 introduce new feature: BOOTLOADERENTRY_FROMSOFTWARE An USBaspLoader supporting this feature is able to be called (and bootLoaderConditioned) from user firmware. You can check MCUCSR watchdog-flag to check for success. (If USBaspLoader starts up, all MCUCSR are removed...) You can use something like this code to switch to the bootloader: #define BOOTLOADER_WORDADDRESS (BOOTLOADER_ADDRESS>>1) wdt_enable(WDTO_15MS); asm volatile ( "ldi r29 , %[ramendhi] \n\t" "ldi r28 , %[ramendlo] \n\t" "ldi r16 , %[boothi] \n\t" "st Y+ , r16 \n\t" "ldi r16 , %[bootme] \n\t" "st Y+ , r16 \n\t" "ldi r16 , %[bootlo] \n\t" "st Y+ , r16 \n\t" "resetloop%=: \n\t" "rjmp resetloop%= \n\t" : : [ramendhi] "M" (((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M" (((RAMEND - 2) >> 0) & 0xff), [boothi] "M" (((BOOTLOADER_WORDADDRESS) >>16) & 0xff), [bootme] "M" (((BOOTLOADER_WORDADDRESS) >> 8) & 0xff), [bootlo] "M" (((BOOTLOADER_WORDADDRESS) >> 0) & 0xff) ); Signed-off-by: Stephan Baerwolf --- diff --git a/firmware/bootloaderconfig.h b/firmware/bootloaderconfig.h index 531ba97..9ca2cd1 100644 --- a/firmware/bootloaderconfig.h +++ b/firmware/bootloaderconfig.h @@ -312,6 +312,16 @@ these macros are defined, the boot loader usees them. * (except registers and IO), since RESET will NOT clear old RAM content. */ +#ifdef CONFIG_NO__BOOTLOADERENTRY_FROMSOFTWARE +# define HAVE_BOOTLOADERENTRY_FROMSOFTWARE 0 +#else +# define HAVE_BOOTLOADERENTRY_FROMSOFTWARE 1 +#endif +/* + * Enable firmware to boot the bootloader without + * user intervention + */ + //#define SIGNATURE_BYTES 0x1e, 0x93, 0x07, 0 /* ATMega8 */ /* This macro defines the signature bytes returned by the emulated USBasp to * the programmer software. They should match the actual device at least in @@ -357,7 +367,41 @@ static inline void bootLoaderExit(void) PIN_PORT(JUMPER_PORT) = 0; /* undo bootLoaderInit() changes */ } -#define bootLoaderCondition() ((PIN_PIN(JUMPER_PORT) & (1 << PIN(JUMPER_PORT, JUMPER_BIT))) == 0) + +#define bootLoaderConditionSimple() ((PIN_PIN(JUMPER_PORT) & (1 << PIN(JUMPER_PORT, JUMPER_BIT))) == 0) + +#if (HAVE_BOOTLOADERENTRY_FROMSOFTWARE) +/* + * How it works: The idea + * + * During normal C initialization, the stackpointer (SP) always is pointed to + * SRAMs end, where it grows towards RAMSTART. + * + * Check if last possible pushed address in stack is bootloaders address. + * Store investigation result into "__BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch" + * Result will be "0xff" in case of mismatch. + */ + +#include +#include + +#define __BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS (BOOTLOADER_ADDRESS>>1) +static volatile uint8_t __BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch __attribute__ ((section(".noinit"))); +static volatile uint8_t __BOOTLOADERENTRY_FROMSOFTWARE__bootup_MCUCSR __attribute__ ((section(".noinit"))); + +static inline bool bootLoaderCondition(void) +{ + if (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_MCUCSR & (_BV(WDRF))) { + if (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch == (__BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS & 0xff)) { + // anything else: match - the firmware is calling the bootloader + return true; + } + } + return bootLoaderConditionSimple(); +} +#else +#define bootLoaderCondition bootLoaderConditionSimple +#endif #endif /* __ASSEMBLER__ */ diff --git a/firmware/main.c b/firmware/main.c index 19c7756..99bbb20 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -196,6 +196,44 @@ static const uchar signatureBytes[4] = { /* ------------------------------------------------------------------------ */ +#if (HAVE_BOOTLOADERENTRY_FROMSOFTWARE) +void __attribute__ ((section(".init3"),naked,used,no_instrument_function)) __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND(void); +void __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND(void) { + asm volatile ( + "in %[mcucsrval] , %[mcucsrio]\n\t" + "ldi r29 , %[ramendhi]\n\t" + "ldi r28 , %[ramendlo]\n\t" +#if (FLASHEND>131071) + "ld %[result] , Y+\n\t" + "cpi %[result] , %[bootaddrhi]\n\t" + "brne __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_mismatch%=\n\t" +#endif + "ld %[result] , Y+\n\t" + "cpi %[result] , %[bootaddrme]\n\t" + "ld %[result] , Y+\n\t" + "breq __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_done%=\n\t" + + "__BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_mismatch%=:\n\t" + "ldi %[result] , 0xff\n\t" + + "__BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_done%=:\n\t" + : [result] "=a" (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch), + [mcucsrval] "=a" (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_MCUCSR) + : [mcucsrio] "I" (_SFR_IO_ADDR(MCUCSR)), +#if (FLASHEND>131071) + [ramendhi] "M" (((RAMEND - 2) >> 8) & 0xff), + [ramendlo] "M" (((RAMEND - 2) >> 0) & 0xff), + [bootaddrhi] "M" (((__BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS) >>16) & 0xff), +#else + [ramendhi] "M" (((RAMEND - 1) >> 8) & 0xff), + [ramendlo] "M" (((RAMEND - 1) >> 0) & 0xff), +#endif + [bootaddrme] "M" (((__BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS) >> 8) & 0xff) + + ); +} +#endif + #if (USE_BOOTUP_CLEARRAM) /* * Under normal circumstances, RESET will not clear contents of RAM. @@ -206,8 +244,10 @@ void __func_clearram(void) { extern size_t __bss_end; asm volatile ( "__clearram:\n\t" +#if (!(HAVE_BOOTLOADERENTRY_FROMSOFTWARE)) "ldi r29, %[ramendhi]\n\t" "ldi r28, %[ramendlo]\n\t" +#endif "__clearramloop%=:\n\t" "st -Y , __zero_reg__\n\t" "cp r28, %A[bssend]\n\t" @@ -692,11 +732,11 @@ asm volatile ( ); #else if (stayinloader >= 0x10) { - if (!bootLoaderCondition()) { + if (!bootLoaderConditionSimple()) { stayinloader-=0x10; } } else { - if (bootLoaderCondition()) { + if (bootLoaderConditionSimple()) { if (stayinloader > 1) stayinloader-=2; } }