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

[QPG] OTA updates + Move to secure bootloader #20224

Merged
merged 3 commits into from
Jul 2, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions examples/lighting-app/qpg/include/CHIPProjectConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@
*/
#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1

/**
* CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION
*
* A uint32_t identifying the software version running on the device.
*/
#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION
#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 0x0001
#endif

/**
* CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING
*
Expand Down
20 changes: 12 additions & 8 deletions examples/persistent-storage/qpg/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,29 @@ void TestTask(void * pvParameter)
}
}

void Application_Init(void)
{
/* Launch application task */
qvCHIP_Printf(LOG_MODULE_ID, "============================");
qvCHIP_Printf(LOG_MODULE_ID, "Qorvo " APP_NAME " Launching");
qvCHIP_Printf(LOG_MODULE_ID, "============================");

// Run tests
xTaskCreateStatic(TestTask, APP_NAME, 2048, NULL, 1, appStack, &appTaskStruct);
}

int main(void)
{

int result;

/* Initialize Qorvo stack */
result = qvCHIP_init();
result = qvCHIP_init(Application_Init);
if (result < 0)
{
goto exit;
}

/* Launch application task */
qvCHIP_Printf(LOG_MODULE_ID, "============================");
qvCHIP_Printf(LOG_MODULE_ID, "Qorvo " APP_NAME " Launching");
qvCHIP_Printf(LOG_MODULE_ID, "============================");

// Run tests
xTaskCreateStatic(TestTask, APP_NAME, 2048, NULL, 1, appStack, &appTaskStruct);
qvCHIP_Printf(LOG_MODULE_ID, "Starting FreeRTOS scheduler");
vTaskStartScheduler();

Expand Down
38 changes: 15 additions & 23 deletions examples/platform/qpg/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,20 @@ constexpr int extDiscTimeoutSecs = 20;
/*****************************************************************************
* Application Function Definitions
*****************************************************************************/
CHIP_ERROR CHIP_Init(void);

int Application_Init(void)
void Application_Init(void)
{
CHIP_ERROR error;

/* Initialize CHIP stack */
error = CHIP_Init();
if (error != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "CHIP_Init failed");
return;
}

/* Launch application task */
ChipLogProgress(NotSpecified, "============================");
ChipLogProgress(NotSpecified, "Qorvo " APP_NAME " Launching");
Expand All @@ -81,10 +92,8 @@ int Application_Init(void)
if (ret != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "GetAppTask().Init() failed");
return -1;
return;
}

return 0;
}

CHIP_ERROR CHIP_Init(void)
Expand Down Expand Up @@ -172,32 +181,15 @@ CHIP_ERROR CHIP_Init(void)
int main(void)
{
int result;
CHIP_ERROR error;

/* Initialize Qorvo stack */
result = qvCHIP_init();
if (result < 0)
{
goto exit;
}

/* Initialize CHIP stack */
error = CHIP_Init();
if (error != CHIP_NO_ERROR)
{
goto exit;
}

/* Application task */
result = Application_Init();
result = qvCHIP_init(Application_Init);
if (result < 0)
{
goto exit;
return 0;
}

/* Start FreeRTOS */
vTaskStartScheduler();

exit:
return 0;
}
16 changes: 16 additions & 0 deletions examples/platform/qpg/ota/ota.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ OTAImageProcessorImpl gImageProcessor;
* Application Function Definitions
*****************************************************************************/

bool OtaHeaderValidationCb(qvCHIP_Ota_ImageHeader_t imageHeader)
{
// Check that the image matches vendor and product ID and that the version is higher than what we currently have
if (imageHeader.vendorId != CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID ||
imageHeader.productId != CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID ||
imageHeader.softwareVersion <= CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION)
{
return false;
}

return true;
}

void InitializeOTARequestor(void)
{
// Initialize and interconnect the Requestor and Image Processor objects
Expand All @@ -60,6 +73,9 @@ void InitializeOTARequestor(void)
gImageProcessor.SetOTADownloader(&gDownloader);
gDownloader.SetImageProcessorDelegate(&gImageProcessor);
gRequestorUser.Init(&gRequestorCore, &gImageProcessor);

// Initialize OTA image validation callback
qvCHIP_OtaSetHeaderValidationCb(OtaHeaderValidationCb);
}

void TriggerOTAQuery(void)
Expand Down
2 changes: 1 addition & 1 deletion src/platform/qpg/CHIPDevicePlatformConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
// ========== Platform-specific Configuration Overrides =========

#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE
#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE (5 * 1024)
#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE (6 * 1024)
#endif // CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE

#ifndef CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE
Expand Down
90 changes: 82 additions & 8 deletions src/platform/qpg/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,87 @@
*/

#include <app/clusters/ota-requestor/OTADownloader.h>
#include <app/clusters/ota-requestor/OTARequestorInterface.h>

#include "OTAImageProcessorImpl.h"

namespace chip {

bool OTAImageProcessorImpl::IsFirstImageRun()
{
OTARequestorInterface * requestor = chip::GetRequestorInstance();
if (requestor == nullptr)
{
return false;
}

return requestor->GetCurrentUpdateState() == OTARequestorInterface::OTAUpdateStateEnum::kApplying;
}

CHIP_ERROR OTAImageProcessorImpl::ConfirmCurrentImage()
{
OTARequestorInterface * requestor = chip::GetRequestorInstance();
if (requestor == nullptr)
{
return CHIP_ERROR_INTERNAL;
}

uint32_t currentVersion;
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSoftwareVersion(currentVersion));

if (currentVersion != requestor->GetTargetVersion())
{
return CHIP_ERROR_INCORRECT_STATE;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::PrepareDownload()
{

// Get OTA status - under what circumstances does prepared break?
// what happens if a prepare is pending and another one is invoked
// Should we store the state here and wait til we receive notification
// Should we store the state here and wait until we receive notification

mHeaderParser.Init();

DeviceLayer::PlatformMgr().ScheduleWork(HandlePrepareDownload, reinterpret_cast<intptr_t>(this));
return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::ProcessHeader(ByteSpan & block)
{
if (mHeaderParser.IsInitialized())
{
OTAImageHeader header;
CHIP_ERROR error = mHeaderParser.AccumulateAndDecode(block, header);

// Needs more data to decode the header
ReturnErrorCodeIf(error == CHIP_ERROR_BUFFER_TOO_SMALL, CHIP_NO_ERROR);
ReturnErrorOnFailure(error);

mParams.totalFileBytes = header.mPayloadSize;
mHeaderParser.Clear();

// Load qvCHIP_Ota header structure and call application callback to validate image header
qvCHIP_Ota_ImageHeader_t qvCHIP_OtaImgHeader;
this->mSwVer = header.mSoftwareVersion; // Store software version in imageProcessor as well
qvCHIP_OtaImgHeader.vendorId = header.mVendorId;
qvCHIP_OtaImgHeader.productId = header.mProductId;
qvCHIP_OtaImgHeader.softwareVersion = header.mSoftwareVersion;
qvCHIP_OtaImgHeader.minApplicableVersion = header.mMinApplicableVersion.ValueOr(0);
qvCHIP_OtaImgHeader.maxApplicableVersion = header.mMaxApplicableVersion.ValueOr(0);

if (true != qvCHIP_OtaValidateImage(qvCHIP_OtaImgHeader))
{
return CHIP_ERROR_UNSUPPORTED_EXCHANGE_VERSION;
}
}

return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::Finalize()
{
DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast<intptr_t>(this));
Expand All @@ -57,16 +122,27 @@ CHIP_ERROR OTAImageProcessorImpl::Abort()

CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block)
{
CHIP_ERROR err;

if ((block.data() == nullptr) || block.empty())
{
return CHIP_ERROR_INVALID_ARGUMENT;
}

// Process block header info
err = ProcessHeader(block);
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Cannot process block header: %" CHIP_ERROR_FORMAT, err.Format());
return err;
}

// Store block data for HandleProcessBlock to access
CHIP_ERROR err = SetBlock(block);
err = SetBlock(block);
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Cannot set block data: %" CHIP_ERROR_FORMAT, err.Format());
return err;
}

DeviceLayer::PlatformMgr().ScheduleWork(HandleProcessBlock, reinterpret_cast<intptr_t>(this));
Expand Down Expand Up @@ -109,8 +185,7 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context)

ChipLogProgress(SoftwareUpdate, "Q: HandleFinalize");

// FIXME - Versions need to be filled in
qvCHIP_OtaSetPendingImage(imageProcessor->mSwVer /*swVer*/, imageProcessor->mHwVer /*hwVer*/, qvCHIP_OtaGetAreaStartAddress(),
qvCHIP_OtaSetPendingImage(imageProcessor->mSwVer /*swVer*/, CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION /*hwVer*/, 0,
static_cast<std::uint32_t>(imageProcessor->mParams.downloadedBytes) /*imgSz*/);

imageProcessor->ReleaseBlock();
Expand Down Expand Up @@ -149,11 +224,10 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context)
}

ChipLogProgress(SoftwareUpdate, "Q: HandleProcessBlock");
// TODO: Process block header if any

status = qvCHIP_OtaWriteChunk(qvCHIP_OtaGetAreaStartAddress() + imageProcessor->mParams.downloadedBytes,
static_cast<std::uint16_t>(imageProcessor->mBlock.size()),
reinterpret_cast<std::uint8_t *>(imageProcessor->mBlock.data()));
status =
qvCHIP_OtaWriteChunk(imageProcessor->mParams.downloadedBytes, static_cast<std::uint16_t>(imageProcessor->mBlock.size()),
reinterpret_cast<std::uint8_t *>(imageProcessor->mBlock.data()));

if (status != qvCHIP_OtaStatusSuccess)
{
Expand Down
9 changes: 6 additions & 3 deletions src/platform/qpg/OTAImageProcessorImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#pragma once

#include <app/clusters/ota-requestor/OTADownloader.h>
#include <lib/core/OTAImageHeader.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/OTAImageProcessor.h>

Expand All @@ -29,12 +30,13 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface
public:
//////////// OTAImageProcessorInterface Implementation ///////////////
CHIP_ERROR PrepareDownload() override;
CHIP_ERROR ProcessHeader(ByteSpan & block);
CHIP_ERROR Finalize() override;
CHIP_ERROR Apply() override;
CHIP_ERROR Abort() override;
CHIP_ERROR ProcessBlock(ByteSpan & block) override;
bool IsFirstImageRun() override { return false; }
CHIP_ERROR ConfirmCurrentImage() override { return CHIP_NO_ERROR; }
bool IsFirstImageRun() override;
CHIP_ERROR ConfirmCurrentImage() override;

void SetOTADownloader(OTADownloader * downloader) { mDownloader = downloader; }

Expand All @@ -59,7 +61,8 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface
std::uint32_t mHwVer;

MutableByteSpan mBlock;
OTADownloader * mDownloader;
OTADownloader * mDownloader = nullptr;
OTAImageHeaderParser mHeaderParser;
};

} // namespace chip
16 changes: 10 additions & 6 deletions third_party/qpg_sdk/qpg_executable.gni
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@

import("//build_overrides/build.gni")
import("//build_overrides/chip.gni")
import("//build_overrides/pigweed.gni")

import("${build_root}/toolchain/flashable_executable.gni")
import("${chip_root}/src/platform/device.gni")
import("${dir_pw_build}/python_action.gni")
import("qpg_sdk.gni")

# Run the generator script that takes a .HEX file and adds the OTA header to it.
Expand All @@ -43,7 +41,7 @@ template("gen_ota_header") {
"data_deps",
])

pw_python_action(target_name) {
action(target_name) {
outputs = [ ota_header_script_name ]

args = ota_header_options
Expand Down Expand Up @@ -96,10 +94,8 @@ template("qpg_executable") {

# If OTA requestor is enabled, generate OTA image from HEX
if (chip_enable_ota_requestor) {
ota_image_name = invoker.output_name + ".ota"

gen_ota_header("$executable_target_name.ota") {
ota_header_script_name = "${root_out_dir}/${ota_image_name}"
ota_header_script_name = "${root_out_dir}/${executable_target_name}.ota"
out_dir = rebase_path(root_out_dir, root_build_dir)
ota_header_generator = "${qpg_sdk_root}/Tools/ota/generate_ota_img.py"

Expand All @@ -119,6 +115,14 @@ template("qpg_executable") {
"--out_file",
"${out_dir}/${invoker.output_name}.ota",
]),
string_join("=",
[
"--pem_file_path",
rebase_path(qpg_sdk_root, root_build_dir) +
"/Tools/ota/example_private_key.pem.example",
]),
"--pem_password=test1234",
"--sign",
]
deps = [ ":$executable_target_name" ]
}
Expand Down
2 changes: 1 addition & 1 deletion third_party/qpg_sdk/qpg_sdk.gni
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ template("qpg_sdk") {
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/MatterQorvoGlue_${qpg_target_ic}_libbuild/libMatterQorvoGlue_${qpg_target_ic}_libbuild.a",
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/QorvoStack_${qpg_target_ic}/libQorvoStack_${qpg_target_ic}.a",
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/mbedtls_alt_${qpg_target_ic}/libmbedtls_alt_${qpg_target_ic}.a",
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/Bootloader_${qpg_target_ic}/libBootloader_${qpg_target_ic}.a",
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/Bootloader_${qpg_target_ic}_compr_secure/libBootloader_${qpg_target_ic}_compr_secure.a",
]
}

Expand Down
2 changes: 1 addition & 1 deletion third_party/qpg_sdk/repo
Submodule repo updated from a29b99 to fa660d