diff options
Diffstat (limited to 'tftf/tests/runtime_services/mm_service')
3 files changed, 414 insertions, 0 deletions
diff --git a/tftf/tests/runtime_services/mm_service/secure_service_helpers.c b/tftf/tests/runtime_services/mm_service/secure_service_helpers.c new file mode 100644 index 000000000..8675daeea --- /dev/null +++ b/tftf/tests/runtime_services/mm_service/secure_service_helpers.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform.h> +#include <secure_partition.h> +#include <string.h> + + +secure_partition_request_info_t *create_sps_request(uint32_t id, + const void *data, + uint64_t data_size) +{ + secure_partition_request_info_t *sps_request + = (void *) ARM_SECURE_SERVICE_BUFFER_BASE; + sps_request->id = id; + sps_request->data_size = data_size; + if (data_size != 0) + memcpy(sps_request->data, data, data_size); + return sps_request; +} diff --git a/tftf/tests/runtime_services/mm_service/test_secure_service_handle.c b/tftf/tests/runtime_services/mm_service/test_secure_service_handle.c new file mode 100644 index 000000000..ce4dd5c2a --- /dev/null +++ b/tftf/tests/runtime_services/mm_service/test_secure_service_handle.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <debug.h> +#include <events.h> +#include <mm_svc.h> +#include <plat_topology.h> +#include <platform.h> +#include <power_management.h> +#include <secure_partition.h> +#include <smccc.h> +#include <spm_svc.h> +#include <test_helpers.h> +#include <tftf_lib.h> +#include <xlat_tables_v2.h> + +static event_t cpu_has_finished_test[PLATFORM_CORE_COUNT]; + +/* Test routine for test_secure_partition_secondary_cores_seq() */ +static test_result_t test_secure_partition_secondary_cores_seq_fn(void) +{ + test_result_t result = TEST_RESULT_SUCCESS; + u_register_t cpu_mpid = read_mpidr_el1() & MPID_MASK; + unsigned int core_pos = platform_get_core_pos(cpu_mpid); + + secure_partition_request_info_t *sps_request = + create_sps_request(SPS_CHECK_ALIVE, NULL, 0); + + INFO("Sending MM_COMMUNICATE_AARCH64 from CPU %u\n", + platform_get_core_pos(read_mpidr_el1() & MPID_MASK)); + + smc_args mm_communicate_smc = { + MM_COMMUNICATE_AARCH64, + 0, + (u_register_t) sps_request, + 0 + }; + + smc_ret_values smc_ret = tftf_smc(&mm_communicate_smc); + + if ((uint32_t)smc_ret.ret0 != 0) { + tftf_testcase_printf("Cactus returned: 0x%x\n", + (uint32_t)smc_ret.ret0); + + result = TEST_RESULT_FAIL; + } + + tftf_send_event(&cpu_has_finished_test[core_pos]); + + return result; +} + +/* + * @Test_Aim@ This tests that secondary CPUs can access SPM services + * sequentially. + */ +test_result_t test_secure_partition_secondary_cores_seq(void) +{ + int psci_ret; + u_register_t lead_mpid, cpu_mpid; + unsigned int cpu_node, core_pos; + test_result_t result = TEST_RESULT_SUCCESS; + + SKIP_TEST_IF_LESS_THAN_N_CPUS(2); + + SKIP_TEST_IF_MM_VERSION_LESS_THAN(1, 0); + + VERBOSE("Mapping NS<->SP shared buffer\n"); + + int rc = mmap_add_dynamic_region(ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_SIZE, + MT_MEMORY | MT_RW | MT_NS); + if (rc != 0) { + tftf_testcase_printf("%d: mmap_add_dynamic_region() = %d\n", + __LINE__, rc); + result = TEST_RESULT_FAIL; + goto exit; + } + + lead_mpid = read_mpidr_el1() & MPID_MASK; + + INFO("Lead CPU is CPU %u\n", platform_get_core_pos(lead_mpid)); + + if (test_secure_partition_secondary_cores_seq_fn() != TEST_RESULT_SUCCESS) { + result = TEST_RESULT_FAIL; + goto exit_unmap; + } + + for_each_cpu(cpu_node) { + cpu_mpid = tftf_get_mpidr_from_node(cpu_node); + /* Skip lead CPU, we have already tested it */ + if (cpu_mpid == lead_mpid) { + continue; + } + + core_pos = platform_get_core_pos(cpu_mpid); + + tftf_init_event(&cpu_has_finished_test[core_pos]); + + VERBOSE("Powering on CPU %u\n", core_pos); + + psci_ret = tftf_cpu_on(cpu_mpid, + (uintptr_t)test_secure_partition_secondary_cores_seq_fn, 0); + if (psci_ret != PSCI_E_SUCCESS) { + tftf_testcase_printf( + "Failed to power on CPU %d (rc = %d)\n", + core_pos, psci_ret); + result = TEST_RESULT_FAIL; + goto exit_unmap; + } + + tftf_wait_for_event(&cpu_has_finished_test[core_pos]); + } + +exit_unmap: + VERBOSE("Unmapping NS<->SP shared buffer\n"); + + mmap_remove_dynamic_region(ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_SIZE); + +exit: + return result; +} + +/******************************************************************************/ + +static event_t cpu_can_start_test[PLATFORM_CORE_COUNT]; + +/* Test routine for test_secure_partition_secondary_core() */ +static test_result_t test_secure_partition_secondary_cores_sim_fn(void) +{ + test_result_t result = TEST_RESULT_SUCCESS; + u_register_t cpu_mpid = read_mpidr_el1() & MPID_MASK; + unsigned int core_pos = platform_get_core_pos(cpu_mpid); + + secure_partition_request_info_t *sps_request = + create_sps_request(SPS_CHECK_ALIVE, NULL, 0); + + smc_args mm_communicate_smc = { + MM_COMMUNICATE_AARCH64, + 0, + (u_register_t) sps_request, + 0 + }; + + tftf_wait_for_event(&cpu_can_start_test[core_pos]); + + /* + * Invoke SMCs for some time to make sure that all CPUs are doing it at + * the same time during the test. + */ + for (int i = 0; i < 100; i++) { + smc_ret_values smc_ret = tftf_smc(&mm_communicate_smc); + + if ((uint32_t)smc_ret.ret0 != 0) { + tftf_testcase_printf("Cactus returned 0x%x at CPU %d\n", + (uint32_t)smc_ret.ret0, core_pos); + result = TEST_RESULT_FAIL; + break; + } + } + + tftf_send_event(&cpu_has_finished_test[core_pos]); + + return result; +} + +/* + * @Test_Aim@ This tests that secondary CPUs can access SPM services + * simultaneously. + */ +test_result_t test_secure_partition_secondary_cores_sim(void) +{ + int psci_ret; + u_register_t lead_mpid, cpu_mpid; + unsigned int cpu_node, core_pos; + test_result_t result = TEST_RESULT_SUCCESS; + + SKIP_TEST_IF_LESS_THAN_N_CPUS(2); + + SKIP_TEST_IF_MM_VERSION_LESS_THAN(1, 0); + + VERBOSE("Mapping NS<->SP shared buffer\n"); + + int rc = mmap_add_dynamic_region(ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_SIZE, + MT_MEMORY | MT_RW | MT_NS); + if (rc != 0) { + tftf_testcase_printf("%d: mmap_add_dynamic_region() = %d\n", + __LINE__, rc); + result = TEST_RESULT_FAIL; + goto exit; + } + + lead_mpid = read_mpidr_el1() & MPID_MASK; + + INFO("Lead CPU is CPU %u\n", platform_get_core_pos(lead_mpid)); + + for_each_cpu(cpu_node) { + cpu_mpid = tftf_get_mpidr_from_node(cpu_node); + core_pos = platform_get_core_pos(cpu_mpid); + tftf_init_event(&cpu_can_start_test[core_pos]); + } + + for_each_cpu(cpu_node) { + cpu_mpid = tftf_get_mpidr_from_node(cpu_node); + /* Skip lead CPU as it is already powered on */ + if (cpu_mpid == lead_mpid) { + continue; + } + + core_pos = platform_get_core_pos(cpu_mpid); + + VERBOSE("Powering on CPU %u\n", core_pos); + + psci_ret = tftf_cpu_on(cpu_mpid, + (uintptr_t)test_secure_partition_secondary_cores_sim_fn, 0); + if (psci_ret != PSCI_E_SUCCESS) { + tftf_testcase_printf( + "Failed to power on CPU %d (rc = %d)\n", + core_pos, psci_ret); + result = TEST_RESULT_FAIL; + goto exit_unmap; + } + } + + for_each_cpu(cpu_node) { + cpu_mpid = tftf_get_mpidr_from_node(cpu_node); + core_pos = platform_get_core_pos(cpu_mpid); + tftf_send_event(&cpu_can_start_test[core_pos]); + } + + result = test_secure_partition_secondary_cores_sim_fn(); + + /* Wait until all CPUs have finished to unmap the NS<->SP buffer */ + for_each_cpu(cpu_node) { + cpu_mpid = tftf_get_mpidr_from_node(cpu_node); + core_pos = platform_get_core_pos(cpu_mpid); + tftf_wait_for_event(&cpu_has_finished_test[core_pos]); + } +exit_unmap: + VERBOSE("Unmapping NS<->SP shared buffer\n"); + + mmap_remove_dynamic_region(ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_SIZE); +exit: + return result; +} diff --git a/tftf/tests/runtime_services/mm_service/test_secure_service_interrupts.c b/tftf/tests/runtime_services/mm_service/test_secure_service_interrupts.c new file mode 100644 index 000000000..50c3df670 --- /dev/null +++ b/tftf/tests/runtime_services/mm_service/test_secure_service_interrupts.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <mm_svc.h> +#include <secure_partition.h> +#include <smccc.h> +#include <spm_svc.h> +#include <string.h> +#include <test_helpers.h> +#include <tftf_lib.h> +#include <timer.h> +#include <xlat_tables_v2.h> + +static volatile int timer_irq_received; + +/* + * ISR for the timer interrupt. + * Just update a global variable to prove it has been called. + */ +static int timer_handler(void *data) +{ + assert(timer_irq_received == 0); + timer_irq_received = 1; + return 0; +} + + +/* + * @Test_Aim@ Test that non-secure interrupts do not interrupt secure service + * requests. + * + * 1. Register a handler for the non-secure timer interrupt. + * + * 2. Program the non-secure timer to fire in 500 ms. + * + * 3. Make a long-running (> 500 ms) fast secure service request. + * This is achieved by requesting the timer sleep service in Cactus + * with a 1 second sleep delay. + * + * 4. While servicing the timer sleep request, the non-secure timer should + * fire but not interrupt Cactus. + * + * 5. Once back in TFTF, check the response from Cactus, which shows whether the + * secure service indeed ran to completion. + * + * 6. Also check whether the pending non-secure timer interrupt successfully got + * handled in TFTF. + */ +test_result_t test_secure_partition_interrupt_by_ns(void) +{ + secure_partition_request_info_t *sps_request; + test_result_t result = TEST_RESULT_FAIL; + + SKIP_TEST_IF_MM_VERSION_LESS_THAN(1, 0); + + VERBOSE("Mapping NS<->SP shared buffer\n"); + + int rc = mmap_add_dynamic_region(ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_SIZE, + MT_MEMORY | MT_RW | MT_NS); + if (rc != 0) { + tftf_testcase_printf("%d: mmap_add_dynamic_region() = %d\n", + __LINE__, rc); + return TEST_RESULT_FAIL; + } + + timer_irq_received = 0; + tftf_timer_register_handler(timer_handler); + + NOTICE("Programming the timer...\n"); + rc = tftf_program_timer(500); + if (rc < 0) { + tftf_testcase_printf("Failed to program timer (%d)\n", rc); + goto exit_test; + } + + INFO("Sending MM_COMMUNICATE_AARCH64 to Cactus\n"); + + uint8_t timer_delay = 1; + sps_request = create_sps_request(SPS_TIMER_SLEEP, + &timer_delay, sizeof(timer_delay)); + smc_args mm_communicate_smc = { + MM_COMMUNICATE_AARCH64, + 0, /* cookie, MBZ */ + (uintptr_t) sps_request, + 0 + }; + + smc_ret_values smc_ret = tftf_smc(&mm_communicate_smc); + + INFO("Returned from Cactus, MM_COMMUNICATE_AARCH64 handling complete\n"); + + /* + * If MM_COMMUNICATE gets interrupted, SPM will return SPM_QUEUED, which + * is normally not a valid return value for MM_COMMUNICATE. + */ + if ((uint32_t) smc_ret.ret0 != SPM_SUCCESS) { + tftf_testcase_printf("Cactus returned: 0x%x\n", + (uint32_t) smc_ret.ret0); + goto exit_test; + } + + uint32_t cactus_response; + memcpy(&cactus_response, sps_request->data, sizeof(cactus_response)); + if (cactus_response != CACTUS_FAST_REQUEST_SUCCESS) { + tftf_testcase_printf("Error code from the timer secure service: 0x%x\n", + cactus_response); + goto exit_test; + } + + /* + * If the timer interrupt is still pending, make sure it is taken right + * now. + */ + isb(); + + if (timer_irq_received == 1) + result = TEST_RESULT_SUCCESS; + +exit_test: + tftf_cancel_timer(); + tftf_timer_unregister_handler(); + + VERBOSE("Unmapping NS<->SP shared buffer\n"); + + mmap_remove_dynamic_region(ARM_SECURE_SERVICE_BUFFER_BASE, + ARM_SECURE_SERVICE_BUFFER_SIZE); + + return result; +} |