blob: 7f7e065cba3ce627b8743f7e159c41ecfeb08002 [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
48#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
49int
50swap_read_status_bytes(const struct flash_area *fap,
51 struct boot_loader_state *state, struct boot_status *bs)
52{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030053 const struct flash_area *fap_stat = NULL;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020054 uint32_t off;
55 uint8_t status = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +030056 uint8_t erased_val;
57 uint8_t last_status;
58 uint32_t max_entries;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020059 int32_t found_idx;
60 bool found;
61 bool invalid;
62 int rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +030063 uint32_t i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020064 (void)state;
65
Roman Okhrimenko977b3752022-03-31 14:40:48 +030066 BOOT_LOG_DBG("> STATUS: swap_read_status_bytes: fa_id = %u", (unsigned)fap->fa_id);
67
68 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
69 if (rc != 0) {
70 return -1;
71 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020072
73 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
74 max_entries = 1;
75 } else {
76 max_entries = BOOT_STATUS_MAX_ENTRIES;
77 }
78
Roman Okhrimenko977b3752022-03-31 14:40:48 +030079 erased_val = flash_area_erased_val(fap_stat);
80
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020081 off = boot_status_off(fap);
82
83 found = false;
84 found_idx = -1;
85 invalid = false;
Roman Okhrimenko977b3752022-03-31 14:40:48 +030086 last_status = erased_val;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020087
88 for (i = 0; i < max_entries; i++) {
89 rc = swap_status_retrieve(fap->fa_id, off + i, &status, 1);
90 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030091 flash_area_close(fap_stat);
92 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020093 }
94
Roman Okhrimenko977b3752022-03-31 14:40:48 +030095 if (status == erased_val) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020096 if (found && (found_idx == -1)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030097 found_idx = (int)i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020098 }
99 } else {
100 last_status = status;
101
102 if (!found) {
103 found = true;
104 } else if (found_idx > 0) {
105 invalid = true;
106 break;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300107 } else {
108 /* No action required */
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200109 }
110 }
111 }
112
113 if (invalid) {
114 /* This means there was an error writing status on the last
115 * swap. Tell user and move on to validation!
116 */
117#if !defined(__BOOTSIM__)
118 BOOT_LOG_ERR("Detected inconsistent status!");
119#endif
120
121#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
122 /* With validation of the primary slot disabled, there is no way
123 * to be sure the swapped primary slot is OK, so abort!
124 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300125 FIH_PANIC;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200126#endif
127 }
128
129 if (found_idx == -1) {
130 /* no swap status found; nothing to do */
131 }
132 else {
133 uint8_t image_index = BOOT_CURR_IMG(state);
134 rc = boot_read_swap_size((int32_t)image_index, &bs->swap_size);
135 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300136 flash_area_close(fap_stat);
137 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200138 }
139
140#ifdef MCUBOOT_SWAP_USING_MOVE
141 /* get image size in blocks */
142 uint32_t move_entries = bs->swap_size / state->write_sz + (uint32_t)(bs->swap_size % state->write_sz != 0u);
143
144 if (found_idx < (int32_t)move_entries) {
145 /* continue move sector up operation */
146 bs->op = (uint8_t)BOOT_STATUS_OP_MOVE;
147 bs->idx = (uint32_t)found_idx;
148 bs->state = (uint8_t)last_status;
149 } else
150#endif /* MCUBOOT_SWAP_USING_MOVE */
151 {
152 /* resume swap sectors operation */
153 last_status++;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300154 if (last_status > (uint8_t)BOOT_STATUS_STATE_COUNT) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200155 last_status = BOOT_STATUS_STATE_0;
156 found_idx++;
157 }
158
159 bs->op = (uint8_t)BOOT_STATUS_OP_SWAP;
160 bs->idx = (uint32_t)found_idx;
161 bs->state = (uint8_t)last_status;
162 }
163 }
164
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300165 flash_area_close(fap_stat);
166
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200167 return 0;
168}
169
170/* this is internal offset in swap status area */
171uint32_t
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300172boot_status_internal_off(const struct boot_status *bs, uint32_t elem_sz)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200173{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300174 uint32_t off = (bs->idx - BOOT_STATUS_IDX_0) * elem_sz;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200175
176 return off;
177}
178#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
179
180#endif /* MCUBOOT_SWAP_USING_STATUS */