2017-07-04 17:54:11 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2017 Nordic Semiconductor ASA
|
|
|
|
* Copyright (c) 2016-2017 Linaro Limited
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2022-05-06 17:12:04 +08:00
|
|
|
#include <zephyr/drivers/flash.h>
|
|
|
|
#include <zephyr/storage/flash_map.h>
|
includes: prefer <zephyr/kernel.h> over <zephyr/zephyr.h>
As of today <zephyr/zephyr.h> is 100% equivalent to <zephyr/kernel.h>.
This patch proposes to then include <zephyr/kernel.h> instead of
<zephyr/zephyr.h> since it is more clear that you are including the
Kernel APIs and (probably) nothing else. <zephyr/zephyr.h> sounds like a
catch-all header that may be confusing. Most applications need to
include a bunch of other things to compile, e.g. driver headers or
subsystem headers like BT, logging, etc.
The idea of a catch-all header in Zephyr is probably not feasible
anyway. Reason is that Zephyr is not a library, like it could be for
example `libpython`. Zephyr provides many utilities nowadays: a kernel,
drivers, subsystems, etc and things will likely grow. A catch-all header
would be massive, difficult to keep up-to-date. It is also likely that
an application will only build a small subset. Note that subsystem-level
headers may use a catch-all approach to make things easier, though.
NOTE: This patch is **NOT** removing the header, just removing its usage
in-tree. I'd advocate for its deprecation (add a #warning on it), but I
understand many people will have concerns.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-08-25 15:58:46 +08:00
|
|
|
#include <zephyr/kernel.h>
|
2022-05-06 17:12:04 +08:00
|
|
|
#include <zephyr/init.h>
|
2017-07-04 17:54:11 +08:00
|
|
|
|
2022-05-06 17:12:04 +08:00
|
|
|
#include <zephyr/sys/__assert.h>
|
|
|
|
#include <zephyr/sys/byteorder.h>
|
2020-11-13 00:59:59 +08:00
|
|
|
|
|
|
|
#include "bootutil/bootutil_public.h"
|
2022-05-06 17:12:04 +08:00
|
|
|
#include <zephyr/dfu/mcuboot.h>
|
2017-07-04 17:54:11 +08:00
|
|
|
|
2020-10-31 02:26:14 +08:00
|
|
|
#include "mcuboot_priv.h"
|
|
|
|
|
2017-07-04 17:54:11 +08:00
|
|
|
/*
|
2018-02-01 14:29:56 +08:00
|
|
|
* Helpers for image headers and trailers, as defined by mcuboot.
|
2017-07-04 17:54:11 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2018-02-01 14:29:56 +08:00
|
|
|
* Strict defines: the definitions in the following block contain
|
|
|
|
* values which are MCUboot implementation requirements.
|
2017-07-04 17:54:11 +08:00
|
|
|
*/
|
2018-02-01 14:29:56 +08:00
|
|
|
|
|
|
|
/* Header: */
|
|
|
|
#define BOOT_HEADER_MAGIC_V1 0x96f3b83d
|
|
|
|
#define BOOT_HEADER_SIZE_V1 32
|
|
|
|
|
2023-09-28 23:07:01 +08:00
|
|
|
/* Get active partition. zephyr,code-partition chosen node must be defined */
|
|
|
|
#define ACTIVE_SLOT_FLASH_AREA_ID DT_FIXED_PARTITION_ID(DT_CHOSEN(zephyr_code_partition))
|
|
|
|
|
2018-02-01 14:29:56 +08:00
|
|
|
/*
|
|
|
|
* Raw (on-flash) representation of the v1 image header.
|
|
|
|
*/
|
|
|
|
struct mcuboot_v1_raw_header {
|
2020-05-28 00:26:57 +08:00
|
|
|
uint32_t header_magic;
|
|
|
|
uint32_t image_load_address;
|
|
|
|
uint16_t header_size;
|
|
|
|
uint16_t pad;
|
|
|
|
uint32_t image_size;
|
|
|
|
uint32_t image_flags;
|
2018-02-01 14:29:56 +08:00
|
|
|
struct {
|
2020-05-28 00:26:57 +08:00
|
|
|
uint8_t major;
|
|
|
|
uint8_t minor;
|
|
|
|
uint16_t revision;
|
|
|
|
uint32_t build_num;
|
2018-02-01 14:29:56 +08:00
|
|
|
} version;
|
2020-05-28 00:26:57 +08:00
|
|
|
uint32_t pad2;
|
2018-02-01 14:29:56 +08:00
|
|
|
} __packed;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End of strict defines
|
|
|
|
*/
|
2017-07-04 17:54:11 +08:00
|
|
|
|
2020-05-28 00:26:57 +08:00
|
|
|
static int boot_read_v1_header(uint8_t area_id,
|
2018-02-01 14:29:56 +08:00
|
|
|
struct mcuboot_v1_raw_header *v1_raw)
|
|
|
|
{
|
2018-08-01 14:50:48 +08:00
|
|
|
const struct flash_area *fa;
|
2018-02-01 14:29:56 +08:00
|
|
|
int rc;
|
|
|
|
|
2018-08-01 14:50:48 +08:00
|
|
|
rc = flash_area_open(area_id, &fa);
|
|
|
|
if (rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-02-01 14:29:56 +08:00
|
|
|
/*
|
|
|
|
* Read and sanity-check the raw header.
|
|
|
|
*/
|
2018-08-01 14:50:48 +08:00
|
|
|
rc = flash_area_read(fa, 0, v1_raw, sizeof(*v1_raw));
|
|
|
|
flash_area_close(fa);
|
2018-02-01 14:29:56 +08:00
|
|
|
if (rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
v1_raw->header_magic = sys_le32_to_cpu(v1_raw->header_magic);
|
|
|
|
v1_raw->image_load_address =
|
|
|
|
sys_le32_to_cpu(v1_raw->image_load_address);
|
|
|
|
v1_raw->header_size = sys_le16_to_cpu(v1_raw->header_size);
|
|
|
|
v1_raw->image_size = sys_le32_to_cpu(v1_raw->image_size);
|
|
|
|
v1_raw->image_flags = sys_le32_to_cpu(v1_raw->image_flags);
|
|
|
|
v1_raw->version.revision =
|
|
|
|
sys_le16_to_cpu(v1_raw->version.revision);
|
|
|
|
v1_raw->version.build_num =
|
|
|
|
sys_le32_to_cpu(v1_raw->version.build_num);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sanity checks.
|
|
|
|
*
|
|
|
|
* Larger values in header_size than BOOT_HEADER_SIZE_V1 are
|
|
|
|
* possible, e.g. if Zephyr was linked with
|
2020-02-10 15:37:24 +08:00
|
|
|
* CONFIG_ROM_START_OFFSET > BOOT_HEADER_SIZE_V1.
|
2018-02-01 14:29:56 +08:00
|
|
|
*/
|
|
|
|
if ((v1_raw->header_magic != BOOT_HEADER_MAGIC_V1) ||
|
|
|
|
(v1_raw->header_size < BOOT_HEADER_SIZE_V1)) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-28 00:26:57 +08:00
|
|
|
int boot_read_bank_header(uint8_t area_id,
|
2018-02-01 14:29:56 +08:00
|
|
|
struct mcuboot_img_header *header,
|
|
|
|
size_t header_size)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct mcuboot_v1_raw_header v1_raw;
|
|
|
|
struct mcuboot_img_sem_ver *sem_ver;
|
2020-05-28 00:26:57 +08:00
|
|
|
size_t v1_min_size = (sizeof(uint32_t) +
|
2018-02-01 14:29:56 +08:00
|
|
|
sizeof(struct mcuboot_img_header_v1));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only version 1 image headers are supported.
|
|
|
|
*/
|
|
|
|
if (header_size < v1_min_size) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2018-08-01 14:50:48 +08:00
|
|
|
rc = boot_read_v1_header(area_id, &v1_raw);
|
2018-02-01 14:29:56 +08:00
|
|
|
if (rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy just the fields we care about into the return parameter.
|
|
|
|
*
|
|
|
|
* - header_magic: skip (only used to check format)
|
|
|
|
* - image_load_address: skip (only matters for PIC code)
|
|
|
|
* - header_size: skip (only used to check format)
|
|
|
|
* - image_size: include
|
|
|
|
* - image_flags: skip (all unsupported or not relevant)
|
|
|
|
* - version: include
|
|
|
|
*/
|
2019-03-27 09:57:45 +08:00
|
|
|
header->mcuboot_version = 1U;
|
2018-02-01 14:29:56 +08:00
|
|
|
header->h.v1.image_size = v1_raw.image_size;
|
|
|
|
sem_ver = &header->h.v1.sem_ver;
|
|
|
|
sem_ver->major = v1_raw.version.major;
|
|
|
|
sem_ver->minor = v1_raw.version.minor;
|
|
|
|
sem_ver->revision = v1_raw.version.revision;
|
|
|
|
sem_ver->build_num = v1_raw.version.build_num;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-08-19 07:01:24 +08:00
|
|
|
int mcuboot_swap_type_multi(int image_index)
|
|
|
|
{
|
|
|
|
return boot_swap_type_multi(image_index);
|
|
|
|
}
|
|
|
|
|
2020-11-13 00:59:59 +08:00
|
|
|
int mcuboot_swap_type(void)
|
2018-01-26 10:31:11 +08:00
|
|
|
{
|
2020-11-13 00:59:59 +08:00
|
|
|
#ifdef FLASH_AREA_IMAGE_SECONDARY
|
|
|
|
return boot_swap_type();
|
2019-06-13 20:51:24 +08:00
|
|
|
#else
|
2020-11-13 00:59:59 +08:00
|
|
|
return BOOT_SWAP_TYPE_NONE;
|
2019-06-13 20:51:24 +08:00
|
|
|
#endif
|
2018-08-01 14:50:48 +08:00
|
|
|
|
2018-01-26 10:31:11 +08:00
|
|
|
}
|
2018-01-18 09:40:36 +08:00
|
|
|
|
2020-11-13 00:59:59 +08:00
|
|
|
int boot_request_upgrade(int permanent)
|
2018-01-18 09:40:36 +08:00
|
|
|
{
|
2020-09-18 19:20:06 +08:00
|
|
|
#ifdef FLASH_AREA_IMAGE_SECONDARY
|
2018-01-18 09:40:36 +08:00
|
|
|
int rc;
|
|
|
|
|
2020-11-13 00:59:59 +08:00
|
|
|
rc = boot_set_pending(permanent);
|
2019-06-01 01:01:13 +08:00
|
|
|
if (rc) {
|
2020-11-13 00:59:59 +08:00
|
|
|
return -EFAULT;
|
2018-01-18 09:40:36 +08:00
|
|
|
}
|
2020-11-13 00:59:59 +08:00
|
|
|
#endif /* FLASH_AREA_IMAGE_SECONDARY */
|
|
|
|
return 0;
|
2018-01-18 09:40:36 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 19:36:43 +08:00
|
|
|
int boot_request_upgrade_multi(int image_index, int permanent)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = boot_set_pending_multi(image_index, permanent);
|
|
|
|
if (rc) {
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-11-13 00:59:59 +08:00
|
|
|
bool boot_is_img_confirmed(void)
|
2017-07-04 17:54:11 +08:00
|
|
|
{
|
2022-10-28 18:08:16 +08:00
|
|
|
struct boot_swap_state state;
|
2020-11-13 00:59:59 +08:00
|
|
|
const struct flash_area *fa;
|
2017-07-04 17:54:11 +08:00
|
|
|
int rc;
|
|
|
|
|
2020-11-13 00:59:59 +08:00
|
|
|
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fa);
|
2019-06-01 01:01:13 +08:00
|
|
|
if (rc) {
|
2020-11-13 00:59:59 +08:00
|
|
|
return false;
|
2019-06-01 01:01:13 +08:00
|
|
|
}
|
|
|
|
|
2022-10-28 18:08:16 +08:00
|
|
|
rc = boot_read_swap_state(fa, &state);
|
|
|
|
if (rc != 0) {
|
2020-11-13 00:59:59 +08:00
|
|
|
return false;
|
2017-07-04 17:54:11 +08:00
|
|
|
}
|
|
|
|
|
2022-10-28 18:08:16 +08:00
|
|
|
if (state.magic == BOOT_MAGIC_UNSET) {
|
|
|
|
/* This is initial/preprogramed image.
|
|
|
|
* Such image can neither be reverted nor physically confirmed.
|
|
|
|
* Treat this image as confirmed which ensures consistency
|
|
|
|
* with `boot_write_img_confirmed...()` procedures.
|
|
|
|
*/
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return state.image_ok == BOOT_FLAG_SET;
|
2018-02-01 07:30:46 +08:00
|
|
|
}
|
|
|
|
|
2017-07-04 17:54:11 +08:00
|
|
|
int boot_write_img_confirmed(void)
|
|
|
|
{
|
2023-09-28 23:07:01 +08:00
|
|
|
const struct flash_area *fa;
|
|
|
|
int rc = 0;
|
2017-07-04 17:54:11 +08:00
|
|
|
|
2023-09-28 23:07:01 +08:00
|
|
|
if (flash_area_open(ACTIVE_SLOT_FLASH_AREA_ID, &fa) != 0) {
|
2020-11-13 00:59:59 +08:00
|
|
|
return -EIO;
|
2017-07-04 17:54:11 +08:00
|
|
|
}
|
|
|
|
|
2023-09-28 23:07:01 +08:00
|
|
|
rc = boot_set_next(fa, true, true);
|
|
|
|
|
|
|
|
flash_area_close(fa);
|
|
|
|
|
|
|
|
return rc;
|
2017-07-04 17:54:11 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 19:36:43 +08:00
|
|
|
int boot_write_img_confirmed_multi(int image_index)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = boot_set_confirmed_multi(image_index);
|
|
|
|
if (rc) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-28 00:26:57 +08:00
|
|
|
int boot_erase_img_bank(uint8_t area_id)
|
2017-07-04 17:54:11 +08:00
|
|
|
{
|
2018-08-01 14:50:48 +08:00
|
|
|
const struct flash_area *fa;
|
2017-07-04 17:54:11 +08:00
|
|
|
int rc;
|
|
|
|
|
2018-08-01 14:50:48 +08:00
|
|
|
rc = flash_area_open(area_id, &fa);
|
2017-07-04 17:54:11 +08:00
|
|
|
if (rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2024-03-10 06:49:32 +08:00
|
|
|
rc = flash_area_flatten(fa, 0, fa->fa_size);
|
2017-07-04 17:54:11 +08:00
|
|
|
|
2018-08-01 14:50:48 +08:00
|
|
|
flash_area_close(fa);
|
2017-07-04 17:54:11 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2022-12-08 19:35:50 +08:00
|
|
|
|
|
|
|
ssize_t boot_get_trailer_status_offset(size_t area_size)
|
|
|
|
{
|
|
|
|
return (ssize_t)area_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t boot_get_area_trailer_status_offset(uint8_t area_id)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
const struct flash_area *fa;
|
|
|
|
ssize_t offset;
|
|
|
|
|
|
|
|
rc = flash_area_open(area_id, &fa);
|
|
|
|
if (rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset = boot_get_trailer_status_offset(fa->fa_size);
|
|
|
|
|
|
|
|
flash_area_close(fa);
|
|
|
|
|
|
|
|
if (offset < 0) {
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|