From 07b4c09b901504c64e23db7712923540b36c379a Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 7 Feb 2021 16:32:56 -0800 Subject: [PATCH] eboot: .RODATA, upstream uzlib, move CRC, save 112 bytes (#7844) RODATA can be copied automatically by the bootrom, so no reason not to allow its use for strings and constants in eboot.c Revert to pfalcon's original uzlib since the single patch to remove RODATA is not required. Rationalize eboot.ld linker script, clean up BSS and init it in code. Saves 112 bytes of space in the bootloader sector by removing the extra code associated with literal loads. * Move CRC out of bootload sector We added protection to only erase the bootload sector when flashing an image when the new sector != the old sector. This was intended to minimize the chance of bricking (i.e. if there was a powerfail during flashing of the boot sector the chip would be dead). Unfortunately, by placing the CRC inside the eboot sector *every* application will have a unique eboot sector (due to the crc/len), so this protection doesn't work. Move the CRC into the first 8 bytes of IROM itself. This frees up extra space in the boot sector and ensures that eboot won't be reflashed unless there really is an eboot change. --- .gitmodules | 2 +- bootloaders/eboot/Makefile | 8 +-- bootloaders/eboot/eboot.c | 42 +++++------- bootloaders/eboot/eboot.elf | Bin 44896 -> 89020 bytes bootloaders/eboot/eboot.ld | 92 +++++++------------------- cores/esp8266/Esp.cpp | 18 ++--- tools/elf2bin.py | 6 +- tools/sdk/ld/eagle.app.v6.common.ld.h | 7 ++ tools/sdk/uzlib | 2 +- 9 files changed, 68 insertions(+), 109 deletions(-) diff --git a/.gitmodules b/.gitmodules index 54e63d88e..ae4299967 100644 --- a/.gitmodules +++ b/.gitmodules @@ -24,4 +24,4 @@ url = https://github.com/arduino-libraries/Ethernet.git [submodule "tools/sdk/uzlib"] path = tools/sdk/uzlib - url = https://github.com/earlephilhower/uzlib.git + url = https://github.com/pfalcon/uzlib.git diff --git a/bootloaders/eboot/Makefile b/bootloaders/eboot/Makefile index 88808117e..3eb9fc58f 100644 --- a/bootloaders/eboot/Makefile +++ b/bootloaders/eboot/Makefile @@ -40,17 +40,17 @@ APP_FW := eboot.bin all: $(APP_OUT) -tinflate.o: $(UZLIB_PATH)/tinflate.c $(UZLIB_PATH)/uzlib.h $(UZLIB_PATH)/uzlib_conf.h +tinflate.o: $(UZLIB_PATH)/tinflate.c $(UZLIB_PATH)/uzlib.h $(UZLIB_PATH)/uzlib_conf.h Makefile $(CC) $(CFLAGS) -c -o tinflate.o $(UZLIB_PATH)/tinflate.c -tinfgzip.o: $(UZLIB_PATH)/tinfgzip.c $(UZLIB_PATH)/uzlib.h $(UZLIB_PATH)/uzlib_conf.h +tinfgzip.o: $(UZLIB_PATH)/tinfgzip.c $(UZLIB_PATH)/uzlib.h $(UZLIB_PATH)/uzlib_conf.h Makefile $(CC) $(CFLAGS) -c -o tinfgzip.o $(UZLIB_PATH)/tinfgzip.c -$(APP_AR): $(TARGET_OBJ_PATHS) tinflate.o tinfgzip.o +$(APP_AR): $(TARGET_OBJ_PATHS) tinflate.o tinfgzip.o Makefile $(AR) cru $@ $^ $(APP_OUT): $(APP_AR) eboot.ld | Makefile - $(LD) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group -Wl,--whole-archive $(APP_AR) -Wl,--end-group -o $@ + $(LD) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group -Wl,--sort-common $(APP_AR) -Wl,--end-group -o $@ clean: rm -f *.o diff --git a/bootloaders/eboot/eboot.c b/bootloaders/eboot/eboot.c index 6e188d806..6e15d137b 100644 --- a/bootloaders/eboot/eboot.c +++ b/bootloaders/eboot/eboot.c @@ -14,28 +14,19 @@ #include "eboot_command.h" #include -extern unsigned char _gzip_dict; #define SWRST do { (*((volatile uint32_t*) 0x60000700)) |= 0x80000000; } while(0); extern void ets_wdt_enable(void); extern void ets_wdt_disable(void); -// Converts bit of a string into a uint32 -#define S(a,b,c,d) ( (((uint32_t)a) & 0xff) | (((uint32_t)b) << 8) | (((uint32_t)c) << 16) | (((uint32_t)d)<<24) ) - int print_version(const uint32_t flash_addr) { uint32_t ver; if (SPIRead(flash_addr + APP_START_OFFSET + sizeof(image_header_t) + sizeof(section_header_t), &ver, sizeof(ver))) { return 1; } - // We don't have BSS and can't print from flash, so build up string - // 4 chars at a time. Smaller code than byte-wise assignment. - uint32_t fmt[2]; - fmt[0] = S('v', '%', '0', '8'); - fmt[1] = S('x', '\n', 0, 0); - ets_printf((const char*) fmt, ver); + ets_printf("v%08x\n", ver); return 0; } @@ -222,6 +213,16 @@ int main() bool clear_cmd = false; struct eboot_command cmd; +// BSS init commented out for now to save space. If any static variables set +// to 0 are used, need to uncomment it or else the BSS will not be cleared and +// the static vars will power on with random values. +#if 0 + // Clear BSS ourselves, we don't have handy C runtime + extern char _bss_start; + extern char _bss_end; + ets_bzero(&_bss_start, &_bss_end - &_bss_start); +#endif + print_version(0); if (eboot_command_read(&cmd) == 0) { @@ -236,32 +237,26 @@ int main() } if (cmd.action == ACTION_COPY_RAW) { - uint32_t cp = S('c', 'p', ':', 0); - ets_printf((const char *)&cp); + ets_printf("cp:"); ets_wdt_disable(); res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2], false); ets_wdt_enable(); - cp = S('0' + res, '\n', 0, 0 ); - ets_printf((const char *)&cp); + ets_printf("%d\n", res); #if 0 //devyte: this verify step below (cmp:) only works when the end of copy operation above does not overwrite the //beginning of the image in the empty area, see #7458. Disabling for now. //TODO: replace the below verify with hash type, crc, or similar. // Verify the copy - uint32_t v[2]; - v[0] = S('c', 'm', 'p', ':'); - v[1] = 0; - ets_printf(const char *)v); + ets_printf("cmp:"); if (res == 0) { ets_wdt_disable(); res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2], true); ets_wdt_enable(); } - cp = S('0' + res, '\n', 0, 0 ); - ets_printf((const char *)&cp); + ets_printf("%d\n", res); #endif if (res == 0) { cmd.action = ACTION_LOAD_APP; @@ -274,13 +269,10 @@ int main() } if (cmd.action == ACTION_LOAD_APP) { - ets_putc('l'); ets_putc('d'); ets_putc('\n'); + ets_printf("ld\n"); res = load_app_from_flash_raw(cmd.args[0]); // We will get to this only on load fail - uint32_t e[2]; - e[0] = S('e', ':', '0' + res, '\n' ); - e[1] = 0; - ets_printf((const char*)e); + ets_printf("e:%d\n", res); } if (res) { diff --git a/bootloaders/eboot/eboot.elf b/bootloaders/eboot/eboot.elf index e9c98216b0805dc482dc122f80ee8fb802d28abf..3a1815fac5d380912bd8b3888f45d04ddfec6ff2 100755 GIT binary patch delta 17597 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 literal 44896 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 YTU6fg%SP6VH|rk!yDNnv?*{LG0^}(VrT_o{ diff --git a/bootloaders/eboot/eboot.ld b/bootloaders/eboot/eboot.ld index c664daf66..3946412db 100644 --- a/bootloaders/eboot/eboot.ld +++ b/bootloaders/eboot/eboot.ld @@ -42,53 +42,13 @@ PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); SECTIONS { - .dport0.rodata : ALIGN(4) + .globals : ALIGN(4) { - _dport0_rodata_start = ABSOLUTE(.); - *(.dport0.rodata) - *(.dport.rodata) - _dport0_rodata_end = ABSOLUTE(.); - } >dport0_0_seg :dport0_0_phdr - - .dport0.literal : ALIGN(4) - { - _dport0_literal_start = ABSOLUTE(.); - *(.dport0.literal) - *(.dport.literal) - _dport0_literal_end = ABSOLUTE(.); - } >dport0_0_seg :dport0_0_phdr - - .dport0.data : ALIGN(4) - { - _dport0_data_start = ABSOLUTE(.); - *(.dport0.data) - *(.dport.data) - _dport0_data_end = ABSOLUTE(.); - } >dport0_0_seg :dport0_0_phdr + *(COMMON) /* Global vars */ + } >dram0_0_seg :dram0_0_bss_phdr .data : ALIGN(4) { - *(COMMON) /* Global vars */ - . = ALIGN(4); - _heap_start = ABSOLUTE(.); -/* _stack_sentry = ALIGN(0x8); */ - } >dram0_0_seg :dram0_0_bss_phdr -/* __stack = 0x3ffc8000; */ - - .text : ALIGN(4) - { - _stext = .; - _text_start = ABSOLUTE(.); - *(.entry.text) - *(.init.literal) - *(.init) - *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) - *(.fini.literal) - *(.fini) - *(.gnu.version) - _text_end = ABSOLUTE(.); - _etext = .; - . = ALIGN (8); _data_start = ABSOLUTE(.); *(.data) *(.data.*) @@ -102,7 +62,10 @@ SECTIONS *(.gnu.linkonce.s2.*) *(.jcr) _data_end = ABSOLUTE(.); - . = ALIGN (8); + } >dram0_0_seg :dram0_0_bss_phdr + + .rodata : ALIGN(4) + { _rodata_start = ABSOLUTE(.); *(.rodata) *(.rodata.*) @@ -131,14 +94,11 @@ SECTIONS *(.xt_except_desc_end) *(.dynamic) *(.gnu.version_d) - . = ALIGN(4); /* this table MUST be 4-byte aligned */ - _bss_table_start = ABSOLUTE(.); - LONG(_bss_start) - LONG(_bss_end) - _bss_table_end = ABSOLUTE(.); _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_bss_phdr - . = ALIGN (8); + .bss : ALIGN(4) + { _bss_start = ABSOLUTE(.); *(.dynsbss) *(.sbss) @@ -152,26 +112,24 @@ SECTIONS *(.bss) *(.bss.*) *(.gnu.linkonce.b.*) - . = ALIGN (8); _bss_end = ABSOLUTE(.); - _free_space = 4096 - 17 - (. - _stext); -/* -The boot loader checksum must be before the CRC, which is written by elf2bin.py. -This leaves 16 bytes after the checksum for the CRC placed at the end of the -4096-byte sector. */ - _cs_here = (ALIGN((. + 1), 16) == ALIGN(16)) ? (ALIGN(16) - 1) : (. + 0x0F); + } >dram0_0_seg :dram0_0_bss_phdr -/* -The filling (padding) and values for _crc_size and _crc_val are handled by -elf2bin.py. With this, we give values to the symbols without explicitly -assigning space. This avoids the linkers back *fill* operation that causes -trouble. -The CRC info is stored in last 8 bytes. */ - _crc_size = _stext + 4096 - 8; - _crc_val = _stext + 4096 - 4; - ASSERT((4096 > (17 + (. - _stext))), "Error: No space for CS and CRC in bootloader sector."); - ASSERT((_crc_size > _cs_here), "Error: CRC must be located after CS."); + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + . = ALIGN (4); /* Ensure 32b alignment since this is written to IRAM */ } >iram1_0_seg :iram1_0_phdr .lit4 : ALIGN(4) diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index 51bdfe8e1..e518755f6 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -444,22 +444,24 @@ bool EspClass::checkFlashConfig(bool needsEquals) { return false; } +// These are defined in the linker script, and filled in by the elf2bin.py util +extern "C" uint32_t __crc_len; +extern "C" uint32_t __crc_val; + bool EspClass::checkFlashCRC() { - // The CRC and total length are placed in extra space at the end of the 4K chunk - // of flash occupied by the bootloader. If the bootloader grows to >4K-8 bytes, - // we'll need to adjust this. - uint32_t flashsize = *((uint32_t*)(0x40200000 + 4088)); // Start of PROGMEM plus 4K-8 - uint32_t flashcrc = *((uint32_t*)(0x40200000 + 4092)); // Start of PROGMEM plus 4K-4 + // Dummy CRC fill uint32_t z[2]; z[0] = z[1] = 0; + uint32_t firstPart = (uintptr_t)&__crc_len - 0x40200000; // How many bytes to check before the 1st CRC val + // Start the checksum - uint32_t crc = crc32((const void*)0x40200000, 4096-8, 0xffffffff); + uint32_t crc = crc32((const void*)0x40200000, firstPart, 0xffffffff); // Pretend the 2 words of crc/len are zero to be idempotent crc = crc32(z, 8, crc); // Finish the CRC calculation over the rest of flash - crc = crc32((const void*)0x40201000, flashsize-4096, crc); - return crc == flashcrc; + crc = crc32((const void*)(0x40200000 + firstPart + 8), __crc_len - (firstPart + 8), crc); + return crc == __crc_val; } diff --git a/tools/elf2bin.py b/tools/elf2bin.py index 231bd5e5d..035f7a93a 100755 --- a/tools/elf2bin.py +++ b/tools/elf2bin.py @@ -30,8 +30,8 @@ fmodeb = { 'dout': 3, 'dio': 2, 'qout': 1, 'qio': 0 } ffreqb = { '40': 0, '26': 1, '20': 2, '80': 15 } fsizeb = { '512K': 0, '256K': 1, '1M': 2, '2M': 3, '4M': 4, '8M': 8, '16M': 9 } -crcsize_offset = 4088 -crcval_offset = 4092 +crcsize_offset = 4096 + 16 +crcval_offset = 4096 + 16 + 4 def get_elf_entry(elf, path): p = subprocess.Popen([path + "/xtensa-lx106-elf-readelf", '-h', elf], stdout=subprocess.PIPE, universal_newlines=True ) @@ -188,7 +188,7 @@ def main(): wrapper( elf=args.eboot, - segments=[".text"], + segments=[".text", ".rodata"], to_addr=4096 ) diff --git a/tools/sdk/ld/eagle.app.v6.common.ld.h b/tools/sdk/ld/eagle.app.v6.common.ld.h index c51de9840..77c834ae1 100644 --- a/tools/sdk/ld/eagle.app.v6.common.ld.h +++ b/tools/sdk/ld/eagle.app.v6.common.ld.h @@ -147,6 +147,13 @@ SECTIONS .irom0.text : ALIGN(4) { _irom0_text_start = ABSOLUTE(.); + + /* Stuff the CRC in well known symbols at a well known location */ + __crc_len = ABSOLUTE(.); + LONG(0x00000000); + __crc_val = ABSOLUTE(.); + LONG(0x00000000); + *(.ver_number) *.c.o(.literal*, .text*) *.cpp.o(EXCLUDE_FILE (umm_malloc.cpp.o) .literal*, EXCLUDE_FILE (umm_malloc.cpp.o) .text*) diff --git a/tools/sdk/uzlib b/tools/sdk/uzlib index 42398df66..27e4f4c15 160000 --- a/tools/sdk/uzlib +++ b/tools/sdk/uzlib @@ -1 +1 @@ -Subproject commit 42398df66c02da1cec387b634b6d2f285007a7af +Subproject commit 27e4f4c15ba30c2cfc89575159e8efb50f95037e