blob: 6299c8ae4bdd353e7e69a252eba48e55acc1191e [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 "bootutil/bootutil_log.h"
39
40#include "swap_status.h"
41
42#include "mcuboot_config/mcuboot_config.h"
43
44MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
45
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030046#define ERROR_VALUE (UINT32_MAX)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020047
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030048#if defined(MCUBOOT_SWAP_USING_STATUS)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020049
50static int
51boot_find_status(int image_index, const struct flash_area **fap);
52
53static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030054boot_magic_decode(const union boot_img_magic_t *magic_p)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020055{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030056 if (memcmp((const void*)magic_p->val, (const void *)&boot_img_magic.val, BOOT_MAGIC_SZ) == 0) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020057 return BOOT_MAGIC_GOOD;
58 }
59 return BOOT_MAGIC_BAD;
60}
61
62static int
63boot_flag_decode(uint8_t flag)
64{
65 if (flag != (uint8_t)BOOT_FLAG_SET) {
66 return BOOT_FLAG_BAD;
67 }
68 return BOOT_FLAG_SET;
69}
70
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020071/* Offset Section */
72static inline uint32_t
73boot_magic_off(const struct flash_area *fap)
74{
75 (void)fap;
Roman Okhrimenko977b3752022-03-31 14:40:48 +030076 return (uint32_t)BOOT_SWAP_STATUS_D_SIZE_RAW - (uint32_t)BOOT_MAGIC_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020077}
78
79uint32_t
80boot_image_ok_off(const struct flash_area *fap)
81{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030082 return boot_magic_off(fap) - BOOT_SWAP_STATUS_IMG_OK_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020083}
84
85uint32_t
86boot_copy_done_off(const struct flash_area *fap)
87{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030088 return boot_image_ok_off(fap) - BOOT_SWAP_STATUS_COPY_DONE_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020089}
90
91uint32_t
92boot_swap_info_off(const struct flash_area *fap)
93{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030094 return boot_copy_done_off(fap) - BOOT_SWAP_STATUS_SWAPINF_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020095}
96
97uint32_t
98boot_swap_size_off(const struct flash_area *fap)
99{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300100 return boot_swap_info_off(fap) - BOOT_SWAP_STATUS_SWAPSZ_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200101}
102
103uint32_t
104boot_status_off(const struct flash_area *fap)
105{
106 (void)fap;
107 /* this offset is equal to 0, because swap status fields
108 in this implementation count from the start of partition */
109 return 0;
110}
111
112#ifdef MCUBOOT_ENC_IMAGES
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300113/**
114 * @returns ERROR_VALUE on error, otherwise result.
115 */
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200116static inline uint32_t
117boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
118{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300119 uint32_t slot_offset;
120 uint32_t res = ERROR_VALUE;
121 uint32_t boot_swap_size_offset = boot_swap_size_off(fap);
122
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200123#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
124 /* suggest encryption key is also stored in status partition */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300125 slot_offset = ((uint32_t)slot + 1UL) * (uint32_t)BOOT_ENC_TLV_SIZE;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200126#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300127 slot_offset = ((uint32_t)slot + 1UL) * (uint32_t)BOOT_ENC_KEY_SIZE;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200128#endif
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300129
130 if (boot_swap_size_offset >= slot_offset)
131 {
132 res = boot_swap_size_offset - slot_offset;
133 }
134 return res;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200135}
136#endif
137
138/**
139 * Write trailer data; status bytes, swap_size, etc
140 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300141 * @returns 0 on success, -1 on error.
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200142 */
143int
144boot_write_trailer(const struct flash_area *fap, uint32_t off,
145 const uint8_t *inbuf, uint8_t inlen)
146{
147 int rc;
148
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300149 /* copy status part trailer to primary image before set copy_done flag */
150 if (boot_copy_done_off(fap) == off &&
151 fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(0u) &&
152 BOOT_SWAP_STATUS_COPY_DONE_SZ == inlen) {
153
154 BOOT_LOG_DBG("copy status part trailer to primary image slot");
155 rc = swap_status_to_image_trailer(fap);
156 if (rc != 0) {
157 BOOT_LOG_ERR("trailer copy failed");
158 return -1;
159 }
160 }
161
162 rc = swap_status_update(fap->fa_id, off, inbuf, inlen);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200163
164 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300165 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200166 }
167 return rc;
168}
169
170#ifdef MCUBOOT_ENC_IMAGES
171int
172boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
173 const struct boot_status *bs)
174{
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200175 int rc;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300176 uint32_t off = boot_enc_key_off(fap, slot);
177 if (ERROR_VALUE == off)
178 {
179 return -1;
180 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200181#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
182 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300183 bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200184#else
185 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300186 bs->enckey[slot], BOOT_ENC_KEY_SIZE);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200187#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300188 if (rc != 0) {
189 return -1;
190 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200191
192 return 0;
193}
194
195int
196boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
197{
198 uint32_t off;
199 const struct flash_area *fap;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200200 int rc;
201
202 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300203 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200204 off = boot_enc_key_off(fap, slot);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300205 if (ERROR_VALUE == off)
206 {
207 return -1;
208 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200209#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
210 rc = swap_status_retrieve(fap->fa_id, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300211 if (0 == rc) {
212 uint8_t aes_iv[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
213
214 /* Only try to decrypt initialized TLV metadata */
215 if (!bootutil_buffer_is_filled(bs->enctlv[slot],
216 BOOT_UNINITIALIZED_TLV_FILL,
217 BOOT_ENC_TLV_ALIGN_SIZE)) {
218 rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot], 0, aes_iv);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200219 }
220 }
221#else
222 rc = swap_status_retrieve(fap->fa_id, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
223#endif
224 flash_area_close(fap);
225 }
226
227 return rc;
228}
229#endif /* MCUBOOT_ENC_IMAGES */
230
231/* Write Section */
232int
233boot_write_magic(const struct flash_area *fap)
234{
235 uint32_t off;
236 int rc;
237
238 off = boot_magic_off(fap);
239
240 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300241 (const uint8_t *)&boot_img_magic, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200242
243 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300244 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200245 }
246 return 0;
247}
248
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200249/**
250 * Writes the supplied boot status to the flash file system. The boot status
251 * contains the current state of an in-progress image copy operation.
252 *
253 * @param bs The boot status to write.
254 *
255 * @return 0 on success; nonzero on failure.
256 */
257int
258boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
259{
260 const struct flash_area *fap = NULL;
261 uint32_t off;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300262 uint8_t area_id;
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000263 uint8_t tmp_state;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200264 int rc;
265 (void)state;
266
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300267 if (bs->idx < BOOT_STATUS_IDX_0) {
268 return BOOT_EFLASH;
269 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200270 /* NOTE: The first sector copied (that is the last sector on slot) contains
271 * the trailer. Since in the last step the primary slot is erased, the
272 * first two status writes go to the scratch which will be copied to
273 * the primary slot!
274 */
275
276#ifdef MCUBOOT_SWAP_USING_SCRATCH
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300277 if (bs->use_scratch != 0U) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200278 /* Write to scratch status. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300279 area_id = (uint8_t)FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200280 } else
281#endif
282 {
283 /* Write to the primary slot. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300284 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200285 }
286
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300287 rc = flash_area_open(area_id, &fap);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200288 if (rc != 0) {
289 rc = BOOT_EFLASH;
290 goto done;
291 }
292 off = boot_status_off(fap) + boot_status_internal_off(bs, 1);
293
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000294 tmp_state = bs->state;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200295
296 rc = swap_status_update(fap->fa_id, off, &tmp_state, 1);
297 if (rc != 0) {
298 rc = BOOT_EFLASH;
299 goto done;
300 }
301
302done:
303 flash_area_close(fap);
304
305 return rc;
306}
307
308int
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200309boot_read_swap_state(const struct flash_area *fap,
310 struct boot_swap_state *state)
311{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300312 union boot_img_magic_t magic = {0U};
313 uint32_t off = 0U;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200314 uint32_t trailer_off = 0U;
315 uint8_t swap_info = 0U;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300316 int rc = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200317 uint32_t erase_trailer = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300318 bool buf_is_clean = false;
319 bool is_primary = false;
320 bool is_secondary = false;
321 uint32_t i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200322
323 const struct flash_area *fap_stat = NULL;
324
325 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
326 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300327 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200328 }
329
330 off = boot_magic_off(fap);
331 /* retrieve value for magic field from status partition area */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300332 rc = swap_status_retrieve(fap->fa_id, off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200333 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300334 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200335 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200336
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300337 for (i = 0u; i < (uint32_t)BOOT_IMAGE_NUMBER; i++) {
338 if (fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(i)) {
339 is_primary = true;
340 break;
341 }
342 if (fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(i)) {
343 is_secondary = true;
344 break;
345 }
346 }
347
348 /* fill magic number value if equal to expected */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300349 if (bootutil_buffer_is_erased(fap_stat, &magic, BOOT_MAGIC_SZ)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200350 state->magic = BOOT_MAGIC_UNSET;
351
352 /* attempt to find magic in upgrade img slot trailer */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300353 if (is_secondary) {
354 trailer_off = fap->fa_size - BOOT_MAGIC_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200355
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300356 rc = flash_area_read(fap, trailer_off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300357 if (rc != 0) {
358 return -1;
359 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300360 buf_is_clean = bootutil_buffer_is_erased(fap, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300361 if (buf_is_clean) {
362 state->magic = BOOT_MAGIC_UNSET;
363 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300364 state->magic = (uint8_t)boot_magic_decode(&magic);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300365 /* put magic to status partition for upgrade slot*/
366 if ((uint32_t)BOOT_MAGIC_GOOD == state->magic) {
367 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300368 (uint8_t *)&magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300369 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200370 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300371 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200372 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300373 erase_trailer = 1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200374 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300375 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200376 }
377 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300378 state->magic = (uint8_t)boot_magic_decode(&magic);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200379 }
380
381 off = boot_swap_info_off(fap);
382 rc = swap_status_retrieve(fap->fa_id, off, &swap_info, sizeof swap_info);
383 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300384 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200385 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300386 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info) ||
387 state->swap_type >= (uint8_t)BOOT_SWAP_TYPE_FAIL) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200388 state->swap_type = (uint8_t)BOOT_SWAP_TYPE_NONE;
389 state->image_num = 0;
390 }
391 else {
392 /* Extract the swap type and image number */
393 state->swap_type = (uint8_t)BOOT_GET_SWAP_TYPE_M(swap_info);
394 state->image_num = (uint8_t)BOOT_GET_IMAGE_NUM_M(swap_info);
395 }
396
397 off = boot_copy_done_off(fap);
398 rc = swap_status_retrieve(fap->fa_id, off, &state->copy_done, sizeof state->copy_done);
399 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300400 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200401 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200402 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300403 if (bootutil_buffer_is_erased(fap_stat, &state->copy_done, sizeof state->copy_done)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200404 state->copy_done = BOOT_FLAG_UNSET;
405 } else {
406 state->copy_done = (uint8_t)boot_flag_decode(state->copy_done);
407 }
408
409 off = boot_image_ok_off(fap);
410 rc = swap_status_retrieve(fap->fa_id, off, &state->image_ok, sizeof state->image_ok);
411 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300412 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200413 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200414 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300415 if (bootutil_buffer_is_erased(fap_stat, &state->image_ok, sizeof state->image_ok)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200416 /* assign img_ok unset */
417 state->image_ok = BOOT_FLAG_UNSET;
418
419 /* attempt to read img_ok value in upgrade img slots trailer area
420 * it is set when image in slot for upgrade is signed for swap_type permanent
421 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300422 bool process_image_ok = (uint8_t)BOOT_FLAG_SET == state->copy_done;
423 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
424 BOOT_LOG_DBG(" * selected SCRATCH area, copy_done = %u", (unsigned)state->copy_done);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200425 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300426 else if (is_secondary) {
427 process_image_ok = true;
428 }
429 else if (!is_primary) {
430 process_image_ok = false;
431 rc = -1;
432 }
433 else {
434 /* Fix MISRA Rule 15.7 */
435 }
436 if (process_image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200437 trailer_off = fap->fa_size - (uint8_t)BOOT_MAGIC_SZ - (uint8_t)BOOT_MAX_ALIGN;
438
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300439 rc = flash_area_read(fap, trailer_off, &state->image_ok, sizeof state->image_ok);
440 if (rc != 0) {
441 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200442 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300443
444 buf_is_clean = bootutil_buffer_is_erased(fap, &state->image_ok, sizeof state->image_ok);
445 if (buf_is_clean) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200446 state->image_ok = BOOT_FLAG_UNSET;
447 } else {
448 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
449
450 /* put img_ok to status partition for upgrade slot */
451 if (state->image_ok != (uint8_t)BOOT_FLAG_BAD) {
452 rc = swap_status_update(fap->fa_id, off,
453 &state->image_ok, sizeof state->image_ok);
454 }
455 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300456 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200457 }
458
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300459 /* don't erase trailer, just move img_ok to status part */
460 erase_trailer = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200461 }
462 }
463 } else {
464 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
465 }
466
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300467 if ((erase_trailer != 0u) && (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) && (0 == rc)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200468 /* erase magic from upgrade img trailer */
469 rc = flash_area_erase(fap, trailer_off, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300470 if (rc != 0) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200471 return rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300472 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200473 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300474 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200475}
476
477/**
478 * This functions tries to locate the status area after an aborted swap,
479 * by looking for the magic in the possible locations.
480 *
481 * If the magic is successfully found, a flash_area * is returned and it
482 * is the responsibility of the called to close it.
483 *
484 * @returns 0 on success, -1 on errors
485 */
486static int
487boot_find_status(int image_index, const struct flash_area **fap)
488{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300489 union boot_img_magic_t magic = {0};
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200490 uint32_t off;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200491 int rc = -1;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300492 uint8_t area = FLASH_AREA_ERROR;
493
494 if ((image_index < 0) || (image_index >= MCUBOOT_IMAGE_NUMBER)) {
495 return rc;
496 }
497 /* the status is always in status partition */
498 area = FLASH_AREA_IMAGE_PRIMARY((uint32_t)image_index);
499
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200500
501 /*
502 * In the middle a swap, tries to locate the area that is currently
503 * storing a valid magic, first on the primary slot, then on scratch.
504 * Both "slots" can end up being temporary storage for a swap and it
505 * is assumed that if magic is valid then other metadata is too,
506 * because magic is always written in the last step.
507 */
508 rc = flash_area_open(area, fap);
509 if (rc != 0) {
510 return rc;
511 }
512 off = boot_magic_off(*fap);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300513 rc = swap_status_retrieve(area, off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200514
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300515 if (0 == rc) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300516 rc = memcmp((const void*)&magic.val, (const void *)&boot_img_magic.val, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200517 }
518
519 flash_area_close(*fap);
520 return rc;
521}
522
523int
524boot_read_swap_size(int image_index, uint32_t *swap_size)
525{
526 uint32_t off;
527 const struct flash_area *fap;
528 int rc;
529
530 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300531 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200532 off = boot_swap_size_off(fap);
533
534 rc = swap_status_retrieve(fap->fa_id, off, swap_size, sizeof *swap_size);
535 }
536 return rc;
537}
538
539int
540swap_erase_trailer_sectors(const struct boot_loader_state *state,
541 const struct flash_area *fap)
542{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300543 int32_t sub_offs;
544 uint32_t trailer_offs;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200545 uint8_t fa_id_primary;
546 uint8_t fa_id_secondary;
547 uint8_t image_index;
548 int rc;
549 (void)state;
550
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300551 BOOT_LOG_INF("Erasing trailer; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200552 /* trailer is located in status-partition */
553 const struct flash_area *fap_stat = NULL;
554
555 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
556 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300557 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200558 }
559
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300560 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200561 image_index = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300562 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200563 BOOT_PRIMARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300564 if (rc < 0) {
565 return -1;
566 }
567 fa_id_primary = (uint8_t)rc;
568
569 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200570 BOOT_SECONDARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300571 if (rc < 0) {
572 return -1;
573 }
574 fa_id_secondary = (uint8_t)rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200575
576 /* skip if Flash Area is not recognizable */
577 if ((fap->fa_id != fa_id_primary) && (fap->fa_id != fa_id_secondary)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300578 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200579 }
580 }
581
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300582 sub_offs = swap_status_init_offset(fap->fa_id);
583 if (sub_offs < 0) {
584 return -1;
585 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200586
587 /* delete starting from last sector and moving to beginning */
588 /* calculate last sector of status sub-area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300589 rc = flash_area_erase(fap_stat, (uint32_t)sub_offs, (uint32_t)BOOT_SWAP_STATUS_SIZE);
590 if (rc != 0) {
591 return -1;
592 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200593
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300594 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200595 /*
596 * it is also needed to erase trailer area in slots since they may contain
597 * data, which is already cleared in corresponding status partition
598 */
599 trailer_offs = fap->fa_size - BOOT_SWAP_STATUS_TRAILER_SIZE;
600 rc = flash_area_erase(fap, trailer_offs, BOOT_SWAP_STATUS_TRAILER_SIZE);
601 }
602
603 flash_area_close(fap_stat);
604
605 return rc;
606}
607
608int
609swap_status_init(const struct boot_loader_state *state,
610 const struct flash_area *fap,
611 const struct boot_status *bs)
612{
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000613 struct boot_swap_state swap_state = {0};
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200614 uint8_t image_index;
615 int rc;
616
617#if (BOOT_IMAGE_NUMBER == 1)
618 (void)state;
619#endif
620
621 image_index = BOOT_CURR_IMG(state);
622
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300623 BOOT_LOG_DBG("initializing status; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200624
625 rc = boot_read_swap_state_by_id((int32_t)FLASH_AREA_IMAGE_SECONDARY(image_index),
626 &swap_state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300627 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200628
629 if (bs->swap_type != (uint8_t)BOOT_SWAP_TYPE_NONE) {
630 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300631 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200632 }
633
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300634 if ((uint8_t)BOOT_FLAG_SET == swap_state.image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200635 rc = boot_write_image_ok(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300636 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200637 }
638
639 rc = boot_write_swap_size(fap, bs->swap_size);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300640 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200641
642#ifdef MCUBOOT_ENC_IMAGES
643 rc = boot_write_enc_key(fap, 0, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300644 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200645
646 rc = boot_write_enc_key(fap, 1, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300647 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200648#endif
649
650 rc = boot_write_magic(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300651 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200652
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300653 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200654}
655
656int
657swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
658{
659 const struct flash_area *fap = NULL;
660 const struct flash_area *fap_stat = NULL;
661 uint32_t off;
662 uint8_t swap_info = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300663 uint8_t area_id;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200664 int rc = 0;
665
666 bs->source = swap_status_source(state);
667
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300668 if (BOOT_STATUS_SOURCE_NONE == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200669 return 0;
670 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300671 else if (BOOT_STATUS_SOURCE_PRIMARY_SLOT == bs->source) {
672 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
673 }
674 else if (BOOT_STATUS_SOURCE_SCRATCH == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200675 area_id = FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300676 }
677 else {
678 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200679 }
680
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300681 rc = flash_area_open(area_id, &fap);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200682 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300683 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200684 }
685
686 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
687 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300688 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200689 }
690
691 rc = swap_read_status_bytes(fap, state, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300692 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200693 off = boot_swap_info_off(fap);
694 rc = swap_status_retrieve((uint8_t)area_id, off, &swap_info, sizeof swap_info);
695 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300696 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200697 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300698 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200699 BOOT_SET_SWAP_INFO_M(swap_info, 0u, (uint8_t)BOOT_SWAP_TYPE_NONE);
700 rc = 0;
701 }
702
703 /* Extract the swap type info */
704 bs->swap_type = BOOT_GET_SWAP_TYPE_M(swap_info);
705 }
706
707 flash_area_close(fap);
708 flash_area_close(fap_stat);
709
710 return rc;
711}
712
713#endif /* MCUBOOT_SWAP_USING_STATUS */