blob: 2f61896d1d7f7e7d5d063e60f769431d65bc9a66 [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>
23
24#include "syscfg/syscfg.h"
25#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
34int boot_current_slot;
35
Fabio Utzig24a273d2017-04-20 08:21:31 -030036const uint32_t boot_img_magic[] = {
Christopher Collins92ea77f2016-12-12 15:59:26 -080037 0xf395c277,
38 0x7fefd260,
39 0x0f505235,
40 0x8079b62c,
41};
42
Fabio Utzig24a273d2017-04-20 08:21:31 -030043const uint32_t BOOT_MAGIC_SZ = sizeof boot_img_magic;
44
Christopher Collins92ea77f2016-12-12 15:59:26 -080045struct boot_swap_table {
46 /** * For each field, a value of 0 means "any". */
47 uint8_t bsw_magic_slot0;
48 uint8_t bsw_magic_slot1;
49 uint8_t bsw_image_ok_slot0;
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080050 uint8_t bsw_image_ok_slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -080051
52 uint8_t bsw_swap_type;
53};
54
55/**
56 * This set of tables maps image trailer contents to swap operation type.
57 * When searching for a match, these tables must be iterated sequentially.
58 */
59static const struct boot_swap_table boot_swap_tables[] = {
60 {
61 /* | slot-0 | slot-1 |
62 *----------+------------+------------|
63 * magic | Unset | Unset |
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080064 * image-ok | Any | Any |
Christopher Collins92ea77f2016-12-12 15:59:26 -080065 * ---------+------------+------------'
66 * swap: none |
67 * -----------------------------------'
68 */
69 .bsw_magic_slot0 = BOOT_MAGIC_UNSET,
70 .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
71 .bsw_image_ok_slot0 = 0,
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080072 .bsw_image_ok_slot1 = 0,
Christopher Collins92ea77f2016-12-12 15:59:26 -080073 .bsw_swap_type = BOOT_SWAP_TYPE_NONE,
74 },
75
76 {
77 /* | slot-0 | slot-1 |
78 *----------+------------+------------|
79 * magic | Any | Good |
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080080 * image-ok | Any | Unset |
81 * ---------+------------+------------`
82 * swap: test |
83 * -----------------------------------'
Christopher Collins92ea77f2016-12-12 15:59:26 -080084 */
85 .bsw_magic_slot0 = 0,
86 .bsw_magic_slot1 = BOOT_MAGIC_GOOD,
87 .bsw_image_ok_slot0 = 0,
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080088 .bsw_image_ok_slot1 = 0xff,
Christopher Collins92ea77f2016-12-12 15:59:26 -080089 .bsw_swap_type = BOOT_SWAP_TYPE_TEST,
90 },
91
92 {
93 /* | slot-0 | slot-1 |
94 *----------+------------+------------|
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -080095 * magic | Any | Good |
96 * image-ok | Any | 0x01 |
97 * ---------+------------+------------`
98 * swap: permanent |
99 * -----------------------------------'
100 */
101 .bsw_magic_slot0 = 0,
102 .bsw_magic_slot1 = BOOT_MAGIC_GOOD,
103 .bsw_image_ok_slot0 = 0,
104 .bsw_image_ok_slot1 = 0x01,
105 .bsw_swap_type = BOOT_SWAP_TYPE_PERM,
106 },
107
108 {
109 /* | slot-0 | slot-1 |
110 *----------+------------+------------|
Christopher Collins92ea77f2016-12-12 15:59:26 -0800111 * magic | Good | Unset |
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800112 * image-ok | 0xff | Any |
Christopher Collins92ea77f2016-12-12 15:59:26 -0800113 * ---------+------------+------------'
114 * swap: revert (test image running) |
115 * -----------------------------------'
116 */
117 .bsw_magic_slot0 = BOOT_MAGIC_GOOD,
118 .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
119 .bsw_image_ok_slot0 = 0xff,
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800120 .bsw_image_ok_slot1 = 0,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800121 .bsw_swap_type = BOOT_SWAP_TYPE_REVERT,
122 },
123
124 {
125 /* | slot-0 | slot-1 |
126 *----------+------------+------------|
127 * magic | Good | Unset |
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800128 * image-ok | 0x01 | Any |
Christopher Collins92ea77f2016-12-12 15:59:26 -0800129 * ---------+------------+------------'
130 * swap: none (confirmed test image) |
131 * -----------------------------------'
132 */
133 .bsw_magic_slot0 = BOOT_MAGIC_GOOD,
134 .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
135 .bsw_image_ok_slot0 = 0x01,
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800136 .bsw_image_ok_slot1 = 0,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800137 .bsw_swap_type = BOOT_SWAP_TYPE_NONE,
138 },
139};
140
141#define BOOT_SWAP_TABLES_COUNT \
142 (sizeof boot_swap_tables / sizeof boot_swap_tables[0])
143
144int
145boot_magic_code(const uint32_t *magic)
146{
147 int i;
148
Fabio Utzig24a273d2017-04-20 08:21:31 -0300149 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800150 return BOOT_MAGIC_GOOD;
151 }
152
Fabio Utzig24a273d2017-04-20 08:21:31 -0300153 for (i = 0; i < BOOT_MAGIC_SZ / sizeof *magic; i++) {
154 if (magic[i] != 0xffffffff) {
155 return BOOT_MAGIC_BAD;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800156 }
157 }
158
Fabio Utzig24a273d2017-04-20 08:21:31 -0300159 return BOOT_MAGIC_UNSET;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800160}
161
162uint32_t
163boot_status_sz(uint8_t min_write_sz)
164{
165 return BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz;
166}
167
168uint32_t
169boot_trailer_sz(uint8_t min_write_sz)
170{
Fabio Utzig24a273d2017-04-20 08:21:31 -0300171 return BOOT_MAGIC_SZ +
Christopher Collins92ea77f2016-12-12 15:59:26 -0800172 boot_status_sz(min_write_sz) +
173 min_write_sz * 2;
174}
175
176static uint32_t
177boot_magic_off(const struct flash_area *fap)
178{
179 uint32_t off_from_end;
180 uint8_t elem_sz;
181
182 elem_sz = flash_area_align(fap);
183
184 off_from_end = boot_trailer_sz(elem_sz);
185
186 assert(off_from_end <= fap->fa_size);
187 return fap->fa_size - off_from_end;
188}
189
190uint32_t
191boot_status_off(const struct flash_area *fap)
192{
Fabio Utzig24a273d2017-04-20 08:21:31 -0300193 return boot_magic_off(fap) + BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800194}
195
196static uint32_t
197boot_copy_done_off(const struct flash_area *fap)
198{
199 return fap->fa_size - flash_area_align(fap) * 2;
200}
201
202static uint32_t
203boot_image_ok_off(const struct flash_area *fap)
204{
205 return fap->fa_size - flash_area_align(fap);
206}
207
208int
209boot_read_swap_state(const struct flash_area *fap,
210 struct boot_swap_state *state)
211{
Fabio Utzig24a273d2017-04-20 08:21:31 -0300212 uint32_t magic[BOOT_MAGIC_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800213 uint32_t off;
214 int rc;
215
216 off = boot_magic_off(fap);
Fabio Utzig24a273d2017-04-20 08:21:31 -0300217 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800218 if (rc != 0) {
219 return BOOT_EFLASH;
220 }
221 state->magic = boot_magic_code(magic);
222
223 off = boot_copy_done_off(fap);
224 rc = flash_area_read(fap, off, &state->copy_done, 1);
225 if (rc != 0) {
226 return BOOT_EFLASH;
227 }
228
229 off = boot_image_ok_off(fap);
230 rc = flash_area_read(fap, off, &state->image_ok, 1);
231 if (rc != 0) {
232 return BOOT_EFLASH;
233 }
234
235 return 0;
236}
237
238/**
239 * Reads the image trailer from the scratch area.
240 */
241int
242boot_read_swap_state_scratch(struct boot_swap_state *state)
243{
244 const struct flash_area *fap;
245 int rc;
246
247 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
248 if (rc) {
249 rc = BOOT_EFLASH;
250 goto done;
251 }
252
253 rc = boot_read_swap_state(fap, state);
254 if (rc != 0) {
255 goto done;
256 }
257
258 rc = 0;
259
260done:
261 flash_area_close(fap);
262 return rc;
263}
264
265/**
266 * Reads the image trailer from a given image slot.
267 */
268int
269boot_read_swap_state_img(int slot, struct boot_swap_state *state)
270{
271 const struct flash_area *fap;
272 int area_id;
273 int rc;
274
275 area_id = flash_area_id_from_image_slot(slot);
276 rc = flash_area_open(area_id, &fap);
277 if (rc != 0) {
278 rc = BOOT_EFLASH;
279 goto done;
280 }
281
282 rc = boot_read_swap_state(fap, state);
283 if (rc != 0) {
284 goto done;
285 }
286
287 rc = 0;
288
289done:
290 flash_area_close(fap);
291 return rc;
292}
293
294int
295boot_write_magic(const struct flash_area *fap)
296{
297 uint32_t off;
298 int rc;
299
300 off = boot_magic_off(fap);
301
Fabio Utzig24a273d2017-04-20 08:21:31 -0300302 rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800303 if (rc != 0) {
304 return BOOT_EFLASH;
305 }
306
307 return 0;
308}
309
310int
311boot_write_copy_done(const struct flash_area *fap)
312{
313 uint32_t off;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800314 int rc;
Fabio Utzig644b8d42017-04-20 07:56:05 -0300315 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700316 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800317
318 off = boot_copy_done_off(fap);
319
David Brown9d725462017-01-23 15:50:58 -0700320 align = hal_flash_align(fap->fa_device_id);
Fabio Utzig644b8d42017-04-20 07:56:05 -0300321 assert(align <= BOOT_MAX_ALIGN);
322 memset(buf, 0xFF, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700323 buf[0] = 1;
324
325 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800326 if (rc != 0) {
327 return BOOT_EFLASH;
328 }
329
330 return 0;
331}
332
333int
334boot_write_image_ok(const struct flash_area *fap)
335{
336 uint32_t off;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800337 int rc;
Fabio Utzig644b8d42017-04-20 07:56:05 -0300338 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700339 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800340
341 off = boot_image_ok_off(fap);
342
David Brown9d725462017-01-23 15:50:58 -0700343 align = hal_flash_align(fap->fa_device_id);
Fabio Utzig644b8d42017-04-20 07:56:05 -0300344 assert(align <= BOOT_MAX_ALIGN);
345 memset(buf, 0xFF, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700346 buf[0] = 1;
Fabio Utzig644b8d42017-04-20 07:56:05 -0300347
David Brown9d725462017-01-23 15:50:58 -0700348 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800349 if (rc != 0) {
350 return BOOT_EFLASH;
351 }
352
353 return 0;
354}
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
365 rc = boot_read_swap_state_img(0, &state_slot0);
366 assert(rc == 0);
367
368 rc = boot_read_swap_state_img(1, &state_slot1);
369 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)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800382
383 return table->bsw_swap_type;
384 }
385 }
386
387 assert(0);
388 return BOOT_SWAP_TYPE_NONE;
389}
390
391/**
392 * Marks the image in slot 1 as pending. On the next reboot, the system will
393 * perform a one-time boot of the slot 1 image.
394 *
Christopher Collins7835c1e2016-12-21 10:10:51 -0800395 * @param permanent Whether the image should be used permanently or
396 * only tested once:
397 * 0=run image once, then confirm or revert.
398 * 1=run image forever.
399 *
Christopher Collins92ea77f2016-12-12 15:59:26 -0800400 * @return 0 on success; nonzero on failure.
401 */
402int
Christopher Collins7835c1e2016-12-21 10:10:51 -0800403boot_set_pending(int permanent)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800404{
405 const struct flash_area *fap;
406 struct boot_swap_state state_slot1;
407 int area_id;
408 int rc;
409
410 rc = boot_read_swap_state_img(1, &state_slot1);
411 if (rc != 0) {
412 return rc;
413 }
414
415 switch (state_slot1.magic) {
416 case BOOT_MAGIC_GOOD:
417 /* Swap already scheduled. */
418 return 0;
419
420 case BOOT_MAGIC_UNSET:
421 area_id = flash_area_id_from_image_slot(1);
422 rc = flash_area_open(area_id, &fap);
423 if (rc != 0) {
424 rc = BOOT_EFLASH;
425 } else {
426 rc = boot_write_magic(fap);
427 }
428
Christopher Collins7835c1e2016-12-21 10:10:51 -0800429 if (rc == 0 && permanent) {
430 rc = boot_write_image_ok(fap);
431 }
432
Christopher Collins92ea77f2016-12-12 15:59:26 -0800433 flash_area_close(fap);
434 return rc;
435
436 default:
437 /* XXX: Temporary assert. */
438 assert(0);
439 return -1;
440 }
441}
442
443/**
444 * 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.
445 *
446 * @return 0 on success; nonzero on failure.
447 */
448int
449boot_set_confirmed(void)
450{
451 const struct flash_area *fap;
452 struct boot_swap_state state_slot0;
453 int rc;
454
455 rc = boot_read_swap_state_img(0, &state_slot0);
456 if (rc != 0) {
457 return rc;
458 }
459
460 switch (state_slot0.magic) {
461 case BOOT_MAGIC_GOOD:
462 /* Confirm needed; proceed. */
463 break;
464
465 case BOOT_MAGIC_UNSET:
466 /* Already confirmed. */
467 return 0;
468
469 case BOOT_MAGIC_BAD:
470 /* Unexpected state. */
471 return BOOT_EBADVECT;
472 }
473
474 if (state_slot0.copy_done == 0xff) {
475 /* Swap never completed. This is unexpected. */
476 return BOOT_EBADVECT;
477 }
478
479 if (state_slot0.image_ok != 0xff) {
480 /* Already confirmed. */
481 return 0;
482 }
483
484 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
485 if (rc) {
486 rc = BOOT_EFLASH;
487 goto done;
488 }
489
490 rc = boot_write_image_ok(fap);
491 if (rc != 0) {
492 goto done;
493 }
494
495 rc = 0;
496
497done:
498 flash_area_close(fap);
499 return rc;
500}