You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
656 lines
20 KiB
656 lines
20 KiB
/*
|
|
* Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <inttypes.h>
|
|
#include <stdint.h>
|
|
|
|
#include "../../services/std_svc/spm/el3_spmc/spmc.h"
|
|
#include "../../services/std_svc/spm/el3_spmc/spmc_shared_mem.h"
|
|
#include <arch_features.h>
|
|
#include <arch_helpers.h>
|
|
#include <bl32/tsp/tsp.h>
|
|
#include <common/bl_common.h>
|
|
#include <common/debug.h>
|
|
#include "ffa_helpers.h"
|
|
#include <lib/psci/psci.h>
|
|
#include <lib/spinlock.h>
|
|
#include <lib/xlat_tables/xlat_tables_defs.h>
|
|
#include <lib/xlat_tables/xlat_tables_v2.h>
|
|
#include <plat/common/platform.h>
|
|
#include <platform_tsp.h>
|
|
#include <services/ffa_svc.h>
|
|
#include "tsp_private.h"
|
|
|
|
#include <platform_def.h>
|
|
|
|
static ffa_endpoint_id16_t tsp_id, spmc_id;
|
|
uint8_t mem_region_buffer[4096 * 2] __aligned(PAGE_SIZE);
|
|
|
|
/* Partition Mailbox. */
|
|
static uint8_t send_page[PAGE_SIZE] __aligned(PAGE_SIZE);
|
|
static uint8_t recv_page[PAGE_SIZE] __aligned(PAGE_SIZE);
|
|
|
|
/*
|
|
* Declare a global mailbox for use within the TSP.
|
|
* This will be initialized appropriately when the buffers
|
|
* are mapped with the SPMC.
|
|
*/
|
|
static struct mailbox mailbox;
|
|
|
|
/*******************************************************************************
|
|
* This enum is used to handle test cases driven from the FF-A Test Driver.
|
|
******************************************************************************/
|
|
/* Keep in Sync with FF-A Test Driver. */
|
|
enum message_t {
|
|
/* Partition Only Messages. */
|
|
FF_A_RELAY_MESSAGE = 0,
|
|
|
|
/* Basic Functionality. */
|
|
FF_A_ECHO_MESSAGE,
|
|
FF_A_RELAY_MESSAGE_EL3,
|
|
|
|
/* Memory Sharing. */
|
|
FF_A_MEMORY_SHARE,
|
|
FF_A_MEMORY_SHARE_FRAGMENTED,
|
|
FF_A_MEMORY_LEND,
|
|
FF_A_MEMORY_LEND_FRAGMENTED,
|
|
|
|
FF_A_MEMORY_SHARE_MULTI_ENDPOINT,
|
|
FF_A_MEMORY_LEND_MULTI_ENDPOINT,
|
|
|
|
LAST,
|
|
FF_A_RUN_ALL = 255,
|
|
FF_A_OP_MAX = 256
|
|
};
|
|
|
|
#if SPMC_AT_EL3
|
|
extern void tsp_cpu_on_entry(void);
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
* Test Functions.
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Enable the TSP to forward the received message to another partition and ask
|
|
* it to echo the value back in order to validate direct messages functionality.
|
|
******************************************************************************/
|
|
static int ffa_test_relay(uint64_t arg0,
|
|
uint64_t arg1,
|
|
uint64_t arg2,
|
|
uint64_t arg3,
|
|
uint64_t arg4,
|
|
uint64_t arg5,
|
|
uint64_t arg6,
|
|
uint64_t arg7)
|
|
{
|
|
smc_args_t ffa_forward_result;
|
|
ffa_endpoint_id16_t receiver = arg5;
|
|
|
|
ffa_forward_result = ffa_msg_send_direct_req(ffa_endpoint_source(arg1),
|
|
receiver,
|
|
FF_A_ECHO_MESSAGE, arg4,
|
|
0, 0, 0);
|
|
return ffa_forward_result._regs[3];
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* This function handles memory management tests, currently share and lend.
|
|
* This test supports the use of FRAG_RX to use memory descriptors that do not
|
|
* fit in a single 4KB buffer.
|
|
******************************************************************************/
|
|
static int test_memory_send(ffa_endpoint_id16_t sender, uint64_t handle,
|
|
ffa_mtd_flag32_t flags, bool multi_endpoint)
|
|
{
|
|
struct ffa_mtd *m;
|
|
struct ffa_emad_v1_0 *receivers;
|
|
struct ffa_comp_mrd *composite;
|
|
int ret, status = 0;
|
|
unsigned int mem_attrs;
|
|
char *ptr;
|
|
ffa_endpoint_id16_t source = sender;
|
|
uint32_t total_length, recv_length = 0;
|
|
|
|
/*
|
|
* In the case that we're testing multiple endpoints choose a partition
|
|
* ID that resides in the normal world so the SPMC won't detect it as
|
|
* invalid.
|
|
* TODO: Should get endpoint receiver id and flag as input from NWd.
|
|
*/
|
|
uint32_t receiver_count = multi_endpoint ? 2 : 1;
|
|
ffa_endpoint_id16_t test_receivers[2] = { tsp_id, 0x10 };
|
|
|
|
/* Ensure that the sender ID resides in the normal world. */
|
|
if (ffa_is_secure_world_id(sender)) {
|
|
ERROR("Invalid sender ID 0x%x.\n", sender);
|
|
return FFA_ERROR_DENIED;
|
|
}
|
|
|
|
if (!memory_retrieve(&mailbox, &m, handle, source, test_receivers,
|
|
receiver_count, flags, &recv_length,
|
|
&total_length)) {
|
|
return FFA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
receivers = (struct ffa_emad_v1_0 *)
|
|
((uint8_t *) m + m->emad_offset);
|
|
while (total_length != recv_length) {
|
|
smc_args_t ffa_return;
|
|
uint32_t frag_length;
|
|
|
|
ffa_return = ffa_mem_frag_rx(handle, recv_length);
|
|
|
|
if (ffa_return._regs[0] == FFA_ERROR) {
|
|
WARN("TSP: failed to resume mem with handle %lx\n",
|
|
handle);
|
|
return ffa_return._regs[2];
|
|
}
|
|
frag_length = ffa_return._regs[3];
|
|
|
|
/* Validate frag_length is less than total_length and mailbox size. */
|
|
if (frag_length > total_length ||
|
|
frag_length > (mailbox.rxtx_page_count * PAGE_SIZE)) {
|
|
ERROR("Invalid parameters!\n");
|
|
return FFA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Validate frag_length is less than remaining mem_region_buffer size. */
|
|
if (frag_length + recv_length >= REGION_BUF_SIZE) {
|
|
ERROR("Out of memory!\n");
|
|
return FFA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
memcpy(&mem_region_buffer[recv_length], mailbox.rx_buffer,
|
|
frag_length);
|
|
|
|
if (ffa_rx_release()) {
|
|
ERROR("Failed to release buffer!\n");
|
|
return FFA_ERROR_DENIED;
|
|
}
|
|
|
|
recv_length += frag_length;
|
|
|
|
assert(recv_length <= total_length);
|
|
}
|
|
|
|
composite = ffa_memory_region_get_composite(m, 0);
|
|
if (composite == NULL) {
|
|
WARN("Failed to get composite descriptor!\n");
|
|
return FFA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
VERBOSE("Address: %p; page_count: %x %lx\n",
|
|
(void *)composite->address_range_array[0].address,
|
|
composite->address_range_array[0].page_count, PAGE_SIZE);
|
|
|
|
/* This test is only concerned with RW permissions. */
|
|
if (ffa_get_data_access_attr(
|
|
receivers[0].mapd.memory_access_permissions) != FFA_MEM_PERM_RW) {
|
|
ERROR("Data permission in retrieve response %x does not match share/lend %x!\n",
|
|
ffa_get_data_access_attr(receivers[0].mapd.memory_access_permissions),
|
|
FFA_MEM_PERM_RW);
|
|
return FFA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
|
|
|
|
/* Only expecting to be sent memory from NWd so map accordingly. */
|
|
mem_attrs |= MT_NS;
|
|
|
|
for (int32_t i = 0; i < (int32_t)composite->address_range_count; i++) {
|
|
size_t size = composite->address_range_array[i].page_count * PAGE_SIZE;
|
|
|
|
ptr = (char *) composite->address_range_array[i].address;
|
|
ret = mmap_add_dynamic_region(
|
|
(uint64_t)ptr,
|
|
(uint64_t)ptr,
|
|
size, mem_attrs);
|
|
|
|
if (ret != 0) {
|
|
ERROR("Failed [%d] mmap_add_dynamic_region %u (%lx) (%lx) (%x)!\n",
|
|
i, ret,
|
|
(uint64_t)composite->address_range_array[i].address,
|
|
size, mem_attrs);
|
|
|
|
/* Remove mappings previously created in this transaction. */
|
|
for (i--; i >= 0; i--) {
|
|
ret = mmap_remove_dynamic_region(
|
|
(uint64_t)composite->address_range_array[i].address,
|
|
composite->address_range_array[i].page_count * PAGE_SIZE);
|
|
|
|
if (ret != 0) {
|
|
ERROR("Failed [%d] mmap_remove_dynamic_region!\n", i);
|
|
panic();
|
|
}
|
|
}
|
|
|
|
return FFA_ERROR_NO_MEMORY;
|
|
}
|
|
|
|
/* Increment memory region for validation purposes. */
|
|
++(*ptr);
|
|
|
|
/*
|
|
* Read initial magic number from memory region for
|
|
* validation purposes.
|
|
*/
|
|
if (!i) {
|
|
status = *ptr;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0U; i < composite->address_range_count; i++) {
|
|
ret = mmap_remove_dynamic_region(
|
|
(uint64_t)composite->address_range_array[i].address,
|
|
composite->address_range_array[i].page_count * PAGE_SIZE);
|
|
|
|
if (ret != 0) {
|
|
ERROR("Failed [%d] mmap_remove_dynamic_region!\n", i);
|
|
return FFA_ERROR_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (!memory_relinquish((struct ffa_mem_relinquish_descriptor *)mailbox.tx_buffer,
|
|
m->handle, tsp_id)) {
|
|
ERROR("Failed to relinquish memory region!\n");
|
|
return FFA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static smc_args_t *send_ffa_pm_success(void)
|
|
{
|
|
return set_smc_args(FFA_MSG_SEND_DIRECT_RESP_SMC32,
|
|
((tsp_id & FFA_DIRECT_MSG_ENDPOINT_ID_MASK)
|
|
<< FFA_DIRECT_MSG_SOURCE_SHIFT) | spmc_id,
|
|
FFA_FWK_MSG_BIT |
|
|
(FFA_PM_MSG_PM_RESP & FFA_FWK_MSG_MASK),
|
|
0, 0, 0, 0, 0);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* This function performs any remaining book keeping in the test secure payload
|
|
* before this cpu is turned off in response to a psci cpu_off request.
|
|
******************************************************************************/
|
|
smc_args_t *tsp_cpu_off_main(uint64_t arg0,
|
|
uint64_t arg1,
|
|
uint64_t arg2,
|
|
uint64_t arg3,
|
|
uint64_t arg4,
|
|
uint64_t arg5,
|
|
uint64_t arg6,
|
|
uint64_t arg7)
|
|
{
|
|
uint32_t linear_id = plat_my_core_pos();
|
|
|
|
/*
|
|
* This cpu is being turned off, so disable the timer to prevent the
|
|
* secure timer interrupt from interfering with power down. A pending
|
|
* interrupt will be lost but we do not care as we are turning off.
|
|
*/
|
|
tsp_generic_timer_stop();
|
|
|
|
/* Update this cpu's statistics. */
|
|
tsp_stats[linear_id].smc_count++;
|
|
tsp_stats[linear_id].eret_count++;
|
|
tsp_stats[linear_id].cpu_off_count++;
|
|
|
|
VERBOSE("TSP: cpu 0x%lx off request\n", read_mpidr());
|
|
VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu off requests\n",
|
|
read_mpidr(),
|
|
tsp_stats[linear_id].smc_count,
|
|
tsp_stats[linear_id].eret_count,
|
|
tsp_stats[linear_id].cpu_off_count);
|
|
|
|
return send_ffa_pm_success();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* This function performs any book keeping in the test secure payload before
|
|
* this cpu's architectural state is saved in response to an earlier psci
|
|
* cpu_suspend request.
|
|
******************************************************************************/
|
|
smc_args_t *tsp_cpu_suspend_main(uint64_t arg0,
|
|
uint64_t arg1,
|
|
uint64_t arg2,
|
|
uint64_t arg3,
|
|
uint64_t arg4,
|
|
uint64_t arg5,
|
|
uint64_t arg6,
|
|
uint64_t arg7)
|
|
{
|
|
uint32_t linear_id = plat_my_core_pos();
|
|
|
|
/*
|
|
* Save the time context and disable it to prevent the secure timer
|
|
* interrupt from interfering with wakeup from the suspend state.
|
|
*/
|
|
tsp_generic_timer_save();
|
|
tsp_generic_timer_stop();
|
|
|
|
/* Update this cpu's statistics. */
|
|
tsp_stats[linear_id].smc_count++;
|
|
tsp_stats[linear_id].eret_count++;
|
|
tsp_stats[linear_id].cpu_suspend_count++;
|
|
|
|
VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n",
|
|
read_mpidr(),
|
|
tsp_stats[linear_id].smc_count,
|
|
tsp_stats[linear_id].eret_count,
|
|
tsp_stats[linear_id].cpu_suspend_count);
|
|
|
|
return send_ffa_pm_success();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* This function performs any bookkeeping in the test secure payload after this
|
|
* cpu's architectural state has been restored after wakeup from an earlier psci
|
|
* cpu_suspend request.
|
|
******************************************************************************/
|
|
smc_args_t *tsp_cpu_resume_main(uint64_t max_off_pwrlvl,
|
|
uint64_t arg1,
|
|
uint64_t arg2,
|
|
uint64_t arg3,
|
|
uint64_t arg4,
|
|
uint64_t arg5,
|
|
uint64_t arg6,
|
|
uint64_t arg7)
|
|
{
|
|
uint32_t linear_id = plat_my_core_pos();
|
|
|
|
/* Restore the generic timer context. */
|
|
tsp_generic_timer_restore();
|
|
|
|
/* Update this cpu's statistics. */
|
|
tsp_stats[linear_id].smc_count++;
|
|
tsp_stats[linear_id].eret_count++;
|
|
tsp_stats[linear_id].cpu_resume_count++;
|
|
|
|
VERBOSE("TSP: cpu 0x%lx resumed. maximum off power level %" PRId64 "\n",
|
|
read_mpidr(), max_off_pwrlvl);
|
|
VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu resume requests\n",
|
|
read_mpidr(),
|
|
tsp_stats[linear_id].smc_count,
|
|
tsp_stats[linear_id].eret_count,
|
|
tsp_stats[linear_id].cpu_resume_count);
|
|
|
|
return send_ffa_pm_success();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* This function handles framework messages. Currently only PM.
|
|
******************************************************************************/
|
|
static smc_args_t *handle_framework_message(uint64_t arg0,
|
|
uint64_t arg1,
|
|
uint64_t arg2,
|
|
uint64_t arg3,
|
|
uint64_t arg4,
|
|
uint64_t arg5,
|
|
uint64_t arg6,
|
|
uint64_t arg7)
|
|
{
|
|
/* Check if it is a power management message from the SPMC. */
|
|
if (ffa_endpoint_source(arg1) != spmc_id) {
|
|
goto err;
|
|
}
|
|
|
|
/* Check if it is a PM request message. */
|
|
if ((arg2 & FFA_FWK_MSG_MASK) == FFA_FWK_MSG_PSCI) {
|
|
/* Check if it is a PSCI CPU_OFF request. */
|
|
if (arg3 == PSCI_CPU_OFF) {
|
|
return tsp_cpu_off_main(arg0, arg1, arg2, arg3,
|
|
arg4, arg5, arg6, arg7);
|
|
} else if (arg3 == PSCI_CPU_SUSPEND_AARCH64) {
|
|
return tsp_cpu_suspend_main(arg0, arg1, arg2, arg3,
|
|
arg4, arg5, arg6, arg7);
|
|
}
|
|
} else if ((arg2 & FFA_FWK_MSG_MASK) == FFA_PM_MSG_WB_REQ) {
|
|
/* Check it is a PSCI Warm Boot request. */
|
|
if (arg3 == FFA_WB_TYPE_NOTS2RAM) {
|
|
return tsp_cpu_resume_main(arg0, arg1, arg2, arg3,
|
|
arg4, arg5, arg6, arg7);
|
|
}
|
|
}
|
|
|
|
err:
|
|
ERROR("%s: Unknown framework message!\n", __func__);
|
|
panic();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Handles partition messages. Exercised from the FF-A Test Driver.
|
|
******************************************************************************/
|
|
static smc_args_t *handle_partition_message(uint64_t arg0,
|
|
uint64_t arg1,
|
|
uint64_t arg2,
|
|
uint64_t arg3,
|
|
uint64_t arg4,
|
|
uint64_t arg5,
|
|
uint64_t arg6,
|
|
uint64_t arg7)
|
|
{
|
|
uint16_t sender = ffa_endpoint_source(arg1);
|
|
uint16_t receiver = ffa_endpoint_destination(arg1);
|
|
int status = -1;
|
|
const bool multi_endpoint = true;
|
|
|
|
switch (arg3) {
|
|
case FF_A_MEMORY_SHARE:
|
|
INFO("TSP Tests: Memory Share Request--\n");
|
|
status = test_memory_send(sender, arg4, FFA_FLAG_SHARE_MEMORY, !multi_endpoint);
|
|
break;
|
|
|
|
case FF_A_MEMORY_LEND:
|
|
INFO("TSP Tests: Memory Lend Request--\n");
|
|
status = test_memory_send(sender, arg4, FFA_FLAG_LEND_MEMORY, !multi_endpoint);
|
|
break;
|
|
|
|
case FF_A_MEMORY_SHARE_MULTI_ENDPOINT:
|
|
INFO("TSP Tests: Multi Endpoint Memory Share Request--\n");
|
|
status = test_memory_send(sender, arg4, FFA_FLAG_SHARE_MEMORY, multi_endpoint);
|
|
break;
|
|
|
|
case FF_A_MEMORY_LEND_MULTI_ENDPOINT:
|
|
INFO("TSP Tests: Multi Endpoint Memory Lend Request--\n");
|
|
status = test_memory_send(sender, arg4, FFA_FLAG_LEND_MEMORY, multi_endpoint);
|
|
break;
|
|
case FF_A_RELAY_MESSAGE:
|
|
INFO("TSP Tests: Relaying message--\n");
|
|
status = ffa_test_relay(arg0, arg1, arg2, arg3, arg4,
|
|
arg5, arg6, arg7);
|
|
break;
|
|
|
|
case FF_A_ECHO_MESSAGE:
|
|
INFO("TSP Tests: echo message--\n");
|
|
status = arg4;
|
|
break;
|
|
|
|
default:
|
|
INFO("TSP Tests: Unknown request ID %d--\n", (int) arg3);
|
|
}
|
|
|
|
/* Swap the sender and receiver in the response. */
|
|
return ffa_msg_send_direct_resp(receiver, sender, status, 0, 0, 0, 0);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* This function implements the event loop for handling FF-A ABI invocations.
|
|
******************************************************************************/
|
|
static smc_args_t *tsp_event_loop(uint64_t smc_fid,
|
|
uint64_t arg1,
|
|
uint64_t arg2,
|
|
uint64_t arg3,
|
|
uint64_t arg4,
|
|
uint64_t arg5,
|
|
uint64_t arg6,
|
|
uint64_t arg7)
|
|
{
|
|
/* Panic if the SPMC did not forward an FF-A call. */
|
|
if (!is_ffa_fid(smc_fid)) {
|
|
ERROR("%s: Unknown SMC FID (0x%lx)\n", __func__, smc_fid);
|
|
panic();
|
|
}
|
|
|
|
switch (smc_fid) {
|
|
case FFA_INTERRUPT:
|
|
/*
|
|
* IRQs were enabled upon re-entry into the TSP. The interrupt
|
|
* must have been handled by now. Return to the SPMC indicating
|
|
* the same.
|
|
*/
|
|
return set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0);
|
|
|
|
case FFA_MSG_SEND_DIRECT_REQ_SMC64:
|
|
case FFA_MSG_SEND_DIRECT_REQ_SMC32:
|
|
/* Check if a framework message, handle accordingly. */
|
|
if ((arg2 & FFA_FWK_MSG_BIT)) {
|
|
return handle_framework_message(smc_fid, arg1, arg2, arg3,
|
|
arg4, arg5, arg6, arg7);
|
|
}
|
|
return handle_partition_message(smc_fid, arg1, arg2, arg3,
|
|
arg4, arg5, arg6, arg7);
|
|
}
|
|
|
|
ERROR("%s: Unsupported FF-A FID (0x%lx)\n", __func__, smc_fid);
|
|
panic();
|
|
}
|
|
|
|
static smc_args_t *tsp_loop(smc_args_t *args)
|
|
{
|
|
smc_args_t ret;
|
|
|
|
do {
|
|
/* --------------------------------------------
|
|
* Mask FIQ interrupts to avoid preemption
|
|
* in case EL3 SPMC delegates an IRQ next or a
|
|
* managed exit. Lastly, unmask IRQs so that
|
|
* they can be handled immediately upon re-entry.
|
|
* ---------------------------------------------
|
|
*/
|
|
write_daifset(DAIF_FIQ_BIT);
|
|
write_daifclr(DAIF_IRQ_BIT);
|
|
ret = smc_helper(args->_regs[0], args->_regs[1], args->_regs[2],
|
|
args->_regs[3], args->_regs[4], args->_regs[5],
|
|
args->_regs[6], args->_regs[7]);
|
|
args = tsp_event_loop(ret._regs[0], ret._regs[1], ret._regs[2],
|
|
ret._regs[3], ret._regs[4], ret._regs[5],
|
|
ret._regs[6], ret._regs[7]);
|
|
} while (1);
|
|
|
|
/* Not Reached. */
|
|
return NULL;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* TSP main entry point where it gets the opportunity to initialize its secure
|
|
* state/applications. Once the state is initialized, it must return to the
|
|
* SPD with a pointer to the 'tsp_vector_table' jump table.
|
|
******************************************************************************/
|
|
uint64_t tsp_main(void)
|
|
{
|
|
smc_args_t smc_args = {0};
|
|
|
|
NOTICE("TSP: %s\n", version_string);
|
|
NOTICE("TSP: %s\n", build_message);
|
|
INFO("TSP: Total memory base : 0x%lx\n", (unsigned long) BL32_BASE);
|
|
INFO("TSP: Total memory size : 0x%lx bytes\n", BL32_TOTAL_SIZE);
|
|
uint32_t linear_id = plat_my_core_pos();
|
|
|
|
/* Initialize the platform. */
|
|
tsp_platform_setup();
|
|
|
|
/* Initialize secure/applications state here. */
|
|
tsp_generic_timer_start();
|
|
|
|
/* Register secondary entrypoint with the SPMC. */
|
|
smc_args = smc_helper(FFA_SECONDARY_EP_REGISTER_SMC64,
|
|
(uint64_t) tsp_cpu_on_entry,
|
|
0, 0, 0, 0, 0, 0);
|
|
if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
|
|
ERROR("TSP could not register secondary ep (0x%lx)\n",
|
|
smc_args._regs[2]);
|
|
panic();
|
|
}
|
|
/* Get TSP's endpoint id. */
|
|
smc_args = smc_helper(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0);
|
|
if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
|
|
ERROR("TSP could not get own ID (0x%lx) on core%d\n",
|
|
smc_args._regs[2], linear_id);
|
|
panic();
|
|
}
|
|
|
|
tsp_id = smc_args._regs[2];
|
|
INFO("TSP FF-A endpoint id = 0x%x\n", tsp_id);
|
|
|
|
/* Get the SPMC ID. */
|
|
smc_args = smc_helper(FFA_SPM_ID_GET, 0, 0, 0, 0, 0, 0, 0);
|
|
if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
|
|
ERROR("TSP could not get SPMC ID (0x%lx) on core%d\n",
|
|
smc_args._regs[2], linear_id);
|
|
panic();
|
|
}
|
|
|
|
spmc_id = smc_args._regs[2];
|
|
|
|
/* Call RXTX_MAP to map a 4k RX and TX buffer. */
|
|
if (ffa_rxtx_map((uintptr_t) send_page,
|
|
(uintptr_t) recv_page, 1)) {
|
|
ERROR("TSP could not map it's RX/TX Buffers\n");
|
|
panic();
|
|
}
|
|
|
|
mailbox.tx_buffer = send_page;
|
|
mailbox.rx_buffer = recv_page;
|
|
mailbox.rxtx_page_count = 1;
|
|
|
|
/* Update this cpu's statistics. */
|
|
tsp_stats[linear_id].smc_count++;
|
|
tsp_stats[linear_id].eret_count++;
|
|
tsp_stats[linear_id].cpu_on_count++;
|
|
|
|
VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n",
|
|
read_mpidr(),
|
|
tsp_stats[linear_id].smc_count,
|
|
tsp_stats[linear_id].eret_count,
|
|
tsp_stats[linear_id].cpu_on_count);
|
|
|
|
/* Tell SPMD that we are done initialising. */
|
|
tsp_loop(set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0));
|
|
|
|
/* Not reached. */
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* This function performs any remaining book keeping in the test secure payload
|
|
* after this cpu's architectural state has been setup in response to an earlier
|
|
* psci cpu_on request.
|
|
******************************************************************************/
|
|
smc_args_t *tsp_cpu_on_main(void)
|
|
{
|
|
uint32_t linear_id = plat_my_core_pos();
|
|
|
|
/* Initialize secure/applications state here. */
|
|
tsp_generic_timer_start();
|
|
|
|
/* Update this cpu's statistics. */
|
|
tsp_stats[linear_id].smc_count++;
|
|
tsp_stats[linear_id].eret_count++;
|
|
tsp_stats[linear_id].cpu_on_count++;
|
|
VERBOSE("TSP: cpu 0x%lx turned on\n", read_mpidr());
|
|
VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n",
|
|
read_mpidr(),
|
|
tsp_stats[linear_id].smc_count,
|
|
tsp_stats[linear_id].eret_count,
|
|
tsp_stats[linear_id].cpu_on_count);
|
|
/* ---------------------------------------------
|
|
* Jump to the main event loop to return to EL3
|
|
* and be ready for the next request on this cpu.
|
|
* ---------------------------------------------
|
|
*/
|
|
return tsp_loop(set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0));
|
|
}
|
|
|