diff --git a/docs/guides/silabs_efr32_software_update.md b/docs/guides/silabs_efr32_software_update.md index 29660f133f6708..c4afffdcc33502 100644 --- a/docs/guides/silabs_efr32_software_update.md +++ b/docs/guides/silabs_efr32_software_update.md @@ -18,8 +18,12 @@ all of the EFR32 example applications. scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/debug chip_config_network_layer_ble=false - Build or download the Gecko Bootloader binary. Bootloader should be built - with the Gecko SDK version 3.2.1 or earlier, type "external SPI" configured - with a single slot of at least 1000 KB. Pre-built binaries should be + with the Gecko SDK version 3.2.1 or earlier. For the bootloader using the + external flash select the "external SPI" bootloader type configured with a + single slot of at least 1000 KB. For the bootloader using the internal flash + (supported on MG24 boards only) select the "internal storage" bootloader + type. Follow the instructions in "UG266: Silicon Labs Gecko Bootloader + User’s Guide". Pre-built binaries for some configurations should be available in third_party/efr32_sdk/repo/platform/bootloader/sample-apps/bootloader-storage-spiflash-single diff --git a/src/platform/EFR32/OTAImageProcessorImpl.cpp b/src/platform/EFR32/OTAImageProcessorImpl.cpp index def99c8afab031..f5703ec7df5cb8 100644 --- a/src/platform/EFR32/OTAImageProcessorImpl.cpp +++ b/src/platform/EFR32/OTAImageProcessorImpl.cpp @@ -21,6 +21,7 @@ extern "C" { #include "platform/bootloader/api/btl_interface.h" +#include "platform/emlib/inc/em_bus.h" // For CORE_CRITICAL_SECTION } /// No error, operation OK @@ -29,8 +30,10 @@ extern "C" { namespace chip { // Define static memebers -uint8_t OTAImageProcessorImpl::mSlotId; -uint32_t OTAImageProcessorImpl::mWriteOffset; +uint8_t OTAImageProcessorImpl::mSlotId = 0; +uint32_t OTAImageProcessorImpl::mWriteOffset = 0; +uint16_t OTAImageProcessorImpl::writeBufOffset = 0; +uint8_t OTAImageProcessorImpl::writeBuffer[kAlignmentBytes] __attribute__((aligned(4))) = { 0 }; CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() { @@ -89,9 +92,13 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) return; } - bootloader_init(); - mSlotId = 0; // Single slot until we support multiple images - mWriteOffset = 0; + ChipLogProgress(SoftwareUpdate, "HandlePrepareDownload"); + + CORE_CRITICAL_SECTION(bootloader_init();) + mSlotId = 0; // Single slot until we support multiple images + writeBufOffset = 0; + mWriteOffset = 0; + imageProcessor->mParams.downloadedBytes = 0; imageProcessor->mHeaderParser.Init(); @@ -102,12 +109,34 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) void OTAImageProcessorImpl::HandleFinalize(intptr_t context) { + uint32_t err = SL_BOOTLOADER_OK; auto * imageProcessor = reinterpret_cast(context); if (imageProcessor == nullptr) { return; } + // Pad the remainder of the write buffer with zeros and write it to bootloader storage + if (writeBufOffset != 0) + { + // Account for last bytes of the image not yet written to storage + imageProcessor->mParams.downloadedBytes += writeBufOffset; + + while (writeBufOffset != kAlignmentBytes) + { + writeBuffer[writeBufOffset] = 0; + writeBufOffset++; + } + + CORE_CRITICAL_SECTION(err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, writeBuffer, kAlignmentBytes);) + if (err) + { + ChipLogError(SoftwareUpdate, "ERROR: In HandleFinalize bootloader_eraseWriteStorage() error %ld", err); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); + return; + } + } + imageProcessor->ReleaseBlock(); ChipLogProgress(SoftwareUpdate, "OTA image downloaded successfully"); @@ -119,14 +148,15 @@ void OTAImageProcessorImpl::HandleApply(intptr_t context) ChipLogProgress(SoftwareUpdate, "OTAImageProcessorImpl::HandleApply()"); - err = bootloader_verifyImage(mSlotId, NULL); + CORE_CRITICAL_SECTION(err = bootloader_verifyImage(mSlotId, NULL);) + if (err != SL_BOOTLOADER_OK) { ChipLogError(SoftwareUpdate, "ERROR: bootloader_verifyImage() error %ld", err); return; } - err = bootloader_setImageToBootload(mSlotId); + CORE_CRITICAL_SECTION(err = bootloader_setImageToBootload(mSlotId);) if (err != SL_BOOTLOADER_OK) { ChipLogError(SoftwareUpdate, "ERROR: bootloader_setImageToBootload() error %ld", err); @@ -134,7 +164,7 @@ void OTAImageProcessorImpl::HandleApply(intptr_t context) } // This reboots the device - bootloader_rebootAndInstall(); + CORE_CRITICAL_SECTION(bootloader_rebootAndInstall();) } void OTAImageProcessorImpl::HandleAbort(intptr_t context) @@ -174,18 +204,30 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) return; } - err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, (uint8_t *) (block.data()), block.size()); - - if (err) + // Copy data into the word-aligned writeBuffer, once it fills write its contents to the bootloader storage + // Final data block is handled in HandleFinalize(). + uint32_t blockReadOffset = 0; + while (blockReadOffset < block.size()) { - ChipLogError(SoftwareUpdate, "ERROR (possible wrong bootloader version): bootloader_eraseWriteStorage() error %ld", err); - - imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); - return; + writeBuffer[writeBufOffset] = *((block.data()) + blockReadOffset); + writeBufOffset++; + blockReadOffset++; + if (writeBufOffset == kAlignmentBytes) + { + writeBufOffset = 0; + + CORE_CRITICAL_SECTION(err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, writeBuffer, kAlignmentBytes);) + if (err) + { + ChipLogError(SoftwareUpdate, "ERROR: In HandleProcessBlock bootloader_eraseWriteStorage() error %ld", err); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); + return; + } + mWriteOffset += kAlignmentBytes; + imageProcessor->mParams.downloadedBytes += kAlignmentBytes; + } } - mWriteOffset += block.size(); // Keep our own track of how far we've written - imageProcessor->mParams.downloadedBytes += block.size(); imageProcessor->mDownloader->FetchNextData(); } diff --git a/src/platform/EFR32/OTAImageProcessorImpl.h b/src/platform/EFR32/OTAImageProcessorImpl.h index b1198e71bb77ce..dac479c37bd3d5 100644 --- a/src/platform/EFR32/OTAImageProcessorImpl.h +++ b/src/platform/EFR32/OTAImageProcessorImpl.h @@ -61,12 +61,20 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface */ CHIP_ERROR ReleaseBlock(); + // EFR32 platform creates a single instance of OTAImageProcessorImpl class. + // If that changes then the use of static members and functions must be revisited static uint32_t mWriteOffset; // End of last written block static uint8_t mSlotId; // Bootloader storage slot MutableByteSpan mBlock; OTADownloader * mDownloader; OTAImageHeaderParser mHeaderParser; - const char * mImageFile = nullptr; + const char * mImageFile = nullptr; + static constexpr size_t kAlignmentBytes = 64; + // Intermediate, word-aligned buffer for writing to the bootloader storage. + // Bootloader storage API requires the buffer size to be a multiple of 4. + static uint8_t writeBuffer[kAlignmentBytes] __attribute__((aligned(4))); + // Offset indicates how far the write buffer has been filled + static uint16_t writeBufOffset; }; } // namespace chip