Commit e2c97da3 authored by Jamie McCrae's avatar Jamie McCrae Committed by Jamie
Browse files

boot: bootutil: Fix serial recovery issues



Fixes serial recovery issues in various MCUboot operating modes by
moving functions that are needed out from loader to a common file
and adapting them to work in these different modes

Signed-off-by: default avatarJamie McCrae <jamie.mccrae@nordicsemi.no>
parent 2fcfba13
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -89,7 +89,9 @@ fih_ret boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id);
void boot_state_clear(struct boot_loader_state *state);
fih_ret context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);
struct boot_loader_state *boot_get_loader_state(void);
struct image_max_size *boot_get_image_max_sizes(void);
const struct image_max_size *boot_get_max_app_size(void);
void boot_fetch_slot_state_sizes(void);
uint32_t boot_get_state_secondary_offset(struct boot_loader_state *state,
                                         const struct flash_area *fap);

+215 −0
Original line number Diff line number Diff line
@@ -43,11 +43,23 @@
#include "bootutil/enc_key.h"
#endif

#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_SWAP_USING_SCRATCH)
#include "swap_priv.h"
#endif

BOOT_LOG_MODULE_DECLARE(mcuboot);

/* Currently only used by imgmgr */
int boot_current_slot;

#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \
defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
/* Used for holding static buffers in multiple functions to work around issues
 * in older versions of gcc (e.g. 4.8.4)
 */
static struct boot_sector_buffer sector_buffers;
#endif

/**
 * @brief Determine if the data at two memory addresses is equal
 *
@@ -696,3 +708,206 @@ boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool
end:
    return rc;
}

#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \
defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
int
boot_initialize_area(struct boot_loader_state *state, int flash_area)
{
    uint32_t num_sectors = BOOT_MAX_IMG_SECTORS;
    boot_sector_t *out_sectors;
    uint32_t *out_num_sectors;
    int rc;

    num_sectors = BOOT_MAX_IMG_SECTORS;

    if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
        out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
        out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
#if BOOT_NUM_SLOTS > 1
    } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
        out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
        out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
#if MCUBOOT_SWAP_USING_SCRATCH
    } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
        out_sectors = state->scratch.sectors;
        out_num_sectors = &state->scratch.num_sectors;
#endif
#endif
    } else {
        return BOOT_EFLASH;
    }

#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
    rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
#else
    _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed");
    rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors);
#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
    if (rc != 0) {
        return rc;
    }
    *out_num_sectors = num_sectors;
    return 0;
}

static uint32_t
boot_write_sz(struct boot_loader_state *state)
{
    uint32_t elem_sz;
#if MCUBOOT_SWAP_USING_SCRATCH
    uint32_t align;
#endif

    /* Figure out what size to write update status update as.  The size depends
     * on what the minimum write size is for scratch area, active image slot.
     * We need to use the bigger of those 2 values.
     */
    elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
#if MCUBOOT_SWAP_USING_SCRATCH
    align = flash_area_align(BOOT_SCRATCH_AREA(state));
    if (align > elem_sz) {
        elem_sz = align;
    }
#endif

    return elem_sz;
}

int
boot_read_sectors(struct boot_loader_state *state, struct boot_sector_buffer *sectors)
{
    uint8_t image_index;
    int rc;

    if (sectors == NULL) {
        sectors = &sector_buffers;
    }

    image_index = BOOT_CURR_IMG(state);

    BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
        sectors->primary[image_index];
#if BOOT_NUM_SLOTS > 1
    BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
        sectors->secondary[image_index];
#if MCUBOOT_SWAP_USING_SCRATCH
    state->scratch.sectors = sectors->scratch;
#endif
#endif

    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
    if (rc != 0) {
        return BOOT_EFLASH;
    }

#if BOOT_NUM_SLOTS > 1
    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
    if (rc != 0) {
        /* We need to differentiate from the primary image issue */
        return BOOT_EFLASH_SEC;
    }

#if MCUBOOT_SWAP_USING_SCRATCH
    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
    if (rc != 0) {
        return BOOT_EFLASH;
    }
#endif
#endif

    BOOT_WRITE_SZ(state) = boot_write_sz(state);

    return 0;
}
#endif

#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
static int
boot_read_sectors_recovery(struct boot_loader_state *state)
{
    uint8_t image_index;
    int rc;

    image_index = BOOT_CURR_IMG(state);

    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
    if (rc != 0) {
        return BOOT_EFLASH;
    }

    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
    if (rc != 0) {
        /* We need to differentiate from the primary image issue */
        return BOOT_EFLASH_SEC;
    }

    return 0;
}

/**
 * Reads image data to find out the maximum application sizes. Only needs to
 * be called in serial recovery mode, as the state information is unpopulated
 * at that time
 */
void boot_fetch_slot_state_sizes(void)
{
    int rc = -1;
    int image_index;

    rc = boot_open_all_flash_areas(boot_get_loader_state());
    if (rc != 0) {
        BOOT_LOG_DBG("boot_fetch_slot_state_sizes: error %d while opening flash areas", rc);
        goto finish;
    }

    IMAGES_ITER(BOOT_CURR_IMG(boot_get_loader_state())) {
        int max_size = 0;

        image_index = BOOT_CURR_IMG(boot_get_loader_state());

        BOOT_IMG(boot_get_loader_state(), BOOT_PRIMARY_SLOT).sectors =
            sector_buffers.primary[image_index];
#if BOOT_NUM_SLOTS > 1
        BOOT_IMG(boot_get_loader_state(), BOOT_SECONDARY_SLOT).sectors =
            sector_buffers.secondary[image_index];
#if MCUBOOT_SWAP_USING_SCRATCH
        boot_get_loader_state()->scratch.sectors = sector_buffers.scratch;
#endif
#endif

        /* Determine the sector layout of the image slots and scratch area. */
        rc = boot_read_sectors_recovery(boot_get_loader_state());

        if (rc == 0) {
            max_size = app_max_size(boot_get_loader_state());

            if (max_size > 0) {
                boot_get_image_max_sizes()[image_index].calculated = true;
                boot_get_image_max_sizes()[image_index].max_size = max_size;
            }
        }
    }

finish:
    boot_close_all_flash_areas(boot_get_loader_state());
    memset(boot_get_loader_state(), 0, sizeof(struct boot_loader_state));
}
#endif

/**
 * Clears the boot state, so that previous operations have no effect on new
 * ones.
 *
 * @param state                 The state that should be cleared. If the value
 *                              is NULL, the default bootloader state will be
 *                              cleared.
 */
void boot_state_clear(struct boot_loader_state *state)
{
    if (state != NULL) {
        memset(state, 0, sizeof(struct boot_loader_state));
    } else {
        memset(boot_get_loader_state(), 0, sizeof(struct boot_loader_state));
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -92,6 +92,12 @@ struct flash_area;
#define BOOT_STATUS_OP_SWAP     2
#endif

#if (BOOT_IMAGE_NUMBER > 1)
#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
#else
#define IMAGES_ITER(x)
#endif

/*
 * Maintain state of copy progress.
 */
+8 −212
Original line number Diff line number Diff line
@@ -68,20 +68,6 @@ static struct boot_loader_state boot_data;
static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0};
#endif

#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \
defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
/* Used for holding static buffers in multiple functions to work around issues
 * in older versions of gcc (e.g. 4.8.4)
 */
static struct boot_sector_buffer sector_buffers;
#endif

#if (BOOT_IMAGE_NUMBER > 1)
#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
#else
#define IMAGES_ITER(x)
#endif

/*
 * This macro allows some control on the allocation of local variables.
 * When running natively on a target, we don't want to allocated huge
@@ -114,6 +100,14 @@ struct boot_loader_state *boot_get_loader_state(void)
    return &boot_data;
}

#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
struct image_max_size *boot_get_image_max_sizes(void)
{
    return image_max_sizes;
}
#endif


static int
boot_read_image_headers(struct boot_loader_state *state, bool require_all,
        struct boot_status *bs)
@@ -296,72 +290,6 @@ boot_version_cmp(const struct image_version *ver1,
}
#endif

#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \
defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
static int
boot_initialize_area(struct boot_loader_state *state, int flash_area)
{
    uint32_t num_sectors = BOOT_MAX_IMG_SECTORS;
    boot_sector_t *out_sectors;
    uint32_t *out_num_sectors;
    int rc;

    num_sectors = BOOT_MAX_IMG_SECTORS;

    if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
        out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
        out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
    } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
        out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
        out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
#if MCUBOOT_SWAP_USING_SCRATCH
    } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
        out_sectors = state->scratch.sectors;
        out_num_sectors = &state->scratch.num_sectors;
#endif
    } else {
        return BOOT_EFLASH;
    }

#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
    rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
#else
    _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed");
    rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors);
#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
    if (rc != 0) {
        return rc;
    }
    *out_num_sectors = num_sectors;
    return 0;
}
#endif

#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
static int
boot_read_sectors_recovery(struct boot_loader_state *state)
{
    uint8_t image_index;
    int rc;

    image_index = BOOT_CURR_IMG(state);

    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
    if (rc != 0) {
        return BOOT_EFLASH;
    }

    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
    if (rc != 0) {
        /* We need to differentiate from the primary image issue */
        return BOOT_EFLASH_SEC;
    }

    return 0;
}
#endif


#if (BOOT_IMAGE_NUMBER > 1)

static int
@@ -589,72 +517,6 @@ done:
#if !defined(MCUBOOT_DIRECT_XIP)

#if !defined(MCUBOOT_RAM_LOAD)
static uint32_t
boot_write_sz(struct boot_loader_state *state)
{
    uint32_t elem_sz;
#if MCUBOOT_SWAP_USING_SCRATCH
    uint32_t align;
#endif

    /* Figure out what size to write update status update as.  The size depends
     * on what the minimum write size is for scratch area, active image slot.
     * We need to use the bigger of those 2 values.
     */
    elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
#if MCUBOOT_SWAP_USING_SCRATCH
    align = flash_area_align(BOOT_SCRATCH_AREA(state));
    if (align > elem_sz) {
        elem_sz = align;
    }
#endif

    return elem_sz;
}

int
boot_read_sectors(struct boot_loader_state *state, struct boot_sector_buffer *sectors)
{
    uint8_t image_index;
    int rc;

    if (sectors == NULL) {
        sectors = &sector_buffers;
    }

    image_index = BOOT_CURR_IMG(state);

    BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
        sectors->primary[image_index];
    BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
        sectors->secondary[image_index];
#if MCUBOOT_SWAP_USING_SCRATCH
    state->scratch.sectors = sectors->scratch;
#endif

    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
    if (rc != 0) {
        return BOOT_EFLASH;
    }

    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
    if (rc != 0) {
        /* We need to differentiate from the primary image issue */
        return BOOT_EFLASH_SEC;
    }

#if MCUBOOT_SWAP_USING_SCRATCH
    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
    if (rc != 0) {
        return BOOT_EFLASH;
    }
#endif

    BOOT_WRITE_SZ(state) = boot_write_sz(state);

    return 0;
}

void
boot_status_reset(struct boot_status *bs)
{
@@ -3077,23 +2939,6 @@ boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id)
    FIH_RET(fih_rc);
}

/**
 * Clears the boot state, so that previous operations have no effect on new
 * ones.
 *
 * @param state                 The state that should be cleared. If the value
 *                              is NULL, the default bootloader state will be
 *                              cleared.
 */
void boot_state_clear(struct boot_loader_state *state)
{
    if (state != NULL) {
        memset(state, 0, sizeof(struct boot_loader_state));
    } else {
        memset(&boot_data, 0, sizeof(struct boot_loader_state));
    }
}

int
boot_open_all_flash_areas(struct boot_loader_state *state)
{
@@ -3166,55 +3011,6 @@ boot_close_all_flash_areas(struct boot_loader_state *state)
    }
}

#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
/**
 * Reads image data to find out the maximum application sizes. Only needs to
 * be called in serial recovery mode, as the state information is unpopulated
 * at that time
 */
static void boot_fetch_slot_state_sizes(void)
{
    int rc = -1;
    int image_index;

    rc = boot_open_all_flash_areas(&boot_data);
    if (rc != 0) {
        BOOT_LOG_DBG("boot_fetch_slot_state_sizes: error %d while opening flash areas", rc);
        goto finish;
    }

    IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
        int max_size = 0;

        image_index = BOOT_CURR_IMG(&boot_data);

        BOOT_IMG(&boot_data, BOOT_PRIMARY_SLOT).sectors =
            sector_buffers.primary[image_index];
        BOOT_IMG(&boot_data, BOOT_SECONDARY_SLOT).sectors =
            sector_buffers.secondary[image_index];
#if MCUBOOT_SWAP_USING_SCRATCH
        boot_data.scratch.sectors = sector_buffers.scratch;
#endif

        /* Determine the sector layout of the image slots and scratch area. */
        rc = boot_read_sectors_recovery(&boot_data);

        if (rc == 0) {
            max_size = app_max_size(&boot_data);

            if (max_size > 0) {
                image_max_sizes[image_index].calculated = true;
                image_max_sizes[image_index].max_size = max_size;
            }
        }
    }

finish:
    boot_close_all_flash_areas(&boot_data);
    memset(&boot_data, 0x00, sizeof(boot_data));
}
#endif

#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING)
/**
 * Fetches the maximum allowed size of the image
+84 −16
Original line number Diff line number Diff line
@@ -18,15 +18,23 @@

BOOT_LOG_MODULE_DECLARE(mcuboot);

/* Variables passed outside of unit via poiters. */
static const struct flash_area *_fa_p;
/* Variables passed outside of unit via pointers. */
static struct image_header _hdr = { 0 };
static struct boot_loader_state boot_data;
static struct boot_loader_state state;

struct boot_loader_state *boot_get_loader_state(void)
{
    return &boot_data;
    return &state;
}

#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0};

struct image_max_size *boot_get_image_max_sizes(void)
{
    return image_max_sizes;
}
#endif

#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) || defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
/**
@@ -103,6 +111,69 @@ boot_image_validate_once(const struct flash_area *fa_p,
}
#endif

int
boot_open_all_flash_areas(struct boot_loader_state *state)
{
    int rc;

    rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
    assert(rc == 0);

    return rc;
}

void
boot_close_all_flash_areas(struct boot_loader_state *state)
{
    flash_area_close(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
}

#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
static int app_max_sectors(struct boot_loader_state *state)
{
    uint32_t sz = 0;
    uint32_t sector_sz;
    uint32_t trailer_sz;
    uint32_t trailer_sectors = 0;

    sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
    trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));

    while (1) {
        sz += sector_sz;
        ++trailer_sectors;

        if  (sz >= trailer_sz) {
            break;
        }
    }

    return boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - trailer_sectors;
}

int app_max_size(struct boot_loader_state *state)
{
    uint32_t sector_sz;

    sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);

    return app_max_sectors(state) * sector_sz;
}

/**
 * Fetches the maximum allowed size of the image
 */
const struct image_max_size *boot_get_max_app_size(void)
{
    if (image_max_sizes[0].calculated == false) {
        /* Information not available, need to fetch it */
        boot_fetch_slot_state_sizes();
    }

    return image_max_sizes;
}
#endif

/**
 * Gather information on image and prepare for booting.
 *
@@ -118,16 +189,13 @@ boot_go(struct boot_rsp *rsp)

    BOOT_LOG_DBG("boot_go: Single loader");

    rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &_fa_p);
    assert(rc == 0);
    rc = boot_open_all_flash_areas(&state);

    rc = boot_image_load_header(_fa_p, &_hdr);
    rc = boot_image_load_header(BOOT_IMG_AREA(&state, BOOT_PRIMARY_SLOT), &_hdr);
    if (rc != 0)
        goto out;

#ifdef MCUBOOT_RAM_LOAD
        static struct boot_loader_state state;
        BOOT_IMG_AREA(&state, 0) = _fa_p;
        state.imgs[0][0].hdr = _hdr;

        rc = boot_load_image_to_sram(&state);
@@ -136,7 +204,7 @@ boot_go(struct boot_rsp *rsp)
#endif

#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
    FIH_CALL(boot_image_validate, fih_rc, _fa_p, &_hdr);
    FIH_CALL(boot_image_validate, fih_rc, BOOT_IMG_AREA(&state, BOOT_PRIMARY_SLOT), &_hdr);
    if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
#ifdef MCUBOOT_RAM_LOAD
        boot_remove_image_from_sram(&state);
@@ -144,7 +212,7 @@ boot_go(struct boot_rsp *rsp)
        goto out;
    }
#elif defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
    FIH_CALL(boot_image_validate_once, fih_rc, _fa_p, &_hdr);
    FIH_CALL(boot_image_validate_once, fih_rc, BOOT_IMG_AREA(&state, BOOT_PRIMARY_SLOT), &_hdr);
    if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
#ifdef MCUBOOT_RAM_LOAD
        boot_remove_image_from_sram(&state);
@@ -156,7 +224,7 @@ boot_go(struct boot_rsp *rsp)
#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */

#ifdef MCUBOOT_MEASURED_BOOT
    rc = boot_save_boot_status(0, &_hdr, _fa_p);
    rc = boot_save_boot_status(0, &_hdr, BOOT_IMG_AREA(&state, BOOT_PRIMARY_SLOT));
    if (rc != 0) {
        BOOT_LOG_ERR("Failed to add image data to shared area");
        return rc;
@@ -164,19 +232,19 @@ boot_go(struct boot_rsp *rsp)
#endif /* MCUBOOT_MEASURED_BOOT */

#ifdef MCUBOOT_DATA_SHARING
    rc = boot_save_shared_data(&_hdr, _fa_p, 0, NULL);
    rc = boot_save_shared_data(&_hdr, BOOT_IMG_AREA(&state, BOOT_PRIMARY_SLOT), 0, NULL);
    if (rc != 0) {
        BOOT_LOG_ERR("Failed to add data to shared memory area.");
        return rc;
    }
#endif /* MCUBOOT_DATA_SHARING */

    rsp->br_flash_dev_id = flash_area_get_device_id(_fa_p);
    rsp->br_image_off = flash_area_get_off(_fa_p);
    rsp->br_flash_dev_id = flash_area_get_device_id(BOOT_IMG_AREA(&state, BOOT_PRIMARY_SLOT));
    rsp->br_image_off = flash_area_get_off(BOOT_IMG_AREA(&state, BOOT_PRIMARY_SLOT));
    rsp->br_hdr = &_hdr;

out:
    flash_area_close(_fa_p);
    boot_close_all_flash_areas(&state);

    FIH_RET(fih_rc);
}