blob: 49bbc5a15aae49b1bbddae0a212ec8bc13bb6244 [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;
David Brown9d725462017-01-23 15:50:58 -0700315 uint8_t buf[8];
316 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);
321 memset(buf, 0xFF, 8);
322 buf[0] = 1;
323
324 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800325 if (rc != 0) {
326 return BOOT_EFLASH;
327 }
328
329 return 0;
330}
331
332int
333boot_write_image_ok(const struct flash_area *fap)
334{
335 uint32_t off;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800336 int rc;
David Brown9d725462017-01-23 15:50:58 -0700337 uint8_t buf[8];
338 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800339
340 off = boot_image_ok_off(fap);
341
David Brown9d725462017-01-23 15:50:58 -0700342 align = hal_flash_align(fap->fa_device_id);
343 memset(buf, 0xFF, 8);
344 buf[0] = 1;
345 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800346 if (rc != 0) {
347 return BOOT_EFLASH;
348 }
349
350 return 0;
351}
352
353int
354boot_swap_type(void)
355{
356 const struct boot_swap_table *table;
357 struct boot_swap_state state_slot0;
358 struct boot_swap_state state_slot1;
359 int rc;
360 int i;
361
362 rc = boot_read_swap_state_img(0, &state_slot0);
363 assert(rc == 0);
364
365 rc = boot_read_swap_state_img(1, &state_slot1);
366 assert(rc == 0);
367
368 for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
369 table = boot_swap_tables + i;
370
371 if ((table->bsw_magic_slot0 == 0 ||
372 table->bsw_magic_slot0 == state_slot0.magic) &&
373 (table->bsw_magic_slot1 == 0 ||
374 table->bsw_magic_slot1 == state_slot1.magic) &&
375 (table->bsw_image_ok_slot0 == 0 ||
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800376 table->bsw_image_ok_slot0 == state_slot0.image_ok) &&
377 (table->bsw_image_ok_slot1 == 0 ||
378 table->bsw_image_ok_slot1 == state_slot1.image_ok)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800379
380 return table->bsw_swap_type;
381 }
382 }
383
384 assert(0);
385 return BOOT_SWAP_TYPE_NONE;
386}
387
388/**
389 * Marks the image in slot 1 as pending. On the next reboot, the system will
390 * perform a one-time boot of the slot 1 image.
391 *
Christopher Collins7835c1e2016-12-21 10:10:51 -0800392 * @param permanent Whether the image should be used permanently or
393 * only tested once:
394 * 0=run image once, then confirm or revert.
395 * 1=run image forever.
396 *
Christopher Collins92ea77f2016-12-12 15:59:26 -0800397 * @return 0 on success; nonzero on failure.
398 */
399int
Christopher Collins7835c1e2016-12-21 10:10:51 -0800400boot_set_pending(int permanent)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800401{
402 const struct flash_area *fap;
403 struct boot_swap_state state_slot1;
404 int area_id;
405 int rc;
406
407 rc = boot_read_swap_state_img(1, &state_slot1);
408 if (rc != 0) {
409 return rc;
410 }
411
412 switch (state_slot1.magic) {
413 case BOOT_MAGIC_GOOD:
414 /* Swap already scheduled. */
415 return 0;
416
417 case BOOT_MAGIC_UNSET:
418 area_id = flash_area_id_from_image_slot(1);
419 rc = flash_area_open(area_id, &fap);
420 if (rc != 0) {
421 rc = BOOT_EFLASH;
422 } else {
423 rc = boot_write_magic(fap);
424 }
425
Christopher Collins7835c1e2016-12-21 10:10:51 -0800426 if (rc == 0 && permanent) {
427 rc = boot_write_image_ok(fap);
428 }
429
Christopher Collins92ea77f2016-12-12 15:59:26 -0800430 flash_area_close(fap);
431 return rc;
432
433 default:
434 /* XXX: Temporary assert. */
435 assert(0);
436 return -1;
437 }
438}
439
440/**
441 * 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.
442 *
443 * @return 0 on success; nonzero on failure.
444 */
445int
446boot_set_confirmed(void)
447{
448 const struct flash_area *fap;
449 struct boot_swap_state state_slot0;
450 int rc;
451
452 rc = boot_read_swap_state_img(0, &state_slot0);
453 if (rc != 0) {
454 return rc;
455 }
456
457 switch (state_slot0.magic) {
458 case BOOT_MAGIC_GOOD:
459 /* Confirm needed; proceed. */
460 break;
461
462 case BOOT_MAGIC_UNSET:
463 /* Already confirmed. */
464 return 0;
465
466 case BOOT_MAGIC_BAD:
467 /* Unexpected state. */
468 return BOOT_EBADVECT;
469 }
470
471 if (state_slot0.copy_done == 0xff) {
472 /* Swap never completed. This is unexpected. */
473 return BOOT_EBADVECT;
474 }
475
476 if (state_slot0.image_ok != 0xff) {
477 /* Already confirmed. */
478 return 0;
479 }
480
481 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
482 if (rc) {
483 rc = BOOT_EFLASH;
484 goto done;
485 }
486
487 rc = boot_write_image_ok(fap);
488 if (rc != 0) {
489 goto done;
490 }
491
492 rc = 0;
493
494done:
495 flash_area_close(fap);
496 return rc;
497}