blob: c3f40178654d063ad36e83601c6c45c0bc74d37f [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
46#if defined(MCUBOOT_SWAP_USING_STATUS)
47
48#define BOOT_MAGIC_ARR_SZ \
49 (sizeof boot_img_magic / sizeof boot_img_magic[0])
50
51static int
52boot_find_status(int image_index, const struct flash_area **fap);
53
54static int
55boot_magic_decode(const uint32_t *magic)
56{
57 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
58 return BOOT_MAGIC_GOOD;
59 }
60 return BOOT_MAGIC_BAD;
61}
62
63static int
64boot_flag_decode(uint8_t flag)
65{
66 if (flag != (uint8_t)BOOT_FLAG_SET) {
67 return BOOT_FLAG_BAD;
68 }
69 return BOOT_FLAG_SET;
70}
71
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020072/* Offset Section */
73static inline uint32_t
74boot_magic_off(const struct flash_area *fap)
75{
76 (void)fap;
Roman Okhrimenko977b3752022-03-31 14:40:48 +030077 return (uint32_t)BOOT_SWAP_STATUS_D_SIZE_RAW - (uint32_t)BOOT_MAGIC_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020078}
79
80uint32_t
81boot_image_ok_off(const struct flash_area *fap)
82{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030083 return boot_magic_off(fap) - BOOT_SWAP_STATUS_IMG_OK_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020084}
85
86uint32_t
87boot_copy_done_off(const struct flash_area *fap)
88{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030089 return boot_image_ok_off(fap) - BOOT_SWAP_STATUS_COPY_DONE_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020090}
91
92uint32_t
93boot_swap_info_off(const struct flash_area *fap)
94{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030095 return boot_copy_done_off(fap) - BOOT_SWAP_STATUS_SWAPINF_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020096}
97
98uint32_t
99boot_swap_size_off(const struct flash_area *fap)
100{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300101 return boot_swap_info_off(fap) - BOOT_SWAP_STATUS_SWAPSZ_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200102}
103
104uint32_t
105boot_status_off(const struct flash_area *fap)
106{
107 (void)fap;
108 /* this offset is equal to 0, because swap status fields
109 in this implementation count from the start of partition */
110 return 0;
111}
112
113#ifdef MCUBOOT_ENC_IMAGES
114static inline uint32_t
115boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
116{
117#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
118 /* suggest encryption key is also stored in status partition */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300119 return boot_swap_size_off(fap) - (((uint32_t)slot + 1UL) * (uint32_t)BOOT_ENC_TLV_SIZE);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200120#else
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300121 return boot_swap_size_off(fap) - (((uint32_t)slot + 1UL) * (uint32_t)BOOT_ENC_KEY_SIZE);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200122#endif
123}
124#endif
125
126/**
127 * Write trailer data; status bytes, swap_size, etc
128 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300129 * @returns 0 on success, -1 on error.
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200130 */
131int
132boot_write_trailer(const struct flash_area *fap, uint32_t off,
133 const uint8_t *inbuf, uint8_t inlen)
134{
135 int rc;
136
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300137 /* copy status part trailer to primary image before set copy_done flag */
138 if (boot_copy_done_off(fap) == off &&
139 fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(0u) &&
140 BOOT_SWAP_STATUS_COPY_DONE_SZ == inlen) {
141
142 BOOT_LOG_DBG("copy status part trailer to primary image slot");
143 rc = swap_status_to_image_trailer(fap);
144 if (rc != 0) {
145 BOOT_LOG_ERR("trailer copy failed");
146 return -1;
147 }
148 }
149
150 rc = swap_status_update(fap->fa_id, off, inbuf, inlen);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200151
152 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300153 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200154 }
155 return rc;
156}
157
158#ifdef MCUBOOT_ENC_IMAGES
159int
160boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
161 const struct boot_status *bs)
162{
163 uint32_t off;
164 int rc;
165
166 off = boot_enc_key_off(fap, slot);
167#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
168 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300169 bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200170#else
171 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300172 bs->enckey[slot], BOOT_ENC_KEY_SIZE);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200173#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300174 if (rc != 0) {
175 return -1;
176 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200177
178 return 0;
179}
180
181int
182boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
183{
184 uint32_t off;
185 const struct flash_area *fap;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200186 int rc;
187
188 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300189 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200190 off = boot_enc_key_off(fap, slot);
191#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
192 rc = swap_status_retrieve(fap->fa_id, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300193 if (0 == rc) {
194 uint8_t aes_iv[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
195
196 /* Only try to decrypt initialized TLV metadata */
197 if (!bootutil_buffer_is_filled(bs->enctlv[slot],
198 BOOT_UNINITIALIZED_TLV_FILL,
199 BOOT_ENC_TLV_ALIGN_SIZE)) {
200 rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot], 0, aes_iv);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200201 }
202 }
203#else
204 rc = swap_status_retrieve(fap->fa_id, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
205#endif
206 flash_area_close(fap);
207 }
208
209 return rc;
210}
211#endif /* MCUBOOT_ENC_IMAGES */
212
213/* Write Section */
214int
215boot_write_magic(const struct flash_area *fap)
216{
217 uint32_t off;
218 int rc;
219
220 off = boot_magic_off(fap);
221
222 rc = swap_status_update(fap->fa_id, off,
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300223 boot_img_magic, BOOT_MAGIC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200224
225 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300226 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200227 }
228 return 0;
229}
230
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200231/**
232 * Writes the supplied boot status to the flash file system. The boot status
233 * contains the current state of an in-progress image copy operation.
234 *
235 * @param bs The boot status to write.
236 *
237 * @return 0 on success; nonzero on failure.
238 */
239int
240boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
241{
242 const struct flash_area *fap = NULL;
243 uint32_t off;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300244 uint8_t area_id;
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000245 uint8_t tmp_state;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200246 int rc;
247 (void)state;
248
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300249 if (bs->idx < BOOT_STATUS_IDX_0) {
250 return BOOT_EFLASH;
251 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200252 /* NOTE: The first sector copied (that is the last sector on slot) contains
253 * the trailer. Since in the last step the primary slot is erased, the
254 * first two status writes go to the scratch which will be copied to
255 * the primary slot!
256 */
257
258#ifdef MCUBOOT_SWAP_USING_SCRATCH
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300259 if (bs->use_scratch != 0U) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200260 /* Write to scratch status. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300261 area_id = (uint8_t)FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200262 } else
263#endif
264 {
265 /* Write to the primary slot. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300266 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200267 }
268
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300269 rc = flash_area_open(area_id, &fap);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200270 if (rc != 0) {
271 rc = BOOT_EFLASH;
272 goto done;
273 }
274 off = boot_status_off(fap) + boot_status_internal_off(bs, 1);
275
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000276 tmp_state = bs->state;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200277
278 rc = swap_status_update(fap->fa_id, off, &tmp_state, 1);
279 if (rc != 0) {
280 rc = BOOT_EFLASH;
281 goto done;
282 }
283
284done:
285 flash_area_close(fap);
286
287 return rc;
288}
289
290int
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200291boot_read_swap_state(const struct flash_area *fap,
292 struct boot_swap_state *state)
293{
294 uint32_t magic[BOOT_MAGIC_ARR_SZ];
295 uint32_t off;
296 uint32_t trailer_off = 0U;
297 uint8_t swap_info = 0U;
298 int rc;
299 uint32_t erase_trailer = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300300 bool buf_is_clean = false;
301 bool is_primary = false;
302 bool is_secondary = false;
303 uint32_t i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200304
305 const struct flash_area *fap_stat = NULL;
306
307 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
308 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300309 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200310 }
311
312 off = boot_magic_off(fap);
313 /* retrieve value for magic field from status partition area */
314 rc = swap_status_retrieve(fap->fa_id, off, magic, BOOT_MAGIC_SZ);
315 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300316 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200317 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200318
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300319 for (i = 0u; i < (uint32_t)BOOT_IMAGE_NUMBER; i++) {
320 if (fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(i)) {
321 is_primary = true;
322 break;
323 }
324 if (fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(i)) {
325 is_secondary = true;
326 break;
327 }
328 }
329
330 /* fill magic number value if equal to expected */
331 if (bootutil_buffer_is_erased(fap_stat, magic, BOOT_MAGIC_SZ)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200332 state->magic = BOOT_MAGIC_UNSET;
333
334 /* attempt to find magic in upgrade img slot trailer */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300335 if (is_secondary) {
336 trailer_off = fap->fa_size - BOOT_MAGIC_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200337
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300338 rc = flash_area_read(fap, trailer_off, magic, BOOT_MAGIC_SZ);
339 if (rc != 0) {
340 return -1;
341 }
342 buf_is_clean = bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ);
343 if (buf_is_clean) {
344 state->magic = BOOT_MAGIC_UNSET;
345 } else {
346 state->magic = (uint8_t)boot_magic_decode(magic);
347 /* put magic to status partition for upgrade slot*/
348 if ((uint32_t)BOOT_MAGIC_GOOD == state->magic) {
349 rc = swap_status_update(fap->fa_id, off,
350 (uint8_t *) magic, BOOT_MAGIC_SZ);
351 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200352 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300353 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200354 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300355 erase_trailer = 1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200356 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300357 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200358 }
359 } else {
360 state->magic = (uint8_t)boot_magic_decode(magic);
361 }
362
363 off = boot_swap_info_off(fap);
364 rc = swap_status_retrieve(fap->fa_id, off, &swap_info, sizeof swap_info);
365 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300366 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200367 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300368 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info) ||
369 state->swap_type >= (uint8_t)BOOT_SWAP_TYPE_FAIL) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200370 state->swap_type = (uint8_t)BOOT_SWAP_TYPE_NONE;
371 state->image_num = 0;
372 }
373 else {
374 /* Extract the swap type and image number */
375 state->swap_type = (uint8_t)BOOT_GET_SWAP_TYPE_M(swap_info);
376 state->image_num = (uint8_t)BOOT_GET_IMAGE_NUM_M(swap_info);
377 }
378
379 off = boot_copy_done_off(fap);
380 rc = swap_status_retrieve(fap->fa_id, off, &state->copy_done, sizeof state->copy_done);
381 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300382 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200383 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200384 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300385 if (bootutil_buffer_is_erased(fap_stat, &state->copy_done, sizeof state->copy_done)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200386 state->copy_done = BOOT_FLAG_UNSET;
387 } else {
388 state->copy_done = (uint8_t)boot_flag_decode(state->copy_done);
389 }
390
391 off = boot_image_ok_off(fap);
392 rc = swap_status_retrieve(fap->fa_id, off, &state->image_ok, sizeof state->image_ok);
393 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300394 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200395 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200396 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300397 if (bootutil_buffer_is_erased(fap_stat, &state->image_ok, sizeof state->image_ok)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200398 /* assign img_ok unset */
399 state->image_ok = BOOT_FLAG_UNSET;
400
401 /* attempt to read img_ok value in upgrade img slots trailer area
402 * it is set when image in slot for upgrade is signed for swap_type permanent
403 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300404 bool process_image_ok = (uint8_t)BOOT_FLAG_SET == state->copy_done;
405 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
406 BOOT_LOG_DBG(" * selected SCRATCH area, copy_done = %u", (unsigned)state->copy_done);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200407 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300408 else if (is_secondary) {
409 process_image_ok = true;
410 }
411 else if (!is_primary) {
412 process_image_ok = false;
413 rc = -1;
414 }
415 else {
416 /* Fix MISRA Rule 15.7 */
417 }
418 if (process_image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200419 trailer_off = fap->fa_size - (uint8_t)BOOT_MAGIC_SZ - (uint8_t)BOOT_MAX_ALIGN;
420
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300421 rc = flash_area_read(fap, trailer_off, &state->image_ok, sizeof state->image_ok);
422 if (rc != 0) {
423 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200424 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300425
426 buf_is_clean = bootutil_buffer_is_erased(fap, &state->image_ok, sizeof state->image_ok);
427 if (buf_is_clean) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200428 state->image_ok = BOOT_FLAG_UNSET;
429 } else {
430 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
431
432 /* put img_ok to status partition for upgrade slot */
433 if (state->image_ok != (uint8_t)BOOT_FLAG_BAD) {
434 rc = swap_status_update(fap->fa_id, off,
435 &state->image_ok, sizeof state->image_ok);
436 }
437 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300438 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200439 }
440
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300441 /* don't erase trailer, just move img_ok to status part */
442 erase_trailer = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200443 }
444 }
445 } else {
446 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
447 }
448
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300449 if ((erase_trailer != 0u) && (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) && (0 == rc)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200450 /* erase magic from upgrade img trailer */
451 rc = flash_area_erase(fap, trailer_off, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300452 if (rc != 0) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200453 return rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300454 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200455 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300456 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200457}
458
459/**
460 * This functions tries to locate the status area after an aborted swap,
461 * by looking for the magic in the possible locations.
462 *
463 * If the magic is successfully found, a flash_area * is returned and it
464 * is the responsibility of the called to close it.
465 *
466 * @returns 0 on success, -1 on errors
467 */
468static int
469boot_find_status(int image_index, const struct flash_area **fap)
470{
471 uint32_t magic[BOOT_MAGIC_ARR_SZ] = {0};
472 uint32_t off;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200473 int rc = -1;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300474 uint8_t area = FLASH_AREA_ERROR;
475
476 if ((image_index < 0) || (image_index >= MCUBOOT_IMAGE_NUMBER)) {
477 return rc;
478 }
479 /* the status is always in status partition */
480 area = FLASH_AREA_IMAGE_PRIMARY((uint32_t)image_index);
481
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200482
483 /*
484 * In the middle a swap, tries to locate the area that is currently
485 * storing a valid magic, first on the primary slot, then on scratch.
486 * Both "slots" can end up being temporary storage for a swap and it
487 * is assumed that if magic is valid then other metadata is too,
488 * because magic is always written in the last step.
489 */
490 rc = flash_area_open(area, fap);
491 if (rc != 0) {
492 return rc;
493 }
494 off = boot_magic_off(*fap);
495 rc = swap_status_retrieve(area, off, magic, BOOT_MAGIC_SZ);
496
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300497 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200498 rc = memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ);
499 }
500
501 flash_area_close(*fap);
502 return rc;
503}
504
505int
506boot_read_swap_size(int image_index, uint32_t *swap_size)
507{
508 uint32_t off;
509 const struct flash_area *fap;
510 int rc;
511
512 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300513 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200514 off = boot_swap_size_off(fap);
515
516 rc = swap_status_retrieve(fap->fa_id, off, swap_size, sizeof *swap_size);
517 }
518 return rc;
519}
520
521int
522swap_erase_trailer_sectors(const struct boot_loader_state *state,
523 const struct flash_area *fap)
524{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300525 int32_t sub_offs;
526 uint32_t trailer_offs;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200527 uint8_t fa_id_primary;
528 uint8_t fa_id_secondary;
529 uint8_t image_index;
530 int rc;
531 (void)state;
532
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300533 BOOT_LOG_INF("Erasing trailer; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200534 /* trailer is located in status-partition */
535 const struct flash_area *fap_stat = NULL;
536
537 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
538 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300539 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200540 }
541
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300542 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200543 image_index = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300544 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200545 BOOT_PRIMARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300546 if (rc < 0) {
547 return -1;
548 }
549 fa_id_primary = (uint8_t)rc;
550
551 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200552 BOOT_SECONDARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300553 if (rc < 0) {
554 return -1;
555 }
556 fa_id_secondary = (uint8_t)rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200557
558 /* skip if Flash Area is not recognizable */
559 if ((fap->fa_id != fa_id_primary) && (fap->fa_id != fa_id_secondary)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300560 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200561 }
562 }
563
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300564 sub_offs = swap_status_init_offset(fap->fa_id);
565 if (sub_offs < 0) {
566 return -1;
567 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200568
569 /* delete starting from last sector and moving to beginning */
570 /* calculate last sector of status sub-area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300571 rc = flash_area_erase(fap_stat, (uint32_t)sub_offs, (uint32_t)BOOT_SWAP_STATUS_SIZE);
572 if (rc != 0) {
573 return -1;
574 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200575
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300576 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200577 /*
578 * it is also needed to erase trailer area in slots since they may contain
579 * data, which is already cleared in corresponding status partition
580 */
581 trailer_offs = fap->fa_size - BOOT_SWAP_STATUS_TRAILER_SIZE;
582 rc = flash_area_erase(fap, trailer_offs, BOOT_SWAP_STATUS_TRAILER_SIZE);
583 }
584
585 flash_area_close(fap_stat);
586
587 return rc;
588}
589
590int
591swap_status_init(const struct boot_loader_state *state,
592 const struct flash_area *fap,
593 const struct boot_status *bs)
594{
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000595 struct boot_swap_state swap_state = {0};
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200596 uint8_t image_index;
597 int rc;
598
599#if (BOOT_IMAGE_NUMBER == 1)
600 (void)state;
601#endif
602
603 image_index = BOOT_CURR_IMG(state);
604
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300605 BOOT_LOG_DBG("initializing status; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200606
607 rc = boot_read_swap_state_by_id((int32_t)FLASH_AREA_IMAGE_SECONDARY(image_index),
608 &swap_state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300609 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200610
611 if (bs->swap_type != (uint8_t)BOOT_SWAP_TYPE_NONE) {
612 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300613 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200614 }
615
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300616 if ((uint8_t)BOOT_FLAG_SET == swap_state.image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200617 rc = boot_write_image_ok(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300618 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200619 }
620
621 rc = boot_write_swap_size(fap, bs->swap_size);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300622 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200623
624#ifdef MCUBOOT_ENC_IMAGES
625 rc = boot_write_enc_key(fap, 0, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300626 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200627
628 rc = boot_write_enc_key(fap, 1, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300629 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200630#endif
631
632 rc = boot_write_magic(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300633 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200634
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300635 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200636}
637
638int
639swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
640{
641 const struct flash_area *fap = NULL;
642 const struct flash_area *fap_stat = NULL;
643 uint32_t off;
644 uint8_t swap_info = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300645 uint8_t area_id;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200646 int rc = 0;
647
648 bs->source = swap_status_source(state);
649
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300650 if (BOOT_STATUS_SOURCE_NONE == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200651 return 0;
652 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300653 else if (BOOT_STATUS_SOURCE_PRIMARY_SLOT == bs->source) {
654 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
655 }
656 else if (BOOT_STATUS_SOURCE_SCRATCH == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200657 area_id = FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300658 }
659 else {
660 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200661 }
662
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300663 rc = flash_area_open(area_id, &fap);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200664 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300665 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200666 }
667
668 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
669 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300670 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200671 }
672
673 rc = swap_read_status_bytes(fap, state, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300674 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200675 off = boot_swap_info_off(fap);
676 rc = swap_status_retrieve((uint8_t)area_id, off, &swap_info, sizeof swap_info);
677 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300678 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200679 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300680 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200681 BOOT_SET_SWAP_INFO_M(swap_info, 0u, (uint8_t)BOOT_SWAP_TYPE_NONE);
682 rc = 0;
683 }
684
685 /* Extract the swap type info */
686 bs->swap_type = BOOT_GET_SWAP_TYPE_M(swap_info);
687 }
688
689 flash_area_close(fap);
690 flash_area_close(fap_stat);
691
692 return rc;
693}
694
695#endif /* MCUBOOT_SWAP_USING_STATUS */