Files
base/middleware/dloader/dloader_test.c
2025-11-07 09:57:14 +08:00

567 lines
17 KiB
C

/**
* @file dloader_test.c
*
* Copyright (c) 2021 Semidrive Semiconductor.
* All rights reserved.
*
* Description:
*
* Revision History:
* -----------------
*/
#include <CLI.h>
#include <armv7-r/cache.h>
#include <board.h>
#include <ctype.h>
#include <debug.h>
#include <md5.h>
#include <param.h>
#include <part.h>
#include <partition_parser.h>
#include <sd_boot_img.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <types.h>
#include "checksum/crc32.h"
#include "dloader.h"
#if CONFIG_E3104 == 0
#define DL_TEST_STACK_SIZE 8192
#define DL_TEST_ARGV_NUM 10
#define DL_TEST_ARGV_LEN 50
#if CONFIG_DLOADER_BLOCK_IO_MODE
#define DL_LENGTH_ALIGN 512
#else
#define DL_LENGTH_ALIGN 128
#endif
#define DL_ADDR_ALIGN 512
#define DL_MD5RAM_ALIGN 512
#define DL_MD5DISK_ALIGN 512
typedef struct dl_test_arg {
int argc;
char argv[DL_TEST_ARGV_NUM][DL_TEST_ARGV_LEN];
} dl_test_arg_t;
static dl_test_arg_t dl_test_arg = {0};
static SemaphoreHandle_t new_msg_event;
static TaskHandle_t dloader_process_thread;
extern uint32_t sfs_get_image_base(DL_STATE_T *ds, uint8_t num);
extern int32_t get_bpt_info(struct bpt *bpt, uint8_t *buffer, uint32_t len);
/**
* @brief hexdump an buffer. The addresss could be set
* @param disk_addr
* @param ptr
* @param len
*/
static void dl_hexdump(uint64_t disk_addr, 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: ", (uint32_t)disk_addr);
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("|\n");
address += 16;
disk_addr += 16;
}
}
/**
* @brief Get the inst num of disk
* @param partiton_type
* @return uint8_t
*/
static uint8_t get_inst_num(PARTITION_TYPE_E partiton_type)
{
uint8_t inst_num = 0;
if (TYPE_BOOT_PACK0 == partiton_type)
inst_num = 1;
else if (TYPE_BOOT_PACK1 == partiton_type)
inst_num = 2;
DBG("disk_inst= %d\n", inst_num);
return inst_num;
}
static uint8_t read_bpt(DL_STATE_T *ds, uint8_t bpt_num)
{
struct bpt *bpt = NULL;
struct iib *iib = NULL;
uint64_t addr = 0;
uint64_t length = 0;
uint8_t inst_num = 0;
uint32_t crc32_val = 0;
uint32_t i = 0;
if (ds->disk_type == NORFLASH) {
addr = sfs_get_image_base(ds, bpt_num);
inst_num = 0;
} else if (0 == bpt_num) {
addr = 0;
inst_num = 1;
} else if (1 == bpt_num) {
addr = 0;
inst_num = 2;
} else if (2 == bpt_num) {
addr = 0x5000;
inst_num = 0;
}
length = 0x1000;
DBG("read inst %d addr 0x%llx, len %lld for BPT\n", inst_num, addr, length);
memset((uint8_t *)dl_scratch_base, 0, length);
if (dl_disk_read(ds->disk_inst[inst_num], addr, (uint8_t *)dl_scratch_base,
length)) {
ERROR("read storage failed\n");
return 1;
}
crc32_val = sfs_crc32(0, (uint8_t *)dl_scratch_base, 0xFEC);
bpt = (struct bpt *)pvPortMallocAligned(sizeof(struct bpt), ds->block_size);
if (0 != get_bpt_info(bpt, (uint8_t *)dl_scratch_base, length)) {
free(bpt);
return 1;
} else {
DBG("bpt->tag = 0x%08x\n", bpt->tag);
DBG("bpt->size = 0x%x\n", bpt->size);
DBG("bpt->sec_version = 0x%08x\n", bpt->sec_version);
DBG("bpt->hash_alg = 0x%x\n", bpt->hash_alg);
DBG("bpt->crc32 = 0x%08x(crc32_val=0x%08x)\n",
bpt->crc32, crc32_val);
DBG("bpt->pac_serial_num = 0x%08x\n", bpt->pac_serial_num);
DBG("bpt->inver_pac_serial_num = 0x%08x\n", bpt->inver_pac_serial_num);
for (i = 0; i < 8; i++) {
iib = &bpt->iib[i];
if ((iib->tag != IIB_TAG)) {
DBG("iib[%d] is none\n", i);
break;
}
DBG("--------\n");
DBG("iib[%d]->tag = 0x%x\n", i, iib->tag);
DBG("iib[%d]->size = 0x%x\n", i, iib->size);
DBG("iib[%d]->image_type = 0x%x\n", i, iib->image_type);
DBG("iib[%d]->target_core = 0x%x\n", i, iib->target_core);
DBG("iib[%d]->decryp_ctl = 0x%x\n", i, iib->decryp_ctl);
DBG("iib[%d]->dev_logic_page = 0x%08x\n", i, iib->dev_logic_page);
DBG("iib[%d]->image_size = 0x%08x\n", i, iib->image_size);
DBG("iib[%d]->load_base = 0x%08x\n", i, iib->load_base);
DBG("iib[%d]->entry_point = 0x%08x\n", i, iib->entry_point);
}
free(bpt);
return 0;
}
}
/**
* @brief dloader test thread
* @param arg
*/
static void dloader_test_thread(void *arg)
{
uint64_t length_total = 0;
uint32_t total_sec = 0;
uint32_t left_sec = 0;
uint32_t i = 0;
uint8_t inst_num = 0;
char *addrsuffix;
uint32_t crc32_val = 0;
uint8_t md5_calc[MD5_LEN] = {0};
struct MD5Context context;
DL_STATE_T *ds = NULL;
uint64_t addr = 0;
uint64_t length = 0;
DL_ERR_CODE_E err;
while (true) {
if (pdTRUE != xSemaphoreTake(new_msg_event, portMAX_DELAY)) {
break;
}
DBG("dloader thread active\n");
ds = NULL;
inst_num = 0;
crc32_val = 0;
memset(md5_calc, 0, MD5_LEN);
/* disk read test */
if (!strcmp(dl_test_arg.argv[0], "read")) {
if (dl_test_arg.argc < 2) {
ERROR("dl read need at least 2 arg\n");
continue;
}
ds = parse_partition_name((const char *)dl_test_arg.argv[1], &err);
if (!ds) {
ERROR("partition name error\n");
continue;
}
if (ds->disk_type == MMC)
inst_num = get_inst_num(ds->partiton_type);
/* read sfs */
if (!strcmp(ds->ptname, "sfs") && (ds->disk_type == NORFLASH)) {
DBG("read sfs\n");
read_sfs(ds);
continue;
}
if (!strcmp(ds->ptname, "rfd") && (ds->disk_type == NORFLASH)) {
DBG("read rfd\n");
read_rfd(ds);
continue;
}
/* read partition table */
if (!strcmp(ds->ptname, "partition")) {
DBG("read partition\n");
ptdev_read_table(ds->ptdev);
ptdev_dump(ds->ptdev);
continue;
}
/* read a partition address in storage device */
else if (!strcmp(ds->ptname, "bpt0")) {
read_bpt(ds, 0);
continue;
}
/* read a partition address in storage device */
else if (!strcmp(ds->ptname, "bpt1")) {
read_bpt(ds, 1);
continue;
}
/* read a partition address in storage device */
else if (!strcmp(ds->ptname, "bpt2")) {
read_bpt(ds, 2);
continue;
}
/* read a partition address in storage device */
else if (dl_test_arg.argc <= 3 && 0 == inst_num) {
if (!ds->ptdev) {
ERROR("partition is null\n");
continue;
}
addr = ptdev_get_offset(ds->ptdev, ds->ptname);
length = ptdev_get_size(ds->ptdev, ds->ptname);
DBG("read partition cmd addr 0x%llx, len %lld\n", addr, length);
if (dl_test_arg.argc == 3) {
DBG("argv[2] = %s(0x%08x)\n", dl_test_arg.argv[2],
atoi(dl_test_arg.argv[2]));
length = atoi(dl_test_arg.argv[2]);
DBG("length is changed to %lld\n", length);
}
if (!length || addr % DL_ADDR_ALIGN ||
length % DL_LENGTH_ALIGN) {
ERROR("do not align\n");
continue;
}
total_sec = length / DL_LENGTH_ALIGN;
for (i = 0; i < total_sec; i++) {
memset((uint8_t *)dl_scratch_base, 0, DL_LENGTH_ALIGN);
if (dl_disk_read(ds->disk_inst[0], addr,
(uint8_t *)dl_scratch_base,
DL_LENGTH_ALIGN)) {
ERROR("read storage failed\n");
continue;
}
dl_hexdump(addr, (void *)dl_scratch_base, DL_LENGTH_ALIGN);
addr += DL_LENGTH_ALIGN;
}
continue;
}
/* read any address in storage device */
else if (dl_test_arg.argc == 4) {
addr = (addr_t)strtoull(dl_test_arg.argv[2], &addrsuffix, 16);
length = atoi(dl_test_arg.argv[3]);
DBG("read addr cmd addr 0x%llx, len %lld\n", addr, length);
if (addr % DL_ADDR_ALIGN || length % DL_LENGTH_ALIGN ||
!length) {
ERROR("do not align\n");
continue;
}
if (dl_disk_read(ds->disk_inst[inst_num], addr,
(uint8_t *)dl_scratch_base,
MIN(length, dl_scratch_sz))) {
ERROR("read storage failed\n");
continue;
}
dl_hexdump((uint64_t)atoi(dl_test_arg.argv[2]),
(void *)dl_scratch_base, atoi(dl_test_arg.argv[3]));
crc32_val = crc32(0, (uint8_t *)dl_scratch_base,
MIN(length, dl_scratch_sz));
DBG("crc32_val = 0x%08x\n", crc32_val);
}
}
/* md5 calc for disk */
else if (!strcmp(dl_test_arg.argv[0], "md5disk")) {
if (dl_test_arg.argc != 4) {
ERROR("md5disk need 4 arg\n");
continue;
}
ds = parse_partition_name((const char *)dl_test_arg.argv[1], &err);
if (!ds) {
ERROR("partition name error\n");
continue;
}
if (ds->disk_type == MMC)
inst_num = get_inst_num(ds->partiton_type);
addr = (addr_t)strtoull(dl_test_arg.argv[2], &addrsuffix, 16);
length = atoi(dl_test_arg.argv[3]);
printf("disk md5 cmd addr 0x%llx, len %lld\n", addr, length);
MD5Init(&context);
if (addr % DL_ADDR_ALIGN || length % DL_LENGTH_ALIGN) {
ERROR("do not align\n");
continue;
}
total_sec = length / DL_LENGTH_ALIGN;
for (i = 0; i < total_sec; i++) {
memset((uint8_t *)dl_scratch_base, 0, DL_LENGTH_ALIGN);
if (dl_disk_read(ds->disk_inst[inst_num], addr,
(uint8_t *)dl_scratch_base, DL_LENGTH_ALIGN)) {
ERROR("read storage failed\n");
continue;
}
crc32_val = crc32(crc32_val, (uint8_t *)dl_scratch_base,
DL_LENGTH_ALIGN);
MD5Update(&context, (uint8_t *)dl_scratch_base,
DL_LENGTH_ALIGN);
addr += DL_LENGTH_ALIGN;
}
DBG("crc32_val = 0x%08x\n", crc32_val);
MD5Final(md5_calc, &context);
dl_hexdump(0, (void *)md5_calc, MD5_LEN);
continue;
}
/* md5 calc for ram */
else if (!strcmp(dl_test_arg.argv[0], "md5ram")) {
if (dl_test_arg.argc != 3) {
ERROR("md5ram need 3 arg\n");
continue;
}
addr = (addr_t)strtoull(dl_test_arg.argv[1], &addrsuffix, 16);
length = atoi(dl_test_arg.argv[2]);
printf("ram md5 cmd addr 0x%llx, len %lld\n", addr, length);
MD5Init(&context);
if (addr % DL_ADDR_ALIGN || length % DL_LENGTH_ALIGN) {
ERROR("do not align\n");
continue;
}
total_sec = length / DL_MD5RAM_ALIGN;
for (i = 0; i < total_sec; i++) {
memset((uint8_t *)dl_scratch_base, 0, DL_MD5RAM_ALIGN);
memcpy((uint8_t *)dl_scratch_base, (void *)(uint32_t)addr,
DL_MD5RAM_ALIGN);
crc32_val = crc32(crc32_val, (uint8_t *)dl_scratch_base,
DL_MD5RAM_ALIGN);
MD5Update(&context, (uint8_t *)dl_scratch_base,
DL_MD5RAM_ALIGN);
addr += DL_MD5RAM_ALIGN;
}
DBG("crc32_val = 0x%08x\n", crc32_val);
MD5Final(md5_calc, &context);
dl_hexdump(0, (void *)md5_calc, MD5_LEN);
continue;
}
/* flash command test */
else if (!strcmp(dl_test_arg.argv[0], "flash")) {
if (dl_test_arg.argc != 4) {
ERROR("dl flash need at least 4 arg\n");
continue;
}
addr = (addr_t)strtoull(dl_test_arg.argv[2], &addrsuffix, 16);
length_total = (uint32_t)atoi(dl_test_arg.argv[3]);
DBG("flash cmd = %s, addr 0x%llx, len %lld\n",
(const char *)dl_test_arg.argv[1], addr, length_total);
total_sec = ((uint32_t)length_total) / dl_data_sz;
left_sec = ((uint32_t)length_total) % dl_data_sz;
DBG("total_sec = %d, left_sec = %d \n", total_sec, left_sec);
for (i = 0; i <= total_sec; i++) {
if (i == total_sec) {
length = left_sec;
} else {
length = dl_data_sz;
}
if (0 == (uint32_t)length)
break;
DBG("flash data from addr = %d, length = %d \n", (uint32_t)addr,
(uint32_t)length);
md5((const uint8_t *)(uint32_t)addr, length, md5_received);
if (dl_cmd_flash((const char *)dl_test_arg.argv[1],
(void *)(uint32_t)addr, (uint32_t)length)) {
ERROR("dl_cmd_flash error\n");
continue;
}
addr += length;
}
DBG("md5_received :\n");
dl_hexdump(0, (void *)md5_received, MD5_LEN);
DBG("dl_cmd_flash finish\n");
continue;
}
/* erase command test*/
else if (!strcmp(dl_test_arg.argv[0], "erase")) {
if (dl_test_arg.argc != 2) {
ERROR("dl flash need at least 2 arg\n");
continue;
}
DBG("cmd = %s\n", (const char *)dl_test_arg.argv[1]);
dl_cmd_erase((const char *)dl_test_arg.argv[1], dl_data_base, 0);
continue;
}
}
}
/**
* @brief test app for dloader
* @param argc
* @param argv
* @return int
*/
static int dloader_test(int argc, char *argv[])
{
int i = 0;
static bool dl_test_thread_on = 0;
if (0 == dl_test_thread_on) {
if (!strcmp(argv[0], "init")) {
dl_test_thread_on = 1;
/* test thread */
new_msg_event = xSemaphoreCreateCounting(1, 0);
xTaskCreate(dloader_test_thread, "dloader_test", DL_TEST_STACK_SIZE,
NULL, (tskIDLE_PRIORITY + 2), &dloader_process_thread);
if (!dloader_process_thread) {
ERROR("failed to dloader_test process thread\n");
return CLI_FALSE;
}
DBG("download test init success\n");
return CLI_FALSE;
}
}
if (argc == 0) {
ERROR("need in put arg\n");
return CLI_FALSE;
}
if (argc > DL_TEST_ARGV_NUM) {
ERROR("too many arg\n");
return CLI_FALSE;
}
DBG("dloader argc = %d\n", argc);
dl_test_arg.argc = argc;
for (i = 0; i < dl_test_arg.argc; i++) {
memset(dl_test_arg.argv[i], 0, DL_TEST_ARGV_LEN);
strncpy(dl_test_arg.argv[i], argv[i], DL_TEST_ARGV_LEN - 1);
DBG("dl_test_arg.argc[%d] = %s\n", i, dl_test_arg.argv[i]);
}
DBG("event set!\r\n");
xSemaphoreGive(new_msg_event);
return CLI_FALSE;
}
CLI_CMD("dl", "download test", dloader_test);
#endif