Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow compressed flash updates #6820

Merged
merged 6 commits into from
Dec 18, 2019

Conversation

earlephilhower
Copy link
Collaborator

As part of the compressed OTA image work, we will need to be able to
build the bootloader using -O2 to minimize code size for the
decompressor.

It was as -O0 which does no code optimization whatsoever because there
was a bit of quasi-assembly that was optimized out with any other
setting. Building uzlib with -O0 is probably a bad thing and will wind
up much larger than with -O2.

Rewrite the jump-to-app code in pure ASM to avoid the optimization
issue.

Add -Wall and clean up warnings it generates.

Remove call to esptool-ck and generation of unused eboot.bin application
image since it is not used by the Arduino core.

@earlephilhower earlephilhower force-pushed the eboot-to-O2 branch 2 times, most recently from 8ebe220 to 83adc5d Compare November 26, 2019 01:33
@earlephilhower earlephilhower changed the title WIP - Allow eboot to be built with -O2, clean up warnings WIP - Allow compressed flash updates Nov 26, 2019
@earlephilhower
Copy link
Collaborator Author

This PR can now automatically decompress GZIP'd .BIN files and run them.

Prior versions had an incorrectly low code size due to me forgetting to set the "use gzip" flag. D'oh.

Real memory usage is 0xee0, leaving ~260 bytes free in the 4K sector.

objdump -t eboot.elf  | sort -k1


00000000 l    d  .comment	00000000 .comment
00000000 l    d  .debug_abbrev	00000000 .debug_abbrev
00000000 l    d  .debug_aranges	00000000 .debug_aranges
00000000 l    d  .debug_frame	00000000 .debug_frame
00000000 l    d  .debug_info	00000000 .debug_info
00000000 l    d  .debug_line	00000000 .debug_line
00000000 l    d  .debug_loc	00000000 .debug_loc
00000000 l    d  .debug_ranges	00000000 .debug_ranges
00000000 l    d  .debug_str	00000000 .debug_str
00000000 l    df *ABS*	00000000 eboot.c
00000000 l    df *ABS*	00000000 eboot_command.c
00000000 l    df *ABS*	00000000 tinfgzip.c
00000000 l    df *ABS*	00000000 tinflate.c
00000000 l    d  .xtensa.info	00000000 .xtensa.info
00000110 g       *ABS*	00000000 _memmap_cacheattr_wb_base
00000110 g       *ABS*	00000000 _memmap_cacheattr_wt_base
00000220 g       *ABS*	00000000 _memmap_cacheattr_bp_base
22222112 g       *ABS*	00000000 _memmap_cacheattr_wb_allvalid
22222112 g       *ABS*	00000000 _memmap_cacheattr_wt_allvalid
2222211f g       *ABS*	00000000 _memmap_cacheattr_wba_trapnull
2222211f g       *ABS*	00000000 _memmap_cacheattr_wbna_trapnull
2222211f g       *ABS*	00000000 _memmap_cacheattr_wb_trapnull
2222211f g       *ABS*	00000000 _memmap_cacheattr_wt_trapnull
22222222 g       *ABS*	00000000 _memmap_cacheattr_bp_allvalid
2222222f g       *ABS*	00000000 _memmap_cacheattr_bp_trapnull
3ff00000 g       *ABS*	00000000 _dport0_data_end
3ff00000 g       *ABS*	00000000 _dport0_data_start
3ff00000 g       *ABS*	00000000 _dport0_literal_end
3ff00000 g       *ABS*	00000000 _dport0_literal_start
3ff00000 g       *ABS*	00000000 _dport0_rodata_end
3ff00000 g       *ABS*	00000000 _dport0_rodata_start
3ffe8000 g     O .data	00008000 gzip_dict
3ffe8000 l    d  .data	00000000 .data
3fff0000 g     O .data	00001000 uzlib_flash_read_cb_buff
3fff1000 g     O .data	00000004 uzlib_flash_read_cb_addr
3fff1004 g     O .data	0000001e length_bits
3fff1024 g     O .data	00000013 clcidx
3fff1038 g     O .data	0000003c length_base
3fff1074 g     O .data	0000001e dist_bits
3fff1094 g     O .data	0000003c dist_base
3fff10d0 g       *ABS*	00000000 _heap_start
400024cc g       *ABS*	00000000 ets_printf
40002be8 g       *ABS*	00000000 ets_putc
40002fa0 g       *ABS*	00000000 ets_wdt_enable
400030f0 g       *ABS*	00000000 ets_wdt_disable
40004a00 g       *ABS*	00000000 SPIEraseSector
40004a4c g       *ABS*	00000000 SPIWrite
40004b1c g       *ABS*	00000000 SPIRead
4000dc88 g       *ABS*	00000000 __divsi3
4010f000 g       *ABS*	00000000 _text_start
4010f000 g       .text	00000000 _stext
4010f000 l    d  .text	00000000 .text
4010f090 g     F .text	0000003f uzlib_flash_read_cb
4010f0d0 g     F .text	00000041 print_version
4010f114 g     F .text	000000ad load_app_from_flash_raw
4010f1c4 g     F .text	00000312 copy_raw
4010f4d8 g     F .text	000000fe main
4010f5d8 g     F .text	00000041 crc_update
4010f61c g     F .text	00000052 eboot_command_read
4010f670 g     F .text	00000014 eboot_command_clear
4010f684 l     F .text	0000008d tinf_build_bits_base
4010f714 l     F .text	00000033 tinf_getbit
4010f748 l     F .text	00000047 tinf_read_bits
4010f790 l     F .text	0000005e tinf_decode_symbol
4010f7f0 l     F .text	0000013b tinf_decode_trees
4010f92c g     F .text	0000009f uzlib_init
4010f9cc g     F .text	0000033c uzlib_uncompress
4010fd08 g     F .text	0000002c tinf_get_uint16
4010fd34 g     F .text	000000b6 uzlib_gzip_parse_header
4010fdec l     F .text	0000007b tinf_build_tree
4010fe68 g     F .text	00000041 uzlib_get_byte
4010feac g     F .text	0000001a uzlib_uncompress_init
4010fec6 g       *ABS*	00000000 _text_end
4010fec6 g       .text	00000000 _etext
4010fec8 g       *ABS*	00000000 _data_end
4010fec8 g       *ABS*	00000000 _data_start
4010fec8 g       *ABS*	00000000 _rodata_start
4010fed1 g       *ABS*	00000000 __XT_EXCEPTION_DESCS__
4010fed1 g       *ABS*	00000000 __XT_EXCEPTION_DESCS_END__
4010fed1 g       *ABS*	00000000 __XT_EXCEPTION_TABLE__
4010fed4 g       *ABS*	00000000 _bss_table_start
4010fedc g       *ABS*	00000000 _bss_table_end
4010fedc g       *ABS*	00000000 _rodata_end
4010fee0 g       *ABS*	00000000 _bss_end
4010fee0 g       *ABS*	00000000 _bss_start
4010fee0 g       *ABS*	00000000 _lit4_end
4010fee0 g       *ABS*	00000000 _lit4_start
40240000 g       *ABS*	00000000 _irom0_text_end
40240000 g       *ABS*	00000000 _irom0_text_start
eboot.elf:     file format elf32-little
fffff00f g       *ABS*	00000000 _memmap_cacheattr_unused_mask
fffff11f g       *ABS*	00000000 _memmap_cacheattr_wb_strict
fffff11f g       *ABS*	00000000 _memmap_cacheattr_wt_strict
fffff22f g       *ABS*	00000000 _memmap_cacheattr_bp_strict
SYMBOL TABLE:

@earlephilhower earlephilhower changed the title WIP - Allow compressed flash updates Allow compressed flash updates Nov 27, 2019
Modified the bootloader to be able to take stored updates in compressed
GZIP format (i.e. the output of "gzip -9 xxx.bin") and decompress them
on-the-fly to their final destination.  This can work for apps and for
filesystems (when used with the 2-step update option).

Allow eboot to be built using -Os/2 optimizations by fixing some portions
which failed when any optimizations were used.  Add -Wall and use data
and function sections to reduce size.  Use -Os to minimize size.

Remove obsolete esptool-ck calls to build a .ROM image, we don't use it.

Move all uninitted variables to RAM from IRAM, allowing 8-bit access.

Hook in @d-a-v and @pfalcon's uzlib port to actually do the
decompression.  Do not use any CRC checking which saves space.  Since we
have overwritten all of flash by the time we know id the CRC matches,
there's nothing we could have done anyway.

Adjust the Updater class to support GZIP files and not attempt to patch
them.

Bootloader builds to 0xd90 out of 0xfff bytes.
@earlephilhower
Copy link
Collaborator Author

Fixes #6614

Copy link
Collaborator

@d-a-v d-a-v left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gives a 🚀 bright future 🚀 for esp8285 and more generally 1M or 2M setups

I tested with the ESP8266HttpUpdate library (with the below changes) and it works very well.

Thanks alot @earlephilhower !

--- a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp
+++ b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp
@@ -370,7 +370,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
                     }
 
                     // check for valid first magic byte
-                    if(buf[0] != 0xE9) {
+                    if(buf[0] != 0xE9 && buf[0] != 0x1f) {
                         DEBUG_HTTP_UPDATE("[httpUpdate] Magic header does not start with 0xE9\n");
                         _setLastError(HTTP_UE_BIN_VERIFY_HEADER_FAILED);
                         http.end();
@@ -378,14 +378,16 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
 
                     }
 
-                    uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4);
+                    if (buf[0] == 0xe9) {
+                        uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4);
 
-                    // check if new bin fits to SPI flash
-                    if(bin_flash_size > ESP.getFlashChipRealSize()) {
-                        DEBUG_HTTP_UPDATE("[httpUpdate] New binary does not fit SPI Flash size\n");
-                        _setLastError(HTTP_UE_BIN_FOR_WRONG_FLASH);
-                        http.end();
-                        return HTTP_UPDATE_FAILED;
+                        // check if new bin fits to SPI flash
+                        if(bin_flash_size > ESP.getFlashChipRealSize()) {
+                            DEBUG_HTTP_UPDATE("[httpUpdate] New binary does not fit SPI Flash size\n");
+                            _setLastError(HTTP_UE_BIN_FOR_WRONG_FLASH);
+                            http.end();
+                            return HTTP_UPDATE_FAILED;
+                        }
                     }
                 }
                 if(runUpdate(*tcp, len, http.header("x-MD5"), command)) {

@earlephilhower
Copy link
Collaborator Author

Thanks, @d-a-v. I tried the httpupdateserver, not the httpupdate path and I'll be sure to include your patch in the next push.

@TD-er
Copy link
Contributor

TD-er commented Dec 7, 2019

Just curious, how should the bin be compressed in order to be uncompressed with this bootloader?
Any specific gzip flags needed?

@earlephilhower
Copy link
Collaborator Author

It should be able to parse any valid gzip file. I just use gzip sketch.elf.binand upload the sketch.elf.bin.gz file. -9 might make sense since every byte counts and images are <16MB by definition.

For now, because there are some self-test failures with @d-a-v's esp8266
branch (whose cool new features we don't actually use in eboot now)
start with pfalcon's 2.9 release and add the 2 patches (clcidx to code
from IRAM/RODATA, and the Windows test file renaming) needed to build
and run successfully.
@csgregg
Copy link

csgregg commented Aug 11, 2020

Are there any working examples of compressed for file system update (LittleFS) OTA using ESP8266httpUpdate? I can't seem to find any.
I can successfully OTA update a compressed program image but it fails with a compressed file system image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants