Implement new swap scheme for devices with large erase size using scratch with status area
diff --git a/boot/bootutil/include/bootutil/bootutil.h b/boot/bootutil/include/bootutil/bootutil.h
index b45334a..cf08a59 100644
--- a/boot/bootutil/include/bootutil/bootutil.h
+++ b/boot/bootutil/include/bootutil/bootutil.h
@@ -72,6 +72,12 @@
 struct boot_loader_state;
 fih_int context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);
 
+int boot_swap_type_multi(int image_index);
+int boot_swap_type(void);
+
+int boot_set_pending(int permanent);
+int boot_set_confirmed(void);
+
 #define SPLIT_GO_OK                 (0)
 #define SPLIT_GO_NON_MATCHING       (-1)
 #define SPLIT_GO_ERR                (-2)
diff --git a/boot/bootutil/include/bootutil/caps.h b/boot/bootutil/include/bootutil/caps.h
index 8ead3be..77182a1 100644
--- a/boot/bootutil/include/bootutil/caps.h
+++ b/boot/bootutil/include/bootutil/caps.h
@@ -47,6 +47,7 @@
 #define BOOTUTIL_CAP_DOWNGRADE_PREVENTION   (1<<12)
 #define BOOTUTIL_CAP_ENC_X25519             (1<<13)
 #define BOOTUTIL_CAP_BOOTSTRAP              (1<<14)
+#define BOOTUTIL_CAP_SWAP_USING_STATUS      (1<<15)
 
 /*
  * Query the number of images this bootloader is configured for.  This
diff --git a/boot/bootutil/include/bootutil/enc_key.h b/boot/bootutil/include/bootutil/enc_key.h
index 779b0d4..1de6f81 100644
--- a/boot/bootutil/include/bootutil/enc_key.h
+++ b/boot/bootutil/include/bootutil/enc_key.h
@@ -45,6 +45,7 @@
 
 struct enc_key_data {
     uint8_t valid;
+    uint8_t aes_iv[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE];
     bootutil_aes_ctr_context aes_ctr;
 };
 
@@ -58,7 +59,7 @@
 int boot_enc_load(struct enc_key_data *enc_state, int image_index,
         const struct image_header *hdr, const struct flash_area *fap,
         struct boot_status *bs);
-int boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey);
+int boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey, uint32_t sz, uint8_t *enciv);
 bool boot_enc_valid(struct enc_key_data *enc_state, int image_index,
         const struct flash_area *fap);
 void boot_encrypt(struct enc_key_data *enc_state, int image_index,
diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c
index 9ee317f..221d8a6 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 */
@@ -134,6 +140,7 @@
     return -1;
 }
 
+#ifndef MCUBOOT_SWAP_USING_STATUS
 uint32_t
 boot_status_off(const struct flash_area *fap)
 {
@@ -147,6 +154,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)
@@ -154,6 +162,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)
 {
@@ -171,6 +181,7 @@
 {
     return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
 }
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
 
 #ifdef MCUBOOT_ENC_IMAGES
 static inline uint32_t
@@ -185,6 +196,7 @@
 }
 #endif
 
+#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.
@@ -272,6 +284,8 @@
     if (rc == 0) {
         off = boot_enc_key_off(fap, slot);
 #if MCUBOOT_SWAP_SAVE_ENCTLV
+        uint8_t aes_iv[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE];
+
         rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
         if (rc == 0) {
             for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
@@ -281,7 +295,7 @@
             }
             /* Only try to decrypt non-erased TLV metadata */
             if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
-                rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]);
+                rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot], 0, aes_iv);
             }
         }
 #else
@@ -294,6 +308,8 @@
 }
 #endif
 
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
+
 int
 boot_write_copy_done(const struct flash_area *fap)
 {
@@ -318,6 +334,8 @@
     return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
 }
 
+#ifndef MCUBOOT_SWAP_USING_STATUS
+
 #ifdef MCUBOOT_ENC_IMAGES
 int
 boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
@@ -342,3 +360,5 @@
     return 0;
 }
 #endif
+
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h
index d2ebca2..37a9350 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -217,6 +217,13 @@
         size_t num_sectors;
     } scratch;
 #endif
+#if 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];
     uint32_t write_sz;
@@ -240,6 +247,7 @@
 uint32_t boot_trailer_sz(uint32_t min_write_sz);
 int boot_status_entries(int image_index, const struct flash_area *fap);
 uint32_t boot_status_off(const struct flash_area *fap);
+uint32_t boot_swap_info_off(const struct flash_area *fap);
 int boot_read_swap_state(const struct flash_area *fap,
                          struct boot_swap_state *state);
 int boot_read_swap_state_by_id(int flash_area_id,
@@ -267,6 +275,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/bootutil_public.c b/boot/bootutil/src/bootutil_public.c
index 793c4e3..6057b41 100644
--- a/boot/bootutil/src/bootutil_public.c
+++ b/boot/bootutil/src/bootutil_public.c
@@ -46,6 +46,7 @@
 #include "bootutil/image.h"
 #include "bootutil/bootutil_public.h"
 #include "bootutil/bootutil_log.h"
+#include "swap_status.h"
 #ifdef MCUBOOT_ENC_IMAGES
 #include "bootutil/enc_key_public.h"
 #endif
@@ -117,6 +118,7 @@
 #define BOOT_SWAP_TABLES_COUNT \
     (sizeof boot_swap_tables / sizeof boot_swap_tables[0])
 
+#ifndef MCUBOOT_SWAP_USING_STATUS
 static int
 boot_magic_decode(const uint32_t *magic)
 {
@@ -125,6 +127,7 @@
     }
     return BOOT_MAGIC_BAD;
 }
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
 
 static int
 boot_flag_decode(uint8_t flag)
@@ -135,6 +138,7 @@
     return BOOT_FLAG_SET;
 }
 
+#ifndef MCUBOOT_SWAP_USING_STATUS
 static inline uint32_t
 boot_magic_off(const struct flash_area *fap)
 {
@@ -153,17 +157,12 @@
     return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
 }
 
-static inline uint32_t
-boot_swap_size_off(const struct flash_area *fap)
-{
-    return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
-}
-
 uint32_t
 boot_swap_info_off(const struct flash_area *fap)
 {
     return boot_copy_done_off(fap) - BOOT_MAX_ALIGN;
 }
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
 
 /**
  * Determines if a status source table is satisfied by the specified magic
@@ -191,19 +190,6 @@
     }
 }
 
-#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
-    return boot_swap_size_off(fap) - ((slot + 1) *
-            ((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN));
-#else
-    return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE);
-#endif
-}
-#endif
-
 bool bootutil_buffer_is_erased(const struct flash_area *area,
                                const void *buffer, size_t len)
 {
@@ -249,6 +235,7 @@
     return boot_read_flag(fap, copy_done, boot_copy_done_off(fap));
 }
 
+#ifndef MCUBOOT_SWAP_USING_STATUS
 
 int
 boot_read_swap_state(const struct flash_area *fap,
@@ -294,6 +281,8 @@
     return boot_read_image_ok(fap, &state->image_ok);
 }
 
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
+
 int
 boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
 {
@@ -310,6 +299,8 @@
     return rc;
 }
 
+#ifndef MCUBOOT_SWAP_USING_STATUS
+
 int
 boot_write_magic(const struct flash_area *fap)
 {
@@ -361,6 +352,8 @@
     return 0;
 }
 
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
+
 int
 boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
         uint8_t flag_val)
@@ -408,6 +401,17 @@
     return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 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
 boot_swap_type_multi(int image_index)
 {
@@ -429,6 +433,9 @@
         return BOOT_SWAP_TYPE_PANIC;
     }
 
+    BOOT_LOG_SWAP_STATE("boot_swap_type_multi: Primary image", &primary_slot);
+    BOOT_LOG_SWAP_STATE("boot_swap_type_multi: Secondary image", &secondary_slot);
+
     for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
         table = boot_swap_tables + i;
 
diff --git a/boot/bootutil/src/caps.c b/boot/bootutil/src/caps.c
index a21bc09..2033056 100644
--- a/boot/bootutil/src/caps.c
+++ b/boot/bootutil/src/caps.c
@@ -44,6 +44,8 @@
     res |= BOOTUTIL_CAP_OVERWRITE_UPGRADE;
 #elif defined(MCUBOOT_SWAP_USING_MOVE)
     res |= BOOTUTIL_CAP_SWAP_USING_MOVE;
+#elif defined(MCUBOOT_SWAP_USING_STATUS)
+    res |= BOOTUTIL_CAP_SWAP_USING_STATUS;
 #else
     res |= BOOTUTIL_CAP_SWAP_USING_SCRATCH;
 #endif
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..329b9d3
--- /dev/null
+++ b/boot/bootutil/src/crc32c.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#ifndef H_CRC32C_
+#define H_CRC32C_
+
+#include <stdint.h>
+
+uint32_t crc32c_checksum(const uint8_t *address, uint32_t length);
+
+#endif /* H_CRC32C_ */
diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c
index d14855b..12c0a9c 100644
--- a/boot/bootutil/src/encrypted.c
+++ b/boot/bootutil/src/encrypted.c
@@ -297,15 +297,16 @@
  * @param ikm_len   Length of the input data.
  * @param info      An information tag.
  * @param info_len  Length of the information tag.
+ * @param salt      An salt tag.
+ * @param salt_len  Length of the salt tag.
  * @param okm       Output of the KDF computation.
  * @param okm_len   On input the requested length; on output the generated length
  */
 static int
-hkdf(uint8_t *ikm, uint16_t ikm_len, uint8_t *info, uint16_t info_len,
-        uint8_t *okm, uint16_t *okm_len)
+hkdf(const uint8_t *ikm, uint16_t ikm_len, const uint8_t *info, uint16_t info_len,
+        const uint8_t *salt, uint16_t salt_len, uint8_t *okm, uint16_t *okm_len)
 {
     bootutil_hmac_sha256_context hmac;
-    uint8_t salt[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
     uint8_t prk[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
     uint8_t T[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
     uint16_t off;
@@ -324,8 +325,7 @@
 
     bootutil_hmac_sha256_init(&hmac);
 
-    memset(salt, 0, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
-    rc = bootutil_hmac_sha256_set_key(&hmac, salt, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
+    rc = bootutil_hmac_sha256_set_key(&hmac, salt, salt_len);
     if (rc != 0) {
         goto error;
     }
@@ -429,21 +429,25 @@
     return 0;
 }
 
-#define EXPECTED_ENC_LEN        BOOT_ENC_TLV_SIZE
+#define EXPECTED_ENC_LEN            BOOT_ENC_TLV_SIZE
 
 #if defined(MCUBOOT_ENCRYPT_RSA)
-#    define EXPECTED_ENC_TLV    IMAGE_TLV_ENC_RSA2048
+#    define EXPECTED_ENC_TLV        IMAGE_TLV_ENC_RSA2048
+#    define EXPECTED_ENC_EXT_LEN    EXPECTED_ENC_TLV
 #elif defined(MCUBOOT_ENCRYPT_KW)
-#    define EXPECTED_ENC_TLV    IMAGE_TLV_ENC_KW128
+#    define EXPECTED_ENC_TLV        IMAGE_TLV_ENC_KW128
+#    define EXPECTED_ENC_EXT_LEN    EXPECTED_ENC_TLV
 #elif defined(MCUBOOT_ENCRYPT_EC256)
-#    define EXPECTED_ENC_TLV    IMAGE_TLV_ENC_EC256
+#    define EXPECTED_ENC_TLV     IMAGE_TLV_ENC_EC256
+#    define EXPECTED_ENC_EXT_LEN (EXPECTED_ENC_LEN + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)
 #    define EC_PUBK_INDEX       (0)
 #    define EC_TAG_INDEX        (65)
 #    define EC_CIPHERKEY_INDEX  (65 + 32)
 _Static_assert(EC_CIPHERKEY_INDEX + 16 == EXPECTED_ENC_LEN,
         "Please fix ECIES-P256 component indexes");
 #elif defined(MCUBOOT_ENCRYPT_X25519)
-#    define EXPECTED_ENC_TLV    IMAGE_TLV_ENC_X25519
+#    define EXPECTED_ENC_TLV        IMAGE_TLV_ENC_X25519
+#    define EXPECTED_ENC_EXT_LEN    EXPECTED_ENC_TLV
 #    define EC_PUBK_INDEX       (0)
 #    define EC_TAG_INDEX        (32)
 #    define EC_CIPHERKEY_INDEX  (32 + 32)
@@ -451,14 +455,19 @@
         "Please fix ECIES-X25519 component indexes");
 #endif
 
+#ifndef EXPECTED_ENC_EXT_LEN
+#define EXPECTED_ENC_EXT_LEN        EXPECTED_ENC_LEN
+#endif
+
 /*
  * Decrypt an encryption key TLV.
  *
- * @param buf An encryption TLV read from flash (build time fixed length)
+ * @param buf An encryption TLV buffer red from flash
+ * @param sz An encryption TLV buffer data size
  * @param enckey An AES-128 key sized buffer to store to plain key.
  */
 int
-boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey)
+boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey, uint32_t sz, uint8_t *enciv)
 {
 #if defined(MCUBOOT_ENCRYPT_RSA)
     mbedtls_rsa_context rsa;
@@ -475,14 +484,22 @@
 #if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
     bootutil_hmac_sha256_context hmac;
     bootutil_aes_ctr_context aes_ctr;
+    uint8_t salt[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
     uint8_t tag[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
     uint8_t shared[SHARED_KEY_LEN];
-    uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
+    uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE + BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE * 2];
     uint8_t *cp;
     uint8_t *cpend;
     uint8_t private_key[PRIV_KEY_LEN];
     uint8_t counter[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
     uint16_t len;
+    uint16_t out_len;
+    const uint8_t *my_salt = salt;
+    uint8_t *my_key_iv = counter;
+    uint8_t *my_counter = counter;
+#else
+    (void)sz;
+    (void)enciv;
 #endif
     int rc = -1;
 
@@ -532,6 +549,7 @@
     bootutil_ecdh_p256_init(&ecdh_p256);
 
     rc = bootutil_ecdh_p256_shared_secret(&ecdh_p256, &buf[EC_PUBK_INDEX], private_key, shared);
+
     bootutil_ecdh_p256_drop(&ecdh_p256);
     if (rc != 0) {
         return -1;
@@ -573,10 +591,31 @@
      * Expand shared secret to create keys for AES-128-CTR + HMAC-SHA256
      */
 
+    /* Prepare for default encryption scheme with zero salt and AES IVs */
+    memset(counter, 0, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
+    memset(salt, 0, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
+
     len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
-    rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16,
-            derived_key, &len);
-    if (rc != 0 || len != (BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) {
+
+    if (sz > EXPECTED_ENC_LEN) {
+        /* Use new enhanced encryption scheme with randomly generated salt and AES IVs */
+        len += BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE * 2;
+
+        my_salt = &buf[EXPECTED_ENC_LEN];
+
+        my_key_iv = &derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE +
+                                 BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
+
+        my_counter = &derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE +
+                                  BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE +
+                                  BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
+    }
+
+    out_len = len;
+    rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE,
+              my_salt, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, derived_key, &out_len);
+
+    if (rc != 0 || len != out_len) {
         return -1;
     }
 
@@ -586,13 +625,13 @@
 
     bootutil_hmac_sha256_init(&hmac);
 
-    rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[16], 32);
+    rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE], BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
     if (rc != 0) {
         (void)bootutil_hmac_sha256_drop(&hmac);
         return -1;
     }
 
-    rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], 16);
+    rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
     if (rc != 0) {
         (void)bootutil_hmac_sha256_drop(&hmac);
         return -1;
@@ -605,22 +644,20 @@
         return -1;
     }
 
-    if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], 32) != 0) {
+    if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE) != 0) {
         (void)bootutil_hmac_sha256_drop(&hmac);
         return -1;
     }
 
     bootutil_hmac_sha256_drop(&hmac);
 
+    (void)memcpy(enciv, my_counter, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
+
     /*
      * Finally decrypt the received ciphered key
      */
 
     bootutil_aes_ctr_init(&aes_ctr);
-    if (rc != 0) {
-        bootutil_aes_ctr_drop(&aes_ctr);
-        return -1;
-    }
 
     rc = bootutil_aes_ctr_set_key(&aes_ctr, derived_key);
     if (rc != 0) {
@@ -628,8 +665,7 @@
         return -1;
     }
 
-    memset(counter, 0, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
-    rc = bootutil_aes_ctr_decrypt(&aes_ctr, counter, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, 0, enckey);
+    rc = bootutil_aes_ctr_decrypt(&aes_ctr, my_key_iv, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, 0, enckey);
     if (rc != 0) {
         bootutil_aes_ctr_drop(&aes_ctr);
         return -1;
@@ -658,7 +694,7 @@
 #if MCUBOOT_SWAP_SAVE_ENCTLV
     uint8_t *buf;
 #else
-    uint8_t buf[EXPECTED_ENC_LEN];
+    uint8_t buf[EXPECTED_ENC_EXT_LEN];
 #endif
     uint8_t slot;
     int rc;
@@ -687,7 +723,7 @@
         return rc;
     }
 
-    if (len != EXPECTED_ENC_LEN) {
+    if ((len < EXPECTED_ENC_LEN) || (len > EXPECTED_ENC_EXT_LEN)) {
         return -1;
     }
 
@@ -696,12 +732,12 @@
     memset(buf, 0xff, BOOT_ENC_TLV_ALIGN_SIZE);
 #endif
 
-    rc = flash_area_read(fap, off, buf, EXPECTED_ENC_LEN);
+    rc = flash_area_read(fap, off, buf, len);
     if (rc) {
         return -1;
     }
 
-    return boot_enc_decrypt(buf, bs->enckey[slot]);
+    return (boot_enc_decrypt(buf, bs->enckey[slot], len, enc_state[slot].aes_iv));
 }
 
 bool
@@ -726,7 +762,7 @@
         uint32_t blk_off, uint8_t *buf)
 {
     struct enc_key_data *enc;
-    uint8_t nonce[16];
+    uint8_t *nonce;
     int rc;
 
     /* boot_copy_region will call boot_encrypt with sz = 0 when skipping over
@@ -735,13 +771,6 @@
        return;
     }
 
-    memset(nonce, 0, 12);
-    off >>= 4;
-    nonce[12] = (uint8_t)(off >> 24);
-    nonce[13] = (uint8_t)(off >> 16);
-    nonce[14] = (uint8_t)(off >> 8);
-    nonce[15] = (uint8_t)off;
-
     rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
     if (rc < 0) {
         assert(0);
@@ -750,6 +779,15 @@
 
     enc = &enc_state[rc];
     assert(enc->valid == 1);
+
+    nonce = enc->aes_iv;
+
+    off >>= 4;
+    nonce[12] = (uint8_t)(off >> 24);
+    nonce[13] = (uint8_t)(off >> 16);
+    nonce[14] = (uint8_t)(off >> 8);
+    nonce[15] = (uint8_t)off;
+
     bootutil_aes_ctr_encrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf);
 }
 
diff --git a/boot/bootutil/src/image_ec256.c b/boot/bootutil/src/image_ec256.c
index 5d73c9f..bdd72c6 100644
--- a/boot/bootutil/src/image_ec256.c
+++ b/boot/bootutil/src/image_ec256.c
@@ -97,7 +97,7 @@
     }
     return 0;
 }
-#endif /* CY_MBEDTLS_HW_ACCELERATION */
+#else /* !CY_MBEDTLS_HW_ACCELERATION */
 static int
 bootutil_import_key(uint8_t **cp, uint8_t *end)
 {
@@ -139,6 +139,7 @@
 
     return 0;
 }
+#endif /* CY_MBEDTLS_HW_ACCELERATION */
 
 #ifndef MCUBOOT_ECDSA_NEED_ASN1_SIG
 /*
diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c
index f066add..18967c5 100644
--- a/boot/bootutil/src/image_validate.c
+++ b/boot/bootutil/src/image_validate.c
@@ -490,6 +490,7 @@
             fih_rc = fih_int_encode_zero_equality(img_security_cnt <
                                    fih_int_decode(security_cnt));
             if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+                /* The image's security counter is not accepted. */
                 goto out;
             }
 
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index e1f1e54..e4c0a3f 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -106,7 +106,7 @@
  * Compute the total size of the given image.  Includes the size of
  * the TLVs.
  */
-#if !defined(MCUBOOT_OVERWRITE_ONLY) ||  defined(MCUBOOT_OVERWRITE_ONLY_FAST)
+#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
 static int
 boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
 {
@@ -166,6 +166,7 @@
 #endif /* !MCUBOOT_OVERWRITE_ONLY */
 
 #if !defined(MCUBOOT_RAM_LOAD)
+
 static uint32_t
 boot_write_sz(struct boot_loader_state *state)
 {
@@ -241,6 +242,11 @@
         out_sectors = state->scratch.sectors;
         out_num_sectors = &state->scratch.num_sectors;
 #endif
+#if 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 +284,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 +331,7 @@
             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.
@@ -381,6 +395,9 @@
     return rc;
 }
 #endif /* !MCUBOOT_RAM_LOAD */
+
+#endif /* MCUBOOT_SWAP_USING_STATUS */
+
 #endif /* !MCUBOOT_DIRECT_XIP */
 
 /*
@@ -525,6 +542,8 @@
 #if (BOOT_IMAGE_NUMBER > 1) || \
     defined(MCUBOOT_DIRECT_XIP) || \
     defined(MCUBOOT_RAM_LOAD) || \
+    defined(MCUBOOT_SWAP_USING_SCRATCH) || \
+    defined(MCUBOOT_SWAP_USING_MOVE) || \
     (defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
 /**
  * Compare image version numbers not including the build number
@@ -620,6 +639,8 @@
         FIH_RET(fih_rc);
     }
 
+    BOOT_LOG_DBG("> boot_validate_slot: fa_id = %d", fap->fa_id);
+
     hdr = boot_img_hdr(state, slot);
     if (boot_check_header_erased(state, slot) == 0 ||
         (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
@@ -635,11 +656,14 @@
          * through mcumgr; so we just get rid of the trailer here, if the header
          * is erased.
          */
+        BOOT_LOG_DBG(" * Fix the secondary slot when image is invalid.");
         if (slot != BOOT_PRIMARY_SLOT) {
+            BOOT_LOG_DBG(" * Erase secondary image trailer.");
             swap_erase_trailer_sectors(state, fap);
         }
 #endif
 
+        BOOT_LOG_DBG(" * No bootable image in slot(%d); continue booting from the primary slot.", slot);
         /* No bootable image in slot; continue booting from the primary slot. */
         fih_rc = fih_int_encode(1);
         goto out;
@@ -666,6 +690,7 @@
     FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
     if (!boot_is_header_valid(hdr, fap) || fih_not_eq(fih_rc, FIH_SUCCESS)) {
         if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
+            BOOT_LOG_DBG(" * Image in the secondary slot is invalid. Erase the image");
             flash_area_erase(fap, 0, fap->fa_size);
             /* Image is invalid, erase it to prevent further unnecessary
              * attempts to validate and boot it.
@@ -679,9 +704,11 @@
         goto out;
     }
 
+    /* Image in the secondary slot is valid. */
+
 out:
     flash_area_close(fap);
-
+    BOOT_LOG_DBG("< boot_validate_slot = %d", fih_int_decode(fih_rc));
     FIH_RET(fih_rc);
 }
 
@@ -834,23 +861,27 @@
 
 #ifdef MCUBOOT_ENC_IMAGES
         image_index = BOOT_CURR_IMG(state);
-        if ((fap_src->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index) ||
-            fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) &&
+        if ((fap_src->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
+             fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
+
+            !(fap_src->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index) &&
+              fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
             !(fap_src->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index) &&
-              fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index))) {
-            /* assume the secondary slot as src, needs decryption */
-            hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
+              fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)))
+        {
+            /* assume the primary slot as src, needs encryption */
+            hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
 #if !defined(MCUBOOT_SWAP_USING_MOVE)
             off = off_src;
-            if (fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
-                /* might need encryption (metadata from the primary slot) */
-                hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
+            if (fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
+                /* might need decryption (metadata from the secondary slot) */
+                hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
                 off = off_dst;
             }
 #else
             off = off_dst;
-            if (fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
-                hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
+            if (fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
+                hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
             }
 #endif
             if (IS_ENCRYPTED(hdr)) {
@@ -859,8 +890,13 @@
                 if (off + bytes_copied < hdr->ih_hdr_size) {
                     /* do not decrypt header */
                     blk_off = 0;
-                    blk_sz = chunk_sz - hdr->ih_hdr_size;
-                    idx = hdr->ih_hdr_size;
+                    if(chunk_sz > hdr->ih_hdr_size) {
+                        blk_sz = chunk_sz - hdr->ih_hdr_size;
+                        idx = hdr->ih_hdr_size - (off + bytes_copied);
+                    } else {
+                        /* still in header-area, no need to decrypt */
+                        blk_sz = 0;
+                    }
                 } else {
                     blk_off = ((off + bytes_copied) - hdr->ih_hdr_size) & 0xf;
                 }
@@ -873,9 +909,11 @@
                         blk_sz = tlv_off - (off + bytes_copied);
                     }
                 }
-                boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
+                if(0 != blk_sz) {
+                    boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
                         (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
                         blk_off, &buf[idx]);
+                }
             }
         }
 #endif
@@ -949,8 +987,12 @@
     assert (rc == 0);
 
     sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
+    BOOT_LOG_DBG(" * primary slot sectors: %d", sect_count);
     for (sect = 0, size = 0; sect < sect_count; sect++) {
         this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
+        /* BOOT_LOG_DBG(" * primary slot erase region (0x%0lx / 0x%0lx): sector = %d, off = %0x, size = %d",
+                     fap_primary_slot->fa_off, fap_primary_slot->fa_size,
+                     sect, size, this_size); */
         rc = boot_erase_region(fap_primary_slot, size, this_size);
         assert(rc == 0);
 
@@ -994,7 +1036,7 @@
     }
 #endif
 
-    BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
+    BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%x bytes",
                  size);
     rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
     if (rc != 0) {
@@ -1326,7 +1368,7 @@
         if (rc == 0) {
             /* All dependencies've been satisfied, continue with next image. */
             BOOT_CURR_IMG(state)++;
-        } else {
+        } else if (rc == BOOT_EBADVERSION) {
             /* Cannot upgrade due to non-met dependencies, so disable all
              * image upgrades.
              */
@@ -1335,6 +1377,9 @@
                 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
             }
             break;
+        } else {
+            /* Other error happened, images are inconsistent */
+            return rc;
         }
     }
     return rc;
@@ -1356,6 +1401,8 @@
     uint8_t swap_type;
 #endif
 
+    BOOT_LOG_DBG("> boot_perform_update: bs->idx = %d", bs->idx);
+
     /* At this point there are no aborted swaps. */
 #if defined(MCUBOOT_OVERWRITE_ONLY)
     rc = boot_copy_image(state, bs);
@@ -1551,6 +1598,8 @@
     int rc;
     fih_int fih_rc = FIH_FAILURE;
 
+    BOOT_LOG_DBG("> boot_prepare_image_for_update: image = %d", BOOT_CURR_IMG(state));
+
     /* Determine the sector layout of the image slots and scratch area. */
     rc = boot_read_sectors(state);
     if (rc != 0) {
@@ -1565,6 +1614,7 @@
 
     /* Attempt to read an image header from each slot. */
     rc = boot_read_image_headers(state, false, NULL);
+    BOOT_LOG_DBG(" * Read an image (%d) header from each slot: rc = %d", BOOT_CURR_IMG(state), rc);
     if (rc != 0) {
         /* Continue with next image if there is one. */
         BOOT_LOG_WRN("Failed reading image headers; Image=%u",
@@ -1590,12 +1640,13 @@
         }
 #endif
 
-#ifdef MCUBOOT_SWAP_USING_MOVE
+#if defined (MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH)
         /*
          * Must re-read image headers because the boot status might
          * have been updated in the previous function call.
          */
         rc = boot_read_image_headers(state, !boot_status_is_reset(bs), bs);
+        BOOT_LOG_DBG(" * re-read image(%d) headers: rc = %d.", BOOT_CURR_IMG(state), rc);
 #ifdef MCUBOOT_BOOTSTRAP
         /* When bootstrapping it's OK to not have image magic in the primary slot */
         if (rc != 0 && (BOOT_CURR_IMG(state) != BOOT_PRIMARY_SLOT ||
@@ -1603,7 +1654,6 @@
 #else
         if (rc != 0) {
 #endif
-
             /* Continue with next image if there is one. */
             BOOT_LOG_WRN("Failed reading image headers; Image=%u",
                     BOOT_CURR_IMG(state));
@@ -1642,6 +1692,8 @@
             /* Swap has finished set to NONE */
             BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
         } else {
+            BOOT_LOG_DBG(" * There was no partial swap, determine swap type.");
+
             /* There was no partial swap, determine swap type. */
             if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
                 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
@@ -1693,6 +1745,7 @@
         /* In that case if slots are not compatible. */
         BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
     }
+    BOOT_LOG_DBG("< boot_prepare_image_for_update");
 }
 
 fih_int
@@ -1716,6 +1769,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_SWAP_STATUS_SECTORS];
+#endif
 
     memset(state, 0, sizeof(struct boot_loader_state));
     has_upgrade = false;
@@ -1747,6 +1803,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.
@@ -1762,6 +1821,7 @@
         assert(rc == 0);
 #endif
 
+        BOOT_LOG_DBG(" * boot_prepare_image_for_update...");
         /* Determine swap type and complete swap if it has been aborted. */
         boot_prepare_image_for_update(state, &bs);
 
@@ -1810,6 +1870,8 @@
         /* Set the previously determined swap type */
         bs.swap_type = BOOT_SWAP_TYPE(state);
 
+        BOOT_LOG_DBG(" * process swap_type = %d", bs.swap_type);
+
         switch (BOOT_SWAP_TYPE(state)) {
         case BOOT_SWAP_TYPE_NONE:
             break;
@@ -1817,6 +1879,7 @@
         case BOOT_SWAP_TYPE_TEST:          /* fallthrough */
         case BOOT_SWAP_TYPE_PERM:          /* fallthrough */
         case BOOT_SWAP_TYPE_REVERT:
+            BOOT_LOG_DBG(" * perform update...", bs.swap_type);
             rc = boot_perform_update(state, &bs);
             assert(rc == 0);
             break;
@@ -1827,6 +1890,7 @@
              * pretending we just reverted back to primary slot.
              */
 #ifndef MCUBOOT_OVERWRITE_ONLY
+            BOOT_LOG_DBG(" * update failed! Set image_ok manually for image(%d)", BOOT_CURR_IMG(state));
             /* image_ok needs to be explicitly set to avoid a new revert. */
             rc = swap_set_image_ok(BOOT_CURR_IMG(state));
             if (rc != 0) {
diff --git a/boot/bootutil/src/swap_misc.c b/boot/bootutil/src/swap_misc.c
index 940d646..42ae7a4 100644
--- a/boot/bootutil/src/swap_misc.c
+++ b/boot/bootutil/src/swap_misc.c
@@ -31,6 +31,9 @@
 MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
 
 #if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
+
+#ifndef MCUBOOT_SWAP_USING_STATUS
+
 int
 swap_erase_trailer_sectors(const struct boot_loader_state *state,
                            const struct flash_area *fap)
@@ -164,7 +167,7 @@
     rc = swap_read_status_bytes(fap, state, bs);
     if (rc == 0) {
         off = boot_swap_info_off(fap);
-        rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
+                rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
         if (rc != 0) {
             return BOOT_EFLASH;
         }
@@ -182,6 +185,7 @@
 
     return rc;
 }
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
 
 int
 swap_set_copy_done(uint8_t image_index)
@@ -228,5 +232,4 @@
     return rc;
 }
 
-
 #endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c
index f2883f6..8fe0b44 100644
--- a/boot/bootutil/src/swap_move.c
+++ b/boot/bootutil/src/swap_move.c
@@ -24,6 +24,9 @@
 #include "bootutil/bootutil.h"
 #include "bootutil_priv.h"
 #include "swap_priv.h"
+#ifdef MCUBOOT_SWAP_USING_STATUS
+#include "swap_status.h"
+#endif
 #include "bootutil/bootutil_log.h"
 
 #include "mcuboot_config/mcuboot_config.h"
@@ -115,6 +118,8 @@
     return rc;
 }
 
+#ifndef MCUBOOT_SWAP_USING_STATUS
+
 int
 swap_read_status_bytes(const struct flash_area *fap,
         struct boot_loader_state *state, struct boot_status *bs)
@@ -181,7 +186,7 @@
     } else if (found_idx < move_entries) {
         bs->op = BOOT_STATUS_OP_MOVE;
         bs->idx = (found_idx  / BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_IDX_0;
-        bs->state = (found_idx % BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_STATE_0;;
+        bs->state = (found_idx % BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_STATE_0;
     } else {
         bs->op = BOOT_STATUS_OP_SWAP;
         bs->idx = ((found_idx - move_entries) / BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_IDX_0;
@@ -208,6 +213,8 @@
     return off;
 }
 
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
+
 int
 boot_slots_compatible(struct boot_loader_state *state)
 {
@@ -219,6 +226,12 @@
 
     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_sec == 0) {
+        BOOT_LOG_WRN("Upgrade disabled for image %d", BOOT_CURR_IMG(state));
+        return 0;
+    }
+
     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");
@@ -442,8 +455,6 @@
     uint32_t sz;
     uint32_t sector_sz;
     uint32_t idx;
-    uint32_t trailer_sz;
-    uint32_t first_trailer_idx;
     uint8_t image_index;
     const struct flash_area *fap_pri;
     const struct flash_area *fap_sec;
@@ -462,6 +473,10 @@
         }
     }
 
+#ifndef MCUBOOT_SWAP_USING_STATUS
+    uint32_t trailer_sz;
+    uint32_t first_trailer_idx;
+
     /*
      * When starting a new swap upgrade, check that there is enough space.
      */
@@ -484,6 +499,7 @@
             return;
         }
     }
+#endif
 
     image_index = BOOT_CURR_IMG(state);
 
diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c
index 55fa61f..9b9228a 100644
--- a/boot/bootutil/src/swap_scratch.c
+++ b/boot/bootutil/src/swap_scratch.c
@@ -24,13 +24,16 @@
 #include "bootutil/bootutil.h"
 #include "bootutil_priv.h"
 #include "swap_priv.h"
+#ifdef MCUBOOT_SWAP_USING_STATUS
+#include "swap_status.h"
+#endif
 #include "bootutil/bootutil_log.h"
 
 #include "mcuboot_config/mcuboot_config.h"
 
 MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
 
-#if !defined(MCUBOOT_SWAP_USING_MOVE)
+#ifndef MCUBOOT_SWAP_USING_MOVE
 
 #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
 /*
@@ -45,7 +48,7 @@
     } while (0)
 #else
 #define BOOT_STATUS_ASSERT(x) ASSERT(x)
-#endif
+#endif /* defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) */
 
 int
 boot_read_image_header(struct boot_loader_state *state, int slot,
@@ -55,12 +58,30 @@
     int area_id;
     int rc;
 
+    int saved_slot = slot;
+
     (void)bs;
 
 #if (BOOT_IMAGE_NUMBER == 1)
     (void)state;
 #endif
 
+    if (bs != NULL) {
+        if (bs->state == BOOT_STATUS_STATE_1) {
+            if (slot == 1) {
+                slot = 2;
+            }
+        }
+        else if (bs->state == BOOT_STATUS_STATE_2) {
+            if (slot == 0) {
+                slot = 1;
+            }
+            else {
+                slot = 2;
+            }
+        }
+    }
+
     area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
     rc = flash_area_open(area_id, &fap);
     if (rc != 0) {
@@ -68,12 +89,43 @@
         goto done;
     }
 
-    rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
-    if (rc != 0) {
+    rc = flash_area_read_is_empty(fap, 0, out_hdr, sizeof *out_hdr);
+    if (rc < 0) {
         rc = BOOT_EFLASH;
         goto done;
     }
 
+    if (rc == 1) {
+        memset(out_hdr, 0, sizeof(*out_hdr));
+    }
+
+    /* We only know where the headers are located when bs is valid */
+    if (bs != NULL && out_hdr->ih_magic != IMAGE_MAGIC) {
+
+        if (bs->state != BOOT_STATUS_STATE_0) {
+
+            flash_area_close(fap);
+
+            area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), saved_slot);
+            rc = flash_area_open(area_id, &fap);
+            if (rc != 0) {
+                rc = BOOT_EFLASH;
+                goto done;
+            }
+
+            rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
+            if (rc < 0) {
+                rc = BOOT_EFLASH;
+                goto done;
+            }
+
+            if (out_hdr->ih_magic != IMAGE_MAGIC) {
+                rc = -1;
+                goto done;
+            }
+        }
+    }
+
     rc = 0;
 
 done:
@@ -82,6 +134,8 @@
 }
 
 #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
+
+#ifndef MCUBOOT_SWAP_USING_STATUS
 /**
  * Reads the status of a partially-completed swap, if any.  This is necessary
  * to recover in case the boot lodaer was reset in the middle of a swap
@@ -165,6 +219,7 @@
     return (bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
            (bs->state - BOOT_STATUS_STATE_0) * elem_sz;
 }
+#endif /* !MCUBOOT_SWAP_USING_STATUS */
 
 /*
  * Slots are compatible when all sectors that store up to to size of the image
@@ -187,9 +242,17 @@
 
     num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
     num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
+
+    if (num_sectors_secondary == 0) {
+        BOOT_LOG_WRN("Upgrade disabled for image %d", BOOT_CURR_IMG(state));
+        return 0;
+    }
+
     if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
         (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
         BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
+        BOOT_LOG_DBG("sectors_primary (%d) or sectors_secondary (%d) > BOOT_MAX_IMG_SECTORS (%d)",
+                     num_sectors_primary, num_sectors_secondary, BOOT_MAX_IMG_SECTORS);
         return 0;
     }
 
@@ -399,7 +462,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.
              */
@@ -500,7 +563,8 @@
     img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
 
     copy_sz = sz;
-    trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
+    // trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); // TODO: fixme for status use case
+    trailer_sz = BOOT_WRITE_SZ(state);
 
     /* sz in this function is always sized on a multiple of the sector size.
      * The check against the start offset of the last sector
@@ -557,8 +621,13 @@
                 assert(rc == 0);
 
                 /* Erase the temporary trailer from the scratch area. */
+#ifndef MCUBOOT_SWAP_USING_STATUS
                 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
                 assert(rc == 0);
+#else
+                rc = swap_erase_trailer_sectors(state, fap_scratch);
+                assert(rc == 0);
+#endif
             }
         }
 
@@ -655,8 +724,16 @@
         BOOT_STATUS_ASSERT(rc == 0);
 
         if (erase_scratch) {
+#ifndef MCUBOOT_SWAP_USING_STATUS
             rc = boot_erase_region(fap_scratch, 0, sz);
             assert(rc == 0);
+#else
+            rc = swap_erase_trailer_sectors(state, fap_scratch);
+            assert(rc == 0);
+
+            rc = swap_erase_trailer_sectors(state, fap_secondary_slot);  // TODO: check if needed and fix
+            assert(rc == 0);
+#endif
         }
     }
 
@@ -709,6 +786,8 @@
         last_idx_secondary_slot++;
     }
 
+    bs->op = BOOT_STATUS_OP_SWAP;
+
     swap_idx = 0;
     while (last_sector_idx >= 0) {
         sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
diff --git a/boot/bootutil/src/swap_status.c b/boot/bootutil/src/swap_status.c
new file mode 100644
index 0000000..6b9d33b
--- /dev/null
+++ b/boot/bootutil/src/swap_status.c
@@ -0,0 +1,164 @@
+/*
+ * 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_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
+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 = 0;
+    uint8_t last_status = 0xff;
+    int max_entries;
+    int32_t found_idx;
+    bool found;
+    bool invalid;
+    int rc;
+    int i;
+    (void)state;
+
+    BOOT_LOG_DBG("> STATUS: swap_read_status_bytes: fa_id = %d", fap->fa_id);
+
+    if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
+        max_entries = 1;
+    } else {
+        max_entries = BOOT_STATUS_MAX_ENTRIES;
+    }
+
+    off = boot_status_off(fap);
+
+    found = false;
+    found_idx = -1;
+    invalid = false;
+
+    for (i = 0; i < max_entries; i++) {
+        rc = swap_status_retrieve(fap->fa_id, off + i, &status, 1);
+        if (rc < 0) {
+            return BOOT_EFLASH;
+        }
+
+        // if (status != flash_area_erased_val(fap)) { // TODO: fixup for external memory fap's
+        if (status == 0) {
+            if (found && (found_idx == -1)) {
+                found_idx = i;
+            }
+        } else {
+            last_status = status;
+
+            if (!found) {
+                found = true;
+            } else if (found_idx > 0) {
+                invalid = true;
+                break;
+            }
+        }
+    }
+
+    if (invalid) {
+        /* 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
+    }
+
+    if (found_idx == -1) {
+        /* no swap status found; nothing to do */
+    }
+    else {
+        uint8_t image_index = BOOT_CURR_IMG(state);
+        rc = boot_read_swap_size((int32_t)image_index, &bs->swap_size);
+        if (rc < 0) {
+            return BOOT_EFLASH;
+        }
+
+#ifdef MCUBOOT_SWAP_USING_MOVE
+        /* get image size in blocks */
+        uint32_t move_entries = bs->swap_size / state->write_sz + (uint32_t)(bs->swap_size % state->write_sz != 0u);
+
+        if (found_idx < (int32_t)move_entries) {
+            /* continue move sector up operation */
+            bs->op = (uint8_t)BOOT_STATUS_OP_MOVE;
+            bs->idx = (uint32_t)found_idx;
+            bs->state = (uint8_t)last_status;
+        } else
+#endif /* MCUBOOT_SWAP_USING_MOVE */
+        {
+            /* resume swap sectors operation */
+            last_status++;
+            if (last_status > BOOT_STATUS_STATE_COUNT) {
+                last_status = BOOT_STATUS_STATE_0;
+                found_idx++;
+            }
+
+            bs->op = (uint8_t)BOOT_STATUS_OP_SWAP;
+            bs->idx = (uint32_t)found_idx;
+            bs->state = (uint8_t)last_status;
+        }
+    }
+
+    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 = (bs->idx - BOOT_STATUS_IDX_0) * (uint32_t)elem_sz;
+
+    return off;
+}
+#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
+
+#endif /* MCUBOOT_SWAP_USING_STATUS */
diff --git a/boot/bootutil/src/swap_status.h b/boot/bootutil/src/swap_status.h
new file mode 100644
index 0000000..dc27d64
--- /dev/null
+++ b/boot/bootutil/src/swap_status.h
@@ -0,0 +1,167 @@
+/*
+ * 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 H_SWAP_STATUS_H_
+#define H_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
+
+#define BOOT_LOG_SWAP_STATE_M(area, state)                            \
+    BOOT_LOG_DBG("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, "   \
+                 "image_ok=0x%x",                                   \
+                 (area),                                            \
+                 ((state)->magic == (uint8_t)BOOT_MAGIC_GOOD ? "good" :\
+                  (state)->magic == (uint8_t)BOOT_MAGIC_UNSET ? "unset" :\
+                  "bad"),                                           \
+                 (state)->swap_type,                                \
+                 (state)->copy_done,                                \
+                 (state)->image_ok)
+
+#define BOOT_SET_SWAP_INFO_M(swap_info, image, type)  {                          \
+                                                    assert((int)((image) < 0xFu));     \
+                                                    assert((int)((type)  < 0xFu));     \
+                                                    (swap_info) = (image) << 4u \
+                                                                | (type);      \
+                                                    }
+
+#define BOOT_GET_SWAP_TYPE_M(swap_info)    ((swap_info) & 0x0Fu)
+#define BOOT_GET_IMAGE_NUM_M(swap_info)    ((swap_info) >> 4u)
+
+extern const uint32_t stat_part_magic[1];
+
+#define BOOT_SWAP_STATUS_MAGIC       (0xDEADBEAFu)
+
+#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-1u)/BOOT_SWAP_STATUS_PAYLD_SZ) + 1u)
+
+/*
+    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 - 1u)/BOOT_SWAP_STATUS_PAYLD_SZ) + 1u)
+
+/* 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       2UL
+
+#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_SZ_SCRATCH 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 /* H_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..c8f8f95
--- /dev/null
+++ b/boot/bootutil/src/swap_status_misc.c
@@ -0,0 +1,718 @@
+/*
+ * 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_find_status(int image_index, const struct flash_area **fap);
+
+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 != (uint8_t)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 ((uint32_t)BOOT_SWAP_STATUS_D_SIZE_RAW - (uint32_t)BOOT_MAGIC_SZ);
+}
+
+uint32_t
+boot_image_ok_off(const struct flash_area *fap)
+{
+    return (uint32_t)(boot_magic_off(fap) - 1u);
+}
+
+uint32_t
+boot_copy_done_off(const struct flash_area *fap)
+{
+    return (uint32_t)(boot_image_ok_off(fap) - 1u);
+}
+
+uint32_t
+boot_swap_info_off(const struct flash_area *fap)
+{
+    return (uint32_t)(boot_copy_done_off(fap) - 1u);
+}
+
+uint32_t
+boot_swap_size_off(const struct flash_area *fap)
+{
+    return (uint32_t)(boot_swap_info_off(fap) - 4u);
+}
+
+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)
+{
+#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
+    /* suggest encryption key is also stored in status partition */
+    return (uint32_t)(boot_swap_size_off(fap) - (uint32_t)((slot + 1u) * (uint32_t)BOOT_ENC_TLV_SIZE));
+#else
+    return (uint32_t)(boot_swap_size_off(fap) - (uint32_t)((slot + 1u) * (uint32_t)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, (uint8_t *)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);
+#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
+    rc = swap_status_update(fap->fa_id, off,
+                            (uint8_t *) bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
+#else
+    rc = swap_status_update(fap->fa_id, off,
+                            (uint8_t *) bs->enckey[slot], BOOT_ENC_KEY_SIZE);
+#endif
+   if (rc != 0) {
+       return BOOT_EFLASH;
+   }
+
+    return 0;
+}
+
+int
+boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
+{
+    uint32_t off;
+    const struct flash_area *fap;
+#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
+    int i;
+#endif
+    int rc;
+
+    rc = boot_find_status(image_index, &fap);
+    if (rc == 0) {
+        off = boot_enc_key_off(fap, slot);
+#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
+        rc = swap_status_retrieve(fap->fa_id, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
+        if (rc == 0) {
+            for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
+                if (bs->enctlv[slot][i] != 0xff) {
+                    break;
+                }
+            }
+            /* Only try to decrypt non-erased TLV metadata */
+            if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
+                rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]);
+            }
+        }
+#else
+        rc = swap_status_retrieve(fap->fa_id, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
+#endif
+        flash_area_close(fap);
+    }
+
+    return rc;
+}
+#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,
+                            (uint8_t *) 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 = NULL;
+    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!
+     */
+
+#ifdef MCUBOOT_SWAP_USING_SCRATCH
+    if (bs->use_scratch) {
+        /* Write to scratch status. */
+        area_id = FLASH_AREA_IMAGE_SCRATCH;
+    } else
+#endif
+    {
+        /* Write to the primary slot. */
+        area_id = (int)FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
+    }
+
+    rc = flash_area_open((uint8_t)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->state;
+
+    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 = 0U;
+    uint8_t swap_info = 0U;
+    int rc;
+    uint32_t erase_trailer = 0;
+
+    const struct flash_area *fap_stat = NULL;
+
+    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 = (uint8_t)boot_magic_decode(magic);
+                    /* put magic to status partition for upgrade slot*/
+                    if (state->magic == (uint32_t)BOOT_MAGIC_GOOD) {
+                        rc = swap_status_update(fap->fa_id, off,
+                                        (uint8_t *) magic, BOOT_MAGIC_SZ);
+                    }
+                    if (rc < 0) {
+                        return BOOT_EFLASH;
+                    } else {
+                        erase_trailer = 1;
+                    }
+                }
+        }
+    } else {
+        state->magic = (uint8_t)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;
+    }
+    if (rc == 1 || state->swap_type > (uint8_t)BOOT_SWAP_TYPE_REVERT) {
+        state->swap_type = (uint8_t)BOOT_SWAP_TYPE_NONE;
+        state->image_num = 0;
+    }
+    else {
+        /* Extract the swap type and image number */
+        state->swap_type = (uint8_t)BOOT_GET_SWAP_TYPE_M(swap_info);
+        state->image_num = (uint8_t)BOOT_GET_IMAGE_NUM_M(swap_info);
+    }
+
+    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 = (uint8_t)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 == (uint8_t)BOOT_FLAG_SET)
+                    process_image_ok = 1;
+            }
+            break;
+            case FLASH_AREA_IMAGE_1:
+            case FLASH_AREA_IMAGE_3:
+            {
+                process_image_ok = 1;
+            }
+            break;
+            case FLASH_AREA_IMAGE_SCRATCH:
+            {
+                BOOT_LOG_DBG(" * selected SCRATCH area, copy_done = %d", state->copy_done);
+                {
+                    if (state->copy_done == (uint8_t)BOOT_FLAG_SET)
+                        process_image_ok = 1;
+                }
+            }
+            break;
+            default:
+            {
+                return BOOT_EFLASH;
+            }
+            break;
+        }
+        if (process_image_ok != 0u) {
+            trailer_off = fap->fa_size - (uint8_t)BOOT_MAGIC_SZ - (uint8_t)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 = (uint8_t)boot_flag_decode(state->image_ok);
+
+                /* put img_ok to status partition for upgrade slot */
+                if (state->image_ok != (uint8_t)BOOT_FLAG_BAD) {
+                    rc = swap_status_update(fap->fa_id, off,
+                                &state->image_ok, sizeof state->image_ok);
+                }
+                if (rc < 0) {
+                    return BOOT_EFLASH;
+                }
+
+                /* mark img trailer needs to be erased */
+                erase_trailer = 1;
+            }
+        }
+    } else {
+       state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
+    }
+
+    if ((erase_trailer != 0u) && (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH)) {
+        /* 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] = {0};
+    uint32_t off;
+
+    /* the status is always in status partition */
+    uint8_t area = FLASH_AREA_IMAGE_PRIMARY((uint32_t)image_index);
+    int rc = -1;
+
+    /*
+     * 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) {
+        rc = memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ);
+    }
+
+    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 sub_offs, trailer_offs;
+    uint32_t sz;
+    uint8_t fa_id_primary;
+    uint8_t fa_id_secondary;
+    uint8_t image_index;
+    int rc;
+    (void)state;
+
+    BOOT_LOG_INF("Erasing trailer; fa_id=%d", fap->fa_id);
+    /* trailer is located in status-partition */
+    const struct flash_area *fap_stat = NULL;
+
+    rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
+    if (rc != 0) {
+        return BOOT_EFLASH;
+    }
+
+    if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH)
+    {
+        image_index = BOOT_CURR_IMG(state);
+        fa_id_primary = (uint8_t)flash_area_id_from_multi_image_slot((int32_t)image_index,
+                BOOT_PRIMARY_SLOT);
+        fa_id_secondary = (uint8_t)flash_area_id_from_multi_image_slot((int32_t)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 = (uint32_t)swap_status_init_offset(fap->fa_id);
+
+    /* delete starting from last sector and moving to beginning */
+    /* calculate last sector of status sub-area */
+    sz = (uint32_t)BOOT_SWAP_STATUS_SIZE;
+
+    rc = flash_area_erase(fap_stat, sub_offs, sz);
+    assert((int)(rc == 0));
+
+    if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH)
+    {
+        /*
+         * 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((int32_t)FLASH_AREA_IMAGE_SECONDARY(image_index),
+            &swap_state);
+    assert((int)(rc == 0));
+
+    if (bs->swap_type != (uint8_t)BOOT_SWAP_TYPE_NONE) {
+        rc = boot_write_swap_info(fap, bs->swap_type, image_index);
+        assert((int)(rc == 0));
+    }
+
+    if (swap_state.image_ok == (uint8_t)BOOT_FLAG_SET) {
+        rc = boot_write_image_ok(fap);
+        assert((int)(rc == 0));
+    }
+
+    rc = boot_write_swap_size(fap, bs->swap_size);
+    assert((int)(rc == 0));
+
+#ifdef MCUBOOT_ENC_IMAGES
+    rc = boot_write_enc_key(fap, 0, bs);
+    assert((int)(rc == 0));
+
+    rc = boot_write_enc_key(fap, 1, bs);
+    assert((int)(rc == 0));
+#endif
+
+    rc = boot_write_magic(fap);
+    assert((int)(rc == 0));
+
+    return 0;
+}
+
+int
+swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
+{
+    const struct flash_area *fap = NULL;
+    const struct flash_area *fap_stat = NULL;
+    uint32_t off;
+    uint8_t swap_info = 0;
+    int area_id;
+    int rc = 0;
+
+    bs->source = swap_status_source(state);
+
+    if (bs->source == BOOT_STATUS_SOURCE_NONE) {
+        return 0;
+    }
+
+    if (bs->source ==  BOOT_STATUS_SOURCE_PRIMARY_SLOT) {
+        area_id = (int32_t)FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
+    } else if (bs->source ==  BOOT_STATUS_SOURCE_SCRATCH) {
+        area_id = FLASH_AREA_IMAGE_SCRATCH;
+    } else {
+        return BOOT_EBADARGS;
+    }
+
+    rc = flash_area_open((uint8_t)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((uint8_t)area_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;
+        }
+
+        if (rc == 1) {
+            BOOT_SET_SWAP_INFO_M(swap_info, 0u, (uint8_t)BOOT_SWAP_TYPE_NONE);
+            rc = 0;
+        }
+
+        /* Extract the swap type info */
+        bs->swap_type = BOOT_GET_SWAP_TYPE_M(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..a2899a9
--- /dev/null
+++ b/boot/bootutil/src/swap_status_part.c
@@ -0,0 +1,404 @@
+/*
+ * 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
+
+#define IMAGE_0_STATUS_OFFS        0
+#define IMAGE_0_STATUS_SIZE        (BOOT_SWAP_STATUS_SIZE)
+
+#define IMAGE_1_STATUS_OFFS        (IMAGE_0_STATUS_OFFS + IMAGE_0_STATUS_SIZE)
+#define IMAGE_1_STATUS_SIZE        (BOOT_SWAP_STATUS_SIZE)
+
+#define SCRATCH_STATUS_OFFS        (IMAGE_1_STATUS_OFFS + BOOT_SWAP_STATUS_SIZE)
+#ifdef MCUBOOT_SWAP_USING_SCRATCH
+#define SCRATCH_STATUS_SIZE        (BOOT_SWAP_STATUS_SIZE)
+#else
+#define SCRATCH_STATUS_SIZE        0
+#endif
+
+#if (MCUBOOT_IMAGE_NUMBER == 2)
+#define IMAGE_2_STATUS_OFFS        (SCRATCH_STATUS_OFFS + SCRATCH_STATUS_SIZE)
+#define IMAGE_2_STATUS_SIZE        (BOOT_SWAP_STATUS_SIZE)
+
+#define IMAGE_3_STATUS_OFFS        (IMAGE_2_STATUS_OFFS + IMAGE_2_STATUS_SIZE)
+#define IMAGE_3_STATUS_SIZE        (BOOT_SWAP_STATUS_SIZE)
+#endif
+
+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 = -1;
+    /* calculate an offset caused by area type: primary_x/secondary_x */
+    switch (area_id) {
+    case FLASH_AREA_IMAGE_0:
+        offset = (int)IMAGE_0_STATUS_OFFS;
+        break;
+    case FLASH_AREA_IMAGE_1:
+        offset = (int)IMAGE_1_STATUS_OFFS;
+        break;
+#ifdef MCUBOOT_SWAP_USING_SCRATCH
+    case FLASH_AREA_IMAGE_SCRATCH:
+        offset = (int)SCRATCH_STATUS_OFFS;
+        break;
+#endif
+#if (MCUBOOT_IMAGE_NUMBER == 2)
+    case FLASH_AREA_IMAGE_2:
+        offset = (int)IMAGE_2_STATUS_OFFS;
+        break;
+    case FLASH_AREA_IMAGE_3:
+        offset = (int)IMAGE_3_STATUS_OFFS;
+        break;
+#endif
+    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;
+    uint32_t data_offset = 0;
+    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 = NULL;
+
+    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 = (int32_t)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 = (int32_t)(BOOT_SWAP_STATUS_MULT-1U);
+        *copy_counter = 0;
+        /* return all erased values */
+        (void)memset(data, (int32_t)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);
+	        if (rc != 0) {
+	            return BOOT_EFLASH;
+	        }
+        }
+    }
+    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 + 1U;
+    uint32_t next_crc;
+
+    uint8_t buff[BOOT_SWAP_STATUS_ROW_SZ];
+
+    const struct flash_area *fap_stat = NULL;
+
+    rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
+    if (rc != 0) {
+        return BOOT_EFLASH;
+    }
+
+    /* copy data into buffer */
+    (void)memcpy(buff, data, BOOT_SWAP_STATUS_PAYLD_SZ);
+    /* append next counter to whole record row */
+    (void)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 */
+    (void)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 */
+    (void)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 - 1U)) {
+        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));
+
+    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 */
+    assert ((int)((offs + len) <= BOOT_SWAP_STATUS_D_SIZE_RAW));
+
+    /* pre-calculate sub-area offset */
+    init_offs = swap_status_init_offset(targ_area_id);
+    assert ((int)(init_offs >= 0));
+
+    /* will start from it
+     * this will be write-aligned */
+    rec_offs = (uint32_t)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 = (uint32_t)length;
+        }
+        (void)memcpy((void *)&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 ((int)(rc == 0));
+
+        /* proceed to next record */
+        length -= (int32_t)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 ((int)((offs + len) <= BOOT_SWAP_STATUS_D_SIZE_RAW));
+
+    /* pre-calculate sub-area offset */
+    init_offs = swap_status_init_offset(target_area_id);
+    assert ((int)(init_offs >= 0));
+
+    /* will start from it
+     * this will be write-aligned */
+    rec_offs = (uint32_t)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 = (uint32_t)length;
+        }
+        (void)memcpy(&((uint8_t *)data)[data_idx], &buff[buff_idx], copy_sz);
+        buff_idx = 0;
+
+        /* proceed to next record */
+        length -= (int32_t)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 */