1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <inttypes.h> 9*91f16700Schasinglulu #include <stdint.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include "../../services/std_svc/spm/el3_spmc/spmc.h" 12*91f16700Schasinglulu #include "../../services/std_svc/spm/el3_spmc/spmc_shared_mem.h" 13*91f16700Schasinglulu #include <arch_features.h> 14*91f16700Schasinglulu #include <arch_helpers.h> 15*91f16700Schasinglulu #include <bl32/tsp/tsp.h> 16*91f16700Schasinglulu #include <common/bl_common.h> 17*91f16700Schasinglulu #include <common/debug.h> 18*91f16700Schasinglulu #include "ffa_helpers.h" 19*91f16700Schasinglulu #include <lib/psci/psci.h> 20*91f16700Schasinglulu #include <lib/spinlock.h> 21*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_defs.h> 22*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h> 23*91f16700Schasinglulu #include <plat/common/platform.h> 24*91f16700Schasinglulu #include <platform_tsp.h> 25*91f16700Schasinglulu #include <services/ffa_svc.h> 26*91f16700Schasinglulu #include "tsp_private.h" 27*91f16700Schasinglulu 28*91f16700Schasinglulu #include <platform_def.h> 29*91f16700Schasinglulu 30*91f16700Schasinglulu static ffa_endpoint_id16_t tsp_id, spmc_id; 31*91f16700Schasinglulu uint8_t mem_region_buffer[4096 * 2] __aligned(PAGE_SIZE); 32*91f16700Schasinglulu 33*91f16700Schasinglulu /* Partition Mailbox. */ 34*91f16700Schasinglulu static uint8_t send_page[PAGE_SIZE] __aligned(PAGE_SIZE); 35*91f16700Schasinglulu static uint8_t recv_page[PAGE_SIZE] __aligned(PAGE_SIZE); 36*91f16700Schasinglulu 37*91f16700Schasinglulu /* 38*91f16700Schasinglulu * Declare a global mailbox for use within the TSP. 39*91f16700Schasinglulu * This will be initialized appropriately when the buffers 40*91f16700Schasinglulu * are mapped with the SPMC. 41*91f16700Schasinglulu */ 42*91f16700Schasinglulu static struct mailbox mailbox; 43*91f16700Schasinglulu 44*91f16700Schasinglulu /******************************************************************************* 45*91f16700Schasinglulu * This enum is used to handle test cases driven from the FF-A Test Driver. 46*91f16700Schasinglulu ******************************************************************************/ 47*91f16700Schasinglulu /* Keep in Sync with FF-A Test Driver. */ 48*91f16700Schasinglulu enum message_t { 49*91f16700Schasinglulu /* Partition Only Messages. */ 50*91f16700Schasinglulu FF_A_RELAY_MESSAGE = 0, 51*91f16700Schasinglulu 52*91f16700Schasinglulu /* Basic Functionality. */ 53*91f16700Schasinglulu FF_A_ECHO_MESSAGE, 54*91f16700Schasinglulu FF_A_RELAY_MESSAGE_EL3, 55*91f16700Schasinglulu 56*91f16700Schasinglulu /* Memory Sharing. */ 57*91f16700Schasinglulu FF_A_MEMORY_SHARE, 58*91f16700Schasinglulu FF_A_MEMORY_SHARE_FRAGMENTED, 59*91f16700Schasinglulu FF_A_MEMORY_LEND, 60*91f16700Schasinglulu FF_A_MEMORY_LEND_FRAGMENTED, 61*91f16700Schasinglulu 62*91f16700Schasinglulu FF_A_MEMORY_SHARE_MULTI_ENDPOINT, 63*91f16700Schasinglulu FF_A_MEMORY_LEND_MULTI_ENDPOINT, 64*91f16700Schasinglulu 65*91f16700Schasinglulu LAST, 66*91f16700Schasinglulu FF_A_RUN_ALL = 255, 67*91f16700Schasinglulu FF_A_OP_MAX = 256 68*91f16700Schasinglulu }; 69*91f16700Schasinglulu 70*91f16700Schasinglulu #if SPMC_AT_EL3 71*91f16700Schasinglulu extern void tsp_cpu_on_entry(void); 72*91f16700Schasinglulu #endif 73*91f16700Schasinglulu 74*91f16700Schasinglulu /******************************************************************************* 75*91f16700Schasinglulu * Test Functions. 76*91f16700Schasinglulu ******************************************************************************/ 77*91f16700Schasinglulu 78*91f16700Schasinglulu /******************************************************************************* 79*91f16700Schasinglulu * Enable the TSP to forward the received message to another partition and ask 80*91f16700Schasinglulu * it to echo the value back in order to validate direct messages functionality. 81*91f16700Schasinglulu ******************************************************************************/ 82*91f16700Schasinglulu static int ffa_test_relay(uint64_t arg0, 83*91f16700Schasinglulu uint64_t arg1, 84*91f16700Schasinglulu uint64_t arg2, 85*91f16700Schasinglulu uint64_t arg3, 86*91f16700Schasinglulu uint64_t arg4, 87*91f16700Schasinglulu uint64_t arg5, 88*91f16700Schasinglulu uint64_t arg6, 89*91f16700Schasinglulu uint64_t arg7) 90*91f16700Schasinglulu { 91*91f16700Schasinglulu smc_args_t ffa_forward_result; 92*91f16700Schasinglulu ffa_endpoint_id16_t receiver = arg5; 93*91f16700Schasinglulu 94*91f16700Schasinglulu ffa_forward_result = ffa_msg_send_direct_req(tsp_id, 95*91f16700Schasinglulu receiver, 96*91f16700Schasinglulu FF_A_ECHO_MESSAGE, arg4, 97*91f16700Schasinglulu 0, 0, 0); 98*91f16700Schasinglulu return ffa_forward_result._regs[3]; 99*91f16700Schasinglulu } 100*91f16700Schasinglulu 101*91f16700Schasinglulu /******************************************************************************* 102*91f16700Schasinglulu * This function handles memory management tests, currently share and lend. 103*91f16700Schasinglulu * This test supports the use of FRAG_RX to use memory descriptors that do not 104*91f16700Schasinglulu * fit in a single 4KB buffer. 105*91f16700Schasinglulu ******************************************************************************/ 106*91f16700Schasinglulu static int test_memory_send(ffa_endpoint_id16_t sender, uint64_t handle, 107*91f16700Schasinglulu ffa_mtd_flag32_t flags, bool multi_endpoint) 108*91f16700Schasinglulu { 109*91f16700Schasinglulu struct ffa_mtd *m; 110*91f16700Schasinglulu struct ffa_emad_v1_0 *receivers; 111*91f16700Schasinglulu struct ffa_comp_mrd *composite; 112*91f16700Schasinglulu int ret, status = 0; 113*91f16700Schasinglulu unsigned int mem_attrs; 114*91f16700Schasinglulu char *ptr; 115*91f16700Schasinglulu ffa_endpoint_id16_t source = sender; 116*91f16700Schasinglulu uint32_t total_length, recv_length = 0; 117*91f16700Schasinglulu 118*91f16700Schasinglulu /* 119*91f16700Schasinglulu * In the case that we're testing multiple endpoints choose a partition 120*91f16700Schasinglulu * ID that resides in the normal world so the SPMC won't detect it as 121*91f16700Schasinglulu * invalid. 122*91f16700Schasinglulu * TODO: Should get endpoint receiver id and flag as input from NWd. 123*91f16700Schasinglulu */ 124*91f16700Schasinglulu uint32_t receiver_count = multi_endpoint ? 2 : 1; 125*91f16700Schasinglulu ffa_endpoint_id16_t test_receivers[2] = { tsp_id, 0x10 }; 126*91f16700Schasinglulu 127*91f16700Schasinglulu /* Ensure that the sender ID resides in the normal world. */ 128*91f16700Schasinglulu if (ffa_is_secure_world_id(sender)) { 129*91f16700Schasinglulu ERROR("Invalid sender ID 0x%x.\n", sender); 130*91f16700Schasinglulu return FFA_ERROR_DENIED; 131*91f16700Schasinglulu } 132*91f16700Schasinglulu 133*91f16700Schasinglulu if (!memory_retrieve(&mailbox, &m, handle, source, test_receivers, 134*91f16700Schasinglulu receiver_count, flags, &recv_length, 135*91f16700Schasinglulu &total_length)) { 136*91f16700Schasinglulu return FFA_ERROR_INVALID_PARAMETER; 137*91f16700Schasinglulu } 138*91f16700Schasinglulu 139*91f16700Schasinglulu receivers = (struct ffa_emad_v1_0 *) 140*91f16700Schasinglulu ((uint8_t *) m + m->emad_offset); 141*91f16700Schasinglulu while (total_length != recv_length) { 142*91f16700Schasinglulu smc_args_t ffa_return; 143*91f16700Schasinglulu uint32_t frag_length; 144*91f16700Schasinglulu 145*91f16700Schasinglulu ffa_return = ffa_mem_frag_rx(handle, recv_length); 146*91f16700Schasinglulu 147*91f16700Schasinglulu if (ffa_return._regs[0] == FFA_ERROR) { 148*91f16700Schasinglulu WARN("TSP: failed to resume mem with handle %lx\n", 149*91f16700Schasinglulu handle); 150*91f16700Schasinglulu return ffa_return._regs[2]; 151*91f16700Schasinglulu } 152*91f16700Schasinglulu frag_length = ffa_return._regs[3]; 153*91f16700Schasinglulu 154*91f16700Schasinglulu /* Validate frag_length is less than total_length and mailbox size. */ 155*91f16700Schasinglulu if (frag_length > total_length || 156*91f16700Schasinglulu frag_length > (mailbox.rxtx_page_count * PAGE_SIZE)) { 157*91f16700Schasinglulu ERROR("Invalid parameters!\n"); 158*91f16700Schasinglulu return FFA_ERROR_INVALID_PARAMETER; 159*91f16700Schasinglulu } 160*91f16700Schasinglulu 161*91f16700Schasinglulu /* Validate frag_length is less than remaining mem_region_buffer size. */ 162*91f16700Schasinglulu if (frag_length + recv_length >= REGION_BUF_SIZE) { 163*91f16700Schasinglulu ERROR("Out of memory!\n"); 164*91f16700Schasinglulu return FFA_ERROR_INVALID_PARAMETER; 165*91f16700Schasinglulu } 166*91f16700Schasinglulu 167*91f16700Schasinglulu memcpy(&mem_region_buffer[recv_length], mailbox.rx_buffer, 168*91f16700Schasinglulu frag_length); 169*91f16700Schasinglulu 170*91f16700Schasinglulu if (ffa_rx_release()) { 171*91f16700Schasinglulu ERROR("Failed to release buffer!\n"); 172*91f16700Schasinglulu return FFA_ERROR_DENIED; 173*91f16700Schasinglulu } 174*91f16700Schasinglulu 175*91f16700Schasinglulu recv_length += frag_length; 176*91f16700Schasinglulu 177*91f16700Schasinglulu assert(recv_length <= total_length); 178*91f16700Schasinglulu } 179*91f16700Schasinglulu 180*91f16700Schasinglulu composite = ffa_memory_region_get_composite(m, 0); 181*91f16700Schasinglulu if (composite == NULL) { 182*91f16700Schasinglulu WARN("Failed to get composite descriptor!\n"); 183*91f16700Schasinglulu return FFA_ERROR_INVALID_PARAMETER; 184*91f16700Schasinglulu } 185*91f16700Schasinglulu 186*91f16700Schasinglulu VERBOSE("Address: %p; page_count: %x %lx\n", 187*91f16700Schasinglulu (void *)composite->address_range_array[0].address, 188*91f16700Schasinglulu composite->address_range_array[0].page_count, PAGE_SIZE); 189*91f16700Schasinglulu 190*91f16700Schasinglulu /* This test is only concerned with RW permissions. */ 191*91f16700Schasinglulu if (ffa_get_data_access_attr( 192*91f16700Schasinglulu receivers[0].mapd.memory_access_permissions) != FFA_MEM_PERM_RW) { 193*91f16700Schasinglulu ERROR("Data permission in retrieve response %x does not match share/lend %x!\n", 194*91f16700Schasinglulu ffa_get_data_access_attr(receivers[0].mapd.memory_access_permissions), 195*91f16700Schasinglulu FFA_MEM_PERM_RW); 196*91f16700Schasinglulu return FFA_ERROR_INVALID_PARAMETER; 197*91f16700Schasinglulu } 198*91f16700Schasinglulu 199*91f16700Schasinglulu mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER; 200*91f16700Schasinglulu 201*91f16700Schasinglulu /* Only expecting to be sent memory from NWd so map accordingly. */ 202*91f16700Schasinglulu mem_attrs |= MT_NS; 203*91f16700Schasinglulu 204*91f16700Schasinglulu for (int32_t i = 0; i < (int32_t)composite->address_range_count; i++) { 205*91f16700Schasinglulu size_t size = composite->address_range_array[i].page_count * PAGE_SIZE; 206*91f16700Schasinglulu 207*91f16700Schasinglulu ptr = (char *) composite->address_range_array[i].address; 208*91f16700Schasinglulu ret = mmap_add_dynamic_region( 209*91f16700Schasinglulu (uint64_t)ptr, 210*91f16700Schasinglulu (uint64_t)ptr, 211*91f16700Schasinglulu size, mem_attrs); 212*91f16700Schasinglulu 213*91f16700Schasinglulu if (ret != 0) { 214*91f16700Schasinglulu ERROR("Failed [%d] mmap_add_dynamic_region %u (%lx) (%lx) (%x)!\n", 215*91f16700Schasinglulu i, ret, 216*91f16700Schasinglulu (uint64_t)composite->address_range_array[i].address, 217*91f16700Schasinglulu size, mem_attrs); 218*91f16700Schasinglulu 219*91f16700Schasinglulu /* Remove mappings previously created in this transaction. */ 220*91f16700Schasinglulu for (i--; i >= 0; i--) { 221*91f16700Schasinglulu ret = mmap_remove_dynamic_region( 222*91f16700Schasinglulu (uint64_t)composite->address_range_array[i].address, 223*91f16700Schasinglulu composite->address_range_array[i].page_count * PAGE_SIZE); 224*91f16700Schasinglulu 225*91f16700Schasinglulu if (ret != 0) { 226*91f16700Schasinglulu ERROR("Failed [%d] mmap_remove_dynamic_region!\n", i); 227*91f16700Schasinglulu panic(); 228*91f16700Schasinglulu } 229*91f16700Schasinglulu } 230*91f16700Schasinglulu 231*91f16700Schasinglulu return FFA_ERROR_NO_MEMORY; 232*91f16700Schasinglulu } 233*91f16700Schasinglulu 234*91f16700Schasinglulu /* Increment memory region for validation purposes. */ 235*91f16700Schasinglulu ++(*ptr); 236*91f16700Schasinglulu 237*91f16700Schasinglulu /* 238*91f16700Schasinglulu * Read initial magic number from memory region for 239*91f16700Schasinglulu * validation purposes. 240*91f16700Schasinglulu */ 241*91f16700Schasinglulu if (!i) { 242*91f16700Schasinglulu status = *ptr; 243*91f16700Schasinglulu } 244*91f16700Schasinglulu } 245*91f16700Schasinglulu 246*91f16700Schasinglulu for (uint32_t i = 0U; i < composite->address_range_count; i++) { 247*91f16700Schasinglulu ret = mmap_remove_dynamic_region( 248*91f16700Schasinglulu (uint64_t)composite->address_range_array[i].address, 249*91f16700Schasinglulu composite->address_range_array[i].page_count * PAGE_SIZE); 250*91f16700Schasinglulu 251*91f16700Schasinglulu if (ret != 0) { 252*91f16700Schasinglulu ERROR("Failed [%d] mmap_remove_dynamic_region!\n", i); 253*91f16700Schasinglulu return FFA_ERROR_NO_MEMORY; 254*91f16700Schasinglulu } 255*91f16700Schasinglulu } 256*91f16700Schasinglulu 257*91f16700Schasinglulu if (!memory_relinquish((struct ffa_mem_relinquish_descriptor *)mailbox.tx_buffer, 258*91f16700Schasinglulu m->handle, tsp_id)) { 259*91f16700Schasinglulu ERROR("Failed to relinquish memory region!\n"); 260*91f16700Schasinglulu return FFA_ERROR_INVALID_PARAMETER; 261*91f16700Schasinglulu } 262*91f16700Schasinglulu return status; 263*91f16700Schasinglulu } 264*91f16700Schasinglulu 265*91f16700Schasinglulu static smc_args_t *send_ffa_pm_success(void) 266*91f16700Schasinglulu { 267*91f16700Schasinglulu return set_smc_args(FFA_MSG_SEND_DIRECT_RESP_SMC32, 268*91f16700Schasinglulu ((tsp_id & FFA_DIRECT_MSG_ENDPOINT_ID_MASK) 269*91f16700Schasinglulu << FFA_DIRECT_MSG_SOURCE_SHIFT) | spmc_id, 270*91f16700Schasinglulu FFA_FWK_MSG_BIT | 271*91f16700Schasinglulu (FFA_PM_MSG_PM_RESP & FFA_FWK_MSG_MASK), 272*91f16700Schasinglulu 0, 0, 0, 0, 0); 273*91f16700Schasinglulu } 274*91f16700Schasinglulu 275*91f16700Schasinglulu /******************************************************************************* 276*91f16700Schasinglulu * This function performs any remaining book keeping in the test secure payload 277*91f16700Schasinglulu * before this cpu is turned off in response to a psci cpu_off request. 278*91f16700Schasinglulu ******************************************************************************/ 279*91f16700Schasinglulu smc_args_t *tsp_cpu_off_main(uint64_t arg0, 280*91f16700Schasinglulu uint64_t arg1, 281*91f16700Schasinglulu uint64_t arg2, 282*91f16700Schasinglulu uint64_t arg3, 283*91f16700Schasinglulu uint64_t arg4, 284*91f16700Schasinglulu uint64_t arg5, 285*91f16700Schasinglulu uint64_t arg6, 286*91f16700Schasinglulu uint64_t arg7) 287*91f16700Schasinglulu { 288*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 289*91f16700Schasinglulu 290*91f16700Schasinglulu /* 291*91f16700Schasinglulu * This cpu is being turned off, so disable the timer to prevent the 292*91f16700Schasinglulu * secure timer interrupt from interfering with power down. A pending 293*91f16700Schasinglulu * interrupt will be lost but we do not care as we are turning off. 294*91f16700Schasinglulu */ 295*91f16700Schasinglulu tsp_generic_timer_stop(); 296*91f16700Schasinglulu 297*91f16700Schasinglulu /* Update this cpu's statistics. */ 298*91f16700Schasinglulu tsp_stats[linear_id].smc_count++; 299*91f16700Schasinglulu tsp_stats[linear_id].eret_count++; 300*91f16700Schasinglulu tsp_stats[linear_id].cpu_off_count++; 301*91f16700Schasinglulu 302*91f16700Schasinglulu VERBOSE("TSP: cpu 0x%lx off request\n", read_mpidr()); 303*91f16700Schasinglulu VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu off requests\n", 304*91f16700Schasinglulu read_mpidr(), 305*91f16700Schasinglulu tsp_stats[linear_id].smc_count, 306*91f16700Schasinglulu tsp_stats[linear_id].eret_count, 307*91f16700Schasinglulu tsp_stats[linear_id].cpu_off_count); 308*91f16700Schasinglulu 309*91f16700Schasinglulu return send_ffa_pm_success(); 310*91f16700Schasinglulu } 311*91f16700Schasinglulu 312*91f16700Schasinglulu /******************************************************************************* 313*91f16700Schasinglulu * This function performs any book keeping in the test secure payload before 314*91f16700Schasinglulu * this cpu's architectural state is saved in response to an earlier psci 315*91f16700Schasinglulu * cpu_suspend request. 316*91f16700Schasinglulu ******************************************************************************/ 317*91f16700Schasinglulu smc_args_t *tsp_cpu_suspend_main(uint64_t arg0, 318*91f16700Schasinglulu uint64_t arg1, 319*91f16700Schasinglulu uint64_t arg2, 320*91f16700Schasinglulu uint64_t arg3, 321*91f16700Schasinglulu uint64_t arg4, 322*91f16700Schasinglulu uint64_t arg5, 323*91f16700Schasinglulu uint64_t arg6, 324*91f16700Schasinglulu uint64_t arg7) 325*91f16700Schasinglulu { 326*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 327*91f16700Schasinglulu 328*91f16700Schasinglulu /* 329*91f16700Schasinglulu * Save the time context and disable it to prevent the secure timer 330*91f16700Schasinglulu * interrupt from interfering with wakeup from the suspend state. 331*91f16700Schasinglulu */ 332*91f16700Schasinglulu tsp_generic_timer_save(); 333*91f16700Schasinglulu tsp_generic_timer_stop(); 334*91f16700Schasinglulu 335*91f16700Schasinglulu /* Update this cpu's statistics. */ 336*91f16700Schasinglulu tsp_stats[linear_id].smc_count++; 337*91f16700Schasinglulu tsp_stats[linear_id].eret_count++; 338*91f16700Schasinglulu tsp_stats[linear_id].cpu_suspend_count++; 339*91f16700Schasinglulu 340*91f16700Schasinglulu VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n", 341*91f16700Schasinglulu read_mpidr(), 342*91f16700Schasinglulu tsp_stats[linear_id].smc_count, 343*91f16700Schasinglulu tsp_stats[linear_id].eret_count, 344*91f16700Schasinglulu tsp_stats[linear_id].cpu_suspend_count); 345*91f16700Schasinglulu 346*91f16700Schasinglulu return send_ffa_pm_success(); 347*91f16700Schasinglulu } 348*91f16700Schasinglulu 349*91f16700Schasinglulu /******************************************************************************* 350*91f16700Schasinglulu * This function performs any bookkeeping in the test secure payload after this 351*91f16700Schasinglulu * cpu's architectural state has been restored after wakeup from an earlier psci 352*91f16700Schasinglulu * cpu_suspend request. 353*91f16700Schasinglulu ******************************************************************************/ 354*91f16700Schasinglulu smc_args_t *tsp_cpu_resume_main(uint64_t max_off_pwrlvl, 355*91f16700Schasinglulu uint64_t arg1, 356*91f16700Schasinglulu uint64_t arg2, 357*91f16700Schasinglulu uint64_t arg3, 358*91f16700Schasinglulu uint64_t arg4, 359*91f16700Schasinglulu uint64_t arg5, 360*91f16700Schasinglulu uint64_t arg6, 361*91f16700Schasinglulu uint64_t arg7) 362*91f16700Schasinglulu { 363*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 364*91f16700Schasinglulu 365*91f16700Schasinglulu /* Restore the generic timer context. */ 366*91f16700Schasinglulu tsp_generic_timer_restore(); 367*91f16700Schasinglulu 368*91f16700Schasinglulu /* Update this cpu's statistics. */ 369*91f16700Schasinglulu tsp_stats[linear_id].smc_count++; 370*91f16700Schasinglulu tsp_stats[linear_id].eret_count++; 371*91f16700Schasinglulu tsp_stats[linear_id].cpu_resume_count++; 372*91f16700Schasinglulu 373*91f16700Schasinglulu VERBOSE("TSP: cpu 0x%lx resumed. maximum off power level %" PRId64 "\n", 374*91f16700Schasinglulu read_mpidr(), max_off_pwrlvl); 375*91f16700Schasinglulu VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu resume requests\n", 376*91f16700Schasinglulu read_mpidr(), 377*91f16700Schasinglulu tsp_stats[linear_id].smc_count, 378*91f16700Schasinglulu tsp_stats[linear_id].eret_count, 379*91f16700Schasinglulu tsp_stats[linear_id].cpu_resume_count); 380*91f16700Schasinglulu 381*91f16700Schasinglulu return send_ffa_pm_success(); 382*91f16700Schasinglulu } 383*91f16700Schasinglulu 384*91f16700Schasinglulu /******************************************************************************* 385*91f16700Schasinglulu * This function handles framework messages. Currently only PM. 386*91f16700Schasinglulu ******************************************************************************/ 387*91f16700Schasinglulu static smc_args_t *handle_framework_message(uint64_t arg0, 388*91f16700Schasinglulu uint64_t arg1, 389*91f16700Schasinglulu uint64_t arg2, 390*91f16700Schasinglulu uint64_t arg3, 391*91f16700Schasinglulu uint64_t arg4, 392*91f16700Schasinglulu uint64_t arg5, 393*91f16700Schasinglulu uint64_t arg6, 394*91f16700Schasinglulu uint64_t arg7) 395*91f16700Schasinglulu { 396*91f16700Schasinglulu /* Check if it is a power management message from the SPMC. */ 397*91f16700Schasinglulu if (ffa_endpoint_source(arg1) != spmc_id) { 398*91f16700Schasinglulu goto err; 399*91f16700Schasinglulu } 400*91f16700Schasinglulu 401*91f16700Schasinglulu /* Check if it is a PM request message. */ 402*91f16700Schasinglulu if ((arg2 & FFA_FWK_MSG_MASK) == FFA_FWK_MSG_PSCI) { 403*91f16700Schasinglulu /* Check if it is a PSCI CPU_OFF request. */ 404*91f16700Schasinglulu if (arg3 == PSCI_CPU_OFF) { 405*91f16700Schasinglulu return tsp_cpu_off_main(arg0, arg1, arg2, arg3, 406*91f16700Schasinglulu arg4, arg5, arg6, arg7); 407*91f16700Schasinglulu } else if (arg3 == PSCI_CPU_SUSPEND_AARCH64) { 408*91f16700Schasinglulu return tsp_cpu_suspend_main(arg0, arg1, arg2, arg3, 409*91f16700Schasinglulu arg4, arg5, arg6, arg7); 410*91f16700Schasinglulu } 411*91f16700Schasinglulu } else if ((arg2 & FFA_FWK_MSG_MASK) == FFA_PM_MSG_WB_REQ) { 412*91f16700Schasinglulu /* Check it is a PSCI Warm Boot request. */ 413*91f16700Schasinglulu if (arg3 == FFA_WB_TYPE_NOTS2RAM) { 414*91f16700Schasinglulu return tsp_cpu_resume_main(arg0, arg1, arg2, arg3, 415*91f16700Schasinglulu arg4, arg5, arg6, arg7); 416*91f16700Schasinglulu } 417*91f16700Schasinglulu } 418*91f16700Schasinglulu 419*91f16700Schasinglulu err: 420*91f16700Schasinglulu ERROR("%s: Unknown framework message!\n", __func__); 421*91f16700Schasinglulu panic(); 422*91f16700Schasinglulu } 423*91f16700Schasinglulu 424*91f16700Schasinglulu /******************************************************************************* 425*91f16700Schasinglulu * Handles partition messages. Exercised from the FF-A Test Driver. 426*91f16700Schasinglulu ******************************************************************************/ 427*91f16700Schasinglulu static smc_args_t *handle_partition_message(uint64_t arg0, 428*91f16700Schasinglulu uint64_t arg1, 429*91f16700Schasinglulu uint64_t arg2, 430*91f16700Schasinglulu uint64_t arg3, 431*91f16700Schasinglulu uint64_t arg4, 432*91f16700Schasinglulu uint64_t arg5, 433*91f16700Schasinglulu uint64_t arg6, 434*91f16700Schasinglulu uint64_t arg7) 435*91f16700Schasinglulu { 436*91f16700Schasinglulu uint16_t sender = ffa_endpoint_source(arg1); 437*91f16700Schasinglulu uint16_t receiver = ffa_endpoint_destination(arg1); 438*91f16700Schasinglulu int status = -1; 439*91f16700Schasinglulu const bool multi_endpoint = true; 440*91f16700Schasinglulu 441*91f16700Schasinglulu switch (arg3) { 442*91f16700Schasinglulu case FF_A_MEMORY_SHARE: 443*91f16700Schasinglulu INFO("TSP Tests: Memory Share Request--\n"); 444*91f16700Schasinglulu status = test_memory_send(sender, arg4, FFA_FLAG_SHARE_MEMORY, !multi_endpoint); 445*91f16700Schasinglulu break; 446*91f16700Schasinglulu 447*91f16700Schasinglulu case FF_A_MEMORY_LEND: 448*91f16700Schasinglulu INFO("TSP Tests: Memory Lend Request--\n"); 449*91f16700Schasinglulu status = test_memory_send(sender, arg4, FFA_FLAG_LEND_MEMORY, !multi_endpoint); 450*91f16700Schasinglulu break; 451*91f16700Schasinglulu 452*91f16700Schasinglulu case FF_A_MEMORY_SHARE_MULTI_ENDPOINT: 453*91f16700Schasinglulu INFO("TSP Tests: Multi Endpoint Memory Share Request--\n"); 454*91f16700Schasinglulu status = test_memory_send(sender, arg4, FFA_FLAG_SHARE_MEMORY, multi_endpoint); 455*91f16700Schasinglulu break; 456*91f16700Schasinglulu 457*91f16700Schasinglulu case FF_A_MEMORY_LEND_MULTI_ENDPOINT: 458*91f16700Schasinglulu INFO("TSP Tests: Multi Endpoint Memory Lend Request--\n"); 459*91f16700Schasinglulu status = test_memory_send(sender, arg4, FFA_FLAG_LEND_MEMORY, multi_endpoint); 460*91f16700Schasinglulu break; 461*91f16700Schasinglulu case FF_A_RELAY_MESSAGE: 462*91f16700Schasinglulu INFO("TSP Tests: Relaying message--\n"); 463*91f16700Schasinglulu status = ffa_test_relay(arg0, arg1, arg2, arg3, arg4, 464*91f16700Schasinglulu arg5, arg6, arg7); 465*91f16700Schasinglulu break; 466*91f16700Schasinglulu 467*91f16700Schasinglulu case FF_A_ECHO_MESSAGE: 468*91f16700Schasinglulu INFO("TSP Tests: echo message--\n"); 469*91f16700Schasinglulu status = arg4; 470*91f16700Schasinglulu break; 471*91f16700Schasinglulu 472*91f16700Schasinglulu default: 473*91f16700Schasinglulu INFO("TSP Tests: Unknown request ID %d--\n", (int) arg3); 474*91f16700Schasinglulu } 475*91f16700Schasinglulu 476*91f16700Schasinglulu /* Swap the sender and receiver in the response. */ 477*91f16700Schasinglulu return ffa_msg_send_direct_resp(receiver, sender, status, 0, 0, 0, 0); 478*91f16700Schasinglulu } 479*91f16700Schasinglulu 480*91f16700Schasinglulu /******************************************************************************* 481*91f16700Schasinglulu * This function implements the event loop for handling FF-A ABI invocations. 482*91f16700Schasinglulu ******************************************************************************/ 483*91f16700Schasinglulu static smc_args_t *tsp_event_loop(uint64_t smc_fid, 484*91f16700Schasinglulu uint64_t arg1, 485*91f16700Schasinglulu uint64_t arg2, 486*91f16700Schasinglulu uint64_t arg3, 487*91f16700Schasinglulu uint64_t arg4, 488*91f16700Schasinglulu uint64_t arg5, 489*91f16700Schasinglulu uint64_t arg6, 490*91f16700Schasinglulu uint64_t arg7) 491*91f16700Schasinglulu { 492*91f16700Schasinglulu /* Panic if the SPMC did not forward an FF-A call. */ 493*91f16700Schasinglulu if (!is_ffa_fid(smc_fid)) { 494*91f16700Schasinglulu ERROR("%s: Unknown SMC FID (0x%lx)\n", __func__, smc_fid); 495*91f16700Schasinglulu panic(); 496*91f16700Schasinglulu } 497*91f16700Schasinglulu 498*91f16700Schasinglulu switch (smc_fid) { 499*91f16700Schasinglulu case FFA_INTERRUPT: 500*91f16700Schasinglulu /* 501*91f16700Schasinglulu * IRQs were enabled upon re-entry into the TSP. The interrupt 502*91f16700Schasinglulu * must have been handled by now. Return to the SPMC indicating 503*91f16700Schasinglulu * the same. 504*91f16700Schasinglulu */ 505*91f16700Schasinglulu return set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0); 506*91f16700Schasinglulu 507*91f16700Schasinglulu case FFA_MSG_SEND_DIRECT_REQ_SMC64: 508*91f16700Schasinglulu case FFA_MSG_SEND_DIRECT_REQ_SMC32: 509*91f16700Schasinglulu /* Check if a framework message, handle accordingly. */ 510*91f16700Schasinglulu if ((arg2 & FFA_FWK_MSG_BIT)) { 511*91f16700Schasinglulu return handle_framework_message(smc_fid, arg1, arg2, arg3, 512*91f16700Schasinglulu arg4, arg5, arg6, arg7); 513*91f16700Schasinglulu } 514*91f16700Schasinglulu return handle_partition_message(smc_fid, arg1, arg2, arg3, 515*91f16700Schasinglulu arg4, arg5, arg6, arg7); 516*91f16700Schasinglulu } 517*91f16700Schasinglulu 518*91f16700Schasinglulu ERROR("%s: Unsupported FF-A FID (0x%lx)\n", __func__, smc_fid); 519*91f16700Schasinglulu panic(); 520*91f16700Schasinglulu } 521*91f16700Schasinglulu 522*91f16700Schasinglulu static smc_args_t *tsp_loop(smc_args_t *args) 523*91f16700Schasinglulu { 524*91f16700Schasinglulu smc_args_t ret; 525*91f16700Schasinglulu 526*91f16700Schasinglulu do { 527*91f16700Schasinglulu /* -------------------------------------------- 528*91f16700Schasinglulu * Mask FIQ interrupts to avoid preemption 529*91f16700Schasinglulu * in case EL3 SPMC delegates an IRQ next or a 530*91f16700Schasinglulu * managed exit. Lastly, unmask IRQs so that 531*91f16700Schasinglulu * they can be handled immediately upon re-entry. 532*91f16700Schasinglulu * --------------------------------------------- 533*91f16700Schasinglulu */ 534*91f16700Schasinglulu write_daifset(DAIF_FIQ_BIT); 535*91f16700Schasinglulu write_daifclr(DAIF_IRQ_BIT); 536*91f16700Schasinglulu ret = smc_helper(args->_regs[0], args->_regs[1], args->_regs[2], 537*91f16700Schasinglulu args->_regs[3], args->_regs[4], args->_regs[5], 538*91f16700Schasinglulu args->_regs[6], args->_regs[7]); 539*91f16700Schasinglulu args = tsp_event_loop(ret._regs[0], ret._regs[1], ret._regs[2], 540*91f16700Schasinglulu ret._regs[3], ret._regs[4], ret._regs[5], 541*91f16700Schasinglulu ret._regs[6], ret._regs[7]); 542*91f16700Schasinglulu } while (1); 543*91f16700Schasinglulu 544*91f16700Schasinglulu /* Not Reached. */ 545*91f16700Schasinglulu return NULL; 546*91f16700Schasinglulu } 547*91f16700Schasinglulu 548*91f16700Schasinglulu /******************************************************************************* 549*91f16700Schasinglulu * TSP main entry point where it gets the opportunity to initialize its secure 550*91f16700Schasinglulu * state/applications. Once the state is initialized, it must return to the 551*91f16700Schasinglulu * SPD with a pointer to the 'tsp_vector_table' jump table. 552*91f16700Schasinglulu ******************************************************************************/ 553*91f16700Schasinglulu uint64_t tsp_main(void) 554*91f16700Schasinglulu { 555*91f16700Schasinglulu smc_args_t smc_args = {0}; 556*91f16700Schasinglulu 557*91f16700Schasinglulu NOTICE("TSP: %s\n", version_string); 558*91f16700Schasinglulu NOTICE("TSP: %s\n", build_message); 559*91f16700Schasinglulu INFO("TSP: Total memory base : 0x%lx\n", (unsigned long) BL32_BASE); 560*91f16700Schasinglulu INFO("TSP: Total memory size : 0x%lx bytes\n", BL32_TOTAL_SIZE); 561*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 562*91f16700Schasinglulu 563*91f16700Schasinglulu /* Initialize the platform. */ 564*91f16700Schasinglulu tsp_platform_setup(); 565*91f16700Schasinglulu 566*91f16700Schasinglulu /* Initialize secure/applications state here. */ 567*91f16700Schasinglulu tsp_generic_timer_start(); 568*91f16700Schasinglulu 569*91f16700Schasinglulu /* Register secondary entrypoint with the SPMC. */ 570*91f16700Schasinglulu smc_args = smc_helper(FFA_SECONDARY_EP_REGISTER_SMC64, 571*91f16700Schasinglulu (uint64_t) tsp_cpu_on_entry, 572*91f16700Schasinglulu 0, 0, 0, 0, 0, 0); 573*91f16700Schasinglulu if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) { 574*91f16700Schasinglulu ERROR("TSP could not register secondary ep (0x%lx)\n", 575*91f16700Schasinglulu smc_args._regs[2]); 576*91f16700Schasinglulu panic(); 577*91f16700Schasinglulu } 578*91f16700Schasinglulu /* Get TSP's endpoint id. */ 579*91f16700Schasinglulu smc_args = smc_helper(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0); 580*91f16700Schasinglulu if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) { 581*91f16700Schasinglulu ERROR("TSP could not get own ID (0x%lx) on core%d\n", 582*91f16700Schasinglulu smc_args._regs[2], linear_id); 583*91f16700Schasinglulu panic(); 584*91f16700Schasinglulu } 585*91f16700Schasinglulu 586*91f16700Schasinglulu tsp_id = smc_args._regs[2]; 587*91f16700Schasinglulu INFO("TSP FF-A endpoint id = 0x%x\n", tsp_id); 588*91f16700Schasinglulu 589*91f16700Schasinglulu /* Get the SPMC ID. */ 590*91f16700Schasinglulu smc_args = smc_helper(FFA_SPM_ID_GET, 0, 0, 0, 0, 0, 0, 0); 591*91f16700Schasinglulu if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) { 592*91f16700Schasinglulu ERROR("TSP could not get SPMC ID (0x%lx) on core%d\n", 593*91f16700Schasinglulu smc_args._regs[2], linear_id); 594*91f16700Schasinglulu panic(); 595*91f16700Schasinglulu } 596*91f16700Schasinglulu 597*91f16700Schasinglulu spmc_id = smc_args._regs[2]; 598*91f16700Schasinglulu 599*91f16700Schasinglulu /* Call RXTX_MAP to map a 4k RX and TX buffer. */ 600*91f16700Schasinglulu if (ffa_rxtx_map((uintptr_t) send_page, 601*91f16700Schasinglulu (uintptr_t) recv_page, 1)) { 602*91f16700Schasinglulu ERROR("TSP could not map it's RX/TX Buffers\n"); 603*91f16700Schasinglulu panic(); 604*91f16700Schasinglulu } 605*91f16700Schasinglulu 606*91f16700Schasinglulu mailbox.tx_buffer = send_page; 607*91f16700Schasinglulu mailbox.rx_buffer = recv_page; 608*91f16700Schasinglulu mailbox.rxtx_page_count = 1; 609*91f16700Schasinglulu 610*91f16700Schasinglulu /* Update this cpu's statistics. */ 611*91f16700Schasinglulu tsp_stats[linear_id].smc_count++; 612*91f16700Schasinglulu tsp_stats[linear_id].eret_count++; 613*91f16700Schasinglulu tsp_stats[linear_id].cpu_on_count++; 614*91f16700Schasinglulu 615*91f16700Schasinglulu VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n", 616*91f16700Schasinglulu read_mpidr(), 617*91f16700Schasinglulu tsp_stats[linear_id].smc_count, 618*91f16700Schasinglulu tsp_stats[linear_id].eret_count, 619*91f16700Schasinglulu tsp_stats[linear_id].cpu_on_count); 620*91f16700Schasinglulu 621*91f16700Schasinglulu /* Tell SPMD that we are done initialising. */ 622*91f16700Schasinglulu tsp_loop(set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0)); 623*91f16700Schasinglulu 624*91f16700Schasinglulu /* Not reached. */ 625*91f16700Schasinglulu return 0; 626*91f16700Schasinglulu } 627*91f16700Schasinglulu 628*91f16700Schasinglulu /******************************************************************************* 629*91f16700Schasinglulu * This function performs any remaining book keeping in the test secure payload 630*91f16700Schasinglulu * after this cpu's architectural state has been setup in response to an earlier 631*91f16700Schasinglulu * psci cpu_on request. 632*91f16700Schasinglulu ******************************************************************************/ 633*91f16700Schasinglulu smc_args_t *tsp_cpu_on_main(void) 634*91f16700Schasinglulu { 635*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 636*91f16700Schasinglulu 637*91f16700Schasinglulu /* Initialize secure/applications state here. */ 638*91f16700Schasinglulu tsp_generic_timer_start(); 639*91f16700Schasinglulu 640*91f16700Schasinglulu /* Update this cpu's statistics. */ 641*91f16700Schasinglulu tsp_stats[linear_id].smc_count++; 642*91f16700Schasinglulu tsp_stats[linear_id].eret_count++; 643*91f16700Schasinglulu tsp_stats[linear_id].cpu_on_count++; 644*91f16700Schasinglulu VERBOSE("TSP: cpu 0x%lx turned on\n", read_mpidr()); 645*91f16700Schasinglulu VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n", 646*91f16700Schasinglulu read_mpidr(), 647*91f16700Schasinglulu tsp_stats[linear_id].smc_count, 648*91f16700Schasinglulu tsp_stats[linear_id].eret_count, 649*91f16700Schasinglulu tsp_stats[linear_id].cpu_on_count); 650*91f16700Schasinglulu /* --------------------------------------------- 651*91f16700Schasinglulu * Jump to the main event loop to return to EL3 652*91f16700Schasinglulu * and be ready for the next request on this cpu. 653*91f16700Schasinglulu * --------------------------------------------- 654*91f16700Schasinglulu */ 655*91f16700Schasinglulu return tsp_loop(set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0)); 656*91f16700Schasinglulu } 657