From: Stephan Baerwolf Date: Sun, 2 Sep 2012 11:30:23 +0000 (+0200) Subject: introduce first updater-functionalities using the do_spm X-Git-Tag: v0.5~1 X-Git-Url: http://git.linex4red.de/pub/USBaspLoader.git/commitdiff_plain/5b0272d9af73a164da192d796fc33ec736b93f0a?ds=inline introduce first updater-functionalities using the do_spm Signed-off-by: Stephan Baerwolf --- diff --git a/updater/Makefile b/updater/Makefile new file mode 100644 index 0000000..e1b1fbb --- /dev/null +++ b/updater/Makefile @@ -0,0 +1,78 @@ +# Name: Makefile +# Project: USBaspLoader (updater) +# Author: Stephan Bärwolf +# Creation Date: 2012-09-01 +# Tabsize: 4 +# License: GNU GPL v2 (see License.txt) + +include ../Makefile.inc + +# elsewise gcc would complain unnecessary +CFLAGS = -Wall -Wno-pointer-to-int-cast -Os -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) -DNEW_BOOTLOADER_ADDRESS=$(NEW_BOOTLOADER_ADDRESS) $(DEFINES) +LDFLAGS = -Wl,--relax,--gc-sections + +ifneq ($(FLASHADDRESS), 0) +ifneq ($(FLASHADDRESS), 00) +ifneq ($(FLASHADDRESS), 000) +ifneq ($(FLASHADDRESS), 0000) +ifneq ($(FLASHADDRESS), 00000) +ifneq ($(FLASHADDRESS), 0x0) +ifneq ($(FLASHADDRESS), 0x00) +ifneq ($(FLASHADDRESS), 0x000) +ifneq ($(FLASHADDRESS), 0x0000) +ifneq ($(FLASHADDRESS), 0x00000) +FLASHPREAMBLE = 0x0000 +LDFLAGS += -Wl,--section-start=.text=$(FLASHADDRESS) +endif +endif +endif +endif +endif +endif +endif +endif +endif +endif + +all: updater.hex + +../firmware/main.bin: + $(MAKE) -C ../firmware main.hex + +updater.o: updater.c firmware.h + $(CC) updater.c -c -o updater.o $(CFLAGS) + +updater.elf: updater.o + $(CC) updater.o -o updater.elf $(CFLAGS) $(LDFLAGS) + +updater.hex: updater.elf + $(OBC) -j .text -j .data -O ihex updater.elf updater.hex + $(ECHO) "." + avr-size updater.elf + $(ECHO) "." + $(AVRDUDE) -D -U flash:w:updater.hex:i + $(ECHO) "." + + + +firmware_gen.o: firmware_gen.c + $(GCC) firmware_gen.c -c -o firmware_gen.o + +firmware_gen: firmware_gen.o + $(GCC) firmware_gen.o -o firmware_gen + +firmware.h: firmware_gen ../firmware/main.bin + $(OBC) -j .text -j .data -O binary ../firmware/main.bin usbasploader.raw + @./firmware_gen > firmware.h + + +deepclean: clean + $(RM) *~ + +clean: + $(RM) *.o + $(RM) *.raw + $(RM) updater.hex + $(RM) updater.elf + $(RM) firmware_gen + $(RM) firmware.h \ No newline at end of file diff --git a/updater/firmware_gen.c b/updater/firmware_gen.c new file mode 100644 index 0000000..4707dd4 --- /dev/null +++ b/updater/firmware_gen.c @@ -0,0 +1,63 @@ + +#include +#include +#include + +#include + +#include +#include +#include + + +#define myfirmware_rawfilename "./usbasploader.raw" +#define myout stdout + +int main(int argc, char** argv) { + int fd; + uint16_t b; + uint64_t c; + struct stat fwstat; + + fprintf(myout, "\n"); + fprintf(myout, "#ifndef FIRMWARE_H_5f27a7e9840141b1aa57eef07c1d939f\n"); + fprintf(myout, "#define FIRMWARE_H_5f27a7e9840141b1aa57eef07c1d939f 1\n"); + fprintf(myout, "\n"); + fprintf(myout, "#include \n"); + fprintf(myout, "#include \n"); + fprintf(myout, "#include \"../firmware/spminterface.h\"\n"); + fprintf(myout, "\n"); + fprintf(myout, "//firmware generator generated\n"); + + fd=open(myfirmware_rawfilename, O_RDONLY); + if (fd > 2) { + fstat(fd, &fwstat); + fprintf(myout, "#define SIZEOF_new_firmware %llu\n",(long long unsigned int)fwstat.st_size); + fprintf(myout, "const uint16_t firmware[SIZEOF_new_firmware>>1] PROGMEM = {"); + fprintf(myout, "\n"); + + c=0; + while (read(fd, &b, 2) == 2) { + c+=2; + fprintf(myout,"0x%04x, ", (unsigned int)b); + if ((c % 20) == 0) fprintf(myout,"\n"); + } + if ((c % 20) != 0) fprintf(myout,"\n"); + fprintf(myout, "};\n"); + fprintf(myout, "const uint8_t *new_firmware = (void*)&firmware;\n"); + fprintf(myout, "\n"); + + close(fd); + } else { + fprintf(stderr, "error opening %s\n", myfirmware_rawfilename); + + fprintf(myout, "#define SIZEOF_new_firmware 0\n"); + fprintf(myout, "const uint16_t firmware[SIZEOF_new_firmware>>1] PROGMEM = {};\n"); + fprintf(myout, "const uint8_t *new_firmware = (void*)&firmware;\n"); + fprintf(myout, "\n"); + } + + fprintf(myout, "#endif\n"); + fprintf(myout, "\n"); + return 0; +} diff --git a/updater/updater.c b/updater/updater.c new file mode 100644 index 0000000..6b9cde3 --- /dev/null +++ b/updater/updater.c @@ -0,0 +1,317 @@ +#ifndef F_CPU + #define F_CPU 1000000UL /* 1 Mhz-Takt; hier richtigen Wert eintragen */ +#endif + +// 1) Test the "changed" - feature by debugging a LED-PIN to high (PB0?) +// 2) Test the "needs_erase" - feature by debugging a LED-PIN to high (PB1?) +// #define mypgmdebug 1 + +#include "../firmware/spminterface.h" +#include "firmware.h" + +#include +#include +#include + +#include + +#include + +#include +#include + + + +// helpful definitions and makros //// + +#ifndef NEW_BOOTLOADER_ADDRESS + #error "where should the new bootloader be positioned?" +#endif + + + +#if (NEW_BOOTLOADER_ADDRESS != (funcaddr___bootloader__do_spm-(funcaddr___bootloader__do_spm % SPM_PAGESIZE))) + #warning the new bootloader seems to be located elsewhere, than the current one! +#endif + +#ifndef NEW_SPM_ADDRESS + #warning I do not know where new "bootloader__do_spm" is located - assuming "NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE)" + #define NEW_SPM_ADDRESS (NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE)) +#endif + +// TEMP_SPM supports up to 4 pages for "bootloader__do_spm"... +#define TEMP_SPM_NUMPAGE 4 +#define TEMP_SPM_BLKSIZE (TEMP_SPM_NUMPAGE*SPM_PAGESIZE) +#ifndef TEMP_SPM_PAGEADR + #warning "TEMP_SPM_PAGEADR" is not defined explicitly - will choose END OF FLASH ! + #define TEMP_SPM_PAGEADR ((FLASHEND+1) - TEMP_SPM_BLKSIZE) +#endif +#define TEMP_SPM_ADDRESS ((TEMP_SPM_PAGEADR) + (funcaddr___bootloader__do_spm % SPM_PAGESIZE)) + + +#if (NEW_SPM_ADDRESS == funcaddr___bootloader__do_spm) + #define new_do_spm do_spm +#else +void new_do_spm(const uint32_t flash_byteaddress, const uint8_t spmcrval, const uint16_t dataword) { + __do_spm_Ex(flash_byteaddress, spmcrval, dataword, NEW_SPM_ADDRESS >> 1); +} +#endif + +void temp_do_spm(const uint32_t flash_byteaddress, const uint8_t spmcrval, const uint16_t dataword) { + __do_spm_Ex(flash_byteaddress, spmcrval, dataword, TEMP_SPM_ADDRESS >> 1); +} + + + +// some important consistency checks //// + +//check if "NEW_BOOTLOADER_ADDRESS" is page-aligned +#if (NEW_BOOTLOADER_ADDRESS % SPM_PAGESIZE != 0) + #error "NEW_BOOTLOADER_ADDRESS" is not aligned to pages! +#endif + +//check, if NEW_SPM_ADDRESS is an even address +#if ((NEW_SPM_ADDRESS % 2) != 0) + #error NEW_SPM_ADDRESS must be an even address, since it contains executable code! +#endif + + + +//check, if TEMP_SPM somehow overlaps with old SPM +#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))) + #error TEMP_SPM_ADDRESS overlaps "funcaddr___bootloader__do_spm"! +#endif + +//check, if TEMP_SPM somehow overlaps with new SPM +#if (((TEMP_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE) >= NEW_SPM_ADDRESS) && (TEMP_SPM_ADDRESS <= (NEW_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE))) + #error TEMP_SPM_ADDRESS overlaps "NEW_SPM_ADDRESS"! +#endif + +//check, if TEMP_SPM_ADDRESS is an even address +#if ((TEMP_SPM_ADDRESS % 2) != 0) + #error TEMP_SPM_ADDRESS must be an even address, since it contains executable code! +#endif + +//check, if TEMP_SPM_ADDRESS fits into flash +#if ((TEMP_SPM_PAGEADR + TEMP_SPM_BLKSIZE) > (FLASHEND+1)) + #error TEMP_SPM_ADDRESS exceeds flashend! +#endif + +//check if size too low +#if (SIZEOF_new_firmware <= (TEMP_SPM_BLKSIZE + (NEW_SPM_ADDRESS - NEW_BOOTLOADER_ADDRESS))) + #error empty firmware! +#endif + +//check if size too high +#if (SIZEOF_new_firmware > ((FLASHEND+1)-NEW_BOOTLOADER_ADDRESS)) + #error firmware too big! firmware does not fit into flash memory! +#endif + +// main code //// + +/* + * in this case a near address + */ +typedef uint32_t mypgm_addr_t; +typedef void (*mypgm_spminterface)(const uint32_t flash_byteaddress, const uint8_t spmcrval, const uint16_t dataword); + + +#if 0 +size_t mypgm_readpage(const mypgm_addr_t byteaddress,const void* buffer, const size_t bufferbytesize) { + size_t result = (bufferbytesize < SPM_PAGESIZE)?bufferbytesize:SPM_PAGESIZE; + size_t pagesize = result >> 1; + uint16_t *pagedata = (void*)buffer; + mypgm_addr_t pageaddr = byteaddress - (byteaddress % SPM_PAGESIZE); + size_t i; + + for (i=0;i> 1; + uint16_t *pagedata = (void*)buffer; + mypgm_addr_t pageaddr_bakup = byteaddress - (byteaddress % SPM_PAGESIZE); + mypgm_addr_t pageaddr = pageaddr_bakup; + + uint8_t changed=0, needs_erase=0; + uint16_t deeword; + size_t i; + + // just check, if page needs a rewrite or an erase... + for (i=0;i 1 + * 1 ? 0 ==> 1 + * 0 ? 1 ==> 0 + * 0 ? 0 ==> 1 + * + * ==> /(/x * y) ==> x + /y + */ + deeword |= ~pagedata[i]; + if ((~deeword) != 0) needs_erase=1; + + pageaddr+=2; + } + + if (changed) { +#ifdef mypgmdebug + DDRB |= (1<sizeof(buffer))?sizeof(buffer):(SIZEOF_new_firmware-i)); + + mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS+i, buffer, sizeof(buffer), temp_do_spm); + + #ifdef mypgmdebug + PORTD ^= (1< (NEW_SPM_ADDRESS+TEMP_SPM_BLKSIZE)) break; + } + + // C + // continue writeing the new_firmware after "NEW_SPM_ADDRESS+TEMP_SPM_BLKSIZE" this time use the "new_do_spm" + for (;isizeof(buffer))?sizeof(buffer):(SIZEOF_new_firmware-i)); + + mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS+i, buffer, sizeof(buffer), new_do_spm); + + #ifdef mypgmdebug + PORTD ^= (1<