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, &copy_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, &copy_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 */