From 9174488795c0f04ba6c776f085b3d3e4c214c5a4 Mon Sep 17 00:00:00 2001 From: Emil Muratov Date: Sat, 16 Jul 2022 20:08:51 +0530 Subject: [PATCH 1/2] UpdateClass - improve flash erase/writes - on flash writes try to use large block erase - skip writing empty blocks of data after erase --- libraries/Update/src/Update.h | 4 ++++ libraries/Update/src/Updater.cpp | 32 ++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/libraries/Update/src/Update.h b/libraries/Update/src/Update.h index abceeb0996b..303ec7cc4cc 100644 --- a/libraries/Update/src/Update.h +++ b/libraries/Update/src/Update.h @@ -28,6 +28,9 @@ #define ENCRYPTED_BLOCK_SIZE 16 +#define SPI_SECTORS_PER_BLOCK 16 // usually large erase block is 32k/64k +#define SPI_FLASH_BLOCK_SIZE (SPI_SECTORS_PER_BLOCK*SPI_FLASH_SEC_SIZE) + class UpdateClass { public: typedef std::function THandlerFunction_Progress; @@ -166,6 +169,7 @@ class UpdateClass { bool _verifyHeader(uint8_t data); bool _verifyEnd(); bool _enablePartition(const esp_partition_t* partition); + bool _chkDataInBlock(const uint8_t *data, size_t len) const; // check if block contains any data or is empty uint8_t _error; diff --git a/libraries/Update/src/Updater.cpp b/libraries/Update/src/Updater.cpp index f9ecbfb057f..eecdb0060cd 100644 --- a/libraries/Update/src/Updater.cpp +++ b/libraries/Update/src/Updater.cpp @@ -203,14 +203,22 @@ bool UpdateClass::_writeBuffer(){ if (!_progress && _progress_callback) { _progress_callback(0, _size); } - if(!ESP.partitionEraseRange(_partition, _progress, SPI_FLASH_SEC_SIZE)){ - _abort(UPDATE_ERROR_ERASE); - return false; + bool block_erase = (_size - _progress >= SPI_FLASH_BLOCK_SIZE) && ((_partition->address + _progress) % SPI_FLASH_BLOCK_SIZE == 0); // if it's the block boundary, than erase the whole block from here + bool part_head_sectors = _partition->address % SPI_FLASH_BLOCK_SIZE && (_progress < SPI_FLASH_BLOCK_SIZE); // sector belong to unaligned partition heading block + bool part_tail_sectors = _partition->address + _progress > (_partition->address + _size) / SPI_FLASH_BLOCK_SIZE * SPI_FLASH_BLOCK_SIZE; // sector belong to unaligned partition tailing block + if (block_erase || part_head_sectors || part_tail_sectors){ + if(!ESP.partitionEraseRange(_partition, _progress, block_erase ? SPI_FLASH_BLOCK_SIZE : SPI_FLASH_SEC_SIZE)){ + _abort(UPDATE_ERROR_ERASE); + return false; + } } - if (!ESP.partitionWrite(_partition, _progress + skip, (uint32_t*)_buffer + skip/sizeof(uint32_t), _bufferLen - skip)) { + + // try to skip empty blocks on unecrypted partitions + if ((_partition->encrypted || _chkDataInBlock(_buffer + skip/sizeof(uint32_t), _bufferLen - skip)) && !ESP.partitionWrite(_partition, _progress + skip, (uint32_t*)_buffer + skip/sizeof(uint32_t), _bufferLen - skip)) { _abort(UPDATE_ERROR_WRITE); return false; } + //restore magic or md5 will fail if(!_progress && _command == U_FLASH){ _buffer[0] = ESP_IMAGE_HEADER_MAGIC; @@ -389,4 +397,20 @@ const char * UpdateClass::errorString(){ return _err2str(_error); } +bool UpdateClass::_chkDataInBlock(const uint8_t *data, size_t len) const { + // check 32-bit aligned blocks only + if (!len || len % sizeof(uint32_t)) + return true; + + size_t dwl = len / sizeof(uint32_t); + + do { + if (*(uint32_t*)data ^ 0xffffffff) // for SPI NOR flash empty blocks are all one's, i.e. filled with 0xff byte + return true; + + data += sizeof(uint32_t); + } while (--dwl); + return false; +} + UpdateClass Update; From 514bc3cb4412db7b353e7bd49e6fe57e8523d869 Mon Sep 17 00:00:00 2001 From: Emil Muratov Date: Tue, 19 Jul 2022 23:23:27 +0530 Subject: [PATCH 2/2] UpdaterClass: more accurate block calculations --- libraries/Update/src/Updater.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/Update/src/Updater.cpp b/libraries/Update/src/Updater.cpp index eecdb0060cd..30d88cb8ff1 100644 --- a/libraries/Update/src/Updater.cpp +++ b/libraries/Update/src/Updater.cpp @@ -203,9 +203,10 @@ bool UpdateClass::_writeBuffer(){ if (!_progress && _progress_callback) { _progress_callback(0, _size); } - bool block_erase = (_size - _progress >= SPI_FLASH_BLOCK_SIZE) && ((_partition->address + _progress) % SPI_FLASH_BLOCK_SIZE == 0); // if it's the block boundary, than erase the whole block from here - bool part_head_sectors = _partition->address % SPI_FLASH_BLOCK_SIZE && (_progress < SPI_FLASH_BLOCK_SIZE); // sector belong to unaligned partition heading block - bool part_tail_sectors = _partition->address + _progress > (_partition->address + _size) / SPI_FLASH_BLOCK_SIZE * SPI_FLASH_BLOCK_SIZE; // sector belong to unaligned partition tailing block + size_t offset = _partition->address + _progress; + bool block_erase = (_size - _progress >= SPI_FLASH_BLOCK_SIZE) && (offset % SPI_FLASH_BLOCK_SIZE == 0); // if it's the block boundary, than erase the whole block from here + bool part_head_sectors = _partition->address % SPI_FLASH_BLOCK_SIZE && offset < (_partition->address / SPI_FLASH_BLOCK_SIZE + 1) * SPI_FLASH_BLOCK_SIZE; // sector belong to unaligned partition heading block + bool part_tail_sectors = offset >= (_partition->address + _size) / SPI_FLASH_BLOCK_SIZE * SPI_FLASH_BLOCK_SIZE; // sector belong to unaligned partition tailing block if (block_erase || part_head_sectors || part_tail_sectors){ if(!ESP.partitionEraseRange(_partition, _progress, block_erase ? SPI_FLASH_BLOCK_SIZE : SPI_FLASH_SEC_SIZE)){ _abort(UPDATE_ERROR_ERASE);