blob: 5ad8bcfe92a4c00a791f171940a7bc5dbc8f5a46 [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
David Vincze401c7422019-06-21 20:44:05 +0200115/**
116 * Determines if a status source table is satisfied by the specified magic
117 * code.
118 *
119 * @param tbl_val A magic field from a status source table.
120 * @param val The magic value in a trailer, encoded as a
121 * BOOT_MAGIC_[...].
122 *
123 * @return 1 if the two values are compatible;
124 * 0 otherwise.
125 */
126int
127boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
128{
129 switch (tbl_val) {
130 case BOOT_MAGIC_ANY:
131 return 1;
132
133 case BOOT_MAGIC_NOTGOOD:
134 return val != BOOT_MAGIC_GOOD;
135
136 default:
137 return tbl_val == val;
138 }
139}
140
Tamas Banf70ef8c2017-12-19 15:35:09 +0000141uint32_t
David Vincze401c7422019-06-21 20:44:05 +0200142boot_trailer_sz(uint8_t min_write_sz)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000143{
144 return /* state for all sectors */
145 BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz +
David Vincze401c7422019-06-21 20:44:05 +0200146 /* swap_type + copy_done + image_ok + swap_size */
147 BOOT_MAX_ALIGN * 4 +
Tamas Banf70ef8c2017-12-19 15:35:09 +0000148 BOOT_MAGIC_SZ;
149}
150
151static uint32_t
152boot_magic_off(const struct flash_area *fap)
153{
Tamas Banf70ef8c2017-12-19 15:35:09 +0000154 return fap->fa_size - BOOT_MAGIC_SZ;
155}
156
157int
158boot_status_entries(const struct flash_area *fap)
159{
160 switch (fap->fa_id) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100161 case FLASH_AREA_IMAGE_PRIMARY:
162 case FLASH_AREA_IMAGE_SECONDARY:
Tamas Banf70ef8c2017-12-19 15:35:09 +0000163 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
164 case FLASH_AREA_IMAGE_SCRATCH:
165 return BOOT_STATUS_STATE_COUNT;
166 default:
167 return BOOT_EBADARGS;
168 }
169}
170
171uint32_t
172boot_status_off(const struct flash_area *fap)
173{
174 uint32_t off_from_end;
175 uint8_t elem_sz;
176
177 elem_sz = flash_area_align(fap);
178
David Vincze401c7422019-06-21 20:44:05 +0200179 off_from_end = boot_trailer_sz(elem_sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000180
181 assert(off_from_end <= fap->fa_size);
182 return fap->fa_size - off_from_end;
183}
184
David Vincze401c7422019-06-21 20:44:05 +0200185uint32_t
186boot_swap_type_off(const struct flash_area *fap)
187{
188 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
189}
190
Tamas Banf70ef8c2017-12-19 15:35:09 +0000191static uint32_t
192boot_copy_done_off(const struct flash_area *fap)
193{
Tamas Banf70ef8c2017-12-19 15:35:09 +0000194 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
195}
196
197static uint32_t
198boot_image_ok_off(const struct flash_area *fap)
199{
Tamas Banf70ef8c2017-12-19 15:35:09 +0000200 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
201}
202
203static uint32_t
204boot_swap_size_off(const struct flash_area *fap)
205{
David Vincze401c7422019-06-21 20:44:05 +0200206 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 4;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000207}
208
209int
210boot_read_swap_state(const struct flash_area *fap,
211 struct boot_swap_state *state)
212{
David Vincze39e78552018-10-10 17:10:01 +0200213 uint32_t magic[BOOT_MAGIC_ARR_SZ];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000214 uint32_t off;
215 int rc;
216
217 off = boot_magic_off(fap);
David Vincze39e78552018-10-10 17:10:01 +0200218 rc = flash_area_read_is_empty(fap, off, magic, BOOT_MAGIC_SZ);
219 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000220 return BOOT_EFLASH;
221 }
David Vincze39e78552018-10-10 17:10:01 +0200222 if (rc == 1) {
223 state->magic = BOOT_MAGIC_UNSET;
224 } else {
225 state->magic = boot_magic_decode(magic);
226 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000227
David Vincze401c7422019-06-21 20:44:05 +0200228 off = boot_swap_type_off(fap);
229 rc = flash_area_read_is_empty(fap, off, &state->swap_type,
230 sizeof state->swap_type);
231 if (rc < 0) {
232 return BOOT_EFLASH;
233 }
234 if (rc == 1 || state->swap_type > BOOT_SWAP_TYPE_REVERT) {
235 state->swap_type = BOOT_SWAP_TYPE_NONE;
236 }
237
238 off = boot_copy_done_off(fap);
239 rc = flash_area_read_is_empty(fap, off, &state->copy_done,
240 sizeof state->copy_done);
241 if (rc < 0) {
242 return BOOT_EFLASH;
243 }
244 if (rc == 1) {
245 state->copy_done = BOOT_FLAG_UNSET;
246 } else {
247 state->copy_done = boot_flag_decode(state->copy_done);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000248 }
249
250 off = boot_image_ok_off(fap);
David Vincze401c7422019-06-21 20:44:05 +0200251 rc = flash_area_read_is_empty(fap, off, &state->image_ok,
252 sizeof state->image_ok);
David Vincze39e78552018-10-10 17:10:01 +0200253 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000254 return BOOT_EFLASH;
255 }
David Vincze39e78552018-10-10 17:10:01 +0200256 if (rc == 1) {
257 state->image_ok = BOOT_FLAG_UNSET;
258 } else {
259 state->image_ok = boot_flag_decode(state->image_ok);
260 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000261
262 return 0;
263}
264
265/**
266 * Reads the image trailer from the scratch area.
267 */
268int
269boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
270{
271 const struct flash_area *fap;
272 int rc;
273
274 switch (flash_area_id) {
275 case FLASH_AREA_IMAGE_SCRATCH:
David Vincze8bdfc2d2019-03-18 15:49:23 +0100276 case FLASH_AREA_IMAGE_PRIMARY:
277 case FLASH_AREA_IMAGE_SECONDARY:
Tamas Banf70ef8c2017-12-19 15:35:09 +0000278 rc = flash_area_open(flash_area_id, &fap);
279 if (rc != 0) {
280 return BOOT_EFLASH;
281 }
282 break;
283 default:
284 return BOOT_EBADARGS;
285 }
286
287 rc = boot_read_swap_state(fap, state);
288 flash_area_close(fap);
289 return rc;
290}
291
292int
293boot_read_swap_size(uint32_t *swap_size)
294{
David Vincze39e78552018-10-10 17:10:01 +0200295 uint32_t magic[BOOT_MAGIC_ARR_SZ];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000296 uint32_t off;
297 const struct flash_area *fap;
298 int rc;
299
300 /*
301 * In the middle a swap, tries to locate the saved swap size. Looks
David Vincze8bdfc2d2019-03-18 15:49:23 +0100302 * for a valid magic, first on the primary slot, then on scratch.
303 * Both "slots" can end up being temporary storage for a swap and it
304 * is assumed that if magic is valid then swap size is too, because
305 * magic is always written in the last step.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000306 */
307
David Vincze8bdfc2d2019-03-18 15:49:23 +0100308 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000309 if (rc != 0) {
310 return BOOT_EFLASH;
311 }
312
313 off = boot_magic_off(fap);
314 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
315 if (rc != 0) {
316 rc = BOOT_EFLASH;
317 goto out;
318 }
319
320 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) != 0) {
321 /*
David Vincze8bdfc2d2019-03-18 15:49:23 +0100322 * If the primary slot's magic is not valid, try scratch...
Tamas Banf70ef8c2017-12-19 15:35:09 +0000323 */
324
325 flash_area_close(fap);
326
327 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
328 if (rc != 0) {
329 return BOOT_EFLASH;
330 }
331
332 off = boot_magic_off(fap);
333 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
334 if (rc != 0) {
335 rc = BOOT_EFLASH;
336 goto out;
337 }
338
339 assert(memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0);
340 }
341
342 off = boot_swap_size_off(fap);
Tamas Ban581034a2017-12-19 19:54:37 +0000343 rc = flash_area_read(fap, off, swap_size, sizeof(*swap_size));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000344 if (rc != 0) {
345 rc = BOOT_EFLASH;
346 }
347
348out:
349 flash_area_close(fap);
350 return rc;
351}
352
353
354int
355boot_write_magic(const struct flash_area *fap)
356{
357 uint32_t off;
358 int rc;
359
360 off = boot_magic_off(fap);
361
David Vincze401c7422019-06-21 20:44:05 +0200362 BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%x (0x%x)",
363 fap->fa_id, off, fap->fa_off + off);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000364 rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
365 if (rc != 0) {
366 return BOOT_EFLASH;
367 }
368
369 return 0;
370}
371
372static int
David Vincze401c7422019-06-21 20:44:05 +0200373boot_write_trailer_byte(const struct flash_area *fap, uint32_t off,
374 uint8_t val)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000375{
Tamas Banf70ef8c2017-12-19 15:35:09 +0000376 uint8_t buf[BOOT_MAX_ALIGN];
377 uint8_t align;
David Vincze39e78552018-10-10 17:10:01 +0200378 uint8_t erased_val;
David Vincze401c7422019-06-21 20:44:05 +0200379 int rc;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000380
Tamas Banc3828852018-02-01 12:24:16 +0000381 align = flash_area_align(fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000382 assert(align <= BOOT_MAX_ALIGN);
David Vincze39e78552018-10-10 17:10:01 +0200383 erased_val = flash_area_erased_val(fap);
384 memset(buf, erased_val, BOOT_MAX_ALIGN);
David Vincze401c7422019-06-21 20:44:05 +0200385 buf[0] = val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000386
387 rc = flash_area_write(fap, off, buf, align);
388 if (rc != 0) {
389 return BOOT_EFLASH;
390 }
391
392 return 0;
393}
394
395int
396boot_write_copy_done(const struct flash_area *fap)
397{
David Vincze401c7422019-06-21 20:44:05 +0200398 uint32_t off;
399
400 off = boot_copy_done_off(fap);
401 BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%x (0x%x)",
402 fap->fa_id, off, fap->fa_off + off);
403 return boot_write_trailer_byte(fap, off, BOOT_FLAG_SET);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000404}
405
406int
407boot_write_image_ok(const struct flash_area *fap)
408{
David Vincze401c7422019-06-21 20:44:05 +0200409 uint32_t off;
410
411 off = boot_image_ok_off(fap);
412 BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%x (0x%x)",
413 fap->fa_id, off, fap->fa_off + off);
414 return boot_write_trailer_byte(fap, off, BOOT_FLAG_SET);
415}
416
417/**
418 * Writes the specified value to the `swap-type` field of an image trailer.
419 * This value is persisted so that the boot loader knows what swap operation to
420 * resume in case of an unexpected reset.
421 */
422int
423boot_write_swap_type(const struct flash_area *fap, uint8_t swap_type)
424{
425 uint32_t off;
426
427 off = boot_swap_type_off(fap);
428 BOOT_LOG_DBG("writing swap_type; fa_id=%d off=0x%x (0x%x), swap_type=0x%x",
429 fap->fa_id, off, fap->fa_off + off, swap_type);
430 return boot_write_trailer_byte(fap, off, swap_type);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000431}
432
433int
434boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
435{
436 uint32_t off;
437 int rc;
438 uint8_t buf[BOOT_MAX_ALIGN];
439 uint8_t align;
David Vincze39e78552018-10-10 17:10:01 +0200440 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000441
442 off = boot_swap_size_off(fap);
Tamas Banc3828852018-02-01 12:24:16 +0000443 align = flash_area_align(fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000444 assert(align <= BOOT_MAX_ALIGN);
Tamas Ban581034a2017-12-19 19:54:37 +0000445 if (align < sizeof(swap_size)) {
446 align = sizeof(swap_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000447 }
David Vincze39e78552018-10-10 17:10:01 +0200448 erased_val = flash_area_erased_val(fap);
449 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Ban581034a2017-12-19 19:54:37 +0000450 memcpy(buf, (uint8_t *)&swap_size, sizeof(swap_size));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000451
David Vincze401c7422019-06-21 20:44:05 +0200452 BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%x (0x%x)",
453 fap->fa_id, off, fap->fa_off + off);
454
Tamas Banf70ef8c2017-12-19 15:35:09 +0000455 rc = flash_area_write(fap, off, buf, align);
456 if (rc != 0) {
457 return BOOT_EFLASH;
458 }
459
460 return 0;
461}
462
463int
464boot_swap_type(void)
465{
466 const struct boot_swap_table *table;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100467 struct boot_swap_state primary_slot;
468 struct boot_swap_state secondary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000469 int rc;
David Vincze39e78552018-10-10 17:10:01 +0200470 size_t i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000471
David Vincze8bdfc2d2019-03-18 15:49:23 +0100472 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY, &primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000473 if (rc) {
474 return BOOT_SWAP_TYPE_PANIC;
475 }
476
David Vincze8bdfc2d2019-03-18 15:49:23 +0100477 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY,
478 &secondary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000479 if (rc) {
480 return BOOT_SWAP_TYPE_PANIC;
481 }
482
483 for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
484 table = boot_swap_tables + i;
485
David Vincze401c7422019-06-21 20:44:05 +0200486 if (boot_magic_compatible_check(table->magic_primary_slot,
487 primary_slot.magic) &&
488 boot_magic_compatible_check(table->magic_secondary_slot,
489 secondary_slot.magic) &&
David Vincze8bdfc2d2019-03-18 15:49:23 +0100490 (table->image_ok_primary_slot == BOOT_FLAG_ANY ||
491 table->image_ok_primary_slot == primary_slot.image_ok) &&
492 (table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
493 table->image_ok_secondary_slot == secondary_slot.image_ok) &&
494 (table->copy_done_primary_slot == BOOT_FLAG_ANY ||
495 table->copy_done_primary_slot == primary_slot.copy_done)) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000496 BOOT_LOG_INF("Swap type: %s",
497 table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
498 table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
499 table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
500 "BUG; can't happen");
501 assert(table->swap_type == BOOT_SWAP_TYPE_TEST ||
502 table->swap_type == BOOT_SWAP_TYPE_PERM ||
503 table->swap_type == BOOT_SWAP_TYPE_REVERT);
504 return table->swap_type;
505 }
506 }
507
508 BOOT_LOG_INF("Swap type: none");
509 return BOOT_SWAP_TYPE_NONE;
510}
511
512/**
David Vincze8bdfc2d2019-03-18 15:49:23 +0100513 * Marks the image in the secondary slot as pending. On the next reboot,
514 * the system will perform a one-time boot of the the secondary slot image.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000515 *
516 * @param permanent Whether the image should be used permanently or
517 * only tested once:
518 * 0=run image once, then confirm or revert.
519 * 1=run image forever.
520 *
521 * @return 0 on success; nonzero on failure.
522 */
523int
524boot_set_pending(int permanent)
525{
Tamas Ban581034a2017-12-19 19:54:37 +0000526 const struct flash_area *fap = NULL;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100527 struct boot_swap_state state_secondary_slot;
David Vincze401c7422019-06-21 20:44:05 +0200528 uint8_t swap_type;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000529 int rc;
530
David Vincze8bdfc2d2019-03-18 15:49:23 +0100531 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY,
532 &state_secondary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000533 if (rc != 0) {
534 return rc;
535 }
536
David Vincze8bdfc2d2019-03-18 15:49:23 +0100537 switch (state_secondary_slot.magic) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000538 case BOOT_MAGIC_GOOD:
539 /* Swap already scheduled. */
540 return 0;
541
542 case BOOT_MAGIC_UNSET:
David Vincze8bdfc2d2019-03-18 15:49:23 +0100543 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000544 if (rc != 0) {
545 rc = BOOT_EFLASH;
546 } else {
547 rc = boot_write_magic(fap);
548 }
549
550 if (rc == 0 && permanent) {
551 rc = boot_write_image_ok(fap);
552 }
553
David Vincze401c7422019-06-21 20:44:05 +0200554 if (rc == 0) {
555 if (permanent) {
556 swap_type = BOOT_SWAP_TYPE_PERM;
557 } else {
558 swap_type = BOOT_SWAP_TYPE_TEST;
559 }
560 rc = boot_write_swap_type(fap, swap_type);
561 }
562
Tamas Banf70ef8c2017-12-19 15:35:09 +0000563 flash_area_close(fap);
564 return rc;
565
David Vincze401c7422019-06-21 20:44:05 +0200566 case BOOT_MAGIC_BAD:
567 /* The image slot is corrupt. There is no way to recover, so erase the
568 * slot to allow future upgrades.
569 */
570 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap);
571 if (rc != 0) {
572 return BOOT_EFLASH;
573 }
574
575 flash_area_erase(fap, 0, fap->fa_size);
576 flash_area_close(fap);
577 return BOOT_EBADIMAGE;
578
Tamas Banf70ef8c2017-12-19 15:35:09 +0000579 default:
Tamas Banf70ef8c2017-12-19 15:35:09 +0000580 assert(0);
David Vincze401c7422019-06-21 20:44:05 +0200581 return BOOT_EBADIMAGE;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000582 }
583}
584
585/**
David Vincze8bdfc2d2019-03-18 15:49:23 +0100586 * Marks the image in the primary slot as confirmed. The system will continue
587 * booting into the image in the primary slot until told to boot from a
588 * different slot.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000589 *
Tamas Ban581034a2017-12-19 19:54:37 +0000590 * @return 0 on success; non-zero on failure.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000591 */
592int
593boot_set_confirmed(void)
594{
Tamas Ban581034a2017-12-19 19:54:37 +0000595 const struct flash_area *fap = NULL;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100596 struct boot_swap_state state_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000597 int rc;
598
David Vincze8bdfc2d2019-03-18 15:49:23 +0100599 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY,
600 &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000601 if (rc != 0) {
602 return rc;
603 }
604
David Vincze8bdfc2d2019-03-18 15:49:23 +0100605 switch (state_primary_slot.magic) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000606 case BOOT_MAGIC_GOOD:
607 /* Confirm needed; proceed. */
608 break;
609
610 case BOOT_MAGIC_UNSET:
611 /* Already confirmed. */
612 return 0;
613
614 case BOOT_MAGIC_BAD:
615 /* Unexpected state. */
616 return BOOT_EBADVECT;
617 }
618
David Vincze8bdfc2d2019-03-18 15:49:23 +0100619 if (state_primary_slot.copy_done == BOOT_FLAG_UNSET) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000620 /* Swap never completed. This is unexpected. */
David Vincze39e78552018-10-10 17:10:01 +0200621 rc = BOOT_EBADVECT;
622 goto done;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000623 }
624
David Vincze8bdfc2d2019-03-18 15:49:23 +0100625 if (state_primary_slot.image_ok != BOOT_FLAG_UNSET) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000626 /* Already confirmed. */
David Vincze39e78552018-10-10 17:10:01 +0200627 goto done;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000628 }
629
David Vincze8bdfc2d2019-03-18 15:49:23 +0100630 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000631 if (rc) {
632 rc = BOOT_EFLASH;
633 goto done;
634 }
635
636 rc = boot_write_image_ok(fap);
637 if (rc != 0) {
638 goto done;
639 }
640
641 rc = 0;
642
643done:
644 flash_area_close(fap);
645 return rc;
646}