blob: ac6d231b9539156da2715084e79fa3d4daace76b [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
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200308static inline int
309boot_read_flag(const struct flash_area *fap, uint8_t *flag, uint32_t off)
310{
311 int rc;
312
313 do {
314 rc = flash_area_read(fap, off, flag, sizeof *flag);
315
316 if (rc != 0) {
317 break;
318 }
319
320 if (*flag == flash_area_erased_val(fap)) {
321 *flag = BOOT_FLAG_UNSET;
322 } else {
323 *flag = boot_flag_decode(*flag);
324 }
325
326 } while (false);
327
328 return rc;
329}
330
331static inline uint32_t
332boot_magic_off_trailer(const struct flash_area *fap)
333{
334 return flash_area_get_size(fap) - BOOT_MAGIC_SZ;
335}
336
337static inline uint32_t
338boot_image_ok_off_trailer(const struct flash_area *fap)
339{
340 return ALIGN_DOWN(boot_magic_off_trailer(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN);
341}
342
343static inline uint32_t
344boot_copy_done_off_trailer(const struct flash_area *fap)
345{
346 return boot_image_ok_off_trailer(fap) - BOOT_MAX_ALIGN;
347}
348
349static inline uint32_t
350boot_swap_info_off_trailer(const struct flash_area *fap)
351{
352 return boot_copy_done_off_trailer(fap) - BOOT_MAX_ALIGN;
353}
354
355int
356boot_read_swap_state_trailer(const struct flash_area *fap,
357 struct boot_swap_state *state)
358{
359 union boot_img_magic_t magic = {0U};
360 uint32_t off;
361 uint8_t swap_info;
362 int rc;
363
364 do {
365 off = boot_magic_off_trailer(fap);
366 rc = flash_area_read(fap, off, &magic, BOOT_MAGIC_SZ);
367
368 if (rc != 0) {
369 break;
370 }
371
372 if (bootutil_buffer_is_erased(fap, &magic, BOOT_MAGIC_SZ)) {
373 state->magic = BOOT_MAGIC_UNSET;
374 } else {
375 state->magic = boot_magic_decode(&magic);
376 }
377
378 off = boot_swap_info_off_trailer(fap);
379 rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
380
381 if (rc != 0) {
382 break;
383 }
384
385 /* Extract the swap type and image number */
386 state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
387 state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
388
389 if (swap_info == flash_area_erased_val(fap) ||
390 state->swap_type > BOOT_SWAP_TYPE_REVERT) {
391 state->swap_type = BOOT_SWAP_TYPE_NONE;
392 state->image_num = 0;
393 }
394
395 off = boot_copy_done_off_trailer(fap);
396 rc = boot_read_flag(fap, &state->copy_done, off);
397
398 if (rc != 0) {
399 break;
400 }
401
402 off = boot_image_ok_off_trailer(fap);
403 rc = boot_read_flag(fap, &state->image_ok, off);
404
405 } while (false);
406
407 return rc;
408}
409
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200410int
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200411boot_read_swap_state(const struct flash_area *fap,
412 struct boot_swap_state *state)
413{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300414 union boot_img_magic_t magic = {0U};
415 uint32_t off = 0U;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200416 uint32_t trailer_off = 0U;
417 uint8_t swap_info = 0U;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300418 int rc = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200419 uint32_t erase_trailer = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300420 bool buf_is_clean = false;
421 bool is_primary = false;
422 bool is_secondary = false;
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200423 bool is_scratch = fap->fa_id == FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300424 uint32_t i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200425
426 const struct flash_area *fap_stat = NULL;
427
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200428 for (i = 0u; i < (uint32_t)BOOT_IMAGE_NUMBER; i++) {
429 if (fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(i)) {
430 is_primary = true;
431 break;
432 }
433 if (fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(i)) {
434 is_secondary = true;
435 break;
436 }
437 }
438
439 rc = boot_read_swap_state_trailer(fap, state);
440
441 if (is_primary)
442 {
443 if (state->image_ok == BOOT_FLAG_SET && state->copy_done == BOOT_FLAG_SET && state->magic == BOOT_MAGIC_GOOD)
444 {
445 return 0;
446 }
447 }
448
449 if (is_secondary || is_scratch)
450 {
451 if (state->image_ok == BOOT_FLAG_UNSET && state->copy_done == BOOT_FLAG_UNSET && state->magic == BOOT_MAGIC_UNSET)
452 {
453 return 0;
454 }
455 }
456
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200457 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
458 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300459 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200460 }
461
462 off = boot_magic_off(fap);
463 /* retrieve value for magic field from status partition area */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300464 rc = swap_status_retrieve(fap->fa_id, off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200465 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300466 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200467 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200468
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300469 /* fill magic number value if equal to expected */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300470 if (bootutil_buffer_is_erased(fap_stat, &magic, BOOT_MAGIC_SZ)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200471 state->magic = BOOT_MAGIC_UNSET;
472
473 /* attempt to find magic in upgrade img slot trailer */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300474 if (is_secondary) {
475 trailer_off = fap->fa_size - BOOT_MAGIC_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200476
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300477 rc = flash_area_read(fap, trailer_off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300478 if (rc != 0) {
479 return -1;
480 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300481 buf_is_clean = bootutil_buffer_is_erased(fap, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300482 if (buf_is_clean) {
483 state->magic = BOOT_MAGIC_UNSET;
484 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300485 state->magic = (uint8_t)boot_magic_decode(&magic);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300486 /* put magic to status partition for upgrade slot*/
487 if ((uint32_t)BOOT_MAGIC_GOOD == state->magic) {
488 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300489 (uint8_t *)&magic, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300490 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200491 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300492 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200493 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300494 erase_trailer = 1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200495 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300496 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200497 }
498 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300499 state->magic = (uint8_t)boot_magic_decode(&magic);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200500 }
501
502 off = boot_swap_info_off(fap);
503 rc = swap_status_retrieve(fap->fa_id, off, &swap_info, sizeof swap_info);
504 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300505 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200506 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300507 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info) ||
508 state->swap_type >= (uint8_t)BOOT_SWAP_TYPE_FAIL) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200509 state->swap_type = (uint8_t)BOOT_SWAP_TYPE_NONE;
510 state->image_num = 0;
511 }
512 else {
513 /* Extract the swap type and image number */
514 state->swap_type = (uint8_t)BOOT_GET_SWAP_TYPE_M(swap_info);
515 state->image_num = (uint8_t)BOOT_GET_IMAGE_NUM_M(swap_info);
516 }
517
518 off = boot_copy_done_off(fap);
519 rc = swap_status_retrieve(fap->fa_id, off, &state->copy_done, sizeof state->copy_done);
520 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300521 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200522 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200523 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300524 if (bootutil_buffer_is_erased(fap_stat, &state->copy_done, sizeof state->copy_done)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200525 state->copy_done = BOOT_FLAG_UNSET;
526 } else {
527 state->copy_done = (uint8_t)boot_flag_decode(state->copy_done);
528 }
529
530 off = boot_image_ok_off(fap);
531 rc = swap_status_retrieve(fap->fa_id, off, &state->image_ok, sizeof state->image_ok);
532 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300533 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200534 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200535 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300536 if (bootutil_buffer_is_erased(fap_stat, &state->image_ok, sizeof state->image_ok)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200537 /* assign img_ok unset */
538 state->image_ok = BOOT_FLAG_UNSET;
539
540 /* attempt to read img_ok value in upgrade img slots trailer area
541 * it is set when image in slot for upgrade is signed for swap_type permanent
542 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300543 bool process_image_ok = (uint8_t)BOOT_FLAG_SET == state->copy_done;
544 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
545 BOOT_LOG_DBG(" * selected SCRATCH area, copy_done = %u", (unsigned)state->copy_done);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200546 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300547 else if (is_secondary) {
548 process_image_ok = true;
549 }
550 else if (!is_primary) {
551 process_image_ok = false;
552 rc = -1;
553 }
554 else {
555 /* Fix MISRA Rule 15.7 */
556 }
557 if (process_image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200558 trailer_off = fap->fa_size - (uint8_t)BOOT_MAGIC_SZ - (uint8_t)BOOT_MAX_ALIGN;
559
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300560 rc = flash_area_read(fap, trailer_off, &state->image_ok, sizeof state->image_ok);
561 if (rc != 0) {
562 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200563 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300564
565 buf_is_clean = bootutil_buffer_is_erased(fap, &state->image_ok, sizeof state->image_ok);
566 if (buf_is_clean) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200567 state->image_ok = BOOT_FLAG_UNSET;
568 } else {
569 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
570
571 /* put img_ok to status partition for upgrade slot */
572 if (state->image_ok != (uint8_t)BOOT_FLAG_BAD) {
573 rc = swap_status_update(fap->fa_id, off,
574 &state->image_ok, sizeof state->image_ok);
575 }
576 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300577 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200578 }
579
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300580 /* don't erase trailer, just move img_ok to status part */
581 erase_trailer = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200582 }
583 }
584 } else {
585 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
586 }
587
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300588 if ((erase_trailer != 0u) && (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) && (0 == rc)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200589 /* erase magic from upgrade img trailer */
590 rc = flash_area_erase(fap, trailer_off, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300591 if (rc != 0) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200592 return rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300593 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200594 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300595 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200596}
597
598/**
599 * This functions tries to locate the status area after an aborted swap,
600 * by looking for the magic in the possible locations.
601 *
602 * If the magic is successfully found, a flash_area * is returned and it
603 * is the responsibility of the called to close it.
604 *
605 * @returns 0 on success, -1 on errors
606 */
607static int
608boot_find_status(int image_index, const struct flash_area **fap)
609{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300610 union boot_img_magic_t magic = {0};
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200611 uint32_t off;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200612 int rc = -1;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300613 uint8_t area = FLASH_AREA_ERROR;
614
615 if ((image_index < 0) || (image_index >= MCUBOOT_IMAGE_NUMBER)) {
616 return rc;
617 }
618 /* the status is always in status partition */
619 area = FLASH_AREA_IMAGE_PRIMARY((uint32_t)image_index);
620
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200621
622 /*
623 * In the middle a swap, tries to locate the area that is currently
624 * storing a valid magic, first on the primary slot, then on scratch.
625 * Both "slots" can end up being temporary storage for a swap and it
626 * is assumed that if magic is valid then other metadata is too,
627 * because magic is always written in the last step.
628 */
629 rc = flash_area_open(area, fap);
630 if (rc != 0) {
631 return rc;
632 }
633 off = boot_magic_off(*fap);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300634 rc = swap_status_retrieve(area, off, &magic, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200635
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300636 if (0 == rc) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300637 rc = memcmp((const void*)&magic.val, (const void *)&boot_img_magic.val, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200638 }
639
640 flash_area_close(*fap);
641 return rc;
642}
643
644int
645boot_read_swap_size(int image_index, uint32_t *swap_size)
646{
647 uint32_t off;
648 const struct flash_area *fap;
649 int rc;
650
651 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300652 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200653 off = boot_swap_size_off(fap);
654
655 rc = swap_status_retrieve(fap->fa_id, off, swap_size, sizeof *swap_size);
656 }
657 return rc;
658}
659
660int
661swap_erase_trailer_sectors(const struct boot_loader_state *state,
662 const struct flash_area *fap)
663{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300664 int32_t sub_offs;
665 uint32_t trailer_offs;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200666 uint8_t fa_id_primary;
667 uint8_t fa_id_secondary;
668 uint8_t image_index;
669 int rc;
670 (void)state;
671
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300672 BOOT_LOG_INF("Erasing trailer; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200673 /* trailer is located in status-partition */
674 const struct flash_area *fap_stat = NULL;
675
676 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
677 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300678 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200679 }
680
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300681 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200682 image_index = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300683 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200684 BOOT_PRIMARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300685 if (rc < 0) {
686 return -1;
687 }
688 fa_id_primary = (uint8_t)rc;
689
690 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200691 BOOT_SECONDARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300692 if (rc < 0) {
693 return -1;
694 }
695 fa_id_secondary = (uint8_t)rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200696
697 /* skip if Flash Area is not recognizable */
698 if ((fap->fa_id != fa_id_primary) && (fap->fa_id != fa_id_secondary)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300699 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200700 }
701 }
702
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300703 sub_offs = swap_status_init_offset(fap->fa_id);
704 if (sub_offs < 0) {
705 return -1;
706 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200707
708 /* delete starting from last sector and moving to beginning */
709 /* calculate last sector of status sub-area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300710 rc = flash_area_erase(fap_stat, (uint32_t)sub_offs, (uint32_t)BOOT_SWAP_STATUS_SIZE);
711 if (rc != 0) {
712 return -1;
713 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200714
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300715 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200716 /*
717 * it is also needed to erase trailer area in slots since they may contain
718 * data, which is already cleared in corresponding status partition
719 */
720 trailer_offs = fap->fa_size - BOOT_SWAP_STATUS_TRAILER_SIZE;
721 rc = flash_area_erase(fap, trailer_offs, BOOT_SWAP_STATUS_TRAILER_SIZE);
722 }
723
724 flash_area_close(fap_stat);
725
726 return rc;
727}
728
729int
730swap_status_init(const struct boot_loader_state *state,
731 const struct flash_area *fap,
732 const struct boot_status *bs)
733{
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000734 struct boot_swap_state swap_state = {0};
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200735 uint8_t image_index;
736 int rc;
737
738#if (BOOT_IMAGE_NUMBER == 1)
739 (void)state;
740#endif
741
742 image_index = BOOT_CURR_IMG(state);
743
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300744 BOOT_LOG_DBG("initializing status; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200745
746 rc = boot_read_swap_state_by_id((int32_t)FLASH_AREA_IMAGE_SECONDARY(image_index),
747 &swap_state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300748 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200749
750 if (bs->swap_type != (uint8_t)BOOT_SWAP_TYPE_NONE) {
751 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300752 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200753 }
754
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300755 if ((uint8_t)BOOT_FLAG_SET == swap_state.image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200756 rc = boot_write_image_ok(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300757 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200758 }
759
760 rc = boot_write_swap_size(fap, bs->swap_size);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300761 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200762
763#ifdef MCUBOOT_ENC_IMAGES
764 rc = boot_write_enc_key(fap, 0, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300765 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200766
767 rc = boot_write_enc_key(fap, 1, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300768 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200769#endif
770
771 rc = boot_write_magic(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300772 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200773
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300774 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200775}
776
777int
778swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
779{
780 const struct flash_area *fap = NULL;
781 const struct flash_area *fap_stat = NULL;
782 uint32_t off;
783 uint8_t swap_info = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300784 uint8_t area_id;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200785 int rc = 0;
786
787 bs->source = swap_status_source(state);
788
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300789 if (BOOT_STATUS_SOURCE_NONE == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200790 return 0;
791 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300792 else if (BOOT_STATUS_SOURCE_PRIMARY_SLOT == bs->source) {
793 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
794 }
795 else if (BOOT_STATUS_SOURCE_SCRATCH == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200796 area_id = FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300797 }
798 else {
799 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200800 }
801
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300802 rc = flash_area_open(area_id, &fap);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200803 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300804 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200805 }
806
807 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
808 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300809 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200810 }
811
812 rc = swap_read_status_bytes(fap, state, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300813 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200814 off = boot_swap_info_off(fap);
815 rc = swap_status_retrieve((uint8_t)area_id, off, &swap_info, sizeof swap_info);
816 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300817 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200818 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300819 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200820 BOOT_SET_SWAP_INFO_M(swap_info, 0u, (uint8_t)BOOT_SWAP_TYPE_NONE);
821 rc = 0;
822 }
823
824 /* Extract the swap type info */
825 bs->swap_type = BOOT_GET_SWAP_TYPE_M(swap_info);
826 }
827
828 flash_area_close(fap);
829 flash_area_close(fap_stat);
830
831 return rc;
832}
833
834#endif /* MCUBOOT_SWAP_USING_STATUS */