Commit 0c721da7 authored by Ederson de Souza's avatar Ederson de Souza Committed by Jamie
Browse files

boot/bootutil: Split RAM load code to its own file



RAM loading code is currently under bootutil/loader.c, and it's not
accessible for different loaders, such as the single loaders. Future
patches will make use of the RAM loading code outside the
bootutil/loader.c context, and this patch prepares for that by making it
standalone on boot/bootutil/src/ram_load.c

Signed-off-by: default avatarEderson de Souza <ederson.desouza@intel.com>
Signed-off-by: default avatarTom Burdick <thomas.burdick@intel.com>
(cherry picked from commit 9f1e573e)
Signed-off-by: default avatarJamie McCrae <jamie.mccrae@nordicsemi.no>
parent f74b77cf
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -33,3 +33,9 @@ target_sources(bootutil
        src/swap_scratch.c
        src/tlv.c
)
if(CONFIG_BOOT_RAM_LOAD)
    target_sources(bootutil
        PRIVATE
            src/ram_load.c
    )
endif()
+3 −0
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@ pkg.ign_files.BOOTUTIL_SINGLE_APPLICATION_SLOT:
    - "loader.c"
    - "swap_scratch.c"

pkg.ign_files:
    - "ram_load.c"

pkg.deps.BOOTUTIL_USE_MBED_TLS:
    - "@apache-mynewt-core/crypto/mbedtls"

+65 −0
Original line number Diff line number Diff line
@@ -355,3 +355,68 @@ uint32_t bootutil_max_image_size(const struct flash_area *fap)
    return boot_swap_info_off(fap);
#endif
}

/*
 * Compute the total size of the given image.  Includes the size of
 * the TLVs.
 */
#if !defined(MCUBOOT_DIRECT_XIP) && \
    (!defined(MCUBOOT_OVERWRITE_ONLY) || \
    defined(MCUBOOT_OVERWRITE_ONLY_FAST))
int
boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
{
    const struct flash_area *fap;
    struct image_tlv_info info;
    uint32_t off;
    uint32_t protect_tlv_size;
    int area_id;
    int rc;

#if (BOOT_IMAGE_NUMBER == 1)
    (void)state;
#endif

    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
    rc = flash_area_open(area_id, &fap);
    if (rc != 0) {
        rc = BOOT_EFLASH;
        goto done;
    }

    off = BOOT_TLV_OFF(boot_img_hdr(state, slot));

    if (flash_area_read(fap, off, &info, sizeof(info))) {
        rc = BOOT_EFLASH;
        goto done;
    }

    protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
    if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
        if (protect_tlv_size != info.it_tlv_tot) {
            rc = BOOT_EBADIMAGE;
            goto done;
        }

        if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
            rc = BOOT_EFLASH;
            goto done;
        }
    } else if (protect_tlv_size != 0) {
        rc = BOOT_EBADIMAGE;
        goto done;
    }

    if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
        rc = BOOT_EBADIMAGE;
        goto done;
    }

    *size = off + protect_tlv_size + info.it_tlv_tot;
    rc = 0;

done:
    flash_area_close(fap);
    return rc;
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */
+11 −0
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ struct flash_area;

#define BOOT_TMPBUF_SZ  256

#define NO_ACTIVE_SLOT UINT32_MAX

/** Number of image slots in flash; currently limited to two. */
#define BOOT_NUM_SLOTS                  2

@@ -467,15 +469,24 @@ struct bootsim_ram_info *bootsim_get_ram_info(void);
#define LOAD_IMAGE_DATA(hdr, fap, start, output, size)       \
    (memcpy((output),(void*)(IMAGE_RAM_BASE + (hdr)->ih_load_addr + (start)), \
    (size)), 0)

int boot_load_image_to_sram(struct boot_loader_state *state);
int boot_remove_image_from_sram(struct boot_loader_state *state);
int boot_remove_image_from_flash(struct boot_loader_state *state,
                                 uint32_t slot);
#else
#define IMAGE_RAM_BASE ((uintptr_t)0)

#define LOAD_IMAGE_DATA(hdr, fap, start, output, size)       \
    (flash_area_read((fap), (start), (output), (size)))

#endif /* MCUBOOT_RAM_LOAD */

uint32_t bootutil_max_image_size(const struct flash_area *fap);

int boot_read_image_size(struct boot_loader_state *state, int slot,
                         uint32_t *size);

#ifdef __cplusplus
}
#endif
+0 −469
Original line number Diff line number Diff line
@@ -110,8 +110,6 @@ static struct sector_buffer_t sector_buffers;
#define BUF_SZ 1024
#endif

#define NO_ACTIVE_SLOT UINT32_MAX

static int
boot_read_image_headers(struct boot_loader_state *state, bool require_all,
        struct boot_status *bs)
@@ -482,11 +480,6 @@ boot_verify_dependencies(struct boot_loader_state *state)
}
#else

#if defined MCUBOOT_RAM_LOAD
static inline int
boot_remove_image_from_sram(struct boot_loader_state *state);
#endif

/**
 * Checks the dependency of all the active slots. If an image found with
 * invalid or not satisfied dependencies the image is removed from SRAM (in
@@ -600,68 +593,6 @@ done:
#endif /* (BOOT_IMAGE_NUMBER > 1) */

#if !defined(MCUBOOT_DIRECT_XIP)
/*
 * Compute the total size of the given image.  Includes the size of
 * the TLVs.
 */
#if !defined(MCUBOOT_OVERWRITE_ONLY) ||  defined(MCUBOOT_OVERWRITE_ONLY_FAST)
static int
boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
{
    const struct flash_area *fap;
    struct image_tlv_info info;
    uint32_t off;
    uint32_t protect_tlv_size;
    int area_id;
    int rc;

#if (BOOT_IMAGE_NUMBER == 1)
    (void)state;
#endif

    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
    rc = flash_area_open(area_id, &fap);
    if (rc != 0) {
        rc = BOOT_EFLASH;
        goto done;
    }

    off = BOOT_TLV_OFF(boot_img_hdr(state, slot));

    if (flash_area_read(fap, off, &info, sizeof(info))) {
        rc = BOOT_EFLASH;
        goto done;
    }

    protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
    if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
        if (protect_tlv_size != info.it_tlv_tot) {
            rc = BOOT_EBADIMAGE;
            goto done;
        }

        if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
            rc = BOOT_EFLASH;
            goto done;
        }
    } else if (protect_tlv_size != 0) {
        rc = BOOT_EBADIMAGE;
        goto done;
    }

    if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
        rc = BOOT_EBADIMAGE;
        goto done;
    }

    *size = off + protect_tlv_size + info.it_tlv_tot;
    rc = 0;

done:
    flash_area_close(fap);
    return rc;
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */

#if !defined(MCUBOOT_RAM_LOAD)
static uint32_t
@@ -2764,406 +2695,6 @@ boot_select_or_erase(struct boot_loader_state *state)
}
#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */

#ifdef MCUBOOT_RAM_LOAD

#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS
#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE)
#error "Platform MUST define executable RAM bounds in case of RAM_LOAD"
#endif
#endif

/**
 * Verifies that the active slot of the current image can be loaded within the
 * predefined bounds that are allowed to be used by executable images.
 *
 * @param  state        Boot loader status information.
 *
 * @return              0 on success; nonzero on failure.
 */
static int
boot_verify_ram_load_address(struct boot_loader_state *state)
{
    uint32_t img_dst;
    uint32_t img_sz;
    uint32_t img_end_addr;
    uint32_t exec_ram_start;
    uint32_t exec_ram_size;

    (void)state;

#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
    int      rc;

    rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start,
                                      &exec_ram_size);
    if (rc != 0) {
        return BOOT_EBADSTATUS;
    }
#else
    exec_ram_start = IMAGE_EXECUTABLE_RAM_START;
    exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE;
#endif

    img_dst = state->slot_usage[BOOT_CURR_IMG(state)].img_dst;
    img_sz = state->slot_usage[BOOT_CURR_IMG(state)].img_sz;

    if (img_dst < exec_ram_start) {
        return BOOT_EBADIMAGE;
    }

    if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
        return BOOT_EBADIMAGE;
    }

    if (img_end_addr > (exec_ram_start + exec_ram_size)) {
        return BOOT_EBADIMAGE;
    }

    return 0;
}

#ifdef MCUBOOT_ENC_IMAGES

/**
 * Copies and decrypts an image from a slot in the flash to an SRAM address.
 *
 * @param  state    Boot loader status information.
 * @param  slot     The flash slot of the image to be copied to SRAM.
 * @param  hdr      The image header.
 * @param  src_sz   Size of the image.
 * @param  img_dst  Pointer to the address at which the image needs to be
 *                  copied to SRAM.
 *
 * @return          0 on success; nonzero on failure.
 */
static int
boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state,
                                    uint32_t slot, struct image_header *hdr,
                                    uint32_t src_sz, uint32_t img_dst)
{
    /* The flow for the decryption and copy of the image is as follows :
     * 1. The whole image is copied to the RAM (header + payload + TLV).
     * 2. The encryption key is loaded from the TLV in flash.
     * 3. The image is then decrypted chunk by chunk in RAM (1 chunk
     * is 1024 bytes). Only the payload section is decrypted.
     * 4. The image is authenticated in RAM.
     */
    const struct flash_area *fap_src = NULL;
    struct boot_status bs;
    uint32_t blk_off;
    uint32_t tlv_off;
    uint32_t blk_sz;
    uint32_t bytes_copied = hdr->ih_hdr_size;
    uint32_t chunk_sz;
    uint32_t max_sz = 1024;
    uint16_t idx;
    uint8_t * cur_dst;
    int area_id;
    int rc;
    uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst);

    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
    rc = flash_area_open(area_id, &fap_src);
    if (rc != 0){
        return BOOT_EFLASH;
    }

    tlv_off = BOOT_TLV_OFF(hdr);

    /* Copying the whole image in RAM */
    rc = flash_area_read(fap_src, 0, ram_dst, src_sz);
    if (rc != 0) {
        goto done;
    }

    rc = boot_enc_load(BOOT_CURR_ENC(state), slot, hdr, fap_src, &bs);
    if (rc < 0) {
        goto done;
    }

    /* if rc > 0 then the key has already been loaded */
    if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) {
        goto done;
    }

    /* Starting at the end of the header as the header section is not encrypted */
    while (bytes_copied < tlv_off) { /* TLV section copied previously */
        if (src_sz - bytes_copied > max_sz) {
            chunk_sz = max_sz;
        } else {
            chunk_sz = src_sz - bytes_copied;
        }

        cur_dst = ram_dst + bytes_copied;
        blk_sz = chunk_sz;
        idx = 0;
        blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
        if (bytes_copied + chunk_sz > tlv_off) {
            /* Going over TLV section
             * Part of the chunk is encrypted payload */
            blk_sz = tlv_off - (bytes_copied);
        }
        boot_enc_decrypt(BOOT_CURR_ENC(state), slot,
                (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
                blk_off, cur_dst);
        bytes_copied += chunk_sz;
    }
    rc = 0;

done:
    flash_area_close(fap_src);

    return rc;
}

#endif /* MCUBOOT_ENC_IMAGES */
/**
 * Copies a slot of the current image into SRAM.
 *
 * @param  state    Boot loader status information.
 * @param  slot     The flash slot of the image to be copied to SRAM.
 * @param  img_dst  The address at which the image needs to be copied to
 *                  SRAM.
 * @param  img_sz   The size of the image that needs to be copied to SRAM.
 *
 * @return          0 on success; nonzero on failure.
 */
static int
boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
                        uint32_t img_dst, uint32_t img_sz)
{
    int rc;
    const struct flash_area *fap_src = NULL;
    int area_id;

#if (BOOT_IMAGE_NUMBER == 1)
    (void)state;
#endif

    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);

    rc = flash_area_open(area_id, &fap_src);
    if (rc != 0) {
        return BOOT_EFLASH;
    }

    /* Direct copy from flash to its new location in SRAM. */
    rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz);
    if (rc != 0) {
        BOOT_LOG_INF("Error whilst copying image %d from Flash to SRAM: %d",
                     BOOT_CURR_IMG(state), rc);
    }

    flash_area_close(fap_src);

    return rc;
}

#if (BOOT_IMAGE_NUMBER > 1)
/**
 * Checks if two memory regions (A and B) are overlap or not.
 *
 * @param  start_a  Start of the A region.
 * @param  end_a    End of the A region.
 * @param  start_b  Start of the B region.
 * @param  end_b    End of the B region.
 *
 * @return          true if there is overlap; false otherwise.
 */
static bool
do_regions_overlap(uint32_t start_a, uint32_t end_a,
                   uint32_t start_b, uint32_t end_b)
{
    if (start_b > end_a) {
        return false;
    } else if (start_b >= start_a) {
        return true;
    } else if (end_b > start_a) {
        return true;
    }

    return false;
}

/**
 * Checks if the image we want to load to memory overlap with an already
 * ramloaded image.
 *
 * @param  state    Boot loader status information.
 *
 * @return                    0 if there is no overlap; nonzero otherwise.
 */
static int
boot_check_ram_load_overlapping(struct boot_loader_state *state)
{
    uint32_t i;

    uint32_t start_a;
    uint32_t end_a;
    uint32_t start_b;
    uint32_t end_b;
    uint32_t image_id_to_check = BOOT_CURR_IMG(state);

    start_a = state->slot_usage[image_id_to_check].img_dst;
    /* Safe to add here, values are already verified in
     * boot_verify_ram_load_address() */
    end_a = start_a + state->slot_usage[image_id_to_check].img_sz;

    for (i = 0; i < BOOT_IMAGE_NUMBER; i++) {
        if (state->slot_usage[i].active_slot == NO_ACTIVE_SLOT
            || i == image_id_to_check) {
            continue;
        }

        start_b = state->slot_usage[i].img_dst;
        /* Safe to add here, values are already verified in
         * boot_verify_ram_load_address() */
        end_b = start_b + state->slot_usage[i].img_sz;

        if (do_regions_overlap(start_a, end_a, start_b, end_b)) {
            return -1;
        }
    }

    return 0;
}
#endif

/**
 * Loads the active slot of the current image into SRAM. The load address and
 * image size is extracted from the image header.
 *
 * @param  state        Boot loader status information.
 *
 * @return              0 on success; nonzero on failure.
 */
static int
boot_load_image_to_sram(struct boot_loader_state *state)
{
    uint32_t active_slot;
    struct image_header *hdr = NULL;
    uint32_t img_dst;
    uint32_t img_sz;
    int rc;

    active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
    hdr = boot_img_hdr(state, active_slot);

    if (hdr->ih_flags & IMAGE_F_RAM_LOAD) {

        img_dst = hdr->ih_load_addr;

        rc = boot_read_image_size(state, active_slot, &img_sz);
        if (rc != 0) {
            return rc;
        }

        state->slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst;
        state->slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz;

        rc = boot_verify_ram_load_address(state);
        if (rc != 0) {
            BOOT_LOG_INF("Image %d RAM load address 0x%x is invalid.", BOOT_CURR_IMG(state), img_dst);
            return rc;
        }

#if (BOOT_IMAGE_NUMBER > 1)
        rc = boot_check_ram_load_overlapping(state);
        if (rc != 0) {
            BOOT_LOG_INF("Image %d RAM loading to address 0x%x would overlap with\
                         another image.", BOOT_CURR_IMG(state), img_dst);
            return rc;
        }
#endif
#ifdef MCUBOOT_ENC_IMAGES
        /* decrypt image if encrypted and copy it to RAM */
        if (IS_ENCRYPTED(hdr)) {
            rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst);
        } else {
            rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
        }
#else
        /* Copy image to the load address from where it currently resides in
         * flash.
         */
        rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
#endif
        if (rc != 0) {
            BOOT_LOG_INF("Image %d RAM loading to 0x%x is failed.", BOOT_CURR_IMG(state), img_dst);
        } else {
            BOOT_LOG_INF("Image %d RAM loading to 0x%x is succeeded.", BOOT_CURR_IMG(state), img_dst);
        }
    } else {
        /* Only images that support IMAGE_F_RAM_LOAD are allowed if
         * MCUBOOT_RAM_LOAD is set.
         */
        rc = BOOT_EBADIMAGE;
    }

    if (rc != 0) {
        state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
        state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
    }

    return rc;
}

/**
 * Removes an image from SRAM, by overwriting it with zeros.
 *
 * @param  state        Boot loader status information.
 *
 * @return              0 on success; nonzero on failure.
 */
static inline int
boot_remove_image_from_sram(struct boot_loader_state *state)
{
    (void)state;

    BOOT_LOG_INF("Removing image %d from SRAM at address 0x%x",
                 BOOT_CURR_IMG(state),
                 state->slot_usage[BOOT_CURR_IMG(state)].img_dst);

    memset((void*)(IMAGE_RAM_BASE + state->slot_usage[BOOT_CURR_IMG(state)].img_dst),
           0, state->slot_usage[BOOT_CURR_IMG(state)].img_sz);

    state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
    state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;

    return 0;
}

/**
 * Removes an image from flash by erasing the corresponding flash area
 *
 * @param  state    Boot loader status information.
 * @param  slot     The flash slot of the image to be erased.
 *
 * @return          0 on success; nonzero on failure.
 */
static inline int
boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot)
{
    int area_id;
    int rc;
    const struct flash_area *fap;

    (void)state;

    BOOT_LOG_INF("Removing image %d slot %d from flash", BOOT_CURR_IMG(state),
                                                         slot);
    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
    rc = flash_area_open(area_id, &fap);
    if (rc == 0) {
        flash_area_erase(fap, 0, flash_area_get_size(fap));
        flash_area_close(fap);
    }

    return rc;
}
#endif /* MCUBOOT_RAM_LOAD */


/**
 * Tries to load a slot for all the images with validation.
 *
Loading