bootutil: initial implementation of swap status partition
Signed-off-by: Bohdan Kovalchuk <bohd@cypress.com>
Signed-off-by: Roman Okhrimenko <roman.okhrimenko@cypress.com>
Signed-off-by: Taras Boretskyy <taras.boretskyy@cypress.com>
Signed-off-by: Kostiantyn Tkachov <kotk@cypress.com>
Signed-off-by: dmiv <dmiv@cypress.com>
diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c
index 57ceff4..905bcf6 100644
--- a/boot/bootutil/src/bootutil_misc.c
+++ b/boot/bootutil/src/bootutil_misc.c
@@ -41,6 +41,12 @@
#include "bootutil/enc_key.h"
#endif
+#ifdef MCUBOOT_SWAP_USING_STATUS
+#include "swap_status.h"
+#endif
+
+#include "mcuboot_config/mcuboot_config.h"
+
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
/* Currently only used by imgmgr */
@@ -150,6 +156,8 @@
}
#endif
+#ifndef MCUBOOT_SWAP_USING_STATUS
+
static int
boot_magic_decode(const uint32_t *magic)
{
@@ -167,7 +175,7 @@
}
return BOOT_FLAG_SET;
}
-
+#endif /* not defined MCUBOOT_SWAP_USING_STATUS */
/**
* Determines if a status source table is satisfied by the specified magic
* code.
@@ -234,6 +242,7 @@
return -1;
}
+#ifndef MCUBOOT_SWAP_USING_STATUS
uint32_t
boot_status_off(const struct flash_area *fap)
{
@@ -247,6 +256,7 @@
assert(off_from_end <= fap->fa_size);
return fap->fa_size - off_from_end;
}
+#endif
static inline uint32_t
boot_magic_off(const struct flash_area *fap)
@@ -254,6 +264,8 @@
return fap->fa_size - BOOT_MAGIC_SZ;
}
+#ifndef MCUBOOT_SWAP_USING_STATUS
+
static inline uint32_t
boot_image_ok_off(const struct flash_area *fap)
{
@@ -277,6 +289,7 @@
{
return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
}
+#endif
#ifdef MCUBOOT_ENC_IMAGES
static inline uint32_t
@@ -312,6 +325,7 @@
return true;
}
+#ifndef MCUBOOT_SWAP_USING_STATUS
int
boot_read_swap_state(const struct flash_area *fap,
struct boot_swap_state *state)
@@ -374,6 +388,7 @@
return 0;
}
+#endif /* not MCUBOOT_SWAP_USING_STATUS */
/**
* Reads the image trailer from the scratch area.
@@ -394,6 +409,8 @@
return rc;
}
+#ifndef MCUBOOT_SWAP_USING_STATUS
+
/**
* This functions tries to locate the status area after an aborted swap,
* by looking for the magic in the possible locations.
@@ -466,6 +483,8 @@
return rc;
}
+#endif /* not MCUBOOT_SWAP_USING_STATUS */
+
#ifdef MCUBOOT_ENC_IMAGES
int
boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
@@ -503,6 +522,7 @@
}
#endif
+#ifndef MCUBOOT_SWAP_USING_STATUS
int
boot_write_magic(const struct flash_area *fap)
{
@@ -555,6 +575,8 @@
return 0;
}
+#endif /* MCUBOOT_SWAP_USING_STATUS */
+
static int
boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
uint8_t flag_val)
@@ -645,6 +667,17 @@
}
#endif
+#define BOOT_LOG_SWAP_STATE(area, state) \
+ BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
+ "image_ok=0x%x", \
+ (area), \
+ ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
+ (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
+ "bad"), \
+ (state)->swap_type, \
+ (state)->copy_done, \
+ (state)->image_ok)
+
int
boot_swap_type_multi(int image_index)
{
@@ -662,6 +695,9 @@
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
&secondary_slot);
+
+ BOOT_LOG_SWAP_STATE("boot_swap_type_multi: Primary image", &primary_slot);
+ BOOT_LOG_SWAP_STATE("boot_swap_type_multi: Secondary image", &secondary_slot);
if (rc) {
return BOOT_SWAP_TYPE_PANIC;
}
diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h
index 3f40861..a2ed15b 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -73,14 +73,16 @@
#if (defined(MCUBOOT_OVERWRITE_ONLY) + \
defined(MCUBOOT_SWAP_USING_MOVE) + \
defined(MCUBOOT_DIRECT_XIP) + \
- defined(MCUBOOT_RAM_LOAD)) > 1
-#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD"
+ defined(MCUBOOT_RAM_LOAD)) + \
+ defined(MCUBOOT_SWAP_USING_STATUS) > 1
+#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD or MCUBOOT_SWAP_USING_STATUS"
#endif
#if !defined(MCUBOOT_OVERWRITE_ONLY) && \
!defined(MCUBOOT_SWAP_USING_MOVE) && \
!defined(MCUBOOT_DIRECT_XIP) && \
- !defined(MCUBOOT_RAM_LOAD)
+ !defined(MCUBOOT_RAM_LOAD) && \
+ !defined(MCUBOOT_SWAP_USING_STATUS)
#define MCUBOOT_SWAP_USING_SCRATCH 1
#endif
@@ -271,6 +273,12 @@
boot_sector_t *sectors;
size_t num_sectors;
} scratch;
+#elif MCUBOOT_SWAP_USING_STATUS
+ struct {
+ const struct flash_area *area;
+ boot_sector_t *sectors;
+ size_t num_sectors;
+ } status;
#endif
uint8_t swap_type[BOOT_IMAGE_NUMBER];
@@ -319,6 +327,13 @@
int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz);
bool boot_status_is_reset(const struct boot_status *bs);
+#ifdef MCUBOOT_SWAP_USING_STATUS
+uint32_t boot_copy_done_off(const struct flash_area *fap);
+uint32_t boot_image_ok_off(const struct flash_area *fap);
+uint32_t boot_swap_size_off(const struct flash_area *fap);
+#endif
+
+
#ifdef MCUBOOT_ENC_IMAGES
int boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
const struct boot_status *bs);
diff --git a/boot/bootutil/src/crc32c.c b/boot/bootutil/src/crc32c.c
new file mode 100644
index 0000000..d298a1f
--- /dev/null
+++ b/boot/bootutil/src/crc32c.c
@@ -0,0 +1,73 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2020 Cypress Semiconductors
+ *
+ * Original license:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "crc32c.h"
+
+#define NIBBLE_POS (4u)
+#define NIBBLE_MSK (0xFu)
+#define CRC_TABLE_SIZE (16u) /* A number of uint32_t elements in the CRC32 table */
+#define CRC_INIT (0xFFFFFFFFu)
+
+
+/*******************************************************************************
+* Function Name: crc32c_checksum
+****************************************************************************//**
+*
+* This function computes a CRC-32C for the provided number of bytes contained
+* in the provided buffer.
+*
+* \param address The pointer to a buffer containing the data to compute
+* the checksum for.
+* \param length The number of bytes in the buffer to compute the checksum
+* for.
+*
+* \return CRC-32C for the provided data.
+*
+*******************************************************************************/
+uint32_t crc32c_checksum(const uint8_t *address, uint32_t length)
+{
+ /* Contains generated values to calculate CRC-32C by 4 bits per iteration*/
+ static const uint32_t crcTable[CRC_TABLE_SIZE] =
+ {
+ 0x00000000u, 0x105ec76fu, 0x20bd8edeu, 0x30e349b1u,
+ 0x417b1dbcu, 0x5125dad3u, 0x61c69362u, 0x7198540du,
+ 0x82f63b78u, 0x92a8fc17u, 0xa24bb5a6u, 0xb21572c9u,
+ 0xc38d26c4u, 0xd3d3e1abu, 0xe330a81au, 0xf36e6f75u,
+ };
+
+ uint32_t crc = CRC_INIT;
+ if (length != 0u)
+ {
+ do
+ {
+ crc = crc ^ *address;
+ crc = (crc >> NIBBLE_POS) ^ crcTable[crc & NIBBLE_MSK];
+ crc = (crc >> NIBBLE_POS) ^ crcTable[crc & NIBBLE_MSK];
+ --length;
+ ++address;
+ } while (length != 0u);
+ }
+ return (~crc);
+}
diff --git a/boot/bootutil/src/crc32c.h b/boot/bootutil/src/crc32c.h
new file mode 100644
index 0000000..56bf6dc
--- /dev/null
+++ b/boot/bootutil/src/crc32c.h
@@ -0,0 +1,28 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2020 Cypress Semiconductors
+ *
+ * Original license:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stdint.h>
+
+uint32_t crc32c_checksum(const uint8_t *address, uint32_t length);
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index b81a7ce..f1168b9 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -240,6 +240,10 @@
} else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
out_sectors = state->scratch.sectors;
out_num_sectors = &state->scratch.num_sectors;
+#elif MCUBOOT_SWAP_USING_STATUS
+ } else if (flash_area == FLASH_AREA_IMAGE_SWAP_STATUS) {
+ out_sectors = state->status.sectors;
+ out_num_sectors = &state->status.num_sectors;
#endif
} else {
return BOOT_EFLASH;
@@ -278,6 +282,13 @@
return BOOT_EFLASH;
}
+#if MCUBOOT_SWAP_USING_STATUS
+ rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SWAP_STATUS);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+#endif
+
#if MCUBOOT_SWAP_USING_SCRATCH
rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
if (rc != 0) {
@@ -318,6 +329,8 @@
bs->state == BOOT_STATUS_STATE_0);
}
+#ifndef MCUBOOT_SWAP_USING_STATUS
+
/**
* Writes the supplied boot status to the flash file system. The boot status
* contains the current state of an in-progress image copy operation.
@@ -383,6 +396,8 @@
#endif /* !MCUBOOT_RAM_LOAD */
#endif /* !MCUBOOT_DIRECT_XIP */
+#endif /* MCUBOOT_SWAP_USING_STATUS */
+
/*
* Validate image hash/signature and optionally the security counter in a slot.
*/
@@ -1686,6 +1701,9 @@
#if MCUBOOT_SWAP_USING_SCRATCH
TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
#endif
+#if MCUBOOT_SWAP_USING_STATUS
+ TARGET_STATIC boot_sector_t status_sectors[BOOT_MAX_IMG_SECTORS];
+#endif
memset(state, 0, sizeof(struct boot_loader_state));
has_upgrade = false;
@@ -1717,6 +1735,9 @@
#if MCUBOOT_SWAP_USING_SCRATCH
state->scratch.sectors = scratch_sectors;
#endif
+#if MCUBOOT_SWAP_USING_STATUS
+ state->status.sectors = status_sectors;
+#endif
/* Open primary and secondary image areas for the duration
* of this call.
diff --git a/boot/bootutil/src/swap_misc.c b/boot/bootutil/src/swap_misc.c
index 940d646..99c46b2 100644
--- a/boot/bootutil/src/swap_misc.c
+++ b/boot/bootutil/src/swap_misc.c
@@ -182,6 +182,10 @@
return rc;
}
+#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
+
+#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || \
+ defined(MCUBOOT_SWAP_USING_STATUS)
int
swap_set_copy_done(uint8_t image_index)
@@ -229,4 +233,4 @@
}
-#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
+#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_STATUS) */
diff --git a/boot/bootutil/src/swap_priv.h b/boot/bootutil/src/swap_priv.h
index 9cf5777..8036174 100644
--- a/boot/bootutil/src/swap_priv.h
+++ b/boot/bootutil/src/swap_priv.h
@@ -21,7 +21,8 @@
#include "mcuboot_config/mcuboot_config.h"
-#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
+#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || \
+ defined(MCUBOOT_SWAP_USING_STATUS)
/**
* Calculates the amount of space required to store the trailer, and erases
diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c
index 55fa61f..c19b97d 100644
--- a/boot/bootutil/src/swap_scratch.c
+++ b/boot/bootutil/src/swap_scratch.c
@@ -30,7 +30,7 @@
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
-#if !defined(MCUBOOT_SWAP_USING_MOVE)
+#if (!defined(MCUBOOT_SWAP_USING_MOVE) && !defined(MCUBOOT_SWAP_USING_STATUS))
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/*
@@ -399,7 +399,7 @@
source = table->bst_status_source;
#if (BOOT_IMAGE_NUMBER > 1)
- /* In case of multi-image boot it can happen that if boot status
+ /* In case of multi image boot it can happen that if boot status
* info is found on scratch area then it does not belong to the
* currently examined image.
*/
diff --git a/boot/bootutil/src/swap_status.c b/boot/bootutil/src/swap_status.c
new file mode 100644
index 0000000..37e1b19
--- /dev/null
+++ b/boot/bootutil/src/swap_status.c
@@ -0,0 +1,503 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2017-2019 Linaro LTD
+ * Copyright (c) 2016-2019 JUUL Labs
+ * Copyright (c) 2019-2020 Arm Limited
+ * Copyright (c) 2020 Cypress Semiconductors
+ *
+ * Original license:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bootutil/bootutil.h"
+#include "bootutil_priv.h"
+#include "swap_priv.h"
+#include "swap_status.h"
+#include "bootutil/bootutil_log.h"
+
+#include "mcuboot_config/mcuboot_config.h"
+
+MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
+
+#ifdef MCUBOOT_SWAP_USING_STATUS
+
+#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
+/*
+ * FIXME: this might have to be updated for threaded sim
+ */
+int boot_status_fails = 0;
+#define BOOT_STATUS_ASSERT(x) \
+ do { \
+ if (!(x)) { \
+ boot_status_fails++; \
+ } \
+ } while (0)
+#else
+#define BOOT_STATUS_ASSERT(x) ASSERT(x)
+#endif
+
+static uint32_t g_last_idx = UINT32_MAX;
+
+int
+boot_read_image_header(struct boot_loader_state *state, int slot,
+ struct image_header *out_hdr, struct boot_status *bs)
+{
+ const struct flash_area *fap;
+ uint32_t off;
+ uint32_t sz;
+ int area_id;
+ int rc = 0;
+
+ off = 0;
+ if (bs) {
+ sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
+ if (bs->op == BOOT_STATUS_OP_MOVE) {
+ if (slot == 0 && bs->idx > g_last_idx) {
+ /* second sector */
+ off = sz;
+ }
+ } else if (bs->op == BOOT_STATUS_OP_SWAP) {
+ if (bs->idx > 1 && bs->idx <= g_last_idx) {
+ if (slot == 0) {
+ slot = 1;
+ } else {
+ slot = 0;
+ }
+ } else if (bs->idx == 1) {
+ if (slot == 0) {
+ off = sz;
+ }
+ if (slot == 1 && bs->state == 2) {
+ slot = 0;
+ }
+ }
+ }
+ }
+
+ area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
+ rc = flash_area_open(area_id, &fap);
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+
+ rc = flash_area_read(fap, off, out_hdr, sizeof *out_hdr);
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+
+ /* We only know where the headers are located when bs is valid */
+ if (bs != NULL && out_hdr->ih_magic != IMAGE_MAGIC) {
+ rc = -1;
+ goto done;
+ }
+
+ rc = 0;
+
+done:
+ flash_area_close(fap);
+ return rc;
+}
+
+int
+swap_read_status_bytes(const struct flash_area *fap,
+ struct boot_loader_state *state, struct boot_status *bs)
+{
+ uint32_t off;
+ uint8_t status;
+ uint8_t last_status_move;
+ uint8_t last_status_swap;
+ int max_entries;
+ int found_idx_move;
+ int found_idx_swap;
+ int move_entries;
+ int rc;
+ int last_rc;
+ int erased_sections;
+ int i;
+ int image_index;
+ (void)state;
+
+ if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
+ max_entries = BOOT_STATUS_MAX_ENTRIES;
+ } else {
+ return BOOT_EBADARGS;
+ }
+
+ erased_sections = 0;
+ found_idx_move = -1;
+ /* skip erased sectors at the end */
+ last_rc = 1;
+ off = boot_status_off(fap);
+
+ for (i = max_entries; i > 0; i--) {
+ rc = swap_status_retrieve(fap->fa_id, off + (i - 1), &status, 1);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+
+ if(status == BOOT_STATUS_STATE_0 || status == BOOT_STATUS_STATE_1) {
+ found_idx_swap = i - BOOT_STATUS_IDX_0;
+ last_status_swap = status;
+ }
+
+ if (status != flash_area_erased_val(fap)) {
+ if (found_idx_move == -1) {
+ found_idx_move = i;
+ last_status_move = status;
+ }
+ }
+ else {
+ if (rc != last_rc) {
+ erased_sections++;
+ }
+ }
+ last_rc = rc;
+ }
+
+ if (erased_sections > 1) {
+ /* This means there was an error writing status on the last
+ * swap. Tell user and move on to validation!
+ */
+#if !defined(__BOOTSIM__)
+ BOOT_LOG_ERR("Detected inconsistent status!");
+#endif
+
+#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
+ /* With validation of the primary slot disabled, there is no way
+ * to be sure the swapped primary slot is OK, so abort!
+ */
+ assert(0);
+#endif
+ }
+
+ image_index = BOOT_CURR_IMG(state);
+ rc = boot_read_swap_size(image_index, &bs->swap_size);
+ assert(rc == 0);
+ /* get image size in blocks */
+ move_entries = bs->swap_size / state->write_sz + (bs->swap_size % state->write_sz != 0);
+
+ if (found_idx_move == -1) {
+ /* no swap status found; nothing to do */
+ } else if (found_idx_move < move_entries) {
+ /* continue move sector up operation */
+ bs->op = BOOT_STATUS_OP_MOVE;
+ bs->idx = found_idx_move;
+ bs->state = last_status_move;
+ } else {
+ /* resume swap sectors operation */
+ bs->op = BOOT_STATUS_OP_SWAP;
+ bs->idx = found_idx_swap;
+ bs->state = last_status_swap;
+ }
+
+ return 0;
+}
+
+/* this is internal offset in swap status area */
+uint32_t
+boot_status_internal_off(const struct boot_status *bs, int elem_sz)
+{
+ uint32_t off;
+ int idx_sz;
+
+ idx_sz = elem_sz;
+
+ off = bs->idx * idx_sz;
+
+ return off;
+}
+
+int
+boot_slots_compatible(struct boot_loader_state *state)
+{
+ size_t num_sectors_pri;
+ size_t num_sectors_sec;
+ size_t sector_sz_pri = 0;
+ size_t sector_sz_sec = 0;
+ size_t i;
+
+ num_sectors_pri = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
+ num_sectors_sec = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
+ if ((num_sectors_pri != num_sectors_sec) &&
+ (num_sectors_pri != (num_sectors_sec + 1))) {
+ BOOT_LOG_WRN("Cannot upgrade: not a compatible amount of sectors");
+ return 0;
+ }
+
+ if (num_sectors_pri > BOOT_MAX_IMG_SECTORS) {
+ BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
+ return 0;
+ }
+
+ for (i = 0; i < num_sectors_sec; i++) {
+ sector_sz_pri = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
+ sector_sz_sec = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, i);
+ if (sector_sz_pri != sector_sz_sec) {
+ BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
+ return 0;
+ }
+ }
+
+ if (num_sectors_pri > num_sectors_sec) {
+ if (sector_sz_pri != boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i)) {
+ BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+#define BOOT_LOG_SWAP_STATE(area, state) \
+ BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
+ "image_ok=0x%x", \
+ (area), \
+ ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
+ (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
+ "bad"), \
+ (state)->swap_type, \
+ (state)->copy_done, \
+ (state)->image_ok)
+
+int
+swap_status_source(struct boot_loader_state *state)
+{
+ struct boot_swap_state state_primary_slot;
+ int rc;
+ uint8_t source;
+ uint8_t image_index;
+
+#if (BOOT_IMAGE_NUMBER == 1)
+ (void)state;
+#endif
+
+ image_index = BOOT_CURR_IMG(state);
+
+ rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
+ &state_primary_slot);
+ assert(rc == 0);
+
+ BOOT_LOG_SWAP_STATE("swap_status_source: Primary image", &state_primary_slot);
+
+ if (state_primary_slot.magic == BOOT_MAGIC_GOOD &&
+ state_primary_slot.copy_done == BOOT_FLAG_UNSET) {
+
+ source = BOOT_STATUS_SOURCE_PRIMARY_SLOT;
+
+ BOOT_LOG_INF("Boot source: primary slot");
+ return source;
+ }
+
+ BOOT_LOG_INF("Boot source: none");
+ return BOOT_STATUS_SOURCE_NONE;
+}
+
+/*
+ * "Moves" the sector located at idx - 1 to idx.
+ */
+static void
+boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
+ struct boot_status *bs, const struct flash_area *fap_pri,
+ const struct flash_area *fap_sec)
+{
+ uint32_t new_off;
+ uint32_t old_off;
+ int rc;
+
+ /* Calculate offset from start of image area. */
+ new_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
+ old_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
+
+ if (bs->idx == BOOT_STATUS_IDX_0) {
+ if (bs->source != BOOT_STATUS_SOURCE_PRIMARY_SLOT) {
+ rc = swap_erase_trailer_sectors(state, fap_pri);
+ assert(rc == 0);
+
+ rc = swap_status_init(state, fap_pri, bs);
+ assert(rc == 0);
+ }
+
+ rc = swap_erase_trailer_sectors(state, fap_sec);
+ assert(rc == 0);
+ }
+
+ rc = boot_erase_region(fap_pri, new_off, sz);
+ assert(rc == 0);
+
+ rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, sz);
+ assert(rc == 0);
+
+ rc = boot_write_status(state, bs);
+
+ bs->idx++;
+ BOOT_STATUS_ASSERT(rc == 0);
+}
+
+static void
+boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
+ struct boot_status *bs, const struct flash_area *fap_pri,
+ const struct flash_area *fap_sec)
+{
+ uint32_t pri_off;
+ uint32_t pri_up_off;
+ uint32_t sec_off;
+ int rc;
+
+ pri_up_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
+ pri_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
+ sec_off = boot_img_sector_off(state, BOOT_SECONDARY_SLOT, idx - 1);
+
+ if (bs->state == BOOT_STATUS_STATE_0) {
+ rc = boot_erase_region(fap_pri, pri_off, sz);
+ assert(rc == 0);
+
+ rc = boot_copy_region(state, fap_sec, fap_pri, sec_off, pri_off, sz);
+ assert(rc == 0);
+ rc = boot_write_status(state, bs);
+ bs->state = BOOT_STATUS_STATE_1;
+ BOOT_STATUS_ASSERT(rc == 0);
+ }
+
+ if (bs->state == BOOT_STATUS_STATE_1) {
+ rc = boot_erase_region(fap_sec, sec_off, sz);
+ assert(rc == 0);
+
+ rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, sz);
+ assert(rc == 0);
+ rc = boot_write_status(state, bs);
+ bs->idx++;
+ bs->state = BOOT_STATUS_STATE_0;
+ BOOT_STATUS_ASSERT(rc == 0);
+ }
+}
+
+/*
+ * When starting a revert the swap status exists in the primary slot, and
+ * the status in the secondary slot is erased. To start the swap, the status
+ * area in the primary slot must be re-initialized; if during the small
+ * window of time between re-initializing it and writing the first metadata
+ * a reset happens, the swap process is broken and cannot be resumed.
+ *
+ * This function handles the issue by making the revert look like a permanent
+ * upgrade (by initializing the secondary slot).
+ */
+void
+fixup_revert(const struct boot_loader_state *state, struct boot_status *bs,
+ const struct flash_area *fap_sec, uint8_t sec_id)
+{
+ struct boot_swap_state swap_state;
+ int rc;
+
+ /* No fixup required */
+ if (bs->swap_type != BOOT_SWAP_TYPE_REVERT ||
+ bs->op != BOOT_STATUS_OP_MOVE ||
+ bs->idx != BOOT_STATUS_IDX_0) {
+ return;
+ }
+
+ rc = boot_read_swap_state_by_id(sec_id, &swap_state);
+ assert(rc == 0);
+
+ BOOT_LOG_SWAP_STATE("fixup_revert: Secondary image", &swap_state);
+
+ if (swap_state.magic == BOOT_MAGIC_UNSET) {
+ rc = swap_erase_trailer_sectors(state, fap_sec);
+ assert(rc == 0);
+
+ rc = boot_write_image_ok(fap_sec);
+ assert(rc == 0);
+
+ rc = boot_write_swap_size(fap_sec, bs->swap_size);
+ assert(rc == 0);
+
+ rc = boot_write_magic(fap_sec);
+ assert(rc == 0);
+ }
+}
+
+void
+swap_run(struct boot_loader_state *state, struct boot_status *bs,
+ uint32_t copy_size)
+{
+ uint32_t sz;
+ uint32_t sector_sz;
+ uint32_t idx;
+ uint8_t image_index;
+ const struct flash_area *fap_pri;
+ const struct flash_area *fap_sec;
+ int rc;
+
+ sz = 0;
+ g_last_idx = 0;
+
+ sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
+ while (1) {
+ sz += sector_sz;
+ /* Skip to next sector because all sectors will be moved up. */
+ g_last_idx++;
+ if (sz >= copy_size) {
+ break;
+ }
+ }
+
+ image_index = BOOT_CURR_IMG(state);
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap_pri);
+ assert (rc == 0);
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec);
+ assert (rc == 0);
+
+ fixup_revert(state, bs, fap_sec, FLASH_AREA_IMAGE_SECONDARY(image_index));
+
+ if (bs->op == BOOT_STATUS_OP_MOVE) {
+ idx = g_last_idx;
+ while (idx > 0) {
+ if (idx <= (g_last_idx - bs->idx + 1)) {
+ boot_move_sector_up(idx, sector_sz, state, bs, fap_pri, fap_sec);
+ }
+ idx--;
+ }
+ bs->idx = BOOT_STATUS_IDX_0;
+ }
+
+ bs->op = BOOT_STATUS_OP_SWAP;
+
+ idx = 1;
+ while (idx <= g_last_idx) {
+ if (idx >= bs->idx) {
+ boot_swap_sectors(idx, sector_sz, state, bs, fap_pri, fap_sec);
+ }
+ idx++;
+ }
+
+ flash_area_close(fap_pri);
+ flash_area_close(fap_sec);
+}
+
+#endif /* defined(MCUBOOT_SWAP_USING_MOVE) */
diff --git a/boot/bootutil/src/swap_status.h b/boot/bootutil/src/swap_status.h
new file mode 100644
index 0000000..ec0480e
--- /dev/null
+++ b/boot/bootutil/src/swap_status.h
@@ -0,0 +1,145 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2017-2019 Linaro LTD
+ * Copyright (c) 2016-2019 JUUL Labs
+ * Copyright (c) 2019-2020 Arm Limited
+ * Copyright (c) 2020 Cypress Semiconductors
+ *
+ * Original license:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef BOOT_BOOTUTIL_SRC_SWAP_STATUS_H_
+#define BOOT_BOOTUTIL_SRC_SWAP_STATUS_H_
+
+#include <stdint.h>
+#include "sysflash/sysflash.h"
+#include "bootutil_priv.h"
+
+#include "mcuboot_config/mcuboot_config.h"
+
+#ifdef MCUBOOT_SWAP_USING_STATUS
+
+extern const uint32_t stat_part_magic[1];
+
+#define BOOT_SWAP_STATUS_MAGIC (0xDEADBEAF)
+
+#define BOOT_SWAP_STATUS_ENCK1_SZ 16UL
+#define BOOT_SWAP_STATUS_ENCK2_SZ 16UL
+
+struct image_status_trailer {
+ uint8_t enc_key1[BOOT_SWAP_STATUS_ENCK1_SZ];
+ uint8_t enc_key2[BOOT_SWAP_STATUS_ENCK2_SZ];
+ uint32_t swap_size;
+ uint8_t swap_type;
+ uint8_t copy_done;
+ uint8_t image_ok;
+ uint8_t magic[BOOT_MAGIC_SZ];
+};
+
+#define BOOT_SWAP_STATUS_SWAPSZ_SZ 4UL
+#define BOOT_SWAP_STATUS_SWAPINF_SZ 1UL
+#define BOOT_SWAP_STATUS_COPY_DONE_SZ 1UL
+#define BOOT_SWAP_STATUS_IMG_OK_SZ 1UL
+
+#define BOOT_SWAP_STATUS_MAGIC_SZ BOOT_MAGIC_SZ
+
+#define BOOT_SWAP_STATUS_MGCREC_SZ 4UL
+#define BOOT_SWAP_STATUS_CNT_SZ 4UL
+#define BOOT_SWAP_STATUS_CRC_SZ 4UL
+
+#define BOOT_SWAP_STATUS_ROW_SZ CY_FLASH_ALIGN
+
+/* agreed to name it "a record" */
+#define BOOT_SWAP_STATUS_PAYLD_SZ (BOOT_SWAP_STATUS_ROW_SZ -\
+ BOOT_SWAP_STATUS_MGCREC_SZ - \
+ BOOT_SWAP_STATUS_CNT_SZ - \
+ BOOT_SWAP_STATUS_CRC_SZ)
+#define BOOT_SWAP_STATUS_ROW_SZ_MIN 16UL
+
+/* INFO: defining record structure for better understanding */
+struct status_part_record{
+ uint8_t payload[BOOT_SWAP_STATUS_PAYLD_SZ];
+ uint8_t magic[BOOT_SWAP_STATUS_MGCREC_SZ];
+ uint8_t counter[BOOT_SWAP_STATUS_CNT_SZ];
+ uint8_t crc[BOOT_SWAP_STATUS_CRC_SZ];
+};
+
+#if (BOOT_SWAP_STATUS_ROW_SZ % BOOT_SWAP_STATUS_ROW_SZ_MIN != 0)
+ #error "BOOT_SWAP_STATUS_ROW_SZ size is less then min value of 16 bytes"
+#endif
+
+/* number of rows sector-status area should fit into */
+#define BOOT_SWAP_STATUS_SECT_ROWS_NUM (((BOOT_MAX_IMG_SECTORS-1)/BOOT_SWAP_STATUS_PAYLD_SZ)+1)
+
+/*
+ Number of flash rows used to store swap info. It consists
+ of following fields. 16 bytes is a minimum required row size,
+ thus 64 bytes required at minimum size of swap info size.
+
+ 16 bytes - uint8_t enc_key1[BOOT_SWAP_STATUS_ENCK1_SZ];
+ 16 bytes - uint8_t enc_key2[BOOT_SWAP_STATUS_ENCK2_SZ];
+ 4 bytes - uint32_t swap_size;
+ 1 byte - uint8_t swap_type;
+ 1 byte - uint8_t copy_done;
+ 1 byte - uint8_t image_ok;
+ 16 bytes - uint8_t magic[BOOT_MAGIC_SZ];
+ = 55 bytes
+ */
+#define BOOT_SWAP_STATUS_TRAILER_SIZE 64UL
+// TODO: check if min write size is 64 or larger
+// TODO: small-magic, coutner and crc aren't coutned here
+
+/* number of rows trailer data should fit into */
+#define BOOT_SWAP_STATUS_TRAIL_ROWS_NUM (((BOOT_SWAP_STATUS_TRAILER_SIZE-1)/BOOT_SWAP_STATUS_PAYLD_SZ)+1)
+
+/* the size of one copy of status area */
+#define BOOT_SWAP_STATUS_D_SIZE (BOOT_SWAP_STATUS_ROW_SZ * \
+ (BOOT_SWAP_STATUS_SECT_ROWS_NUM + \
+ BOOT_SWAP_STATUS_TRAIL_ROWS_NUM))
+
+/* the size of one copy of status area without cnt and crc fields */
+#define BOOT_SWAP_STATUS_D_SIZE_RAW (BOOT_SWAP_STATUS_PAYLD_SZ * \
+ (BOOT_SWAP_STATUS_SECT_ROWS_NUM + \
+ BOOT_SWAP_STATUS_TRAIL_ROWS_NUM))
+
+/* multiplier which defines how many blocks will be used to reduce Flash wear
+ * 1 is for single write wear, 2 - twice less wear, 3 - three times less wear, etc */
+#define BOOT_SWAP_STATUS_MULT 2
+
+#define BOOT_SWAP_STATUS_SIZE (BOOT_SWAP_STATUS_MULT * BOOT_SWAP_STATUS_D_SIZE)
+
+#define BOOT_SWAP_STATUS_SZ_PRIM BOOT_SWAP_STATUS_SIZE
+#define BOOT_SWAP_STATUS_SZ_SEC BOOT_SWAP_STATUS_SIZE
+
+#define BOOT_SWAP_STATUS_OFFS_PRIM 0UL
+#define BOOT_SWAP_STATUS_OFFS_SEC (BOOT_SWAP_STATUS_OFFS_PRIM + \
+ BOOT_SWAP_STATUS_SZ_PRIM)
+
+int32_t swap_status_init_offset(uint32_t area_id);
+int swap_status_update(uint32_t target_area_id, uint32_t offs, const void *data, uint32_t len);
+int swap_status_retrieve(uint32_t target_area_id, uint32_t offs, void *data, uint32_t len);
+
+int boot_write_trailer(const struct flash_area *fap, uint32_t off,
+ const uint8_t *inbuf, uint8_t inlen);
+
+#endif /* MCUBOOT_SWAP_USING_STATUS */
+
+#endif /* BOOT_BOOTUTIL_SRC_SWAP_STATUS_H_ */
diff --git a/boot/bootutil/src/swap_status_misc.c b/boot/bootutil/src/swap_status_misc.c
new file mode 100644
index 0000000..82917be
--- /dev/null
+++ b/boot/bootutil/src/swap_status_misc.c
@@ -0,0 +1,660 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2017-2019 Linaro LTD
+ * Copyright (c) 2016-2019 JUUL Labs
+ * Copyright (c) 2019-2020 Arm Limited
+ * Copyright (c) 2020 Cypress Semiconductors
+ *
+ * Original license:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bootutil/bootutil.h"
+#include "bootutil_priv.h"
+#include "swap_priv.h"
+#include "bootutil/bootutil_log.h"
+
+#include "swap_status.h"
+
+#include "mcuboot_config/mcuboot_config.h"
+
+MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
+
+#if defined(MCUBOOT_SWAP_USING_STATUS)
+
+#define BOOT_MAGIC_ARR_SZ \
+ (sizeof boot_img_magic / sizeof boot_img_magic[0])
+
+static int
+boot_magic_decode(const uint32_t *magic)
+{
+ if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
+ return BOOT_MAGIC_GOOD;
+ }
+ return BOOT_MAGIC_BAD;
+}
+
+static int
+boot_flag_decode(uint8_t flag)
+{
+ if (flag != BOOT_FLAG_SET) {
+ return BOOT_FLAG_BAD;
+ }
+ return BOOT_FLAG_SET;
+}
+
+static inline size_t
+boot_status_sector_size(const struct boot_loader_state *state, size_t sector)
+{
+ return state->status.sectors[sector].fs_size;
+}
+
+static inline uint32_t
+boot_status_sector_off(const struct boot_loader_state *state,
+ size_t sector)
+{
+ return state->status.sectors[sector].fs_off -
+ state->status.sectors[0].fs_off;
+}
+
+/* Offset Section */
+static inline uint32_t
+boot_magic_off(const struct flash_area *fap)
+{
+ (void)fap;
+ return BOOT_SWAP_STATUS_D_SIZE_RAW - BOOT_MAGIC_SZ;
+}
+
+uint32_t
+boot_image_ok_off(const struct flash_area *fap)
+{
+ return boot_magic_off(fap) - 1;
+}
+
+uint32_t
+boot_copy_done_off(const struct flash_area *fap)
+{
+ return boot_image_ok_off(fap) - 1;
+}
+
+uint32_t
+boot_swap_info_off(const struct flash_area *fap)
+{
+ return boot_copy_done_off(fap) - 1;
+}
+
+uint32_t
+boot_swap_size_off(const struct flash_area *fap)
+{
+ return boot_swap_info_off(fap) - 4;
+}
+
+uint32_t
+boot_status_off(const struct flash_area *fap)
+{
+ (void)fap;
+ /* this offset is equal to 0, because swap status fields
+ in this implementation count from the start of partition */
+ return 0;
+}
+
+#ifdef MCUBOOT_ENC_IMAGES
+static inline uint32_t
+boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
+{
+#if MCUBOOT_SWAP_SAVE_ENCTLV
+ /* suggest encryption key is also stored in status partition */
+ return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_TLV_SIZE);
+#else
+ return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE);
+#endif
+}
+#endif
+
+/**
+ * Write trailer data; status bytes, swap_size, etc
+ *
+ * @returns 0 on success, != 0 on error.
+ */
+int
+boot_write_trailer(const struct flash_area *fap, uint32_t off,
+ const uint8_t *inbuf, uint8_t inlen)
+{
+ int rc;
+
+ rc = swap_status_update(fap->fa_id, off, inbuf, inlen);
+
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+ return rc;
+}
+
+#ifdef MCUBOOT_ENC_IMAGES
+int
+boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
+ const struct boot_status *bs)
+{
+ uint32_t off;
+ int rc;
+
+ off = boot_enc_key_off(fap, slot);
+#if MCUBOOT_SWAP_SAVE_ENCTLV
+ rc = swap_status_update(fap->fa_id, off,
+ bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
+#else
+ rc = swap_status_update(fap->fa_id, off,
+ bs->enckey[slot], BOOT_ENC_KEY_SIZE);
+#endif
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
+ return 0;
+}
+#endif /* MCUBOOT_ENC_IMAGES */
+/* Write Section */
+int
+boot_write_magic(const struct flash_area *fap)
+{
+ uint32_t off;
+ int rc;
+
+ off = boot_magic_off(fap);
+
+ rc = swap_status_update(fap->fa_id, off,
+ boot_img_magic, BOOT_MAGIC_SZ);
+
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+ return 0;
+}
+
+int boot_status_num_sectors(const struct boot_loader_state *state)
+{
+ return (int)(BOOT_SWAP_STATUS_SIZE / boot_status_sector_size(state, 0));
+}
+
+/**
+ * Writes the supplied boot status to the flash file system. The boot status
+ * contains the current state of an in-progress image copy operation.
+ *
+ * @param bs The boot status to write.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+int
+boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
+{
+ const struct flash_area *fap;
+ uint32_t off;
+ int area_id;
+ int rc;
+ (void)state;
+
+ /* NOTE: The first sector copied (that is the last sector on slot) contains
+ * the trailer. Since in the last step the primary slot is erased, the
+ * first two status writes go to the scratch which will be copied to
+ * the primary slot!
+ */
+
+#if MCUBOOT_SWAP_USING_SCRATCH
+ if (bs->use_scratch) {
+ /* Write to scratch. */
+ area_id = FLASH_AREA_IMAGE_SCRATCH;
+ } else {
+#endif
+ /* Write to the primary slot. */
+ area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
+#if MCUBOOT_SWAP_USING_SCRATCH
+ }
+#endif
+
+ rc = flash_area_open(area_id, &fap);
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+ off = boot_status_off(fap) + boot_status_internal_off(bs, 1);
+
+ uint8_t tmp_state = ((bs->op == BOOT_STATUS_OP_MOVE) ? bs->state : bs->state + 1);
+ rc = swap_status_update(fap->fa_id, off, &tmp_state, 1);
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+
+done:
+ flash_area_close(fap);
+
+ return rc;
+}
+
+int
+boot_read_data_empty(const struct flash_area *fap, void *data, uint32_t len)
+{
+ uint8_t *buf;
+
+ buf = (uint8_t *)data;
+ for (uint32_t i = 0; i < len; i++) {
+ if (buf[i] != flash_area_erased_val(fap)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int
+boot_read_swap_state(const struct flash_area *fap,
+ struct boot_swap_state *state)
+{
+ uint32_t magic[BOOT_MAGIC_ARR_SZ];
+ uint32_t off;
+ uint32_t trailer_off = 0;
+ uint8_t swap_info;
+ int rc;
+ uint32_t erase_trailer = 0;
+
+ const struct flash_area *fap_stat;
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
+ off = boot_magic_off(fap);
+ /* retrieve value for magic field from status partition area */
+ rc = swap_status_retrieve(fap->fa_id, off, magic, BOOT_MAGIC_SZ);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ rc = boot_read_data_empty(fap_stat, magic, BOOT_MAGIC_SZ);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ /* fill magic number value if equal to expected */
+ if (rc == 1) {
+
+ state->magic = BOOT_MAGIC_UNSET;
+
+ /* attempt to find magic in upgrade img slot trailer */
+ if (fap->fa_id == FLASH_AREA_IMAGE_1 ||
+ fap->fa_id == FLASH_AREA_IMAGE_3) {
+
+ trailer_off = fap->fa_size - BOOT_MAGIC_SZ;
+
+ rc = flash_area_read_is_empty(fap, trailer_off, magic, BOOT_MAGIC_SZ);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ if (rc == 1) {
+ state->magic = BOOT_MAGIC_UNSET;
+ } else {
+ state->magic = boot_magic_decode(magic);
+ /* put magic to status partition for upgrade slot*/
+ if (state->magic == BOOT_MAGIC_GOOD) {
+ rc = swap_status_update(fap->fa_id, off,
+ magic, BOOT_MAGIC_SZ);
+ }
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ } else {
+ erase_trailer = 1;
+ }
+ }
+ }
+ } else {
+ state->magic = boot_magic_decode(magic);
+ }
+ off = boot_swap_info_off(fap);
+ rc = swap_status_retrieve(fap->fa_id, off, &swap_info, sizeof swap_info);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ rc = boot_read_data_empty(fap_stat, &swap_info, sizeof swap_info);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ /* Extract the swap type and image number */
+ state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
+ state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
+
+ if (rc == 1 || state->swap_type > BOOT_SWAP_TYPE_REVERT) {
+ state->swap_type = BOOT_SWAP_TYPE_NONE;
+ state->image_num = 0;
+ }
+
+ off = boot_copy_done_off(fap);
+ rc = swap_status_retrieve(fap->fa_id, off, &state->copy_done, sizeof state->copy_done);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ rc = boot_read_data_empty(fap_stat, &state->copy_done, sizeof state->copy_done);
+ /* need to check swap_info was empty */
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ if (rc == 1) {
+ state->copy_done = BOOT_FLAG_UNSET;
+ } else {
+ state->copy_done = boot_flag_decode(state->copy_done);
+ }
+
+ off = boot_image_ok_off(fap);
+ rc = swap_status_retrieve(fap->fa_id, off, &state->image_ok, sizeof state->image_ok);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ rc = boot_read_data_empty(fap_stat, &state->image_ok, sizeof state->image_ok);
+ /* need to check swap_info was empty */
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ if (rc == 1) {
+ /* assign img_ok unset */
+ state->image_ok = BOOT_FLAG_UNSET;
+
+ /* attempt to read img_ok value in upgrade img slots trailer area
+ * it is set when image in slot for upgrade is signed for swap_type permanent
+ */
+ uint32_t process_image_ok = 0;
+ switch (fap->fa_id) {
+ case FLASH_AREA_IMAGE_0:
+ case FLASH_AREA_IMAGE_2:
+ if (state->copy_done == BOOT_FLAG_SET)
+ process_image_ok = 1;
+ break;
+ case FLASH_AREA_IMAGE_1:
+ case FLASH_AREA_IMAGE_3:
+ process_image_ok = 1;
+ break;
+ default:
+ return BOOT_EFLASH;
+ break;
+ }
+ if (process_image_ok != 0) {
+ trailer_off = fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
+
+ rc = flash_area_read_is_empty(fap, trailer_off, &state->image_ok, sizeof state->image_ok);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ if (rc == 1) {
+ state->image_ok = BOOT_FLAG_UNSET;
+ } else {
+ state->image_ok = boot_flag_decode(state->image_ok);
+ /* put img_ok to status partition for upgrade slot */
+ if (state->image_ok != BOOT_FLAG_BAD) {
+ rc = swap_status_update(fap->fa_id, off,
+ &state->image_ok, sizeof state->image_ok);
+ }
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ } else {
+ /* mark img trailer needs to be erased */
+ erase_trailer = 1;
+ }
+ }
+ }
+ } else {
+ state->image_ok = boot_flag_decode(state->image_ok);
+ }
+
+ if (erase_trailer != 0) {
+ /* erase magic from upgrade img trailer */
+ rc = flash_area_erase(fap, trailer_off, BOOT_MAGIC_SZ);
+ if (rc != 0)
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * This functions tries to locate the status area after an aborted swap,
+ * by looking for the magic in the possible locations.
+ *
+ * If the magic is successfully found, a flash_area * is returned and it
+ * is the responsibility of the called to close it.
+ *
+ * @returns 0 on success, -1 on errors
+ */
+static int
+boot_find_status(int image_index, const struct flash_area **fap)
+{
+ uint32_t magic[BOOT_MAGIC_ARR_SZ];
+ uint32_t off;
+
+ /* the status is always in status partition */
+ uint8_t area = FLASH_AREA_IMAGE_PRIMARY(image_index);
+ int rc;
+
+ /*
+ * In the middle a swap, tries to locate the area that is currently
+ * storing a valid magic, first on the primary slot, then on scratch.
+ * Both "slots" can end up being temporary storage for a swap and it
+ * is assumed that if magic is valid then other metadata is too,
+ * because magic is always written in the last step.
+ */
+ rc = flash_area_open(area, fap);
+ if (rc != 0) {
+ return rc;
+ }
+ off = boot_magic_off(*fap);
+ rc = swap_status_retrieve(area, off, magic, BOOT_MAGIC_SZ);
+ if (rc == 0) {
+ if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
+ rc = 0;
+ }
+ }
+ flash_area_close(*fap);
+ return rc;
+}
+
+int
+boot_read_swap_size(int image_index, uint32_t *swap_size)
+{
+ uint32_t off;
+ const struct flash_area *fap;
+ int rc;
+
+ rc = boot_find_status(image_index, &fap);
+ if (rc == 0) {
+ off = boot_swap_size_off(fap);
+
+ rc = swap_status_retrieve(fap->fa_id, off, swap_size, sizeof *swap_size);
+ }
+ return rc;
+}
+
+int
+swap_erase_trailer_sectors(const struct boot_loader_state *state,
+ const struct flash_area *fap)
+{
+ uint32_t sector;
+ uint32_t trailer_sz;
+ uint32_t total_sz;
+ uint32_t off, sub_offs, trailer_offs;
+ uint32_t sz;
+ int fa_id_primary;
+ int fa_id_secondary;
+ uint8_t image_index;
+ int rc;
+
+ BOOT_LOG_INF("Erasing trailer; fa_id=%d", fap->fa_id);
+ /* trailer is located in status-partition */
+ const struct flash_area *fap_stat;
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
+ image_index = BOOT_CURR_IMG(state);
+ fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
+ BOOT_PRIMARY_SLOT);
+ fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
+ BOOT_SECONDARY_SLOT);
+ /* skip if Flash Area is not recognizable */
+ if ((fap->fa_id != fa_id_primary) && (fap->fa_id != fa_id_secondary)) {
+ return BOOT_EFLASH;
+ }
+ sub_offs = swap_status_init_offset(fap->fa_id);
+
+ /* delete starting from last sector and moving to beginning */
+ /* calculate last sector of status sub-area */
+ sector = boot_status_num_sectors(state) - 1;
+ /* whole status area size to be erased */
+ trailer_sz = BOOT_SWAP_STATUS_SIZE;
+ total_sz = 0;
+ do {
+ sz = boot_status_sector_size(state, sector);
+ off = boot_status_sector_off(state, sector) + sub_offs;
+ rc = boot_erase_region(fap_stat, off, sz);
+ assert(rc == 0);
+
+ sector--;
+ total_sz += sz;
+ } while (total_sz < trailer_sz);
+
+ /*
+ * it is also needed to erase trailer area in slots since they may contain
+ * data, which is already cleared in corresponding status partition
+ */
+ trailer_offs = fap->fa_size - BOOT_SWAP_STATUS_TRAILER_SIZE;
+ rc = flash_area_erase(fap, trailer_offs, BOOT_SWAP_STATUS_TRAILER_SIZE);
+
+ flash_area_close(fap_stat);
+
+ return rc;
+}
+
+int
+swap_status_init(const struct boot_loader_state *state,
+ const struct flash_area *fap,
+ const struct boot_status *bs)
+{
+ struct boot_swap_state swap_state;
+ uint8_t image_index;
+ int rc;
+
+#if (BOOT_IMAGE_NUMBER == 1)
+ (void)state;
+#endif
+
+ image_index = BOOT_CURR_IMG(state);
+
+ BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
+
+ rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
+ &swap_state);
+ assert(rc == 0);
+
+ if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
+ rc = boot_write_swap_info(fap, bs->swap_type, image_index);
+ assert(rc == 0);
+ }
+
+ if (swap_state.image_ok == BOOT_FLAG_SET) {
+ rc = boot_write_image_ok(fap);
+ assert(rc == 0);
+ }
+
+ rc = boot_write_swap_size(fap, bs->swap_size);
+ assert(rc == 0);
+
+#ifdef MCUBOOT_ENC_IMAGES
+ rc = boot_write_enc_key(fap, 0, bs);
+ assert(rc == 0);
+
+ rc = boot_write_enc_key(fap, 1, bs);
+ assert(rc == 0);
+#endif
+
+ rc = boot_write_magic(fap);
+ assert(rc == 0);
+
+ return 0;
+}
+
+int
+swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
+{
+ const struct flash_area *fap;
+ const struct flash_area *fap_stat;
+ uint32_t off;
+ uint8_t swap_info;
+ int area_id;
+ int rc = 0;
+
+ bs->source = swap_status_source(state);
+ switch (bs->source) {
+ case BOOT_STATUS_SOURCE_NONE:
+ return 0;
+
+ case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
+ area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
+ break;
+
+ default:
+ assert(0);
+ return BOOT_EBADARGS;
+ }
+ rc = flash_area_open(area_id, &fap);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+ rc = swap_read_status_bytes(fap, state, bs);
+ if (rc == 0) {
+ off = boot_swap_info_off(fap);
+ rc = swap_status_retrieve(area_id, off, &swap_info, sizeof swap_info);
+
+ rc = boot_read_data_empty(fap_stat, &swap_info, sizeof swap_info);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+
+ if (rc == 1) {
+ BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
+ rc = 0;
+ }
+
+ /* Extract the swap type info */
+ bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
+ }
+
+ flash_area_close(fap);
+ flash_area_close(fap_stat);
+
+ return rc;
+}
+
+#endif /* MCUBOOT_SWAP_USING_STATUS */
diff --git a/boot/bootutil/src/swap_status_part.c b/boot/bootutil/src/swap_status_part.c
new file mode 100644
index 0000000..6848771
--- /dev/null
+++ b/boot/bootutil/src/swap_status_part.c
@@ -0,0 +1,377 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2017-2019 Linaro LTD
+ * Copyright (c) 2016-2019 JUUL Labs
+ * Copyright (c) 2019-2020 Arm Limited
+ * Copyright (c) 2020 Cypress Semiconductors
+ *
+ * Original license:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include "crc32c.h"
+#include <string.h>
+#include "swap_status.h"
+
+#ifdef MCUBOOT_SWAP_USING_STATUS
+
+const uint32_t stat_part_magic[] = {
+ BOOT_SWAP_STATUS_MAGIC
+};
+
+uint32_t calc_rec_idx(uint32_t value)
+{
+ uint32_t rec_idx;
+
+ rec_idx = value/BOOT_SWAP_STATUS_PAYLD_SZ;
+
+ return rec_idx;
+}
+
+uint32_t calc_record_offs(uint32_t offs)
+{
+ uint32_t rec_offs;
+
+ rec_offs = BOOT_SWAP_STATUS_ROW_SZ*calc_rec_idx(offs);
+
+ return rec_offs;
+}
+
+uint32_t calc_record_crc(const uint8_t *data, uint32_t length)
+{
+ uint32_t crc;
+
+ crc = crc32c_checksum(data, length);
+
+ return crc;
+}
+
+int32_t swap_status_init_offset(uint32_t area_id)
+{
+ int32_t offset;
+ /* calculate an offset caused by area type: primary_x/secondary_x */
+ switch (area_id) {
+ case FLASH_AREA_IMAGE_0:
+ offset = 0x00;
+ break;
+ case FLASH_AREA_IMAGE_1:
+ offset = BOOT_SWAP_STATUS_SIZE;
+ break;
+// TODO: add multi-image conditional compilation here
+ case FLASH_AREA_IMAGE_2:
+ offset = 2*BOOT_SWAP_STATUS_SIZE;
+ break;
+ case FLASH_AREA_IMAGE_3:
+ offset = 3*BOOT_SWAP_STATUS_SIZE;
+ break;
+ default:
+ offset = -1;
+ break;
+ }
+ return offset;
+}
+
+int swap_status_read_record(uint32_t rec_offset, uint8_t *data, uint32_t *copy_counter)
+{ /* returns BOOT_SWAP_STATUS_PAYLD_SZ of data */
+ int rc = -1;
+
+ uint32_t fin_offset, data_offset;
+ uint32_t counter, crc, magic;
+ uint32_t crc_fail = 0;
+ uint32_t magic_fail = 0;
+ uint32_t max_cnt = 0;
+
+ int32_t max_idx = 0;
+
+ uint8_t buff[BOOT_SWAP_STATUS_ROW_SZ];
+
+ const struct flash_area *fap_stat;
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
+ /* loop over copies/duplicates */
+ for(uint32_t i = 0; i<BOOT_SWAP_STATUS_MULT; i++) {
+ /* calculate final duplicate offset */
+ fin_offset = rec_offset + i*BOOT_SWAP_STATUS_D_SIZE;
+
+ rc = flash_area_read(fap_stat, fin_offset, buff, sizeof(buff));
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+ /* read magic value to know if area was pre-erased */
+ magic = *((uint32_t *)&buff[BOOT_SWAP_STATUS_ROW_SZ -\
+ BOOT_SWAP_STATUS_MGCREC_SZ -\
+ BOOT_SWAP_STATUS_CNT_SZ-\
+ BOOT_SWAP_STATUS_CRC_SZ]);
+ if (magic == BOOT_SWAP_STATUS_MAGIC) { /* read CRC */
+ crc = *((uint32_t *)&buff[BOOT_SWAP_STATUS_ROW_SZ -\
+ BOOT_SWAP_STATUS_CRC_SZ]);
+ /* check record data integrity first */
+ if (crc == calc_record_crc(buff, BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ)) {
+ /* look for counter */
+ counter = *((uint32_t *)&buff[BOOT_SWAP_STATUS_ROW_SZ -\
+ BOOT_SWAP_STATUS_CNT_SZ - \
+ BOOT_SWAP_STATUS_CRC_SZ]);
+ /* find out counter max */
+ if (counter >= max_cnt) {
+ max_cnt = counter;
+ max_idx = i;
+ data_offset = fin_offset;
+ }
+ }
+ /* if crc != calculated() */
+ else {
+ crc_fail++;
+ }
+ }
+ else {
+ magic_fail++;
+ }
+ }
+ /* no magic found - status area is pre-erased, start from scratch */
+ if (magic_fail == BOOT_SWAP_STATUS_MULT) {
+ /* emulate last index was received, so next will start from beginning */
+ max_idx = BOOT_SWAP_STATUS_MULT-1;
+ *copy_counter = 0;
+ /* return all erased values */
+ memset(data, flash_area_erased_val(fap_stat), BOOT_SWAP_STATUS_PAYLD_SZ);
+ }
+ else {
+ /* no valid CRC found - status pre-read failure */
+ if (crc_fail == BOOT_SWAP_STATUS_MULT)
+ {
+ max_idx = -1;
+ }
+ else {
+ *copy_counter = max_cnt;
+ /* read payload data */
+ rc = flash_area_read(fap_stat, data_offset, data, BOOT_SWAP_STATUS_PAYLD_SZ);
+ assert (rc == 0);
+ }
+ }
+ flash_area_close(fap_stat);
+
+ /* return back duplicate index */
+ return max_idx;
+}
+
+static int swap_status_write_record(uint32_t rec_offset, uint32_t copy_num, uint32_t copy_counter, const uint8_t *data)
+{ /* it receives explicitly BOOT_SWAP_STATUS_PAYLD_SZ of data */
+ int rc = -1;
+
+ uint32_t fin_offset;
+ /* increment counter field */
+ uint32_t next_counter = copy_counter+1;
+ uint32_t next_crc;
+
+ uint8_t buff[BOOT_SWAP_STATUS_ROW_SZ];
+
+ const struct flash_area *fap_stat;
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
+ /* copy data into buffer */
+ memcpy(buff, data, BOOT_SWAP_STATUS_PAYLD_SZ);
+ /* append next counter to whole record row */
+ memcpy(&buff[BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CNT_SZ-BOOT_SWAP_STATUS_CRC_SZ], \
+ &next_counter, \
+ BOOT_SWAP_STATUS_CNT_SZ);
+ /* append record magic */
+ memcpy(&buff[BOOT_SWAP_STATUS_ROW_SZ-\
+ BOOT_SWAP_STATUS_MGCREC_SZ-\
+ BOOT_SWAP_STATUS_CNT_SZ-\
+ BOOT_SWAP_STATUS_CRC_SZ], \
+ stat_part_magic, \
+ BOOT_SWAP_STATUS_MGCREC_SZ);
+
+ /* calculate CRC field*/
+ next_crc = calc_record_crc(buff, BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ);
+
+ /* append new CRC to whole record row */
+ memcpy(&buff[BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ], \
+ &next_crc, \
+ BOOT_SWAP_STATUS_CRC_SZ);
+
+ /* we already know what copy number was last and correct */
+ /* increment duplicate index */
+ /* calculate final duplicate offset */
+ if (copy_num == (BOOT_SWAP_STATUS_MULT-1)) {
+ copy_num = 0;
+ }
+ else {
+ copy_num++;
+ }
+ fin_offset = rec_offset + copy_num*BOOT_SWAP_STATUS_D_SIZE;
+
+ /* write prepared record into flash */
+ rc = flash_area_write(fap_stat, fin_offset, buff, sizeof(buff));
+ assert (rc == 0);
+
+ flash_area_close(fap_stat);
+
+ return rc;
+}
+
+/**
+ * Updates len bytes of status partition with values from *data-pointer.
+ *
+ * @param targ_area_id Target area id for which status is being written.
+ * Not a status-partition area id.
+ * @param offset Status byte offset inside status table. Should not include CRC and CNT.
+ * @param data Pointer to data status table to needs to be updated with.
+ * @param len Number of bytes to be written
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+int swap_status_update(uint32_t targ_area_id, uint32_t offs, const void *data, uint32_t len)
+{
+ int rc = -1;
+
+ int32_t init_offs;
+ int32_t length = (int32_t)len;
+ int32_t copy_num;
+
+ uint32_t rec_offs;
+ uint32_t copy_sz;
+ uint32_t copy_counter;
+ uint32_t data_idx = 0;
+ uint32_t buff_idx = offs%BOOT_SWAP_STATUS_PAYLD_SZ;
+
+ uint8_t buff[BOOT_SWAP_STATUS_PAYLD_SZ];
+
+ /* check if end of data is still inside writable area */
+ // TODO: update for multi image
+ assert ((offs + len) <= BOOT_SWAP_STATUS_D_SIZE_RAW);
+
+ /* pre-calculate sub-area offset */
+ init_offs = swap_status_init_offset(targ_area_id);
+ assert (init_offs >= 0);
+
+ /* will start from it
+ * this will be write-aligned */
+ rec_offs = init_offs + calc_record_offs(offs);
+
+ /* go over all records to be updated */
+ while (length > 0) {
+ /* preserve record */
+ copy_num = swap_status_read_record(rec_offs, buff, ©_counter);
+ /* it returns copy number */
+ if (copy_num < 0)
+ { /* something went wrong while read, exit */
+ rc = -1;
+ break;
+ }
+ /* update record data */
+ if (length > (int)BOOT_SWAP_STATUS_PAYLD_SZ) {
+ copy_sz = BOOT_SWAP_STATUS_PAYLD_SZ - buff_idx;
+ }
+ else {
+ copy_sz = length;
+ }
+ memcpy((uint8_t *)buff+buff_idx, &((uint8_t *)data)[data_idx], copy_sz);
+ buff_idx = 0;
+
+ /* write record back */
+ rc = swap_status_write_record(rec_offs, (uint32_t)copy_num, copy_counter, buff);
+ assert (rc == 0);
+
+ /* proceed to next record */
+ length -= BOOT_SWAP_STATUS_PAYLD_SZ;
+ rec_offs += BOOT_SWAP_STATUS_ROW_SZ;
+ data_idx += BOOT_SWAP_STATUS_PAYLD_SZ;
+ }
+ return rc;
+}
+
+/**
+ * Reads len bytes of status partition with values from *data-pointer.
+ *
+ * @param targ_area_id Target area id for which status is being read.
+ * Not a status-partition area id.
+ * @param offset Status byte offset inside status table. Should not include CRC and CNT.
+ * @param data Pointer to data where status table values will be written.
+ * @param len Number of bytes to be read from status table.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+int swap_status_retrieve(uint32_t target_area_id, uint32_t offs, void *data, uint32_t len)
+{
+ int rc = 0;
+
+ int32_t init_offs;
+ int32_t length = (int32_t)len;
+ int32_t copy_num;
+
+ uint32_t rec_offs;
+ uint32_t copy_sz;
+ uint32_t copy_counter;
+ uint32_t data_idx = 0;
+ uint32_t buff_idx = offs%BOOT_SWAP_STATUS_PAYLD_SZ;
+
+ uint8_t buff[BOOT_SWAP_STATUS_PAYLD_SZ];
+
+ /* check if end of data is still inside writable area */
+ // TODO: update for multi image
+ assert ((offs + len) <= BOOT_SWAP_STATUS_D_SIZE_RAW);
+
+ /* pre-calculate sub-area offset */
+ init_offs = swap_status_init_offset(target_area_id);
+ assert (init_offs >= 0);
+
+ /* will start from it
+ * this will be write-aligned */
+ rec_offs = init_offs + calc_record_offs(offs);
+
+ /* go over all records to be updated */
+ while (length > 0) {
+ /* preserve record */
+ copy_num = swap_status_read_record(rec_offs, buff, ©_counter);
+ /* it returns copy number */
+ if (copy_num < 0) {
+ /* something went wrong while read, exit */
+ rc = -1;
+ break;
+ }
+ /* update record data */
+ if (length > (int)BOOT_SWAP_STATUS_PAYLD_SZ) {
+ copy_sz = BOOT_SWAP_STATUS_PAYLD_SZ - buff_idx;
+ }
+ else {
+ copy_sz = length;
+ }
+ memcpy((uint8_t *)data+data_idx, &buff[buff_idx], copy_sz);
+ buff_idx = 0;
+
+ /* proceed to next record */
+ length -= BOOT_SWAP_STATUS_PAYLD_SZ;
+ rec_offs += BOOT_SWAP_STATUS_ROW_SZ;
+ data_idx += BOOT_SWAP_STATUS_PAYLD_SZ;
+ }
+ return rc;
+}
+
+#endif /* MCUBOOT_SWAP_USING_STATUS */