Merge branch 'contrib/github_pr_15030' into 'master'

feat(app_update): esp_ota_mark_app_invalid_rollback() without reboot (GitHub PR)

Closes IDFGH-14234
Closes https://github.com/espressif/esp-idf/pull/15030

See merge request espressif/esp-idf!35843
This commit is contained in:
Mahavir Jain 2025-01-20 20:59:05 +08:00
commit ff13eb1791
4 changed files with 35 additions and 15 deletions

View File

@ -867,8 +867,7 @@ static esp_err_t esp_ota_current_ota_is_workable(bool valid)
if (err != ESP_OK) {
return err;
}
ESP_LOGI(TAG, "Rollback to previously worked partition. Restart.");
esp_restart();
ESP_LOGI(TAG, "Rollback to previously worked partition.");
}
} else {
ESP_LOGE(TAG, "Running firmware is factory");
@ -882,11 +881,20 @@ esp_err_t esp_ota_mark_app_valid_cancel_rollback(void)
return esp_ota_current_ota_is_workable(true);
}
esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot(void)
esp_err_t esp_ota_mark_app_invalid_rollback(void)
{
return esp_ota_current_ota_is_workable(false);
}
esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot(void)
{
esp_err_t ret = esp_ota_mark_app_invalid_rollback();
if (ret == ESP_OK) {
esp_restart();
}
return ret;
}
static bool check_invalid_otadata (const esp_ota_select_entry_t *s) {
return s->ota_seq != UINT32_MAX &&
s->crc == bootloader_common_ota_select_crc(s) &&

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -334,12 +334,24 @@ uint8_t esp_ota_get_app_partition_count(void);
esp_err_t esp_ota_mark_app_valid_cancel_rollback(void);
/**
* @brief This function is called to roll back to the previously workable app with reboot.
* @brief This function is called to roll back to the previously workable app without reboot.
*
* If rollback is successful then device will reset else API will return with error code.
* Checks applications on a flash drive that can be booted in case of rollback.
* If the flash does not have at least one app (except the running app) then rollback is not possible.
* @return
* - ESP_OK: if successful.
* - ESP_FAIL: if not successful.
* - ESP_ERR_OTA_ROLLBACK_FAILED: The rollback is not possible because the available OTA partitions
* on the flash do not contain a valid application.
*/
esp_err_t esp_ota_mark_app_invalid_rollback(void);
/**
* @brief This function is called to roll back to the previously workable app with reboot.
*
* Equivalent to calling esp_ota_mark_app_invalid_rollback(), and, if successful, followed by esp_restart().
*
* @return
* - ESP_FAIL: if not successful.
* - ESP_ERR_OTA_ROLLBACK_FAILED: The rollback is not possible due to flash does not have any apps.
*/

View File

@ -140,7 +140,7 @@ A brief description of where the states are set:
* ``ESP_OTA_IMG_VALID`` state is set by :cpp:func:`esp_ota_mark_app_valid_cancel_rollback` function.
* ``ESP_OTA_IMG_UNDEFINED`` state is set by :cpp:func:`esp_ota_set_boot_partition` function if :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` option is not enabled.
* ``ESP_OTA_IMG_NEW`` state is set by :cpp:func:`esp_ota_set_boot_partition` function if :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` option is enabled.
* ``ESP_OTA_IMG_INVALID`` state is set by :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` function.
* ``ESP_OTA_IMG_INVALID`` state is set by function :cpp:func:`esp_ota_mark_app_invalid_rollback` or :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot`.
* ``ESP_OTA_IMG_ABORTED`` state is set if there was no confirmation of the application operability and occurs reboots (if :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` option is enabled).
* ``ESP_OTA_IMG_PENDING_VERIFY`` state is set in a bootloader if :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` option is enabled and selected app has ``ESP_OTA_IMG_NEW`` state.
@ -165,7 +165,7 @@ A Typical Anti-rollback Scheme Is
- To make it bootable, run the function :cpp:func:`esp_ota_set_boot_partition`. If the security version of the new application is smaller than the version in the chip, the new application will be erased. Update to new firmware is not possible.
- Reboot.
- In the bootloader, an application with a security version greater than or equal to the version in the chip will be selected. If otadata is in the initial state, and one firmware was loaded via a serial channel, whose secure version is higher than the chip, then the secure version of efuse will be immediately updated in the bootloader.
- New application booted. Then the application should perform diagnostics of the operation and if it is completed successfully, you should call :cpp:func:`esp_ota_mark_app_valid_cancel_rollback` function to mark the running application with the ``ESP_OTA_IMG_VALID`` state and update the secure version on chip. Note that if was called :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` function a rollback may not happen as the device may not have any bootable apps. It will then return ``ESP_ERR_OTA_ROLLBACK_FAILED`` error and stay in the ``ESP_OTA_IMG_PENDING_VERIFY`` state.
- New application booted. Then the application should perform diagnostics of the operation and if it is completed successfully, you should call :cpp:func:`esp_ota_mark_app_valid_cancel_rollback` function to mark the running application with the ``ESP_OTA_IMG_VALID`` state and update the secure version on chip. Note that if the :cpp:func:`esp_ota_mark_app_invalid_rollback` or :cpp:func:`esp_ota_mark_app_invalid_rollback_with_reboot` function is called a rollback may not happen as the device may not have any bootable apps. It will then return ``ESP_ERR_OTA_ROLLBACK_FAILED`` error and stay in the ``ESP_OTA_IMG_PENDING_VERIFY`` state.
- The next update of app is possible if a running app is in the ``ESP_OTA_IMG_VALID`` state.
Recommendation:
@ -215,7 +215,7 @@ Restrictions:
.. only:: esp32
- In ESP32 it is stored in efuse ``EFUSE_BLK3_RDATA4_REG``. (when a eFuse bit is programmed to 1, it can never be reverted to 0). The number of bits set in this register is the ``security_version`` from app.
- In ESP32, it is stored in efuse ``EFUSE_BLK3_RDATA4_REG``. (when an eFuse bit is programmed to 1, it can never be reverted to 0). The number of bits set in this register is the ``security_version`` from app.
.. _secure-ota-updates:
@ -223,11 +223,11 @@ Restrictions:
Secure OTA Updates Without Secure Boot
--------------------------------------
The verification of signed OTA updates can be performed even without enabling hardware secure boot. This can be achieved by setting :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` and :ref:`CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT`
The verification of signed OTA updates can be performed even without enabling hardware secure boot. This can be achieved by setting :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` and :ref:`CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT`.
.. only:: esp32
For more information refer to :ref:`signed-app-verify`
For more information, please refer to :ref:`signed-app-verify`.
Tuning OTA Performance
----------------------
@ -275,7 +275,7 @@ Before anything else, make sure that the ``otatool`` module is imported.
sys.path.append(otatool_dir) # this enables Python to find otatool module
from otatool import * # import all names inside otatool module
The starting point for using the tool's Python API to do is create a ``OtatoolTarget`` object:
The starting point for using the tool's Python API to do is create an ``OtatoolTarget`` object:
.. code-block:: python

View File

@ -12,7 +12,7 @@ OTA 升级机制可以让设备在固件正常运行时根据接收数据(如
- **安全更新模式**:可靠、稳定的分区更新,即使在更新期间断电,芯片仍能正常运行,并能够启动当前的应用程序。以下分区支持此模式:
- 应用程序分区。要进行 OTA 更新,需在设备的 :doc:`../../api-guides/partition-tables` 分区表中配置至少两个 OTA 应用程序分区槽(例如 ``ota_0````ota_1``)以及一个 OTA 数据分区。OTA 操作函数会将新的应用程序固件镜像写入当前未被选为启动分区的 OTA 应用程序分区槽。镜像验证通过后OTA 数据分区将被更新,以指定在下次启动时使用该镜像。
- 应用程序分区。要进行 OTA 更新,需在设备的 :doc:`../../api-guides/partition-tables` 中配置至少两个 OTA 应用程序分区槽(例如 ``ota_0````ota_1``)以及一个 OTA 数据分区。OTA 操作函数会将新的应用程序固件镜像写入当前未被选为启动分区的 OTA 应用程序分区槽。镜像验证通过后OTA 数据分区将被更新,以指定在下次启动时使用该镜像。
- **非安全更新模式**:此更新过程容易受到干扰,如果在更新过程中断电,可能会导致当前应用程序无法加载,甚至进入无法恢复的状态。在此模式下,新的镜像会先下载到临时分区,下载完成后复制到最终的目标分区。如果在最终复制过程中发生中断,可能会导致问题。以下分区支持此模式:
@ -140,7 +140,7 @@ Kconfig 中的 :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 可以帮助用户
* ``ESP_OTA_IMG_VALID`` 由函数 :cpp:func:`esp_ota_mark_app_valid_cancel_rollback` 设置。
* 如果 :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 没有使能,``ESP_OTA_IMG_UNDEFINED`` 由函数 :cpp:func:`esp_ota_set_boot_partition` 设置。
* 如果 :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 使能,``ESP_OTA_IMG_NEW`` 由函数 :cpp:func:`esp_ota_set_boot_partition` 设置。
* ``ESP_OTA_IMG_INVALID`` 由函数 :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` 设置。
* ``ESP_OTA_IMG_INVALID`` 由函数 :cpp:func:`esp_ota_mark_app_invalid_rollback` 或 :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot` 设置。
* 如果应用程序的可操作性无法确认,发生重启(:ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 使能),则设置 ``ESP_OTA_IMG_ABORTED``
* 如果 :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 使能,选取的应用程序状态为 ``ESP_OTA_IMG_NEW``,则在引导加载程序中设置 ``ESP_OTA_IMG_PENDING_VERIFY``
@ -165,7 +165,7 @@ Kconfig 中的 :ref:`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE` 可以帮助用户
- 运行函数 :cpp:func:`esp_ota_set_boot_partition`,将新版应用程序设为可启动。如果新版应用程序的安全版本号低于芯片中的应用安全版本号,新版应用程序会被擦除,无法更新到新固件。
- 重新启动。
- 在引导加载程序中选取安全版本号等于或高于芯片中应用安全版本号的应用程序。如果 otadata 处于初始阶段,通过串行通道加载了安全版本号高于芯片中应用安全版本号的固件,则引导加载程序中 eFuse 的安全版本号会立即更新。
- 新版应用程序启动,之后进行可操作性检测,如果通过检测,则调用函数 :cpp:func:`esp_ota_mark_app_valid_cancel_rollback`,将应用程序标记为 ``ESP_OTA_IMG_VALID``,更新芯片中应用程序的安全版本号。注意,如果调用函数 :cpp:func:`esp_ota_mark_app_invalid_rollback_and_reboot`可能会因为设备中没有可启动的应用程序而回滚失败,返回 ``ESP_ERR_OTA_ROLLBACK_FAILED`` 错误,应用程序状态一直``ESP_OTA_IMG_PENDING_VERIFY``
- 新版应用程序启动,之后进行可操作性检测,如果通过检测,则调用函数 :cpp:func:`esp_ota_mark_app_valid_cancel_rollback`,将应用程序标记为 ``ESP_OTA_IMG_VALID``,更新芯片中应用程序的安全版本号。注意,如果调用函数 :cpp:func:`esp_ota_mark_app_invalid_rollback` 或 :cpp:func:`esp_ota_mark_app_invalid_rollback_with_reboot`可能会因为设备中没有可启动的应用程序而回滚失败,返回 ``ESP_ERR_OTA_ROLLBACK_FAILED`` 错误,应用程序状态一直处于 ``ESP_OTA_IMG_PENDING_VERIFY`` 状态。
- 如果运行的应用程序处于 ``ESP_OTA_IMG_VALID`` 状态,则可再次更新。
建议: