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

[EFR32] OTA: Use word-aligned buffer in bootloader storage APIs #17281

Merged
merged 31 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
35fad7d
Test added march 8 (#15957)
kowsisoundhar12 Mar 9, 2022
d5f4b0b
[OTA] Fix OTARequestorDriverImpl inclusion (#15981)
carol-apple Mar 9, 2022
9bee828
Regen to fix CI failures (#15990)
bzbarsky-apple Mar 9, 2022
b942392
[ota] Store Default OTA Providers in flash (#15970)
Damian-Nordic Mar 9, 2022
c219807
Merge branch 'master' of github.com:project-chip/connectedhomeip
selissia Mar 11, 2022
fa279bc
Merge branch 'project-chip:master' into master
selissia Mar 11, 2022
9e18f9b
Merge branch 'project-chip:master' into master
selissia Mar 14, 2022
b6ca5ca
Merge branch 'project-chip:master' into master
selissia Mar 15, 2022
135dc25
Merge branch 'project-chip:master' into master
selissia Mar 18, 2022
0446c67
Merge branch 'project-chip:master' into master
selissia Mar 22, 2022
e69e63c
Merge branch 'project-chip:master' into master
selissia Mar 23, 2022
a40f6df
Merge branch 'project-chip:master' into master
selissia Mar 24, 2022
e5925ba
Merge branch 'project-chip:master' into master
selissia Mar 30, 2022
0435362
Merge branch 'project-chip:master' into master
selissia Apr 5, 2022
ce57ef5
Use an intermediate buffer for writing the image to the booloader sto…
selissia Apr 11, 2022
c6463f3
Use critical section in the bootloader API call
selissia Apr 12, 2022
a9970c2
Cleanup log messages, move variables into a class
selissia Apr 12, 2022
23c99a9
Remove merge artifacts
selissia Apr 12, 2022
df6bb72
Update EFR32 documentation
selissia Apr 12, 2022
a9b9a92
Fix typo
selissia Apr 12, 2022
df33dd5
Restyled by whitespace
restyled-commits Apr 12, 2022
74bc0cc
Restyled by clang-format
restyled-commits Apr 12, 2022
2714cbe
Restyled by prettier-markdown
restyled-commits Apr 12, 2022
63bf1fa
Rename array size parameter, add aligned attribute
selissia Apr 12, 2022
0b813ec
Trivial change to restart the CI (restyle job need to be kicked)
selissia Apr 12, 2022
40b3412
Merge branch 'project-chip:master' into master
selissia Apr 12, 2022
bfbd6e6
Merge branch 'master' of github.com:selissia/connectedhomeip into int…
selissia Apr 12, 2022
f8f961f
Restyled by clang-format
restyled-commits Apr 12, 2022
d197cb5
Merge branch 'project-chip:master' into master
selissia Apr 13, 2022
86310c3
Merge branch 'master' of github.com:selissia/connectedhomeip into int…
selissia Apr 13, 2022
bbf022d
Update comments
selissia Apr 13, 2022
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
8 changes: 6 additions & 2 deletions docs/guides/silabs_efr32_software_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
76 changes: 59 additions & 17 deletions src/platform/EFR32/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 };
selissia marked this conversation as resolved.
Show resolved Hide resolved

CHIP_ERROR OTAImageProcessorImpl::PrepareDownload()
{
Expand Down Expand Up @@ -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();

Expand All @@ -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<OTAImageProcessorImpl *>(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");
Expand All @@ -119,22 +148,23 @@ 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);
return;
}

// This reboots the device
bootloader_rebootAndInstall();
CORE_CRITICAL_SECTION(bootloader_rebootAndInstall();)
}

void OTAImageProcessorImpl::HandleAbort(intptr_t context)
Expand Down Expand Up @@ -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())
selissia marked this conversation as resolved.
Show resolved Hide resolved
{
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();
}

Expand Down
10 changes: 9 additions & 1 deletion src/platform/EFR32/OTAImageProcessorImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
selissia marked this conversation as resolved.
Show resolved Hide resolved
};

} // namespace chip