blob: 5c04c2facf07c5746f201488df96c130b44af1cb [file] [log] [blame]
Christopher Collins92ea77f2016-12-12 15:59:26 -08001/*
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>
Fabio Utziga0bc9b52017-06-28 09:19:55 -030023#include <stddef.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080024
Christopher Collins92ea77f2016-12-12 15:59:26 -080025#include "sysflash/sysflash.h"
26#include "hal/hal_bsp.h"
27#include "hal/hal_flash.h"
28#include "flash_map/flash_map.h"
29#include "os/os.h"
30#include "bootutil/image.h"
31#include "bootutil/bootutil.h"
32#include "bootutil_priv.h"
33
Fabio Utzig7ebb7c22017-04-26 10:59:31 -030034#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
35#include "bootutil/bootutil_log.h"
36
Christopher Collins92ea77f2016-12-12 15:59:26 -080037int boot_current_slot;
38
Fabio Utzig24a273d2017-04-20 08:21:31 -030039const uint32_t boot_img_magic[] = {
Christopher Collins92ea77f2016-12-12 15:59:26 -080040 0xf395c277,
41 0x7fefd260,
42 0x0f505235,
43 0x8079b62c,
44};
45
Fabio Utzig24a273d2017-04-20 08:21:31 -030046const uint32_t BOOT_MAGIC_SZ = sizeof boot_img_magic;
Fabio Utziga0bc9b52017-06-28 09:19:55 -030047const uint32_t BOOT_MAX_ALIGN = MAX_FLASH_ALIGN;
Fabio Utzig24a273d2017-04-20 08:21:31 -030048
Christopher Collins92ea77f2016-12-12 15:59:26 -080049struct boot_swap_table {
50 /** * For each field, a value of 0 means "any". */
51 uint8_t bsw_magic_slot0;
52 uint8_t bsw_magic_slot1;
53 uint8_t bsw_image_ok_slot0;
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080054 uint8_t bsw_image_ok_slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -080055
56 uint8_t bsw_swap_type;
57};
58
59/**
60 * This set of tables maps image trailer contents to swap operation type.
61 * When searching for a match, these tables must be iterated sequentially.
62 */
63static const struct boot_swap_table boot_swap_tables[] = {
64 {
65 /* | slot-0 | slot-1 |
66 *----------+------------+------------|
67 * magic | Unset | Unset |
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080068 * image-ok | Any | Any |
Christopher Collins92ea77f2016-12-12 15:59:26 -080069 * ---------+------------+------------'
70 * swap: none |
71 * -----------------------------------'
72 */
73 .bsw_magic_slot0 = BOOT_MAGIC_UNSET,
74 .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
75 .bsw_image_ok_slot0 = 0,
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080076 .bsw_image_ok_slot1 = 0,
Christopher Collins92ea77f2016-12-12 15:59:26 -080077 .bsw_swap_type = BOOT_SWAP_TYPE_NONE,
78 },
79
80 {
81 /* | slot-0 | slot-1 |
82 *----------+------------+------------|
83 * magic | Any | Good |
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080084 * image-ok | Any | Unset |
85 * ---------+------------+------------`
86 * swap: test |
87 * -----------------------------------'
Christopher Collins92ea77f2016-12-12 15:59:26 -080088 */
89 .bsw_magic_slot0 = 0,
90 .bsw_magic_slot1 = BOOT_MAGIC_GOOD,
91 .bsw_image_ok_slot0 = 0,
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080092 .bsw_image_ok_slot1 = 0xff,
Christopher Collins92ea77f2016-12-12 15:59:26 -080093 .bsw_swap_type = BOOT_SWAP_TYPE_TEST,
94 },
95
96 {
97 /* | slot-0 | slot-1 |
98 *----------+------------+------------|
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080099 * magic | Any | Good |
100 * image-ok | Any | 0x01 |
101 * ---------+------------+------------`
102 * swap: permanent |
103 * -----------------------------------'
104 */
105 .bsw_magic_slot0 = 0,
106 .bsw_magic_slot1 = BOOT_MAGIC_GOOD,
107 .bsw_image_ok_slot0 = 0,
108 .bsw_image_ok_slot1 = 0x01,
109 .bsw_swap_type = BOOT_SWAP_TYPE_PERM,
110 },
111
112 {
113 /* | slot-0 | slot-1 |
114 *----------+------------+------------|
Christopher Collins92ea77f2016-12-12 15:59:26 -0800115 * magic | Good | Unset |
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800116 * image-ok | 0xff | Any |
Christopher Collins92ea77f2016-12-12 15:59:26 -0800117 * ---------+------------+------------'
118 * swap: revert (test image running) |
119 * -----------------------------------'
120 */
121 .bsw_magic_slot0 = BOOT_MAGIC_GOOD,
122 .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
123 .bsw_image_ok_slot0 = 0xff,
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800124 .bsw_image_ok_slot1 = 0,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800125 .bsw_swap_type = BOOT_SWAP_TYPE_REVERT,
126 },
127
128 {
129 /* | slot-0 | slot-1 |
130 *----------+------------+------------|
131 * magic | Good | Unset |
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800132 * image-ok | 0x01 | Any |
Christopher Collins92ea77f2016-12-12 15:59:26 -0800133 * ---------+------------+------------'
134 * swap: none (confirmed test image) |
135 * -----------------------------------'
136 */
137 .bsw_magic_slot0 = BOOT_MAGIC_GOOD,
138 .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
139 .bsw_image_ok_slot0 = 0x01,
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800140 .bsw_image_ok_slot1 = 0,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800141 .bsw_swap_type = BOOT_SWAP_TYPE_NONE,
142 },
143};
144
145#define BOOT_SWAP_TABLES_COUNT \
146 (sizeof boot_swap_tables / sizeof boot_swap_tables[0])
147
148int
149boot_magic_code(const uint32_t *magic)
150{
151 int i;
152
Fabio Utzig24a273d2017-04-20 08:21:31 -0300153 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800154 return BOOT_MAGIC_GOOD;
155 }
156
Fabio Utzig24a273d2017-04-20 08:21:31 -0300157 for (i = 0; i < BOOT_MAGIC_SZ / sizeof *magic; i++) {
158 if (magic[i] != 0xffffffff) {
159 return BOOT_MAGIC_BAD;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800160 }
161 }
162
Fabio Utzig24a273d2017-04-20 08:21:31 -0300163 return BOOT_MAGIC_UNSET;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800164}
165
166uint32_t
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300167boot_slots_trailer_sz(uint8_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800168{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300169 return /* state for all sectors */
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300170 BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz +
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300171 BOOT_MAX_ALIGN * 2 /* copy_done + image_ok */ +
172 BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800173}
174
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300175static uint32_t
176boot_scratch_trailer_sz(uint8_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800177{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300178 return BOOT_STATUS_STATE_COUNT * min_write_sz + /* state for one sector */
179 BOOT_MAX_ALIGN + /* image_ok */
180 BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800181}
182
183static uint32_t
184boot_magic_off(const struct flash_area *fap)
185{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300186 assert(offsetof(struct image_trailer, magic) == 16);
187 return fap->fa_size - BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800188}
189
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400190int
191boot_status_entries(const struct flash_area *fap)
192{
193 switch (fap->fa_id) {
194 case FLASH_AREA_IMAGE_0:
195 case FLASH_AREA_IMAGE_1:
196 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
197 case FLASH_AREA_IMAGE_SCRATCH:
198 return BOOT_STATUS_STATE_COUNT;
199 default:
200 return BOOT_EBADARGS;
201 }
202}
203
Christopher Collins92ea77f2016-12-12 15:59:26 -0800204uint32_t
205boot_status_off(const struct flash_area *fap)
206{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300207 uint32_t off_from_end;
208 uint8_t elem_sz;
209
210 elem_sz = flash_area_align(fap);
211
212 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
213 off_from_end = boot_scratch_trailer_sz(elem_sz);
214 } else {
215 off_from_end = boot_slots_trailer_sz(elem_sz);
216 }
217
218 assert(off_from_end <= fap->fa_size);
219 return fap->fa_size - off_from_end;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800220}
221
222static uint32_t
223boot_copy_done_off(const struct flash_area *fap)
224{
Fabio Utzig2473ac02017-05-02 12:45:02 -0300225 assert(fap->fa_id != FLASH_AREA_IMAGE_SCRATCH);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300226 assert(offsetof(struct image_trailer, copy_done) == 0);
227 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800228}
229
230static uint32_t
231boot_image_ok_off(const struct flash_area *fap)
232{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300233 assert(offsetof(struct image_trailer, image_ok) == 8);
234 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800235}
236
237int
238boot_read_swap_state(const struct flash_area *fap,
239 struct boot_swap_state *state)
240{
Fabio Utzig24a273d2017-04-20 08:21:31 -0300241 uint32_t magic[BOOT_MAGIC_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800242 uint32_t off;
243 int rc;
244
245 off = boot_magic_off(fap);
Fabio Utzig24a273d2017-04-20 08:21:31 -0300246 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800247 if (rc != 0) {
248 return BOOT_EFLASH;
249 }
250 state->magic = boot_magic_code(magic);
251
Fabio Utzig2473ac02017-05-02 12:45:02 -0300252 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
253 off = boot_copy_done_off(fap);
254 rc = flash_area_read(fap, off, &state->copy_done, 1);
255 if (rc != 0) {
256 return BOOT_EFLASH;
257 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800258 }
259
260 off = boot_image_ok_off(fap);
261 rc = flash_area_read(fap, off, &state->image_ok, 1);
262 if (rc != 0) {
263 return BOOT_EFLASH;
264 }
265
266 return 0;
267}
268
269/**
270 * Reads the image trailer from the scratch area.
271 */
272int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300273boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800274{
275 const struct flash_area *fap;
276 int rc;
277
Fabio Utzig2473ac02017-05-02 12:45:02 -0300278 switch (flash_area_id) {
279 case FLASH_AREA_IMAGE_SCRATCH:
280 case FLASH_AREA_IMAGE_0:
281 case FLASH_AREA_IMAGE_1:
282 rc = flash_area_open(flash_area_id, &fap);
283 if (rc != 0) {
284 return BOOT_EFLASH;
285 }
286 break;
287 default:
Fabio Utzig856f7832017-05-22 11:04:44 -0400288 return BOOT_EBADARGS;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300289 }
290
291 rc = boot_read_swap_state(fap, state);
Fabio Utzigacfba2e2017-05-22 11:06:29 -0400292 flash_area_close(fap);
293 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800294}
295
296int
297boot_write_magic(const struct flash_area *fap)
298{
299 uint32_t off;
300 int rc;
301
302 off = boot_magic_off(fap);
303
Fabio Utzig24a273d2017-04-20 08:21:31 -0300304 rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800305 if (rc != 0) {
306 return BOOT_EFLASH;
307 }
308
309 return 0;
310}
311
Fabio Utzig2473ac02017-05-02 12:45:02 -0300312static int
313boot_write_flag(int flag, const struct flash_area *fap)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800314{
315 uint32_t off;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800316 int rc;
Fabio Utzig644b8d42017-04-20 07:56:05 -0300317 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700318 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800319
Fabio Utzig2473ac02017-05-02 12:45:02 -0300320 switch (flag) {
321 case BOOT_FLAG_COPY_DONE:
322 off = boot_copy_done_off(fap);
323 break;
324 case BOOT_FLAG_IMAGE_OK:
325 off = boot_image_ok_off(fap);
326 break;
327 default:
Fabio Utzig856f7832017-05-22 11:04:44 -0400328 return BOOT_EBADARGS;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300329 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800330
David Brown9d725462017-01-23 15:50:58 -0700331 align = hal_flash_align(fap->fa_device_id);
Fabio Utzig644b8d42017-04-20 07:56:05 -0300332 assert(align <= BOOT_MAX_ALIGN);
333 memset(buf, 0xFF, BOOT_MAX_ALIGN);
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400334 buf[0] = BOOT_FLAG_SET;
David Brown9d725462017-01-23 15:50:58 -0700335
336 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800337 if (rc != 0) {
338 return BOOT_EFLASH;
339 }
340
341 return 0;
342}
343
344int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300345boot_write_copy_done(const struct flash_area *fap)
346{
347 return boot_write_flag(BOOT_FLAG_COPY_DONE, fap);
348}
349
350int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800351boot_write_image_ok(const struct flash_area *fap)
352{
Fabio Utzig2473ac02017-05-02 12:45:02 -0300353 return boot_write_flag(BOOT_FLAG_IMAGE_OK, fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800354}
355
356int
357boot_swap_type(void)
358{
359 const struct boot_swap_table *table;
360 struct boot_swap_state state_slot0;
361 struct boot_swap_state state_slot1;
362 int rc;
363 int i;
364
Fabio Utzig2473ac02017-05-02 12:45:02 -0300365 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800366 assert(rc == 0);
367
Fabio Utzig2473ac02017-05-02 12:45:02 -0300368 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &state_slot1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800369 assert(rc == 0);
370
371 for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
372 table = boot_swap_tables + i;
373
374 if ((table->bsw_magic_slot0 == 0 ||
375 table->bsw_magic_slot0 == state_slot0.magic) &&
376 (table->bsw_magic_slot1 == 0 ||
377 table->bsw_magic_slot1 == state_slot1.magic) &&
378 (table->bsw_image_ok_slot0 == 0 ||
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800379 table->bsw_image_ok_slot0 == state_slot0.image_ok) &&
380 (table->bsw_image_ok_slot1 == 0 ||
381 table->bsw_image_ok_slot1 == state_slot1.image_ok)) {
Fabio Utzig34e393e2017-05-22 11:07:07 -0400382 BOOT_LOG_INF("Swap type: %s",
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300383 table->bsw_swap_type == BOOT_SWAP_TYPE_NONE ? "none" :
384 table->bsw_swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
385 table->bsw_swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
386 table->bsw_swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
387 table->bsw_swap_type == BOOT_SWAP_TYPE_FAIL ? "fail" :
388 "BUG; can't happen");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800389 return table->bsw_swap_type;
390 }
391 }
392
393 assert(0);
394 return BOOT_SWAP_TYPE_NONE;
395}
396
397/**
398 * Marks the image in slot 1 as pending. On the next reboot, the system will
399 * perform a one-time boot of the slot 1 image.
400 *
Christopher Collins7835c1e2016-12-21 10:10:51 -0800401 * @param permanent Whether the image should be used permanently or
402 * only tested once:
403 * 0=run image once, then confirm or revert.
404 * 1=run image forever.
405 *
Christopher Collins92ea77f2016-12-12 15:59:26 -0800406 * @return 0 on success; nonzero on failure.
407 */
408int
Christopher Collins7835c1e2016-12-21 10:10:51 -0800409boot_set_pending(int permanent)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800410{
411 const struct flash_area *fap;
412 struct boot_swap_state state_slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800413 int rc;
414
Fabio Utzig2473ac02017-05-02 12:45:02 -0300415 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &state_slot1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800416 if (rc != 0) {
417 return rc;
418 }
419
420 switch (state_slot1.magic) {
421 case BOOT_MAGIC_GOOD:
422 /* Swap already scheduled. */
423 return 0;
424
425 case BOOT_MAGIC_UNSET:
Fabio Utzig2473ac02017-05-02 12:45:02 -0300426 rc = flash_area_open(FLASH_AREA_IMAGE_1, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800427 if (rc != 0) {
428 rc = BOOT_EFLASH;
429 } else {
430 rc = boot_write_magic(fap);
431 }
432
Christopher Collins7835c1e2016-12-21 10:10:51 -0800433 if (rc == 0 && permanent) {
434 rc = boot_write_image_ok(fap);
435 }
436
Christopher Collins92ea77f2016-12-12 15:59:26 -0800437 flash_area_close(fap);
438 return rc;
439
440 default:
441 /* XXX: Temporary assert. */
442 assert(0);
443 return -1;
444 }
445}
446
447/**
448 * Marks the image in slot 0 as confirmed. The system will continue booting into the image in slot 0 until told to boot from a different slot.
449 *
450 * @return 0 on success; nonzero on failure.
451 */
452int
453boot_set_confirmed(void)
454{
455 const struct flash_area *fap;
456 struct boot_swap_state state_slot0;
457 int rc;
458
Fabio Utzig2473ac02017-05-02 12:45:02 -0300459 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800460 if (rc != 0) {
461 return rc;
462 }
463
464 switch (state_slot0.magic) {
465 case BOOT_MAGIC_GOOD:
466 /* Confirm needed; proceed. */
467 break;
468
469 case BOOT_MAGIC_UNSET:
470 /* Already confirmed. */
471 return 0;
472
473 case BOOT_MAGIC_BAD:
474 /* Unexpected state. */
475 return BOOT_EBADVECT;
476 }
477
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400478 if (state_slot0.copy_done == BOOT_FLAG_UNSET) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800479 /* Swap never completed. This is unexpected. */
480 return BOOT_EBADVECT;
481 }
482
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400483 if (state_slot0.image_ok != BOOT_FLAG_UNSET) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800484 /* Already confirmed. */
485 return 0;
486 }
487
488 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
489 if (rc) {
490 rc = BOOT_EFLASH;
491 goto done;
492 }
493
494 rc = boot_write_image_ok(fap);
495 if (rc != 0) {
496 goto done;
497 }
498
499 rc = 0;
500
501done:
502 flash_area_close(fap);
503 return rc;
504}