sdk-hwV1.3/lichee/xr806/appos/project/common/cmd/cmd_trustzone.c

631 lines
16 KiB
C
Executable File

/*
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef CONFIG_TRUSTZONE
#include "cmd_util.h"
#include "sys/xr_debug.h"
#include "trustzone/nsc_table.h"
#include "trustzone/tz_thread.h"
#include "../src/trustzone/include/tz_internal_debug.h"
#include "kernel/os/os_semaphore.h"
#include "driver/chip/psram/psram.h"
#include "driver/chip/hal_dcache.h"
#include "driver/chip/hal_xip.h"
#include "sys/sys_heap.h"
typedef struct {
OS_Semaphore_t sem;
} cmd_tz_t;
static cmd_tz_t cmd_tz_priv;
typedef struct {
uint8_t task_idx;
uint8_t task_num;
uint32_t timeout_ms;
uint32_t test_sec;
uint32_t in_data1;
uint32_t in_data2;
uint32_t out_rst;
} tz_multi_acc_t;
static enum cmd_status cmd_tz_memr_exec(char *cmd)
{
int32_t cnt;
uint32_t addr, len;
cnt = cmd_sscanf(cmd, "%x %x", &addr, &len);
if (cnt != 2) {
return CMD_STATUS_INVALID_ARG;
}
tz_debug_memr_nsc(addr, len);
return CMD_STATUS_ACKED;
}
static enum cmd_status cmd_tz_memw_exec(char *cmd)
{
int32_t cnt;
uint32_t addr, len, value;
cnt = cmd_sscanf(cmd, "%x %x %x", &addr, &len, &value);
if (cnt != 3) {
return CMD_STATUS_INVALID_ARG;
}
if ((len != 1) && (len != 2) && (len != 4)) {
CMD_ERR("invalid len %x\n", len);
return CMD_STATUS_INVALID_ARG;
}
tz_debug_memw_nsc(addr, len, value);
return CMD_STATUS_ACKED;
}
static enum cmd_status cmd_tz_heap_press_exec(char *cmd)
{
int32_t cnt;
uint32_t test_num = 0, pass_num = 0;
cnt = cmd_sscanf(cmd, "n=%u", &test_num);
if (cnt != 1) {
return CMD_STATUS_INVALID_ARG;
}
test_num = test_num < 10000 ? 10000 : test_num;
pass_num = TEE_FUNC_CALL(tz_debug_heap_press_nsc, test_num);
if (pass_num == test_num) {
CMD_LOG(1, "%s test %d successful !\n", __func__, pass_num);
} else {
CMD_LOG(1, "%s test failed on the %d cycle !\n", __func__, pass_num);
}
return CMD_STATUS_ACKED;
}
static enum cmd_status cmd_tz_heap_space_exec(char *cmd)
{
uint8_t *start, *end, *current;
TEE_FUNC_CALL(TZ_GetHeapSpace_NSC, &start, &end, &current);
cmd_write_respond(CMD_STATUS_OK, "heap total %u, use %u, free %u, [%p, %p, %p)",
end - start, current - start, end - current, start, current, end);
return CMD_STATUS_ACKED;
}
static enum cmd_status cmd_tz_bkpt_exec(char *cmd)
{
uint32_t ret = 1;
ret = tz_debug_bkpt_nsc(1);
while (ret)
;
return CMD_STATUS_ACKED;
}
#if (defined(CONFIG_PSRAM))
/*
* @brief t = [0,1,2,3]
* 0-> sdma access ns-sram and s-sram
* 1-> sdma access ns-psram and s-psram
* 2-> sdma access s-flash
* 3-> sdma access ns-flash
* 4-> sdma access the 16KB sram which share with BLE
*/
static enum cmd_status cmd_tz_sdma_mem_exec(char *cmd)
{
int32_t cnt;
uint32_t i, type = 3, len = 0;
uint8_t *buf, *sram_buf, *psram_buf, data = 0x5a;
tz_remote_call_t rpc_t;
enum cmd_status ret = CMD_STATUS_ACKED;
cnt = cmd_sscanf(cmd, "t=%u l=%u", &type, &len);
if (cnt != 2) {
return CMD_STATUS_INVALID_ARG;
}
if ((len < 10) || (len > 0x1000) || (type > 4)) {
CMD_ERR("invalid params !\n");
return CMD_STATUS_FAIL;
}
sram_buf = (uint8_t *)cmd_malloc(len);
if (sram_buf == NULL) {
CMD_ERR("no sram heap space !\n");
}
psram_buf = (uint8_t *)psram_malloc(len);
if (psram_buf == NULL) {
CMD_ERR("no psram heap space !\n");
}
buf = sram_buf;
switch (type) {
case 0:
cmd_memset(buf, data, len);
break;
case 1:
buf = psram_buf;
cmd_memset(buf, data, len);
HAL_Dcache_Clean((uint32_t)buf, len);
break;
case 2:
rpc_t.retArg0 = 1;
ret = CMD_STATUS_FAIL;
break;
case 3:
rpc_t.retArg0 = 1;
rpc_t.arg3 = FLASH_XIP_START_ADDR;
ret = CMD_STATUS_FAIL;
break;
case 4:
buf = (uint8_t *)0x240000;
cmd_memset(buf, data, len);
break;
default:
break;
}
rpc_t.arg0 = (uint32_t)buf;
rpc_t.arg1 = len;
rpc_t.arg2 = type;
tz_sdma_test_nsc(&rpc_t);
if ((type != 2) && (type != 3)) {
for (i = 0; i < len; i++) {
if (buf[i] != (uint8_t)~data) {
break;
}
}
if (i != len) {
CMD_ERR("sdma test error, error index begin: %d, ref data:0x%x !\n", i, (uint8_t)~data);
print_hex_dump_bytes(buf, len);
} else {
CMD_LOG(1, "sdma test successful !\n");
}
} else {
if (!rpc_t.retArg0) {
ret = CMD_STATUS_ACKED;
CMD_LOG(1, "sdma test successful !\n");
}
}
cmd_free(sram_buf);
psram_free(psram_buf);
return ret;
}
#endif
static enum cmd_status cmd_tz_sdma_dev_exec(char *cmd)
{
int32_t cnt;
enum cmd_status ret = CMD_STATUS_FAIL;
uint32_t i, len = 0, secure = 0;
uint8_t *buf, digest[32];
tz_remote_call_t rpc_t;
cnt = cmd_sscanf(cmd, "s=%u l=%u", &secure, &len);
if (cnt != 2) {
return CMD_STATUS_INVALID_ARG;
}
if ((len < 10) || (len > 0x10000) || (secure > 1)) {
CMD_ERR("invalid params !\n");
return CMD_STATUS_FAIL;
}
buf = (uint8_t *)cmd_malloc(len);
if (buf == NULL) {
CMD_ERR("no heap space !\n");
goto out;
}
for (i = 0; i < len; i++) {
buf[i] = (i % 0x0a);
}
cmd_memset((void *)digest, 0, sizeof(digest));
rpc_t.arg0 = (uint32_t)buf;
rpc_t.arg1 = len;
rpc_t.arg2 = secure;
rpc_t.argPtr = (uint32_t *)digest;
if (tz_hw_sha256_nsc(&rpc_t) != RPC_OK) {
CMD_ERR("tz hw_sha256 run error.\n");
goto out;
}
CMD_LOG(1, "tz hw sha256 result ->\n");
print_hex_dump_bytes(digest, sizeof(digest));
ret = CMD_STATUS_ACKED;
out:
cmd_free(buf);
return ret;
}
static enum cmd_status cmd_tz_sdma_test_exec(char *cmd)
{
int32_t cnt, ret;
uint32_t src_addr, dst_addr, len;
tz_remote_call_t rpc_t;
cnt = cmd_sscanf(cmd, "s=%x d=%x l=%x", &src_addr, &dst_addr, &len);
if (cnt != 3) {
return CMD_STATUS_INVALID_ARG;
}
rpc_t.arg0 = src_addr;
rpc_t.arg1 = dst_addr;
rpc_t.arg2 = len;
ret = tz_sdma_test_random_nsc(&rpc_t);
if (ret == 0) {
CMD_LOG(1, "sdma test successful !\n");
} else {
CMD_LOG(1, "sdma test error !\n");
}
return CMD_STATUS_ACKED;
}
void cmd_tz_dma_callback(void *arg)
{
OS_SemaphoreRelease(&cmd_tz_priv.sem);
}
static enum cmd_status cmd_tz_ndma_test_exec(char *cmd)
{
int32_t cnt;
uint32_t src_addr, dst_addr, len;
DMA_Channel chan = DMA_CHANNEL_INVALID;
DMA_ChannelInitParam dmaParam;
cnt = cmd_sscanf(cmd, "s=%x d=%x l=%x", &src_addr, &dst_addr, &len);
if (cnt != 3) {
return CMD_STATUS_INVALID_ARG;
}
dmaParam.irqType = DMA_IRQ_TYPE_END;
dmaParam.endCallback = cmd_tz_dma_callback;
dmaParam.endArg = NULL;
OS_SemaphoreCreateBinary(&cmd_tz_priv.sem);
dmaParam.cfg = HAL_DMA_MakeChannelInitCfg(DMA_WORK_MODE_SINGLE,
DMA_WAIT_CYCLE_2,
DMA_BYTE_CNT_MODE_REMAIN,
DMA_DATA_WIDTH_8BIT,
DMA_BURST_LEN_1,
DMA_ADDR_MODE_INC,
DMA_PERIPH_SRAM,
DMA_DATA_WIDTH_8BIT,
DMA_BURST_LEN_1,
DMA_ADDR_MODE_INC,
DMA_PERIPH_SRAM);
chan = HAL_DMA_Request();
if (chan == DMA_CHANNEL_INVALID) {
return chan;
}
HAL_DMA_Init(chan, &dmaParam);
HAL_DMA_Start(chan, src_addr, dst_addr, len);
OS_SemaphoreWait(&cmd_tz_priv.sem, 5000);
CMD_LOG(1, "ndma test successful !\n");
OS_SemaphoreDelete(&cmd_tz_priv.sem);
HAL_DMA_Stop(chan);
HAL_DMA_DeInit(chan);
HAL_DMA_Release(chan);
return CMD_STATUS_ACKED;
}
static uint8_t task_end = 0;
static void cmd_tz_compete_resource_task(void *arg)
{
tz_remote_call_t rpc_t;
tz_multi_acc_t *task_priv = (tz_multi_acc_t *)arg;
static uint32_t run_time = 0;
OS_Time_t tick_current = 0, tick_record = 0;
OS_Time_t tick_end = OS_GetTicks() + OS_SecsToTicks(task_priv->test_sec);
rpc_t.arg0 = task_priv->in_data1;
rpc_t.arg1 = task_priv->in_data2;
rpc_t.arg2 = task_priv->timeout_ms;
while (tick_current < tick_end) {
OS_MSleep(task_priv->timeout_ms >> 1);
TEE_FUNC_CALL(tz_multi_access_nsc, &rpc_t);
tick_current = OS_GetTicks();
if (task_priv->task_idx == 0) {
if (OS_TicksToSecs(tick_current - tick_record) >= 10) {
run_time += 10;
CMD_LOG(1, "A total of %d %ss run normally %04ds...\n", task_priv->task_num, __func__, run_time);
tick_record = tick_current;
}
}
if (rpc_t.retArg0 != rpc_t.arg0 * rpc_t.arg1) {
CMD_ERR("expect result : %d, but get %d.\n", rpc_t.arg0 * rpc_t.arg1, rpc_t.retArg0);
break;
}
}
CMD_LOG(1, "%s task[%d] test finished, exit !\n", __func__, task_priv->task_idx);
if (++task_end == task_priv->task_num) {
CMD_LOG(1, "task competition %d times!\n", rpc_t.retArg1);
rpc_t.arg0 = 0xffffa55a;
TEE_FUNC_CALL(tz_multi_access_nsc, &rpc_t);
task_end = 0;
run_time = 0;
}
cmd_free(task_priv);
OS_ThreadDelete(NULL);
}
static enum cmd_status cmd_tz_multi_thread_exec(char *cmd)
{
int32_t cnt;
OS_Thread_t thread;
uint32_t thread_num, test_sec, i;
tz_multi_acc_t *task_priv;
cnt = cmd_sscanf(cmd, "r=%d t=%d", &thread_num, &test_sec);
if (cnt != 2) {
CMD_ERR("invalid argument %s\n", cmd);
return CMD_STATUS_FAIL;
}
if ((thread_num < 1) || (thread_num > 6) || (test_sec < 10)) {
CMD_ERR("invalid params !\n");
return CMD_STATUS_INVALID_ARG;
}
for (i = 0; i < thread_num; i++) {
task_priv = cmd_malloc(sizeof(tz_multi_acc_t));
if (!task_priv) {
CMD_ERR("no heap space !\n");
return CMD_STATUS_FAIL;
}
task_priv->task_num = thread_num;
task_priv->task_idx = i;
task_priv->test_sec = test_sec;
task_priv->timeout_ms = (thread_num - i) * 10;
task_priv->in_data1 = task_priv->timeout_ms;
task_priv->in_data2 = i + 2;
OS_ThreadSetInvalid(&thread);
if (OS_ThreadCreate(&thread,
"",
cmd_tz_compete_resource_task,
(void *)task_priv,
OS_THREAD_PRIO_APP,
2 * 1024) != OS_OK) {
CMD_ERR("create trustzone test task:%d failed\n", i);
return CMD_STATUS_FAIL;
}
}
return CMD_STATUS_OK;
}
static enum cmd_status cmd_tz_press_test_exec(char *cmd)
{
enum cmd_status ret = CMD_STATUS_FAIL;
int32_t cnt;
uint32_t i, test_sec = 0, size = 512;
tz_remote_call_t rpc_t;
uint8_t iv[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 1, 1};
uint8_t ctr[16];
uint8_t *in = NULL, *out = NULL, *dec = NULL;
OS_Time_t tick_current = 0, tick_record = 0, tick_end = 0;
static uint32_t run_time = 0;
cnt = cmd_sscanf(cmd, "t=%d", &test_sec);
if (cnt != 1) {
CMD_ERR("invalid argument %s\n", cmd);
return CMD_STATUS_FAIL;
}
if (test_sec < 1) {
CMD_ERR("invalid params !\n");
return CMD_STATUS_FAIL;
}
in = (uint8_t *)cmd_malloc(size);
if (!in) {
CMD_ERR("no heap space !\n");
goto error;
}
out = (uint8_t *)cmd_malloc(size);
if (!out) {
CMD_ERR("no heap space !\n");
goto error;
}
dec = (uint8_t *)cmd_malloc(size);
if (!dec) {
CMD_ERR("no heap space !\n");
goto error;
}
for (i = 0; i < size; i++) {
in[i] = (i & 0xff);
}
tick_end = OS_GetTicks() + OS_SecsToTicks(test_sec);
while (tick_current < tick_end) {
rpc_t.argPtr = (uint32_t *)out;
rpc_t.arg1 = size;
rpc_t.arg2 = (uint32_t)in;
rpc_t.arg3 = size;
cmd_memcpy(ctr, iv, sizeof(ctr));
if (AES_Decrypt_NSC(&rpc_t, ctr, AES_MODE_NSC_CTR) != RPC_OK) {
CMD_ERR("aes_ctr encrypt test failure !\n");
break;
} else {
rpc_t.argPtr = (uint32_t *)dec;
rpc_t.arg1 = size;
rpc_t.arg2 = (uint32_t)out;
rpc_t.arg3 = size;
cmd_memcpy(ctr, iv, sizeof(ctr));
if (AES_Decrypt_NSC(&rpc_t, ctr, AES_MODE_NSC_CTR) != RPC_OK) {
CMD_ERR("aes_ctr decyrpt test failure !\n");
break;
}
}
if (cmd_memcmp(in, dec, size)) {
CMD_ERR("aes_crt test error, decrypt data :!\n");
print_hex_dump_bytes(dec, size);
break;
} else {
tick_current = OS_GetTicks();
if (OS_TicksToSecs(tick_current - tick_record) >= 10) {
run_time += 10;
CMD_LOG(1, "%s run normally %04ds...\n", __func__, run_time);
tick_record = tick_current;
}
OS_MSleep(5);
}
}
if (tick_current >= tick_end) {
CMD_LOG(1, "tz pressure test successful !\n");
ret = CMD_STATUS_OK;
}
run_time = 0;
error:
cmd_free(dec);
cmd_free(out);
cmd_free(in);
return ret;
}
static enum cmd_status cmd_tz_ahb_set_exec(char *cmd)
{
int32_t cnt;
uint32_t dev_id, sec_en;
cnt = cmd_sscanf(cmd, "d=%d s=%d", &dev_id, &sec_en);
if (cnt != 2) {
CMD_ERR("invalid argument %s\n", cmd);
return CMD_STATUS_FAIL;
}
if (dev_id > 31 || sec_en > 1) {
CMD_ERR("invalid params !\n");
return CMD_STATUS_FAIL;
}
cmd_write_respond(CMD_STATUS_OK, "OK");
tz_ahb_secure_set_nsc(dev_id, sec_en);
return CMD_STATUS_OK;
}
static enum cmd_status cmd_tz_apb_set_exec(char *cmd)
{
int32_t cnt;
uint32_t dev_id, sec_en;
cnt = cmd_sscanf(cmd, "d=%d s=%d", &dev_id, &sec_en);
if (cnt != 2) {
CMD_ERR("invalid argument %s\n", cmd);
return CMD_STATUS_FAIL;
}
if (dev_id > 31 || sec_en > 1) {
CMD_ERR("invalid params !\n");
return CMD_STATUS_FAIL;
}
cmd_write_respond(CMD_STATUS_OK, "OK");
tz_apb_secure_set_nsc(dev_id, sec_en);
return CMD_STATUS_OK;
}
#if (defined(CONFIG_TZ_PSRAM))
static enum cmd_status cmd_tz_psram_run_exec(char *cmd)
{
cmd_write_respond(CMD_STATUS_OK, "OK");
tz_psram_run_exec();
return CMD_STATUS_OK;
}
static const struct cmd_data g_tz_psram_cmds[] = {
{ "run", cmd_tz_psram_run_exec },
};
static enum cmd_status cmd_tz_psram_exec(char *cmd)
{
return cmd_exec(cmd, g_tz_psram_cmds, cmd_nitems(g_tz_psram_cmds));
}
#endif
static enum cmd_status cmd_tz_sau_info_exec(char *cmd)
{
cmd_write_respond(CMD_STATUS_OK, "OK");
tz_sau_info_nsc();
return CMD_STATUS_OK;
}
static const struct cmd_data g_tz_cmds[] = {
{ "mem-read", cmd_tz_memr_exec },
{ "mem-write", cmd_tz_memw_exec },
{ "heap-space", cmd_tz_heap_space_exec },
{ "heap-press", cmd_tz_heap_press_exec },
{ "break", cmd_tz_bkpt_exec },
#if (defined(CONFIG_PSRAM))
{ "sdma-mem", cmd_tz_sdma_mem_exec },
#if (defined(CONFIG_TZ_PSRAM))
{ "tz_psram", cmd_tz_psram_exec},
#endif
#endif
{ "sdma-dev", cmd_tz_sdma_dev_exec },
{ "sdma-test", cmd_tz_sdma_test_exec },
{ "ndma-test", cmd_tz_ndma_test_exec },
{ "multi-thread", cmd_tz_multi_thread_exec },
{ "press-test", cmd_tz_press_test_exec },
{ "ahb-set", cmd_tz_ahb_set_exec},
{ "apb-set", cmd_tz_apb_set_exec},
{ "sau-config", cmd_tz_sau_info_exec},
};
enum cmd_status cmd_trustzone_exec(char *cmd)
{
return cmd_exec(cmd, g_tz_cmds, cmd_nitems(g_tz_cmds));
}
#endif