Merge branch 'feature/ota_update_for_partitions' into 'master'

feat(ota): Supports OTA update for any partitions (bootloader, partition_table, nvs, etc.)

Closes IDFGH-13262, IDF-7781, and IDFGH-12860

See merge request espressif/esp-idf!32866
This commit is contained in:
Konstantin Kondrashov
2024-11-09 00:53:45 +08:00
38 changed files with 2280 additions and 82 deletions

View File

@@ -31,13 +31,19 @@
#include "esp_attr.h"
#include "esp_bootloader_desc.h"
#include "esp_flash.h"
#include "esp_flash_internal.h"
#define SUB_TYPE_ID(i) (i & 0x0F)
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
/* Partial_data is word aligned so no reallocation is necessary for encrypted flash write */
typedef struct ota_ops_entry_ {
uint32_t handle;
const esp_partition_t *part;
struct {
const esp_partition_t *staging; /*!< New image will be downloaded in this staging partition. */
const esp_partition_t *final; /*!< Final destination partition which is intended to be updated. Its type/subtype shall be used for verification. */
bool finalize_with_copy; /*!< Flag to copy the image from staging partition to the final partition at the end of OTA update */
} partition;
bool need_erase;
uint32_t wrote_size;
uint8_t partial_bytes;
@@ -52,6 +58,8 @@ static uint32_t s_ota_ops_last_handle = 0;
const static char *TAG = "esp_ota_ops";
static ota_ops_entry_t *get_ota_ops_entry(esp_ota_handle_t handle);
/* Return true if this is an OTA app partition */
static bool is_ota_partition(const esp_partition_t *p)
{
@@ -114,8 +122,6 @@ static esp_ota_img_states_t set_new_state_otadata(void)
esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle)
{
ota_ops_entry_t *new_entry;
esp_err_t ret = ESP_OK;
if ((partition == NULL) || (out_handle == NULL)) {
return ESP_ERR_INVALID_ARG;
}
@@ -125,36 +131,26 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
return ESP_ERR_NOT_FOUND;
}
if (!is_ota_partition(partition)) {
return ESP_ERR_INVALID_ARG;
}
if (partition->type == ESP_PARTITION_TYPE_APP) {
// The staging partition cannot be of type Factory, but the final partition can be.
if (!is_ota_partition(partition)) {
return ESP_ERR_INVALID_ARG;
}
const esp_partition_t* running_partition = esp_ota_get_running_partition();
if (partition == running_partition) {
return ESP_ERR_OTA_PARTITION_CONFLICT;
}
const esp_partition_t* running_partition = esp_ota_get_running_partition();
if (partition == running_partition) {
return ESP_ERR_OTA_PARTITION_CONFLICT;
}
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
esp_ota_img_states_t ota_state_running_part;
if (esp_ota_get_state_partition(running_partition, &ota_state_running_part) == ESP_OK) {
if (ota_state_running_part == ESP_OTA_IMG_PENDING_VERIFY) {
ESP_LOGE(TAG, "Running app has not confirmed state (ESP_OTA_IMG_PENDING_VERIFY)");
return ESP_ERR_OTA_ROLLBACK_INVALID_STATE;
esp_ota_img_states_t ota_state_running_part;
if (esp_ota_get_state_partition(running_partition, &ota_state_running_part) == ESP_OK) {
if (ota_state_running_part == ESP_OTA_IMG_PENDING_VERIFY) {
ESP_LOGE(TAG, "Running app has not confirmed state (ESP_OTA_IMG_PENDING_VERIFY)");
return ESP_ERR_OTA_ROLLBACK_INVALID_STATE;
}
}
}
#endif
if (image_size != OTA_WITH_SEQUENTIAL_WRITES) {
// If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition
if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) {
ret = esp_partition_erase_range(partition, 0, partition->size);
} else {
const int aligned_erase_size = (image_size + partition->erase_size - 1) & ~(partition->erase_size - 1);
ret = esp_partition_erase_range(partition, 0, aligned_erase_size);
}
if (ret != ESP_OK) {
return ret;
}
}
new_entry = (ota_ops_entry_t *) calloc(1, sizeof(ota_ops_entry_t));
@@ -164,10 +160,60 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
LIST_INSERT_HEAD(&s_ota_ops_entries_head, new_entry, entries);
new_entry->part = partition;
new_entry->partition.staging = partition;
new_entry->partition.final = partition;
new_entry->partition.finalize_with_copy = false;
new_entry->handle = ++s_ota_ops_last_handle;
new_entry->need_erase = (image_size == OTA_WITH_SEQUENTIAL_WRITES);
*out_handle = new_entry->handle;
if (partition->type == ESP_PARTITION_TYPE_BOOTLOADER) {
esp_image_bootloader_offset_set(partition->address);
}
if (partition->type == ESP_PARTITION_TYPE_BOOTLOADER || partition->type == ESP_PARTITION_TYPE_PARTITION_TABLE) {
esp_flash_set_dangerous_write_protection(esp_flash_default_chip, false);
}
if (image_size != OTA_WITH_SEQUENTIAL_WRITES) {
// If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition
size_t erase_size;
if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) {
erase_size = partition->size;
} else {
erase_size = ALIGN_UP(image_size, partition->erase_size);
}
return esp_partition_erase_range(partition, 0, erase_size);
}
return ESP_OK;
}
esp_err_t esp_ota_set_final_partition(esp_ota_handle_t handle, const esp_partition_t *final, bool finalize_with_copy)
{
ota_ops_entry_t *it = get_ota_ops_entry(handle);
if (final == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (it == NULL) {
return ESP_ERR_NOT_FOUND;
}
if (it->wrote_size != 0) {
return ESP_ERR_INVALID_STATE;
}
if (it->partition.staging != final) {
const esp_partition_t* final_partition = esp_partition_verify(final);
if (final_partition == NULL) {
return ESP_ERR_NOT_FOUND;
}
ESP_LOGI(TAG,"Staging partition - <%s>. Final partition - <%s>.", it->partition.staging->label, final_partition->label);
it->partition.final = final_partition;
it->partition.finalize_with_copy = finalize_with_copy;
if (final_partition->type == ESP_PARTITION_TYPE_BOOTLOADER) {
esp_image_bootloader_offset_set(it->partition.staging->address);
}
if (final_partition->type == ESP_PARTITION_TYPE_BOOTLOADER || final_partition->type == ESP_PARTITION_TYPE_PARTITION_TABLE) {
esp_flash_set_dangerous_write_protection(esp_flash_default_chip, false);
}
}
return ESP_OK;
}
@@ -192,23 +238,33 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
if (it->handle == handle) {
if (it->need_erase) {
// must erase the partition before writing to it
uint32_t first_sector = it->wrote_size / it->part->erase_size; // first affected sector
uint32_t last_sector = (it->wrote_size + size - 1) / it->part->erase_size; // last affected sector
uint32_t first_sector = it->wrote_size / it->partition.staging->erase_size; // first affected sector
uint32_t last_sector = (it->wrote_size + size - 1) / it->partition.staging->erase_size; // last affected sector
ret = ESP_OK;
if ((it->wrote_size % it->part->erase_size) == 0) {
ret = esp_partition_erase_range(it->part, it->wrote_size, ((last_sector - first_sector) + 1) * it->part->erase_size);
if ((it->wrote_size % it->partition.staging->erase_size) == 0) {
ret = esp_partition_erase_range(it->partition.staging, it->wrote_size, ((last_sector - first_sector) + 1) * it->partition.staging->erase_size);
} else if (first_sector != last_sector) {
ret = esp_partition_erase_range(it->part, (first_sector + 1) * it->part->erase_size, (last_sector - first_sector) * it->part->erase_size);
ret = esp_partition_erase_range(it->partition.staging, (first_sector + 1) * it->partition.staging->erase_size, (last_sector - first_sector) * it->partition.staging->erase_size);
}
if (ret != ESP_OK) {
return ret;
}
}
if (it->wrote_size == 0 && it->partial_bytes == 0 && size > 0 && data_bytes[0] != ESP_IMAGE_HEADER_MAGIC) {
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x)", data_bytes[0]);
return ESP_ERR_OTA_VALIDATE_FAILED;
if (it->wrote_size == 0 && it->partial_bytes == 0 && size > 0) {
if (it->partition.final->type == ESP_PARTITION_TYPE_APP || it->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
if (data_bytes[0] != ESP_IMAGE_HEADER_MAGIC) {
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x)", data_bytes[0]);
return ESP_ERR_OTA_VALIDATE_FAILED;
}
} else if (it->partition.final->type == ESP_PARTITION_TYPE_PARTITION_TABLE) {
if (*(uint16_t*)data_bytes != (uint16_t)ESP_PARTITION_MAGIC) {
ESP_LOGE(TAG, "Partition table image has invalid magic word (expected 0x50AA, saw 0x%04x)", *(uint16_t*)data_bytes);
return ESP_ERR_OTA_VALIDATE_FAILED;
}
}
}
if (esp_flash_encryption_enabled()) {
@@ -224,7 +280,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
return ESP_OK; /* nothing to write yet, just filling buffer */
}
/* write 16 byte to partition */
ret = esp_partition_write(it->part, it->wrote_size, it->partial_data, 16);
ret = esp_partition_write(it->partition.staging, it->wrote_size, it->partial_data, 16);
if (ret != ESP_OK) {
return ret;
}
@@ -243,7 +299,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
}
}
ret = esp_partition_write(it->part, it->wrote_size, data_bytes, size);
ret = esp_partition_write(it->partition.staging, it->wrote_size, data_bytes, size);
if(ret == ESP_OK){
it->wrote_size += size;
}
@@ -280,7 +336,7 @@ esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, s
ESP_LOGE(TAG, "Size should be 16byte aligned for flash encryption case");
return ESP_ERR_INVALID_ARG;
}
ret = esp_partition_write(it->part, offset, data_bytes, size);
ret = esp_partition_write(it->partition.staging, offset, data_bytes, size);
if (ret == ESP_OK) {
it->wrote_size += size;
}
@@ -316,6 +372,34 @@ esp_err_t esp_ota_abort(esp_ota_handle_t handle)
return ESP_OK;
}
static esp_err_t ota_verify_partition(ota_ops_entry_t *ota_ops)
{
esp_err_t ret = ESP_OK;
if (ota_ops->partition.final->type == ESP_PARTITION_TYPE_APP || ota_ops->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
esp_image_metadata_t data;
const esp_partition_pos_t part_pos = {
.offset = ota_ops->partition.staging->address,
.size = ota_ops->partition.staging->size,
};
if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
return ESP_ERR_OTA_VALIDATE_FAILED;
}
} else if (ota_ops->partition.final->type == ESP_PARTITION_TYPE_PARTITION_TABLE) {
const esp_partition_info_t *partition_table = NULL;
esp_partition_mmap_handle_t partition_table_map;
ret = esp_partition_mmap(ota_ops->partition.staging, 0, ESP_PARTITION_TABLE_MAX_LEN, ESP_PARTITION_MMAP_DATA, (const void**)&partition_table, &partition_table_map);
if (ret == ESP_OK) {
int num_partitions;
if (esp_partition_table_verify(partition_table, true, &num_partitions) != ESP_OK) {
esp_partition_munmap(partition_table_map);
return ESP_ERR_OTA_VALIDATE_FAILED;
}
esp_partition_munmap(partition_table_map);
}
}
return ret;
}
esp_err_t esp_ota_end(esp_ota_handle_t handle)
{
ota_ops_entry_t *it = get_ota_ops_entry(handle);
@@ -335,7 +419,7 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
if (it->partial_bytes > 0) {
/* Write out last 16 bytes, if necessary */
ret = esp_partition_write(it->part, it->wrote_size, it->partial_data, 16);
ret = esp_partition_write(it->partition.staging, it->wrote_size, it->partial_data, 16);
if (ret != ESP_OK) {
ret = ESP_ERR_INVALID_STATE;
goto cleanup;
@@ -344,18 +428,21 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
it->partial_bytes = 0;
}
esp_image_metadata_t data;
const esp_partition_pos_t part_pos = {
.offset = it->part->address,
.size = it->part->size,
};
if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
ret = ESP_ERR_OTA_VALIDATE_FAILED;
goto cleanup;
ret = ota_verify_partition(it);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "New image failed verification");
} else {
if (it->partition.finalize_with_copy) {
ESP_LOGI(TAG, "Copy from <%s> staging partition to <%s>...", it->partition.staging->label, it->partition.final->label);
ret = esp_partition_copy(it->partition.final, 0, it->partition.staging, 0, it->partition.final->size);
}
}
cleanup:
if (it->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
// In esp_ota_begin, bootloader offset was updated, here we return it to default.
esp_image_bootloader_offset_set(ESP_PRIMARY_BOOTLOADER_OFFSET);
}
LIST_REMOVE(it, entries);
free(it);
return ret;

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -82,7 +82,11 @@ int esp_ota_get_app_elf_sha256(char* dst, size_t size) __attribute__((deprecated
* it will lead to the ESP_ERR_OTA_ROLLBACK_INVALID_STATE error. Confirm the running app before to run download a new app,
* use esp_ota_mark_app_valid_cancel_rollback() function for it (this should be done as early as possible when you first download a new application).
*
* @param partition Pointer to info for partition which will receive the OTA update. Required.
* Note: Rollback is applicable only for app type partitions.
*
* @param partition Pointer to info for partition which will receive the OTA update. Required.
* This is considered as the staging partition (where OTA is downloaded), be default this also considered as the final partition which supposed to be updated.
* The final partition can be overwritten using esp_ota_set_final_partition() after calling esp_ota_begin() to relocate contents to the final destination partition.
* @param image_size Size of new OTA app image. Partition will be erased in order to receive this size of image. If 0 or OTA_SIZE_UNKNOWN, the entire partition is erased.
* @param out_handle On success, returns a handle which should be used for subsequent esp_ota_write() and esp_ota_end() calls.
@@ -99,6 +103,31 @@ int esp_ota_get_app_elf_sha256(char* dst, size_t size) __attribute__((deprecated
*/
esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp_ota_handle_t* out_handle);
/**
* @brief Set the final destination partition for OTA update
*
* This function configures the specified final partition as the destination for the OTA update.
* It also allows setting a flag to indicate if the image should be copied from the staging
* partition to the final partition after the OTA update completes. Otherwise, copying will need
* to be handled by custom code using esp_partition_copy().
*
* @note This can be called after esp_ota_begin() and before the OTA update has started (before esp_ota_write()).
*
* @param handle OTA update handle obtained from esp_ota_begin().
* @param final Pointer to the final destination partition where the new image will be verified and potentially finalized.
* This partition must not be NULL.
* @param finalize_with_copy Boolean flag indicating if the downloaded image should be copied
* from the staging partition to the final partition upon completion.
* Set to False if you intend to perform the final copy process manually later.
*
* @return
* - ESP_OK: final destination partition set successfully.
* - ESP_ERR_INVALID_STATE: Once the OTA update has started, changing the final destination partition is prohibited.
* - ESP_ERR_INVALID_ARG: Invalid arguments were passed (e.g., final partition is NULL).
* - ESP_ERR_NOT_FOUND: OTA handle not found or final partition verification failed.
*/
esp_err_t esp_ota_set_final_partition(esp_ota_handle_t handle, const esp_partition_t *final, bool finalize_with_copy);
/**
* @brief Write OTA update data to partition
*
@@ -113,9 +142,8 @@ esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp
* @return
* - ESP_OK: Data was written to flash successfully, or size = 0
* - ESP_ERR_INVALID_ARG: handle is invalid.
* - ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid app image magic byte.
* - ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid image magic byte.
* - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
* - ESP_ERR_OTA_SELECT_INFO_INVALID: OTA data partition has invalid contents
* - ESP_ERR_INVALID_SIZE: if write would go out of bounds of the partition
* - or one of error codes from lower-level flash driver.
*/
@@ -138,9 +166,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void* data, size_t size);
* @return
* - ESP_OK: Data was written to flash successfully.
* - ESP_ERR_INVALID_ARG: handle is invalid.
* - ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid app image magic byte.
* - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
* - ESP_ERR_OTA_SELECT_INFO_INVALID: OTA data partition has invalid contents
*/
esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, size_t size, uint32_t offset);
@@ -150,6 +176,11 @@ esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, s
* @param handle Handle obtained from esp_ota_begin().
*
* @note After calling esp_ota_end(), the handle is no longer valid and any memory associated with it is freed (regardless of result).
* @note If either the final or staging partitions were for the bootloader, then at the end of this function,
* the bootloader is reset to its default offset: esp_image_bootloader_offset_set(ESP_PRIMARY_BOOTLOADER_OFFSET)
*
* If the finalize_with_copy option is set, the staging partition will be copied to the final partition at the end of this function.
* Otherwise, copying will need to be handled by custom code using esp_partition_copy().
*
* @return
* - ESP_OK: Newly written OTA app image is valid.
@@ -258,7 +289,7 @@ esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, es
* @brief Returns the description structure of the bootloader.
*
* @param[in] bootloader_partition Pointer to bootloader partition.
* If NULL, then the current bootloader is used (the default location).
* If NULL, then the PRIMARY bootloader is used (the default location).
* offset = CONFIG_BOOTLOADER_OFFSET_IN_FLASH,
* size = CONFIG_PARTITION_TABLE_OFFSET - CONFIG_BOOTLOADER_OFFSET_IN_FLASH,
* @param[out] desc Structure of info about bootloader.

View File

@@ -0,0 +1,256 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_flash_partitions.h"
#include "esp_flash_internal.h"
#include "spi_flash_mmap.h"
#include "esp_image_format.h"
#include "esp_system.h"
#include "esp_log.h"
#include "unity.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
static const char *TAG = "test";
static uint8_t buffer[SPI_FLASH_SEC_SIZE];
// Find the unused offset after the last partition, checking that it is of the required size
static uint32_t find_unused_space(size_t required_size)
{
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
TEST_ASSERT_NOT_NULL(it);
const esp_partition_t* latest_partition = esp_partition_get(it);
for (; it != NULL; it = esp_partition_next(it)) {
const esp_partition_t *p = esp_partition_get(it);
if (p->address > latest_partition->address) {
latest_partition = p;
}
}
esp_partition_iterator_release(it);
TEST_ASSERT_NOT_NULL(latest_partition);
#if CONFIG_IDF_TARGET_LINUX
uint32_t flash_chip_size;
esp_flash_get_size(NULL, &flash_chip_size);
#else
uint32_t flash_chip_size = esp_flash_default_chip->size;
#endif // CONFIG_IDF_TARGET_LINUX
uint32_t unused_offset = latest_partition->address + latest_partition->size;
TEST_ASSERT_GREATER_OR_EQUAL_UINT32(required_size, flash_chip_size - unused_offset);
return unused_offset;
}
static void check_after_reboot(void)
{
ESP_LOGI(TAG, "App runs");
}
static void download_new_image_from_partition(esp_ota_handle_t update_handle, const esp_partition_t *copy_from_part)
{
uint32_t offset = 0;
ESP_LOGI(TAG, "Downloading image...");
do {
TEST_ESP_OK(esp_partition_read(copy_from_part, offset, buffer, sizeof(buffer)));
TEST_ESP_OK(esp_ota_write(update_handle, buffer, sizeof(buffer)));
offset += sizeof(buffer);
} while (offset < copy_from_part->size);
}
static void start_bootloader_ota_update_via_ota_bootloader_part(void)
{
const esp_partition_t *primary_bootloader;
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
const esp_partition_t *ota_bootloader;
const uint32_t ota_bootloader_offset = find_unused_space(ESP_BOOTLOADER_SIZE);
TEST_ESP_OK(esp_partition_register_external(NULL, ota_bootloader_offset, ESP_BOOTLOADER_SIZE, "OtaBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_OTA, &ota_bootloader));
esp_ota_handle_t update_handle;
TEST_ESP_OK(esp_ota_begin(ota_bootloader, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, primary_bootloader, true));
download_new_image_from_partition(update_handle, primary_bootloader);
TEST_ESP_OK(esp_ota_end(update_handle));
TEST_ESP_OK(esp_partition_deregister_external(primary_bootloader));
TEST_ESP_OK(esp_partition_deregister_external(ota_bootloader));
esp_restart();
}
TEST_CASE_MULTIPLE_STAGES("OTA update of bootloader via temp partition", "[bootloader_ota][reset=SW_CPU_RESET]", start_bootloader_ota_update_via_ota_bootloader_part, check_after_reboot);
static void start_bootloader_ota_update_via_primary_bootloader_part(void)
{
const esp_partition_t *primary_bootloader;
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
esp_ota_handle_t update_handle;
TEST_ESP_OK(esp_ota_begin(primary_bootloader, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
download_new_image_from_partition(update_handle, primary_bootloader);
TEST_ESP_OK(esp_ota_end(update_handle));
TEST_ESP_OK(esp_partition_deregister_external(primary_bootloader));
esp_restart();
}
TEST_CASE_MULTIPLE_STAGES("OTA update of bootloader via primary partition", "[bootloader_ota][reset=SW_CPU_RESET]", start_bootloader_ota_update_via_primary_bootloader_part, check_after_reboot);
static void start_partition_table_ota_update_via_ota_part_table(void)
{
const esp_partition_t *primary_partition_table;
const esp_partition_t *ota_partition_table;
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE, "PrimaryPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &primary_partition_table));
uint32_t ota_partition_table_offset = find_unused_space(ESP_PARTITION_TABLE_SIZE);
TEST_ESP_OK(esp_partition_register_external(NULL, ota_partition_table_offset, ESP_PARTITION_TABLE_SIZE, "OtaPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_OTA, &ota_partition_table));
esp_ota_handle_t update_handle;
TEST_ESP_OK(esp_ota_begin(ota_partition_table, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, primary_partition_table, true));
download_new_image_from_partition(update_handle, primary_partition_table);
TEST_ESP_OK(esp_ota_end(update_handle));
TEST_ESP_OK(esp_partition_deregister_external(primary_partition_table));
TEST_ESP_OK(esp_partition_deregister_external(ota_partition_table));
esp_restart();
}
TEST_CASE_MULTIPLE_STAGES("OTA update of partition_table via temp partition", "[partition_table_ota][reset=SW_CPU_RESET]", start_partition_table_ota_update_via_ota_part_table, check_after_reboot);
static void start_partition_table_ota_update_via_primary_part_table(void)
{
const esp_partition_t *primary_partition_table;
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE, "PrimaryPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &primary_partition_table));
esp_ota_handle_t update_handle;
TEST_ESP_OK(esp_ota_begin(primary_partition_table, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
download_new_image_from_partition(update_handle, primary_partition_table);
TEST_ESP_OK(esp_ota_end(update_handle));
TEST_ESP_OK(esp_partition_deregister_external(primary_partition_table));
esp_restart();
}
TEST_CASE_MULTIPLE_STAGES("OTA update of partition_table via primary partition", "[partition_table_ota][reset=SW_CPU_RESET]", start_partition_table_ota_update_via_primary_part_table, check_after_reboot);
TEST_CASE("OTA update of NVS partition", "[nvs_ota]")
{
// intilaize "nvs" partition and define a var (magic_value).
TEST_ESP_OK(nvs_flash_erase());
TEST_ESP_OK(nvs_flash_init());
nvs_handle_t my_handle;
TEST_ESP_OK(nvs_open("namespace", NVS_READWRITE, &my_handle));
uint32_t magic_value = 0x0729FEED;
TEST_ESP_OK(nvs_set_u32(my_handle, "magic_value", magic_value));
TEST_ESP_OK(nvs_commit(my_handle));
magic_value = 0;
TEST_ESP_OK(nvs_get_u32(my_handle, "magic_value", &magic_value));
TEST_ASSERT_EQUAL_HEX(0x0729FEED, magic_value);
nvs_close(my_handle);
TEST_ESP_OK(nvs_flash_deinit());
// register a new "nvs2" partition
const esp_partition_t *nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "nvs");
const esp_partition_t *nvs2_part;
TEST_ESP_OK(esp_partition_register_external(NULL, find_unused_space(nvs_part->size), nvs_part->size, "nvs2", ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, &nvs2_part));
ESP_LOGI(TAG, "Use %s partition (0x%08" PRIx32 ") to load a new image", nvs2_part->label, nvs2_part->address);
TEST_ESP_OK(nvs_flash_erase_partition("nvs2"));
// OTA update of the new "nvs2" partition, taking "nvs" partition as source.
esp_ota_handle_t update_handle;
TEST_ESP_OK(esp_ota_begin(nvs2_part, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
download_new_image_from_partition(update_handle, nvs_part);
TEST_ESP_OK(esp_ota_end(update_handle));
// init "nvs2" partition and check if the magic_value == 0x0729FEED
TEST_ESP_OK(nvs_flash_init_partition("nvs2"));
nvs_handle_t my_handle2;
TEST_ESP_OK(nvs_open_from_partition("nvs2", "namespace", NVS_READWRITE, &my_handle2));
magic_value = 0;
TEST_ESP_OK(nvs_get_u32(my_handle2, "magic_value", &magic_value));
TEST_ASSERT_EQUAL_HEX(0x0729FEED, magic_value);
nvs_close(my_handle2);
TEST_ESP_OK(nvs_flash_deinit_partition("nvs2"));
// deregister "nvs2"
TEST_ESP_OK(esp_partition_deregister_external(nvs2_part));
TEST_ESP_OK(nvs_flash_erase());
}
static void start_bootloader_ota_update_via_app_part(void)
{
const esp_partition_t *primary_bootloader;
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
const esp_partition_t *free_app_ota_partition = esp_ota_get_next_update_partition(NULL);
esp_ota_handle_t update_handle;
TEST_ESP_OK(esp_ota_begin(free_app_ota_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, primary_bootloader, true));
download_new_image_from_partition(update_handle, primary_bootloader);
TEST_ESP_OK(esp_ota_end(update_handle));
TEST_ESP_OK(esp_partition_deregister_external(primary_bootloader));
esp_restart();
}
TEST_CASE_MULTIPLE_STAGES("OTA update of bootloader via a free ota partition", "[bootloader_ota][reset=SW_CPU_RESET]", start_bootloader_ota_update_via_app_part, check_after_reboot);
static void start_partition_table_ota_update_via_app_part(void)
{
const esp_partition_t *primary_partition_table;
TEST_ESP_OK(esp_partition_register_external(NULL, ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE, "PrimaryPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &primary_partition_table));
const esp_partition_t *free_app_ota_partition = esp_ota_get_next_update_partition(NULL);
esp_ota_handle_t update_handle;
TEST_ESP_OK(esp_ota_begin(free_app_ota_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, primary_partition_table, true));
download_new_image_from_partition(update_handle, primary_partition_table);
TEST_ESP_OK(esp_ota_end(update_handle));
TEST_ESP_OK(esp_partition_deregister_external(primary_partition_table));
esp_restart();
}
TEST_CASE_MULTIPLE_STAGES("OTA update of partition_table via a free ota partition", "[partition_table_ota][reset=SW_CPU_RESET]", start_partition_table_ota_update_via_app_part, check_after_reboot);
TEST_CASE("OTA update of NVS partition via a free ota partition", "[nvs_ota]")
{
// intilaize "nvs" partition and define a var (magic_value).
const esp_partition_t *nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "nvs");
TEST_ESP_OK(nvs_flash_erase());
TEST_ESP_OK(nvs_flash_init());
nvs_handle_t my_handle;
TEST_ESP_OK(nvs_open("namespace", NVS_READWRITE, &my_handle));
uint32_t magic_value = 0x0729FEED;
TEST_ESP_OK(nvs_set_u32(my_handle, "magic_value", magic_value));
TEST_ESP_OK(nvs_commit(my_handle));
magic_value = 0;
TEST_ESP_OK(nvs_get_u32(my_handle, "magic_value", &magic_value));
TEST_ASSERT_EQUAL_HEX(0x0729FEED, magic_value);
nvs_close(my_handle);
TEST_ESP_OK(nvs_flash_deinit());
// 1. OTA update nvs partition into free_app_ota_partition
// 2. copy free_app_ota_partition into the original nvs partition (which was erased before coping)
const esp_partition_t *free_app_ota_partition = esp_ota_get_next_update_partition(NULL);
esp_ota_handle_t update_handle;
TEST_ESP_OK(esp_ota_begin(free_app_ota_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle));
TEST_ESP_OK(esp_ota_set_final_partition(update_handle, nvs_part, true));
download_new_image_from_partition(update_handle, nvs_part);
TEST_ESP_OK(esp_ota_end(update_handle));
// Check if the magic_value == 0x0729FEED
TEST_ESP_OK(nvs_flash_init());
TEST_ESP_OK(nvs_open("namespace", NVS_READONLY, &my_handle));
magic_value = 0;
TEST_ESP_OK(nvs_get_u32(my_handle, "magic_value", &magic_value));
TEST_ASSERT_EQUAL_HEX(0x0729FEED, magic_value);
nvs_close(my_handle);
TEST_ESP_OK(nvs_flash_deinit());
TEST_ESP_OK(nvs_flash_erase());
}

View File

@@ -43,7 +43,12 @@ static const char *TAG = "ota_test";
static void set_boot_count_in_nvs(uint8_t boot_count)
{
nvs_handle_t boot_count_handle;
TEST_ESP_OK(nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle));
esp_err_t err = nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle);
if (err != ESP_OK) {
TEST_ESP_OK(nvs_flash_erase());
TEST_ESP_OK(nvs_flash_init());
TEST_ESP_OK(nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle));
}
TEST_ESP_OK(nvs_set_u8(boot_count_handle, "boot_count", boot_count));
TEST_ESP_OK(nvs_commit(boot_count_handle));
nvs_close(boot_count_handle);

View File

@@ -63,7 +63,20 @@ static void init_efuse_virtual(void)
// esp_flash must be initialized in advance because here we read the efuse partition.
const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL);
if (efuse_partition) {
/*
* esp_partition_find_first triggers the reading of partitions from the partition table.
* However, since the efuses have not yet been read from the 'efuse_em' partition,
* the encryption flag for these partitions is set to false.
*
* Unloading all partitions ensures that the next time the esp_partition API is called,
* the efuses will have been read, and the correct encryption flags will be applied.
*/
esp_efuse_init_virtual_mode_in_flash(efuse_partition->address, efuse_partition->size);
esp_partition_unload_all();
// Use volatile to ensure this function call is not optimized out and the partition table will be loaded again.
volatile const esp_partition_t *dummy_partition = esp_partition_find_first(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
(void) dummy_partition;
}
#else // !CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
// For efuse virtual mode we need to seed virtual efuses from efuse_regs.

View File

@@ -9,6 +9,7 @@
#include <esp_http_client.h>
#include <bootloader_common.h>
#include "esp_app_desc.h"
#include "esp_bootloader_desc.h"
#include <sdkconfig.h>
#include "esp_event.h"
@@ -26,7 +27,7 @@ ESP_EVENT_DECLARE_BASE(ESP_HTTPS_OTA_EVENT);
typedef enum {
ESP_HTTPS_OTA_START, /*!< OTA started */
ESP_HTTPS_OTA_CONNECTED, /*!< Connected to server */
ESP_HTTPS_OTA_GET_IMG_DESC, /*!< Read app description from image header */
ESP_HTTPS_OTA_GET_IMG_DESC, /*!< Read app/bootloader description from image header */
ESP_HTTPS_OTA_VERIFY_CHIP_ID, /*!< Verify chip id of new image */
ESP_HTTPS_OTA_DECRYPT_CB, /*!< Callback to decrypt function */
ESP_HTTPS_OTA_WRITE_FLASH, /*!< Flash write operation */
@@ -68,6 +69,11 @@ typedef struct {
void *decrypt_user_ctx; /*!< User context for external decryption layer */
uint16_t enc_img_header_size; /*!< Header size of pre-encrypted ota image header */
#endif
struct { /*!< Details of staging and final partitions for OTA update */
const esp_partition_t *staging; /*!< New image will be downloaded in this staging partition. If NULL then a free app partition (passive app partition) is selected as the staging partition. */
const esp_partition_t *final; /*!< Final destination partition. Its type/subtype will be used for verification. If set to NULL, staging partition shall be set as the final partition. */
bool finalize_with_copy; /*!< Flag to copy the staging image to the final partition at the end of OTA update */
} partition; /*!< Struct containing details about the staging and final partitions for OTA update. */
} esp_https_ota_config_t;
#define ESP_ERR_HTTPS_OTA_BASE (0x9000)
@@ -223,6 +229,23 @@ esp_err_t esp_https_ota_abort(esp_https_ota_handle_t https_ota_handle);
*/
esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info);
/**
* @brief Reads bootloader description from image header. The bootloader description provides information
* like the "Bootloader version" of the image.
*
* @note This API can be called only after esp_https_ota_begin() and before esp_https_ota_perform().
* Calling this API is not mandatory.
*
* @param[in] https_ota_handle pointer to esp_https_ota_handle_t structure
* @param[out] new_img_info pointer to an allocated esp_bootloader_desc_t structure
*
* @return
* - ESP_ERR_INVALID_ARG: Invalid arguments
* - ESP_ERR_INVALID_STATE: Invalid state to call this API. esp_https_ota_begin() not called yet.
* - ESP_FAIL: Failed to read image descriptor
* - ESP_OK: Successfully read image descriptor
*/
esp_err_t esp_https_ota_get_bootloader_img_desc(esp_https_ota_handle_t https_ota_handle, esp_bootloader_desc_t *new_img_info);
/**
* @brief This function returns OTA image data read so far.

View File

@@ -39,7 +39,11 @@ typedef enum {
struct esp_https_ota_handle {
esp_ota_handle_t update_handle;
const esp_partition_t *update_partition;
struct { /*!< Details of staging and final partitions for OTA update */
const esp_partition_t *staging; /*!< New image will be downloaded in this staging partition. If NULL then a free app partition (passive app partition) is selected as the staging partition. */
const esp_partition_t *final; /*!< Final destination partition which is intended to be updated. Its type/subtype shall be used for verification. If NULL, staging partition is considered as the final partition. */
bool finalize_with_copy; /*!< Flag to copy the staging image to the final at the end of OTA update */
} partition;
esp_http_client_handle_t http_client;
char *ota_upgrade_buf;
size_t ota_upgrade_buf_size;
@@ -368,16 +372,35 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
#endif
}
https_ota_handle->update_partition = NULL;
https_ota_handle->partition.staging = NULL;
ESP_LOGI(TAG, "Starting OTA...");
https_ota_handle->update_partition = esp_ota_get_next_update_partition(NULL);
if (https_ota_handle->update_partition == NULL) {
ESP_LOGE(TAG, "Passive OTA partition not found");
if (ota_config->partition.staging != NULL) {
https_ota_handle->partition.staging = esp_partition_verify(ota_config->partition.staging);
} else {
https_ota_handle->partition.staging = esp_ota_get_next_update_partition(NULL);
}
if (https_ota_handle->partition.staging == NULL) {
ESP_LOGE(TAG, "Given staging partition or another suitable Passive OTA partition could not be found");
err = ESP_FAIL;
goto http_cleanup;
}
ESP_LOGI(TAG, "Writing to <%s> partition at offset 0x%" PRIx32,
https_ota_handle->update_partition->label, https_ota_handle->update_partition->address);
https_ota_handle->partition.staging->label, https_ota_handle->partition.staging->address);
if (ota_config->partition.final == NULL) {
https_ota_handle->partition.final = https_ota_handle->partition.staging;
} else {
if (ota_config->partition.staging != ota_config->partition.final) {
const esp_partition_t *final = esp_partition_verify(ota_config->partition.final);
if (final == NULL) {
ESP_LOGE(TAG, "Given final partition not found");
err = ESP_FAIL;
goto http_cleanup;
}
https_ota_handle->partition.final = final;
https_ota_handle->partition.finalize_with_copy = ota_config->partition.finalize_with_copy;
}
}
const int alloc_size = MAX(ota_config->http_config->buffer_size, DEFAULT_OTA_BUF_SIZE);
if (ota_config->buffer_caps != 0) {
@@ -449,7 +472,7 @@ static esp_err_t read_header(esp_https_ota_t *handle)
return ESP_OK;
}
esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info)
static esp_err_t get_description_from_image(esp_https_ota_handle_t https_ota_handle, void *new_img_info)
{
esp_https_ota_dispatch_event(ESP_HTTPS_OTA_GET_IMG_DESC, NULL, 0);
@@ -460,7 +483,7 @@ esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, es
#endif
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
if (handle == NULL || new_app_info == NULL) {
if (handle == NULL || new_img_info == NULL) {
ESP_LOGE(TAG, "esp_https_ota_get_img_desc: Invalid argument");
return ESP_ERR_INVALID_ARG;
}
@@ -472,17 +495,41 @@ esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, es
return ESP_FAIL;
}
const int app_desc_offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t);
esp_app_desc_t *app_info = (esp_app_desc_t *) &handle->ota_upgrade_buf[app_desc_offset];
if (app_info->magic_word != ESP_APP_DESC_MAGIC_WORD) {
ESP_LOGE(TAG, "Incorrect app descriptor magic");
void *img_info = (void *)&handle->ota_upgrade_buf[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)];
unsigned img_info_len;
if (handle->partition.final->type == ESP_PARTITION_TYPE_APP) {
img_info_len = sizeof(esp_app_desc_t);
esp_app_desc_t *app_info = (esp_app_desc_t *)img_info;
if (app_info->magic_word != ESP_APP_DESC_MAGIC_WORD) {
ESP_LOGE(TAG, "Incorrect app descriptor magic");
return ESP_FAIL;
}
} else if (handle->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
img_info_len = sizeof(esp_bootloader_desc_t);
esp_bootloader_desc_t *bootloader_info = (esp_bootloader_desc_t *)img_info;
if (bootloader_info->magic_byte != ESP_BOOTLOADER_DESC_MAGIC_BYTE) {
ESP_LOGE(TAG, "Incorrect bootloader descriptor magic");
return ESP_FAIL;
}
} else {
ESP_LOGE(TAG, "This partition type (%d) is not supported", handle->partition.final->type);
return ESP_FAIL;
}
memcpy(new_app_info, app_info, sizeof(esp_app_desc_t));
memcpy(new_img_info, img_info, img_info_len);
return ESP_OK;
}
esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info)
{
return get_description_from_image(https_ota_handle, new_app_info);
}
esp_err_t esp_https_ota_get_bootloader_img_desc(esp_https_ota_handle_t https_ota_handle, esp_bootloader_desc_t *new_img_info)
{
return get_description_from_image(https_ota_handle, new_img_info);
}
static esp_err_t esp_ota_verify_chip_id(const void *arg)
{
esp_image_header_t *data = (esp_image_header_t *)(arg);
@@ -512,11 +559,12 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
const int erase_size = handle->bulk_flash_erase ? (handle->image_length > 0 ? handle->image_length : OTA_SIZE_UNKNOWN) : OTA_WITH_SEQUENTIAL_WRITES;
switch (handle->state) {
case ESP_HTTPS_OTA_BEGIN:
err = esp_ota_begin(handle->update_partition, erase_size, &handle->update_handle);
err = esp_ota_begin(handle->partition.staging, erase_size, &handle->update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
return err;
}
esp_ota_set_final_partition(handle->update_handle, handle->partition.final, handle->partition.finalize_with_copy);
handle->state = ESP_HTTPS_OTA_IN_PROGRESS;
/* In case `esp_https_ota_get_img_desc` was invoked first,
then the image data read there should be written to OTA partition
@@ -550,9 +598,11 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
return ESP_FAIL;
}
#endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
err = esp_ota_verify_chip_id(data_buf);
if (err != ESP_OK) {
return err;
if (handle->partition.final->type == ESP_PARTITION_TYPE_APP || handle->partition.final->type == ESP_PARTITION_TYPE_BOOTLOADER) {
err = esp_ota_verify_chip_id(data_buf);
if (err != ESP_OK) {
return err;
}
}
return _ota_write(handle, data_buf, binary_file_len);
case ESP_HTTPS_OTA_IN_PROGRESS:
@@ -674,12 +724,16 @@ esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)
break;
}
if ((err == ESP_OK) && (handle->state == ESP_HTTPS_OTA_SUCCESS)) {
err = esp_ota_set_boot_partition(handle->update_partition);
if ((handle->partition.final->type == ESP_PARTITION_TYPE_APP) && (err == ESP_OK) && (handle->state == ESP_HTTPS_OTA_SUCCESS)) {
if (handle->partition.final->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_0 && handle->partition.final->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX) {
// Do not allow the boot partition to be set as the Factory partition, because ota_data will be erased in this case.
// The user can call it afterward if needed.
err = esp_ota_set_boot_partition(handle->partition.staging);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err);
} else {
esp_https_ota_dispatch_event(ESP_HTTPS_OTA_UPDATE_BOOT_PARTITION, (void *)(&handle->update_partition->subtype), sizeof(esp_partition_subtype_t));
esp_https_ota_dispatch_event(ESP_HTTPS_OTA_UPDATE_BOOT_PARTITION, (void *)(&handle->partition.final->subtype), sizeof(esp_partition_subtype_t));
}
}
free(handle);

View File

@@ -33,6 +33,7 @@
#include "esp_log.h"
#include "esp_rom_md5.h"
#include "bootloader_util.h"
#include "hal/efuse_hal.h"
#if CONFIG_IDF_TARGET_LINUX
#include "esp_private/partition_linux.h"
@@ -92,6 +93,10 @@ static bool is_partition_encrypted(bool encryption_config, esp_partition_type_t
are always encrypted */
ret_encrypted = true;
}
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
// FE can be enabled in virt eFuses but not in real eFuses.
ret_encrypted &= efuse_hal_flash_encryption_enabled();
#endif
return ret_encrypted;
#endif
}

View File

@@ -150,6 +150,8 @@ Application Examples
- :example:`system/ota/advanced_https_ota` demonstrates how to use the Advanced HTTPS OTA update functionality on {IDF_TARGET_NAME} using the `esp_https_ota` component's APIs. For the applicable SoCs, please refer to :example_file:`system/ota/advanced_https_ota/README.md`.
- :example:`system/ota/partitions_ota` demonstrates how to perform OTA updates for various partitions (app, bootloader, partition table, storage) using the `esp_https_ota` component's APIs.
- :example:`system/ota/simple_ota_example` demonstrates how to use the `esp_https_ota` component's APIs to support firmware upgrades through specific networking interfaces such as Ethernet or Wi-Fi Station on {IDF_TARGET_NAME}. For the applicable SoCs, please refer to :example_file:`system/ota/simple_ota_example/README.md`.
API Reference

View File

@@ -8,9 +8,17 @@ OTA Process Overview
The OTA update mechanism allows a device to update itself based on data received while the normal firmware is running (for example, over Wi-Fi, Bluetooth or Ethernet).
OTA requires configuring the :doc:`../../api-guides/partition-tables` of the device with at least two OTA app slot partitions (i.e., ``ota_0`` and ``ota_1``) and an OTA Data Partition.
The following modes support OTA updates for certain partitions:
The OTA operation functions write a new app firmware image to whichever OTA app slot that is currently not selected for booting. Once the image is verified, the OTA Data partition is updated to specify that this image should be used for the next boot.
- **Safe update mode**. The update process for certain partitions is designed to be resilient, ensuring that even if the power is cut off during the update, the chip will remain operational and capable of booting the current application. The following partitions support this mode:
- Application. OTA requires configuring the :doc:`../../api-guides/partition-tables` of the device with at least two OTA app slot partitions (i.e., ``ota_0`` and ``ota_1``) and an OTA Data Partition. The OTA operation functions write a new app firmware image to whichever OTA app slot that is currently not selected for booting. Once the image is verified, the OTA Data partition is updated to specify that this image should be used for the next boot.
- **Unsafe update mode**. The update process is vulnerable, meaning that a power interruption during the update can cause issues that prevent the current application from loading, potentially leading to an unrecoverable state. The temporary partition receives the new image, and once it is fully downloaded, the image is copied to the final destination partition. If an interruption occurs during this final copying process, it can lead to issues. The following partitions support this mode:
- Bootloader.
- Partition table.
- other data partitions like nvs, fat, etc.
.. _ota_data_partition:

View File

@@ -172,6 +172,25 @@ examples/system/ota/otatool:
enable:
- if: INCLUDE_DEFAULT == 1 or IDF_TARGET in ["esp32c5", "esp32c61"]
examples/system/ota/partitions_ota:
disable:
- if: IDF_TARGET in ["esp32h2"]
temporary: true
reason: target esp32h2 is not supported yet
disable_test:
- if: IDF_TARGET not in ["esp32", "esp32c3", "esp32s3"]
temporary: true
reason: lack of runners
depends_components:
- app_update
- esp_https_ota
- esp_http_client
# different configs need different components
- esp_eth
- esp_wifi
- esp_phy
- mbedtls
examples/system/ota/pre_encrypted_ota:
disable:
- if: IDF_TARGET in ["esp32h2"]

View File

@@ -15,7 +15,15 @@ An application on "ESP-Dev-Board" may be upgraded at runtime by downloading a ne
- Using the native APIs provided by the [`app_update`](../../../components/app_update) component.
- Using simplified APIs provided by the [`esp_https_ota`](../../../components/esp_https_ota) component, which provides functionality to upgrade over HTTPS.
Use of the native API is demonstrated in the `native_ota_example` directory while the API provided by the `esp_https_ota` component is demonstrated under `simple_ota_example` and `advanced_https_ota`.
Use of the native API is demonstrated in the `native_ota_example` directory while the API provided by the `esp_https_ota` component is demonstrated under `simple_ota_example`, `advanced_https_ota`, and `partitions_ota`.
The `partitions_ota` demonstrates the OTA update process for any partition type (other examples support only safe updates for application):
- Application (safe update).
- Bootloader (unsafe update).
- Partition table (unsafe update).
- other data partitions (unsafe update).
**Note:** **Safe updates** are designed to ensure that the device remains operational even if the update process is interrupted. This means that the device can still boot and function normally, minimizing the risk of failure. On the other hand, **unsafe updates** carry a significant risk. If the update is disrupted while copying to the destination partition, it can lead to critical failures, potentially making the device inoperable and unrecoverable. Since the final copying is performed on the user side, this risk can be minimized by ensuring stable power and error-free conditions during this time.
For information regarding the `esp_https_ota` component, please refer to [ESP HTTPS OTA](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_https_ota.html).

View File

@@ -0,0 +1,15 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(partitions_ota)
# Copy storage.bin from test folder to build directory
add_custom_target(copy_storage_bin ALL
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/test/storage.bin
${CMAKE_BINARY_DIR}/storage.bin
COMMENT "Copying test/storage.bin to build directory"
DEPENDS ${CMAKE_SOURCE_DIR}/test/storage.bin
)

View File

@@ -0,0 +1,633 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
# Partition OTA Example
This example demonstrates how to perform OTA updates for various partitions using the `esp_https_ota` component's APIs. The following partitions can be updated:
- Application (app)
- Bootloader
- Partition Table
- Storage
This example can be easily modified to perform OTA updates for any partition type.
> ⚠️ **WARNING**: Updating the bootloader and partition table is not safe. If the final copying to the destination partition is interrupted, the chip may fail to boot. Ensure that the final copy occurs only when power is stable and there is a low risk of errors.
## OTA Update
Currently, there is no rollback mechanism for non-application partitions. In case of failure, only the application partition can safely rollback.
### Application
Application OTA updates use one active and one passive partition. The new image is downloaded into the passive partition. Once the download is complete and verified, the device switches to the new image. This approach ensures that unexpected reboots during the update do not render the device unusable.
### Bootloader
Bootloader OTA updates are not inherently safe because the ROM bootloader does not support fallback to a recovery bootloader partition. Only the primary bootloader partition can be loaded by the ROM bootloader. Updating the bootloader is rarely necessary, and it is generally not recommended. However, if required, it can be done using the following approaches:
- Register the primary bootloader partition in the partition table, if not already present (see `test/partitions_efuse_emul_2.csv`).
- Decide where to download the new bootloader image:
- Use a passive app partition, if app rollback is not used at the same time.
- Use a dedicated OTA bootloader partition (type=bootloader, subtype=ota). You can find unallocated flash space with `partition_utils_find_unallocated()`.
- Download directly into the primary bootloader partition (this approach is highly unsafe).
After verification, if `finalize_with_copy` is set to `true`, the tool will automatically copy the new image to the primary bootloader partition. Set `finalize_with_copy` to `false` if you wish to control the final copy step manually.
Limitations for Bootloader OTA updates:
- Secure Boot V1-enabled devices do not support bootloader updates.
- There is always a risk of device bricking when updating the bootloader.
### Partition Table
Updating the partition table via OTA is similarly unsafe because the bootloader cannot use a backup partition table in case of failure. If the update fails, the device will be unable to boot. Partition table updates are rarely needed, and caution is strongly advised. The workflow for partition table updates is the same as for the bootloader.
### Storage
Updating storage partitions via OTA is also risky due to the potential for data loss in the partition. There is no fallback mechanism if an error occurs during the update. The workflow for Storage updates is the same as for the bootloader.
## Configuration
Refer to the README.md file in the parent directory for setup instructions.
This example supports binding to a specific network interface ("Ethernet" or "WiFi Station") for firmware updates. You can configure this in `idf.py menuconfig -> Example Configuration -> Support firmware upgrade bind specified interface -> Choose OTA data bind interface`.
The CSV partition table file may include these entries at the beginning (see `test/partitions_efuse_emul_2.csv`):
```
PrimaryBTLDR, bootloader, primary, N/A, N/A, encrypted
PrimaryPrtTable, partition_table, primary, N/A, N/A, encrypted
```
## Example output
Running the exapmple with sdkconfig.ci.on_update_no_sb_rsa settings:
```
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2820,len:0x15a0
load:0x403c8700,len:0x4
load:0x403c8704,len:0xd20
load:0x403cb700,len:0x2f3c
entry 0x403c8928
I (27) boot: ESP-IDF 95a1e4cd 2nd stage bootloader
I (27) boot: compile time Oct 28 2024 15:26:41
I (27) boot: Multicore bootloader
I (27) boot: chip revision: v0.1
I (30) boot: efuse block revision: v1.2
I (34) boot.esp32s3: Boot SPI Speed : 80MHz
I (37) boot.esp32s3: SPI Mode : DIO
I (41) boot.esp32s3: SPI Flash Size : 4MB
I (45) boot: Enabling RNG early entropy source...
I (49) boot: Partition Table:
I (52) boot: ## Label Usage Type ST Offset Length
I (58) boot: 0 nvs WiFi data 01 02 0000d000 00006000
I (65) boot: 1 nvs_key NVS keys 01 04 00013000 00001000
I (71) boot: 2 storage Unknown data 01 06 00014000 00001000
I (78) boot: 3 otadata OTA data 01 00 00015000 00002000
I (84) boot: 4 phy_init RF data 01 01 00017000 00001000
I (91) boot: 5 emul_efuse efuse 01 05 00018000 00002000
I (97) boot: 6 ota_0 OTA app 00 10 00020000 001b0000
I (104) boot: 7 ota_1 OTA app 00 11 001d0000 001b0000
I (111) boot: End of partition table
I (114) boot: No factory image, trying OTA 0
I (118) esp_image: segment 0: paddr=00020020 vaddr=3c090020 size=24288h (148104) map
I (152) esp_image: segment 1: paddr=000442b0 vaddr=3fc98900 size=04970h ( 18800) load
I (156) esp_image: segment 2: paddr=00048c28 vaddr=40374000 size=073f0h ( 29680) load
I (162) esp_image: segment 3: paddr=00050020 vaddr=42000020 size=8fc00h (588800) map
I (267) esp_image: segment 4: paddr=000dfc28 vaddr=4037b3f0 size=0d4ach ( 54444) load
I (279) esp_image: segment 5: paddr=000ed0dc vaddr=600fe100 size=0001ch ( 28) load
I (287) boot: Loaded app from partition at offset 0x20000
I (429) boot: Set actual ota_seq=1 in otadata[0]
I (430) boot: Disabling RNG early entropy source...
I (439) cpu_start: Multicore app
I (449) cpu_start: Pro cpu start user code
I (449) cpu_start: cpu freq: 160000000 Hz
I (449) app_init: Application information:
I (449) app_init: Project name: partitions_ota
I (453) app_init: App version: 95a1e4cd
I (457) app_init: Compile time: Oct 28 2024 15:26:38
I (462) app_init: ELF file SHA256: 0810d7fd3...
I (467) app_init: ESP-IDF: 95a1e4cd
I (471) efuse_init: Min chip rev: v0.0
I (475) efuse_init: Max chip rev: v0.99
I (479) efuse_init: Chip rev: v0.1
I (482) heap_init: Initializing. RAM available for dynamic allocation:
I (489) heap_init: At 3FCA14A0 len 00048270 (288 KiB): RAM
I (494) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (499) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (504) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
I (511) spi_flash: detected chip: generic
I (513) spi_flash: flash io: dio
W (516) spi_flash: Detected size(8192k) larger than the size in the binary image header(4096k). Using the size in the binary image header.
I (530) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (535) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (542) main_task: Started on CPU0
I (562) main_task: Calling app_main()
I (562) ota_example: OTA example app_main start
I (572) example_connect: Start example_connect.
I (572) pp: pp rom version: e7ae62f
I (572) net80211: net80211 rom version: e7ae62f
I (592) wifi:wifi driver task: 3fcab44c, prio:23, stack:6656, core=0
I (592) wifi:wifi firmware version: 2d9c351b0
I (592) wifi:wifi certification version: v7.0
I (592) wifi:config NVS flash: enabled
I (592) wifi:config nano formatting: disabled
I (602) wifi:Init data frame dynamic rx buffer num: 32
I (602) wifi:Init static rx mgmt buffer num: 5
I (612) wifi:Init management short buffer num: 32
I (612) wifi:Init dynamic tx buffer num: 32
I (612) wifi:Init static tx FG buffer num: 2
I (622) wifi:Init static rx buffer size: 1600
I (622) wifi:Init static rx buffer num: 10
I (632) wifi:Init dynamic rx buffer num: 32
I (632) wifi_init: rx ba win: 6
I (632) wifi_init: accept mbox: 6
I (642) wifi_init: tcpip mbox: 32
I (642) wifi_init: udp mbox: 6
I (642) wifi_init: tcp mbox: 6
I (642) wifi_init: tcp tx win: 5760
I (652) wifi_init: tcp rx win: 5760
I (652) wifi_init: tcp mss: 1440
I (652) wifi_init: WiFi IRAM OP enabled
I (662) wifi_init: WiFi RX IRAM OP enabled
I (662) phy_init: phy_version 680,a6008b2,Jun 4 2024,16:41:10
W (672) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration
W (702) phy_init: saving new calibration data because of checksum failure, mode(2)
I (722) wifi:mode : sta (68:b6:b3:4d:91:08)
I (722) wifi:enable tsf
I (722) example_connect: Please input ssid password:
I (752) example_connect: Connecting to myssid...
W (752) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
I (762) example_connect: Waiting for IP(s)
I (3592) wifi:new:<2,1>, old:<1,0>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
I (3592) wifi:state: init -> auth (0xb0)
I (3592) wifi:state: auth -> assoc (0x0)
I (3602) wifi:state: assoc -> run (0x10)
I (3622) wifi:connected with myssid, aid = 3, channel 2, 40U, bssid = 22:d8:d0:45:23:7a
I (3622) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
I (3622) wifi:pm start, type: 1
I (3632) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3632) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (3722) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (4722) esp_netif_handlers: example_netif_sta ip: 192.168.3.26, mask: 255.255.255.0, gw: 192.168.3.1
I (4722) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.3.26
I (4732) example_common: Connected to example_netif_sta
I (4732) example_common: - IPv4 address: 192.168.3.26,
I (4742) wifi:Set ps type: 0, coexist: 0
I (4742) ota_example: Starting OTA example task
I (4742) ota_example: Bind interface name is st1
I (4752) main_task: Returned from app_main()
I (4762) ota_example: Attempting to download update from https://192.168.3.9:8000/partitions_ota.bin
I (4782) wifi:<ba-add>idx:0 (ifx:0, 22:d8:d0:45:23:7a), tid:0, ssn:1, winSize:64
I (4812) esp-x509-crt-bundle: Certificate validated
I (5142) esp_https_ota: Starting OTA...
I (5142) esp_https_ota: Writing to <ota_1> partition at offset 0x1d0000
I (29702) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
I (29722) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800)
I (29732) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680)
I (29732) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
I (29822) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444)
I (29832) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28)
I (29832) esp_image: Verifying image signature...
I (29842) secure_boot_v2: Take trusted digest key(s) from running app
I (29852) secure_boot_v2: #0 app key digest == #0 trusted key digest
I (29852) secure_boot_v2: Verifying with RSA-PSS...
I (29912) secure_boot_v2_rsa: Signature verified successfully!
I (29912) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
I (29932) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800)
I (29942) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680)
I (29942) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
I (30032) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444)
I (30042) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28)
I (30042) esp_image: Verifying image signature...
I (30042) secure_boot_v2: Take trusted digest key(s) from running app
I (30062) secure_boot_v2: #0 app key digest == #0 trusted key digest
I (30062) secure_boot_v2: Verifying with RSA-PSS...
I (30122) secure_boot_v2_rsa: Signature verified successfully!
I (30292) ota_example: OTA Succeed, Rebooting...
I (30292) wifi:state: run -> init (0x0)
I (30292) wifi:pm stop, total sleep time: 737814 us / 26659208 us
I (30292) wifi:<ba-del>idx:0, tid:0
I (30302) wifi:new:<2,0>, old:<2,1>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
I (30352) wifi:flush txq
I (30352) wifi:stop sw txq
I (30352) wifi:lmac stop hw txq
I (30352) wifi:Deinit lldesc rx mblock:10
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40376c31
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2820,len:0x15a0
load:0x403c8700,len:0x4
load:0x403c8704,len:0xd20
load:0x403cb700,len:0x2f3c
entry 0x403c8928
I (31) boot: ESP-IDF 95a1e4cd 2nd stage bootloader
I (31) boot: compile time Oct 28 2024 15:26:41
I (31) boot: Multicore bootloader
I (32) boot: chip revision: v0.1
I (34) boot: efuse block revision: v1.2
I (38) boot.esp32s3: Boot SPI Speed : 80MHz
I (42) boot.esp32s3: SPI Mode : DIO
I (46) boot.esp32s3: SPI Flash Size : 4MB
I (49) boot: Enabling RNG early entropy source...
I (54) boot: Partition Table:
I (56) boot: ## Label Usage Type ST Offset Length
I (63) boot: 0 nvs WiFi data 01 02 0000d000 00006000
I (69) boot: 1 nvs_key NVS keys 01 04 00013000 00001000
I (76) boot: 2 storage Unknown data 01 06 00014000 00001000
I (82) boot: 3 otadata OTA data 01 00 00015000 00002000
I (89) boot: 4 phy_init RF data 01 01 00017000 00001000
I (95) boot: 5 emul_efuse efuse 01 05 00018000 00002000
I (102) boot: 6 ota_0 OTA app 00 10 00020000 001b0000
I (108) boot: 7 ota_1 OTA app 00 11 001d0000 001b0000
I (115) boot: End of partition table
I (118) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
I (152) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800) load
I (156) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680) load
I (163) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
I (267) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444) load
I (279) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28) load
I (288) boot: Loaded app from partition at offset 0x1d0000
I (288) boot: Disabling RNG early entropy source...
I (298) cpu_start: Multicore app
I (308) cpu_start: Pro cpu start user code
I (308) cpu_start: cpu freq: 160000000 Hz
I (308) app_init: Application information:
I (308) app_init: Project name: partitions_ota
I (312) app_init: App version: 95a1e4cd
I (316) app_init: Compile time: Oct 28 2024 15:26:38
I (321) app_init: ELF file SHA256: 0810d7fd3...
I (326) app_init: ESP-IDF: 95a1e4cd
I (330) efuse_init: Min chip rev: v0.0
I (334) efuse_init: Max chip rev: v0.99
I (338) efuse_init: Chip rev: v0.1
I (341) heap_init: Initializing. RAM available for dynamic allocation:
I (348) heap_init: At 3FCA14A0 len 00048270 (288 KiB): RAM
I (353) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (358) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (363) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
I (370) spi_flash: detected chip: generic
I (372) spi_flash: flash io: dio
W (375) spi_flash: Detected size(8192k) larger than the size in the binary image header(4096k). Using the size in the binary image header.
I (389) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (394) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (401) main_task: Started on CPU0
I (421) main_task: Calling app_main()
I (421) ota_example: OTA example app_main start
I (431) example_connect: Start example_connect.
I (431) pp: pp rom version: e7ae62f
I (431) net80211: net80211 rom version: e7ae62f
I (441) wifi:wifi driver task: 3fcab48c, prio:23, stack:6656, core=0
I (441) wifi:wifi firmware version: 2d9c351b0
I (441) wifi:wifi certification version: v7.0
I (451) wifi:config NVS flash: enabled
I (451) wifi:config nano formatting: disabled
I (451) wifi:Init data frame dynamic rx buffer num: 32
I (461) wifi:Init static rx mgmt buffer num: 5
I (461) wifi:Init management short buffer num: 32
I (471) wifi:Init dynamic tx buffer num: 32
I (471) wifi:Init static tx FG buffer num: 2
I (471) wifi:Init static rx buffer size: 1600
I (481) wifi:Init static rx buffer num: 10
I (481) wifi:Init dynamic rx buffer num: 32
I (491) wifi_init: rx ba win: 6
I (491) wifi_init: accept mbox: 6
I (491) wifi_init: tcpip mbox: 32
I (501) wifi_init: udp mbox: 6
I (501) wifi_init: tcp mbox: 6
I (501) wifi_init: tcp tx win: 5760
I (501) wifi_init: tcp rx win: 5760
I (511) wifi_init: tcp mss: 1440
I (511) wifi_init: WiFi IRAM OP enabled
I (511) wifi_init: WiFi RX IRAM OP enabled
I (521) phy_init: phy_version 680,a6008b2,Jun 4 2024,16:41:10
I (561) wifi:mode : sta (68:b6:b3:4d:91:08)
I (561) wifi:enable tsf
I (561) example_connect: Please input ssid password:
I (611) example_connect: Connecting to myssid...
W (611) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
I (611) example_connect: Waiting for IP(s)
I (3441) wifi:new:<2,1>, old:<1,0>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
I (3441) wifi:state: init -> auth (0xb0)
I (3451) wifi:state: auth -> assoc (0x0)
I (3451) wifi:state: assoc -> run (0x10)
I (3471) wifi:connected with myssid, aid = 3, channel 2, 40U, bssid = 22:d8:d0:45:23:7a
I (3471) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
I (3471) wifi:pm start, type: 1
I (3491) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3491) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (3571) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (4591) esp_netif_handlers: example_netif_sta ip: 192.168.3.26, mask: 255.255.255.0, gw: 192.168.3.1
I (4591) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.3.26
I (4601) example_common: Connected to example_netif_sta
I (4601) example_common: - IPv4 address: 192.168.3.26,
I (4611) wifi:Set ps type: 0, coexist: 0
I (4611) ota_example: Starting OTA example task
I (4611) ota_example: Bind interface name is st1
I (4621) main_task: Returned from app_main()
I (4671) ota_example: Attempting to download update from https://192.168.3.9:8000/bootloader/bootloader.bin
I (4671) ota_example: Use <PrimaryBTLDR> partition (0x00000000)
I (4701) wifi:<ba-add>idx:0 (ifx:0, 22:d8:d0:45:23:7a), tid:0, ssn:1, winSize:64
I (4731) esp-x509-crt-bundle: Certificate validated
I (5061) esp_https_ota: Starting OTA...
I (5061) esp_https_ota: Writing to <ota_0> partition at offset 0x20000
I (5061) esp_ota_ops: Staging partition - <ota_0>. Final partition - <PrimaryBTLDR>.
I (5071) esp_image: Bootloader offsets for PRIMARY: 0x0, Secondary: 0x20000
I (6121) esp_image: segment 0: paddr=00020020 vaddr=3fce2820 size=015a0h ( 5536)
I (6121) esp_image: segment 1: paddr=000215c8 vaddr=403c8700 size=00004h ( 4)
I (6131) esp_image: segment 2: paddr=000215d4 vaddr=403c8704 size=00d20h ( 3360)
I (6131) esp_image: segment 3: paddr=000222fc vaddr=403cb700 size=02f3ch ( 12092)
I (6151) esp_image: Bootloader offsets for PRIMARY: 0x0, Secondary: 0x0
W (6151) ota_example: Ensure stable power supply! Loss of power at this stage leads to a chip bricking
I (6151) ota_example: Copy from <ota_0> staging partition to <PrimaryBTLDR>...
I (7801) ota_example: OTA Succeed, Rebooting...
I (7801) wifi:state: run -> init (0x0)
I (7801) wifi:pm stop, total sleep time: 742270 us / 4318054 us
I (7801) wifi:<ba-del>idx:0, tid:0
I (7821) wifi:new:<2,0>, old:<2,1>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
I (7831) wifi:flush txq
I (7831) wifi:stop sw txq
I (7831) wifi:lmac stop hw txq
I (7831) wifi:Deinit lldesc rx mblock:10
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40376c31
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2820,len:0x15a0
load:0x403c8700,len:0x4
load:0x403c8704,len:0xd20
load:0x403cb700,len:0x2f3c
entry 0x403c8928
I (31) boot: ESP-IDF 95a1e4cd 2nd stage bootloader
I (31) boot: compile time Oct 28 2024 15:26:41
I (31) boot: Multicore bootloader
I (32) boot: chip revision: v0.1
I (34) boot: efuse block revision: v1.2
I (38) boot.esp32s3: Boot SPI Speed : 80MHz
I (42) boot.esp32s3: SPI Mode : DIO
I (46) boot.esp32s3: SPI Flash Size : 4MB
I (49) boot: Enabling RNG early entropy source...
I (54) boot: Partition Table:
I (56) boot: ## Label Usage Type ST Offset Length
I (63) boot: 0 nvs WiFi data 01 02 0000d000 00006000
I (69) boot: 1 nvs_key NVS keys 01 04 00013000 00001000
I (76) boot: 2 storage Unknown data 01 06 00014000 00001000
I (82) boot: 3 otadata OTA data 01 00 00015000 00002000
I (89) boot: 4 phy_init RF data 01 01 00017000 00001000
I (95) boot: 5 emul_efuse efuse 01 05 00018000 00002000
I (102) boot: 6 ota_0 OTA app 00 10 00020000 001b0000
I (108) boot: 7 ota_1 OTA app 00 11 001d0000 001b0000
I (115) boot: End of partition table
I (118) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
I (152) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800) load
I (156) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680) load
I (163) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
I (267) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444) load
I (279) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28) load
I (288) boot: Loaded app from partition at offset 0x1d0000
I (288) boot: Disabling RNG early entropy source...
I (298) cpu_start: Multicore app
I (308) cpu_start: Pro cpu start user code
I (308) cpu_start: cpu freq: 160000000 Hz
I (308) app_init: Application information:
I (308) app_init: Project name: partitions_ota
I (312) app_init: App version: 95a1e4cd
I (316) app_init: Compile time: Oct 28 2024 15:26:38
I (321) app_init: ELF file SHA256: 0810d7fd3...
I (326) app_init: ESP-IDF: 95a1e4cd
I (330) efuse_init: Min chip rev: v0.0
I (334) efuse_init: Max chip rev: v0.99
I (338) efuse_init: Chip rev: v0.1
I (341) heap_init: Initializing. RAM available for dynamic allocation:
I (348) heap_init: At 3FCA14A0 len 00048270 (288 KiB): RAM
I (353) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (358) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (363) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
I (370) spi_flash: detected chip: generic
I (372) spi_flash: flash io: dio
W (375) spi_flash: Detected size(8192k) larger than the size in the binary image header(4096k). Using the size in the binary image header.
I (389) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (394) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (401) main_task: Started on CPU0
I (421) main_task: Calling app_main()
I (421) ota_example: OTA example app_main start
I (431) example_connect: Start example_connect.
I (431) pp: pp rom version: e7ae62f
I (431) net80211: net80211 rom version: e7ae62f
I (441) wifi:wifi driver task: 3fcab48c, prio:23, stack:6656, core=0
I (441) wifi:wifi firmware version: 2d9c351b0
I (441) wifi:wifi certification version: v7.0
I (451) wifi:config NVS flash: enabled
I (451) wifi:config nano formatting: disabled
I (451) wifi:Init data frame dynamic rx buffer num: 32
I (461) wifi:Init static rx mgmt buffer num: 5
I (461) wifi:Init management short buffer num: 32
I (471) wifi:Init dynamic tx buffer num: 32
I (471) wifi:Init static tx FG buffer num: 2
I (471) wifi:Init static rx buffer size: 1600
I (481) wifi:Init static rx buffer num: 10
I (481) wifi:Init dynamic rx buffer num: 32
I (491) wifi_init: rx ba win: 6
I (491) wifi_init: accept mbox: 6
I (491) wifi_init: tcpip mbox: 32
I (501) wifi_init: udp mbox: 6
I (501) wifi_init: tcp mbox: 6
I (501) wifi_init: tcp tx win: 5760
I (501) wifi_init: tcp rx win: 5760
I (511) wifi_init: tcp mss: 1440
I (511) wifi_init: WiFi IRAM OP enabled
I (511) wifi_init: WiFi RX IRAM OP enabled
I (521) phy_init: phy_version 680,a6008b2,Jun 4 2024,16:41:10
I (561) wifi:mode : sta (68:b6:b3:4d:91:08)
I (561) wifi:enable tsf
I (561) example_connect: Please input ssid password:
I (601) example_connect: Connecting to myssid...
W (601) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
I (601) example_connect: Waiting for IP(s)
I (3431) wifi:new:<2,1>, old:<1,0>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
I (3431) wifi:state: init -> auth (0xb0)
I (3431) wifi:state: auth -> assoc (0x0)
I (3441) wifi:state: assoc -> run (0x10)
I (3461) wifi:connected with myssid, aid = 1, channel 2, 40U, bssid = 22:d8:d0:45:23:7a
I (3461) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
I (3461) wifi:pm start, type: 1
I (3471) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3471) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (3511) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (4571) esp_netif_handlers: example_netif_sta ip: 192.168.3.26, mask: 255.255.255.0, gw: 192.168.3.1
I (4571) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.3.26
I (4581) example_common: Connected to example_netif_sta
I (4581) example_common: - IPv4 address: 192.168.3.26,
I (4591) wifi:Set ps type: 0, coexist: 0
I (4591) ota_example: Starting OTA example task
I (4591) ota_example: Bind interface name is st1
I (4601) main_task: Returned from app_main()
I (4621) ota_example: Attempting to download update from https://192.168.3.9:8000/partition_table/partition-table.bin
I (4631) ota_example: Use <PrimaryPrtTable> partition (0x0000c000)
I (4651) wifi:<ba-add>idx:0 (ifx:0, 22:d8:d0:45:23:7a), tid:0, ssn:1, winSize:64
I (4681) esp-x509-crt-bundle: Certificate validated
I (5021) esp_https_ota: Starting OTA...
I (5021) esp_https_ota: Writing to <ota_0> partition at offset 0x20000
I (5021) esp_ota_ops: Staging partition - <ota_0>. Final partition - <PrimaryPrtTable>.
W (5181) ota_example: Ensure stable power supply! Loss of power at this stage leads to a chip bricking.
I (5181) ota_example: Copy from <ota_0> staging partition to <PrimaryPrtTable>...
I (5261) ota_example: OTA Succeed, Rebooting...
I (5261) wifi:state: run -> init (0x0)
I (5261) wifi:pm stop, total sleep time: 715566 us / 1792923 us
I (5261) wifi:<ba-del>idx:0, tid:0
I (5281) wifi:new:<2,0>, old:<2,1>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
I (5291) wifi:flush txq
I (5291) wifi:stop sw txq
I (5291) wifi:lmac stop hw txq
I (5291) wifi:Deinit lldesc rx mblock:10
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40376c31
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2820,len:0x15a0
load:0x403c8700,len:0x4
load:0x403c8704,len:0xd20
load:0x403cb700,len:0x2f3c
entry 0x403c8928
I (31) boot: ESP-IDF 95a1e4cd 2nd stage bootloader
I (31) boot: compile time Oct 28 2024 15:26:41
I (31) boot: Multicore bootloader
I (32) boot: chip revision: v0.1
I (34) boot: efuse block revision: v1.2
I (38) boot.esp32s3: Boot SPI Speed : 80MHz
I (42) boot.esp32s3: SPI Mode : DIO
I (46) boot.esp32s3: SPI Flash Size : 4MB
I (49) boot: Enabling RNG early entropy source...
I (54) boot: Partition Table:
I (56) boot: ## Label Usage Type ST Offset Length
I (63) boot: 0 nvs WiFi data 01 02 0000d000 00006000
I (69) boot: 1 nvs_key NVS keys 01 04 00013000 00001000
I (76) boot: 2 storage Unknown data 01 06 00014000 00001000
I (82) boot: 3 otadata OTA data 01 00 00015000 00002000
I (89) boot: 4 phy_init RF data 01 01 00017000 00001000
I (95) boot: 5 emul_efuse efuse 01 05 00018000 00002000
I (102) boot: 6 ota_0 OTA app 00 10 00020000 001b0000
I (108) boot: 7 ota_1 OTA app 00 11 001d0000 001b0000
I (115) boot: End of partition table
I (118) esp_image: segment 0: paddr=001d0020 vaddr=3c090020 size=24288h (148104) map
I (152) esp_image: segment 1: paddr=001f42b0 vaddr=3fc98900 size=04970h ( 18800) load
I (156) esp_image: segment 2: paddr=001f8c28 vaddr=40374000 size=073f0h ( 29680) load
I (163) esp_image: segment 3: paddr=00200020 vaddr=42000020 size=8fc00h (588800) map
I (267) esp_image: segment 4: paddr=0028fc28 vaddr=4037b3f0 size=0d4ach ( 54444) load
I (279) esp_image: segment 5: paddr=0029d0dc vaddr=600fe100 size=0001ch ( 28) load
I (288) boot: Loaded app from partition at offset 0x1d0000
I (288) boot: Disabling RNG early entropy source...
I (298) cpu_start: Multicore app
I (308) cpu_start: Pro cpu start user code
I (308) cpu_start: cpu freq: 160000000 Hz
I (308) app_init: Application information:
I (308) app_init: Project name: partitions_ota
I (312) app_init: App version: 95a1e4cd
I (316) app_init: Compile time: Oct 28 2024 15:26:38
I (321) app_init: ELF file SHA256: 0810d7fd3...
I (326) app_init: ESP-IDF: 95a1e4cd
I (330) efuse_init: Min chip rev: v0.0
I (334) efuse_init: Max chip rev: v0.99
I (338) efuse_init: Chip rev: v0.1
I (341) heap_init: Initializing. RAM available for dynamic allocation:
I (348) heap_init: At 3FCA14A0 len 00048270 (288 KiB): RAM
I (353) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (358) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (363) heap_init: At 600FE11C len 00001ECC (7 KiB): RTCRAM
I (370) spi_flash: detected chip: generic
I (372) spi_flash: flash io: dio
W (375) spi_flash: Detected size(8192k) larger than the size in the binary image header(4096k). Using the size in the binary image header.
I (389) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (394) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (401) main_task: Started on CPU0
I (421) main_task: Calling app_main()
I (421) ota_example: OTA example app_main start
I (431) example_connect: Start example_connect.
I (431) pp: pp rom version: e7ae62f
I (431) net80211: net80211 rom version: e7ae62f
I (441) wifi:wifi driver task: 3fcab48c, prio:23, stack:6656, core=0
I (441) wifi:wifi firmware version: 2d9c351b0
I (441) wifi:wifi certification version: v7.0
I (451) wifi:config NVS flash: enabled
I (451) wifi:config nano formatting: disabled
I (451) wifi:Init data frame dynamic rx buffer num: 32
I (461) wifi:Init static rx mgmt buffer num: 5
I (461) wifi:Init management short buffer num: 32
I (471) wifi:Init dynamic tx buffer num: 32
I (471) wifi:Init static tx FG buffer num: 2
I (471) wifi:Init static rx buffer size: 1600
I (481) wifi:Init static rx buffer num: 10
I (481) wifi:Init dynamic rx buffer num: 32
I (491) wifi_init: rx ba win: 6
I (491) wifi_init: accept mbox: 6
I (491) wifi_init: tcpip mbox: 32
I (501) wifi_init: udp mbox: 6
I (501) wifi_init: tcp mbox: 6
I (501) wifi_init: tcp tx win: 5760
I (501) wifi_init: tcp rx win: 5760
I (511) wifi_init: tcp mss: 1440
I (511) wifi_init: WiFi IRAM OP enabled
I (511) wifi_init: WiFi RX IRAM OP enabled
I (521) phy_init: phy_version 680,a6008b2,Jun 4 2024,16:41:10
I (561) wifi:mode : sta (68:b6:b3:4d:91:08)
I (561) wifi:enable tsf
I (561) example_connect: Please input ssid password:
I (591) example_connect: Connecting to myssid...
W (591) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
I (591) example_connect: Waiting for IP(s)
I (3421) wifi:new:<2,1>, old:<1,0>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
I (3421) wifi:state: init -> auth (0xb0)
I (3431) wifi:state: auth -> assoc (0x0)
I (3431) wifi:state: assoc -> run (0x10)
I (3451) wifi:connected with myssid, aid = 1, channel 2, 40U, bssid = 22:d8:d0:45:23:7a
I (3451) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
I (3451) wifi:pm start, type: 1
I (3461) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3461) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (3541) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (4551) esp_netif_handlers: example_netif_sta ip: 192.168.3.26, mask: 255.255.255.0, gw: 192.168.3.1
I (4551) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.3.26
I (4561) example_common: Connected to example_netif_sta
I (4561) example_common: - IPv4 address: 192.168.3.26,
I (4571) wifi:Set ps type: 0, coexist: 0
I (4571) ota_example: Starting OTA example task
I (4571) ota_example: Bind interface name is st1
I (4581) main_task: Returned from app_main()
I (4601) ota_example: Attempting to download update from https://192.168.3.9:8000/storage.bin
I (4621) wifi:<ba-add>idx:0 (ifx:0, 22:d8:d0:45:23:7a), tid:0, ssn:1, winSize:64
I (4641) esp-x509-crt-bundle: Certificate validated
I (4981) esp_https_ota: Starting OTA...
I (4981) esp_https_ota: Writing to <ota_0> partition at offset 0x20000
I (4981) esp_ota_ops: Staging partition - <ota_0>. Final partition - <storage>.
I (5161) esp_ota_ops: Copy from <ota_0> staging partition to <storage>...
I (5351) ota_example: 7296406769363431
I (5351) ota_example: OTA Succeed, Rebooting...
I (5361) wifi:state: run -> init (0x0)
I (5361) wifi:pm stop, total sleep time: 772888 us / 1893437 us
I (5371) wifi:<ba-del>idx:0, tid:0
I (5371) wifi:new:<2,0>, old:<2,1>, ap:<255,255>, sta:<2,1>, prof:1, snd_ch_cfg:0x0
```

View File

@@ -0,0 +1,64 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import logging
import os
import pytest
from _pytest.fixtures import FixtureRequest
from _pytest.monkeypatch import MonkeyPatch
from pytest_embedded_idf.app import FlashFile
from pytest_embedded_idf.serial import IdfSerial
# This is a custom IdfSerial class to support custom functionality
# which is required only for this test
class EfuseFlashEncSerial(IdfSerial):
@IdfSerial.use_esptool()
def write_flash_no_enc(self) -> None:
self.app.flash_settings['encrypt'] = False
flash_files = []
for file in self.app.flash_files:
# Set encrypted flag to false for each file.
flash_files.append(file._replace(encrypted=False))
# Replace the original tuple with modified tuple with all the files marked as unencrypted.
self.app.flash_files = tuple(flash_files)
# Now flash the files
self.flash()
def bootloader_flash(self) -> None:
"""
Flash bootloader.
:return: None
"""
logging.info('Flashing bootloader')
bootloader_path = os.path.join(self.app.binary_path, 'bootloader', 'bootloader.bin')
offs = int(self.app.sdkconfig.get('BOOTLOADER_OFFSET_IN_FLASH', 0))
logging.info('bootloader offset is {0}'.format(hex(offs)))
prev_flash_files = self.app.flash_files
flash_files = []
flash_files.append(
FlashFile(
offs,
bootloader_path,
False,
)
)
self.app.flash_files = flash_files
self.app.flash_settings['encrypt'] = False
self.flash()
# Restore self.app.flash files to original value
self.app.flash_files = prev_flash_files
@pytest.fixture(scope='module')
def monkeypatch_module(request: FixtureRequest) -> MonkeyPatch:
mp = MonkeyPatch()
request.addfinalizer(mp.undo)
return mp
@pytest.fixture(scope='module', autouse=True)
def replace_dut_class(monkeypatch_module: MonkeyPatch) -> None:
monkeypatch_module.setattr('pytest_embedded_idf.IdfSerial', EfuseFlashEncSerial)

View File

@@ -0,0 +1,5 @@
# Embed the server root certificate into the final binary
idf_build_get_property(project_dir PROJECT_DIR)
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem)

View File

@@ -0,0 +1,54 @@
menu "Example Configuration"
config EXAMPLE_FIRMWARE_UPGRADE_URL
string "firmware upgrade url endpoint"
default "https://192.168.0.3:8070/partitions_ota.bin"
help
URL of server which hosts the firmware
image.
config EXAMPLE_USE_CERT_BUNDLE
bool "Enable certificate bundle"
default y
depends on MBEDTLS_CERTIFICATE_BUNDLE
help
Enable trusted root certificate bundle. This approach allows to have
OTA updates functional with any public server without requirement
to explicitly add its server certificate.
config EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN
bool
default y if EXAMPLE_FIRMWARE_UPGRADE_URL = "FROM_STDIN"
config EXAMPLE_SKIP_COMMON_NAME_CHECK
bool "Skip server certificate CN fieldcheck"
default n
help
This allows you to skip the validation of OTA server certificate CN field.
config EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
bool "Support firmware upgrade bind specified interface"
default n
help
This allows you to bind specified interface in OTA example.
choice EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_TYPE
prompt "Choose OTA data bind interface"
default EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_STA
depends on EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
help
Select which interface type of OTA data go through.
config EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_STA
bool "Bind wifi station interface"
depends on EXAMPLE_CONNECT_WIFI
help
Select wifi station interface to pass the OTA data.
config EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_ETH
bool "Bind ethernet interface"
depends on EXAMPLE_CONNECT_ETHERNET
help
Select ethernet interface to pass the OTA data.
endchoice
endmenu

View File

@@ -0,0 +1,268 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* OTA partitions example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "protocol_examples_common.h"
#include "string.h"
#ifdef CONFIG_EXAMPLE_USE_CERT_BUNDLE
#include "esp_crt_bundle.h"
#endif
#include "esp_flash.h"
#include "esp_flash_partitions.h"
#include "esp_partition.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include <sys/socket.h>
#if CONFIG_EXAMPLE_CONNECT_WIFI
#include "esp_wifi.h"
#endif
#include "partition_utils.h"
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
/* The interface name value can refer to if_desc in esp_netif_defaults.h */
#if CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_ETH
static const char *bind_interface_name = EXAMPLE_NETIF_DESC_ETH;
#elif CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_STA
static const char *bind_interface_name = EXAMPLE_NETIF_DESC_STA;
#endif
#endif
static const char *TAG = "ota_example";
extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
#define OTA_URL_SIZE 256
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
switch (evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
break;
case HTTP_EVENT_REDIRECT:
ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
break;
}
return ESP_OK;
}
static esp_err_t register_partition(size_t offset, size_t size, const char *label, esp_partition_type_t type, esp_partition_subtype_t subtype, const esp_partition_t **p_partition)
{
// If the partition table contains this partition, then use it, otherwise register it.
*p_partition = esp_partition_find_first(type, subtype, NULL);
if ((*p_partition) == NULL) {
esp_err_t error = esp_partition_register_external(NULL, offset, size, label, type, subtype, p_partition);
if (error != ESP_OK) {
ESP_LOGE(TAG, "Failed to register %s partition (err=0x%x)", "PrimaryBTLDR", error);
return error;
}
}
ESP_LOGI(TAG, "Use <%s> partition (0x%08" PRIx32 ")", (*p_partition)->label, (*p_partition)->address);
return ESP_OK;
}
static esp_err_t ota_update_partitions(esp_https_ota_config_t *ota_config)
{
esp_err_t ret = ESP_ERR_NOT_SUPPORTED;
if (strstr(ota_config->http_config->url, "partitions_ota.bin") != NULL) {
ret = esp_https_ota(ota_config);
} else if (strstr(ota_config->http_config->url, "bootloader.bin") != NULL) {
const esp_partition_t *primary_bootloader;
ESP_ERROR_CHECK(register_partition(ESP_PRIMARY_BOOTLOADER_OFFSET, ESP_BOOTLOADER_SIZE, "PrimaryBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_PRIMARY, &primary_bootloader));
const esp_partition_t *ota_partition = esp_ota_get_next_update_partition(NULL); // free app ota partition will be used for downloading a new image
#if CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
// Check if the passive OTA app partition is not needed for rollback before using it for other partitions.
// The same can be done for partition table and storage updates.
esp_ota_img_states_t ota_state;
ESP_ERROR_CHECK(esp_ota_get_state_partition(ota_partition, &ota_state));
if (ota_state == ESP_OTA_IMG_VALID) {
ESP_LOGW(TAG, "Passive OTA app partition <%s> contains a valid app image eligible for rollback.", ota_partition->label);
uint32_t ota_bootloader_offset;
ESP_ERROR_CHECK(partition_utils_find_unallocated(NULL, ESP_BOOTLOADER_SIZE, ESP_PARTITION_TABLE_OFFSET + ESP_PARTITION_TABLE_SIZE, &ota_bootloader_offset, NULL));
ESP_ERROR_CHECK(register_partition(ota_bootloader_offset, ESP_BOOTLOADER_SIZE, "OtaBTLDR", ESP_PARTITION_TYPE_BOOTLOADER, ESP_PARTITION_SUBTYPE_BOOTLOADER_OTA, &ota_partition));
ESP_LOGW(TAG, "To avoid overwriting the passive app partition, using the unallocated space on the flash to create a temporary OTA bootloader partition <%s>", ota_partition->label);
}
#endif
ota_config->partition.staging = ota_partition;
ota_config->partition.final = primary_bootloader;
ret = esp_https_ota(ota_config);
if (ret == ESP_OK) {
ESP_LOGW(TAG, "Ensure stable power supply! Loss of power at this stage leads to a chip bricking");
ESP_LOGI(TAG, "Copy from <%s> staging partition to <%s>...", ota_partition->label, primary_bootloader->label);
ret = esp_partition_copy(primary_bootloader, 0, ota_partition, 0, primary_bootloader->size);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to copy partition to Primary bootloader (err=0x%x). Bootloader likely corrupted. Device will not be able to boot again!", ret);
}
// If the primary_bootloader already exists in the partition table on flash, it will not be deregistered, and the function will return an error.
esp_partition_deregister_external(primary_bootloader);
}
} else if (strstr(ota_config->http_config->url, "partition-table.bin") != NULL) {
const esp_partition_t *primary_partition_table;
ESP_ERROR_CHECK(register_partition(ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE, "PrimaryPrtTable", ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &primary_partition_table));
const esp_partition_t *free_app_ota_partition = esp_ota_get_next_update_partition(NULL); // free app ota partition will be used for downloading a new image
ota_config->partition.staging = free_app_ota_partition;
ota_config->partition.final = primary_partition_table;
ota_config->partition.finalize_with_copy = false; // After the download is complete, do not copy the received image to the final partition automatically (it is false by default)
ret = esp_https_ota(ota_config);
if (ret == ESP_OK) {
ESP_LOGW(TAG, "Ensure stable power supply! Loss of power at this stage leads to a chip bricking.");
ESP_LOGI(TAG, "Copy from <%s> staging partition to <%s>...", free_app_ota_partition->label, primary_partition_table->label);
ret = esp_partition_copy(primary_partition_table, 0, free_app_ota_partition, 0, primary_partition_table->size);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to copy partition to Primary partition table (err=0x%x). Partition table likely corrupted. Device will not be able to boot again!", ret);
}
// If the primary_partition_table already exists in the partition table on flash, it will not be deregistered, and the function will return an error.
esp_partition_deregister_external(primary_partition_table);
}
} else if (strstr(ota_config->http_config->url, "storage.bin") != NULL) {
ota_config->partition.staging = NULL; // free app ota partition will be selected and used for downloading a new image
ota_config->partition.final = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
assert(ota_config->partition.final != NULL);
ota_config->partition.finalize_with_copy = true; // After the download is complete, copy the received image to the final partition automatically
ret = esp_https_ota(ota_config);
char text[16];
ESP_ERROR_CHECK(esp_partition_read(ota_config->partition.final, 0, text, sizeof(text)));
ESP_LOG_BUFFER_CHAR(TAG, text, sizeof(text));
assert(memcmp("7296406769363431", text, sizeof(text)) == 0);
} else {
ESP_LOGE(TAG, "Unable to load this file (%s). The final partition is unknown.", ota_config->http_config->url);
}
return ret;
}
void ota_example_task(void *pvParameter)
{
ESP_LOGI(TAG, "Starting OTA example task");
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
esp_netif_t *netif = get_example_netif_from_desc(bind_interface_name);
if (netif == NULL) {
ESP_LOGE(TAG, "Can't find netif from interface description");
abort();
}
struct ifreq ifr;
esp_netif_get_netif_impl_name(netif, ifr.ifr_name);
ESP_LOGI(TAG, "Bind interface name is %s", ifr.ifr_name);
#endif
esp_http_client_config_t config = {
.url = CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL,
#ifdef CONFIG_EXAMPLE_USE_CERT_BUNDLE
.crt_bundle_attach = esp_crt_bundle_attach,
#else
.cert_pem = (char *)server_cert_pem_start,
#endif /* CONFIG_EXAMPLE_USE_CERT_BUNDLE */
.event_handler = _http_event_handler,
.keep_alive_enable = true,
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
.if_name = &ifr,
#endif
};
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN
char url_buf[OTA_URL_SIZE];
if (strcmp(config.url, "FROM_STDIN") == 0) {
example_configure_stdin_stdout();
fgets(url_buf, OTA_URL_SIZE, stdin);
int len = strlen(url_buf);
url_buf[len - 1] = '\0';
config.url = url_buf;
} else {
ESP_LOGE(TAG, "Configuration mismatch: wrong firmware upgrade image url");
abort();
}
#endif
#ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK
config.skip_cert_common_name_check = true;
#endif
esp_https_ota_config_t ota_config = {
.http_config = &config,
};
ESP_LOGI(TAG, "Attempting to download update from %s", config.url);
esp_err_t ret = ota_update_partitions(&ota_config);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "OTA Succeed, Rebooting...");
esp_restart();
} else {
ESP_LOGE(TAG, "Firmware upgrade failed");
}
while (1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
ESP_LOGI(TAG, "OTA example app_main start");
// Initialize NVS.
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// 1.OTA app partition table has a smaller NVS partition size than the non-OTA
// partition table. This size mismatch may cause NVS initialization to fail.
// 2.NVS partition contains data in new format and cannot be recognized by this version of code.
// If this happens, we erase NVS partition and initialize NVS again.
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
#if CONFIG_EXAMPLE_CONNECT_WIFI
/* Ensure to disable any WiFi power save mode, this allows best throughput
* and hence timings for overall OTA operation.
*/
esp_wifi_set_ps(WIFI_PS_NONE);
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
xTaskCreate(&ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);
}

View File

@@ -0,0 +1,3 @@
dependencies:
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common

View File

@@ -0,0 +1,118 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <sys/param.h>
#include "esp_flash_partitions.h"
#include "esp_flash_internal.h"
#include "esp_image_format.h"
#include "esp_flash.h"
#include "esp_partition.h"
#include "esp_log.h"
// Returns the number of partitions belonging to the specified flash chip
static unsigned int count_partitions(esp_flash_t *flash_chip)
{
unsigned int partition_count = 0;
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
assert(it != NULL);
for (; it != NULL; it = esp_partition_next(it)) {
if (esp_partition_get(it)->flash_chip == flash_chip) {
partition_count++;
}
}
esp_partition_iterator_release(it);
return partition_count;
}
// Compare function for qsort to sort partitions by address
static int compare_partitions(const void *a, const void *b) {
const esp_partition_t *part_a = *(const esp_partition_t **)a;
const esp_partition_t *part_b = *(const esp_partition_t **)b;
return ((int32_t)part_a->address - (int32_t)part_b->address);
}
static const esp_partition_t **get_sorted_partition_array(esp_flash_t *flash_chip, unsigned int *out_partition_count)
{
// Number of partitions on the flash chip
unsigned int partition_count = count_partitions(flash_chip);
assert(partition_count != 0);
*out_partition_count = partition_count;
// Allocate an array for copying partitions
const esp_partition_t **part_array = (const esp_partition_t **) calloc(partition_count, sizeof(esp_partition_t *));
assert(part_array != NULL);
// Copy partitions to the array
unsigned i = 0;
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
assert(it != NULL);
for (; it != NULL; it = esp_partition_next(it)) {
const esp_partition_t *p = esp_partition_get(it);
if (p->flash_chip == flash_chip) {
part_array[i++] = p;
}
}
esp_partition_iterator_release(it);
assert(i == partition_count);
// Sort partitions by address using qsort
qsort(part_array, partition_count, sizeof(esp_partition_t *), compare_partitions);
return part_array;
}
esp_err_t partition_utils_find_unallocated(esp_flash_t *flash_chip, size_t required_size, uint32_t start_offset, uint32_t *found_offset, size_t *found_size)
{
if (flash_chip == NULL) {
flash_chip = esp_flash_default_chip;
}
if (required_size == 0 || found_offset == NULL) {
return ESP_ERR_INVALID_ARG;
}
// Get a sorted partition array for the given flash chip
unsigned int partition_count;
const esp_partition_t **sorted_partitions = get_sorted_partition_array(flash_chip, &partition_count);
if (sorted_partitions == NULL) {
return ESP_ERR_NO_MEM;
}
// Scan for unallocated space between partitions, starting after the start_offset with unused space >= required_size
uint32_t last_end_address = start_offset;
for (size_t i = 0; i < partition_count; ++i) {
if (sorted_partitions[i]->address > start_offset && sorted_partitions[i]->address > last_end_address) {
size_t unallocated_size = sorted_partitions[i]->address - last_end_address;
if (unallocated_size >= required_size) {
*found_offset = last_end_address;
if (found_size != NULL) {
*found_size = unallocated_size;
}
free(sorted_partitions);
return ESP_OK;
}
}
last_end_address = sorted_partitions[i]->address + sorted_partitions[i]->size;
}
// Check for unallocated space after the last partition
last_end_address = MAX(last_end_address, start_offset);
size_t unallocated_size = flash_chip->size - last_end_address;
if (unallocated_size >= required_size) {
*found_offset = last_end_address;
if (found_size != NULL) {
*found_size = unallocated_size;
}
free(sorted_partitions);
return ESP_OK;
}
free(sorted_partitions);
return ESP_ERR_NOT_FOUND;
}

View File

@@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_partition.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Find unallocated space in the partition table.
*
* This function searches for a contiguous space in the specified flash memory chip
* that can accommodate a region of the given size and is not allocated to any partition.
* It starts searching from the specifies start_offset and continues until the end of the flash memory.
*
* @param[in] flash_chip Pointer to the flash chip structure. If NULL, the default flash chip (internal) is used.
* @param[in] required_size Size of the required unallocated space in bytes.
* @param[in] start_offset Starting offset in the flash memory from where the search should begin.
* @param[out] found_offset Pointer where the offset of the found unallocated space will be stored.
* @param[out] found_size Pointer where the actual size of the found unallocated space will be stored (optional, if it is NULL).
*
* @return
* - ESP_OK: Unallocated space of the required size was found.
* - ESP_ERR_INVALID_ARG: The found_offset parameter is NULL or the required_size is invalid (e.g., 0).
* - ESP_ERR_NOT_FOUND: No suitable unallocated space was found.
*/
esp_err_t partition_utils_find_unallocated(esp_flash_t *flash_chip, size_t required_size, uint32_t start_offset, uint32_t *found_offset, size_t *found_size);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,186 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import http.server
import multiprocessing
import os
import ssl
import sys
from typing import Any
from typing import Optional
import pexpect
import pytest
from pytest_embedded import Dut
try:
from common_test_methods import get_env_config_variable, get_host_ip4_by_dest_ip
except ModuleNotFoundError:
idf_path = os.environ['IDF_PATH']
sys.path.insert(0, idf_path + '/tools/ci/python_packages')
from common_test_methods import get_env_config_variable, get_host_ip4_by_dest_ip
server_cert = '-----BEGIN CERTIFICATE-----\n' \
'MIIDWDCCAkACCQCbF4+gVh/MLjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJJ\n'\
'TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\n'\
'VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\n'\
'b20wHhcNMjEwNzEyMTIzNjI3WhcNNDEwNzA3MTIzNjI3WjBuMQswCQYDVQQGEwJJ\n'\
'TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\n'\
'VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\n'\
'b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxF/y7bygndxPwiWL\n'\
'SwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQuc32W\n'\
'ukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2mKRbQ\n'\
'S5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO2fEz\n'\
'YaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnvL6Oz\n'\
'3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdOAoap\n'\
'rFTRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAItw24y565k3C/zENZlxyzto44ud\n'\
'IYPQXN8Fa2pBlLe1zlSIyuaA/rWQ+i1daS8nPotkCbWZyf5N8DYaTE4B0OfvoUPk\n'\
'B5uGDmbuk6akvlB5BGiYLfQjWHRsK9/4xjtIqN1H58yf3QNROuKsPAeywWS3Fn32\n'\
'3//OpbWaClQePx6udRYMqAitKR+QxL7/BKZQsX+UyShuq8hjphvXvk0BW8ONzuw9\n'\
'RcoORxM0FzySYjeQvm4LhzC/P3ZBhEq0xs55aL2a76SJhq5hJy7T/Xz6NFByvlrN\n'\
'lFJJey33KFrAf5vnV9qcyWFIo7PYy2VsaaEjFeefr7q3sTFSMlJeadexW2Y=\n'\
'-----END CERTIFICATE-----\n'
server_key = '-----BEGIN PRIVATE KEY-----\n'\
'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDhxF/y7bygndxP\n'\
'wiWLSwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQu\n'\
'c32WukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2m\n'\
'KRbQS5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO\n'\
'2fEzYaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnv\n'\
'L6Oz3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdO\n'\
'AoaprFTRAgMBAAECggEAE0HCxV/N1Q1h+1OeDDGL5+74yjKSFKyb/vTVcaPCrmaH\n'\
'fPvp0ddOvMZJ4FDMAsiQS6/n4gQ7EKKEnYmwTqj4eUYW8yxGUn3f0YbPHbZT+Mkj\n'\
'z5woi3nMKi/MxCGDQZX4Ow3xUQlITUqibsfWcFHis8c4mTqdh4qj7xJzehD2PVYF\n'\
'gNHZsvVj6MltjBDAVwV1IlGoHjuElm6vuzkfX7phxcA1B4ZqdYY17yCXUnvui46z\n'\
'Xn2kUTOOUCEgfgvGa9E+l4OtdXi5IxjaSraU+dlg2KsE4TpCuN2MEVkeR5Ms3Y7Q\n'\
'jgJl8vlNFJDQpbFukLcYwG7rO5N5dQ6WWfVia/5XgQKBgQD74at/bXAPrh9NxPmz\n'\
'i1oqCHMDoM9sz8xIMZLF9YVu3Jf8ux4xVpRSnNy5RU1gl7ZXbpdgeIQ4v04zy5aw\n'\
'8T4tu9K3XnR3UXOy25AK0q+cnnxZg3kFQm+PhtOCKEFjPHrgo2MUfnj+EDddod7N\n'\
'JQr9q5rEFbqHupFPpWlqCa3QmQKBgQDldWUGokNaEpmgHDMnHxiibXV5LQhzf8Rq\n'\
'gJIQXb7R9EsTSXEvsDyqTBb7PHp2Ko7rZ5YQfyf8OogGGjGElnPoU/a+Jij1gVFv\n'\
'kZ064uXAAISBkwHdcuobqc5EbG3ceyH46F+FBFhqM8KcbxJxx08objmh58+83InN\n'\
'P9Qr25Xw+QKBgEGXMHuMWgQbSZeM1aFFhoMvlBO7yogBTKb4Ecpu9wI5e3Kan3Al\n'\
'pZYltuyf+VhP6XG3IMBEYdoNJyYhu+nzyEdMg8CwXg+8LC7FMis/Ve+o7aS5scgG\n'\
'1to/N9DK/swCsdTRdzmc/ZDbVC+TuVsebFBGYZTyO5KgqLpezqaIQrTxAoGALFCU\n'\
'10glO9MVyl9H3clap5v+MQ3qcOv/EhaMnw6L2N6WVT481tnxjW4ujgzrFcE4YuxZ\n'\
'hgwYu9TOCmeqopGwBvGYWLbj+C4mfSahOAs0FfXDoYazuIIGBpuv03UhbpB1Si4O\n'\
'rJDfRnuCnVWyOTkl54gKJ2OusinhjztBjcrV1XkCgYEA3qNi4uBsPdyz9BZGb/3G\n'\
'rOMSw0CaT4pEMTLZqURmDP/0hxvTk1polP7O/FYwxVuJnBb6mzDa0xpLFPTpIAnJ\n'\
'YXB8xpXU69QVh+EBbemdJWOd+zp5UCfXvb2shAeG3Tn/Dz4cBBMEUutbzP+or0nG\n'\
'vSXnRLaxQhooWm+IuX9SuBQ=\n'\
'-----END PRIVATE KEY-----\n'
@pytest.mark.esp32 # This chip should be >= v3.0
@pytest.mark.esp32c3
@pytest.mark.esp32s3
@pytest.mark.wifi_high_traffic
@pytest.mark.parametrize('config', [
'on_update_no_sb_ecdsa',
'on_update_no_sb_rsa',
'virt_sb_v2_and_fe',
'virt_sb_v2_and_fe_2'
], indirect=True)
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
@pytest.mark.timeout(2400)
def test_examples_partitions_ota(dut: Dut) -> None:
print(' - Erase flash')
dut.serial.erase_flash()
print(' - Flash bootloader')
dut.serial.bootloader_flash()
print(' - Start app (flash partition_table and app)')
dut.serial.write_flash_no_enc()
update_partitions(dut, 'wifi_high_traffic')
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.flash_encryption_wifi_high_traffic
@pytest.mark.nightly_run
@pytest.mark.timeout(2400)
@pytest.mark.parametrize('config', [
'flash_enc_wifi',
'flash_enc_wifi_2'
], indirect=True)
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
def test_examples_partitions_ota_with_flash_encryption_wifi(dut: Dut) -> None:
dut.serial.erase_flash()
dut.serial.flash()
update_partitions(dut, 'flash_encryption_wifi_high_traffic')
def update_partitions(dut: Dut, env_name: Optional[str]) -> None:
port = 8000
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', port))
thread1.daemon = True
thread1.start()
try:
update(dut, port, 'partitions_ota.bin', env_name)
update(dut, port, 'bootloader/bootloader.bin', env_name)
update(dut, port, 'partition_table/partition-table.bin', env_name)
update(dut, port, 'storage.bin', env_name)
finally:
thread1.terminate()
def update(dut: Dut, port: int, path_to_image: str, env_name: Optional[str]) -> None:
dut.expect('OTA example app_main start', timeout=90)
host_ip = setting_connection(dut, env_name)
dut.expect('Starting OTA example task', timeout=30)
url = f'https://{host_ip}:{port}/{path_to_image}'
print(f'Writing to device: {url}')
dut.write(url)
dut.expect('OTA Succeed, Rebooting...', timeout=90)
def setting_connection(dut: Dut, env_name: Optional[str]) -> Any:
if env_name is not None and dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
dut.expect('Please input ssid password:')
ap_ssid = get_env_config_variable(env_name, 'ap_ssid')
ap_password = get_env_config_variable(env_name, 'ap_password')
dut.write(f'{ap_ssid} {ap_password}')
try:
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
print(f'Connected to AP/Ethernet with IP: {ip_address}')
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
return get_host_ip4_by_dest_ip(ip_address)
def start_https_server(ota_image_dir: str, server_ip: str, server_port: int, server_file: Optional[str] = None, key_file: Optional[str] = None) -> None:
os.chdir(ota_image_dir)
if server_file is None:
server_file = os.path.join(ota_image_dir, 'server_cert.pem')
cert_file_handle = open(server_file, 'w+')
cert_file_handle.write(server_cert)
cert_file_handle.close()
if key_file is None:
key_file = os.path.join(ota_image_dir, 'server_key.pem')
key_file_handle = open('server_key.pem', 'w+')
key_file_handle.write(server_key)
key_file_handle.close()
httpd = http.server.HTTPServer((server_ip, server_port), http.server.SimpleHTTPRequestHandler)
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file)
httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True)
httpd.serve_forever()
if __name__ == '__main__':
if sys.argv[2:]: # if two or more arguments provided:
# Usage: pytest_partition_ota.py <image_dir> <server_port> [cert_dir]
image_dir = os.path.dirname(os.path.realpath(__file__))
bin_dir = os.path.join(image_dir, sys.argv[1])
server_port = int(sys.argv[2])
server_file = None
key_file = None
if sys.argv[3:]: # [cert_dir] - optional argument
cert_dir = os.path.join(image_dir, sys.argv[3])
server_file = os.path.join(cert_dir, 'ca_cert.pem')
key_file = os.path.join(cert_dir, 'ca_key.pem')
print(f'Starting HTTPS server at "https://0.0.0.0:{server_port}"')
start_https_server(bin_dir, '0.0.0.0', server_port, server_file=server_file, key_file=key_file)

View File

@@ -0,0 +1,21 @@
# Common configs
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_EXAMPLE_CONNECT_IPV6=n
CONFIG_SECURE_FLASH_ENC_ENABLED=y
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y
CONFIG_SECURE_BOOT_ALLOW_JTAG=y
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
# This is required for nvs encryption (which is enabled by default with flash encryption)
CONFIG_PARTITION_TABLE_OFFSET=0x9000

View File

@@ -0,0 +1,24 @@
# Common configs
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_EXAMPLE_CONNECT_IPV6=n
CONFIG_SECURE_FLASH_ENC_ENABLED=y
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y
CONFIG_SECURE_BOOT_ALLOW_JTAG=y
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
# This is required for nvs encryption (which is enabled by default with flash encryption)
CONFIG_PARTITION_TABLE_OFFSET=0x9000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul_2.csv"

View File

@@ -0,0 +1,19 @@
# Common configs
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_EXAMPLE_CONNECT_IPV6=n
# ECDSA is available only in ESP32
CONFIG_IDF_TARGET="esp32"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT=y
CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT=y
CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME=y
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key_ecdsa.pem"

View File

@@ -0,0 +1,17 @@
# Common configs
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_EXAMPLE_CONNECT_IPV6=n
CONFIG_PARTITION_TABLE_OFFSET=0xC000
CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT=y
CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT=y
CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=y
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION=y

View File

@@ -0,0 +1,3 @@
# ESP32 supports SIGNED_APPS_RSA_SCHEME only in ECO3
CONFIG_IDF_TARGET="esp32"
CONFIG_ESP32_REV_MIN_3=y

View File

@@ -0,0 +1,23 @@
# Common configs
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_EXAMPLE_CONNECT_IPV6=n
# FLASH_ENCRYPTION & SECURE_BOOT_V2 with EFUSE_VIRTUAL_KEEP_IN_FLASH
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
CONFIG_EFUSE_VIRTUAL=y
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
CONFIG_PARTITION_TABLE_OFFSET=0xE000
CONFIG_SECURE_BOOT=y
CONFIG_SECURE_BOOT_V2_ENABLED=y
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
CONFIG_SECURE_DISABLE_ROM_DL_MODE=y
CONFIG_SECURE_FLASH_ENC_ENABLED=y

View File

@@ -0,0 +1,3 @@
# ESP32 supports SECURE_BOOT_V2 only in ECO3
CONFIG_IDF_TARGET="esp32"
CONFIG_ESP32_REV_MIN_3=y

View File

@@ -0,0 +1,26 @@
# Common configs
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF=y
CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_EXAMPLE_CONNECT_IPV6=n
# FLASH_ENCRYPTION & SECURE_BOOT_V2 with EFUSE_VIRTUAL_KEEP_IN_FLASH
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
CONFIG_EFUSE_VIRTUAL=y
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y
CONFIG_PARTITION_TABLE_OFFSET=0xE000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul_2.csv"
CONFIG_SECURE_BOOT=y
CONFIG_SECURE_BOOT_V2_ENABLED=y
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
CONFIG_SECURE_DISABLE_ROM_DL_MODE=y
CONFIG_SECURE_FLASH_ENC_ENABLED=y

View File

@@ -0,0 +1,3 @@
# ESP32 supports SECURE_BOOT_V2 only in ECO3
CONFIG_IDF_TARGET="esp32"
CONFIG_ESP32_REV_MIN_3=y

View File

@@ -0,0 +1,11 @@
# Default sdkconfig parameters to use the OTA
# partition table layout, with a 4MB flash size
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul_1.csv"
# Certificate bundle configuration
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="server_certs/ca_cert.pem"

View File

@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDWDCCAkACCQCbF4+gVh/MLjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJJ
TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD
VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j
b20wHhcNMjEwNzEyMTIzNjI3WhcNNDEwNzA3MTIzNjI3WjBuMQswCQYDVQQGEwJJ
TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD
VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxF/y7bygndxPwiWL
SwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQuc32W
ukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2mKRbQ
S5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO2fEz
YaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnvL6Oz
3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdOAoap
rFTRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAItw24y565k3C/zENZlxyzto44ud
IYPQXN8Fa2pBlLe1zlSIyuaA/rWQ+i1daS8nPotkCbWZyf5N8DYaTE4B0OfvoUPk
B5uGDmbuk6akvlB5BGiYLfQjWHRsK9/4xjtIqN1H58yf3QNROuKsPAeywWS3Fn32
3//OpbWaClQePx6udRYMqAitKR+QxL7/BKZQsX+UyShuq8hjphvXvk0BW8ONzuw9
RcoORxM0FzySYjeQvm4LhzC/P3ZBhEq0xs55aL2a76SJhq5hJy7T/Xz6NFByvlrN
lFJJey33KFrAf5vnV9qcyWFIo7PYy2VsaaEjFeefr7q3sTFSMlJeadexW2Y=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,9 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, , 0x6000,
nvs_key, data, nvs_keys, , 4K,
storage, data, , , 0x1000, encrypted
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
emul_efuse, data, efuse, , 0x2000,
ota_0, app, ota_0, , 0x1B0000,
ota_1, app, ota_1, , 0x1B0000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x6000
3 nvs_key data nvs_keys 4K
4 storage data 0x1000 encrypted
5 otadata data ota 0x2000
6 phy_init data phy 0x1000
7 emul_efuse data efuse 0x2000
8 ota_0 app ota_0 0x1B0000
9 ota_1 app ota_1 0x1B0000

View File

@@ -0,0 +1,11 @@
# Name, Type, SubType, Offset, Size, Flags
PrimaryBTLDR, bootloader, primary, N/A, N/A,
PrimaryPrtTable, partition_table, primary, N/A, N/A,
nvs, data, nvs, , 0x6000,
nvs_key, data, nvs_keys, , 4K,
storage, data, , , 0x1000, encrypted
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
emul_efuse, data, efuse, , 0x2000,
ota_0, app, ota_0, , 0x1B0000,
ota_1, app, ota_1, , 0x1B0000,
1 # Name Type SubType Offset Size Flags
2 PrimaryBTLDR bootloader primary N/A N/A
3 PrimaryPrtTable partition_table primary N/A N/A
4 nvs data nvs 0x6000
5 nvs_key data nvs_keys 4K
6 storage data 0x1000 encrypted
7 otadata data ota 0x2000
8 phy_init data phy 0x1000
9 emul_efuse data efuse 0x2000
10 ota_0 app ota_0 0x1B0000
11 ota_1 app ota_1 0x1B0000

View File

@@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
MIIG4wIBAAKCAYEAzJUktQ+7wpPDfDGterxiMRx5w9n7PFaUSK3wnE+05ALsEF8F
rUOC7/q0GutYYdWopdRM1FUKX2XVaryMViC+DHof42fEbpWYnfrCkYrDn8MLuMyK
4uGunl8LUTIAZk3I3SZKJZy5FW9eb1XtkwfN1lAd6lEEGQKyoR6Bk/Rkisj0LP7R
dyV9NKbJhxavZ1ohZXiXU5FW873iGdPIsloZoUK3QGRE1KRIH2woUGHATfXBCf5a
+e41wJzz7YHl5tjyxAbJ9PET52N14G73WoZKHu3QPShALrZVfjsk1oYdFvNdOBDL
uU0vpyKl7mJHno11gM0UM0s9PrMxk9ffdAqMyS8YeLEk2Xl3AwPv7m9oeGIdSD/P
okcISYcm4YAl5veqIG3RlkfpWjf5G15UYyLbgmn4GOkgr6ksB/dCFOMi9V1LjPah
32A7gxqTlapQza+wNs30SYBIXrFde4bNnhFhj4Cbt34ADefWm26KLiZEHFHFN30Z
IownitXz3rT7rmzBAgMBAAECggGBAK6bBA88dGWnM4rF42gDbFK6GPqdCp3+zuQR
AHCIXrzT+aInV3L/Ubt730eyYWZusleGEGSQiB/PjAxjC+teWpXPjXPK1o4DQ5Rh
trn9EuVB1LlOaaMmNqCYQdJ0uH6YGL0WtuXPEvBGcvTXA8MfQACPtFiN+M9XzBlT
LgiW51DEHhJhEWl9J5VOXGXdaKru893kxFLgkrPI9jZQ2NPPrlxB0qE0csKBy8R1
zRp9s2FWRAFBg2gYdOwFiPLGkO8rbM+jhXM+IUV1GgVYdxAC6zS9AiIAWuACDEwp
Pzg3d3/5uyOFK1xTIPl/cG8CZyPQL1v/mUx0MZFaB1R1CVeDuMoFVz2YSbEaAVFv
QIcJGDN/WlJbt0jwj7/RJKKTx0ipFlUdNbodzdaSl3Yg4N+evzR1nS8DvLJpwl/e
ybu40IbavwYXWVzirH3wRg+P/NDsHLU5xASAyUwf1minsmObILayEZgfTA6TbrKL
fZbJCvy2/IuCM6iqKZwSvYy0bJdaAQKBwQDzDVa/M4/sJV0GEbwegeN6Xf+XKkl3
Gosjd+vQgv/0X1gbdMc0Ej9eYSU5/GYIHxDzDRkYIxtIfwaze1gGeNRHycMCmVkl
09DMi48jLGE7wzObPu6MtBCSAGHaS9zMTVCYDYtRlykPzG2/1QNrRUDNACnpzneK
MkWObzFYTIup1zh+JaD56vLIDdL7qM9apmEkq4O6y1BBPnCgRYJy5EU3BDZxz9fP
47JtCZ47uVguoh/NVYY5uibdvI5iJ4SA/VECgcEA13srpwJppfTTFPRWgD+g7PdU
Yg+ENBWygiJuwgGv6DyD4k73pxiyshNo7jxsdOLeGFA8hI3dvd/Ei6uUsGnWPy/a
OwuBcOZrJZjyawNSiC+mrCSP0LGQrC5VjmuE8IU1d2hFWyV/NzkSLaXJ52Zkg3ee
sSepBHtWEYpwH929u5FTKDKhL0qRH8E1EsULSjmkTa+cVDYgx8+2mb3vHRdJdvt3
FZU9erKyDb4II5GJhyNQo/cxBosDzj4yIMKM/dxxAoHAE1r1lIZjqLeU/927sGZB
mkYQC5a3gP+hIvLy2YkFHw3Us2MKVhA58ack0shRy8XFkMVzQSPSkWRkQTjKWsGW
jhz4JaXWnpeOoite+7sWBy9VVcCeOKBCTY4wPLUb4T0q9ODnPlkeUP7Doqow+oLq
VSj1LYReqqe0OFKMiG6YFK9p9UnD1wMp0FqheZ8I3DwxsjziYaa9PmTdjTXb3JBn
Hql8OHYHxqtoUxyX+EObTSNmCvELnl8/pxrT7+cbuzXxAoHAfmNYb1US8qxvQtMu
CXtIwLUxYXMIcCRp17qqjFDBBM657Hu09uWdqqWH3nTCiKyo6EnntTgg38XoWqQB
SphJejZvIkLVYYtFPYBAcFQ6jHampEGtuRLtcJCczjRyfUEk4yzdwWB1BccLyop7
qqZ8PkBjbDV/BYnyKcexjH9bUjEjPWi08jAifyWsI54/yQGWRZrDbwFwqMJEsFif
b8jA5nEIoDgxH07A8R6NV499wy4LlqDeuJ/BU69XZ6+1UxGBAoHAXfb9t5ivdf9N
ZbZj61GcrDLyYGDTotucy8HPNMr5P3ZmBR/5UzClpCbWVSaziK3CKzR0zURLw0W7
rF4CySTjuD9FHOFFWjjlkS4KwOyYiy8fuMMLg1RmsCS8H+0L3Pm25PmRQ9TLjEf4
0uFWf7fG4GQiciqGcvfaFH3w//d0Q7PSvIMNlM1Gc7JS1Qn4HoDF2Ux6drNb6nJL
l6tdXNMkUFHBMtaQy0l9D/ex5NZlAniePT3xfMrQf6m0rVAAaAY0
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOvP45grF4dSM2fWbOAp4W8PgFm30HIZqtNEK13O5hVHoAoGCCqGSM49
AwEHoUQDQgAE1IL73BARrNpkHj1jG50eHoF2LERCwz1BfbshuAeLcsED5aT92Xgu
gJvq45LN9p6eBi62ZZwr6Z2ZfX3YB3/8KA==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,68 @@
729640676936343167405726443197135657269157998
933232050979719444751452267503063397819023382
556506319597389776571009503699952437641061732
002752455079598828837517200348560233202884961
289477881250470899211041514323644847313434252
730231884515472435547694444234642911818478157
604144032495549544339412331088820122187613561
037928985771855738051392892725939092474036895
578049014383949960944604448487826864453409450
296161831460741246018093614276144348092833874
140428241649972439923475366687089049988769325
628351145210907812434482037266152681719092912
195052933351010873736343964178221498387487568
880765493241408400507065714578908626300143903
883991915607625769735210770743664311477574805
803046247728563775122702680062751243196677727
591992825319085180539338771922153143676093557
878162825694361186599018123247178797942043904
253513230477134391345104969412487168458933717
879463603920957341514770185585897085439536061
546050366983003480039672501169984474709911556
432680670735296891758812059406730550421434400
799748308597104378938356890827982866134014221
535217212317851509531435779909442853259569048
580409528656447379596945028254287449496748086
321387039712708832937716833909605696109504066
278470671408892520188316938495958536257526665
660640085363653328064067701371831709621622531
436530770318421608478245539795335337571927836
848053923388780499943352551523532238273698176
049362112819423888880054249487849648130087221
687010509088780417528465152444332299326657281
255338606197500772061483497687185654530379009
809223233886931933248343109674340504152295885
765334333996117982147891052573656099707681910
057424651564819028940604517398495382795147311
752675767253643761529415181834038113062154258
694020157776375821024488585116268734923621487
797603120028758119376826166666195814602885184
256054926782662332557983780119850277271110264
534729118343464049562614126424801063288960662
418497776363476573070239863993771788850167929
544623158969320919268138503435885988442279793
367410227609285002234584503009426598103851672
344936392655102339554247845914915561479550647
291980804702566220358719744252448087492119608
704318916097427876642053084788623400842338607
771470900612011584595877155134205277401842505
909521197008143210604801870018968664140327930
324980994466472002076385074301506530901535978
320185664126981369956414311892197871161156454
378766138079997290959022342245831189632927648
364825257659858363550270789813108372635022027
738652557666400070994836903956811374712435567
047611244061167695176168226753393440679656386
185089811485754675632410309589122549282952655
762982585738215953889178883392751359696199678
466365406348114092011380838127323464485769393
308459315194527893288390791240690970366091968
418737882756335691688926129739468319284933735
112439699935630133393004802185263769845456882
716047319575852391012595513490467744266860105
117800597394726582034935172600056709435421428
760032386987855643579460268598949375417486418
353173014844750264581499676629717396353130841
051820655315640727727623322576821500963566535
812443435910850388330357301683274331804203320
356920660584480371919309487962624455455544515