Skip to content

Commit

Permalink
allows the system to flash modules, particularly the bootloader by fl…
Browse files Browse the repository at this point in the history
…ashing them to the OTA backup region and then having them applied by the system firmware as a regular OTA. [CH32507]
  • Loading branch information
m-mcgowan authored and technobly committed Jun 14, 2019
1 parent 5165c25 commit aa9484e
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 7 deletions.
1 change: 1 addition & 0 deletions hal/inc/hal_dynalib_ota.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ DYNALIB_FN(6, hal_ota, HAL_FLASH_Update, int(const uint8_t*, uint32_t, uint32_t,
DYNALIB_FN(7, hal_ota, HAL_FLASH_End, hal_update_complete_t(hal_module_t*))
DYNALIB_FN(8, hal_ota, HAL_FLASH_OTA_Validate, int(hal_module_t*, bool, module_validation_flags_t, void*))
DYNALIB_FN(9, hal_ota, HAL_OTA_Add_System_Info, void(hal_system_info_t* info, bool create, void* reserved))
DYNALIB_FN(10, hal_ota, HAL_FLASH_ApplyPendingUpdate, hal_update_complete_t(hal_module_t*, bool, void*))
DYNALIB_END(hal_ota)

#endif /* HAL_DYNALIB_OTA_H */
Expand Down
7 changes: 7 additions & 0 deletions hal/inc/ota_flash_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ typedef enum {

hal_update_complete_t HAL_FLASH_End(hal_module_t* module);

/**
* @param module Optional pointer to a module that receives the module definition of the firmware that was flashed.
* @param dryRun when true, only test that the system has a pending update in memory. When false, the test is performed and the module
* applied if valid (or the bootloader instructed to apply it.)
*/
hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved);

uint32_t HAL_FLASH_ModuleAddress(uint32_t address);
uint32_t HAL_FLASH_ModuleLength(uint32_t address);
bool HAL_FLASH_VerifyCRC32(uint32_t address, uint32_t length);
Expand Down
2 changes: 1 addition & 1 deletion hal/src/core/ota_flash_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ int HAL_FLASH_OTA_Validate(hal_module_t* mod, bool userDepsOptional, module_vali
return 0;
}

hal_update_complete_t HAL_FLASH_End(hal_module_t* reserved)
hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved)
{
FLASH_End();
return HAL_UPDATE_APPLIED_PENDING_RESTART;
Expand Down
6 changes: 5 additions & 1 deletion hal/src/gcc/ota_flash_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ int HAL_FLASH_OTA_Validate(hal_module_t* mod, bool userDepsOptional, module_vali
return HAL_UPDATE_APPLIED;
}


hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved)
{
HAL_FLASH_End(module);
return HAL_UPDATE_APPLIED_PENDING_RESTART;
}

/**
* Set the claim code for this device.
Expand Down
25 changes: 25 additions & 0 deletions hal/src/nRF52840/ota_flash_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,31 @@ hal_update_complete_t HAL_FLASH_End(hal_module_t* mod)
return result;
}

// Todo this code and much of the code here is duplicated between Gen2 and Gen3
// This should be factored out into directory shared by both platforms.
hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved)
{
uint8_t otaUpdateFlag = DCT_OTA_UPDATE_FLAG_CLEAR;
STATIC_ASSERT(sizeof(otaUpdateFlag)==DCT_OTA_UPDATE_FLAG_SIZE, "expected ota update flag size to be 1");
dct_read_app_data_copy(DCT_OTA_UPDATE_FLAG_OFFSET, &otaUpdateFlag, DCT_OTA_UPDATE_FLAG_SIZE);
hal_update_complete_t result = HAL_UPDATE_ERROR;
if (otaUpdateFlag==DCT_OTA_UPDATE_FLAG_SET) {
if (dryRun) {
// todo - we should probably check the module integrity too
// ideally this parameter would be passed to HAL_FLASH_End to avoid duplication of logic here.
result = HAL_UPDATE_APPLIED;
}
else {
// clear the flag
otaUpdateFlag = DCT_OTA_UPDATE_FLAG_CLEAR;
dct_write_app_data(&otaUpdateFlag, DCT_OTA_UPDATE_FLAG_OFFSET, DCT_OTA_UPDATE_FLAG_SIZE);
result = HAL_FLASH_End(module);
}
}
return result;
}


void HAL_FLASH_Read_ServerAddress(ServerAddress* server_addr)
{
bool udp = HAL_Feature_Get(FEATURE_CLOUD_UDP);
Expand Down
25 changes: 25 additions & 0 deletions hal/src/stm32f2xx/ota_flash_hal_stm32f2xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,31 @@ hal_update_complete_t HAL_FLASH_End(hal_module_t* mod)
return result;
}

// Todo this code and much of the code here is duplicated between Gen2 and Gen3
// This should be factored out into directory shared by both platforms.
hal_update_complete_t HAL_FLASH_ApplyPendingUpdate(hal_module_t* module, bool dryRun, void* reserved)
{
uint8_t otaUpdateFlag = DCT_OTA_UPDATE_FLAG_CLEAR;
STATIC_ASSERT(sizeof(otaUpdateFlag)==DCT_OTA_UPDATE_FLAG_SIZE, "expected ota update flag size to be 1");
dct_read_app_data_copy(DCT_OTA_UPDATE_FLAG_OFFSET, &otaUpdateFlag, DCT_OTA_UPDATE_FLAG_SIZE);
hal_update_complete_t result = HAL_UPDATE_ERROR;
if (otaUpdateFlag==DCT_OTA_UPDATE_FLAG_SET) {
if (dryRun) {
// todo - we should probably check the module integrity too
// ideally this parameter would be passed to HAL_FLASH_End to avoid duplication of logic here.
result = HAL_UPDATE_APPLIED;
}
else {
// clear the flag
otaUpdateFlag = DCT_OTA_UPDATE_FLAG_CLEAR;
dct_write_app_data(&otaUpdateFlag, DCT_OTA_UPDATE_FLAG_OFFSET, DCT_OTA_UPDATE_FLAG_SIZE);
result = HAL_FLASH_End(module);
}
}
return result;
}


void copy_dct(void* target, uint16_t offset, uint16_t length) {
dct_read_app_data_copy(offset, target, length);
}
Expand Down
10 changes: 9 additions & 1 deletion platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc/dct.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ typedef struct __attribute__((packed)) application_dct {
uint8_t device_private_key[1216]; // sufficient for 2048 bits
uint8_t device_public_key[384]; // sufficient for 2048 bits
static_ip_config_t ip_config;
uint8_t unused[96];
uint8_t unused[95]; //
uint8_t ota_update_flag; // should be 0xA5 to trigger an update from data stored in the update region
uint32_t feature_flags[1]; // Configurable feature flags (see HAL_Feature_Set()). Default uninitialized value is 0xffffffff
uint8_t country_code[4]; // WICED country code. Stored as bit-endian format: CH1/CH2/0/rev (max 255)
uint8_t claim_code[63]; // claim code. no terminating null.
Expand Down Expand Up @@ -111,6 +112,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_SERVER_PUBLIC_KEY_OFFSET (offsetof(application_dct_t, server_public_key))
#define DCT_SERVER_ADDRESS_OFFSET ((DCT_SERVER_PUBLIC_KEY_OFFSET)+384)
#define DCT_IP_CONFIG_OFFSET (offsetof(application_dct_t, ip_config))
#define DCT_OTA_UPDATE_FLAG_OFFSET (offsetof(application_dct_t, ota_update_flag))
#define DCT_FEATURE_FLAGS_OFFSET (offsetof(application_dct_t, feature_flags))
#define DCT_COUNTRY_CODE_OFFSET (offsetof(application_dct_t, country_code))
#define DCT_CLAIM_CODE_OFFSET (offsetof(application_dct_t, claim_code))
Expand Down Expand Up @@ -138,6 +140,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_DEVICE_PUBLIC_KEY_SIZE (sizeof(application_dct_t::device_public_key))
#define DCT_SERVER_PUBLIC_KEY_SIZE (sizeof(application_dct_t::server_public_key))
#define DCT_IP_CONFIG_SIZE (sizeof(application_dct_t::ip_config))
#define DCT_OTA_UPDATE_FLAG_SIZE (sizeof(application_dct_t::ota_update_flag))
#define DCT_FEATURE_FLAGS_SIZE (sizeof(application_dct_t::feature_flags))
#define DCT_COUNTRY_CODE_SIZE (sizeof(application_dct_t::country_code))
#define DCT_CLAIM_CODE_SIZE (sizeof(application_dct_t::claim_code))
Expand Down Expand Up @@ -171,6 +174,7 @@ STATIC_ASSERT_DCT_OFFSET(version, 32);
STATIC_ASSERT_DCT_OFFSET(device_private_key, 34);
STATIC_ASSERT_DCT_OFFSET(device_public_key, 1250 /*34+1216*/);
STATIC_ASSERT_DCT_OFFSET(ip_config, 1634 /* 1250 + 384 */);
STATIC_ASSERT_DCT_OFFSET(ota_update_flag, 1753);
STATIC_ASSERT_DCT_OFFSET(feature_flags, 1754 /* 1634 + 120 */);
STATIC_ASSERT_DCT_OFFSET(country_code, 1758 /* 1754 + 4 */);
STATIC_ASSERT_DCT_OFFSET(claim_code, 1762 /* 1758 + 4 */);
Expand Down Expand Up @@ -212,6 +216,10 @@ STATIC_ASSERT_FLAGS_OFFSET(FeaturesEnabled_SysFlag, 19);
STATIC_ASSERT_FLAGS_OFFSET(RCC_CSR_SysFlag, 20);
STATIC_ASSERT_FLAGS_OFFSET(reserved, 24);

#define DCT_OTA_UPDATE_FLAG_SET (0xA5)
#define DCT_OTA_UPDATE_FLAG_CLEAR (0XFF)


// Note: This function is deprecated, use dct_read_app_data_copy() or dct_read_app_data_lock() instead
const void* dct_read_app_data(uint32_t offset);

Expand Down
9 changes: 8 additions & 1 deletion platform/MCU/nRF52840/inc/dct.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ typedef struct __attribute__((packed)) application_dct {
uint8_t device_private_key[1216]; // sufficient for 2048 bits
uint8_t device_public_key[384]; // sufficient for 2048 bits
static_ip_config_t ip_config;
uint8_t unused[96];
uint8_t unused[95];
uint8_t ota_update_flag; // should be 0xA5 to trigger an update from data stored in the update region
uint32_t feature_flags[1]; // Configurable feature flags (see HAL_Feature_Set()). Default uninitialized value is 0xffffffff
uint8_t country_code[4]; // WICED country code. Stored as bit-endian format: CH1/CH2/0/rev (max 255)
uint8_t claim_code[63]; // claim code. no terminating null.
Expand Down Expand Up @@ -118,6 +119,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_SERVER_PUBLIC_KEY_OFFSET (offsetof(application_dct_t, server_public_key))
#define DCT_SERVER_ADDRESS_OFFSET ((DCT_SERVER_PUBLIC_KEY_OFFSET)+384)
#define DCT_IP_CONFIG_OFFSET (offsetof(application_dct_t, ip_config))
#define DCT_OTA_UPDATE_FLAG_OFFSET (offsetof(application_dct_t, ota_update_flag))
#define DCT_FEATURE_FLAGS_OFFSET (offsetof(application_dct_t, feature_flags))
#define DCT_COUNTRY_CODE_OFFSET (offsetof(application_dct_t, country_code))
#define DCT_CLAIM_CODE_OFFSET (offsetof(application_dct_t, claim_code))
Expand Down Expand Up @@ -149,6 +151,7 @@ typedef struct __attribute__((packed)) application_dct {
#define DCT_DEVICE_PUBLIC_KEY_SIZE (sizeof(application_dct_t::device_public_key))
#define DCT_SERVER_PUBLIC_KEY_SIZE (sizeof(application_dct_t::server_public_key))
#define DCT_IP_CONFIG_SIZE (sizeof(application_dct_t::ip_config))
#define DCT_OTA_UPDATE_FLAG_SIZE (sizeof(application_dct_t::ota_update_flag))
#define DCT_FEATURE_FLAGS_SIZE (sizeof(application_dct_t::feature_flags))
#define DCT_COUNTRY_CODE_SIZE (sizeof(application_dct_t::country_code))
#define DCT_CLAIM_CODE_SIZE (sizeof(application_dct_t::claim_code))
Expand Down Expand Up @@ -178,6 +181,9 @@ typedef struct __attribute__((packed)) application_dct {
#define STATIC_ASSERT_DCT_OFFSET(field, expected) PARTICLE_STATIC_ASSERT( dct_##field, offsetof(application_dct_t, field)==expected)
#define STATIC_ASSERT_FLAGS_OFFSET(field, expected) PARTICLE_STATIC_ASSERT( dct_sysflag_##field, offsetof(platform_system_flags_t, field)==expected)

#define DCT_OTA_UPDATE_FLAG_SET (0xA5)
#define DCT_OTA_UPDATE_FLAG_CLEAR (0XFF)

/**
* Assert offsets. These ensure that the layout in flash isn't inadvertently changed.
*/
Expand All @@ -186,6 +192,7 @@ STATIC_ASSERT_DCT_OFFSET(version, 32);
STATIC_ASSERT_DCT_OFFSET(device_private_key, 34);
STATIC_ASSERT_DCT_OFFSET(device_public_key, 1250 /*34+1216*/);
STATIC_ASSERT_DCT_OFFSET(ip_config, 1634 /* 1250 + 384 */);
STATIC_ASSERT_DCT_OFFSET(ota_update_flag, 1753);
STATIC_ASSERT_DCT_OFFSET(feature_flags, 1754 /* 1634 + 120 */);
STATIC_ASSERT_DCT_OFFSET(country_code, 1758 /* 1754 + 4 */);
STATIC_ASSERT_DCT_OFFSET(claim_code, 1762 /* 1758 + 4 */);
Expand Down
8 changes: 7 additions & 1 deletion system/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,13 @@ void app_setup_and_loop(void)
bool threaded = system_thread_get_state(NULL) != spark::feature::DISABLED &&
(system_mode()!=SAFE_MODE);

Network_Setup(threaded);
if (HAL_FLASH_ApplyPendingUpdate(nullptr /*module*/, false /*dryRun*/, nullptr /*reserved*/)==HAL_UPDATE_APPLIED_PENDING_RESTART) {
// the regular OTA update delays 100 milliseconds so maintaining the same behavior.
HAL_Delay_Milliseconds(100);
HAL_Core_System_Reset_Ex(RESET_REASON_UPDATE, 0, nullptr);
}

Network_Setup(threaded); // todo - why does this come before system thread initialization?

#if PLATFORM_THREADING
if (threaded)
Expand Down
4 changes: 2 additions & 2 deletions system/src/system_update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,8 @@ int Spark_Finish_Firmware_Update(FileTransfer::Descriptor& file, uint32_t flags,
if (file.store==FileTransfer::Store::FIRMWARE)
{
hal_update_complete_t result = HAL_FLASH_End(module ? (hal_module_t*)module : &mod);
system_notify_event(firmware_update, result!=HAL_UPDATE_ERROR ? firmware_update_complete : firmware_update_failed, &file);
res = (result == HAL_UPDATE_ERROR);
system_notify_event(firmware_update, result<=HAL_UPDATE_ERROR ? firmware_update_complete : firmware_update_failed, &file);
res = (result <= HAL_UPDATE_ERROR);

// always restart for now
if ((true || result==HAL_UPDATE_APPLIED_PENDING_RESTART) && !(flags & UpdateFlag::DONT_RESET))
Expand Down

0 comments on commit aa9484e

Please sign in to comment.