bootutil: extracted app common library from bootutil_misc
Part of code of boot/bootutil/ is re-implemented in zephyr-rtos repository. As some code are defined here and there it becomes problem when need to include it with outstanding feature in a build. It is possible to mitigate problem using #fdefry - but this was rather temporary hack. This patch introduce new module which is common for MCUBoot build and application build. Common code were extracted to bootutil_public.c source file and bootutil_public.h header MCUboot also select DISABLE_MCUBOOT_BOOTUTIL_LIB_OWN_LOG Kconfig option, as it must define log configuration on its own for all its sourcecode. Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
This commit is contained in:
parent
e512181609
commit
f573b392ec
|
@ -18,6 +18,7 @@ target_sources(bootutil
|
|||
PRIVATE
|
||||
src/boot_record.c
|
||||
src/bootutil_misc.c
|
||||
src/bootutil_public.c
|
||||
src/caps.c
|
||||
src/encrypted.c
|
||||
src/fault_injection_hardening.c
|
||||
|
|
|
@ -30,37 +30,12 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include "bootutil/fault_injection_hardening.h"
|
||||
#include "bootutil/bootutil_public.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Attempt to boot the contents of the primary slot. */
|
||||
#define BOOT_SWAP_TYPE_NONE 1
|
||||
|
||||
/**
|
||||
* Swap to the secondary slot.
|
||||
* Absent a confirm command, revert back on next boot.
|
||||
*/
|
||||
#define BOOT_SWAP_TYPE_TEST 2
|
||||
|
||||
/**
|
||||
* Swap to the secondary slot,
|
||||
* and permanently switch to booting its contents.
|
||||
*/
|
||||
#define BOOT_SWAP_TYPE_PERM 3
|
||||
|
||||
/** Swap back to alternate slot. A confirm changes this state to NONE. */
|
||||
#define BOOT_SWAP_TYPE_REVERT 4
|
||||
|
||||
/** Swap failed because image to be run is not valid */
|
||||
#define BOOT_SWAP_TYPE_FAIL 5
|
||||
|
||||
/** Swapping encountered an unrecoverable error */
|
||||
#define BOOT_SWAP_TYPE_PANIC 0xff
|
||||
|
||||
#define BOOT_MAX_ALIGN 8
|
||||
|
||||
struct image_header;
|
||||
/**
|
||||
* A response object provided by the boot loader code; indicates where to jump
|
||||
|
@ -97,12 +72,6 @@ fih_int boot_go(struct boot_rsp *rsp);
|
|||
struct boot_loader_state;
|
||||
fih_int context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);
|
||||
|
||||
int boot_swap_type_multi(int image_index);
|
||||
int boot_swap_type(void);
|
||||
|
||||
int boot_set_pending(int permanent);
|
||||
int boot_set_confirmed(void);
|
||||
|
||||
#define SPLIT_GO_OK (0)
|
||||
#define SPLIT_GO_NON_MATCHING (-1)
|
||||
#define SPLIT_GO_ERR (-2)
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2017-2019 Linaro LTD
|
||||
* Copyright (c) 2016-2019 JUUL Labs
|
||||
* Copyright (c) 2019-2020 Arm Limited
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* Original license:
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BOOTUTIL_PUBLIC
|
||||
#define H_BOOTUTIL_PUBLIC
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <flash_map_backend/flash_map_backend.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Attempt to boot the contents of the primary slot. */
|
||||
#define BOOT_SWAP_TYPE_NONE 1
|
||||
|
||||
/**
|
||||
* Swap to the secondary slot.
|
||||
* Absent a confirm command, revert back on next boot.
|
||||
*/
|
||||
#define BOOT_SWAP_TYPE_TEST 2
|
||||
|
||||
/**
|
||||
* Swap to the secondary slot,
|
||||
* and permanently switch to booting its contents.
|
||||
*/
|
||||
#define BOOT_SWAP_TYPE_PERM 3
|
||||
|
||||
/** Swap back to alternate slot. A confirm changes this state to NONE. */
|
||||
#define BOOT_SWAP_TYPE_REVERT 4
|
||||
|
||||
/** Swap failed because image to be run is not valid */
|
||||
#define BOOT_SWAP_TYPE_FAIL 5
|
||||
|
||||
/** Swapping encountered an unrecoverable error */
|
||||
#define BOOT_SWAP_TYPE_PANIC 0xff
|
||||
|
||||
#define BOOT_MAX_ALIGN 8
|
||||
|
||||
#define BOOT_MAGIC_GOOD 1
|
||||
#define BOOT_MAGIC_BAD 2
|
||||
#define BOOT_MAGIC_UNSET 3
|
||||
#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */
|
||||
#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */
|
||||
|
||||
/*
|
||||
* NOTE: leave BOOT_FLAG_SET equal to one, this is written to flash!
|
||||
*/
|
||||
#define BOOT_FLAG_SET 1
|
||||
#define BOOT_FLAG_BAD 2
|
||||
#define BOOT_FLAG_UNSET 3
|
||||
#define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */
|
||||
|
||||
#define BOOT_MAGIC_SZ (sizeof boot_img_magic)
|
||||
|
||||
int boot_swap_type_multi(int image_index);
|
||||
int boot_swap_type(void);
|
||||
|
||||
int boot_set_pending(int permanent);
|
||||
int boot_set_confirmed(void);
|
||||
uint32_t boot_swap_info_off(const struct flash_area *fap);
|
||||
|
||||
#define BOOT_MAGIC_ARR_SZ \
|
||||
(sizeof boot_img_magic / sizeof boot_img_magic[0])
|
||||
|
||||
extern const uint32_t boot_img_magic[4];
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -46,67 +46,11 @@ MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
|
|||
/* Currently only used by imgmgr */
|
||||
int boot_current_slot;
|
||||
|
||||
const uint32_t boot_img_magic[] = {
|
||||
0xf395c277,
|
||||
0x7fefd260,
|
||||
0x0f505235,
|
||||
0x8079b62c,
|
||||
};
|
||||
extern const uint32_t boot_img_magic[];
|
||||
|
||||
#define BOOT_MAGIC_ARR_SZ \
|
||||
(sizeof boot_img_magic / sizeof boot_img_magic[0])
|
||||
|
||||
struct boot_swap_table {
|
||||
uint8_t magic_primary_slot;
|
||||
uint8_t magic_secondary_slot;
|
||||
uint8_t image_ok_primary_slot;
|
||||
uint8_t image_ok_secondary_slot;
|
||||
uint8_t copy_done_primary_slot;
|
||||
|
||||
uint8_t swap_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* This set of tables maps image trailer contents to swap operation type.
|
||||
* When searching for a match, these tables must be iterated sequentially.
|
||||
*
|
||||
* NOTE: the table order is very important. The settings in the secondary
|
||||
* slot always are priority to the primary slot and should be located
|
||||
* earlier in the table.
|
||||
*
|
||||
* The table lists only states where there is action needs to be taken by
|
||||
* the bootloader, as in starting/finishing a swap operation.
|
||||
*/
|
||||
static const struct boot_swap_table boot_swap_tables[] = {
|
||||
{
|
||||
.magic_primary_slot = BOOT_MAGIC_ANY,
|
||||
.magic_secondary_slot = BOOT_MAGIC_GOOD,
|
||||
.image_ok_primary_slot = BOOT_FLAG_ANY,
|
||||
.image_ok_secondary_slot = BOOT_FLAG_UNSET,
|
||||
.copy_done_primary_slot = BOOT_FLAG_ANY,
|
||||
.swap_type = BOOT_SWAP_TYPE_TEST,
|
||||
},
|
||||
{
|
||||
.magic_primary_slot = BOOT_MAGIC_ANY,
|
||||
.magic_secondary_slot = BOOT_MAGIC_GOOD,
|
||||
.image_ok_primary_slot = BOOT_FLAG_ANY,
|
||||
.image_ok_secondary_slot = BOOT_FLAG_SET,
|
||||
.copy_done_primary_slot = BOOT_FLAG_ANY,
|
||||
.swap_type = BOOT_SWAP_TYPE_PERM,
|
||||
},
|
||||
{
|
||||
.magic_primary_slot = BOOT_MAGIC_GOOD,
|
||||
.magic_secondary_slot = BOOT_MAGIC_UNSET,
|
||||
.image_ok_primary_slot = BOOT_FLAG_UNSET,
|
||||
.image_ok_secondary_slot = BOOT_FLAG_ANY,
|
||||
.copy_done_primary_slot = BOOT_FLAG_SET,
|
||||
.swap_type = BOOT_SWAP_TYPE_REVERT,
|
||||
},
|
||||
};
|
||||
|
||||
#define BOOT_SWAP_TABLES_COUNT \
|
||||
(sizeof boot_swap_tables / sizeof boot_swap_tables[0])
|
||||
|
||||
/**
|
||||
* @brief Determine if the data at two memory addresses is equal
|
||||
*
|
||||
|
@ -150,50 +94,6 @@ out:
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
boot_magic_decode(const uint32_t *magic)
|
||||
{
|
||||
if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
|
||||
return BOOT_MAGIC_GOOD;
|
||||
}
|
||||
return BOOT_MAGIC_BAD;
|
||||
}
|
||||
|
||||
static int
|
||||
boot_flag_decode(uint8_t flag)
|
||||
{
|
||||
if (flag != BOOT_FLAG_SET) {
|
||||
return BOOT_FLAG_BAD;
|
||||
}
|
||||
return BOOT_FLAG_SET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a status source table is satisfied by the specified magic
|
||||
* code.
|
||||
*
|
||||
* @param tbl_val A magic field from a status source table.
|
||||
* @param val The magic value in a trailer, encoded as a
|
||||
* BOOT_MAGIC_[...].
|
||||
*
|
||||
* @return 1 if the two values are compatible;
|
||||
* 0 otherwise.
|
||||
*/
|
||||
int
|
||||
boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
|
||||
{
|
||||
switch (tbl_val) {
|
||||
case BOOT_MAGIC_ANY:
|
||||
return 1;
|
||||
|
||||
case BOOT_MAGIC_NOTGOOD:
|
||||
return val != BOOT_MAGIC_GOOD;
|
||||
|
||||
default:
|
||||
return tbl_val == val;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
boot_status_sz(uint32_t min_write_sz)
|
||||
{
|
||||
|
@ -266,12 +166,6 @@ boot_copy_done_off(const struct flash_area *fap)
|
|||
return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
boot_swap_info_off(const struct flash_area *fap)
|
||||
{
|
||||
return boot_copy_done_off(fap) - BOOT_MAX_ALIGN;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
boot_swap_size_off(const struct flash_area *fap)
|
||||
{
|
||||
|
@ -291,109 +185,6 @@ boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
|
|||
}
|
||||
#endif
|
||||
|
||||
bool bootutil_buffer_is_erased(const struct flash_area *area,
|
||||
const void *buffer, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
uint8_t *u8b;
|
||||
uint8_t erased_val;
|
||||
|
||||
if (buffer == NULL || len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
erased_val = flash_area_erased_val(area);
|
||||
for (i = 0, u8b = (uint8_t *)buffer; i < len; i++) {
|
||||
if (u8b[i] != erased_val) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
boot_read_swap_state(const struct flash_area *fap,
|
||||
struct boot_swap_state *state)
|
||||
{
|
||||
uint32_t magic[BOOT_MAGIC_ARR_SZ];
|
||||
uint32_t off;
|
||||
uint8_t swap_info;
|
||||
int rc;
|
||||
|
||||
off = boot_magic_off(fap);
|
||||
rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
|
||||
if (rc < 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
if (bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ)) {
|
||||
state->magic = BOOT_MAGIC_UNSET;
|
||||
} else {
|
||||
state->magic = boot_magic_decode(magic);
|
||||
}
|
||||
|
||||
off = boot_swap_info_off(fap);
|
||||
rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
|
||||
if (rc < 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
/* Extract the swap type and image number */
|
||||
state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
|
||||
state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
|
||||
|
||||
if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info) ||
|
||||
state->swap_type > BOOT_SWAP_TYPE_REVERT) {
|
||||
state->swap_type = BOOT_SWAP_TYPE_NONE;
|
||||
state->image_num = 0;
|
||||
}
|
||||
|
||||
off = boot_copy_done_off(fap);
|
||||
rc = flash_area_read(fap, off, &state->copy_done, sizeof state->copy_done);
|
||||
if (rc < 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
if (bootutil_buffer_is_erased(fap, &state->copy_done,
|
||||
sizeof state->copy_done)) {
|
||||
state->copy_done = BOOT_FLAG_UNSET;
|
||||
} else {
|
||||
state->copy_done = boot_flag_decode(state->copy_done);
|
||||
}
|
||||
|
||||
off = boot_image_ok_off(fap);
|
||||
rc = flash_area_read(fap, off, &state->image_ok, sizeof state->image_ok);
|
||||
if (rc < 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
if (bootutil_buffer_is_erased(fap, &state->image_ok,
|
||||
sizeof state->image_ok)) {
|
||||
state->image_ok = BOOT_FLAG_UNSET;
|
||||
} else {
|
||||
state->image_ok = boot_flag_decode(state->image_ok);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the image trailer from the scratch area.
|
||||
*/
|
||||
int
|
||||
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
|
||||
{
|
||||
const struct flash_area *fap;
|
||||
int rc;
|
||||
|
||||
rc = flash_area_open(flash_area_id, &fap);
|
||||
if (rc != 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
rc = boot_read_swap_state(fap, state);
|
||||
flash_area_close(fap);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* This functions tries to locate the status area after an aborted swap,
|
||||
* by looking for the magic in the possible locations.
|
||||
|
@ -503,25 +294,6 @@ boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
|
|||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
boot_write_magic(const struct flash_area *fap)
|
||||
{
|
||||
uint32_t off;
|
||||
int rc;
|
||||
|
||||
off = boot_magic_off(fap);
|
||||
|
||||
BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)",
|
||||
fap->fa_id, (unsigned long)off,
|
||||
(unsigned long)(fap->fa_off + off));
|
||||
rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
|
||||
if (rc != 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write trailer data; status bytes, swap_size, etc
|
||||
*
|
||||
|
@ -575,39 +347,6 @@ boot_write_copy_done(const struct flash_area *fap)
|
|||
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
|
||||
}
|
||||
|
||||
int
|
||||
boot_write_image_ok(const struct flash_area *fap)
|
||||
{
|
||||
uint32_t off;
|
||||
|
||||
off = boot_image_ok_off(fap);
|
||||
BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%lx (0x%lx)",
|
||||
fap->fa_id, (unsigned long)off,
|
||||
(unsigned long)(fap->fa_off + off));
|
||||
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified value to the `swap-type` field of an image trailer.
|
||||
* This value is persisted so that the boot loader knows what swap operation to
|
||||
* resume in case of an unexpected reset.
|
||||
*/
|
||||
int
|
||||
boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
|
||||
uint8_t image_num)
|
||||
{
|
||||
uint32_t off;
|
||||
uint8_t swap_info;
|
||||
|
||||
BOOT_SET_SWAP_INFO(swap_info, image_num, swap_type);
|
||||
off = boot_swap_info_off(fap);
|
||||
BOOT_LOG_DBG("writing swap_info; fa_id=%d off=0x%lx (0x%lx), swap_type=0x%x"
|
||||
" image_num=0x%x",
|
||||
fap->fa_id, (unsigned long)off,
|
||||
(unsigned long)(fap->fa_off + off), swap_type, image_num);
|
||||
return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 1);
|
||||
}
|
||||
|
||||
int
|
||||
boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
|
||||
{
|
||||
|
@ -644,196 +383,3 @@ boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
boot_swap_type_multi(int image_index)
|
||||
{
|
||||
const struct boot_swap_table *table;
|
||||
struct boot_swap_state primary_slot;
|
||||
struct boot_swap_state secondary_slot;
|
||||
int rc;
|
||||
size_t i;
|
||||
|
||||
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||
&primary_slot);
|
||||
if (rc) {
|
||||
return BOOT_SWAP_TYPE_PANIC;
|
||||
}
|
||||
|
||||
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
|
||||
&secondary_slot);
|
||||
if (rc) {
|
||||
return BOOT_SWAP_TYPE_PANIC;
|
||||
}
|
||||
|
||||
for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
|
||||
table = boot_swap_tables + i;
|
||||
|
||||
if (boot_magic_compatible_check(table->magic_primary_slot,
|
||||
primary_slot.magic) &&
|
||||
boot_magic_compatible_check(table->magic_secondary_slot,
|
||||
secondary_slot.magic) &&
|
||||
(table->image_ok_primary_slot == BOOT_FLAG_ANY ||
|
||||
table->image_ok_primary_slot == primary_slot.image_ok) &&
|
||||
(table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
|
||||
table->image_ok_secondary_slot == secondary_slot.image_ok) &&
|
||||
(table->copy_done_primary_slot == BOOT_FLAG_ANY ||
|
||||
table->copy_done_primary_slot == primary_slot.copy_done)) {
|
||||
BOOT_LOG_INF("Swap type: %s",
|
||||
table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
|
||||
table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
|
||||
table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
|
||||
"BUG; can't happen");
|
||||
if (table->swap_type != BOOT_SWAP_TYPE_TEST &&
|
||||
table->swap_type != BOOT_SWAP_TYPE_PERM &&
|
||||
table->swap_type != BOOT_SWAP_TYPE_REVERT) {
|
||||
return BOOT_SWAP_TYPE_PANIC;
|
||||
}
|
||||
return table->swap_type;
|
||||
}
|
||||
}
|
||||
|
||||
BOOT_LOG_INF("Swap type: none");
|
||||
return BOOT_SWAP_TYPE_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is not used by the bootloader itself, but its required API
|
||||
* by external tooling like mcumgr.
|
||||
*/
|
||||
int
|
||||
boot_swap_type(void)
|
||||
{
|
||||
return boot_swap_type_multi(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the image in the secondary slot as pending. On the next reboot,
|
||||
* the system will perform a one-time boot of the the secondary slot image.
|
||||
*
|
||||
* @param permanent Whether the image should be used permanently or
|
||||
* only tested once:
|
||||
* 0=run image once, then confirm or revert.
|
||||
* 1=run image forever.
|
||||
*
|
||||
* @return 0 on success; nonzero on failure.
|
||||
*/
|
||||
int
|
||||
boot_set_pending(int permanent)
|
||||
{
|
||||
const struct flash_area *fap;
|
||||
struct boot_swap_state state_secondary_slot;
|
||||
uint8_t swap_type;
|
||||
int rc;
|
||||
|
||||
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(0),
|
||||
&state_secondary_slot);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (state_secondary_slot.magic) {
|
||||
case BOOT_MAGIC_GOOD:
|
||||
/* Swap already scheduled. */
|
||||
return 0;
|
||||
|
||||
case BOOT_MAGIC_UNSET:
|
||||
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(0), &fap);
|
||||
if (rc != 0) {
|
||||
rc = BOOT_EFLASH;
|
||||
} else {
|
||||
rc = boot_write_magic(fap);
|
||||
}
|
||||
|
||||
if (rc == 0 && permanent) {
|
||||
rc = boot_write_image_ok(fap);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
if (permanent) {
|
||||
swap_type = BOOT_SWAP_TYPE_PERM;
|
||||
} else {
|
||||
swap_type = BOOT_SWAP_TYPE_TEST;
|
||||
}
|
||||
rc = boot_write_swap_info(fap, swap_type, 0);
|
||||
}
|
||||
|
||||
flash_area_close(fap);
|
||||
return rc;
|
||||
|
||||
case BOOT_MAGIC_BAD:
|
||||
/* The image slot is corrupt. There is no way to recover, so erase the
|
||||
* slot to allow future upgrades.
|
||||
*/
|
||||
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(0), &fap);
|
||||
if (rc != 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
flash_area_erase(fap, 0, fap->fa_size);
|
||||
flash_area_close(fap);
|
||||
return BOOT_EBADIMAGE;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return BOOT_EBADIMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the image in the primary slot as confirmed. The system will continue
|
||||
* booting into the image in the primary slot until told to boot from a
|
||||
* different slot.
|
||||
*
|
||||
* @return 0 on success; nonzero on failure.
|
||||
*/
|
||||
int
|
||||
boot_set_confirmed(void)
|
||||
{
|
||||
const struct flash_area *fap;
|
||||
struct boot_swap_state state_primary_slot;
|
||||
int rc;
|
||||
|
||||
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(0),
|
||||
&state_primary_slot);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (state_primary_slot.magic) {
|
||||
case BOOT_MAGIC_GOOD:
|
||||
/* Confirm needed; proceed. */
|
||||
break;
|
||||
|
||||
case BOOT_MAGIC_UNSET:
|
||||
/* Already confirmed. */
|
||||
return 0;
|
||||
|
||||
case BOOT_MAGIC_BAD:
|
||||
/* Unexpected state. */
|
||||
return BOOT_EBADVECT;
|
||||
}
|
||||
|
||||
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &fap);
|
||||
if (rc) {
|
||||
rc = BOOT_EFLASH;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (state_primary_slot.copy_done == BOOT_FLAG_UNSET) {
|
||||
/* Swap never completed. This is unexpected. */
|
||||
rc = BOOT_EBADVECT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (state_primary_slot.image_ok != BOOT_FLAG_UNSET) {
|
||||
/* Already confirmed. */
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = boot_write_image_ok(fap);
|
||||
|
||||
done:
|
||||
flash_area_close(fap);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -106,20 +106,6 @@ struct boot_status {
|
|||
int source; /* Which slot contains swap status metadata */
|
||||
};
|
||||
|
||||
#define BOOT_MAGIC_GOOD 1
|
||||
#define BOOT_MAGIC_BAD 2
|
||||
#define BOOT_MAGIC_UNSET 3
|
||||
#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */
|
||||
#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */
|
||||
|
||||
/*
|
||||
* NOTE: leave BOOT_FLAG_SET equal to one, this is written to flash!
|
||||
*/
|
||||
#define BOOT_FLAG_SET 1
|
||||
#define BOOT_FLAG_BAD 2
|
||||
#define BOOT_FLAG_UNSET 3
|
||||
#define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */
|
||||
|
||||
#define BOOT_STATUS_IDX_0 1
|
||||
|
||||
#define BOOT_STATUS_STATE_0 1
|
||||
|
@ -243,8 +229,6 @@ _Static_assert(BOOT_IMAGE_NUMBER > 0, "Invalid value for BOOT_IMAGE_NUMBER");
|
|||
#define BOOT_STATUS_SOURCE_SCRATCH 1
|
||||
#define BOOT_STATUS_SOURCE_PRIMARY_SLOT 2
|
||||
|
||||
#define BOOT_MAGIC_SZ (sizeof boot_img_magic)
|
||||
|
||||
/**
|
||||
* Compatibility shim for flash sector type.
|
||||
*
|
||||
|
@ -295,7 +279,6 @@ uint32_t boot_status_sz(uint32_t min_write_sz);
|
|||
uint32_t boot_trailer_sz(uint32_t min_write_sz);
|
||||
int boot_status_entries(int image_index, const struct flash_area *fap);
|
||||
uint32_t boot_status_off(const struct flash_area *fap);
|
||||
uint32_t boot_swap_info_off(const struct flash_area *fap);
|
||||
int boot_read_swap_state(const struct flash_area *fap,
|
||||
struct boot_swap_state *state);
|
||||
int boot_read_swap_state_by_id(int flash_area_id,
|
||||
|
|
|
@ -0,0 +1,585 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2017-2019 Linaro LTD
|
||||
* Copyright (c) 2016-2019 JUUL Labs
|
||||
* Copyright (c) 2019-2020 Arm Limited
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* Original license:
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "sysflash/sysflash.h"
|
||||
#include "flash_map_backend/flash_map_backend.h"
|
||||
|
||||
#include "bootutil/image.h"
|
||||
#include "bootutil/bootutil_public.h"
|
||||
#include "bootutil_priv.h"
|
||||
#include "bootutil/bootutil_log.h"
|
||||
#ifdef MCUBOOT_ENC_IMAGES
|
||||
#include "bootutil/enc_key.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MCUBOOT
|
||||
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
|
||||
#else
|
||||
MCUBOOT_LOG_MODULE_REGISTER(mcuboot_util);
|
||||
#endif
|
||||
|
||||
const uint32_t boot_img_magic[] = {
|
||||
0xf395c277,
|
||||
0x7fefd260,
|
||||
0x0f505235,
|
||||
0x8079b62c,
|
||||
};
|
||||
|
||||
#define BOOT_MAGIC_ARR_SZ \
|
||||
(sizeof boot_img_magic / sizeof boot_img_magic[0])
|
||||
|
||||
struct boot_swap_table {
|
||||
uint8_t magic_primary_slot;
|
||||
uint8_t magic_secondary_slot;
|
||||
uint8_t image_ok_primary_slot;
|
||||
uint8_t image_ok_secondary_slot;
|
||||
uint8_t copy_done_primary_slot;
|
||||
|
||||
uint8_t swap_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* This set of tables maps image trailer contents to swap operation type.
|
||||
* When searching for a match, these tables must be iterated sequentially.
|
||||
*
|
||||
* NOTE: the table order is very important. The settings in the secondary
|
||||
* slot always are priority to the primary slot and should be located
|
||||
* earlier in the table.
|
||||
*
|
||||
* The table lists only states where there is action needs to be taken by
|
||||
* the bootloader, as in starting/finishing a swap operation.
|
||||
*/
|
||||
static const struct boot_swap_table boot_swap_tables[] = {
|
||||
{
|
||||
.magic_primary_slot = BOOT_MAGIC_ANY,
|
||||
.magic_secondary_slot = BOOT_MAGIC_GOOD,
|
||||
.image_ok_primary_slot = BOOT_FLAG_ANY,
|
||||
.image_ok_secondary_slot = BOOT_FLAG_UNSET,
|
||||
.copy_done_primary_slot = BOOT_FLAG_ANY,
|
||||
.swap_type = BOOT_SWAP_TYPE_TEST,
|
||||
},
|
||||
{
|
||||
.magic_primary_slot = BOOT_MAGIC_ANY,
|
||||
.magic_secondary_slot = BOOT_MAGIC_GOOD,
|
||||
.image_ok_primary_slot = BOOT_FLAG_ANY,
|
||||
.image_ok_secondary_slot = BOOT_FLAG_SET,
|
||||
.copy_done_primary_slot = BOOT_FLAG_ANY,
|
||||
.swap_type = BOOT_SWAP_TYPE_PERM,
|
||||
},
|
||||
{
|
||||
.magic_primary_slot = BOOT_MAGIC_GOOD,
|
||||
.magic_secondary_slot = BOOT_MAGIC_UNSET,
|
||||
.image_ok_primary_slot = BOOT_FLAG_UNSET,
|
||||
.image_ok_secondary_slot = BOOT_FLAG_ANY,
|
||||
.copy_done_primary_slot = BOOT_FLAG_SET,
|
||||
.swap_type = BOOT_SWAP_TYPE_REVERT,
|
||||
},
|
||||
};
|
||||
|
||||
#define BOOT_SWAP_TABLES_COUNT \
|
||||
(sizeof boot_swap_tables / sizeof boot_swap_tables[0])
|
||||
|
||||
static int
|
||||
boot_magic_decode(const uint32_t *magic)
|
||||
{
|
||||
if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
|
||||
return BOOT_MAGIC_GOOD;
|
||||
}
|
||||
return BOOT_MAGIC_BAD;
|
||||
}
|
||||
|
||||
static int
|
||||
boot_flag_decode(uint8_t flag)
|
||||
{
|
||||
if (flag != BOOT_FLAG_SET) {
|
||||
return BOOT_FLAG_BAD;
|
||||
}
|
||||
return BOOT_FLAG_SET;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
boot_magic_off(const struct flash_area *fap)
|
||||
{
|
||||
return fap->fa_size - BOOT_MAGIC_SZ;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
boot_image_ok_off(const struct flash_area *fap)
|
||||
{
|
||||
return boot_magic_off(fap) - BOOT_MAX_ALIGN;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
boot_copy_done_off(const struct flash_area *fap)
|
||||
{
|
||||
return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
boot_swap_size_off(const struct flash_area *fap)
|
||||
{
|
||||
return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
boot_swap_info_off(const struct flash_area *fap)
|
||||
{
|
||||
return boot_copy_done_off(fap) - BOOT_MAX_ALIGN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a status source table is satisfied by the specified magic
|
||||
* code.
|
||||
*
|
||||
* @param tbl_val A magic field from a status source table.
|
||||
* @param val The magic value in a trailer, encoded as a
|
||||
* BOOT_MAGIC_[...].
|
||||
*
|
||||
* @return 1 if the two values are compatible;
|
||||
* 0 otherwise.
|
||||
*/
|
||||
int
|
||||
boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
|
||||
{
|
||||
switch (tbl_val) {
|
||||
case BOOT_MAGIC_ANY:
|
||||
return 1;
|
||||
|
||||
case BOOT_MAGIC_NOTGOOD:
|
||||
return val != BOOT_MAGIC_GOOD;
|
||||
|
||||
default:
|
||||
return tbl_val == val;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MCUBOOT_ENC_IMAGES
|
||||
static inline uint32_t
|
||||
boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
|
||||
{
|
||||
#if MCUBOOT_SWAP_SAVE_ENCTLV
|
||||
return boot_swap_size_off(fap) - ((slot + 1) *
|
||||
((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN));
|
||||
#else
|
||||
return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
bool bootutil_buffer_is_erased(const struct flash_area *area,
|
||||
const void *buffer, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
uint8_t *u8b;
|
||||
uint8_t erased_val;
|
||||
|
||||
if (buffer == NULL || len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
erased_val = flash_area_erased_val(area);
|
||||
for (i = 0, u8b = (uint8_t *)buffer; i < len; i++) {
|
||||
if (u8b[i] != erased_val) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
boot_read_swap_state(const struct flash_area *fap,
|
||||
struct boot_swap_state *state)
|
||||
{
|
||||
uint32_t magic[BOOT_MAGIC_ARR_SZ];
|
||||
uint32_t off;
|
||||
uint8_t swap_info;
|
||||
int rc;
|
||||
|
||||
off = boot_magic_off(fap);
|
||||
rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
|
||||
if (rc < 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
if (bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ)) {
|
||||
state->magic = BOOT_MAGIC_UNSET;
|
||||
} else {
|
||||
state->magic = boot_magic_decode(magic);
|
||||
}
|
||||
|
||||
off = boot_swap_info_off(fap);
|
||||
rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
|
||||
if (rc < 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
/* Extract the swap type and image number */
|
||||
state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
|
||||
state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
|
||||
|
||||
if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info) ||
|
||||
state->swap_type > BOOT_SWAP_TYPE_REVERT) {
|
||||
state->swap_type = BOOT_SWAP_TYPE_NONE;
|
||||
state->image_num = 0;
|
||||
}
|
||||
|
||||
off = boot_copy_done_off(fap);
|
||||
rc = flash_area_read(fap, off, &state->copy_done, sizeof state->copy_done);
|
||||
if (rc < 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
if (bootutil_buffer_is_erased(fap, &state->copy_done,
|
||||
sizeof state->copy_done)) {
|
||||
state->copy_done = BOOT_FLAG_UNSET;
|
||||
} else {
|
||||
state->copy_done = boot_flag_decode(state->copy_done);
|
||||
}
|
||||
|
||||
off = boot_image_ok_off(fap);
|
||||
rc = flash_area_read(fap, off, &state->image_ok, sizeof state->image_ok);
|
||||
if (rc < 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
if (bootutil_buffer_is_erased(fap, &state->image_ok,
|
||||
sizeof state->image_ok)) {
|
||||
state->image_ok = BOOT_FLAG_UNSET;
|
||||
} else {
|
||||
state->image_ok = boot_flag_decode(state->image_ok);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the image trailer from the scratch area.
|
||||
*/
|
||||
int
|
||||
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
|
||||
{
|
||||
const struct flash_area *fap;
|
||||
int rc;
|
||||
|
||||
rc = flash_area_open(flash_area_id, &fap);
|
||||
if (rc != 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
rc = boot_read_swap_state(fap, state);
|
||||
flash_area_close(fap);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
boot_write_magic(const struct flash_area *fap)
|
||||
{
|
||||
uint32_t off;
|
||||
int rc;
|
||||
|
||||
off = boot_magic_off(fap);
|
||||
|
||||
BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)",
|
||||
fap->fa_id, (unsigned long)off,
|
||||
(unsigned long)(fap->fa_off + off));
|
||||
rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
|
||||
if (rc != 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write trailer data; status bytes, swap_size, etc
|
||||
*
|
||||
* @returns 0 on success, != 0 on error.
|
||||
*/
|
||||
static int
|
||||
boot_write_trailer(const struct flash_area *fap, uint32_t off,
|
||||
const uint8_t *inbuf, uint8_t inlen)
|
||||
{
|
||||
uint8_t buf[BOOT_MAX_ALIGN];
|
||||
uint8_t align;
|
||||
uint8_t erased_val;
|
||||
int rc;
|
||||
|
||||
align = flash_area_align(fap);
|
||||
if (inlen > BOOT_MAX_ALIGN || align > BOOT_MAX_ALIGN) {
|
||||
return -1;
|
||||
}
|
||||
erased_val = flash_area_erased_val(fap);
|
||||
if (align < inlen) {
|
||||
align = inlen;
|
||||
}
|
||||
memcpy(buf, inbuf, inlen);
|
||||
memset(&buf[inlen], erased_val, align - inlen);
|
||||
|
||||
rc = flash_area_write(fap, off, buf, align);
|
||||
if (rc != 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
|
||||
uint8_t flag_val)
|
||||
{
|
||||
const uint8_t buf[1] = { flag_val };
|
||||
return boot_write_trailer(fap, off, buf, 1);
|
||||
}
|
||||
|
||||
int
|
||||
boot_write_image_ok(const struct flash_area *fap)
|
||||
{
|
||||
uint32_t off;
|
||||
|
||||
off = boot_image_ok_off(fap);
|
||||
BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%lx (0x%lx)",
|
||||
fap->fa_id, (unsigned long)off,
|
||||
(unsigned long)(fap->fa_off + off));
|
||||
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified value to the `swap-type` field of an image trailer.
|
||||
* This value is persisted so that the boot loader knows what swap operation to
|
||||
* resume in case of an unexpected reset.
|
||||
*/
|
||||
int
|
||||
boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
|
||||
uint8_t image_num)
|
||||
{
|
||||
uint32_t off;
|
||||
uint8_t swap_info;
|
||||
|
||||
BOOT_SET_SWAP_INFO(swap_info, image_num, swap_type);
|
||||
off = boot_swap_info_off(fap);
|
||||
BOOT_LOG_DBG("writing swap_info; fa_id=%d off=0x%lx (0x%lx), swap_type=0x%x"
|
||||
" image_num=0x%x",
|
||||
fap->fa_id, (unsigned long)off,
|
||||
(unsigned long)(fap->fa_off + off), swap_type, image_num);
|
||||
return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 1);
|
||||
}
|
||||
|
||||
int
|
||||
boot_swap_type_multi(int image_index)
|
||||
{
|
||||
const struct boot_swap_table *table;
|
||||
struct boot_swap_state primary_slot;
|
||||
struct boot_swap_state secondary_slot;
|
||||
int rc;
|
||||
size_t i;
|
||||
|
||||
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
|
||||
&primary_slot);
|
||||
if (rc) {
|
||||
return BOOT_SWAP_TYPE_PANIC;
|
||||
}
|
||||
|
||||
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
|
||||
&secondary_slot);
|
||||
if (rc) {
|
||||
return BOOT_SWAP_TYPE_PANIC;
|
||||
}
|
||||
|
||||
for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
|
||||
table = boot_swap_tables + i;
|
||||
|
||||
if (boot_magic_compatible_check(table->magic_primary_slot,
|
||||
primary_slot.magic) &&
|
||||
boot_magic_compatible_check(table->magic_secondary_slot,
|
||||
secondary_slot.magic) &&
|
||||
(table->image_ok_primary_slot == BOOT_FLAG_ANY ||
|
||||
table->image_ok_primary_slot == primary_slot.image_ok) &&
|
||||
(table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
|
||||
table->image_ok_secondary_slot == secondary_slot.image_ok) &&
|
||||
(table->copy_done_primary_slot == BOOT_FLAG_ANY ||
|
||||
table->copy_done_primary_slot == primary_slot.copy_done)) {
|
||||
BOOT_LOG_INF("Swap type: %s",
|
||||
table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
|
||||
table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
|
||||
table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
|
||||
"BUG; can't happen");
|
||||
if (table->swap_type != BOOT_SWAP_TYPE_TEST &&
|
||||
table->swap_type != BOOT_SWAP_TYPE_PERM &&
|
||||
table->swap_type != BOOT_SWAP_TYPE_REVERT) {
|
||||
return BOOT_SWAP_TYPE_PANIC;
|
||||
}
|
||||
return table->swap_type;
|
||||
}
|
||||
}
|
||||
|
||||
BOOT_LOG_INF("Swap type: none");
|
||||
return BOOT_SWAP_TYPE_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is not used by the bootloader itself, but its required API
|
||||
* by external tooling like mcumgr.
|
||||
*/
|
||||
int
|
||||
boot_swap_type(void)
|
||||
{
|
||||
return boot_swap_type_multi(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the image in the secondary slot as pending. On the next reboot,
|
||||
* the system will perform a one-time boot of the the secondary slot image.
|
||||
*
|
||||
* @param permanent Whether the image should be used permanently or
|
||||
* only tested once:
|
||||
* 0=run image once, then confirm or revert.
|
||||
* 1=run image forever.
|
||||
*
|
||||
* @return 0 on success; nonzero on failure.
|
||||
*/
|
||||
int
|
||||
boot_set_pending(int permanent)
|
||||
{
|
||||
const struct flash_area *fap;
|
||||
struct boot_swap_state state_secondary_slot;
|
||||
uint8_t swap_type;
|
||||
int rc;
|
||||
|
||||
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(0),
|
||||
&state_secondary_slot);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (state_secondary_slot.magic) {
|
||||
case BOOT_MAGIC_GOOD:
|
||||
/* Swap already scheduled. */
|
||||
return 0;
|
||||
|
||||
case BOOT_MAGIC_UNSET:
|
||||
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(0), &fap);
|
||||
if (rc != 0) {
|
||||
rc = BOOT_EFLASH;
|
||||
} else {
|
||||
rc = boot_write_magic(fap);
|
||||
}
|
||||
|
||||
if (rc == 0 && permanent) {
|
||||
rc = boot_write_image_ok(fap);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
if (permanent) {
|
||||
swap_type = BOOT_SWAP_TYPE_PERM;
|
||||
} else {
|
||||
swap_type = BOOT_SWAP_TYPE_TEST;
|
||||
}
|
||||
rc = boot_write_swap_info(fap, swap_type, 0);
|
||||
}
|
||||
|
||||
flash_area_close(fap);
|
||||
return rc;
|
||||
|
||||
case BOOT_MAGIC_BAD:
|
||||
/* The image slot is corrupt. There is no way to recover, so erase the
|
||||
* slot to allow future upgrades.
|
||||
*/
|
||||
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(0), &fap);
|
||||
if (rc != 0) {
|
||||
return BOOT_EFLASH;
|
||||
}
|
||||
|
||||
flash_area_erase(fap, 0, fap->fa_size);
|
||||
flash_area_close(fap);
|
||||
return BOOT_EBADIMAGE;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return BOOT_EBADIMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the image in the primary slot as confirmed. The system will continue
|
||||
* booting into the image in the primary slot until told to boot from a
|
||||
* different slot.
|
||||
*
|
||||
* @return 0 on success; nonzero on failure.
|
||||
*/
|
||||
int
|
||||
boot_set_confirmed(void)
|
||||
{
|
||||
const struct flash_area *fap;
|
||||
struct boot_swap_state state_primary_slot;
|
||||
int rc;
|
||||
|
||||
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(0),
|
||||
&state_primary_slot);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (state_primary_slot.magic) {
|
||||
case BOOT_MAGIC_GOOD:
|
||||
/* Confirm needed; proceed. */
|
||||
break;
|
||||
|
||||
case BOOT_MAGIC_UNSET:
|
||||
/* Already confirmed. */
|
||||
return 0;
|
||||
|
||||
case BOOT_MAGIC_BAD:
|
||||
/* Unexpected state. */
|
||||
return BOOT_EBADVECT;
|
||||
}
|
||||
|
||||
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &fap);
|
||||
if (rc) {
|
||||
rc = BOOT_EFLASH;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (state_primary_slot.copy_done == BOOT_FLAG_UNSET) {
|
||||
/* Swap never completed. This is unexpected. */
|
||||
rc = BOOT_EBADVECT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (state_primary_slot.image_ok != BOOT_FLAG_UNSET) {
|
||||
/* Already confirmed. */
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = boot_write_image_ok(fap);
|
||||
|
||||
done:
|
||||
flash_area_close(fap);
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
if(CONFIG_MCUBOOT_BOOTUTIL_LIB)
|
||||
|
||||
zephyr_interface_library_named(MCUBOOT_BOOTUTIL)
|
||||
|
||||
target_include_directories(MCUBOOT_BOOTUTIL INTERFACE
|
||||
../
|
||||
../include
|
||||
../../zephyr/include
|
||||
)
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_sources(
|
||||
../src/bootutil_public.c
|
||||
)
|
||||
zephyr_library_link_libraries(MCUBOOT_BOOTUTIL)
|
||||
target_link_libraries(MCUBOOT_BOOTUTIL INTERFACE zephyr_interface)
|
||||
endif()
|
|
@ -113,6 +113,9 @@ zephyr_library_sources(
|
|||
${BOOT_DIR}/bootutil/src/fault_injection_hardening.c
|
||||
)
|
||||
|
||||
# library which might be common source code for MCUBoot and an application
|
||||
zephyr_link_libraries(MCUBOOT_BOOTUTIL)
|
||||
|
||||
if(CONFIG_BOOT_FIH_PROFILE_HIGH)
|
||||
zephyr_library_sources(
|
||||
${BOOT_DIR}/bootutil/src/fault_injection_hardening_delay_rng_mbedtls.c
|
||||
|
|
|
@ -14,6 +14,7 @@ config MCUBOOT
|
|||
bool
|
||||
select MPU_ALLOW_FLASH_WRITE if ARM_MPU
|
||||
select USE_DT_CODE_PARTITION if HAS_FLASH_LOAD_OFFSET
|
||||
select MCUBOOT_BOOTUTIL_LIB
|
||||
|
||||
config BOOT_USE_MBEDTLS
|
||||
bool
|
||||
|
@ -573,4 +574,9 @@ config LOG_PROCESS_THREAD
|
|||
config USB_DEVICE_PRODUCT
|
||||
default "MCUBOOT"
|
||||
|
||||
# use MCUboot's own log configuration
|
||||
config MCUBOOT_BOOTUTIL_LIB_OWN_LOG
|
||||
bool
|
||||
default n
|
||||
|
||||
source "Kconfig.zephyr"
|
||||
|
|
|
@ -154,8 +154,14 @@
|
|||
*/
|
||||
#define MCUBOOT_USE_FLASH_AREA_GET_SECTORS
|
||||
|
||||
#ifdef CONFIG_BOOT_MAX_IMG_SECTORS
|
||||
|
||||
#define MCUBOOT_MAX_IMG_SECTORS CONFIG_BOOT_MAX_IMG_SECTORS
|
||||
|
||||
#else
|
||||
#define MCUBOOT_MAX_IMG_SECTORS 128
|
||||
#endif
|
||||
|
||||
#endif /* !__BOOTSIM__ */
|
||||
|
||||
#if CONFIG_BOOT_WATCHDOG_FEED
|
||||
|
|
|
@ -13,9 +13,13 @@
|
|||
* When building for targets running Zephyr, delegate to its native
|
||||
* logging subsystem.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_MCUBOOT
|
||||
#define MCUBOOT_LOG_MODULE_DECLARE(domain) LOG_MODULE_DECLARE(domain, CONFIG_MCUBOOT_LOG_LEVEL)
|
||||
#define MCUBOOT_LOG_MODULE_REGISTER(domain) LOG_MODULE_REGISTER(domain, CONFIG_MCUBOOT_LOG_LEVEL)
|
||||
#else
|
||||
#define MCUBOOT_LOG_MODULE_DECLARE(domain) LOG_MODULE_DECLARE(domain, CONFIG_MCUBOOT_UTIL_LOG_LEVEL)
|
||||
#define MCUBOOT_LOG_MODULE_REGISTER(domain) LOG_MODULE_REGISTER(domain, CONFIG_MCUBOOT_UTIL_LOG_LEVEL)
|
||||
#endif
|
||||
|
||||
#define MCUBOOT_LOG_ERR(...) LOG_ERR(__VA_ARGS__)
|
||||
#define MCUBOOT_LOG_WRN(...) LOG_WRN(__VA_ARGS__)
|
||||
|
|
|
@ -269,6 +269,7 @@ fn main() {
|
|||
conf.file("../../boot/bootutil/src/swap_move.c");
|
||||
conf.file("../../boot/bootutil/src/caps.c");
|
||||
conf.file("../../boot/bootutil/src/bootutil_misc.c");
|
||||
conf.file("../../boot/bootutil/src/bootutil_public.c");
|
||||
conf.file("../../boot/bootutil/src/tlv.c");
|
||||
conf.file("../../boot/bootutil/src/fault_injection_hardening.c");
|
||||
conf.file("csupport/run.c");
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
samples:
|
||||
- boot/zephyr
|
||||
build:
|
||||
cmake: ./boot/bootutil/zephyr
|
||||
|
|
Loading…
Reference in New Issue