blob: ed879b8b382247eb4ecdf50fd76751de4f645a6d [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". */
Fabio Utzigb5b2f552017-06-30 10:03:47 -030051 uint8_t magic_slot0;
52 uint8_t magic_slot1;
53 uint8_t image_ok_slot0;
54 uint8_t image_ok_slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -080055
Fabio Utzigb5b2f552017-06-30 10:03:47 -030056 uint8_t swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -080057};
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.
Fabio Utzigb5b2f552017-06-30 10:03:47 -030062 *
63 * NOTE: the table order is very important. The settings in Slot 1 always
64 * are priority to Slot 0 and should be located earlier in the table.
65 *
66 * The table lists only states where there is action needs to be taken by
67 * the bootloader, as in starting/finishing a swap operation.
Christopher Collins92ea77f2016-12-12 15:59:26 -080068 */
69static const struct boot_swap_table boot_swap_tables[] = {
70 {
Fabio Utzigb5b2f552017-06-30 10:03:47 -030071 .magic_slot0 = 0,
72 .magic_slot1 = BOOT_MAGIC_GOOD,
73 .image_ok_slot0 = 0,
74 .image_ok_slot1 = 0xff,
75 .swap_type = BOOT_SWAP_TYPE_TEST,
Christopher Collins92ea77f2016-12-12 15:59:26 -080076 },
Christopher Collins92ea77f2016-12-12 15:59:26 -080077 {
Fabio Utzigb5b2f552017-06-30 10:03:47 -030078 .magic_slot0 = 0,
79 .magic_slot1 = BOOT_MAGIC_GOOD,
80 .image_ok_slot0 = 0,
81 .image_ok_slot1 = 0x01,
82 .swap_type = BOOT_SWAP_TYPE_PERM,
Christopher Collins92ea77f2016-12-12 15:59:26 -080083 },
Christopher Collins92ea77f2016-12-12 15:59:26 -080084 {
Fabio Utzigb5b2f552017-06-30 10:03:47 -030085 .magic_slot0 = BOOT_MAGIC_GOOD,
86 .magic_slot1 = BOOT_MAGIC_UNSET,
87 .image_ok_slot0 = 0xff,
88 .image_ok_slot1 = 0,
89 .swap_type = BOOT_SWAP_TYPE_REVERT,
Christopher Collins92ea77f2016-12-12 15:59:26 -080090 },
91};
92
93#define BOOT_SWAP_TABLES_COUNT \
94 (sizeof boot_swap_tables / sizeof boot_swap_tables[0])
95
96int
97boot_magic_code(const uint32_t *magic)
98{
99 int i;
100
Fabio Utzig24a273d2017-04-20 08:21:31 -0300101 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800102 return BOOT_MAGIC_GOOD;
103 }
104
Fabio Utzig24a273d2017-04-20 08:21:31 -0300105 for (i = 0; i < BOOT_MAGIC_SZ / sizeof *magic; i++) {
106 if (magic[i] != 0xffffffff) {
107 return BOOT_MAGIC_BAD;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800108 }
109 }
110
Fabio Utzig24a273d2017-04-20 08:21:31 -0300111 return BOOT_MAGIC_UNSET;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800112}
113
114uint32_t
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300115boot_slots_trailer_sz(uint8_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800116{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300117 return /* state for all sectors */
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300118 BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz +
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300119 BOOT_MAX_ALIGN * 2 /* copy_done + image_ok */ +
120 BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800121}
122
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300123static uint32_t
124boot_scratch_trailer_sz(uint8_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800125{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300126 return BOOT_STATUS_STATE_COUNT * min_write_sz + /* state for one sector */
127 BOOT_MAX_ALIGN + /* image_ok */
128 BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800129}
130
131static uint32_t
132boot_magic_off(const struct flash_area *fap)
133{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300134 assert(offsetof(struct image_trailer, magic) == 16);
135 return fap->fa_size - BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800136}
137
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400138int
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
Christopher Collins92ea77f2016-12-12 15:59:26 -0800152uint32_t
153boot_status_off(const struct flash_area *fap)
154{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300155 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;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800168}
169
170static uint32_t
171boot_copy_done_off(const struct flash_area *fap)
172{
Fabio Utzig2473ac02017-05-02 12:45:02 -0300173 assert(fap->fa_id != FLASH_AREA_IMAGE_SCRATCH);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300174 assert(offsetof(struct image_trailer, copy_done) == 0);
175 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800176}
177
178static uint32_t
179boot_image_ok_off(const struct flash_area *fap)
180{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300181 assert(offsetof(struct image_trailer, image_ok) == 8);
182 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800183}
184
185int
186boot_read_swap_state(const struct flash_area *fap,
187 struct boot_swap_state *state)
188{
Fabio Utzig24a273d2017-04-20 08:21:31 -0300189 uint32_t magic[BOOT_MAGIC_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800190 uint32_t off;
191 int rc;
192
193 off = boot_magic_off(fap);
Fabio Utzig24a273d2017-04-20 08:21:31 -0300194 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800195 if (rc != 0) {
196 return BOOT_EFLASH;
197 }
198 state->magic = boot_magic_code(magic);
199
Fabio Utzig2473ac02017-05-02 12:45:02 -0300200 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
201 off = boot_copy_done_off(fap);
202 rc = flash_area_read(fap, off, &state->copy_done, 1);
203 if (rc != 0) {
204 return BOOT_EFLASH;
205 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800206 }
207
208 off = boot_image_ok_off(fap);
209 rc = flash_area_read(fap, off, &state->image_ok, 1);
210 if (rc != 0) {
211 return BOOT_EFLASH;
212 }
213
214 return 0;
215}
216
217/**
218 * Reads the image trailer from the scratch area.
219 */
220int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300221boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800222{
223 const struct flash_area *fap;
224 int rc;
225
Fabio Utzig2473ac02017-05-02 12:45:02 -0300226 switch (flash_area_id) {
227 case FLASH_AREA_IMAGE_SCRATCH:
228 case FLASH_AREA_IMAGE_0:
229 case FLASH_AREA_IMAGE_1:
230 rc = flash_area_open(flash_area_id, &fap);
231 if (rc != 0) {
232 return BOOT_EFLASH;
233 }
234 break;
235 default:
Fabio Utzig856f7832017-05-22 11:04:44 -0400236 return BOOT_EBADARGS;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300237 }
238
239 rc = boot_read_swap_state(fap, state);
Fabio Utzigacfba2e2017-05-22 11:06:29 -0400240 flash_area_close(fap);
241 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800242}
243
244int
245boot_write_magic(const struct flash_area *fap)
246{
247 uint32_t off;
248 int rc;
249
250 off = boot_magic_off(fap);
251
Fabio Utzig24a273d2017-04-20 08:21:31 -0300252 rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800253 if (rc != 0) {
254 return BOOT_EFLASH;
255 }
256
257 return 0;
258}
259
Fabio Utzig2473ac02017-05-02 12:45:02 -0300260static int
261boot_write_flag(int flag, const struct flash_area *fap)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800262{
263 uint32_t off;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800264 int rc;
Fabio Utzig644b8d42017-04-20 07:56:05 -0300265 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700266 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800267
Fabio Utzig2473ac02017-05-02 12:45:02 -0300268 switch (flag) {
269 case BOOT_FLAG_COPY_DONE:
270 off = boot_copy_done_off(fap);
271 break;
272 case BOOT_FLAG_IMAGE_OK:
273 off = boot_image_ok_off(fap);
274 break;
275 default:
Fabio Utzig856f7832017-05-22 11:04:44 -0400276 return BOOT_EBADARGS;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300277 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800278
David Brown9d725462017-01-23 15:50:58 -0700279 align = hal_flash_align(fap->fa_device_id);
Fabio Utzig644b8d42017-04-20 07:56:05 -0300280 assert(align <= BOOT_MAX_ALIGN);
281 memset(buf, 0xFF, BOOT_MAX_ALIGN);
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400282 buf[0] = BOOT_FLAG_SET;
David Brown9d725462017-01-23 15:50:58 -0700283
284 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800285 if (rc != 0) {
286 return BOOT_EFLASH;
287 }
288
289 return 0;
290}
291
292int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300293boot_write_copy_done(const struct flash_area *fap)
294{
295 return boot_write_flag(BOOT_FLAG_COPY_DONE, fap);
296}
297
298int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800299boot_write_image_ok(const struct flash_area *fap)
300{
Fabio Utzig2473ac02017-05-02 12:45:02 -0300301 return boot_write_flag(BOOT_FLAG_IMAGE_OK, fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800302}
303
304int
305boot_swap_type(void)
306{
307 const struct boot_swap_table *table;
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300308 struct boot_swap_state slot0;
309 struct boot_swap_state slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800310 int rc;
311 int i;
312
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300313 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &slot0);
314 if (rc) {
315 return BOOT_SWAP_TYPE_PANIC;
316 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800317
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300318 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &slot1);
319 if (rc) {
320 return BOOT_SWAP_TYPE_PANIC;
321 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800322
323 for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
324 table = boot_swap_tables + i;
325
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300326 if ((!table->magic_slot0 || table->magic_slot0 == slot0.magic) &&
327 (!table->magic_slot1 || table->magic_slot1 == slot1.magic) &&
328 (!table->image_ok_slot0 || table->image_ok_slot0 == slot0.image_ok) &&
329 (!table->image_ok_slot1 || table->image_ok_slot1 == slot1.image_ok)) {
Fabio Utzig34e393e2017-05-22 11:07:07 -0400330 BOOT_LOG_INF("Swap type: %s",
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300331 table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
332 table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
333 table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
334 "BUG; can't happen");
335 assert(table->swap_type == BOOT_SWAP_TYPE_TEST ||
336 table->swap_type == BOOT_SWAP_TYPE_PERM ||
337 table->swap_type == BOOT_SWAP_TYPE_REVERT);
338 return table->swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800339 }
340 }
341
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300342 BOOT_LOG_INF("Swap type: none");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800343 return BOOT_SWAP_TYPE_NONE;
344}
345
346/**
347 * Marks the image in slot 1 as pending. On the next reboot, the system will
348 * perform a one-time boot of the slot 1 image.
349 *
Christopher Collins7835c1e2016-12-21 10:10:51 -0800350 * @param permanent Whether the image should be used permanently or
351 * only tested once:
352 * 0=run image once, then confirm or revert.
353 * 1=run image forever.
354 *
Christopher Collins92ea77f2016-12-12 15:59:26 -0800355 * @return 0 on success; nonzero on failure.
356 */
357int
Christopher Collins7835c1e2016-12-21 10:10:51 -0800358boot_set_pending(int permanent)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800359{
360 const struct flash_area *fap;
361 struct boot_swap_state state_slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800362 int rc;
363
Fabio Utzig2473ac02017-05-02 12:45:02 -0300364 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &state_slot1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800365 if (rc != 0) {
366 return rc;
367 }
368
369 switch (state_slot1.magic) {
370 case BOOT_MAGIC_GOOD:
371 /* Swap already scheduled. */
372 return 0;
373
374 case BOOT_MAGIC_UNSET:
Fabio Utzig2473ac02017-05-02 12:45:02 -0300375 rc = flash_area_open(FLASH_AREA_IMAGE_1, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800376 if (rc != 0) {
377 rc = BOOT_EFLASH;
378 } else {
379 rc = boot_write_magic(fap);
380 }
381
Christopher Collins7835c1e2016-12-21 10:10:51 -0800382 if (rc == 0 && permanent) {
383 rc = boot_write_image_ok(fap);
384 }
385
Christopher Collins92ea77f2016-12-12 15:59:26 -0800386 flash_area_close(fap);
387 return rc;
388
389 default:
390 /* XXX: Temporary assert. */
391 assert(0);
392 return -1;
393 }
394}
395
396/**
397 * 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.
398 *
399 * @return 0 on success; nonzero on failure.
400 */
401int
402boot_set_confirmed(void)
403{
404 const struct flash_area *fap;
405 struct boot_swap_state state_slot0;
406 int rc;
407
Fabio Utzig2473ac02017-05-02 12:45:02 -0300408 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800409 if (rc != 0) {
410 return rc;
411 }
412
413 switch (state_slot0.magic) {
414 case BOOT_MAGIC_GOOD:
415 /* Confirm needed; proceed. */
416 break;
417
418 case BOOT_MAGIC_UNSET:
419 /* Already confirmed. */
420 return 0;
421
422 case BOOT_MAGIC_BAD:
423 /* Unexpected state. */
424 return BOOT_EBADVECT;
425 }
426
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400427 if (state_slot0.copy_done == BOOT_FLAG_UNSET) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800428 /* Swap never completed. This is unexpected. */
429 return BOOT_EBADVECT;
430 }
431
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400432 if (state_slot0.image_ok != BOOT_FLAG_UNSET) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800433 /* Already confirmed. */
434 return 0;
435 }
436
437 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
438 if (rc) {
439 rc = BOOT_EFLASH;
440 goto done;
441 }
442
443 rc = boot_write_image_ok(fap);
444 if (rc != 0) {
445 goto done;
446 }
447
448 rc = 0;
449
450done:
451 flash_area_close(fap);
452 return rc;
453}