Implement new swap scheme for devices with large erase size using scratch with status area
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 */