]> granicus.if.org Git - esp-idf/commitdiff
bootloader app_update: Refactoring otadata part
authorKonstantin Kondrashov <konstantin@espressif.com>
Mon, 22 Oct 2018 15:11:10 +0000 (23:11 +0800)
committerKonstantin Kondrashov <konstantin@espressif.com>
Wed, 5 Dec 2018 03:20:03 +0000 (11:20 +0800)
components/app_update/esp_ota_ops.c
components/bootloader_support/include/bootloader_common.h
components/bootloader_support/src/bootloader_common.c
components/bootloader_support/src/bootloader_utility.c

index fdab1b95cd02853b525b0b1e372c1f67c1106387..5d415ffecae82dc732e058ec40a1f25520dd542e 100644 (file)
 #include "rom/crc.h"
 #include "soc/dport_reg.h"
 #include "esp_log.h"
+#include "esp_flash_data_types.h"
+#include "bootloader_common.h"
+#include "sys/param.h"
 
-
-#define OTA_MAX(a,b) ((a) >= (b) ? (a) : (b)) 
-#define OTA_MIN(a,b) ((a) <= (b) ? (a) : (b)) 
 #define SUB_TYPE_ID(i) (i & 0x0F) 
 
 typedef struct ota_ops_entry_ {
@@ -52,19 +52,10 @@ typedef struct ota_ops_entry_ {
     LIST_ENTRY(ota_ops_entry_) entries;
 } ota_ops_entry_t;
 
-/* OTA selection structure (two copies in the OTA data partition.)
-   Size of 32 bytes is friendly to flash encryption */
-typedef struct {
-    uint32_t ota_seq;
-    uint8_t  seq_label[24];
-    uint32_t crc;                /* CRC32 of ota_seq field only */
-} ota_select;
-
 static LIST_HEAD(ota_ops_entries_head, ota_ops_entry_) s_ota_ops_entries_head =
     LIST_HEAD_INITIALIZER(s_ota_ops_entries_head);
 
 static uint32_t s_ota_ops_last_handle = 0;
-static ota_select s_ota_select[2];
 
 const static char *TAG = "esp_ota_ops";
 
@@ -77,6 +68,53 @@ static bool is_ota_partition(const esp_partition_t *p)
             && p->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX);
 }
 
+// Read otadata partition and fill array from two otadata structures.
+// Also return pointer to otadata info partition.
+static const esp_partition_t *read_otadata(esp_ota_select_entry_t *two_otadata)
+{
+    const esp_partition_t *otadata_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
+
+    if (otadata_partition == NULL) {
+        ESP_LOGE(TAG, "not found otadata");
+        return NULL;
+    }
+
+    spi_flash_mmap_handle_t ota_data_map;
+    const void *result = NULL;
+    esp_err_t err = esp_partition_mmap(otadata_partition, 0, otadata_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "mmap otadata filed. Err=0x%8x", err);
+        return NULL;
+    } else {
+        memcpy(&two_otadata[0], result, sizeof(esp_ota_select_entry_t));
+        memcpy(&two_otadata[1], result + SPI_FLASH_SEC_SIZE, sizeof(esp_ota_select_entry_t));
+        spi_flash_munmap(ota_data_map);
+    }
+    return otadata_partition;
+}
+
+static esp_err_t image_validate(const esp_partition_t *partition, esp_image_load_mode_t load_mode)
+{
+    esp_image_metadata_t data;
+    const esp_partition_pos_t part_pos = {
+        .offset = partition->address,
+        .size = partition->size,
+    };
+
+    if (esp_image_verify(load_mode, &part_pos, &data) != ESP_OK) {
+        return ESP_ERR_OTA_VALIDATE_FAILED;
+    }
+
+#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
+    esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len);
+    if (ret != ESP_OK) {
+        return ESP_ERR_OTA_VALIDATE_FAILED;
+    }
+#endif
+
+    return ESP_OK;
+}
+
 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;
@@ -157,7 +195,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
 
                 /* check if we have partially written data from earlier */
                 if (it->partial_bytes != 0) {
-                    copy_len = OTA_MIN(16 - it->partial_bytes, size);
+                    copy_len = MIN(16 - it->partial_bytes, size);
                     memcpy(it->partial_data + it->partial_bytes, data_bytes, copy_len);
                     it->partial_bytes += copy_len;
                     if (it->partial_bytes != 16) {
@@ -247,31 +285,19 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
     return ret;
 }
 
-static uint32_t ota_select_crc(const ota_select *s)
+static esp_err_t rewrite_ota_seq(esp_ota_select_entry_t *two_otadata, uint32_t seq, uint8_t sec_id, const esp_partition_t *ota_data_partition)
 {
-    return crc32_le(UINT32_MAX, (uint8_t *)&s->ota_seq, 4);
-}
-
-static bool ota_select_valid(const ota_select *s)
-{
-    return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
-}
-
-static esp_err_t rewrite_ota_seq(uint32_t seq, uint8_t sec_id, const esp_partition_t *ota_data_partition)
-{
-    esp_err_t ret;
+    if (two_otadata == NULL || sec_id > 1) {
+        return ESP_ERR_INVALID_ARG;
+    }
 
-    if (sec_id == 0 || sec_id == 1) {
-        s_ota_select[sec_id].ota_seq = seq;
-        s_ota_select[sec_id].crc = ota_select_crc(&s_ota_select[sec_id]);
-        ret = esp_partition_erase_range(ota_data_partition, sec_id * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
-        if (ret != ESP_OK) {
-            return ret;
-        } else {
-            return esp_partition_write(ota_data_partition, SPI_FLASH_SEC_SIZE * sec_id, &s_ota_select[sec_id].ota_seq, sizeof(ota_select));
-        }
+    two_otadata[sec_id].ota_seq = seq;
+    two_otadata[sec_id].crc = bootloader_common_ota_select_crc(&two_otadata[sec_id]);
+    esp_err_t ret = esp_partition_erase_range(ota_data_partition, sec_id * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
+    if (ret != ESP_OK) {
+        return ret;
     } else {
-        return ESP_ERR_INVALID_ARG;
+        return esp_partition_write(ota_data_partition, SPI_FLASH_SEC_SIZE * sec_id, &two_otadata[sec_id], sizeof(esp_ota_select_entry_t));
     }
 }
 
@@ -287,119 +313,70 @@ static uint8_t get_ota_partition_count(void)
 
 static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype)
 {
-    esp_err_t ret;
-    const esp_partition_t *find_partition = NULL;
-    uint16_t ota_app_count = 0;
-    uint32_t i = 0;
-    uint32_t seq;
-    spi_flash_mmap_handle_t ota_data_map;
-    const void *result = NULL;
-
-    find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
-    if (find_partition != NULL) {
-        ota_app_count = get_ota_partition_count();
-        //esp32_idf use two sector for store information about which partition is running
-        //it defined the two sector as ota data partition,two structure ota_select is saved in the two sector
-        //named data in first sector as s_ota_select[0], second sector data as s_ota_select[1]
-        //e.g.
-        //if s_ota_select[0].ota_seq == s_ota_select[1].ota_seq == 0xFFFFFFFF,means ota info partition is in init status
-        //so it will boot factory application(if there is),if there's no factory application,it will boot ota[0] application 
-        //if s_ota_select[0].ota_seq != 0 and s_ota_select[1].ota_seq != 0,it will choose a max seq ,and get value of max_seq%max_ota_app_number
-        //and boot a subtype (mask 0x0F) value is (max_seq - 1)%max_ota_app_number,so if want switch to run ota[x],can use next formulas.
-        //for example, if s_ota_select[0].ota_seq = 4, s_ota_select[1].ota_seq = 5, and there are 8 ota application, 
-        //current running is (5-1)%8 = 4,running ota[4],so if we want to switch to run ota[7],
-        //we should add s_ota_select[0].ota_seq (is 4) to 4 ,(8-1)%8=7,then it will boot ota[7]
-        //if      A=(B - C)%D
-        //then    B=(A + C)%D + D*n ,n= (0,1,2...)
-        //so current ota app sub type id is x , dest bin subtype is y,total ota app count is n
-        //seq will add (x + n*1 + 1 - seq)%n
-        if (SUB_TYPE_ID(subtype) >= ota_app_count) {
-            return ESP_ERR_INVALID_ARG;
-        }
-
-        ret = esp_partition_mmap(find_partition, 0, find_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
-        if (ret != ESP_OK) {
-            result = NULL;
-            return ret;
-        } else {
-            memcpy(&s_ota_select[0], result, sizeof(ota_select));
-            memcpy(&s_ota_select[1], result + SPI_FLASH_SEC_SIZE, sizeof(ota_select));
-            spi_flash_munmap(ota_data_map);
-        }
-
-        if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) {
-            seq = OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq);
-            while (seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
-                i++;
-            }
-
-            if (s_ota_select[0].ota_seq >= s_ota_select[1].ota_seq) {
-                return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 1, find_partition);
-            } else {
-                return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition);
-            }
-
-        } else if (ota_select_valid(&s_ota_select[0])) {
-            while (s_ota_select[0].ota_seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
-                i++;
-            }
-            return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 1, find_partition);
+    esp_ota_select_entry_t otadata[2];
+    const esp_partition_t *otadata_partition = read_otadata(otadata);
+    if (otadata_partition == NULL) {
+        return ESP_ERR_NOT_FOUND;
+    }
 
-        } else if (ota_select_valid(&s_ota_select[1])) {
-            while (s_ota_select[1].ota_seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
-                i++;
-            }
-            return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition);
+    int ota_app_count = get_ota_partition_count();
+    if (SUB_TYPE_ID(subtype) >= ota_app_count) {
+        return ESP_ERR_INVALID_ARG;
+    }
 
-        } else {
-            /* Both OTA slots are invalid, probably because unformatted... */
-            return rewrite_ota_seq(SUB_TYPE_ID(subtype) + 1, 0, find_partition);
+    //esp32_idf use two sector for store information about which partition is running
+    //it defined the two sector as ota data partition,two structure esp_ota_select_entry_t is saved in the two sector
+    //named data in first sector as otadata[0], second sector data as otadata[1]
+    //e.g.
+    //if otadata[0].ota_seq == otadata[1].ota_seq == 0xFFFFFFFF,means ota info partition is in init status
+    //so it will boot factory application(if there is),if there's no factory application,it will boot ota[0] application
+    //if otadata[0].ota_seq != 0 and otadata[1].ota_seq != 0,it will choose a max seq ,and get value of max_seq%max_ota_app_number
+    //and boot a subtype (mask 0x0F) value is (max_seq - 1)%max_ota_app_number,so if want switch to run ota[x],can use next formulas.
+    //for example, if otadata[0].ota_seq = 4, otadata[1].ota_seq = 5, and there are 8 ota application,
+    //current running is (5-1)%8 = 4,running ota[4],so if we want to switch to run ota[7],
+    //we should add otadata[0].ota_seq (is 4) to 4 ,(8-1)%8=7,then it will boot ota[7]
+    //if      A=(B - C)%D
+    //then    B=(A + C)%D + D*n ,n= (0,1,2...)
+    //so current ota app sub type id is x , dest bin subtype is y,total ota app count is n
+    //seq will add (x + n*1 + 1 - seq)%n
+
+    int active_otadata = bootloader_common_get_active_otadata(otadata);
+    if (active_otadata != -1) {
+        uint32_t seq = otadata[active_otadata].ota_seq;
+        uint32_t i = 0;
+        while (seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
+            i++;
         }
-
+        int next_otadata = (~active_otadata)&1; // if 0 -> will be next 1. and if 1 -> will be next 0.
+        return rewrite_ota_seq(otadata, (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, next_otadata, otadata_partition);
     } else {
-        return ESP_ERR_NOT_FOUND;
+        /* Both OTA slots are invalid, probably because unformatted... */
+        int next_otadata = 0;
+        return rewrite_ota_seq(otadata, SUB_TYPE_ID(subtype) + 1, next_otadata, otadata_partition);
     }
 }
 
 esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)
 {
-    const esp_partition_t *find_partition = NULL;
     if (partition == NULL) {
         return ESP_ERR_INVALID_ARG;
     }
 
-    esp_image_metadata_t data;
-    const esp_partition_pos_t part_pos = {
-        .offset = partition->address,
-        .size = partition->size,
-    };
-    if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
+    if (image_validate(partition, ESP_IMAGE_VERIFY) != ESP_OK) {
         return ESP_ERR_OTA_VALIDATE_FAILED;
     }
 
-#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
-    esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len);
-    if (ret != ESP_OK) {
-        return ESP_ERR_OTA_VALIDATE_FAILED;
-    }
-#endif
     // if set boot partition to factory bin ,just format ota info partition
     if (partition->type == ESP_PARTITION_TYPE_APP) {
         if (partition->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY) {
-            find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
+            const esp_partition_t *find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
             if (find_partition != NULL) {
                 return esp_partition_erase_range(find_partition, 0, find_partition->size);
             } else {
                 return ESP_ERR_NOT_FOUND;
             }
         } else {
-            // try to find this partition in flash,if not find it ,return error
-            find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
-            if (find_partition != NULL) {
-                return esp_rewrite_ota_data(partition->subtype);
-            } else {
-                return ESP_ERR_NOT_FOUND;
-            }
+            return esp_rewrite_ota_data(partition->subtype);
         }
     } else {
         return ESP_ERR_INVALID_ARG;
@@ -436,58 +413,30 @@ static const esp_partition_t *find_default_boot_partition(void)
 
 const esp_partition_t *esp_ota_get_boot_partition(void)
 {
-    esp_err_t ret;
-    const esp_partition_t *find_partition = NULL;
-    spi_flash_mmap_handle_t ota_data_map;
-    const void *result = NULL;
-    uint16_t ota_app_count = 0;
-    find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
-
-    if (find_partition == NULL) {
-        ESP_LOGE(TAG, "not found ota data");
-        return NULL;
-    }
-
-    ret = esp_partition_mmap(find_partition, 0, find_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
-    if (ret != ESP_OK) {
-        spi_flash_munmap(ota_data_map);
-        ESP_LOGE(TAG, "mmap ota data filed");
+    esp_ota_select_entry_t otadata[2];
+    const esp_partition_t *otadata_partition = read_otadata(otadata);
+    if (otadata_partition == NULL) {
         return NULL;
-    } else {
-        memcpy(&s_ota_select[0], result, sizeof(ota_select));
-        memcpy(&s_ota_select[1], result + 0x1000, sizeof(ota_select));
-        spi_flash_munmap(ota_data_map);
     }
-    ota_app_count = get_ota_partition_count();
 
+    int ota_app_count = get_ota_partition_count();
     ESP_LOGD(TAG, "found ota app max = %d", ota_app_count);
 
-    if (s_ota_select[0].ota_seq == 0xFFFFFFFF && s_ota_select[1].ota_seq == 0xFFFFFFFF) {
-        ESP_LOGD(TAG, "finding factory app......");
+    if ((bootloader_common_ota_select_invalid(&otadata[0]) &&
+         bootloader_common_ota_select_invalid(&otadata[1])) ||
+         ota_app_count == 0) {
+        ESP_LOGD(TAG, "finding factory app...");
         return find_default_boot_partition();
-    } else if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) {
-        ESP_LOGD(TAG, "finding ota_%d app......", \
-                 ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count));
-
-        return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
-                                        ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count), NULL);
-    } else if (ota_select_valid(&s_ota_select[0])) {
-        ESP_LOGD(TAG, "finding ota_%d app......", \
-                 ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count);
-
-        return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
-                                        ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count, NULL);
-
-    } else if (ota_select_valid(&s_ota_select[1])) {
-        ESP_LOGD(TAG, "finding ota_%d app......", \
-                 ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count);
-
-        return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
-                                        ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count, NULL);
-
     } else {
-        ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory");
-        return find_default_boot_partition();
+        int active_otadata = bootloader_common_get_active_otadata(otadata);
+        if (active_otadata != -1) {
+            int ota_slot = (otadata[active_otadata].ota_seq - 1) % ota_app_count; // Actual OTA partition selection
+            ESP_LOGD(TAG, "finding ota_%d app...", ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot);
+            return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot, NULL);
+        } else {
+            ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory");
+            return find_default_boot_partition();
+        }
     }
 }
 
index d15d902ec09cd3c4207cf97bdd561ddad3852455..f57b4b8a9af53c984dfdbb8ae1558c64e5c179dc 100644 (file)
@@ -24,21 +24,29 @@ typedef enum {
 } esp_comm_gpio_hold_t;
 
 /**
- * @brief Calculate crc for the OTA data partition.
+ * @brief Calculate crc for the OTA data select.
  *
- * @param[in] ota_data The OTA data partition.
+ * @param[in] s The OTA data select.
  * @return    Returns crc value.
  */
 uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s);
 
 /**
- * @brief Verifies the validity of the OTA data partition
+ * @brief Verifies the validity of the OTA data select
  *
- * @param[in] ota_data The OTA data partition.
+ * @param[in] s The OTA data select.
  * @return    Returns true on valid, false otherwise.
  */
 bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s);
 
+/**
+ * @brief Returns true if OTADATA is not marked as bootable partition.
+ *
+ * @param[in] s The OTA data select.
+ * @return    Returns true if OTADATA invalid, false otherwise.
+ */
+bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s);
+
 /**
  * @brief Check if the GPIO input is a long hold or a short hold.
  *
@@ -93,6 +101,16 @@ bool bootloader_common_label_search(const char *list, char *label);
  */
 esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256);
 
+/**
+ * @brief Returns the number of active otadata.
+ *
+ * @param[in] two_otadata Pointer on array from two otadata structures.
+ *
+ * @return The number of active otadata (0 or 1).
+ *        - -1: If it does not have active otadata.
+ */
+int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata);
+
 /**
  * @brief Returns esp_app_desc structure for app partition. This structure includes app version.
  * 
index c4feb32b7da665e2088fc2dbd0b1b26e45f5ef19..75b4a31b9b0dd1f356eefc85f4f11fa9e64722a8 100644 (file)
@@ -29,6 +29,7 @@
 #include "soc/gpio_periph.h"
 #include "esp_image_format.h"
 #include "bootloader_sha.h"
+#include "sys/param.h"
 
 #define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
 
@@ -39,9 +40,14 @@ uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s)
     return crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
 }
 
+bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s)
+{
+    return s->ota_seq == UINT32_MAX;
+}
+
 bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s)
 {
-    return s->ota_seq != UINT32_MAX && s->crc == bootloader_common_ota_select_crc(s);
+    return bootloader_common_ota_select_invalid(s) == false && s->crc == bootloader_common_ota_select_crc(s);
 }
 
 esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio(uint32_t num_pin, uint32_t delay_sec)
@@ -193,6 +199,32 @@ esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t
     return ESP_OK;
 }
 
+int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata)
+{
+    int active_otadata = -1;
+
+    bool valid_otadata[2];
+    valid_otadata[0] = bootloader_common_ota_select_valid(&two_otadata[0]);
+    valid_otadata[1] = bootloader_common_ota_select_valid(&two_otadata[1]);
+    if (valid_otadata[0] && valid_otadata[1]) {
+        if (MAX(two_otadata[0].ota_seq, two_otadata[1].ota_seq) == two_otadata[0].ota_seq) {
+            active_otadata = 0;
+        } else {
+            active_otadata = 1;
+        }
+        ESP_LOGD(TAG, "Both OTA copies are valid");
+    } else {
+        for (int i = 0; i < 2; ++i) {
+            if (valid_otadata[i]) {
+                active_otadata = i;
+                ESP_LOGD(TAG, "Only otadata[%d] is valid", i);
+                break;
+            }
+        }
+    }
+    return active_otadata;
+}
+
 esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc)
 {
     if (partition == NULL || app_desc == NULL || partition->offset == 0) {
index 644496c5b51ef6504c9ef879e6ea7139a99fd27d..06b01f8a467850699fe70ccd90664b5dac609748 100644 (file)
@@ -67,6 +67,34 @@ static void set_cache_and_start_app(uint32_t drom_addr,
     uint32_t irom_size,
     uint32_t entry_addr);
 
+// Read ota_info partition and fill array from two otadata structures.
+static esp_err_t read_otadata(const esp_partition_pos_t *ota_info, esp_ota_select_entry_t *two_otadata)
+{
+    const esp_ota_select_entry_t *ota_select_map;
+    if (ota_info->offset == 0) {
+        return ESP_ERR_NOT_FOUND;
+    }
+
+    // partition table has OTA data partition
+    if (ota_info->size < 2 * SPI_SEC_SIZE) {
+        ESP_LOGE(TAG, "ota_info partition size %d is too small (minimum %d bytes)", ota_info->size, sizeof(esp_ota_select_entry_t));
+        return ESP_FAIL; // can't proceed
+    }
+
+    ESP_LOGD(TAG, "OTA data offset 0x%x", ota_info->offset);
+    ota_select_map = bootloader_mmap(ota_info->offset, ota_info->size);
+    if (!ota_select_map) {
+        ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ota_info->offset, ota_info->size);
+        return ESP_FAIL; // can't proceed
+    }
+
+    memcpy(&two_otadata[0], ota_select_map, sizeof(esp_ota_select_entry_t));
+    memcpy(&two_otadata[1], (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
+    bootloader_munmap(ota_select_map);
+
+    return ESP_OK;
+}
+
 bool bootloader_utility_load_partition_table(bootloader_state_t* bs)
 {
     const esp_partition_info_t *partitions;
@@ -194,71 +222,48 @@ static void log_invalid_app_partition(int index)
 
 int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs)
 {
-    esp_ota_select_entry_t sa,sb;
-    const esp_ota_select_entry_t *ota_select_map;
+    esp_ota_select_entry_t otadata[2];
+    int boot_index = FACTORY_INDEX;
 
-    if (bs->ota_info.offset != 0) {
-        // partition table has OTA data partition
-        if (bs->ota_info.size < 2 * SPI_SEC_SIZE) {
-            ESP_LOGE(TAG, "ota_info partition size %d is too small (minimum %d bytes)", bs->ota_info.size, sizeof(esp_ota_select_entry_t));
-            return INVALID_INDEX; // can't proceed
-        }
+    if (bs->ota_info.offset == 0) {
+        return FACTORY_INDEX;
+    }
 
-        ESP_LOGD(TAG, "OTA data offset 0x%x", bs->ota_info.offset);
-        ota_select_map = bootloader_mmap(bs->ota_info.offset, bs->ota_info.size);
-        if (!ota_select_map) {
-            ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs->ota_info.offset, bs->ota_info.size);
-            return INVALID_INDEX; // can't proceed
-        }
-        memcpy(&sa, ota_select_map, sizeof(esp_ota_select_entry_t));
-        memcpy(&sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
-        bootloader_munmap(ota_select_map);
-
-        ESP_LOGD(TAG, "OTA sequence values A 0x%08x B 0x%08x", sa.ota_seq, sb.ota_seq);
-        if ((sa.ota_seq == UINT32_MAX && sb.ota_seq == UINT32_MAX) || (bs->app_count == 0)) {
-            ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF) or partition table does not have bootable ota_apps (app_count=%d)", bs->app_count);
-            if (bs->factory.offset != 0) {
-                ESP_LOGI(TAG, "Defaulting to factory image");
-                return FACTORY_INDEX;
-            } else {
-                ESP_LOGI(TAG, "No factory image, trying OTA 0");
-                return 0;
-            }
-        } else  {
-            bool ota_valid = false;
-            const char *ota_msg;
-            int ota_seq; // Raw OTA sequence number. May be more than # of OTA slots
-            if(bootloader_common_ota_select_valid(&sa) && bootloader_common_ota_select_valid(&sb)) {
-                ota_valid = true;
-                ota_msg = "Both OTA values";
-                ota_seq = MAX(sa.ota_seq, sb.ota_seq) - 1;
-            } else if(bootloader_common_ota_select_valid(&sa)) {
-                ota_valid = true;
-                ota_msg = "Only OTA sequence A is";
-                ota_seq = sa.ota_seq - 1;
-            } else if(bootloader_common_ota_select_valid(&sb)) {
-                ota_valid = true;
-                ota_msg = "Only OTA sequence B is";
-                ota_seq = sb.ota_seq - 1;
-            }
+    if (read_otadata(&bs->ota_info, otadata) != ESP_OK) {
+        return INVALID_INDEX;
+    }
 
-            if (ota_valid) {
-                int ota_slot = ota_seq % bs->app_count; // Actual OTA partition selection
-                ESP_LOGD(TAG, "%s valid. Mapping seq %d -> OTA slot %d", ota_msg, ota_seq, ota_slot);
-                return ota_slot;
-            } else if (bs->factory.offset != 0) {
-                ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
-                return FACTORY_INDEX;
-            } else {
-                ESP_LOGE(TAG, "ota data partition invalid and no factory, will try all partitions");
-                return FACTORY_INDEX;
-            }
+    ESP_LOGD(TAG, "otadata[0]: sequence values 0x%08x", otadata[0].ota_seq);
+    ESP_LOGD(TAG, "otadata[1]: sequence values 0x%08x", otadata[1].ota_seq);
+
+    if ((bootloader_common_ota_select_invalid(&otadata[0]) &&
+         bootloader_common_ota_select_invalid(&otadata[1])) ||
+         bs->app_count == 0) {
+        ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF) or partition table does not have bootable ota_apps (app_count=%d)", bs->app_count);
+        if (bs->factory.offset != 0) {
+            ESP_LOGI(TAG, "Defaulting to factory image");
+            boot_index = FACTORY_INDEX;
+        } else {
+            ESP_LOGI(TAG, "No factory image, trying OTA 0");
+            boot_index = 0;
+        }
+    } else {
+        int active_otadata = bootloader_common_get_active_otadata(otadata);
+        if (active_otadata != -1) {
+            ESP_LOGD(TAG, "Active OTADATA copy is #%d", active_otadata);
+            uint32_t ota_seq = otadata[active_otadata].ota_seq - 1; // Raw OTA sequence number. May be more than # of OTA slots
+            boot_index = ota_seq % bs->app_count; // Actual OTA partition selection
+            ESP_LOGD(TAG, "Mapping seq %d -> OTA slot %d", ota_seq, boot_index);
+        } else if (bs->factory.offset != 0) {
+            ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
+            boot_index = FACTORY_INDEX;
+        } else {
+            ESP_LOGE(TAG, "ota data partition invalid and no factory, will try all partitions");
+            boot_index = FACTORY_INDEX;
         }
     }
 
-    // otherwise, start from factory app partition and let the search logic
-    // proceed from there
-    return FACTORY_INDEX;
+    return boot_index;
 }
 
 /* Return true if a partition has a valid app image that was successfully loaded */