blob: b4c6ee77d911e0dc7792dd5a4c89b5c3ad20d1c0 [file] [log] [blame]
Tamas Banf70ef8c2017-12-19 15:35:09 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#include <assert.h>
21#include <string.h>
22#include <inttypes.h>
23#include <stddef.h>
24
Tamas Banf70ef8c2017-12-19 15:35:09 +000025#include "flash_map/flash_map.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000026#include "bootutil/image.h"
27#include "bootutil/bootutil.h"
28#include "bootutil_priv.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000029#include "bootutil/bootutil_log.h"
30
31int boot_current_slot;
32
33const uint32_t boot_img_magic[] = {
34 0xf395c277,
35 0x7fefd260,
36 0x0f505235,
37 0x8079b62c,
38};
39
David Vincze39e78552018-10-10 17:10:01 +020040#define BOOT_MAGIC_ARR_SZ \
41 (sizeof boot_img_magic / sizeof boot_img_magic[0])
42
Tamas Ban581034a2017-12-19 19:54:37 +000043const uint32_t BOOT_MAGIC_SZ = sizeof(boot_img_magic);
Tamas Banf70ef8c2017-12-19 15:35:09 +000044const uint32_t BOOT_MAX_ALIGN = MAX_FLASH_ALIGN;
45
46struct boot_swap_table {
David Vincze8bdfc2d2019-03-18 15:49:23 +010047 uint8_t magic_primary_slot;
48 uint8_t magic_secondary_slot;
49 uint8_t image_ok_primary_slot;
50 uint8_t image_ok_secondary_slot;
51 uint8_t copy_done_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000052
53 uint8_t swap_type;
54};
55
56/**
57 * This set of tables maps image trailer contents to swap operation type.
58 * When searching for a match, these tables must be iterated sequentially.
59 *
David Vincze8bdfc2d2019-03-18 15:49:23 +010060 * NOTE: the table order is very important. The settings in the secondary
61 * slot always are priority to the primary slot and should be located
62 * earlier in the table.
Tamas Banf70ef8c2017-12-19 15:35:09 +000063 *
64 * The table lists only states where there is action needs to be taken by
65 * the bootloader, as in starting/finishing a swap operation.
66 */
67static const struct boot_swap_table boot_swap_tables[] = {
68 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010069 .magic_primary_slot = BOOT_MAGIC_ANY,
70 .magic_secondary_slot = BOOT_MAGIC_GOOD,
71 .image_ok_primary_slot = BOOT_FLAG_ANY,
72 .image_ok_secondary_slot = BOOT_FLAG_UNSET,
73 .copy_done_primary_slot = BOOT_FLAG_ANY,
74 .swap_type = BOOT_SWAP_TYPE_TEST,
Tamas Banf70ef8c2017-12-19 15:35:09 +000075 },
76 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010077 .magic_primary_slot = BOOT_MAGIC_ANY,
78 .magic_secondary_slot = BOOT_MAGIC_GOOD,
79 .image_ok_primary_slot = BOOT_FLAG_ANY,
80 .image_ok_secondary_slot = BOOT_FLAG_SET,
81 .copy_done_primary_slot = BOOT_FLAG_ANY,
82 .swap_type = BOOT_SWAP_TYPE_PERM,
Tamas Banf70ef8c2017-12-19 15:35:09 +000083 },
84 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010085 .magic_primary_slot = BOOT_MAGIC_GOOD,
86 .magic_secondary_slot = BOOT_MAGIC_UNSET,
87 .image_ok_primary_slot = BOOT_FLAG_UNSET,
88 .image_ok_secondary_slot = BOOT_FLAG_ANY,
89 .copy_done_primary_slot = BOOT_FLAG_SET,
90 .swap_type = BOOT_SWAP_TYPE_REVERT,
Tamas Banf70ef8c2017-12-19 15:35:09 +000091 },
92};
93
94#define BOOT_SWAP_TABLES_COUNT \
Tamas Ban581034a2017-12-19 19:54:37 +000095 (sizeof(boot_swap_tables) / sizeof(boot_swap_tables[0]))
Tamas Banf70ef8c2017-12-19 15:35:09 +000096
David Vincze39e78552018-10-10 17:10:01 +020097static int
98boot_magic_decode(const uint32_t *magic)
Tamas Banf70ef8c2017-12-19 15:35:09 +000099{
Tamas Banf70ef8c2017-12-19 15:35:09 +0000100 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
101 return BOOT_MAGIC_GOOD;
102 }
David Vincze39e78552018-10-10 17:10:01 +0200103 return BOOT_MAGIC_BAD;
104}
Tamas Banf70ef8c2017-12-19 15:35:09 +0000105
David Vincze39e78552018-10-10 17:10:01 +0200106static int
107boot_flag_decode(uint8_t flag)
108{
109 if (flag != BOOT_FLAG_SET) {
110 return BOOT_FLAG_BAD;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000111 }
David Vincze39e78552018-10-10 17:10:01 +0200112 return BOOT_FLAG_SET;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000113}
114
115uint32_t
116boot_slots_trailer_sz(uint8_t min_write_sz)
117{
118 return /* state for all sectors */
119 BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz +
120 BOOT_MAX_ALIGN * 3 /* copy_done + image_ok + swap_size */ +
121 BOOT_MAGIC_SZ;
122}
123
124static uint32_t
125boot_scratch_trailer_sz(uint8_t min_write_sz)
126{
127 return BOOT_STATUS_STATE_COUNT * min_write_sz + /* state for one sector */
128 BOOT_MAX_ALIGN * 2 + /* image_ok + swap_size */
129 BOOT_MAGIC_SZ;
130}
131
132static uint32_t
133boot_magic_off(const struct flash_area *fap)
134{
135 assert(offsetof(struct image_trailer, magic) == 16);
136 return fap->fa_size - BOOT_MAGIC_SZ;
137}
138
139int
140boot_status_entries(const struct flash_area *fap)
141{
142 switch (fap->fa_id) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100143 case FLASH_AREA_IMAGE_PRIMARY:
144 case FLASH_AREA_IMAGE_SECONDARY:
Tamas Banf70ef8c2017-12-19 15:35:09 +0000145 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
146 case FLASH_AREA_IMAGE_SCRATCH:
147 return BOOT_STATUS_STATE_COUNT;
148 default:
149 return BOOT_EBADARGS;
150 }
151}
152
153uint32_t
154boot_status_off(const struct flash_area *fap)
155{
156 uint32_t off_from_end;
157 uint8_t elem_sz;
158
159 elem_sz = flash_area_align(fap);
160
161 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
162 off_from_end = boot_scratch_trailer_sz(elem_sz);
163 } else {
164 off_from_end = boot_slots_trailer_sz(elem_sz);
165 }
166
167 assert(off_from_end <= fap->fa_size);
168 return fap->fa_size - off_from_end;
169}
170
171static uint32_t
172boot_copy_done_off(const struct flash_area *fap)
173{
174 assert(fap->fa_id != FLASH_AREA_IMAGE_SCRATCH);
175 assert(offsetof(struct image_trailer, copy_done) == 0);
176 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
177}
178
179static uint32_t
180boot_image_ok_off(const struct flash_area *fap)
181{
182 assert(offsetof(struct image_trailer, image_ok) == 8);
183 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
184}
185
186static uint32_t
187boot_swap_size_off(const struct flash_area *fap)
188{
189 /*
190 * The "swap_size" field if located just before the trailer.
191 * The scratch slot doesn't store "copy_done"...
192 */
193 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
194 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
195 }
196
197 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
198}
199
200int
201boot_read_swap_state(const struct flash_area *fap,
202 struct boot_swap_state *state)
203{
David Vincze39e78552018-10-10 17:10:01 +0200204 uint32_t magic[BOOT_MAGIC_ARR_SZ];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000205 uint32_t off;
206 int rc;
207
208 off = boot_magic_off(fap);
David Vincze39e78552018-10-10 17:10:01 +0200209 rc = flash_area_read_is_empty(fap, off, magic, BOOT_MAGIC_SZ);
210 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000211 return BOOT_EFLASH;
212 }
David Vincze39e78552018-10-10 17:10:01 +0200213 if (rc == 1) {
214 state->magic = BOOT_MAGIC_UNSET;
215 } else {
216 state->magic = boot_magic_decode(magic);
217 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000218
219 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
220 off = boot_copy_done_off(fap);
David Vincze39e78552018-10-10 17:10:01 +0200221 rc = flash_area_read_is_empty(fap, off, &state->copy_done,
222 sizeof state->copy_done);
223 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000224 return BOOT_EFLASH;
225 }
David Vincze39e78552018-10-10 17:10:01 +0200226 if (rc == 1) {
227 state->copy_done = BOOT_FLAG_UNSET;
228 } else {
229 state->copy_done = boot_flag_decode(state->copy_done);
230 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000231 }
232
233 off = boot_image_ok_off(fap);
David Vincze39e78552018-10-10 17:10:01 +0200234 rc = flash_area_read_is_empty(fap, off, &state->image_ok, sizeof state->image_ok);
235 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000236 return BOOT_EFLASH;
237 }
David Vincze39e78552018-10-10 17:10:01 +0200238 if (rc == 1) {
239 state->image_ok = BOOT_FLAG_UNSET;
240 } else {
241 state->image_ok = boot_flag_decode(state->image_ok);
242 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000243
244 return 0;
245}
246
247/**
248 * Reads the image trailer from the scratch area.
249 */
250int
251boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
252{
253 const struct flash_area *fap;
254 int rc;
255
256 switch (flash_area_id) {
257 case FLASH_AREA_IMAGE_SCRATCH:
David Vincze8bdfc2d2019-03-18 15:49:23 +0100258 case FLASH_AREA_IMAGE_PRIMARY:
259 case FLASH_AREA_IMAGE_SECONDARY:
Tamas Banf70ef8c2017-12-19 15:35:09 +0000260 rc = flash_area_open(flash_area_id, &fap);
261 if (rc != 0) {
262 return BOOT_EFLASH;
263 }
264 break;
265 default:
266 return BOOT_EBADARGS;
267 }
268
269 rc = boot_read_swap_state(fap, state);
270 flash_area_close(fap);
271 return rc;
272}
273
274int
275boot_read_swap_size(uint32_t *swap_size)
276{
David Vincze39e78552018-10-10 17:10:01 +0200277 uint32_t magic[BOOT_MAGIC_ARR_SZ];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000278 uint32_t off;
279 const struct flash_area *fap;
280 int rc;
281
282 /*
283 * In the middle a swap, tries to locate the saved swap size. Looks
David Vincze8bdfc2d2019-03-18 15:49:23 +0100284 * for a valid magic, first on the primary slot, then on scratch.
285 * Both "slots" can end up being temporary storage for a swap and it
286 * is assumed that if magic is valid then swap size is too, because
287 * magic is always written in the last step.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000288 */
289
David Vincze8bdfc2d2019-03-18 15:49:23 +0100290 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000291 if (rc != 0) {
292 return BOOT_EFLASH;
293 }
294
295 off = boot_magic_off(fap);
296 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
297 if (rc != 0) {
298 rc = BOOT_EFLASH;
299 goto out;
300 }
301
302 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) != 0) {
303 /*
David Vincze8bdfc2d2019-03-18 15:49:23 +0100304 * If the primary slot's magic is not valid, try scratch...
Tamas Banf70ef8c2017-12-19 15:35:09 +0000305 */
306
307 flash_area_close(fap);
308
309 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
310 if (rc != 0) {
311 return BOOT_EFLASH;
312 }
313
314 off = boot_magic_off(fap);
315 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
316 if (rc != 0) {
317 rc = BOOT_EFLASH;
318 goto out;
319 }
320
321 assert(memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0);
322 }
323
324 off = boot_swap_size_off(fap);
Tamas Ban581034a2017-12-19 19:54:37 +0000325 rc = flash_area_read(fap, off, swap_size, sizeof(*swap_size));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000326 if (rc != 0) {
327 rc = BOOT_EFLASH;
328 }
329
330out:
331 flash_area_close(fap);
332 return rc;
333}
334
335
336int
337boot_write_magic(const struct flash_area *fap)
338{
339 uint32_t off;
340 int rc;
341
342 off = boot_magic_off(fap);
343
344 rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
345 if (rc != 0) {
346 return BOOT_EFLASH;
347 }
348
349 return 0;
350}
351
352static int
353boot_write_flag(int flag, const struct flash_area *fap)
354{
355 uint32_t off;
356 int rc;
357 uint8_t buf[BOOT_MAX_ALIGN];
358 uint8_t align;
David Vincze39e78552018-10-10 17:10:01 +0200359 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000360
361 switch (flag) {
362 case BOOT_FLAG_COPY_DONE:
363 off = boot_copy_done_off(fap);
364 break;
365 case BOOT_FLAG_IMAGE_OK:
366 off = boot_image_ok_off(fap);
367 break;
368 default:
369 return BOOT_EBADARGS;
370 }
371
Tamas Banc3828852018-02-01 12:24:16 +0000372 align = flash_area_align(fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000373 assert(align <= BOOT_MAX_ALIGN);
David Vincze39e78552018-10-10 17:10:01 +0200374 erased_val = flash_area_erased_val(fap);
375 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000376 buf[0] = BOOT_FLAG_SET;
377
378 rc = flash_area_write(fap, off, buf, align);
379 if (rc != 0) {
380 return BOOT_EFLASH;
381 }
382
383 return 0;
384}
385
386int
387boot_write_copy_done(const struct flash_area *fap)
388{
389 return boot_write_flag(BOOT_FLAG_COPY_DONE, fap);
390}
391
392int
393boot_write_image_ok(const struct flash_area *fap)
394{
395 return boot_write_flag(BOOT_FLAG_IMAGE_OK, fap);
396}
397
398int
399boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
400{
401 uint32_t off;
402 int rc;
403 uint8_t buf[BOOT_MAX_ALIGN];
404 uint8_t align;
David Vincze39e78552018-10-10 17:10:01 +0200405 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000406
407 off = boot_swap_size_off(fap);
Tamas Banc3828852018-02-01 12:24:16 +0000408 align = flash_area_align(fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000409 assert(align <= BOOT_MAX_ALIGN);
Tamas Ban581034a2017-12-19 19:54:37 +0000410 if (align < sizeof(swap_size)) {
411 align = sizeof(swap_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000412 }
David Vincze39e78552018-10-10 17:10:01 +0200413 erased_val = flash_area_erased_val(fap);
414 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Ban581034a2017-12-19 19:54:37 +0000415 memcpy(buf, (uint8_t *)&swap_size, sizeof(swap_size));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000416
417 rc = flash_area_write(fap, off, buf, align);
418 if (rc != 0) {
419 return BOOT_EFLASH;
420 }
421
422 return 0;
423}
424
425int
426boot_swap_type(void)
427{
428 const struct boot_swap_table *table;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100429 struct boot_swap_state primary_slot;
430 struct boot_swap_state secondary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000431 int rc;
David Vincze39e78552018-10-10 17:10:01 +0200432 size_t i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000433
David Vincze8bdfc2d2019-03-18 15:49:23 +0100434 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY, &primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000435 if (rc) {
436 return BOOT_SWAP_TYPE_PANIC;
437 }
438
David Vincze8bdfc2d2019-03-18 15:49:23 +0100439 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY,
440 &secondary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000441 if (rc) {
442 return BOOT_SWAP_TYPE_PANIC;
443 }
444
445 for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
446 table = boot_swap_tables + i;
447
David Vincze8bdfc2d2019-03-18 15:49:23 +0100448 if ((table->magic_primary_slot == BOOT_MAGIC_ANY ||
449 table->magic_primary_slot == primary_slot.magic) &&
450 (table->magic_secondary_slot == BOOT_MAGIC_ANY ||
451 table->magic_secondary_slot == secondary_slot.magic) &&
452 (table->image_ok_primary_slot == BOOT_FLAG_ANY ||
453 table->image_ok_primary_slot == primary_slot.image_ok) &&
454 (table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
455 table->image_ok_secondary_slot == secondary_slot.image_ok) &&
456 (table->copy_done_primary_slot == BOOT_FLAG_ANY ||
457 table->copy_done_primary_slot == primary_slot.copy_done)) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000458 BOOT_LOG_INF("Swap type: %s",
459 table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
460 table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
461 table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
462 "BUG; can't happen");
463 assert(table->swap_type == BOOT_SWAP_TYPE_TEST ||
464 table->swap_type == BOOT_SWAP_TYPE_PERM ||
465 table->swap_type == BOOT_SWAP_TYPE_REVERT);
466 return table->swap_type;
467 }
468 }
469
470 BOOT_LOG_INF("Swap type: none");
471 return BOOT_SWAP_TYPE_NONE;
472}
473
474/**
David Vincze8bdfc2d2019-03-18 15:49:23 +0100475 * Marks the image in the secondary slot as pending. On the next reboot,
476 * the system will perform a one-time boot of the the secondary slot image.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000477 *
478 * @param permanent Whether the image should be used permanently or
479 * only tested once:
480 * 0=run image once, then confirm or revert.
481 * 1=run image forever.
482 *
483 * @return 0 on success; nonzero on failure.
484 */
485int
486boot_set_pending(int permanent)
487{
Tamas Ban581034a2017-12-19 19:54:37 +0000488 const struct flash_area *fap = NULL;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100489 struct boot_swap_state state_secondary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000490 int rc;
491
David Vincze8bdfc2d2019-03-18 15:49:23 +0100492 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY,
493 &state_secondary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000494 if (rc != 0) {
495 return rc;
496 }
497
David Vincze8bdfc2d2019-03-18 15:49:23 +0100498 switch (state_secondary_slot.magic) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000499 case BOOT_MAGIC_GOOD:
500 /* Swap already scheduled. */
501 return 0;
502
503 case BOOT_MAGIC_UNSET:
David Vincze8bdfc2d2019-03-18 15:49:23 +0100504 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000505 if (rc != 0) {
506 rc = BOOT_EFLASH;
507 } else {
508 rc = boot_write_magic(fap);
509 }
510
511 if (rc == 0 && permanent) {
512 rc = boot_write_image_ok(fap);
513 }
514
515 flash_area_close(fap);
516 return rc;
517
518 default:
519 /* XXX: Temporary assert. */
520 assert(0);
521 return -1;
522 }
523}
524
525/**
David Vincze8bdfc2d2019-03-18 15:49:23 +0100526 * Marks the image in the primary slot as confirmed. The system will continue
527 * booting into the image in the primary slot until told to boot from a
528 * different slot.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000529 *
Tamas Ban581034a2017-12-19 19:54:37 +0000530 * @return 0 on success; non-zero on failure.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000531 */
532int
533boot_set_confirmed(void)
534{
Tamas Ban581034a2017-12-19 19:54:37 +0000535 const struct flash_area *fap = NULL;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100536 struct boot_swap_state state_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000537 int rc;
538
David Vincze8bdfc2d2019-03-18 15:49:23 +0100539 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY,
540 &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000541 if (rc != 0) {
542 return rc;
543 }
544
David Vincze8bdfc2d2019-03-18 15:49:23 +0100545 switch (state_primary_slot.magic) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000546 case BOOT_MAGIC_GOOD:
547 /* Confirm needed; proceed. */
548 break;
549
550 case BOOT_MAGIC_UNSET:
551 /* Already confirmed. */
552 return 0;
553
554 case BOOT_MAGIC_BAD:
555 /* Unexpected state. */
556 return BOOT_EBADVECT;
557 }
558
David Vincze8bdfc2d2019-03-18 15:49:23 +0100559 if (state_primary_slot.copy_done == BOOT_FLAG_UNSET) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000560 /* Swap never completed. This is unexpected. */
David Vincze39e78552018-10-10 17:10:01 +0200561 rc = BOOT_EBADVECT;
562 goto done;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000563 }
564
David Vincze8bdfc2d2019-03-18 15:49:23 +0100565 if (state_primary_slot.image_ok != BOOT_FLAG_UNSET) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000566 /* Already confirmed. */
David Vincze39e78552018-10-10 17:10:01 +0200567 goto done;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000568 }
569
David Vincze8bdfc2d2019-03-18 15:49:23 +0100570 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000571 if (rc) {
572 rc = BOOT_EFLASH;
573 goto done;
574 }
575
576 rc = boot_write_image_ok(fap);
577 if (rc != 0) {
578 goto done;
579 }
580
581 rc = 0;
582
583done:
584 flash_area_close(fap);
585 return rc;
586}