mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 01:24:27 +00:00

Change the names of some FWU metadata structure members to have them align with the wording used in the corresponding specification. Use the GUID type instead of UUID as the fields described in the specification are GUIDs. Make corresponding changes to the code that accesses these fields. No functional changes are introduced by the patch. Change-Id: Id3544ed1633811b0eeee2bf99477f9b7e6667044 Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
785 lines
19 KiB
C
785 lines
19 KiB
C
/*
|
|
* Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include <arch_helpers.h>
|
|
#include <common/debug.h>
|
|
#include <common/desc_image_load.h>
|
|
#include <drivers/fwu/fwu.h>
|
|
#include <drivers/fwu/fwu_metadata.h>
|
|
#include <drivers/io/io_block.h>
|
|
#include <drivers/io/io_driver.h>
|
|
#include <drivers/io/io_encrypted.h>
|
|
#include <drivers/io/io_fip.h>
|
|
#include <drivers/io/io_memmap.h>
|
|
#include <drivers/io/io_mtd.h>
|
|
#include <drivers/io/io_storage.h>
|
|
#include <drivers/mmc.h>
|
|
#include <drivers/partition/efi.h>
|
|
#include <drivers/partition/partition.h>
|
|
#include <drivers/raw_nand.h>
|
|
#include <drivers/spi_nand.h>
|
|
#include <drivers/spi_nor.h>
|
|
#include <drivers/st/stm32_fmc2_nand.h>
|
|
#include <drivers/st/stm32_qspi.h>
|
|
#include <drivers/st/stm32_sdmmc2.h>
|
|
#include <drivers/usb_device.h>
|
|
#include <lib/fconf/fconf.h>
|
|
#include <lib/mmio.h>
|
|
#include <lib/utils.h>
|
|
#include <plat/common/platform.h>
|
|
#include <tools_share/firmware_image_package.h>
|
|
|
|
#include <platform_def.h>
|
|
#include <stm32cubeprogrammer.h>
|
|
#include <stm32mp_efi.h>
|
|
#include <stm32mp_fconf_getter.h>
|
|
#include <stm32mp_io_storage.h>
|
|
#include <usb_dfu.h>
|
|
|
|
/* IO devices */
|
|
uintptr_t fip_dev_handle;
|
|
uintptr_t storage_dev_handle;
|
|
|
|
static const io_dev_connector_t *fip_dev_con;
|
|
|
|
#ifndef DECRYPTION_SUPPORT_none
|
|
static const io_dev_connector_t *enc_dev_con;
|
|
uintptr_t enc_dev_handle;
|
|
#endif
|
|
|
|
#if STM32MP_SDMMC || STM32MP_EMMC
|
|
static struct mmc_device_info mmc_info;
|
|
|
|
static uint8_t block_buffer[MMC_BLOCK_SIZE] __aligned(MMC_BLOCK_SIZE);
|
|
|
|
static io_block_dev_spec_t mmc_block_dev_spec = {
|
|
/* It's used as temp buffer in block driver */
|
|
.buffer = {
|
|
.offset = (size_t)&block_buffer,
|
|
.length = MMC_BLOCK_SIZE,
|
|
},
|
|
.ops = {
|
|
.read = mmc_read_blocks,
|
|
.write = NULL,
|
|
},
|
|
.block_size = MMC_BLOCK_SIZE,
|
|
};
|
|
|
|
static const io_dev_connector_t *mmc_dev_con;
|
|
#endif /* STM32MP_SDMMC || STM32MP_EMMC */
|
|
|
|
#if STM32MP_SPI_NOR
|
|
static io_mtd_dev_spec_t spi_nor_dev_spec = {
|
|
.ops = {
|
|
.init = spi_nor_init,
|
|
.read = spi_nor_read,
|
|
},
|
|
};
|
|
#endif
|
|
|
|
#if STM32MP_RAW_NAND
|
|
static io_mtd_dev_spec_t nand_dev_spec = {
|
|
.ops = {
|
|
.init = nand_raw_init,
|
|
.read = nand_read,
|
|
.seek = nand_seek_bb
|
|
},
|
|
};
|
|
|
|
static const io_dev_connector_t *nand_dev_con;
|
|
#endif
|
|
|
|
#if STM32MP_SPI_NAND
|
|
static io_mtd_dev_spec_t spi_nand_dev_spec = {
|
|
.ops = {
|
|
.init = spi_nand_init,
|
|
.read = nand_read,
|
|
.seek = nand_seek_bb
|
|
},
|
|
};
|
|
#endif
|
|
|
|
#if STM32MP_SPI_NAND || STM32MP_SPI_NOR
|
|
static const io_dev_connector_t *spi_dev_con;
|
|
#endif
|
|
|
|
#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
|
|
static const io_dev_connector_t *memmap_dev_con;
|
|
#endif
|
|
|
|
io_block_spec_t image_block_spec = {
|
|
.offset = 0U,
|
|
.length = 0U,
|
|
};
|
|
|
|
int open_fip(const uintptr_t spec)
|
|
{
|
|
return io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
|
|
}
|
|
|
|
#ifndef DECRYPTION_SUPPORT_none
|
|
int open_enc_fip(const uintptr_t spec)
|
|
{
|
|
int result;
|
|
uintptr_t local_image_handle;
|
|
|
|
result = io_dev_init(enc_dev_handle, (uintptr_t)ENC_IMAGE_ID);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
|
|
result = io_open(enc_dev_handle, spec, &local_image_handle);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
|
|
VERBOSE("Using encrypted FIP\n");
|
|
io_close(local_image_handle);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int open_storage(const uintptr_t spec)
|
|
{
|
|
return io_dev_init(storage_dev_handle, 0);
|
|
}
|
|
|
|
#if STM32MP_EMMC_BOOT
|
|
static uint32_t get_boot_part_fip_header(void)
|
|
{
|
|
io_block_spec_t emmc_boot_fip_block_spec = {
|
|
.offset = STM32MP_EMMC_BOOT_FIP_OFFSET,
|
|
.length = MMC_BLOCK_SIZE, /* We are interested only in first 4 bytes */
|
|
};
|
|
uint32_t magic = 0U;
|
|
int io_result;
|
|
size_t bytes_read;
|
|
uintptr_t fip_hdr_handle;
|
|
|
|
io_result = io_open(storage_dev_handle, (uintptr_t)&emmc_boot_fip_block_spec,
|
|
&fip_hdr_handle);
|
|
assert(io_result == 0);
|
|
|
|
io_result = io_read(fip_hdr_handle, (uintptr_t)&magic, sizeof(magic),
|
|
&bytes_read);
|
|
if ((io_result != 0) || (bytes_read != sizeof(magic))) {
|
|
panic();
|
|
}
|
|
|
|
io_close(fip_hdr_handle);
|
|
|
|
VERBOSE("%s: eMMC boot magic at offset 256K: %08x\n",
|
|
__func__, magic);
|
|
|
|
return magic;
|
|
}
|
|
#endif
|
|
|
|
static void print_boot_device(boot_api_context_t *boot_context)
|
|
{
|
|
switch (boot_context->boot_interface_selected) {
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
|
|
INFO("Using SDMMC\n");
|
|
break;
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
|
|
INFO("Using EMMC\n");
|
|
break;
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_SPI:
|
|
INFO("Using SPI NOR\n");
|
|
break;
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
|
|
INFO("Using FMC NAND\n");
|
|
break;
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_SPI:
|
|
INFO("Using SPI NAND\n");
|
|
break;
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
|
|
INFO("Using UART\n");
|
|
break;
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
|
|
INFO("Using USB\n");
|
|
break;
|
|
default:
|
|
ERROR("Boot interface %u not found\n",
|
|
boot_context->boot_interface_selected);
|
|
panic();
|
|
break;
|
|
}
|
|
|
|
if (boot_context->boot_interface_instance != 0U) {
|
|
INFO(" Instance %d\n", boot_context->boot_interface_instance);
|
|
}
|
|
}
|
|
|
|
#if STM32MP_SDMMC || STM32MP_EMMC
|
|
static void boot_mmc(enum mmc_device_type mmc_dev_type,
|
|
uint16_t boot_interface_instance)
|
|
{
|
|
int io_result __maybe_unused;
|
|
struct stm32_sdmmc2_params params;
|
|
|
|
zeromem(¶ms, sizeof(struct stm32_sdmmc2_params));
|
|
|
|
mmc_info.mmc_dev_type = mmc_dev_type;
|
|
|
|
switch (boot_interface_instance) {
|
|
case 1:
|
|
params.reg_base = STM32MP_SDMMC1_BASE;
|
|
break;
|
|
case 2:
|
|
params.reg_base = STM32MP_SDMMC2_BASE;
|
|
break;
|
|
case 3:
|
|
params.reg_base = STM32MP_SDMMC3_BASE;
|
|
break;
|
|
default:
|
|
WARN("SDMMC instance not found, using default\n");
|
|
if (mmc_dev_type == MMC_IS_SD) {
|
|
params.reg_base = STM32MP_SDMMC1_BASE;
|
|
} else {
|
|
params.reg_base = STM32MP_SDMMC2_BASE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (mmc_dev_type != MMC_IS_EMMC) {
|
|
params.flags = MMC_FLAG_SD_CMD6;
|
|
}
|
|
|
|
params.device_info = &mmc_info;
|
|
if (stm32_sdmmc2_mmc_init(¶ms) != 0) {
|
|
ERROR("SDMMC%u init failed\n", boot_interface_instance);
|
|
panic();
|
|
}
|
|
|
|
/* Open MMC as a block device to read FIP */
|
|
io_result = register_io_dev_block(&mmc_dev_con);
|
|
if (io_result != 0) {
|
|
panic();
|
|
}
|
|
|
|
io_result = io_dev_open(mmc_dev_con, (uintptr_t)&mmc_block_dev_spec,
|
|
&storage_dev_handle);
|
|
assert(io_result == 0);
|
|
|
|
#if STM32MP_EMMC_BOOT
|
|
if (mmc_dev_type == MMC_IS_EMMC) {
|
|
io_result = mmc_part_switch_current_boot();
|
|
assert(io_result == 0);
|
|
|
|
if (get_boot_part_fip_header() != TOC_HEADER_NAME) {
|
|
WARN("%s: Can't find FIP header on eMMC boot partition. Trying GPT\n",
|
|
__func__);
|
|
io_result = mmc_part_switch_user();
|
|
assert(io_result == 0);
|
|
return;
|
|
}
|
|
|
|
VERBOSE("%s: FIP header found on eMMC boot partition\n",
|
|
__func__);
|
|
image_block_spec.offset = STM32MP_EMMC_BOOT_FIP_OFFSET;
|
|
image_block_spec.length = mmc_boot_part_size() - STM32MP_EMMC_BOOT_FIP_OFFSET;
|
|
}
|
|
#endif
|
|
}
|
|
#endif /* STM32MP_SDMMC || STM32MP_EMMC */
|
|
|
|
#if STM32MP_SPI_NOR
|
|
static void boot_spi_nor(boot_api_context_t *boot_context)
|
|
{
|
|
int io_result __maybe_unused;
|
|
|
|
io_result = stm32_qspi_init();
|
|
assert(io_result == 0);
|
|
|
|
io_result = register_io_dev_mtd(&spi_dev_con);
|
|
assert(io_result == 0);
|
|
|
|
/* Open connections to device */
|
|
io_result = io_dev_open(spi_dev_con,
|
|
(uintptr_t)&spi_nor_dev_spec,
|
|
&storage_dev_handle);
|
|
assert(io_result == 0);
|
|
}
|
|
#endif /* STM32MP_SPI_NOR */
|
|
|
|
#if STM32MP_RAW_NAND
|
|
static void boot_fmc2_nand(boot_api_context_t *boot_context)
|
|
{
|
|
int io_result __maybe_unused;
|
|
|
|
io_result = stm32_fmc2_init();
|
|
assert(io_result == 0);
|
|
|
|
/* Register the IO device on this platform */
|
|
io_result = register_io_dev_mtd(&nand_dev_con);
|
|
assert(io_result == 0);
|
|
|
|
/* Open connections to device */
|
|
io_result = io_dev_open(nand_dev_con, (uintptr_t)&nand_dev_spec,
|
|
&storage_dev_handle);
|
|
assert(io_result == 0);
|
|
}
|
|
#endif /* STM32MP_RAW_NAND */
|
|
|
|
#if STM32MP_SPI_NAND
|
|
static void boot_spi_nand(boot_api_context_t *boot_context)
|
|
{
|
|
int io_result __maybe_unused;
|
|
|
|
io_result = stm32_qspi_init();
|
|
assert(io_result == 0);
|
|
|
|
io_result = register_io_dev_mtd(&spi_dev_con);
|
|
assert(io_result == 0);
|
|
|
|
/* Open connections to device */
|
|
io_result = io_dev_open(spi_dev_con,
|
|
(uintptr_t)&spi_nand_dev_spec,
|
|
&storage_dev_handle);
|
|
assert(io_result == 0);
|
|
}
|
|
#endif /* STM32MP_SPI_NAND */
|
|
|
|
#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
|
|
static void mmap_io_setup(void)
|
|
{
|
|
int io_result __maybe_unused;
|
|
|
|
io_result = register_io_dev_memmap(&memmap_dev_con);
|
|
assert(io_result == 0);
|
|
|
|
io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
|
|
&storage_dev_handle);
|
|
assert(io_result == 0);
|
|
}
|
|
|
|
#if STM32MP_UART_PROGRAMMER
|
|
static void stm32cubeprogrammer_uart(void)
|
|
{
|
|
int ret __maybe_unused;
|
|
boot_api_context_t *boot_context =
|
|
(boot_api_context_t *)stm32mp_get_boot_ctx_address();
|
|
uintptr_t uart_base;
|
|
|
|
uart_base = get_uart_address(boot_context->boot_interface_instance);
|
|
ret = stm32cubeprog_uart_load(uart_base, DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
|
|
assert(ret == 0);
|
|
}
|
|
#endif
|
|
|
|
#if STM32MP_USB_PROGRAMMER
|
|
static void stm32cubeprogrammer_usb(void)
|
|
{
|
|
int ret __maybe_unused;
|
|
struct usb_handle *pdev;
|
|
|
|
/* Init USB on platform */
|
|
pdev = usb_dfu_plat_init();
|
|
|
|
ret = stm32cubeprog_usb_load(pdev, DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
|
|
assert(ret == 0);
|
|
}
|
|
#endif
|
|
#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */
|
|
|
|
void stm32mp_io_setup(void)
|
|
{
|
|
int io_result __maybe_unused;
|
|
boot_api_context_t *boot_context =
|
|
(boot_api_context_t *)stm32mp_get_boot_ctx_address();
|
|
|
|
print_boot_device(boot_context);
|
|
|
|
if ((boot_context->boot_partition_used_toboot == 1U) ||
|
|
(boot_context->boot_partition_used_toboot == 2U)) {
|
|
INFO("Boot used partition fsbl%u\n",
|
|
boot_context->boot_partition_used_toboot);
|
|
}
|
|
|
|
io_result = register_io_dev_fip(&fip_dev_con);
|
|
assert(io_result == 0);
|
|
|
|
io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
|
|
&fip_dev_handle);
|
|
|
|
#ifndef DECRYPTION_SUPPORT_none
|
|
io_result = register_io_dev_enc(&enc_dev_con);
|
|
assert(io_result == 0);
|
|
|
|
io_result = io_dev_open(enc_dev_con, (uintptr_t)NULL,
|
|
&enc_dev_handle);
|
|
assert(io_result == 0);
|
|
#endif
|
|
|
|
switch (boot_context->boot_interface_selected) {
|
|
#if STM32MP_SDMMC
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
|
|
dmbsy();
|
|
boot_mmc(MMC_IS_SD, boot_context->boot_interface_instance);
|
|
break;
|
|
#endif
|
|
#if STM32MP_EMMC
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
|
|
dmbsy();
|
|
boot_mmc(MMC_IS_EMMC, boot_context->boot_interface_instance);
|
|
break;
|
|
#endif
|
|
#if STM32MP_SPI_NOR
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_SPI:
|
|
dmbsy();
|
|
boot_spi_nor(boot_context);
|
|
break;
|
|
#endif
|
|
#if STM32MP_RAW_NAND
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
|
|
dmbsy();
|
|
boot_fmc2_nand(boot_context);
|
|
break;
|
|
#endif
|
|
#if STM32MP_SPI_NAND
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_SPI:
|
|
dmbsy();
|
|
boot_spi_nand(boot_context);
|
|
break;
|
|
#endif
|
|
#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
|
|
#if STM32MP_UART_PROGRAMMER
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
|
|
#endif
|
|
#if STM32MP_USB_PROGRAMMER
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
|
|
#endif
|
|
dmbsy();
|
|
mmap_io_setup();
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
ERROR("Boot interface %d not supported\n",
|
|
boot_context->boot_interface_selected);
|
|
panic();
|
|
break;
|
|
}
|
|
}
|
|
|
|
int bl2_plat_handle_pre_image_load(unsigned int image_id)
|
|
{
|
|
static bool gpt_init_done __maybe_unused;
|
|
uint16_t boot_itf = stm32mp_get_boot_itf_selected();
|
|
|
|
switch (boot_itf) {
|
|
#if STM32MP_SDMMC || STM32MP_EMMC
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
|
|
#if STM32MP_EMMC_BOOT
|
|
if (image_block_spec.offset == STM32MP_EMMC_BOOT_FIP_OFFSET) {
|
|
break;
|
|
}
|
|
#endif
|
|
/* fallthrough */
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
|
|
if (!gpt_init_done) {
|
|
/*
|
|
* With FWU Multi Bank feature enabled, the selection of
|
|
* the image to boot will be done by fwu_init calling the
|
|
* platform hook, plat_fwu_set_images_source.
|
|
*/
|
|
#if !PSA_FWU_SUPPORT
|
|
const partition_entry_t *entry;
|
|
const struct efi_guid fip_guid = STM32MP_FIP_GUID;
|
|
|
|
partition_init(GPT_IMAGE_ID);
|
|
entry = get_partition_entry_by_type(&fip_guid);
|
|
if (entry == NULL) {
|
|
entry = get_partition_entry(FIP_IMAGE_NAME);
|
|
if (entry == NULL) {
|
|
ERROR("Could NOT find the %s partition!\n",
|
|
FIP_IMAGE_NAME);
|
|
|
|
return -ENOENT;
|
|
}
|
|
}
|
|
|
|
image_block_spec.offset = entry->start;
|
|
image_block_spec.length = entry->length;
|
|
#endif
|
|
gpt_init_done = true;
|
|
} else {
|
|
bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
|
|
|
|
assert(bl_mem_params != NULL);
|
|
|
|
mmc_block_dev_spec.buffer.offset = bl_mem_params->image_info.image_base;
|
|
mmc_block_dev_spec.buffer.length = bl_mem_params->image_info.image_max_size;
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
|
|
#if STM32MP_RAW_NAND || STM32MP_SPI_NAND
|
|
#if STM32MP_RAW_NAND
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
|
|
#endif
|
|
#if STM32MP_SPI_NAND
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_SPI:
|
|
#endif
|
|
image_block_spec.offset = STM32MP_NAND_FIP_OFFSET;
|
|
break;
|
|
#endif
|
|
|
|
#if STM32MP_SPI_NOR
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_SPI:
|
|
/*
|
|
* With FWU Multi Bank feature enabled, the selection of
|
|
* the image to boot will be done by fwu_init calling the
|
|
* platform hook, plat_fwu_set_images_source.
|
|
*/
|
|
#if !PSA_FWU_SUPPORT
|
|
image_block_spec.offset = STM32MP_NOR_FIP_OFFSET;
|
|
#endif
|
|
break;
|
|
#endif
|
|
|
|
#if STM32MP_UART_PROGRAMMER
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
|
|
if (image_id == FW_CONFIG_ID) {
|
|
stm32cubeprogrammer_uart();
|
|
/* FIP loaded at DWL address */
|
|
image_block_spec.offset = DWL_BUFFER_BASE;
|
|
image_block_spec.length = DWL_BUFFER_SIZE;
|
|
}
|
|
break;
|
|
#endif
|
|
#if STM32MP_USB_PROGRAMMER
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
|
|
if (image_id == FW_CONFIG_ID) {
|
|
stm32cubeprogrammer_usb();
|
|
/* FIP loaded at DWL address */
|
|
image_block_spec.offset = DWL_BUFFER_BASE;
|
|
image_block_spec.length = DWL_BUFFER_SIZE;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
ERROR("FIP Not found\n");
|
|
panic();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Return an IO device handle and specification which can be used to access
|
|
* an image. Use this to enforce platform load policy.
|
|
*/
|
|
int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
|
|
uintptr_t *image_spec)
|
|
{
|
|
int rc;
|
|
const struct plat_io_policy *policy;
|
|
|
|
policy = FCONF_GET_PROPERTY(stm32mp, io_policies, image_id);
|
|
rc = policy->check(policy->image_spec);
|
|
if (rc == 0) {
|
|
*image_spec = policy->image_spec;
|
|
*dev_handle = *(policy->dev_handle);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
#if (STM32MP_SDMMC || STM32MP_EMMC || STM32MP_SPI_NOR) && PSA_FWU_SUPPORT
|
|
/*
|
|
* In each boot in non-trial mode, we set the BKP register to
|
|
* FWU_MAX_TRIAL_REBOOT, and return the active_index from metadata.
|
|
*
|
|
* As long as the update agent didn't update the "accepted" field in metadata
|
|
* (i.e. we are in trial mode), we select the new active_index.
|
|
* To avoid infinite boot loop at trial boot we decrement a BKP register.
|
|
* If this counter is 0:
|
|
* - an unexpected TAMPER event raised (that resets the BKP registers to 0)
|
|
* - a power-off occurs before the update agent was able to update the
|
|
* "accepted' field
|
|
* - we already boot FWU_MAX_TRIAL_REBOOT times in trial mode.
|
|
* we select the previous_active_index.
|
|
*/
|
|
uint32_t plat_fwu_get_boot_idx(void)
|
|
{
|
|
/*
|
|
* Select boot index and update boot counter only once per boot
|
|
* even if this function is called several times.
|
|
*/
|
|
static uint32_t boot_idx = INVALID_BOOT_IDX;
|
|
|
|
if (boot_idx == INVALID_BOOT_IDX) {
|
|
const struct fwu_metadata *data = fwu_get_metadata();
|
|
|
|
boot_idx = data->active_index;
|
|
|
|
if (data->bank_state[boot_idx] == FWU_BANK_STATE_VALID) {
|
|
if (stm32_get_and_dec_fwu_trial_boot_cnt() == 0U) {
|
|
WARN("Trial FWU fails %u times\n",
|
|
FWU_MAX_TRIAL_REBOOT);
|
|
boot_idx = fwu_get_alternate_boot_bank();
|
|
}
|
|
} else if (data->bank_state[boot_idx] ==
|
|
FWU_BANK_STATE_ACCEPTED) {
|
|
stm32_set_max_fwu_trial_boot_cnt();
|
|
} else {
|
|
ERROR("The active bank(%u) of the platform is in Invalid State.\n",
|
|
boot_idx);
|
|
boot_idx = fwu_get_alternate_boot_bank();
|
|
stm32_clear_fwu_trial_boot_cnt();
|
|
}
|
|
}
|
|
|
|
return boot_idx;
|
|
}
|
|
|
|
static void *stm32_get_image_spec(const struct efi_guid *img_type_guid)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0U; i < MAX_NUMBER_IDS; i++) {
|
|
if ((guidcmp(&policies[i].img_type_guid, img_type_guid)) == 0) {
|
|
return (void *)policies[i].image_spec;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void plat_fwu_set_images_source(const struct fwu_metadata *metadata)
|
|
{
|
|
unsigned int i;
|
|
uint32_t boot_idx;
|
|
const partition_entry_t *entry __maybe_unused;
|
|
const struct fwu_image_entry *img_entry;
|
|
const void *img_type_guid;
|
|
const void *img_guid;
|
|
io_block_spec_t *image_spec;
|
|
const uint16_t boot_itf = stm32mp_get_boot_itf_selected();
|
|
|
|
boot_idx = plat_fwu_get_boot_idx();
|
|
assert(boot_idx < NR_OF_FW_BANKS);
|
|
VERBOSE("Selecting to boot from bank %u\n", boot_idx);
|
|
|
|
img_entry = (void *)&metadata->fw_desc.img_entry;
|
|
for (i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
|
|
img_type_guid = &img_entry[i].img_type_guid;
|
|
|
|
img_guid = &img_entry[i].img_bank_info[boot_idx].img_guid;
|
|
|
|
image_spec = stm32_get_image_spec(img_type_guid);
|
|
if (image_spec == NULL) {
|
|
ERROR("Unable to get image spec for the image in the metadata\n");
|
|
panic();
|
|
}
|
|
|
|
switch (boot_itf) {
|
|
#if (STM32MP_SDMMC || STM32MP_EMMC)
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
|
|
entry = get_partition_entry_by_guid(img_guid);
|
|
if (entry == NULL) {
|
|
ERROR("No partition with the uuid mentioned in metadata\n");
|
|
panic();
|
|
}
|
|
|
|
image_spec->offset = entry->start;
|
|
image_spec->length = entry->length;
|
|
break;
|
|
#endif
|
|
#if STM32MP_SPI_NOR
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_SPI:
|
|
if (guidcmp(img_guid, &STM32MP_NOR_FIP_A_GUID) == 0) {
|
|
image_spec->offset = STM32MP_NOR_FIP_A_OFFSET;
|
|
} else if (guidcmp(img_guid, &STM32MP_NOR_FIP_B_GUID) == 0) {
|
|
image_spec->offset = STM32MP_NOR_FIP_B_OFFSET;
|
|
} else {
|
|
ERROR("Invalid uuid mentioned in metadata\n");
|
|
panic();
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
panic();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int plat_set_image_source(unsigned int image_id,
|
|
uintptr_t *handle,
|
|
uintptr_t *image_spec)
|
|
{
|
|
struct plat_io_policy *policy;
|
|
io_block_spec_t *spec __maybe_unused;
|
|
const partition_entry_t *entry __maybe_unused;
|
|
const uint16_t boot_itf = stm32mp_get_boot_itf_selected();
|
|
|
|
policy = &policies[image_id];
|
|
spec = (io_block_spec_t *)policy->image_spec;
|
|
|
|
switch (boot_itf) {
|
|
#if (STM32MP_SDMMC || STM32MP_EMMC)
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
|
|
partition_init(GPT_IMAGE_ID);
|
|
|
|
if (image_id == FWU_METADATA_IMAGE_ID) {
|
|
entry = get_partition_entry(METADATA_PART_1);
|
|
} else {
|
|
entry = get_partition_entry(METADATA_PART_2);
|
|
}
|
|
|
|
if (entry == NULL) {
|
|
ERROR("Unable to find a metadata partition\n");
|
|
return -ENOENT;
|
|
}
|
|
|
|
spec->offset = entry->start;
|
|
spec->length = entry->length;
|
|
break;
|
|
#endif
|
|
|
|
#if STM32MP_SPI_NOR
|
|
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_SPI:
|
|
if (image_id == FWU_METADATA_IMAGE_ID) {
|
|
spec->offset = STM32MP_NOR_METADATA1_OFFSET;
|
|
} else {
|
|
spec->offset = STM32MP_NOR_METADATA2_OFFSET;
|
|
}
|
|
|
|
spec->length = sizeof(struct fwu_metadata);
|
|
break;
|
|
#endif
|
|
default:
|
|
panic();
|
|
break;
|
|
}
|
|
|
|
*image_spec = policy->image_spec;
|
|
*handle = *policy->dev_handle;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int plat_fwu_set_metadata_image_source(unsigned int image_id,
|
|
uintptr_t *handle,
|
|
uintptr_t *image_spec)
|
|
{
|
|
assert((image_id == FWU_METADATA_IMAGE_ID) ||
|
|
(image_id == BKUP_FWU_METADATA_IMAGE_ID));
|
|
|
|
return plat_set_image_source(image_id, handle, image_spec);
|
|
}
|
|
#endif /* (STM32MP_SDMMC || STM32MP_EMMC || STM32MP_SPI_NOR) && PSA_FWU_SUPPORT */
|