Files
E3/e3_176_ref/middleware/flashloader/bpt_update.c
2025-10-21 19:40:27 +08:00

456 lines
13 KiB
C

/**
* @file bpt_update.c
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include <board.h>
#include <bpt_v2.h>
#include <config.h>
#include <ctype.h>
#include <debug.h>
#include <flash_wrapper.h>
#include <param.h>
#include <sd_boot_img/sd_boot_img.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
sfs_t *sfs = NULL;
static uint8_t sfs_buffer[FL_SFS_SIZE] __ALIGNED(CONFIG_ARCH_CACHE_LINE);
uint8_t bpt_buffer[FL_BPT_HEDAER_LEN] __ALIGNED(CONFIG_ARCH_CACHE_LINE);
bpt_iib_t iib_info_temp __ALIGNED(CONFIG_ARCH_CACHE_LINE) = {0};
/* dump data */
void hexdump(const void *ptr, size_t len)
{
addr_t address = (addr_t)ptr;
size_t count;
for (count = 0; count < len; count += 16) {
union {
uint32_t buf[4];
uint8_t cbuf[16];
} u;
size_t s = ROUNDUP(MIN(len - count, 16), 4);
size_t i;
printf("0x%08x: ", address);
for (i = 0; i < s / 4; i++) {
u.buf[i] = ((const uint32_t *)address)[i];
printf("%08x ", u.buf[i]);
}
for (; i < 4; i++) {
printf(" ");
}
printf("|");
for (i = 0; i < 16; i++) {
unsigned char c = u.cbuf[i];
if (i < s && isprint(c)) {
printf("%c", c);
} else {
printf(".");
}
}
printf("|\r\n");
address += 16;
}
}
/* dump data */
static void BptInit(bpt_v2_t *bpt)
{
bpt->tag = FL_BPT_TAG_VAL;
bpt->reserved1 = 0;
bpt->size = FL_BPT_HEDAER_LEN;
bpt->sec_ver = 0;
bpt->digest_alg = 3;
memset(bpt->reserved2, 0, 19);
bpt->rcp.tag = FL_BPT_RCP_TAG;
bpt->rcp.size = FL_BPT_RCP_SIZE;
memset(&bpt->rcp.rot_id, 0, 1040);
memset(bpt->signature, 0, 512);
memset(bpt->key_wraps, 0, 512);
memset(bpt->reserved3, 0, 984);
bpt->sn = FL_BPT_PAGE_SN;
bpt->sn_inversion = ~(FL_BPT_PAGE_SN);
memset(bpt->reserved4, 0, 8);
}
/* add iib data */
static int BptAddIIB(bpt_iib_t *iib_info, uint32_t img_base, uint32_t bpt_base,
uint32_t link_base, uint32_t img_size, uint8_t core)
{
uint32_t img_offset;
img_offset = FLASH_ADDR_MASK((uint32_t)img_base);
if (img_offset >= (bpt_base + FL_BPT_HEDAER_LEN)) {
img_offset -= bpt_base;
} else {
ssdk_printf(SSDK_ALERT, "img_base 0x%x < bpt base 0x%x\r\n", img_base,
bpt_base);
return -1;
}
iib_info->tag = FL_BPT_IIB_TAG_VAL;
iib_info->size = FL_BPT_IIB_SIZE;
iib_info->reserved1 = 0;
memset(iib_info->dbg_ctrl, 0, 8);
memset(iib_info->did, 0, 8);
iib_info->img_type = 0;
iib_info->target_core = core;
iib_info->dec_ctrl = 0;
iib_info->reserved2 = 0;
memset(iib_info->iv, 0, 8);
iib_info->img_page = img_offset / FL_BPT_PAGE_SIZE;
iib_info->img_size = img_size;
if (link_base == 0) {
iib_info->load_addr = (uint32_t)img_base;
} else {
iib_info->load_addr = link_base;
}
iib_info->reserved3 = 0;
iib_info->entry = iib_info->load_addr;
iib_info->reserved4 = 0;
memset(iib_info->hash, 0x00, 64);
return 0;
}
/* get the iib image base */
uint32_t BptGetIIBImgbase(bpt_v2_t *bpt, uint8_t core)
{
bpt_iib_t *iib_info;
uint8_t idx;
for (idx = 0; idx < FL_BPT_IIB_NUM; idx++) {
iib_info = (bpt_iib_t *)(bpt->iib[idx]);
if (iib_info->tag == FL_BPT_IIB_TAG_VAL &&
iib_info->target_core == core) {
return (iib_info->img_page) * FL_BPT_PAGE_SIZE;
}
}
return 0;
}
/* mask an iib */
static void BptMaskIIB(bpt_v2_t *bpt, uint8_t core)
{
bpt_iib_t *iib_info;
uint8_t idx;
for (idx = 0; idx < FL_BPT_IIB_NUM; idx++) {
iib_info = (bpt_iib_t *)(bpt->iib[idx]);
if (iib_info->tag == FL_BPT_IIB_TAG_VAL &&
iib_info->target_core == core) {
memset(iib_info, 0, FL_BPT_IIB_SIZE);
break;
}
}
}
/* remove an empty iib*/
static void BptRemoveEmptyIIB(bpt_v2_t *bpt, uint8_t index)
{
bpt_iib_t *iib_info;
bpt_iib_t *iib_info_next;
uint8_t idx = index;
for (idx = index; idx < FL_BPT_IIB_NUM - 1; idx++) {
iib_info = (bpt_iib_t *)(bpt->iib[idx]);
iib_info_next = (bpt_iib_t *)(bpt->iib[idx + 1]);
if (iib_info->tag != FL_BPT_IIB_TAG_VAL) {
memcpy(iib_info, iib_info_next, FL_BPT_IIB_SIZE);
}
}
if (idx == (FL_BPT_IIB_NUM - 1)) {
iib_info = (bpt_iib_t *)(bpt->iib[idx]);
if (iib_info->tag != FL_BPT_IIB_TAG_VAL) {
memset(iib_info, 0, FL_BPT_IIB_SIZE);
}
}
}
/* exchange two iib's position */
static void BptExchangeIIB(bpt_v2_t *bpt, uint8_t index_des, uint8_t index_src)
{
bpt_iib_t *iib_info_des;
bpt_iib_t *iib_info_src;
iib_info_des = (bpt_iib_t *)(bpt->iib[index_des]);
iib_info_src = (bpt_iib_t *)(bpt->iib[index_src]);
memcpy(&iib_info_temp, iib_info_des, FL_BPT_IIB_SIZE);
memcpy(iib_info_des, iib_info_src, FL_BPT_IIB_SIZE);
memcpy(iib_info_src, &iib_info_temp, FL_BPT_IIB_SIZE);
}
/* search iib for one core */
static bpt_iib_t *BptSearchIIB(bpt_v2_t *bpt, uint8_t core)
{
bpt_iib_t *iib_info;
uint8_t idx;
uint8_t core_temp = core;
uint8_t core_remove = 0;
if (core == FL_BPT_CORE_CR5_SX) {
core = FL_BPT_CORE_CR5_SX0;
core_remove = FL_BPT_CORE_CR5_SX1;
}
if (core == FL_BPT_CORE_CR5_SP) {
core = FL_BPT_CORE_CR5_SP0;
core_remove = FL_BPT_CORE_CR5_SP1;
}
iib_info = (bpt_iib_t *)(bpt->iib[0]);
if ((iib_info->tag != FL_BPT_IIB_TAG_VAL) || (iib_info->target_core != 0)) {
ssdk_printf(SSDK_ALERT, "sf core not in bpt, download sf first\r\n");
return NULL;
}
for (idx = 1; idx < FL_BPT_IIB_NUM; idx++) {
iib_info = (bpt_iib_t *)(bpt->iib[idx]);
/* find same core */
if (iib_info->tag == FL_BPT_IIB_TAG_VAL &&
((iib_info->target_core == core) ||
(iib_info->target_core == core_temp))) {
/* if the core is lockstep, remove the split core sp1 or sx1*/
if (core_temp != core) {
BptMaskIIB(bpt, core_remove);
}
iib_info->target_core = core_temp;
return iib_info;
}
}
for (idx = 1; idx < FL_BPT_IIB_NUM; idx++) {
iib_info = (bpt_iib_t *)(bpt->iib[idx]);
/* find the first invalid tag core */
if (iib_info->tag != FL_BPT_IIB_TAG_VAL) {
return iib_info;
}
}
return NULL;
}
/* sort iib */
static void BptSortIIB(bpt_v2_t *bpt)
{
bpt_iib_t *iib_info;
bpt_iib_t *iib_info_next;
uint8_t idx;
uint8_t idy;
uint8_t min_idy;
for (idx = 1; idx < FL_BPT_IIB_NUM; idx++) {
BptRemoveEmptyIIB(bpt, idx);
}
for (idx = 1; idx < FL_BPT_IIB_NUM - 1; idx++) {
iib_info = (bpt_iib_t *)(bpt->iib[idx]);
if (iib_info->tag != FL_BPT_IIB_TAG_VAL)
break;
min_idy = idx;
for (idy = idx + 1; idy < FL_BPT_IIB_NUM; idy++) {
iib_info_next = (bpt_iib_t *)(bpt->iib[idy]);
if (iib_info_next->tag != FL_BPT_IIB_TAG_VAL)
break;
if (iib_info_next->target_core < iib_info->target_core) {
min_idy = idy;
} else if (iib_info_next->target_core == iib_info->target_core) {
memset(iib_info_next, 0, FL_BPT_IIB_SIZE);
BptRemoveEmptyIIB(bpt, idy);
}
}
if (min_idy != idx)
BptExchangeIIB(bpt, idx, min_idy);
}
return;
}
/* dump bpt information */
static int32_t dump_bpt_info(bpt_v2_t *bpt)
{
int i = 0;
bpt_iib_t *iib;
ssdk_printf(SSDK_ALERT,
"================= FL_BPT 0 ================= \r\n");
ssdk_printf(SSDK_ALERT, "bpt->tag = 0x%08x\r\n", bpt->tag);
ssdk_printf(SSDK_ALERT, "bpt->size = 0x%x\r\n", bpt->size);
ssdk_printf(SSDK_ALERT, "bpt->sec_version = 0x%08x\r\n",
bpt->sec_ver);
ssdk_printf(SSDK_ALERT, "bpt->hash_alg = 0x%x\r\n",
bpt->digest_alg);
ssdk_printf(SSDK_ALERT, "bpt->crc32 = 0x%08x\r\n", bpt->crc);
ssdk_printf(SSDK_ALERT, "bpt->pac_serial_num = 0x%08x\r\n", bpt->sn);
ssdk_printf(SSDK_ALERT, "bpt->inver_pac_serial_num = 0x%08x\r\n",
bpt->sn_inversion);
for (i = 0; i < FL_BPT_IIB_NUM; i++) {
iib = (bpt_iib_t *)(bpt->iib[i]);
if ((iib->tag != FL_BPT_IIB_TAG_VAL)) {
ssdk_printf(SSDK_ALERT, "iib[%d] is none\r\n", i);
break;
}
ssdk_printf(SSDK_ALERT, "--------\r\n");
ssdk_printf(SSDK_ALERT, "iib[%d]->tag = 0x%x\r\n", i,
iib->tag);
ssdk_printf(SSDK_ALERT, "iib[%d]->size = 0x%x\r\n", i,
iib->size);
ssdk_printf(SSDK_ALERT, "iib[%d]->image_type = 0x%x\r\n", i,
iib->img_type);
ssdk_printf(SSDK_ALERT, "iib[%d]->target_core = 0x%x\r\n", i,
iib->target_core);
ssdk_printf(SSDK_ALERT, "iib[%d]->decryp_ctl = 0x%x\r\n", i,
iib->dec_ctrl);
ssdk_printf(SSDK_ALERT, "iib[%d]->dev_logic_page = 0x%08x\r\n", i,
iib->img_page);
ssdk_printf(SSDK_ALERT, "iib[%d]->image_size = 0x%08x\r\n", i,
iib->img_size);
ssdk_printf(SSDK_ALERT, "iib[%d]->load_base = 0x%08x\r\n", i,
iib->load_addr);
ssdk_printf(SSDK_ALERT, "iib[%d]->entry_point = 0x%08x\r\n", i,
iib->entry);
}
return 0;
}
/* update bpt */
int BptUpdate(flash_wrapper_t *flash_wrapper, void *img_base,
uint32_t link_base, uint32_t img_size, uint8_t core)
{
bpt_v2_t *bpt;
bpt_iib_t *iib_info;
uint32_t bpt_base0, bpt_base1, bpt_base2;
int crc;
// read sfs
if (sfs == NULL) {
ssdk_printf(SSDK_ALERT, "read sfs error\r\n");
return -1;
}
bpt_base0 = sfs->normal_img_base;
bpt_base1 = sfs->backup_img_base;
bpt_base2 = sfs->third_img_base;
ssdk_printf(SSDK_ALERT, "bpt0: 0x%x, bpt1: 0x%x, bpt2: 0x%x\r\n", bpt_base0,
bpt_base1, bpt_base2);
flash_wrapper_read(flash_wrapper, (flash_addr_t)bpt_base0, bpt_buffer,
FL_BPT_HEDAER_LEN);
bpt = (bpt_v2_t *)bpt_buffer;
if (core == 0) {
BptInit(bpt);
iib_info = (bpt_iib_t *)(bpt->iib[0]);
} else {
iib_info = BptSearchIIB(bpt, core);
}
if (iib_info == NULL) {
ssdk_printf(SSDK_ALERT, "Find IIB error\r\n");
return -1;
}
if (BptAddIIB(iib_info, (uint32_t)img_base, bpt_base0, link_base, img_size,
core) < 0) {
return -1;
}
BptSortIIB(bpt);
crc = sfs_crc32(0, (uint8_t *)bpt, FL_BPT_CRC_CHECKSUM_OFFSET);
memcpy(&bpt->crc, &crc, 4);
if (flash_wrapper_erase(flash_wrapper, (flash_addr_t)bpt_base0,
FL_BPT_HEDAER_LEN)) {
ssdk_printf(SSDK_ALERT, " erase 0x%08x, length 0x%08x error",
(uint32_t)bpt_base0, FL_BPT_HEDAER_LEN);
return -1;
}
if (flash_wrapper_write(flash_wrapper, (flash_addr_t)bpt_base0, bpt_buffer,
FL_BPT_HEDAER_LEN)) {
ssdk_printf(SSDK_ALERT, " write 0x%08x, length 0x%08x error",
(uint32_t)bpt_base0, FL_BPT_HEDAER_LEN);
return -1;
}
if (flash_wrapper_read(flash_wrapper, (flash_addr_t)bpt_base0, bpt_buffer,
FL_BPT_HEDAER_LEN)) {
ssdk_printf(SSDK_ALERT, " read 0x%08x, length 0x%08x error",
(uint32_t)bpt_base0, FL_BPT_HEDAER_LEN);
return -1;
}
bpt = (bpt_v2_t *)bpt_buffer;
dump_bpt_info(bpt);
return 0;
}
/* read sfs in flash */
int read_sfs(flash_wrapper_t *flash_wrapper)
{
uint32_t crc_val = 0;
uint32_t crc_orig = 0;
flash_wrapper_read(flash_wrapper, FL_SFS_BASE, sfs_buffer, FL_SFS_SIZE);
ssdk_printf(SSDK_ALERT, "sfs dump\r\n");
hexdump(sfs_buffer, FL_SFS_SIZE);
sfs = (sfs_t *)sfs_buffer;
crc_orig = sfs->crc32;
crc_val = sfs_crc32(0, sfs_buffer, FL_SFS_SIZE - 4);
if (crc_val != crc_orig) {
ssdk_printf(SSDK_ALERT, "sfs crc_orig:0x%0x crc_val:0x%0x!\r\n",
crc_orig, crc_val);
sfs = NULL;
return -1;
}
ssdk_printf(SSDK_ALERT, "sfs tag = 0x%08x\r\n", sfs->tag);
ssdk_printf(SSDK_ALERT, "sfs freq = 0x%02x\r\n", sfs->freq);
ssdk_printf(SSDK_ALERT, "sfs sw_reset_info = 0x%02x\r\n",
sfs->sw_reset_info);
ssdk_printf(SSDK_ALERT, "sfs normal_img_base = 0x%08x\r\n",
sfs->normal_img_base);
ssdk_printf(SSDK_ALERT, "sfs backup_img_base = 0x%08x\r\n",
sfs->backup_img_base);
ssdk_printf(SSDK_ALERT, "sfs third_img_base = 0x%08x\r\n",
sfs->third_img_base);
ssdk_printf(SSDK_ALERT, "sfs crc32 = 0x%08x\r\n", sfs->crc32);
return 0;
}