blob: 75c1dd9f4a6db6a9a3de3ad8513f003ed39c8ea8 [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"
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +020026#include "flash_map_backend/flash_map_backend.h"
27
Christopher Collins92ea77f2016-12-12 15:59:26 -080028#include "bootutil/image.h"
29#include "bootutil/bootutil.h"
30#include "bootutil_priv.h"
Fabio Utzig7ebb7c22017-04-26 10:59:31 -030031#include "bootutil/bootutil_log.h"
Fabio Utzigba829042018-09-18 08:29:34 -030032#ifdef MCUBOOT_ENC_IMAGES
33#include "bootutil/enc_key.h"
34#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -030035
Christopher Collins92ea77f2016-12-12 15:59:26 -080036int boot_current_slot;
37
Fabio Utzig24a273d2017-04-20 08:21:31 -030038const uint32_t boot_img_magic[] = {
Christopher Collins92ea77f2016-12-12 15:59:26 -080039 0xf395c277,
40 0x7fefd260,
41 0x0f505235,
42 0x8079b62c,
43};
44
Hovland, Sigvart1d96f362018-09-25 13:23:42 +020045#define BOOT_MAGIC_ARR_SZ \
46 (sizeof boot_img_magic / sizeof boot_img_magic[0])
47
Fabio Utzig24a273d2017-04-20 08:21:31 -030048const uint32_t BOOT_MAGIC_SZ = sizeof boot_img_magic;
Fabio Utziga0bc9b52017-06-28 09:19:55 -030049const uint32_t BOOT_MAX_ALIGN = MAX_FLASH_ALIGN;
Fabio Utzig24a273d2017-04-20 08:21:31 -030050
Christopher Collins92ea77f2016-12-12 15:59:26 -080051struct boot_swap_table {
Fabio Utzigb5b2f552017-06-30 10:03:47 -030052 uint8_t magic_slot0;
53 uint8_t magic_slot1;
54 uint8_t image_ok_slot0;
55 uint8_t image_ok_slot1;
Fabio Utzigd7d20752017-07-13 16:03:25 -030056 uint8_t copy_done_slot0;
Christopher Collins92ea77f2016-12-12 15:59:26 -080057
Fabio Utzigb5b2f552017-06-30 10:03:47 -030058 uint8_t swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -080059};
60
61/**
62 * This set of tables maps image trailer contents to swap operation type.
63 * When searching for a match, these tables must be iterated sequentially.
Fabio Utzigb5b2f552017-06-30 10:03:47 -030064 *
65 * NOTE: the table order is very important. The settings in Slot 1 always
66 * are priority to Slot 0 and should be located earlier in the table.
67 *
68 * The table lists only states where there is action needs to be taken by
69 * the bootloader, as in starting/finishing a swap operation.
Christopher Collins92ea77f2016-12-12 15:59:26 -080070 */
71static const struct boot_swap_table boot_swap_tables[] = {
72 {
Fabio Utzig39000012018-07-30 12:40:20 -030073 .magic_slot0 = BOOT_MAGIC_ANY,
Fabio Utzigb5b2f552017-06-30 10:03:47 -030074 .magic_slot1 = BOOT_MAGIC_GOOD,
Fabio Utzig39000012018-07-30 12:40:20 -030075 .image_ok_slot0 = BOOT_FLAG_ANY,
76 .image_ok_slot1 = BOOT_FLAG_UNSET,
77 .copy_done_slot0 = BOOT_FLAG_ANY,
Fabio Utzigb5b2f552017-06-30 10:03:47 -030078 .swap_type = BOOT_SWAP_TYPE_TEST,
Christopher Collins92ea77f2016-12-12 15:59:26 -080079 },
Christopher Collins92ea77f2016-12-12 15:59:26 -080080 {
Fabio Utzig39000012018-07-30 12:40:20 -030081 .magic_slot0 = BOOT_MAGIC_ANY,
Fabio Utzigb5b2f552017-06-30 10:03:47 -030082 .magic_slot1 = BOOT_MAGIC_GOOD,
Fabio Utzig39000012018-07-30 12:40:20 -030083 .image_ok_slot0 = BOOT_FLAG_ANY,
84 .image_ok_slot1 = BOOT_FLAG_SET,
85 .copy_done_slot0 = BOOT_FLAG_ANY,
Fabio Utzigb5b2f552017-06-30 10:03:47 -030086 .swap_type = BOOT_SWAP_TYPE_PERM,
Christopher Collins92ea77f2016-12-12 15:59:26 -080087 },
Christopher Collins92ea77f2016-12-12 15:59:26 -080088 {
Fabio Utzigb5b2f552017-06-30 10:03:47 -030089 .magic_slot0 = BOOT_MAGIC_GOOD,
90 .magic_slot1 = BOOT_MAGIC_UNSET,
Fabio Utzig39000012018-07-30 12:40:20 -030091 .image_ok_slot0 = BOOT_FLAG_UNSET,
92 .image_ok_slot1 = BOOT_FLAG_ANY,
93 .copy_done_slot0 = BOOT_FLAG_SET,
Fabio Utzigb5b2f552017-06-30 10:03:47 -030094 .swap_type = BOOT_SWAP_TYPE_REVERT,
Christopher Collins92ea77f2016-12-12 15:59:26 -080095 },
96};
97
98#define BOOT_SWAP_TABLES_COUNT \
99 (sizeof boot_swap_tables / sizeof boot_swap_tables[0])
100
Fabio Utzig39000012018-07-30 12:40:20 -0300101static int
Fabio Utzig178be542018-09-19 08:12:56 -0300102boot_magic_decode(const uint32_t *magic)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800103{
Fabio Utzig24a273d2017-04-20 08:21:31 -0300104 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800105 return BOOT_MAGIC_GOOD;
106 }
Fabio Utzig178be542018-09-19 08:12:56 -0300107 return BOOT_MAGIC_BAD;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800108}
109
Fabio Utzig39000012018-07-30 12:40:20 -0300110static int
Fabio Utzig178be542018-09-19 08:12:56 -0300111boot_flag_decode(uint8_t flag)
Fabio Utzig39000012018-07-30 12:40:20 -0300112{
Fabio Utzig39000012018-07-30 12:40:20 -0300113 if (flag != BOOT_FLAG_SET) {
114 return BOOT_FLAG_BAD;
115 }
116 return BOOT_FLAG_SET;
117}
118
Christopher Collins92ea77f2016-12-12 15:59:26 -0800119uint32_t
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300120boot_slots_trailer_sz(uint8_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800121{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300122 return /* state for all sectors */
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300123 BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz +
Fabio Utzigba829042018-09-18 08:29:34 -0300124#ifdef MCUBOOT_ENC_IMAGES
125 /* encryption keys */
126 BOOT_ENC_KEY_SIZE * 2 +
127#endif
128 /* copy_done + image_ok + swap_size */
129 BOOT_MAX_ALIGN * 3 +
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300130 BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800131}
132
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300133static uint32_t
134boot_scratch_trailer_sz(uint8_t min_write_sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800135{
Fabio Utzigba829042018-09-18 08:29:34 -0300136 /* state for one sector */
137 return BOOT_STATUS_STATE_COUNT * min_write_sz +
138#ifdef MCUBOOT_ENC_IMAGES
139 /* encryption keys */
140 BOOT_ENC_KEY_SIZE * 2 +
141#endif
142 /* image_ok + swap_size */
143 BOOT_MAX_ALIGN * 2 +
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300144 BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800145}
146
147static uint32_t
148boot_magic_off(const struct flash_area *fap)
149{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300150 assert(offsetof(struct image_trailer, magic) == 16);
151 return fap->fa_size - BOOT_MAGIC_SZ;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800152}
153
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400154int
155boot_status_entries(const struct flash_area *fap)
156{
157 switch (fap->fa_id) {
158 case FLASH_AREA_IMAGE_0:
159 case FLASH_AREA_IMAGE_1:
160 return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
161 case FLASH_AREA_IMAGE_SCRATCH:
162 return BOOT_STATUS_STATE_COUNT;
163 default:
164 return BOOT_EBADARGS;
165 }
166}
167
Christopher Collins92ea77f2016-12-12 15:59:26 -0800168uint32_t
169boot_status_off(const struct flash_area *fap)
170{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300171 uint32_t off_from_end;
172 uint8_t elem_sz;
173
174 elem_sz = flash_area_align(fap);
175
176 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
177 off_from_end = boot_scratch_trailer_sz(elem_sz);
178 } else {
179 off_from_end = boot_slots_trailer_sz(elem_sz);
180 }
181
182 assert(off_from_end <= fap->fa_size);
183 return fap->fa_size - off_from_end;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800184}
185
186static uint32_t
187boot_copy_done_off(const struct flash_area *fap)
188{
Fabio Utzig2473ac02017-05-02 12:45:02 -0300189 assert(fap->fa_id != FLASH_AREA_IMAGE_SCRATCH);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300190 assert(offsetof(struct image_trailer, copy_done) == 0);
191 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800192}
193
194static uint32_t
195boot_image_ok_off(const struct flash_area *fap)
196{
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300197 assert(offsetof(struct image_trailer, image_ok) == 8);
198 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800199}
200
Fabio Utzig46490722017-09-04 15:34:32 -0300201static uint32_t
202boot_swap_size_off(const struct flash_area *fap)
203{
204 /*
205 * The "swap_size" field if located just before the trailer.
206 * The scratch slot doesn't store "copy_done"...
207 */
208 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
209 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
210 }
211
212 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
213}
214
Fabio Utzigba829042018-09-18 08:29:34 -0300215#ifdef MCUBOOT_ENC_IMAGES
216static uint32_t
217boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
218{
219 if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
220 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2 -
221 ((slot + 1) * BOOT_ENC_KEY_SIZE);
222 }
223
224 return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3 -
225 ((slot + 1) * BOOT_ENC_KEY_SIZE);
226}
227#endif
228
Christopher Collins92ea77f2016-12-12 15:59:26 -0800229int
230boot_read_swap_state(const struct flash_area *fap,
231 struct boot_swap_state *state)
232{
Hovland, Sigvart1d96f362018-09-25 13:23:42 +0200233 uint32_t magic[BOOT_MAGIC_ARR_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800234 uint32_t off;
235 int rc;
236
237 off = boot_magic_off(fap);
Fabio Utzig178be542018-09-19 08:12:56 -0300238 rc = flash_area_read_is_empty(fap, off, magic, BOOT_MAGIC_SZ);
239 if (rc < 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800240 return BOOT_EFLASH;
241 }
Fabio Utzig178be542018-09-19 08:12:56 -0300242 if (rc == 1) {
243 state->magic = BOOT_MAGIC_UNSET;
244 } else {
245 state->magic = boot_magic_decode(magic);
246 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800247
Fabio Utzig2473ac02017-05-02 12:45:02 -0300248 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
249 off = boot_copy_done_off(fap);
Fabio Utzig178be542018-09-19 08:12:56 -0300250 rc = flash_area_read_is_empty(fap, off, &state->copy_done,
251 sizeof state->copy_done);
252 if (rc < 0) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300253 return BOOT_EFLASH;
254 }
Fabio Utzig178be542018-09-19 08:12:56 -0300255 if (rc == 1) {
256 state->copy_done = BOOT_FLAG_UNSET;
257 } else {
258 state->copy_done = boot_flag_decode(state->copy_done);
259 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800260 }
261
262 off = boot_image_ok_off(fap);
Fabio Utzig178be542018-09-19 08:12:56 -0300263 rc = flash_area_read_is_empty(fap, off, &state->image_ok, sizeof state->image_ok);
264 if (rc < 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800265 return BOOT_EFLASH;
266 }
Fabio Utzig178be542018-09-19 08:12:56 -0300267 if (rc == 1) {
268 state->image_ok = BOOT_FLAG_UNSET;
269 } else {
270 state->image_ok = boot_flag_decode(state->image_ok);
271 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800272
273 return 0;
274}
275
276/**
277 * Reads the image trailer from the scratch area.
278 */
279int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300280boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800281{
282 const struct flash_area *fap;
283 int rc;
284
Fabio Utzig2473ac02017-05-02 12:45:02 -0300285 switch (flash_area_id) {
286 case FLASH_AREA_IMAGE_SCRATCH:
287 case FLASH_AREA_IMAGE_0:
288 case FLASH_AREA_IMAGE_1:
289 rc = flash_area_open(flash_area_id, &fap);
290 if (rc != 0) {
291 return BOOT_EFLASH;
292 }
293 break;
294 default:
Fabio Utzig856f7832017-05-22 11:04:44 -0400295 return BOOT_EBADARGS;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300296 }
297
298 rc = boot_read_swap_state(fap, state);
Fabio Utzigacfba2e2017-05-22 11:06:29 -0400299 flash_area_close(fap);
300 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800301}
302
303int
Fabio Utzig46490722017-09-04 15:34:32 -0300304boot_read_swap_size(uint32_t *swap_size)
305{
Hovland, Sigvart1d96f362018-09-25 13:23:42 +0200306 uint32_t magic[BOOT_MAGIC_ARR_SZ];
Fabio Utzig46490722017-09-04 15:34:32 -0300307 uint32_t off;
308 const struct flash_area *fap;
309 int rc;
310
311 /*
312 * In the middle a swap, tries to locate the saved swap size. Looks
313 * for a valid magic, first on Slot 0, then on scratch. Both "slots"
314 * can end up being temporary storage for a swap and it is assumed
315 * that if magic is valid then swap size is too, because magic is
316 * always written in the last step.
317 */
318
319 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
320 if (rc != 0) {
321 return BOOT_EFLASH;
322 }
323
324 off = boot_magic_off(fap);
325 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
326 if (rc != 0) {
327 rc = BOOT_EFLASH;
328 goto out;
329 }
330
331 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) != 0) {
332 /*
333 * If Slot 0 's magic is not valid, try scratch...
334 */
335
336 flash_area_close(fap);
337
338 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
339 if (rc != 0) {
340 return BOOT_EFLASH;
341 }
342
343 off = boot_magic_off(fap);
344 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
345 if (rc != 0) {
346 rc = BOOT_EFLASH;
347 goto out;
348 }
349
350 assert(memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0);
351 }
352
353 off = boot_swap_size_off(fap);
354 rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
355 if (rc != 0) {
356 rc = BOOT_EFLASH;
357 }
358
359out:
360 flash_area_close(fap);
361 return rc;
362}
363
Fabio Utzigba829042018-09-18 08:29:34 -0300364#ifdef MCUBOOT_ENC_IMAGES
365int
366boot_read_enc_key(uint8_t slot, uint8_t *enckey)
367{
368 uint32_t magic[BOOT_MAGIC_SZ];
369 uint32_t off;
370 const struct flash_area *fap;
371 int rc;
372
373 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
374 if (rc != 0) {
375 return BOOT_EFLASH;
376 }
377
378 off = boot_magic_off(fap);
379 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
380 if (rc != 0) {
381 rc = BOOT_EFLASH;
382 goto out;
383 }
384
385 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) != 0) {
386 /*
387 * If Slot 0 's magic is not valid, try scratch...
388 */
389
390 flash_area_close(fap);
391
392 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
393 if (rc != 0) {
394 return BOOT_EFLASH;
395 }
396
397 off = boot_magic_off(fap);
398 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
399 if (rc != 0) {
400 rc = BOOT_EFLASH;
401 goto out;
402 }
403
404 assert(memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0);
405 }
406
407 off = boot_enc_key_off(fap, slot);
408 rc = flash_area_read(fap, off, enckey, BOOT_ENC_KEY_SIZE);
409 if (rc != 0) {
410 rc = BOOT_EFLASH;
411 }
412
413out:
414 flash_area_close(fap);
415 return rc;
416}
417#endif
Fabio Utzig46490722017-09-04 15:34:32 -0300418
419int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800420boot_write_magic(const struct flash_area *fap)
421{
422 uint32_t off;
423 int rc;
424
425 off = boot_magic_off(fap);
426
Fabio Utzig24a273d2017-04-20 08:21:31 -0300427 rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800428 if (rc != 0) {
429 return BOOT_EFLASH;
430 }
431
432 return 0;
433}
434
Fabio Utzig2473ac02017-05-02 12:45:02 -0300435static int
436boot_write_flag(int flag, const struct flash_area *fap)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800437{
438 uint32_t off;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800439 int rc;
Fabio Utzig644b8d42017-04-20 07:56:05 -0300440 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700441 uint8_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300442 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800443
Fabio Utzig2473ac02017-05-02 12:45:02 -0300444 switch (flag) {
445 case BOOT_FLAG_COPY_DONE:
446 off = boot_copy_done_off(fap);
447 break;
448 case BOOT_FLAG_IMAGE_OK:
449 off = boot_image_ok_off(fap);
450 break;
451 default:
Fabio Utzig856f7832017-05-22 11:04:44 -0400452 return BOOT_EBADARGS;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300453 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800454
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200455 align = flash_area_align(fap);
Fabio Utzig644b8d42017-04-20 07:56:05 -0300456 assert(align <= BOOT_MAX_ALIGN);
Fabio Utzig39000012018-07-30 12:40:20 -0300457 erased_val = flash_area_erased_val(fap);
458 memset(buf, erased_val, BOOT_MAX_ALIGN);
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400459 buf[0] = BOOT_FLAG_SET;
David Brown9d725462017-01-23 15:50:58 -0700460
461 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800462 if (rc != 0) {
463 return BOOT_EFLASH;
464 }
465
466 return 0;
467}
468
469int
Fabio Utzig2473ac02017-05-02 12:45:02 -0300470boot_write_copy_done(const struct flash_area *fap)
471{
472 return boot_write_flag(BOOT_FLAG_COPY_DONE, fap);
473}
474
475int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800476boot_write_image_ok(const struct flash_area *fap)
477{
Fabio Utzig2473ac02017-05-02 12:45:02 -0300478 return boot_write_flag(BOOT_FLAG_IMAGE_OK, fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800479}
480
481int
Fabio Utzig46490722017-09-04 15:34:32 -0300482boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
483{
484 uint32_t off;
485 int rc;
486 uint8_t buf[BOOT_MAX_ALIGN];
487 uint8_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300488 uint8_t erased_val;
Fabio Utzig46490722017-09-04 15:34:32 -0300489
490 off = boot_swap_size_off(fap);
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200491 align = flash_area_align(fap);
Fabio Utzig46490722017-09-04 15:34:32 -0300492 assert(align <= BOOT_MAX_ALIGN);
493 if (align < sizeof swap_size) {
494 align = sizeof swap_size;
495 }
Fabio Utzig39000012018-07-30 12:40:20 -0300496 erased_val = flash_area_erased_val(fap);
497 memset(buf, erased_val, BOOT_MAX_ALIGN);
Fabio Utzig46490722017-09-04 15:34:32 -0300498 memcpy(buf, (uint8_t *)&swap_size, sizeof swap_size);
499
500 rc = flash_area_write(fap, off, buf, align);
501 if (rc != 0) {
502 return BOOT_EFLASH;
503 }
504
505 return 0;
506}
507
Fabio Utzigba829042018-09-18 08:29:34 -0300508#ifdef MCUBOOT_ENC_IMAGES
509int
510boot_write_enc_key(const struct flash_area *fap, uint8_t slot, const uint8_t *enckey)
511{
512 uint32_t off;
513 int rc;
514
515 off = boot_enc_key_off(fap, slot);
516 rc = flash_area_write(fap, off, enckey, BOOT_ENC_KEY_SIZE);
517 if (rc != 0) {
518 return BOOT_EFLASH;
519 }
520
521 return 0;
522}
523#endif
524
Fabio Utzig46490722017-09-04 15:34:32 -0300525int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800526boot_swap_type(void)
527{
528 const struct boot_swap_table *table;
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300529 struct boot_swap_state slot0;
530 struct boot_swap_state slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800531 int rc;
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200532 size_t i;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800533
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300534 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &slot0);
535 if (rc) {
536 return BOOT_SWAP_TYPE_PANIC;
537 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800538
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300539 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &slot1);
540 if (rc) {
541 return BOOT_SWAP_TYPE_PANIC;
542 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800543
544 for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
545 table = boot_swap_tables + i;
546
Fabio Utzig39000012018-07-30 12:40:20 -0300547 if ((table->magic_slot0 == BOOT_MAGIC_ANY ||
548 table->magic_slot0 == slot0.magic) &&
549 (table->magic_slot1 == BOOT_MAGIC_ANY ||
550 table->magic_slot1 == slot1.magic) &&
551 (table->image_ok_slot0 == BOOT_FLAG_ANY ||
552 table->image_ok_slot0 == slot0.image_ok) &&
553 (table->image_ok_slot1 == BOOT_FLAG_ANY ||
554 table->image_ok_slot1 == slot1.image_ok) &&
555 (table->copy_done_slot0 == BOOT_FLAG_ANY ||
556 table->copy_done_slot0 == slot0.copy_done)) {
Fabio Utzig34e393e2017-05-22 11:07:07 -0400557 BOOT_LOG_INF("Swap type: %s",
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300558 table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
559 table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
560 table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
561 "BUG; can't happen");
562 assert(table->swap_type == BOOT_SWAP_TYPE_TEST ||
563 table->swap_type == BOOT_SWAP_TYPE_PERM ||
564 table->swap_type == BOOT_SWAP_TYPE_REVERT);
565 return table->swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800566 }
567 }
568
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300569 BOOT_LOG_INF("Swap type: none");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800570 return BOOT_SWAP_TYPE_NONE;
571}
572
573/**
574 * Marks the image in slot 1 as pending. On the next reboot, the system will
575 * perform a one-time boot of the slot 1 image.
576 *
Christopher Collins7835c1e2016-12-21 10:10:51 -0800577 * @param permanent Whether the image should be used permanently or
578 * only tested once:
579 * 0=run image once, then confirm or revert.
580 * 1=run image forever.
581 *
Christopher Collins92ea77f2016-12-12 15:59:26 -0800582 * @return 0 on success; nonzero on failure.
583 */
584int
Christopher Collins7835c1e2016-12-21 10:10:51 -0800585boot_set_pending(int permanent)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800586{
587 const struct flash_area *fap;
588 struct boot_swap_state state_slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800589 int rc;
590
Fabio Utzig2473ac02017-05-02 12:45:02 -0300591 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &state_slot1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800592 if (rc != 0) {
593 return rc;
594 }
595
596 switch (state_slot1.magic) {
597 case BOOT_MAGIC_GOOD:
598 /* Swap already scheduled. */
599 return 0;
600
601 case BOOT_MAGIC_UNSET:
Fabio Utzig2473ac02017-05-02 12:45:02 -0300602 rc = flash_area_open(FLASH_AREA_IMAGE_1, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800603 if (rc != 0) {
604 rc = BOOT_EFLASH;
605 } else {
606 rc = boot_write_magic(fap);
607 }
608
Christopher Collins7835c1e2016-12-21 10:10:51 -0800609 if (rc == 0 && permanent) {
610 rc = boot_write_image_ok(fap);
611 }
612
Christopher Collins92ea77f2016-12-12 15:59:26 -0800613 flash_area_close(fap);
614 return rc;
615
616 default:
617 /* XXX: Temporary assert. */
618 assert(0);
619 return -1;
620 }
621}
622
623/**
624 * 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.
625 *
626 * @return 0 on success; nonzero on failure.
627 */
628int
629boot_set_confirmed(void)
630{
631 const struct flash_area *fap;
632 struct boot_swap_state state_slot0;
633 int rc;
634
Fabio Utzig2473ac02017-05-02 12:45:02 -0300635 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800636 if (rc != 0) {
637 return rc;
638 }
639
640 switch (state_slot0.magic) {
641 case BOOT_MAGIC_GOOD:
642 /* Confirm needed; proceed. */
643 break;
644
645 case BOOT_MAGIC_UNSET:
646 /* Already confirmed. */
647 return 0;
648
649 case BOOT_MAGIC_BAD:
650 /* Unexpected state. */
651 return BOOT_EBADVECT;
652 }
653
Christopher Collins92ea77f2016-12-12 15:59:26 -0800654 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
655 if (rc) {
656 rc = BOOT_EFLASH;
657 goto done;
658 }
659
Fabio Utzig08fa2672018-09-26 12:16:18 -0300660 if (state_slot0.copy_done == BOOT_FLAG_UNSET) {
Fabio Utzig39000012018-07-30 12:40:20 -0300661 /* Swap never completed. This is unexpected. */
662 rc = BOOT_EBADVECT;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800663 goto done;
664 }
665
Ɓukasz Rymanowskia1927f42018-09-26 15:31:50 +0200666 if (state_slot0.image_ok != BOOT_FLAG_UNSET) {
Fabio Utzig39000012018-07-30 12:40:20 -0300667 /* Already confirmed. */
668 goto done;
669 }
670
671 rc = boot_write_image_ok(fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800672
673done:
674 flash_area_close(fap);
675 return rc;
676}