blob: 8512b02ac7a8408cb5ec6d3ae30d5f2e1488277d [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;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200245 int rc;
246 (void)state;
247
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300248 if (bs->idx < BOOT_STATUS_IDX_0) {
249 return BOOT_EFLASH;
250 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200251 /* NOTE: The first sector copied (that is the last sector on slot) contains
252 * the trailer. Since in the last step the primary slot is erased, the
253 * first two status writes go to the scratch which will be copied to
254 * the primary slot!
255 */
256
257#ifdef MCUBOOT_SWAP_USING_SCRATCH
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300258 if (bs->use_scratch != 0U) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200259 /* Write to scratch status. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300260 area_id = (uint8_t)FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200261 } else
262#endif
263 {
264 /* Write to the primary slot. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300265 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200266 }
267
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300268 rc = flash_area_open(area_id, &fap);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200269 if (rc != 0) {
270 rc = BOOT_EFLASH;
271 goto done;
272 }
273 off = boot_status_off(fap) + boot_status_internal_off(bs, 1);
274
275 uint8_t tmp_state = bs->state;
276
277 rc = swap_status_update(fap->fa_id, off, &tmp_state, 1);
278 if (rc != 0) {
279 rc = BOOT_EFLASH;
280 goto done;
281 }
282
283done:
284 flash_area_close(fap);
285
286 return rc;
287}
288
289int
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200290boot_read_swap_state(const struct flash_area *fap,
291 struct boot_swap_state *state)
292{
293 uint32_t magic[BOOT_MAGIC_ARR_SZ];
294 uint32_t off;
295 uint32_t trailer_off = 0U;
296 uint8_t swap_info = 0U;
297 int rc;
298 uint32_t erase_trailer = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300299 bool buf_is_clean = false;
300 bool is_primary = false;
301 bool is_secondary = false;
302 uint32_t i;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200303
304 const struct flash_area *fap_stat = NULL;
305
306 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
307 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300308 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200309 }
310
311 off = boot_magic_off(fap);
312 /* retrieve value for magic field from status partition area */
313 rc = swap_status_retrieve(fap->fa_id, off, magic, BOOT_MAGIC_SZ);
314 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300315 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200316 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200317
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300318 for (i = 0u; i < (uint32_t)BOOT_IMAGE_NUMBER; i++) {
319 if (fap->fa_id == FLASH_AREA_IMAGE_PRIMARY(i)) {
320 is_primary = true;
321 break;
322 }
323 if (fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(i)) {
324 is_secondary = true;
325 break;
326 }
327 }
328
329 /* fill magic number value if equal to expected */
330 if (bootutil_buffer_is_erased(fap_stat, magic, BOOT_MAGIC_SZ)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200331 state->magic = BOOT_MAGIC_UNSET;
332
333 /* attempt to find magic in upgrade img slot trailer */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300334 if (is_secondary) {
335 trailer_off = fap->fa_size - BOOT_MAGIC_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200336
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300337 rc = flash_area_read(fap, trailer_off, magic, BOOT_MAGIC_SZ);
338 if (rc != 0) {
339 return -1;
340 }
341 buf_is_clean = bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ);
342 if (buf_is_clean) {
343 state->magic = BOOT_MAGIC_UNSET;
344 } else {
345 state->magic = (uint8_t)boot_magic_decode(magic);
346 /* put magic to status partition for upgrade slot*/
347 if ((uint32_t)BOOT_MAGIC_GOOD == state->magic) {
348 rc = swap_status_update(fap->fa_id, off,
349 (uint8_t *) magic, BOOT_MAGIC_SZ);
350 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200351 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300352 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200353 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300354 erase_trailer = 1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200355 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300356 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200357 }
358 } else {
359 state->magic = (uint8_t)boot_magic_decode(magic);
360 }
361
362 off = boot_swap_info_off(fap);
363 rc = swap_status_retrieve(fap->fa_id, off, &swap_info, sizeof swap_info);
364 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300365 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200366 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300367 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info) ||
368 state->swap_type >= (uint8_t)BOOT_SWAP_TYPE_FAIL) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200369 state->swap_type = (uint8_t)BOOT_SWAP_TYPE_NONE;
370 state->image_num = 0;
371 }
372 else {
373 /* Extract the swap type and image number */
374 state->swap_type = (uint8_t)BOOT_GET_SWAP_TYPE_M(swap_info);
375 state->image_num = (uint8_t)BOOT_GET_IMAGE_NUM_M(swap_info);
376 }
377
378 off = boot_copy_done_off(fap);
379 rc = swap_status_retrieve(fap->fa_id, off, &state->copy_done, sizeof state->copy_done);
380 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300381 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200382 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200383 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300384 if (bootutil_buffer_is_erased(fap_stat, &state->copy_done, sizeof state->copy_done)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200385 state->copy_done = BOOT_FLAG_UNSET;
386 } else {
387 state->copy_done = (uint8_t)boot_flag_decode(state->copy_done);
388 }
389
390 off = boot_image_ok_off(fap);
391 rc = swap_status_retrieve(fap->fa_id, off, &state->image_ok, sizeof state->image_ok);
392 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300393 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200394 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200395 /* need to check swap_info was empty */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300396 if (bootutil_buffer_is_erased(fap_stat, &state->image_ok, sizeof state->image_ok)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200397 /* assign img_ok unset */
398 state->image_ok = BOOT_FLAG_UNSET;
399
400 /* attempt to read img_ok value in upgrade img slots trailer area
401 * it is set when image in slot for upgrade is signed for swap_type permanent
402 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300403 bool process_image_ok = (uint8_t)BOOT_FLAG_SET == state->copy_done;
404 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
405 BOOT_LOG_DBG(" * selected SCRATCH area, copy_done = %u", (unsigned)state->copy_done);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200406 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300407 else if (is_secondary) {
408 process_image_ok = true;
409 }
410 else if (!is_primary) {
411 process_image_ok = false;
412 rc = -1;
413 }
414 else {
415 /* Fix MISRA Rule 15.7 */
416 }
417 if (process_image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200418 trailer_off = fap->fa_size - (uint8_t)BOOT_MAGIC_SZ - (uint8_t)BOOT_MAX_ALIGN;
419
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300420 rc = flash_area_read(fap, trailer_off, &state->image_ok, sizeof state->image_ok);
421 if (rc != 0) {
422 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200423 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300424
425 buf_is_clean = bootutil_buffer_is_erased(fap, &state->image_ok, sizeof state->image_ok);
426 if (buf_is_clean) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200427 state->image_ok = BOOT_FLAG_UNSET;
428 } else {
429 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
430
431 /* put img_ok to status partition for upgrade slot */
432 if (state->image_ok != (uint8_t)BOOT_FLAG_BAD) {
433 rc = swap_status_update(fap->fa_id, off,
434 &state->image_ok, sizeof state->image_ok);
435 }
436 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300437 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200438 }
439
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300440 /* don't erase trailer, just move img_ok to status part */
441 erase_trailer = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200442 }
443 }
444 } else {
445 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
446 }
447
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300448 if ((erase_trailer != 0u) && (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) && (0 == rc)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200449 /* erase magic from upgrade img trailer */
450 rc = flash_area_erase(fap, trailer_off, BOOT_MAGIC_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300451 if (rc != 0) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200452 return rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300453 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200454 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300455 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200456}
457
458/**
459 * This functions tries to locate the status area after an aborted swap,
460 * by looking for the magic in the possible locations.
461 *
462 * If the magic is successfully found, a flash_area * is returned and it
463 * is the responsibility of the called to close it.
464 *
465 * @returns 0 on success, -1 on errors
466 */
467static int
468boot_find_status(int image_index, const struct flash_area **fap)
469{
470 uint32_t magic[BOOT_MAGIC_ARR_SZ] = {0};
471 uint32_t off;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200472 int rc = -1;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300473 uint8_t area = FLASH_AREA_ERROR;
474
475 if ((image_index < 0) || (image_index >= MCUBOOT_IMAGE_NUMBER)) {
476 return rc;
477 }
478 /* the status is always in status partition */
479 area = FLASH_AREA_IMAGE_PRIMARY((uint32_t)image_index);
480
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200481
482 /*
483 * In the middle a swap, tries to locate the area that is currently
484 * storing a valid magic, first on the primary slot, then on scratch.
485 * Both "slots" can end up being temporary storage for a swap and it
486 * is assumed that if magic is valid then other metadata is too,
487 * because magic is always written in the last step.
488 */
489 rc = flash_area_open(area, fap);
490 if (rc != 0) {
491 return rc;
492 }
493 off = boot_magic_off(*fap);
494 rc = swap_status_retrieve(area, off, magic, BOOT_MAGIC_SZ);
495
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300496 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200497 rc = memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ);
498 }
499
500 flash_area_close(*fap);
501 return rc;
502}
503
504int
505boot_read_swap_size(int image_index, uint32_t *swap_size)
506{
507 uint32_t off;
508 const struct flash_area *fap;
509 int rc;
510
511 rc = boot_find_status(image_index, &fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300512 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200513 off = boot_swap_size_off(fap);
514
515 rc = swap_status_retrieve(fap->fa_id, off, swap_size, sizeof *swap_size);
516 }
517 return rc;
518}
519
520int
521swap_erase_trailer_sectors(const struct boot_loader_state *state,
522 const struct flash_area *fap)
523{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300524 int32_t sub_offs;
525 uint32_t trailer_offs;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200526 uint8_t fa_id_primary;
527 uint8_t fa_id_secondary;
528 uint8_t image_index;
529 int rc;
530 (void)state;
531
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300532 BOOT_LOG_INF("Erasing trailer; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200533 /* trailer is located in status-partition */
534 const struct flash_area *fap_stat = NULL;
535
536 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
537 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300538 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200539 }
540
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300541 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200542 image_index = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300543 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200544 BOOT_PRIMARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300545 if (rc < 0) {
546 return -1;
547 }
548 fa_id_primary = (uint8_t)rc;
549
550 rc = flash_area_id_from_multi_image_slot((int32_t)image_index,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200551 BOOT_SECONDARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300552 if (rc < 0) {
553 return -1;
554 }
555 fa_id_secondary = (uint8_t)rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200556
557 /* skip if Flash Area is not recognizable */
558 if ((fap->fa_id != fa_id_primary) && (fap->fa_id != fa_id_secondary)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300559 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200560 }
561 }
562
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300563 sub_offs = swap_status_init_offset(fap->fa_id);
564 if (sub_offs < 0) {
565 return -1;
566 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200567
568 /* delete starting from last sector and moving to beginning */
569 /* calculate last sector of status sub-area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300570 rc = flash_area_erase(fap_stat, (uint32_t)sub_offs, (uint32_t)BOOT_SWAP_STATUS_SIZE);
571 if (rc != 0) {
572 return -1;
573 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200574
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300575 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200576 /*
577 * it is also needed to erase trailer area in slots since they may contain
578 * data, which is already cleared in corresponding status partition
579 */
580 trailer_offs = fap->fa_size - BOOT_SWAP_STATUS_TRAILER_SIZE;
581 rc = flash_area_erase(fap, trailer_offs, BOOT_SWAP_STATUS_TRAILER_SIZE);
582 }
583
584 flash_area_close(fap_stat);
585
586 return rc;
587}
588
589int
590swap_status_init(const struct boot_loader_state *state,
591 const struct flash_area *fap,
592 const struct boot_status *bs)
593{
594 struct boot_swap_state swap_state;
595 uint8_t image_index;
596 int rc;
597
598#if (BOOT_IMAGE_NUMBER == 1)
599 (void)state;
600#endif
601
602 image_index = BOOT_CURR_IMG(state);
603
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300604 BOOT_LOG_DBG("initializing status; fa_id=%u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200605
606 rc = boot_read_swap_state_by_id((int32_t)FLASH_AREA_IMAGE_SECONDARY(image_index),
607 &swap_state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300608 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200609
610 if (bs->swap_type != (uint8_t)BOOT_SWAP_TYPE_NONE) {
611 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300612 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200613 }
614
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300615 if ((uint8_t)BOOT_FLAG_SET == swap_state.image_ok) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200616 rc = boot_write_image_ok(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300617 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200618 }
619
620 rc = boot_write_swap_size(fap, bs->swap_size);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300621 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200622
623#ifdef MCUBOOT_ENC_IMAGES
624 rc = boot_write_enc_key(fap, 0, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300625 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200626
627 rc = boot_write_enc_key(fap, 1, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300628 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200629#endif
630
631 rc = boot_write_magic(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300632 assert(0 == rc);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200633
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300634 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200635}
636
637int
638swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
639{
640 const struct flash_area *fap = NULL;
641 const struct flash_area *fap_stat = NULL;
642 uint32_t off;
643 uint8_t swap_info = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300644 uint8_t area_id;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200645 int rc = 0;
646
647 bs->source = swap_status_source(state);
648
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300649 if (BOOT_STATUS_SOURCE_NONE == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200650 return 0;
651 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300652 else if (BOOT_STATUS_SOURCE_PRIMARY_SLOT == bs->source) {
653 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
654 }
655 else if (BOOT_STATUS_SOURCE_SCRATCH == bs->source) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200656 area_id = FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300657 }
658 else {
659 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200660 }
661
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300662 rc = flash_area_open(area_id, &fap);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200663 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300664 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200665 }
666
667 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
668 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300669 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200670 }
671
672 rc = swap_read_status_bytes(fap, state, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300673 if (0 == rc) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200674 off = boot_swap_info_off(fap);
675 rc = swap_status_retrieve((uint8_t)area_id, off, &swap_info, sizeof swap_info);
676 if (rc < 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300677 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200678 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300679 if (bootutil_buffer_is_erased(fap_stat, &swap_info, sizeof swap_info)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200680 BOOT_SET_SWAP_INFO_M(swap_info, 0u, (uint8_t)BOOT_SWAP_TYPE_NONE);
681 rc = 0;
682 }
683
684 /* Extract the swap type info */
685 bs->swap_type = BOOT_GET_SWAP_TYPE_M(swap_info);
686 }
687
688 flash_area_close(fap);
689 flash_area_close(fap_stat);
690
691 return rc;
692}
693
694#endif /* MCUBOOT_SWAP_USING_STATUS */