blob: b5fc1ed790beeb8e34dfccda70b2aa3b43e600c2 [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
INFINEON\DovhalA3d3b51d2024-06-12 17:01:18 +0300308#if defined (MCUBOOT_SWAP_STATUS_FAST_BOOT)
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200309static inline int
310boot_read_flag(const struct flash_area *fap, uint8_t *flag, uint32_t off)
311{
312 int rc;
313
314 do {
315 rc = flash_area_read(fap, off, flag, sizeof *flag);
316
317 if (rc != 0) {
318 break;
319 }
320
321 if (*flag == flash_area_erased_val(fap)) {
322 *flag = BOOT_FLAG_UNSET;
323 } else {
324 *flag = boot_flag_decode(*flag);
325 }
326
327 } while (false);
328
329 return rc;
330}
331
332static inline uint32_t
333boot_magic_off_trailer(const struct flash_area *fap)
334{
335 return flash_area_get_size(fap) - BOOT_MAGIC_SZ;
336}
337
338static inline uint32_t
339boot_image_ok_off_trailer(const struct flash_area *fap)
340{
341 return ALIGN_DOWN(boot_magic_off_trailer(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN);
342}
343
344static inline uint32_t
345boot_copy_done_off_trailer(const struct flash_area *fap)
346{
347 return boot_image_ok_off_trailer(fap) - BOOT_MAX_ALIGN;
348}
349
350static inline uint32_t
351boot_swap_info_off_trailer(const struct flash_area *fap)
352{
353 return boot_copy_done_off_trailer(fap) - BOOT_MAX_ALIGN;
354}
355
356int
357boot_read_swap_state_trailer(const struct flash_area *fap,
358 struct boot_swap_state *state)
359{
360 union boot_img_magic_t magic = {0U};
361 uint32_t off;
362 uint8_t swap_info;
363 int rc;
364
365 do {
366 off = boot_magic_off_trailer(fap);
367 rc = flash_area_read(fap, off, &magic, BOOT_MAGIC_SZ);
368
369 if (rc != 0) {
370 break;
371 }
372
373 if (bootutil_buffer_is_erased(fap, &magic, BOOT_MAGIC_SZ)) {
374 state->magic = BOOT_MAGIC_UNSET;
375 } else {
376 state->magic = boot_magic_decode(&magic);
377 }
378
379 off = boot_swap_info_off_trailer(fap);
380 rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
381
382 if (rc != 0) {
383 break;
384 }
385
386 /* Extract the swap type and image number */
387 state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
388 state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
389
390 if (swap_info == flash_area_erased_val(fap) ||
391 state->swap_type > BOOT_SWAP_TYPE_REVERT) {
392 state->swap_type = BOOT_SWAP_TYPE_NONE;
393 state->image_num = 0;
394 }
395
396 off = boot_copy_done_off_trailer(fap);
397 rc = boot_read_flag(fap, &state->copy_done, off);
398
399 if (rc != 0) {
400 break;
401 }
402
403 off = boot_image_ok_off_trailer(fap);
404 rc = boot_read_flag(fap, &state->image_ok, off);
405
406 } while (false);
407
408 return rc;
409}
INFINEON\DovhalA3d3b51d2024-06-12 17:01:18 +0300410#endif
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200411
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200412int
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200413boot_read_swap_state(const struct flash_area *fap,
414 struct boot_swap_state *state)
415{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300416 union boot_img_magic_t magic = {0U};
417 uint32_t off = 0U;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200418 uint32_t trailer_off = 0U;
419 uint8_t swap_info = 0U;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300420 int rc = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200421 uint32_t erase_trailer = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300422 bool buf_is_clean = false;
423 bool is_primary = false;
424 bool is_secondary = false;
425 uint32_t i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200426
427 const struct flash_area *fap_stat = NULL;
428
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200429 for (i = 0u; i < (uint32_t)BOOT_IMAGE_NUMBER; i++) {
430 if (fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(i)) {
431 is_primary = true;
432 break;
433 }
434 if (fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(i)) {
435 is_secondary = true;
436 break;
437 }
438 }
439
INFINEON\DovhalA3d3b51d2024-06-12 17:01:18 +0300440#if defined(MCUBOOT_SWAP_STATUS_FAST_BOOT)
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200441 {
INFINEON\DovhalA3d3b51d2024-06-12 17:01:18 +0300442 bool is_scratch = fap->fa_id == FLASH_AREA_IMAGE_SCRATCH;
443 boot_read_swap_state_trailer(fap, state);
444
445 if (is_primary) {
446 if (state->image_ok == BOOT_FLAG_SET && state->copy_done == BOOT_FLAG_SET && state->magic == BOOT_MAGIC_GOOD) {
447 return 0;
448 }
449 }
450
451 if (is_secondary || is_scratch) {
452 if (state->image_ok == BOOT_FLAG_UNSET && state->copy_done == BOOT_FLAG_UNSET && state->magic == BOOT_MAGIC_UNSET) {
453 return 0;
454 }
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200455 }
456 }
INFINEON\DovhalA3d3b51d2024-06-12 17:01:18 +0300457#endif
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200458
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200459 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
460 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300461 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200462 }
463
464 off = boot_magic_off(fap);
465 /* retrieve value for magic field from status partition area */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300466 rc = swap_status_retrieve(fap->fa_id, off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200467 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300468 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200469 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200470
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300471 /* fill magic number value if equal to expected */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300472 if (bootutil_buffer_is_erased(fap_stat, &magic, BOOT_MAGIC_SZ)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200473 state->magic = BOOT_MAGIC_UNSET;
474
475 /* attempt to find magic in upgrade img slot trailer */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300476 if (is_secondary) {
477 trailer_off = fap->fa_size - BOOT_MAGIC_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200478
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300479 rc = flash_area_read(fap, trailer_off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300480 if (rc != 0) {
481 return -1;
482 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300483 buf_is_clean = bootutil_buffer_is_erased(fap, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300484 if (buf_is_clean) {
485 state->magic = BOOT_MAGIC_UNSET;
486 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300487 state->magic = (uint8_t)boot_magic_decode(&magic);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300488 /* put magic to status partition for upgrade slot*/
489 if ((uint32_t)BOOT_MAGIC_GOOD == state->magic) {
490 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300491 (uint8_t *)&magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300492 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200493 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300494 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200495 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300496 erase_trailer = 1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200497 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300498 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200499 }
500 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300501 state->magic = (uint8_t)boot_magic_decode(&magic);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200502 }
503
504 off = boot_swap_info_off(fap);
505 rc = swap_status_retrieve(fap->fa_id, off, &swap_info, sizeof swap_info);
506 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300507 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200508 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300509 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info) ||
510 state->swap_type >= (uint8_t)BOOT_SWAP_TYPE_FAIL) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200511 state->swap_type = (uint8_t)BOOT_SWAP_TYPE_NONE;
512 state->image_num = 0;
513 }
514 else {
515 /* Extract the swap type and image number */
516 state->swap_type = (uint8_t)BOOT_GET_SWAP_TYPE_M(swap_info);
517 state->image_num = (uint8_t)BOOT_GET_IMAGE_NUM_M(swap_info);
518 }
519
520 off = boot_copy_done_off(fap);
521 rc = swap_status_retrieve(fap->fa_id, off, &state->copy_done, sizeof state->copy_done);
522 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300523 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200524 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200525 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300526 if (bootutil_buffer_is_erased(fap_stat, &state->copy_done, sizeof state->copy_done)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200527 state->copy_done = BOOT_FLAG_UNSET;
528 } else {
529 state->copy_done = (uint8_t)boot_flag_decode(state->copy_done);
530 }
531
532 off = boot_image_ok_off(fap);
533 rc = swap_status_retrieve(fap->fa_id, off, &state->image_ok, sizeof state->image_ok);
534 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300535 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200536 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200537 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300538 if (bootutil_buffer_is_erased(fap_stat, &state->image_ok, sizeof state->image_ok)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200539 /* assign img_ok unset */
540 state->image_ok = BOOT_FLAG_UNSET;
541
542 /* attempt to read img_ok value in upgrade img slots trailer area
543 * it is set when image in slot for upgrade is signed for swap_type permanent
544 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300545 bool process_image_ok = (uint8_t)BOOT_FLAG_SET == state->copy_done;
546 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
547 BOOT_LOG_DBG(" * selected SCRATCH area, copy_done = %u", (unsigned)state->copy_done);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200548 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300549 else if (is_secondary) {
550 process_image_ok = true;
551 }
552 else if (!is_primary) {
553 process_image_ok = false;
554 rc = -1;
555 }
556 else {
557 /* Fix MISRA Rule 15.7 */
558 }
559 if (process_image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200560 trailer_off = fap->fa_size - (uint8_t)BOOT_MAGIC_SZ - (uint8_t)BOOT_MAX_ALIGN;
561
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300562 rc = flash_area_read(fap, trailer_off, &state->image_ok, sizeof state->image_ok);
563 if (rc != 0) {
564 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200565 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300566
567 buf_is_clean = bootutil_buffer_is_erased(fap, &state->image_ok, sizeof state->image_ok);
568 if (buf_is_clean) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200569 state->image_ok = BOOT_FLAG_UNSET;
570 } else {
571 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
572
573 /* put img_ok to status partition for upgrade slot */
574 if (state->image_ok != (uint8_t)BOOT_FLAG_BAD) {
575 rc = swap_status_update(fap->fa_id, off,
576 &state->image_ok, sizeof state->image_ok);
577 }
578 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300579 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200580 }
581
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300582 /* don't erase trailer, just move img_ok to status part */
583 erase_trailer = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200584 }
585 }
586 } else {
587 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
588 }
589
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300590 if ((erase_trailer != 0u) && (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) && (0 == rc)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200591 /* erase magic from upgrade img trailer */
592 rc = flash_area_erase(fap, trailer_off, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300593 if (rc != 0) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200594 return rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300595 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200596 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300597 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200598}
599
600/**
601 * This functions tries to locate the status area after an aborted swap,
602 * by looking for the magic in the possible locations.
603 *
604 * If the magic is successfully found, a flash_area * is returned and it
605 * is the responsibility of the called to close it.
606 *
607 * @returns 0 on success, -1 on errors
608 */
609static int
610boot_find_status(int image_index, const struct flash_area **fap)
611{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300612 union boot_img_magic_t magic = {0};
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200613 uint32_t off;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200614 int rc = -1;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300615 uint8_t area = FLASH_AREA_ERROR;
616
617 if ((image_index < 0) || (image_index >= MCUBOOT_IMAGE_NUMBER)) {
618 return rc;
619 }
620 /* the status is always in status partition */
621 area = FLASH_AREA_IMAGE_PRIMARY((uint32_t)image_index);
622
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200623
624 /*
625 * In the middle a swap, tries to locate the area that is currently
626 * storing a valid magic, first on the primary slot, then on scratch.
627 * Both "slots" can end up being temporary storage for a swap and it
628 * is assumed that if magic is valid then other metadata is too,
629 * because magic is always written in the last step.
630 */
631 rc = flash_area_open(area, fap);
632 if (rc != 0) {
633 return rc;
634 }
635 off = boot_magic_off(*fap);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300636 rc = swap_status_retrieve(area, off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200637
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300638 if (0 == rc) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300639 rc = memcmp((const void*)&magic.val, (const void *)&boot_img_magic.val, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200640 }
641
642 flash_area_close(*fap);
643 return rc;
644}
645
646int
647boot_read_swap_size(int image_index, uint32_t *swap_size)
648{
649 uint32_t off;
650 const struct flash_area *fap;
651 int rc;
652
653 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300654 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200655 off = boot_swap_size_off(fap);
656
657 rc = swap_status_retrieve(fap->fa_id, off, swap_size, sizeof *swap_size);
658 }
659 return rc;
660}
661
662int
663swap_erase_trailer_sectors(const struct boot_loader_state *state,
664 const struct flash_area *fap)
665{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300666 int32_t sub_offs;
667 uint32_t trailer_offs;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200668 uint8_t fa_id_primary;
669 uint8_t fa_id_secondary;
670 uint8_t image_index;
671 int rc;
672 (void)state;
673
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300674 BOOT_LOG_INF("Erasing trailer; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200675 /* trailer is located in status-partition */
676 const struct flash_area *fap_stat = NULL;
677
678 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
679 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300680 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200681 }
682
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300683 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200684 image_index = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300685 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200686 BOOT_PRIMARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300687 if (rc < 0) {
688 return -1;
689 }
690 fa_id_primary = (uint8_t)rc;
691
692 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200693 BOOT_SECONDARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300694 if (rc < 0) {
695 return -1;
696 }
697 fa_id_secondary = (uint8_t)rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200698
699 /* skip if Flash Area is not recognizable */
700 if ((fap->fa_id != fa_id_primary) && (fap->fa_id != fa_id_secondary)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300701 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200702 }
703 }
704
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300705 sub_offs = swap_status_init_offset(fap->fa_id);
706 if (sub_offs < 0) {
707 return -1;
708 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200709
710 /* delete starting from last sector and moving to beginning */
711 /* calculate last sector of status sub-area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300712 rc = flash_area_erase(fap_stat, (uint32_t)sub_offs, (uint32_t)BOOT_SWAP_STATUS_SIZE);
713 if (rc != 0) {
714 return -1;
715 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200716
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300717 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200718 /*
719 * it is also needed to erase trailer area in slots since they may contain
720 * data, which is already cleared in corresponding status partition
721 */
722 trailer_offs = fap->fa_size - BOOT_SWAP_STATUS_TRAILER_SIZE;
723 rc = flash_area_erase(fap, trailer_offs, BOOT_SWAP_STATUS_TRAILER_SIZE);
724 }
725
726 flash_area_close(fap_stat);
727
728 return rc;
729}
730
731int
732swap_status_init(const struct boot_loader_state *state,
733 const struct flash_area *fap,
734 const struct boot_status *bs)
735{
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000736 struct boot_swap_state swap_state = {0};
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200737 uint8_t image_index;
738 int rc;
739
740#if (BOOT_IMAGE_NUMBER == 1)
741 (void)state;
742#endif
743
744 image_index = BOOT_CURR_IMG(state);
745
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300746 BOOT_LOG_DBG("initializing status; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200747
748 rc = boot_read_swap_state_by_id((int32_t)FLASH_AREA_IMAGE_SECONDARY(image_index),
749 &swap_state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300750 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200751
752 if (bs->swap_type != (uint8_t)BOOT_SWAP_TYPE_NONE) {
753 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300754 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200755 }
756
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300757 if ((uint8_t)BOOT_FLAG_SET == swap_state.image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200758 rc = boot_write_image_ok(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300759 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200760 }
761
762 rc = boot_write_swap_size(fap, bs->swap_size);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300763 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200764
765#ifdef MCUBOOT_ENC_IMAGES
766 rc = boot_write_enc_key(fap, 0, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300767 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200768
769 rc = boot_write_enc_key(fap, 1, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300770 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200771#endif
772
773 rc = boot_write_magic(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300774 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200775
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300776 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200777}
778
779int
780swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
781{
782 const struct flash_area *fap = NULL;
783 const struct flash_area *fap_stat = NULL;
784 uint32_t off;
785 uint8_t swap_info = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300786 uint8_t area_id;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200787 int rc = 0;
788
789 bs->source = swap_status_source(state);
790
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300791 if (BOOT_STATUS_SOURCE_NONE == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200792 return 0;
793 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300794 else if (BOOT_STATUS_SOURCE_PRIMARY_SLOT == bs->source) {
795 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
796 }
797 else if (BOOT_STATUS_SOURCE_SCRATCH == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200798 area_id = FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300799 }
800 else {
801 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200802 }
803
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300804 rc = flash_area_open(area_id, &fap);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200805 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300806 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200807 }
808
809 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
810 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300811 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200812 }
813
814 rc = swap_read_status_bytes(fap, state, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300815 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200816 off = boot_swap_info_off(fap);
817 rc = swap_status_retrieve((uint8_t)area_id, off, &swap_info, sizeof swap_info);
818 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300819 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200820 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300821 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200822 BOOT_SET_SWAP_INFO_M(swap_info, 0u, (uint8_t)BOOT_SWAP_TYPE_NONE);
823 rc = 0;
824 }
825
826 /* Extract the swap type info */
827 bs->swap_type = BOOT_GET_SWAP_TYPE_M(swap_info);
828 }
829
830 flash_area_close(fap);
831 flash_area_close(fap_stat);
832
833 return rc;
834}
835
836#endif /* MCUBOOT_SWAP_USING_STATUS */