blob: d5be7c4c965cf0bc7255d86ef847f69d50549a9d [file] [log] [blame]
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001/*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2017-2019 Linaro LTD
5 * Copyright (c) 2016-2019 JUUL Labs
6 * Copyright (c) 2019-2020 Arm Limited
7 * Copyright (c) 2020 Cypress Semiconductors
8 *
9 * Original license:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one
12 * or more contributor license agreements. See the NOTICE file
13 * distributed with this work for additional information
14 * regarding copyright ownership. The ASF licenses this file
15 * to you under the Apache License, Version 2.0 (the
16 * "License"); you may not use this file except in compliance
17 * with the License. You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing,
22 * software distributed under the License is distributed on an
23 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
24 * KIND, either express or implied. See the License for the
25 * specific language governing permissions and limitations
26 * under the License.
27 */
28
29#include <assert.h>
30#include <stddef.h>
31#include <stdbool.h>
32#include <inttypes.h>
33#include <stdlib.h>
34#include <string.h>
35#include "bootutil/bootutil.h"
36#include "bootutil_priv.h"
37#include "swap_priv.h"
38#include "swap_status.h"
39#include "bootutil/bootutil_log.h"
Roman Okhrimenko977b3752022-03-31 14:40:48 +030040#include "bootutil/fault_injection_hardening.h"
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020041
42#include "mcuboot_config/mcuboot_config.h"
43
44MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
45
46#ifdef MCUBOOT_SWAP_USING_STATUS
47
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020048int
49swap_read_status_bytes(const struct flash_area *fap,
50 struct boot_loader_state *state, struct boot_status *bs)
51{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030052 const struct flash_area *fap_stat = NULL;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020053 uint32_t off;
54 uint8_t status = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +030055 uint8_t erased_val;
56 uint8_t last_status;
57 uint32_t max_entries;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020058 int32_t found_idx;
59 bool found;
60 bool invalid;
61 int rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +030062 uint32_t i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020063 (void)state;
64
Roman Okhrimenko977b3752022-03-31 14:40:48 +030065 BOOT_LOG_DBG("> STATUS: swap_read_status_bytes: fa_id = %u", (unsigned)fap->fa_id);
66
67 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
68 if (rc != 0) {
69 return -1;
70 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020071
72 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
73 max_entries = 1;
74 } else {
75 max_entries = BOOT_STATUS_MAX_ENTRIES;
76 }
77
Roman Okhrimenko977b3752022-03-31 14:40:48 +030078 erased_val = flash_area_erased_val(fap_stat);
79
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020080 off = boot_status_off(fap);
81
82 found = false;
83 found_idx = -1;
84 invalid = false;
Roman Okhrimenko977b3752022-03-31 14:40:48 +030085 last_status = erased_val;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020086
87 for (i = 0; i < max_entries; i++) {
88 rc = swap_status_retrieve(fap->fa_id, off + i, &status, 1);
89 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030090 flash_area_close(fap_stat);
91 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020092 }
93
Roman Okhrimenko977b3752022-03-31 14:40:48 +030094 if (status == erased_val) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020095 if (found && (found_idx == -1)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030096 found_idx = (int)i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020097 }
98 } else {
99 last_status = status;
100
101 if (!found) {
102 found = true;
103 } else if (found_idx > 0) {
104 invalid = true;
105 break;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300106 } else {
107 /* No action required */
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200108 }
109 }
110 }
111
112 if (invalid) {
113 /* This means there was an error writing status on the last
114 * swap. Tell user and move on to validation!
115 */
116#if !defined(__BOOTSIM__)
117 BOOT_LOG_ERR("Detected inconsistent status!");
118#endif
119
120#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
121 /* With validation of the primary slot disabled, there is no way
122 * to be sure the swapped primary slot is OK, so abort!
123 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300124 FIH_PANIC;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200125#endif
126 }
127
128 if (found_idx == -1) {
129 /* no swap status found; nothing to do */
130 }
131 else {
132 uint8_t image_index = BOOT_CURR_IMG(state);
133 rc = boot_read_swap_size((int32_t)image_index, &bs->swap_size);
134 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300135 flash_area_close(fap_stat);
136 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200137 }
138
139#ifdef MCUBOOT_SWAP_USING_MOVE
140 /* get image size in blocks */
141 uint32_t move_entries = bs->swap_size / state->write_sz + (uint32_t)(bs->swap_size % state->write_sz != 0u);
142
143 if (found_idx < (int32_t)move_entries) {
144 /* continue move sector up operation */
145 bs->op = (uint8_t)BOOT_STATUS_OP_MOVE;
146 bs->idx = (uint32_t)found_idx;
147 bs->state = (uint8_t)last_status;
148 } else
149#endif /* MCUBOOT_SWAP_USING_MOVE */
150 {
151 /* resume swap sectors operation */
152 last_status++;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300153 if (last_status > (uint8_t)BOOT_STATUS_STATE_COUNT) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200154 last_status = BOOT_STATUS_STATE_0;
155 found_idx++;
156 }
157
158 bs->op = (uint8_t)BOOT_STATUS_OP_SWAP;
159 bs->idx = (uint32_t)found_idx;
160 bs->state = (uint8_t)last_status;
161 }
162 }
163
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300164 flash_area_close(fap_stat);
165
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200166 return 0;
167}
168
169/* this is internal offset in swap status area */
170uint32_t
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300171boot_status_internal_off(const struct boot_status *bs, uint32_t elem_sz)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200172{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300173 return (bs->idx - BOOT_STATUS_IDX_0) * elem_sz;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200174}
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200175
176#endif /* MCUBOOT_SWAP_USING_STATUS */