1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

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.
This commit is contained in:
Earle F. Philhower, III 2021-02-07 16:32:56 -08:00 committed by GitHub
parent 6c564c269c
commit 07b4c09b90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 68 additions and 109 deletions

2
.gitmodules vendored
View File

@ -24,4 +24,4 @@
url = https://github.com/arduino-libraries/Ethernet.git url = https://github.com/arduino-libraries/Ethernet.git
[submodule "tools/sdk/uzlib"] [submodule "tools/sdk/uzlib"]
path = tools/sdk/uzlib path = tools/sdk/uzlib
url = https://github.com/earlephilhower/uzlib.git url = https://github.com/pfalcon/uzlib.git

View File

@ -40,17 +40,17 @@ APP_FW := eboot.bin
all: $(APP_OUT) 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 $(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 $(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 $@ $^ $(AR) cru $@ $^
$(APP_OUT): $(APP_AR) eboot.ld | Makefile $(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: clean:
rm -f *.o rm -f *.o

View File

@ -14,28 +14,19 @@
#include "eboot_command.h" #include "eboot_command.h"
#include <uzlib.h> #include <uzlib.h>
extern unsigned char _gzip_dict;
#define SWRST do { (*((volatile uint32_t*) 0x60000700)) |= 0x80000000; } while(0); #define SWRST do { (*((volatile uint32_t*) 0x60000700)) |= 0x80000000; } while(0);
extern void ets_wdt_enable(void); extern void ets_wdt_enable(void);
extern void ets_wdt_disable(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) int print_version(const uint32_t flash_addr)
{ {
uint32_t ver; uint32_t ver;
if (SPIRead(flash_addr + APP_START_OFFSET + sizeof(image_header_t) + sizeof(section_header_t), &ver, sizeof(ver))) { if (SPIRead(flash_addr + APP_START_OFFSET + sizeof(image_header_t) + sizeof(section_header_t), &ver, sizeof(ver))) {
return 1; return 1;
} }
// We don't have BSS and can't print from flash, so build up string ets_printf("v%08x\n", ver);
// 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);
return 0; return 0;
} }
@ -222,6 +213,16 @@ int main()
bool clear_cmd = false; bool clear_cmd = false;
struct eboot_command cmd; 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); print_version(0);
if (eboot_command_read(&cmd) == 0) { if (eboot_command_read(&cmd) == 0) {
@ -236,32 +237,26 @@ int main()
} }
if (cmd.action == ACTION_COPY_RAW) { if (cmd.action == ACTION_COPY_RAW) {
uint32_t cp = S('c', 'p', ':', 0); ets_printf("cp:");
ets_printf((const char *)&cp);
ets_wdt_disable(); ets_wdt_disable();
res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2], false); res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2], false);
ets_wdt_enable(); ets_wdt_enable();
cp = S('0' + res, '\n', 0, 0 ); ets_printf("%d\n", res);
ets_printf((const char *)&cp);
#if 0 #if 0
//devyte: this verify step below (cmp:) only works when the end of copy operation above does not overwrite the //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. //beginning of the image in the empty area, see #7458. Disabling for now.
//TODO: replace the below verify with hash type, crc, or similar. //TODO: replace the below verify with hash type, crc, or similar.
// Verify the copy // Verify the copy
uint32_t v[2]; ets_printf("cmp:");
v[0] = S('c', 'm', 'p', ':');
v[1] = 0;
ets_printf(const char *)v);
if (res == 0) { if (res == 0) {
ets_wdt_disable(); ets_wdt_disable();
res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2], true); res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2], true);
ets_wdt_enable(); ets_wdt_enable();
} }
cp = S('0' + res, '\n', 0, 0 ); ets_printf("%d\n", res);
ets_printf((const char *)&cp);
#endif #endif
if (res == 0) { if (res == 0) {
cmd.action = ACTION_LOAD_APP; cmd.action = ACTION_LOAD_APP;
@ -274,13 +269,10 @@ int main()
} }
if (cmd.action == ACTION_LOAD_APP) { 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]); res = load_app_from_flash_raw(cmd.args[0]);
// We will get to this only on load fail // We will get to this only on load fail
uint32_t e[2]; ets_printf("e:%d\n", res);
e[0] = S('e', ':', '0' + res, '\n' );
e[1] = 0;
ets_printf((const char*)e);
} }
if (res) { if (res) {

Binary file not shown.

View File

@ -42,53 +42,13 @@ PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
SECTIONS SECTIONS
{ {
.dport0.rodata : ALIGN(4) .globals : ALIGN(4)
{ {
_dport0_rodata_start = ABSOLUTE(.); *(COMMON) /* Global vars */
*(.dport0.rodata) } >dram0_0_seg :dram0_0_bss_phdr
*(.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
.data : ALIGN(4) .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_start = ABSOLUTE(.);
*(.data) *(.data)
*(.data.*) *(.data.*)
@ -102,7 +62,10 @@ SECTIONS
*(.gnu.linkonce.s2.*) *(.gnu.linkonce.s2.*)
*(.jcr) *(.jcr)
_data_end = ABSOLUTE(.); _data_end = ABSOLUTE(.);
. = ALIGN (8); } >dram0_0_seg :dram0_0_bss_phdr
.rodata : ALIGN(4)
{
_rodata_start = ABSOLUTE(.); _rodata_start = ABSOLUTE(.);
*(.rodata) *(.rodata)
*(.rodata.*) *(.rodata.*)
@ -131,14 +94,11 @@ SECTIONS
*(.xt_except_desc_end) *(.xt_except_desc_end)
*(.dynamic) *(.dynamic)
*(.gnu.version_d) *(.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(.); _rodata_end = ABSOLUTE(.);
} >dram0_0_seg :dram0_0_bss_phdr
. = ALIGN (8); .bss : ALIGN(4)
{
_bss_start = ABSOLUTE(.); _bss_start = ABSOLUTE(.);
*(.dynsbss) *(.dynsbss)
*(.sbss) *(.sbss)
@ -152,26 +112,24 @@ SECTIONS
*(.bss) *(.bss)
*(.bss.*) *(.bss.*)
*(.gnu.linkonce.b.*) *(.gnu.linkonce.b.*)
. = ALIGN (8);
_bss_end = ABSOLUTE(.); _bss_end = ABSOLUTE(.);
_free_space = 4096 - 17 - (. - _stext); } >dram0_0_seg :dram0_0_bss_phdr
/*
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);
/*
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. */ .text : ALIGN(4)
_crc_size = _stext + 4096 - 8; {
_crc_val = _stext + 4096 - 4; _stext = .;
ASSERT((4096 > (17 + (. - _stext))), "Error: No space for CS and CRC in bootloader sector."); _text_start = ABSOLUTE(.);
ASSERT((_crc_size > _cs_here), "Error: CRC must be located after CS."); *(.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 } >iram1_0_seg :iram1_0_phdr
.lit4 : ALIGN(4) .lit4 : ALIGN(4)

View File

@ -444,22 +444,24 @@ bool EspClass::checkFlashConfig(bool needsEquals) {
return false; 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() { bool EspClass::checkFlashCRC() {
// The CRC and total length are placed in extra space at the end of the 4K chunk // Dummy CRC fill
// 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
uint32_t z[2]; uint32_t z[2];
z[0] = z[1] = 0; 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 // 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 // Pretend the 2 words of crc/len are zero to be idempotent
crc = crc32(z, 8, crc); crc = crc32(z, 8, crc);
// Finish the CRC calculation over the rest of flash // Finish the CRC calculation over the rest of flash
crc = crc32((const void*)0x40201000, flashsize-4096, crc); crc = crc32((const void*)(0x40200000 + firstPart + 8), __crc_len - (firstPart + 8), crc);
return crc == flashcrc; return crc == __crc_val;
} }

View File

@ -30,8 +30,8 @@ fmodeb = { 'dout': 3, 'dio': 2, 'qout': 1, 'qio': 0 }
ffreqb = { '40': 0, '26': 1, '20': 2, '80': 15 } ffreqb = { '40': 0, '26': 1, '20': 2, '80': 15 }
fsizeb = { '512K': 0, '256K': 1, '1M': 2, '2M': 3, '4M': 4, '8M': 8, '16M': 9 } fsizeb = { '512K': 0, '256K': 1, '1M': 2, '2M': 3, '4M': 4, '8M': 8, '16M': 9 }
crcsize_offset = 4088 crcsize_offset = 4096 + 16
crcval_offset = 4092 crcval_offset = 4096 + 16 + 4
def get_elf_entry(elf, path): def get_elf_entry(elf, path):
p = subprocess.Popen([path + "/xtensa-lx106-elf-readelf", '-h', elf], stdout=subprocess.PIPE, universal_newlines=True ) p = subprocess.Popen([path + "/xtensa-lx106-elf-readelf", '-h', elf], stdout=subprocess.PIPE, universal_newlines=True )
@ -188,7 +188,7 @@ def main():
wrapper( wrapper(
elf=args.eboot, elf=args.eboot,
segments=[".text"], segments=[".text", ".rodata"],
to_addr=4096 to_addr=4096
) )

View File

@ -147,6 +147,13 @@ SECTIONS
.irom0.text : ALIGN(4) .irom0.text : ALIGN(4)
{ {
_irom0_text_start = ABSOLUTE(.); _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) *(.ver_number)
*.c.o(.literal*, .text*) *.c.o(.literal*, .text*)
*.cpp.o(EXCLUDE_FILE (umm_malloc.cpp.o) .literal*, EXCLUDE_FILE (umm_malloc.cpp.o) .text*) *.cpp.o(EXCLUDE_FILE (umm_malloc.cpp.o) .literal*, EXCLUDE_FILE (umm_malloc.cpp.o) .text*)

@ -1 +1 @@
Subproject commit 42398df66c02da1cec387b634b6d2f285007a7af Subproject commit 27e4f4c15ba30c2cfc89575159e8efb50f95037e