diff options
author | Dimitris Papastamos <dimitris.papastamos@arm.com> | 2018-03-16 10:51:43 +0000 |
---|---|---|
committer | Dimitris Papastamos <dimitris.papastamos@arm.com> | 2018-03-19 14:05:44 +0000 |
commit | a0d9ef5c54fb8ed43967b5a871346c635c6e6886 (patch) | |
tree | 257a4f8d4d8f4112b8bab2f2ed67a655f18e44c8 /tests/runtime_services | |
parent | 90d54fce5f4c2ed0ab4de290e2c47f9093d998b2 (diff) |
Add SMCCC v1.2 test case
Change-Id: I3af1aded9f42344874cd1f0bd5140db22d74ad26
Signed-off-by: Dimitris Papastamos <dimitris.papastamos@arm.com>
Diffstat (limited to 'tests/runtime_services')
-rw-r--r-- | tests/runtime_services/arm_arch_svc/arm_arch_svc.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/tests/runtime_services/arm_arch_svc/arm_arch_svc.c b/tests/runtime_services/arm_arch_svc/arm_arch_svc.c new file mode 100644 index 0000000..64c26c9 --- /dev/null +++ b/tests/runtime_services/arm_arch_svc/arm_arch_svc.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of ARM 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 HOLDER 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. + */ + +#include <arch_helpers.h> +#include <arm_arch_svc.h> +#include <debug.h> +#include <plat_topology.h> +#include <power_management.h> +#include <psci.h> +#include <smc.h> +#include <string.h> +#include <tftf_lib.h> + +#ifdef AARCH64 +#define CORTEX_A57_MIDR 0x410FD070 +#define CORTEX_A72_MIDR 0x410FD080 +#define CORTEX_A73_MIDR 0x410FD090 +#define CORTEX_A75_MIDR 0x410FD0A0 + +static int cortex_a57_test(void); +static int csv2_test(void); + +static struct ent { + unsigned int midr; + int (*wa_required)(void); +} entries[] = { + { .midr = CORTEX_A57_MIDR, .wa_required = cortex_a57_test }, + { .midr = CORTEX_A72_MIDR, .wa_required = csv2_test }, + { .midr = CORTEX_A73_MIDR, .wa_required = csv2_test }, + { .midr = CORTEX_A75_MIDR, .wa_required = csv2_test }, +}; + +static int cortex_a57_test(void) +{ + return 1; +} + +static int csv2_test(void) +{ + uint64_t pfr0; + + pfr0 = read_id_aa64pfr0_el1() >> ID_AA64PFR0_CSV2_SHIFT; + if ((pfr0 & ID_AA64PFR0_CSV2_MASK) == 1) + return 0; + return 1; +} + +static test_result_t test_smccc_entrypoint(void) +{ + smc_args args; + smc_ret_values ret; + int32_t expected_ver; + unsigned int my_midr, midr_mask; + int wa_required; + size_t i; + + /* Check if SMCCC version is at least v1.1 */ + expected_ver = MAKE_SMCCC_VERSION(1, 1); + memset(&args, 0, sizeof(args)); + args.arg0 = SMCCC_VERSION; + ret = tftf_smc(&args); + if ((int32_t)ret.ret0 < expected_ver) { + tftf_testcase_printf("Unexpected SMCCC version: 0x%x\n", + (int)ret.ret0); + return TEST_RESULT_SKIPPED; + } + + /* Check if SMCCC_ARCH_WORKAROUND_1 is required or not */ + memset(&args, 0, sizeof(args)); + args.arg0 = SMCCC_ARCH_FEATURES; + args.arg1 = SMCCC_ARCH_WORKAROUND_1; + ret = tftf_smc(&args); + if ((int)ret.ret0 == -1) { + tftf_testcase_printf("SMCCC_ARCH_WORKAROUND_1 is not implemented\n"); + return TEST_RESULT_SKIPPED; + } + + /* If the call returns 0, it means the workaround is required */ + if ((int)ret.ret0 == 0) + wa_required = 1; + else + wa_required = 0; + + /* Check if the SMC return value matches our expectations */ + my_midr = (unsigned int)read_midr_el1(); + midr_mask = (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | + (MIDR_PN_MASK << MIDR_PN_SHIFT); + for (i = 0; i < ARRAY_SIZE(entries); i++) { + struct ent *entp = &entries[i]; + + if ((my_midr & midr_mask) == (entp->midr & midr_mask)) { + if (entp->wa_required() != wa_required) + return TEST_RESULT_FAIL; + break; + } + } + if (i == ARRAY_SIZE(entries) && wa_required) { + tftf_testcase_printf("TFTF workaround table out of sync with TF\n"); + return TEST_RESULT_FAIL; + } + + /* Invoke the workaround to make sure nothing nasty happens */ + memset(&args, 0, sizeof(args)); + args.arg0 = SMCCC_ARCH_WORKAROUND_1; + tftf_smc(&args); + return TEST_RESULT_SUCCESS; +} + +test_result_t test_arm_arch_svc(void) +{ + u_register_t lead_mpid, target_mpid; + int cpu_node, ret; + + lead_mpid = read_mpidr_el1() & MPID_MASK; + + /* Power on all the non-lead cores. */ + for_each_cpu(cpu_node) { + target_mpid = tftf_get_mpidr_from_node(cpu_node); + if (lead_mpid == target_mpid) + continue; + ret = tftf_cpu_on(target_mpid, + (uintptr_t)test_smccc_entrypoint, 0); + if (ret != PSCI_E_SUCCESS) { + ERROR("CPU ON failed for 0x%llx\n", + (unsigned long long)target_mpid); + return TEST_RESULT_FAIL; + } + /* + * Wait for test_smccc_entrypoint to return + * and the CPU to power down + */ + while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) != + PSCI_STATE_OFF) + continue; + } + + return test_smccc_entrypoint(); +} +#else +test_result_t test_arm_arch_svc(void) +{ + INFO("%s skipped on AArch32\n", __func__); + return TEST_RESULT_SKIPPED; +} +#endif |