Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libraries/Update/src/Update.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<void(size_t, size_t)> THandlerFunction_Progress;
Expand Down Expand Up @@ -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;
Expand Down
33 changes: 29 additions & 4 deletions libraries/Update/src/Updater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,23 @@ 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;
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);
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;
Expand Down Expand Up @@ -389,4 +398,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;