This commit is contained in:
2025-12-24 17:21:08 +09:00
parent a96323de19
commit 96dc62d8dc
2302 changed files with 455822 additions and 0 deletions

View File

@@ -0,0 +1,336 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (C) 2017 The Android Open Source Project
*/
// #include <common.h>
#include <android_ab.h>
#include <android_bootloader_message.h>
// #include <blk.h>
#include <log.h>
// #include <malloc.h>
#include <string.h>
// #include <part.h>
// #include <memalign.h>
// #include <linux/err.h>
#include <errno.h>
// #include <u-boot/crc.h>
#include <crc.h>
#include <emmc_multiboot.h>
#include <image_load_emmc.h>
#include <mem_io.h>
typedef unsigned long int ulong;
typedef uint32_t u32;
#define typeof(x) __typeof__(x)
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
volatile uint8_t *_disk_buffer = (volatile uint8_t *)DISK_BUFFER_ADDR;
/**
* Compute the CRC-32 of the bootloader control struct.
*
* Only the bytes up to the crc32_le field are considered for the CRC-32
* calculation.
*
* @param[in] abc bootloader control block
*
* @return crc32 sum
*/
static uint32_t ab_control_compute_crc(struct bootloader_control *abc)
{
return crc32(0, (void *)abc, offsetof(typeof(*abc), crc32_le));
}
/**
* Initialize bootloader_control to the default value.
*
* It allows us to boot all slots in order from the first one. This value
* should be used when the bootloader message is corrupted, but not when
* a valid message indicates that all slots are unbootable.
*
* @param[in] abc bootloader control block
*
* @return 0 on success and a negative on error
*/
static int ab_control_default(struct bootloader_control *abc)
{
int i;
const struct slot_metadata metadata = {
.priority = 15,
.tries_remaining = 7,
.successful_boot = 0,
.verity_corrupted = 0,
.reserved = 0
};
if (!abc)
return -EFAULT;
memcpy(abc->slot_suffix, "a\0\0\0", 4);
abc->magic = BOOT_CTRL_MAGIC;
abc->version = BOOT_CTRL_VERSION;
abc->nb_slot = NUM_SLOTS;
memset(abc->reserved0, 0, sizeof(abc->reserved0));
for (i = 0; i < abc->nb_slot; ++i)
abc->slot_info[i] = metadata;
memset(abc->reserved1, 0, sizeof(abc->reserved1));
abc->crc32_le = ab_control_compute_crc(abc);
return 0;
}
/**
* Load the boot_control struct from disk into newly allocated memory.
*
* This function allocates and returns an integer number of disk blocks,
* based on the block size of the passed device to help performing a
* read-modify-write operation on the boot_control struct.
* The boot_control struct offset (2 KiB) must be a multiple of the device
* block size, for simplicity.
*
* @param[in] dev_desc Device where to read the boot_control struct from
* @param[in] part_info Partition in 'dev_desc' where to read from, normally
* the "misc" partition should be used
* @param[out] pointer to pointer to bootloader_control data
* @return 0 on success and a negative on error
*/
static int ab_control_create_from_disk(
// struct blk_desc *dev_desc,
// const struct disk_partition *part_info,
struct bootloader_control **abc)
{
// ulong abc_offset, abc_blocks, ret;
// abc_offset = offsetof(struct bootloader_message_ab, slot_suffix);
// if (abc_offset % CX_EMMC_SECTOR_SIZE) {
// ERROR("Boot control block not block aligned.\n");
// return -EINVAL;
// }
// abc_offset /= CX_EMMC_SECTOR_SIZE;
// abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
// CX_EMMC_SECTOR_SIZE);
// if (abc_offset + abc_blocks > part_info->size) {
// ERROR("boot control partition too small. Need at"
// " least %lu blocks but have %lu blocks.\n",
// abc_offset + abc_blocks, part_info->size);
// return -EINVAL;
// }
// *abc = malloc_cache_aligned(abc_blocks * CX_EMMC_SECTOR_SIZE);
// if (!*abc)
// return -ENOMEM;
// [ab_control_create_from_disk:112] start 0x3f800(260096), abc_offset(0x4,4), blocks 1
// ret = blk_dread(dev_desc, part_info->start + abc_offset, abc_blocks,
// *abc);
uint32_t rtn_val = EMMC_DEV_ERR;
#define CX_EMMC_MISC_PART 0 // user partition
#define CX_EMMC_MISC_START 0x3F800 // 127MB in user partition
#define CX_EMMC_AB_CONTROL (CX_EMMC_MISC_START + 4)
#define CX_EMMC_AB_SIZE (1)
rtn_val = emmc_trans_data(CX_EMMC_MISC_PART, (uintptr_t)(CX_EMMC_AB_CONTROL),
(uintptr_t)_disk_buffer, CX_EMMC_AB_SIZE);
if(EMMC_DEV_OK != rtn_val)
{
ERROR("Could not read from boot ctrl partition\n");
*abc = NULL;
return -EIO;
}
*abc = (struct bootloader_control *)_disk_buffer;
return 0;
}
/**
* Store the loaded boot_control block.
*
* Store back to the same location it was read from with
* ab_control_create_from_misc().
*
* @param[in] dev_desc Device where we should write the boot_control struct
* @param[in] part_info Partition on the 'dev_desc' where to write
* @param[in] abc Pointer to the boot control struct and the extra bytes after
* it up to the nearest block boundary
* @return 0 on success and a negative on error
*/
// static int ab_control_store(struct blk_desc *dev_desc,
// const struct disk_partition *part_info,
// struct bootloader_control *abc)
// {
// ulong abc_offset, abc_blocks, ret;
// abc_offset = offsetof(struct bootloader_message_ab, slot_suffix) /
// part_info->blksz;
// abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
// part_info->blksz);
// ret = blk_dwrite(dev_desc, part_info->start + abc_offset, abc_blocks,
// abc);
// if (IS_ERR_VALUE(ret)) {
// log_err("ANDROID: Could not write back the misc partition\n");
// return -EIO;
// }
// return 0;
// }
/**
* Compare two slots.
*
* The function determines slot which is should we boot from among the two.
*
* @param[in] a The first bootable slot metadata
* @param[in] b The second bootable slot metadata
* @return Negative if the slot "a" is better, positive of the slot "b" is
* better or 0 if they are equally good.
*/
static int ab_compare_slots(const struct slot_metadata *a,
const struct slot_metadata *b)
{
/* Higher priority is better */
if (a->priority != b->priority)
return b->priority - a->priority;
/* Higher successful_boot value is better, in case of same priority */
if (a->successful_boot != b->successful_boot)
return b->successful_boot - a->successful_boot;
/* Higher tries_remaining is better to ensure round-robin */
if (a->tries_remaining != b->tries_remaining)
return b->tries_remaining - a->tries_remaining;
return 0;
}
int ab_select_slot(
// struct blk_desc *dev_desc, struct disk_partition *part_info
void
)
{
struct bootloader_control *abc = NULL;
u32 crc32_le;
int slot, i, ret;
bool store_needed = false;
char slot_suffix[4];
mem_write32(AB_INFO_FLAG_ADDR, AB_INFO_FLAG_INIT);
ret = ab_control_create_from_disk(/*dev_desc, part_info,*/ &abc);
if (ret < 0) {
/*
* This condition represents an actual problem with the code or
* the board setup, like an invalid partition information.
* Signal a repair mode and do not try to boot from either slot.
*/
return ret;
}
crc32_le = ab_control_compute_crc(abc);
if (abc->crc32_le != crc32_le) {
ERROR("Invalid CRC-32 (expected %.8x, found %.8x),"
"re-initializing A/B metadata.\n", crc32_le, abc->crc32_le);
ret = ab_control_default(abc);
if (ret < 0) {
// free(abc);
return -ENODATA;
}
store_needed = true;
}
if (abc->magic != BOOT_CTRL_MAGIC) {
ERROR("Unknown A/B metadata: %.8x\n", abc->magic);
// free(abc);
return -ENODATA;
}
if (abc->version > BOOT_CTRL_VERSION) {
ERROR("Unsupported A/B metadata version: %.8x\n", abc->version);
// free(abc);
return -ENODATA;
}
/*
* At this point a valid boot control metadata is stored in abc,
* followed by other reserved data in the same block. We select a with
* the higher priority slot that
* - is not marked as corrupted and
* - either has tries_remaining > 0 or successful_boot is true.
* If the selected slot has a false successful_boot, we also decrement
* the tries_remaining until it eventually becomes unbootable because
* tries_remaining reaches 0. This mechanism produces a bootloader
* induced rollback, typically right after a failed update.
*/
/* Safety check: limit the number of slots. */
if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) {
abc->nb_slot = ARRAY_SIZE(abc->slot_info);
NOTICE("[%s:%d] abc->nb_slot > ARRAY_SIZE(abc->slot_info)\n", __func__, __LINE__);
store_needed = true;
}
slot = -1;
for (i = 0; i < abc->nb_slot; ++i) {
if (abc->slot_info[i].verity_corrupted ||
!abc->slot_info[i].tries_remaining) {
NOTICE("unbootable slot %d tries: %d, corrupt: %d\n",
i, abc->slot_info[i].tries_remaining,
abc->slot_info[i].verity_corrupted);
continue;
}
NOTICE("bootable slot %d pri: %d, tries: %d, "
"corrupt: %d, successful: %d\n",
i, abc->slot_info[i].priority,
abc->slot_info[i].tries_remaining,
abc->slot_info[i].verity_corrupted,
abc->slot_info[i].successful_boot);
if (slot < 0 ||
ab_compare_slots(&abc->slot_info[i],
&abc->slot_info[slot]) < 0) {
slot = i;
}
}
if (slot >= 0 && !abc->slot_info[slot].successful_boot) {
ERROR("Attempting slot %d, tries remaining %d\n",
slot, abc->slot_info[slot].tries_remaining);
abc->slot_info[slot].tries_remaining--;
store_needed = true;
}
if (slot >= 0) {
/*
* Legacy user-space requires this field to be set in the BCB.
* Newer releases load this slot suffix from the command line
* or the device tree.
*/
memset(slot_suffix, 0, sizeof(slot_suffix));
slot_suffix[0] = BOOT_SLOT_NAME(slot);
if (memcmp(abc->slot_suffix, slot_suffix,
sizeof(slot_suffix))) {
memcpy(abc->slot_suffix, slot_suffix,
sizeof(slot_suffix));
NOTICE("[%s:%d] slot_suffix is differ\n", __func__, __LINE__);
store_needed = true;
}
}
if (store_needed) {
abc->crc32_le = ab_control_compute_crc(abc);
// ab_control_store(dev_desc, part_info, abc);
crc32_le = AB_INFO_FLAG_STORE;
}
else
crc32_le = AB_INFO_FLAG_OK;
// free(abc);
if (slot == 1)
crc32_le |= AB_INFO_SELECT_2nd;
mem_write32(AB_INFO_FLAG_ADDR, crc32_le);
if (slot < 0)
return -EINVAL;
return slot;
}

View File

@@ -0,0 +1,494 @@
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2018-2025 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/
/*******************************************************************************
* DESCRIPTION : Image load function
******************************************************************************/
/******************************************************************************
* @file image_load.c
* - Version : 0.11
* @brief Access protection setting driver.
* .
*****************************************************************************/
/******************************************************************************
* History : DD.MM.YYYY Version Description
* : 29.11.2021 0.01 First Release
* : 10.02.2022 0.02 Updated eMMC driver
* Removed the comment
* Change the line feed code of log output
* Change the number of CA programs
* : 17.02.2022 0.03 Support AArch32
* : 22.03.2022 0.04 Support for GSCE[3.3b]
* : 11.05.2022 0.05 Used the standard library
* Integrated LOAD_INFO
* Changed image_name table
* Changed check_load_area
* - Change RAM check process
* - Change address check process
* - Add Image check process
* - Processing integration
* Changed to processing for each device
* Change structure member name
* Added function return value judgment
* Changed LOGICAL_CONTENT_CERT_ADDR to
* get_logic_cont_cert_addr
* Changed uint32_t to uintptr_t
* Change log output
* Add argument of load_init()
* Change to error when key information is invalid
* Remove unnecessary type conversion
* : 11.07.2022 0.06 Change log output
* Support secure boot for S4
* Change load start processing other than 512byte align
* : 02.09.2022 0.07 Added 512byte boundary check
* : 31.10.2022 0.08 License notation change.
* : 21.08.2023 0.09 Add support for V4M.
* : 19.12.2024 0.10 Add support for RTOS#1 and RTOS#2.
* : 26.05.2025 0.11 Change key cert address of [CA_OPTIONAL_ID+2].
*****************************************************************************/
/* indelude */
#include <stdint.h>
#include <image_load.h>
#include <mem_io.h>
#include <log.h>
#include <image_load_emmc.h>
#include <emmc_multiboot.h>
#define KEY_SIZE_FLG_MSK (0x00000003U)
#define KEY_SIZE_BIT_SHIFT (21U)
#define CERT_INFO_FLG_OFFSET (0x0000000CU)
#define KEY_SIZE_4096 (0x00000002U)
#define KEY_SIZE_3072 (0x00000001U)
#define KEY_SIZE_2048 (0x00000000U)
#define WORD_TO_BYTE (4U)
#define NOT_OVERLAP_FLAG (0U)
#define OVERLAP_FLAG (1U)
#define RAM_RANGE_OK (0U)
#define RAM_RANGE_NG (1U)
#if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_1)
#define RAM_MAX (4U)
#elif (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3)
#define RAM_MAX (5U) /* ++ SRAM in RT-VRAM (0xE2000000 - 0xE200FFFF) */
#endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */
#define ADDRESS_RANGE_512 (512U)
static void check_load_area(LOAD_INFO* li);
static void get_info_from_cert(uint32_t cert_addr, uint32_t *size,
uint32_t *dest_addr);
void load_image(LOAD_INFO* li)
{
/* log output of load image for information */
load_image_info_print_for_emmc(li);
/* Check transfer range of image. */
check_load_area(li);
/* Image load start. */
load_start(li);
}
/* End of function load_image(LOAD_INFO* li) */
void load_init(LOAD_INFO* li, uint32_t num)
{
uint32_t loop;
uintptr_t buf;
const char *image_name[MAX_PLACED] = {
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
[RTOS_ID] = "RTOS",
#endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */
#ifdef MOBIS_PRK3
[CA_OPTIONAL_ID] = "BL31",
[CA_OPTIONAL_ID + 1] = "u-boot",
[CA_OPTIONAL_ID + 2] = "tee OS",
[CA_OPTIONAL_ID + 3] = "BL2",
[CA_OPTIONAL_ID + 4] = "QNX OS",
#else
[CA_OPTIONAL_ID] = "CA Program #1",
[CA_OPTIONAL_ID + 1] = "CA Program #2",
[CA_OPTIONAL_ID + 2] = "CA Program #3",
[CA_OPTIONAL_ID + 3] = "CA Program #4",
[CA_OPTIONAL_ID + 4] = "CA Program #5",
#endif
[CA_OPTIONAL_ID + 5] = "CA Program #6",
[CA_OPTIONAL_ID + 6] = "CA Program #7",
[CA_OPTIONAL_ID + 7] = "CA Program #8",
#if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3)
[RTOS1_ID] = "RTOS#1",
[RTOS2_ID] = "RTOS#2",
#endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */
};
const uint32_t key_cert[MAX_PLACED] = {
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
[RTOS_ID] = TFMV_KEY_CERT_ADDR,
#endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */
[CA_OPTIONAL_ID] = TFMV_KEY_CERT_ADDR, /* bl31 */
#if (RCAR_LSI == RCAR_S4)
[CA_OPTIONAL_ID + 1] = TFMV_KEY_CERT_ADDR,
#elif ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
[CA_OPTIONAL_ID + 1] = NTFMV_KEY_CERT_ADDR, /* u-boot */
#endif
#if (OPTEE_LOAD_ENABLE == OPTEE_DISABLE)
[CA_OPTIONAL_ID + 2] = NTFMV_KEY_CERT_ADDR,
#else
[CA_OPTIONAL_ID + 2] = TFMV_KEY_CERT_ADDR, /* tee OS */
#endif /* OPTEE_LOAD_ENABLE == OPTEE_DISABLE */
#if (BL2_LOAD_ENABLE == BL2_DISABLE)
[CA_OPTIONAL_ID + 3] = NTFMV_KEY_CERT_ADDR,
#else
[CA_OPTIONAL_ID + 3] = TFMV_KEY_CERT_ADDR, /* ca76-loader */
#endif /* BL2_LOAD_ENABLE == BL2_DISABLE */
[CA_OPTIONAL_ID + 4] = NTFMV_KEY_CERT_ADDR, /* qnx OS */
[CA_OPTIONAL_ID + 5] = NTFMV_KEY_CERT_ADDR,
[CA_OPTIONAL_ID + 6] = NTFMV_KEY_CERT_ADDR,
[CA_OPTIONAL_ID + 7] = NTFMV_KEY_CERT_ADDR,
#if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3)
[RTOS1_ID] = TFMV_KEY_CERT_ADDR,
[RTOS2_ID] = TFMV_KEY_CERT_ADDR,
#endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */
};
if (num >= 1U && num <= 8U)
{
/* Set Load info parameter */
for (loop = CA_OPTIONAL_ID; loop < CA_OPTIONAL_ID + num; loop++)
{
li[loop].name = image_name[loop];
li[loop].key_cert_addr = key_cert[loop];
li[loop].cnt_cert_addr = get_logic_cont_cert_addr(loop);
get_info_from_cert(li[loop].cnt_cert_addr, &li[loop].image_size, &li[loop].boot_addr);
buf = get_src_addr_offset_in_cert(loop);
li[loop].src_addr = (SRC_TOP + mem_read32(buf));
buf = get_part_num_in_cert(loop);
li[loop].part_num = mem_read32(buf);
li[loop].load_id = loop;
}
}
else
{
ERROR("load_init(CA program num error).\n");
panic;
}
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
li[RTOS_ID].name = image_name[RTOS_ID];
li[RTOS_ID].key_cert_addr = key_cert[RTOS_ID];
li[RTOS_ID].cnt_cert_addr = get_logic_cont_cert_addr(RTOS_ID);
get_info_from_cert(li[RTOS_ID].cnt_cert_addr, &li[RTOS_ID].image_size, &li[RTOS_ID].boot_addr);
buf = get_src_addr_offset_in_cert(RTOS_ID);
li[RTOS_ID].src_addr = (SRC_TOP + mem_read32(buf));
buf = get_part_num_in_cert(RTOS_ID);
li[RTOS_ID].part_num = mem_read32(buf);
li[RTOS_ID].load_id = RTOS_ID;
#if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3)
/* Set Load info parameter for RTOS#1 and RTOS#2 */
for (loop = RTOS1_ID; loop <= RTOS2_ID; loop++)
{
li[loop].name = image_name[loop];
li[loop].key_cert_addr = key_cert[loop];
li[loop].cnt_cert_addr = get_logic_cont_cert_addr(loop);
get_info_from_cert(li[loop].cnt_cert_addr, &li[loop].image_size, &li[loop].boot_addr);
buf = get_src_addr_offset_in_cert(loop);
li[loop].src_addr = (SRC_TOP + mem_read32(buf));
buf = get_part_num_in_cert(loop);
li[loop].part_num = mem_read32(buf);
li[loop].load_id = loop;
}
#endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */
#endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */
}/* End of function load_init(LOAD_INFO* li) */
void load_update_part_num(LOAD_INFO* li, uint32_t num, int slot)
{
uint32_t loop;
/* Set Load info parameter */
for (loop = CA_OPTIONAL_ID; loop < CA_OPTIONAL_ID + num; loop++)
{
li[loop].part_num = (slot == 1) ? 2 : 1;
}
li[RTOS_ID].part_num = (slot == 1) ? 2 : 1;
}
static void check_load_area(LOAD_INFO* li)
{
uint32_t src;
uint32_t dst;
uint32_t len;
uint32_t dst_end;
uint32_t overlap;
uint32_t loop;
uint32_t rge_chk_flg;
static uint32_t s_num = 1U;
/* The memory range of destination. */
const ADDRESS_RANGE add_list[RAM_MAX] = {
[TARGET_MEM_DRAM] = {DRAM_BASE, DRAM_END},
[TARGET_MEM_RTSRAM] = {RTSRAM_BASE, RTSRAM_END},
[TARGET_MEM_RTVRAM] = {RTVRAM_VBUF_TOP, RTVRAM_VBUF_END},
[TARGET_MEM_SYSRAM] = {SYSRAM_BASE, SYSRAM_END},
#if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3)
[TARGET_MEM_SRAM_IN_RTVRAM] = {RTVRAM_SRAM_TOP, RTVRAM_SRAM_END},
#endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */
};
/* The image range check */
const IMAGE_RANGE size_list[CA_IMAGESIZECHK_DEF] = {
{ CA_PROGRAM1_ID, CA_PROGRAM1_ADR, CA_PROGRAM1_SIZE},
{ CA_PROGRAM2_ID, CA_PROGRAM2_ADR, CA_PROGRAM2_SIZE},
#if (OPTEE_LOAD_ENABLE == OPTEE_ENABLE)
{ CA_PROGRAM3_ID, CA_PROGRAM3_ADR, CA_PROGRAM3_SIZE},
#endif /* OPTEE_LOAD_ENABLE == OPTEE_ENABLE */
#if (BL2_LOAD_ENABLE == BL2_ENABLE)
{ CA_PROGRAM4_ID, CA_PROGRAM4_ADR, CA_PROGRAM4_SIZE},
#endif /* BL2_LOAD_ENABLE == BL2_ENABLE */
#if (QNX_OS_LOAD_ENABLE == QNX_OS_ENABLE)
{ CA_PROGRAM5_ID, CA_PROGRAM5_ADR, CA_PROGRAM5_SIZE},
#endif /* QNX_OS_LOAD_ENABLE == QNX_OS_ENABLE */
};
static ADDRESS_RANGE s_placed_image[MAX_PLACED] = {
[0] = {IPL_TOP, IPL_END}
};
src = li->src_addr;
dst = li->boot_addr;
len = li->image_size;
/* Check image size */
if (len == 0U)
{
ERROR("image size error\n");
panic;
}
/* Check whether source is overflow */
/* INT30-C Pre confirmation */
if (src > (UINT32_MAX - len))
{
ERROR("1:overflow is occurred at source\n");
ERROR("1:source address = 0x%x image size = 0x%x\n", (unsigned int)src, (unsigned int)len);
panic;
}
/* Check whether destination is overflow */
/* INT30-C Pre confirmation */
if (dst > (UINT32_MAX - len))
{
ERROR("1:overflow is occurred at destination\n");
ERROR("1:destination address = 0x%x image size = 0x%x\n", (unsigned int)dst,
(unsigned int)len);
panic;
}
else
{
dst_end = dst + len - 1U;
}
/* Check source address range. */
/* No error check is performed because it is detected by the eMMC device */
/* Check destination address range. */
/* 512byte boundary check */
if (0U != (dst % ADDRESS_RANGE_512))
{
ERROR("check_load_area (destination address)\n");
ERROR("destination address = 0x%x \n", (unsigned int)dst);
panic;
}
/* range check */
rge_chk_flg = RAM_RANGE_NG;
for(loop = 0U; loop < RAM_MAX; loop++)
{
if (add_list[loop].cx_topadd <= dst)
{
if(dst_end <= add_list[loop].cx_endadd)
{
rge_chk_flg = RAM_RANGE_OK;
break;
}
}
}
if(rge_chk_flg != RAM_RANGE_OK)
{
ERROR("check_load_area (destination address)\n");
ERROR("destination address = 0x%x image size = 0x%x\n", (unsigned int)dst,
(unsigned int)len);
panic;
}
/* Check whether destination is overflow */
for (loop = 0U; loop < CA_IMAGESIZECHK_DEF; loop++)
{
if (li->load_id == size_list[loop].load_id)
{
if ((size_list[loop].image_adr != 0U) && (dst != size_list[loop].image_adr))
{
ERROR("check load area.(outside secure area)\n");
ERROR("destination address = 0x%x(0x%x) image size = 0x%x\n", (unsigned int)dst,
(unsigned int)(size_list[loop].image_adr), (unsigned int)len);
panic;
}
if ((size_list[loop].image_size != 0U) && (len > size_list[loop].image_size))
{
ERROR("check load area.(outside secure area)\n");
ERROR("destination address = 0x%x image size = 0x%x(0x%x)\n", (unsigned int)dst,
(unsigned int)len, (unsigned int)(size_list[loop].image_size));
panic;
}
}
}
/* Check there are no overlaps the image that will be loaded and
the images that have already loaded. */
overlap = NOT_OVERLAP_FLAG;
loop = 0U;
do
{
/* check overlap */
if ((dst >= s_placed_image[loop].cx_topadd)
&& (dst <= s_placed_image[loop].cx_endadd))
{
overlap = OVERLAP_FLAG;
}
else if ((dst_end >= s_placed_image[loop].cx_topadd)
&& (dst_end <= s_placed_image[loop].cx_endadd))
{
overlap = OVERLAP_FLAG;
}
else if ((dst < s_placed_image[loop].cx_topadd)
&& (s_placed_image[loop].cx_endadd < dst_end))
{
overlap = OVERLAP_FLAG;
}
else
{
loop++;
}
} while ((loop < s_num) && (overlap == NOT_OVERLAP_FLAG));
/* Check the overlap flag.
Parameter error if overwrite occurred.
Otherwise, add parameters of the image to be loaded into
Placed_image. */
if (overlap == NOT_OVERLAP_FLAG)
{
s_placed_image[s_num].cx_topadd = dst;
s_placed_image[s_num].cx_endadd = dst_end;
s_num++;
}
else
{
ERROR("check load area (overlap)\n");
ERROR("destination address = 0x%x image size = 0x%x\n", (unsigned int)dst, (unsigned int)len);
ERROR("overlapped image is [%u]\n", (unsigned int)loop);
ERROR("top address = 0x%x end address = 0x%x\n",
(unsigned int)s_placed_image[loop].cx_topadd, (unsigned int)s_placed_image[loop].cx_endadd);
panic;
}
}
/* End of function check_load_area(uint32_t dst, uint32_t src, uint32_t len) */
static void get_info_from_cert(uint32_t cert_addr, uint32_t *size,
uint32_t *dest_addr)
{
uint32_t val;
uint32_t certInfo1;
uintptr_t pSize;
uintptr_t pDestL;
/* Get key length of content certificate. */
val = mem_read32((uintptr_t)cert_addr + CERT_INFO_FLG_OFFSET);
certInfo1 = (val >> KEY_SIZE_BIT_SHIFT) & KEY_SIZE_FLG_MSK;
/* Get the transfer address and transfer size from
the certificate in accordance with the key length. */
if (KEY_SIZE_4096 == certInfo1) /* key size = 4096 */
{
pSize = cert_addr + CERT_INFO_SIZE_OFFSET2;
*size = mem_read32(pSize) * WORD_TO_BYTE;
pDestL = cert_addr + CERT_INFO_DST_OFFSET2;
*dest_addr = mem_read32(pDestL);
}
else if (KEY_SIZE_3072 == certInfo1) /* key size = 3072 */
{
pSize = cert_addr + CERT_INFO_SIZE_OFFSET1;
*size = mem_read32(pSize) * WORD_TO_BYTE;
pDestL = cert_addr + CERT_INFO_DST_OFFSET1;
*dest_addr = mem_read32(pDestL);
}
else if (KEY_SIZE_2048 == certInfo1) /* key size = 2048 */
{
pSize = cert_addr + CERT_INFO_SIZE_OFFSET;
*size = mem_read32(pSize) * WORD_TO_BYTE;
pDestL = cert_addr + CERT_INFO_DST_OFFSET;
*dest_addr = mem_read32(pDestL);
}
else
{
ERROR("get_info_from_cert key size error.\n");
panic;
}
}
/* End of function get_info_from_cert(uint32_t cert_addr, uint32_t *size, uint32_t *dest_addr) */
void load_start(LOAD_INFO* li)
{
uint32_t rtn_val = EMMC_DEV_ERR;
uint32_t sector_count;
uint32_t fraction;
/* Converted to number of sectors transferred. */
sector_count = li->image_size >> CX_EMMC_SECTOR_SIZE_SHIFT;
fraction = li->image_size % CX_EMMC_SECTOR_SIZE;
/* Add 1 if there is a fraction */
if(0U != fraction)
{
sector_count += 1U;
}
rtn_val = emmc_trans_data(li->part_num, (uintptr_t)(li->src_addr >> CX_EMMC_SECTOR_SIZE_SHIFT),
(uintptr_t)li->boot_addr, sector_count);
if(EMMC_DEV_OK != rtn_val)
{
ERROR("load_start(emmc_trans_data error).\n");
panic;
}
}
/* End of function load_start(LOAD_INFO* li) */