blob: 79fdc9a3669b91e64a1fd2d01fafbb03e980e27a [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 {
Tamas Banf70ef8c2017-12-19 15:35:09 +000047 uint8_t magic_slot0;
48 uint8_t magic_slot1;
49 uint8_t image_ok_slot0;
50 uint8_t image_ok_slot1;
51 uint8_t copy_done_slot0;
52
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 *
60 * NOTE: the table order is very important. The settings in Slot 1 always
61 * are priority to Slot 0 and should be located earlier in the table.
62 *
63 * The table lists only states where there is action needs to be taken by
64 * the bootloader, as in starting/finishing a swap operation.
65 */
66static const struct boot_swap_table boot_swap_tables[] = {
67 {
David Vincze39e78552018-10-10 17:10:01 +020068 .magic_slot0 = BOOT_MAGIC_ANY,
Tamas Banf70ef8c2017-12-19 15:35:09 +000069 .magic_slot1 = BOOT_MAGIC_GOOD,
David Vincze39e78552018-10-10 17:10:01 +020070 .image_ok_slot0 = BOOT_FLAG_ANY,
71 .image_ok_slot1 = BOOT_FLAG_UNSET,
72 .copy_done_slot0 = BOOT_FLAG_ANY,
Tamas Banf70ef8c2017-12-19 15:35:09 +000073 .swap_type = BOOT_SWAP_TYPE_TEST,
74 },
75 {
David Vincze39e78552018-10-10 17:10:01 +020076 .magic_slot0 = BOOT_MAGIC_ANY,
Tamas Banf70ef8c2017-12-19 15:35:09 +000077 .magic_slot1 = BOOT_MAGIC_GOOD,
David Vincze39e78552018-10-10 17:10:01 +020078 .image_ok_slot0 = BOOT_FLAG_ANY,
79 .image_ok_slot1 = BOOT_FLAG_SET,
80 .copy_done_slot0 = BOOT_FLAG_ANY,
Tamas Banf70ef8c2017-12-19 15:35:09 +000081 .swap_type = BOOT_SWAP_TYPE_PERM,
82 },
83 {
84 .magic_slot0 = BOOT_MAGIC_GOOD,
85 .magic_slot1 = BOOT_MAGIC_UNSET,
David Vincze39e78552018-10-10 17:10:01 +020086 .image_ok_slot0 = BOOT_FLAG_UNSET,
87 .image_ok_slot1 = BOOT_FLAG_ANY,
88 .copy_done_slot0 = BOOT_FLAG_SET,
Tamas Banf70ef8c2017-12-19 15:35:09 +000089 .swap_type = BOOT_SWAP_TYPE_REVERT,
90 },
91};
92
93#define BOOT_SWAP_TABLES_COUNT \
Tamas Ban581034a2017-12-19 19:54:37 +000094 (sizeof(boot_swap_tables) / sizeof(boot_swap_tables[0]))
Tamas Banf70ef8c2017-12-19 15:35:09 +000095
David Vincze39e78552018-10-10 17:10:01 +020096static int
97boot_magic_decode(const uint32_t *magic)
Tamas Banf70ef8c2017-12-19 15:35:09 +000098{
Tamas Banf70ef8c2017-12-19 15:35:09 +000099 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
100 return BOOT_MAGIC_GOOD;
101 }
David Vincze39e78552018-10-10 17:10:01 +0200102 return BOOT_MAGIC_BAD;
103}
Tamas Banf70ef8c2017-12-19 15:35:09 +0000104
David Vincze39e78552018-10-10 17:10:01 +0200105static int
106boot_flag_decode(uint8_t flag)
107{
108 if (flag != BOOT_FLAG_SET) {
109 return BOOT_FLAG_BAD;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000110 }
David Vincze39e78552018-10-10 17:10:01 +0200111 return BOOT_FLAG_SET;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000112}
113
114uint32_t
115boot_slots_trailer_sz(uint8_t min_write_sz)
116{
117 return /* state for all sectors */
118 BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz +
119 BOOT_MAX_ALIGN * 3 /* copy_done + image_ok + swap_size */ +
120 BOOT_MAGIC_SZ;
121}
122
123static uint32_t
124boot_scratch_trailer_sz(uint8_t min_write_sz)
125{
126 return BOOT_STATUS_STATE_COUNT * min_write_sz + /* state for one sector */
127 BOOT_MAX_ALIGN * 2 + /* image_ok + swap_size */
128 BOOT_MAGIC_SZ;
129}
130
131static uint32_t
132boot_magic_off(const struct flash_area *fap)
133{
134 assert(offsetof(struct image_trailer, magic) == 16);
135 return fap->fa_size - BOOT_MAGIC_SZ;
136}
137
138int
139boot_status_entries(const struct flash_area *fap)
140{
141 switch (fap->fa_id) {
142 case FLASH_AREA_IMAGE_0:
143 case FLASH_AREA_IMAGE_1:
144 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
145 case FLASH_AREA_IMAGE_SCRATCH:
146 return BOOT_STATUS_STATE_COUNT;
147 default:
148 return BOOT_EBADARGS;
149 }
150}
151
152uint32_t
153boot_status_off(const struct flash_area *fap)
154{
155 uint32_t off_from_end;
156 uint8_t elem_sz;
157
158 elem_sz = flash_area_align(fap);
159
160 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
161 off_from_end = boot_scratch_trailer_sz(elem_sz);
162 } else {
163 off_from_end = boot_slots_trailer_sz(elem_sz);
164 }
165
166 assert(off_from_end <= fap->fa_size);
167 return fap->fa_size - off_from_end;
168}
169
170static uint32_t
171boot_copy_done_off(const struct flash_area *fap)
172{
173 assert(fap->fa_id != FLASH_AREA_IMAGE_SCRATCH);
174 assert(offsetof(struct image_trailer, copy_done) == 0);
175 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
176}
177
178static uint32_t
179boot_image_ok_off(const struct flash_area *fap)
180{
181 assert(offsetof(struct image_trailer, image_ok) == 8);
182 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
183}
184
185static uint32_t
186boot_swap_size_off(const struct flash_area *fap)
187{
188 /*
189 * The "swap_size" field if located just before the trailer.
190 * The scratch slot doesn't store "copy_done"...
191 */
192 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
193 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
194 }
195
196 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
197}
198
199int
200boot_read_swap_state(const struct flash_area *fap,
201 struct boot_swap_state *state)
202{
David Vincze39e78552018-10-10 17:10:01 +0200203 uint32_t magic[BOOT_MAGIC_ARR_SZ];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000204 uint32_t off;
205 int rc;
206
207 off = boot_magic_off(fap);
David Vincze39e78552018-10-10 17:10:01 +0200208 rc = flash_area_read_is_empty(fap, off, magic, BOOT_MAGIC_SZ);
209 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000210 return BOOT_EFLASH;
211 }
David Vincze39e78552018-10-10 17:10:01 +0200212 if (rc == 1) {
213 state->magic = BOOT_MAGIC_UNSET;
214 } else {
215 state->magic = boot_magic_decode(magic);
216 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000217
218 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
219 off = boot_copy_done_off(fap);
David Vincze39e78552018-10-10 17:10:01 +0200220 rc = flash_area_read_is_empty(fap, off, &state->copy_done,
221 sizeof state->copy_done);
222 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000223 return BOOT_EFLASH;
224 }
David Vincze39e78552018-10-10 17:10:01 +0200225 if (rc == 1) {
226 state->copy_done = BOOT_FLAG_UNSET;
227 } else {
228 state->copy_done = boot_flag_decode(state->copy_done);
229 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000230 }
231
232 off = boot_image_ok_off(fap);
David Vincze39e78552018-10-10 17:10:01 +0200233 rc = flash_area_read_is_empty(fap, off, &state->image_ok, sizeof state->image_ok);
234 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000235 return BOOT_EFLASH;
236 }
David Vincze39e78552018-10-10 17:10:01 +0200237 if (rc == 1) {
238 state->image_ok = BOOT_FLAG_UNSET;
239 } else {
240 state->image_ok = boot_flag_decode(state->image_ok);
241 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000242
243 return 0;
244}
245
246/**
247 * Reads the image trailer from the scratch area.
248 */
249int
250boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
251{
252 const struct flash_area *fap;
253 int rc;
254
255 switch (flash_area_id) {
256 case FLASH_AREA_IMAGE_SCRATCH:
257 case FLASH_AREA_IMAGE_0:
258 case FLASH_AREA_IMAGE_1:
259 rc = flash_area_open(flash_area_id, &fap);
260 if (rc != 0) {
261 return BOOT_EFLASH;
262 }
263 break;
264 default:
265 return BOOT_EBADARGS;
266 }
267
268 rc = boot_read_swap_state(fap, state);
269 flash_area_close(fap);
270 return rc;
271}
272
273int
274boot_read_swap_size(uint32_t *swap_size)
275{
David Vincze39e78552018-10-10 17:10:01 +0200276 uint32_t magic[BOOT_MAGIC_ARR_SZ];
Tamas Banf70ef8c2017-12-19 15:35:09 +0000277 uint32_t off;
278 const struct flash_area *fap;
279 int rc;
280
281 /*
282 * In the middle a swap, tries to locate the saved swap size. Looks
283 * for a valid magic, first on Slot 0, then on scratch. Both "slots"
284 * can end up being temporary storage for a swap and it is assumed
285 * that if magic is valid then swap size is too, because magic is
286 * always written in the last step.
287 */
288
289 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
290 if (rc != 0) {
291 return BOOT_EFLASH;
292 }
293
294 off = boot_magic_off(fap);
295 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
296 if (rc != 0) {
297 rc = BOOT_EFLASH;
298 goto out;
299 }
300
301 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) != 0) {
302 /*
303 * If Slot 0 's magic is not valid, try scratch...
304 */
305
306 flash_area_close(fap);
307
308 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
309 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 assert(memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0);
321 }
322
323 off = boot_swap_size_off(fap);
Tamas Ban581034a2017-12-19 19:54:37 +0000324 rc = flash_area_read(fap, off, swap_size, sizeof(*swap_size));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000325 if (rc != 0) {
326 rc = BOOT_EFLASH;
327 }
328
329out:
330 flash_area_close(fap);
331 return rc;
332}
333
334
335int
336boot_write_magic(const struct flash_area *fap)
337{
338 uint32_t off;
339 int rc;
340
341 off = boot_magic_off(fap);
342
343 rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
344 if (rc != 0) {
345 return BOOT_EFLASH;
346 }
347
348 return 0;
349}
350
351static int
352boot_write_flag(int flag, const struct flash_area *fap)
353{
354 uint32_t off;
355 int rc;
356 uint8_t buf[BOOT_MAX_ALIGN];
357 uint8_t align;
David Vincze39e78552018-10-10 17:10:01 +0200358 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000359
360 switch (flag) {
361 case BOOT_FLAG_COPY_DONE:
362 off = boot_copy_done_off(fap);
363 break;
364 case BOOT_FLAG_IMAGE_OK:
365 off = boot_image_ok_off(fap);
366 break;
367 default:
368 return BOOT_EBADARGS;
369 }
370
Tamas Banc3828852018-02-01 12:24:16 +0000371 align = flash_area_align(fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000372 assert(align <= BOOT_MAX_ALIGN);
David Vincze39e78552018-10-10 17:10:01 +0200373 erased_val = flash_area_erased_val(fap);
374 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000375 buf[0] = BOOT_FLAG_SET;
376
377 rc = flash_area_write(fap, off, buf, align);
378 if (rc != 0) {
379 return BOOT_EFLASH;
380 }
381
382 return 0;
383}
384
385int
386boot_write_copy_done(const struct flash_area *fap)
387{
388 return boot_write_flag(BOOT_FLAG_COPY_DONE, fap);
389}
390
391int
392boot_write_image_ok(const struct flash_area *fap)
393{
394 return boot_write_flag(BOOT_FLAG_IMAGE_OK, fap);
395}
396
397int
398boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
399{
400 uint32_t off;
401 int rc;
402 uint8_t buf[BOOT_MAX_ALIGN];
403 uint8_t align;
David Vincze39e78552018-10-10 17:10:01 +0200404 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000405
406 off = boot_swap_size_off(fap);
Tamas Banc3828852018-02-01 12:24:16 +0000407 align = flash_area_align(fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000408 assert(align <= BOOT_MAX_ALIGN);
Tamas Ban581034a2017-12-19 19:54:37 +0000409 if (align < sizeof(swap_size)) {
410 align = sizeof(swap_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000411 }
David Vincze39e78552018-10-10 17:10:01 +0200412 erased_val = flash_area_erased_val(fap);
413 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Ban581034a2017-12-19 19:54:37 +0000414 memcpy(buf, (uint8_t *)&swap_size, sizeof(swap_size));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000415
416 rc = flash_area_write(fap, off, buf, align);
417 if (rc != 0) {
418 return BOOT_EFLASH;
419 }
420
421 return 0;
422}
423
424int
425boot_swap_type(void)
426{
427 const struct boot_swap_table *table;
428 struct boot_swap_state slot0;
429 struct boot_swap_state slot1;
430 int rc;
David Vincze39e78552018-10-10 17:10:01 +0200431 size_t i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000432
433 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &slot0);
434 if (rc) {
435 return BOOT_SWAP_TYPE_PANIC;
436 }
437
438 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &slot1);
439 if (rc) {
440 return BOOT_SWAP_TYPE_PANIC;
441 }
442
443 for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
444 table = boot_swap_tables + i;
445
David Vincze39e78552018-10-10 17:10:01 +0200446 if ((table->magic_slot0 == BOOT_MAGIC_ANY ||
447 table->magic_slot0 == slot0.magic) &&
448 (table->magic_slot1 == BOOT_MAGIC_ANY ||
449 table->magic_slot1 == slot1.magic) &&
450 (table->image_ok_slot0 == BOOT_FLAG_ANY ||
451 table->image_ok_slot0 == slot0.image_ok) &&
452 (table->image_ok_slot1 == BOOT_FLAG_ANY ||
453 table->image_ok_slot1 == slot1.image_ok) &&
454 (table->copy_done_slot0 == BOOT_FLAG_ANY ||
455 table->copy_done_slot0 == slot0.copy_done)) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000456 BOOT_LOG_INF("Swap type: %s",
457 table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
458 table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
459 table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
460 "BUG; can't happen");
461 assert(table->swap_type == BOOT_SWAP_TYPE_TEST ||
462 table->swap_type == BOOT_SWAP_TYPE_PERM ||
463 table->swap_type == BOOT_SWAP_TYPE_REVERT);
464 return table->swap_type;
465 }
466 }
467
468 BOOT_LOG_INF("Swap type: none");
469 return BOOT_SWAP_TYPE_NONE;
470}
471
472/**
473 * Marks the image in slot 1 as pending. On the next reboot, the system will
474 * perform a one-time boot of the slot 1 image.
475 *
476 * @param permanent Whether the image should be used permanently or
477 * only tested once:
478 * 0=run image once, then confirm or revert.
479 * 1=run image forever.
480 *
481 * @return 0 on success; nonzero on failure.
482 */
483int
484boot_set_pending(int permanent)
485{
Tamas Ban581034a2017-12-19 19:54:37 +0000486 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000487 struct boot_swap_state state_slot1;
488 int rc;
489
490 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &state_slot1);
491 if (rc != 0) {
492 return rc;
493 }
494
495 switch (state_slot1.magic) {
496 case BOOT_MAGIC_GOOD:
497 /* Swap already scheduled. */
498 return 0;
499
500 case BOOT_MAGIC_UNSET:
501 rc = flash_area_open(FLASH_AREA_IMAGE_1, &fap);
502 if (rc != 0) {
503 rc = BOOT_EFLASH;
504 } else {
505 rc = boot_write_magic(fap);
506 }
507
508 if (rc == 0 && permanent) {
509 rc = boot_write_image_ok(fap);
510 }
511
512 flash_area_close(fap);
513 return rc;
514
515 default:
516 /* XXX: Temporary assert. */
517 assert(0);
518 return -1;
519 }
520}
521
522/**
Tamas Ban581034a2017-12-19 19:54:37 +0000523 * Marks the image in slot 0 as confirmed. The system will continue booting
524 * into the image in slot 0 until told to boot from a different slot.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000525 *
Tamas Ban581034a2017-12-19 19:54:37 +0000526 * @return 0 on success; non-zero on failure.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000527 */
528int
529boot_set_confirmed(void)
530{
Tamas Ban581034a2017-12-19 19:54:37 +0000531 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000532 struct boot_swap_state state_slot0;
533 int rc;
534
535 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
536 if (rc != 0) {
537 return rc;
538 }
539
540 switch (state_slot0.magic) {
541 case BOOT_MAGIC_GOOD:
542 /* Confirm needed; proceed. */
543 break;
544
545 case BOOT_MAGIC_UNSET:
546 /* Already confirmed. */
547 return 0;
548
549 case BOOT_MAGIC_BAD:
550 /* Unexpected state. */
551 return BOOT_EBADVECT;
552 }
553
554 if (state_slot0.copy_done == BOOT_FLAG_UNSET) {
555 /* Swap never completed. This is unexpected. */
David Vincze39e78552018-10-10 17:10:01 +0200556 rc = BOOT_EBADVECT;
557 goto done;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000558 }
559
560 if (state_slot0.image_ok != BOOT_FLAG_UNSET) {
561 /* Already confirmed. */
David Vincze39e78552018-10-10 17:10:01 +0200562 goto done;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000563 }
564
565 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
566 if (rc) {
567 rc = BOOT_EFLASH;
568 goto done;
569 }
570
571 rc = boot_write_image_ok(fap);
572 if (rc != 0) {
573 goto done;
574 }
575
576 rc = 0;
577
578done:
579 flash_area_close(fap);
580 return rc;
581}