diff options
Diffstat (limited to 'tftf')
-rw-r--r-- | tftf/framework/framework.mk | 9 | ||||
-rw-r--r-- | tftf/framework/main.c | 20 | ||||
-rw-r--r-- | tftf/tests/extensions/mte/test_mte.c | 57 | ||||
-rw-r--r-- | tftf/tests/extensions/pauth/test_pauth.c | 267 | ||||
-rw-r--r-- | tftf/tests/extensions/ptrauth/test_ptrauth.c | 164 | ||||
-rw-r--r-- | tftf/tests/misc_tests/test_pmu_leakage.c | 393 | ||||
-rw-r--r-- | tftf/tests/runtime_services/standard_service/psci/api_tests/system_reset/test_system_reset.c | 32 | ||||
-rw-r--r-- | tftf/tests/tests-cpu-extensions.mk | 3 | ||||
-rw-r--r-- | tftf/tests/tests-cpu-extensions.xml | 2 | ||||
-rw-r--r-- | tftf/tests/tests-extensive.xml | 2 | ||||
-rw-r--r-- | tftf/tests/tests-manual.mk | 5 | ||||
-rw-r--r-- | tftf/tests/tests-manual.xml | 4 | ||||
-rw-r--r-- | tftf/tests/tests-pmu-leakage.mk | 9 | ||||
-rw-r--r-- | tftf/tests/tests-pmu-leakage.xml | 16 | ||||
-rw-r--r-- | tftf/tests/tests-reboot.mk | 1 | ||||
-rw-r--r-- | tftf/tests/tests-reboot.xml | 4 | ||||
-rw-r--r-- | tftf/tests/tests-standard.mk | 3 | ||||
-rw-r--r-- | tftf/tests/tests-standard.xml | 4 |
18 files changed, 812 insertions, 183 deletions
diff --git a/tftf/framework/framework.mk b/tftf/framework/framework.mk index 00bb84aa9..34601c2d6 100644 --- a/tftf/framework/framework.mk +++ b/tftf/framework/framework.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, Arm Limited. All rights reserved. +# Copyright (c) 2018-2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -73,6 +73,13 @@ FRAMEWORK_SOURCES += \ FRAMEWORK_SOURCES += ${COMPILER_RT_SRCS} +ifeq (${ARCH},aarch64) +# ARMv8.3 Pointer Authentication support files +FRAMEWORK_SOURCES += \ + lib/extensions/pauth/aarch64/pauth.c \ + lib/extensions/pauth/aarch64/pauth_helpers.S +endif + TFTF_LINKERFILE := tftf/framework/tftf.ld.S diff --git a/tftf/framework/main.c b/tftf/framework/main.c index e84e45070..a2e84b7ea 100644 --- a/tftf/framework/main.c +++ b/tftf/framework/main.c @@ -12,6 +12,7 @@ #include <irq.h> #include <mmio.h> #include <nvm.h> +#include <pauth.h> #include <plat_topology.h> #include <platform.h> #include <platform_def.h> @@ -528,19 +529,12 @@ void __dead2 tftf_cold_boot_main(void) #if ENABLE_PAUTH assert(is_armv8_3_pauth_apa_api_present()); - uint64_t *apiakey = plat_init_apiakey(); - - write_apiakeylo_el1(apiakey[0]); - write_apiakeyhi_el1(apiakey[1]); - - if (IS_IN_EL2()) { - write_sctlr_el2(read_sctlr_el2() | SCTLR_EnIA_BIT); - } else { - assert(IS_IN_EL1()); - write_sctlr_el1(read_sctlr_el1() | SCTLR_EnIA_BIT); - } - - isb(); + /* + * Program APIAKey_EL1 key and enable ARMv8.3-PAuth here as this + * function doesn't return, and RETAA instuction won't be executed, + * what would cause translation fault otherwise. + */ + pauth_init_enable(); #endif /* ENABLE_PAUTH */ tftf_platform_setup(); diff --git a/tftf/tests/extensions/mte/test_mte.c b/tftf/tests/extensions/mte/test_mte.c new file mode 100644 index 000000000..13da667d2 --- /dev/null +++ b/tftf/tests/extensions/mte/test_mte.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <tftf.h> +#include <tftf_lib.h> +#include <tsp.h> +#include <test_helpers.h> + +test_result_t test_mte_instructions(void) +{ + SKIP_TEST_IF_AARCH32(); +#ifdef AARCH64 + SKIP_TEST_IF_MTE_SUPPORT_LESS_THAN(MTE_IMPLEMENTED_EL0); + + /* irg */ + __asm__ volatile (".inst 0xD29BD5A9"); + __asm__ volatile (".inst 0x9ADF1129"); + /* addg */ + __asm__ volatile (".inst 0x91800129"); + /* subg */ + __asm__ volatile (".inst 0xD1800129"); + + return TEST_RESULT_SUCCESS; +#endif /* AARCH64 */ +} + +test_result_t test_mte_leakage(void) +{ + SKIP_TEST_IF_AARCH32(); +#ifdef AARCH64 + smc_args tsp_svc_params; + int gcr_el1; + + SKIP_TEST_IF_MTE_SUPPORT_LESS_THAN(MTE_IMPLEMENTED_ELX); + SKIP_TEST_IF_TSP_NOT_PRESENT(); + + /* We only test gcr_el1 as writes to other MTE registers are ignored */ + write_gcr_el1(0xdd); + + /* Standard SMC to ADD two numbers */ + tsp_svc_params.fid = TSP_STD_FID(TSP_ADD); + tsp_svc_params.arg1 = 4; + tsp_svc_params.arg2 = 6; + tftf_smc(&tsp_svc_params); + + gcr_el1 = read_gcr_el1(); + if (gcr_el1 != 0xdd) { + printf("gcr_el1 has changed to %d\n", gcr_el1); + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +#endif /* AARCH64 */ +} diff --git a/tftf/tests/extensions/pauth/test_pauth.c b/tftf/tests/extensions/pauth/test_pauth.c new file mode 100644 index 000000000..30b78ef19 --- /dev/null +++ b/tftf/tests/extensions/pauth/test_pauth.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <pauth.h> +#include <psci.h> +#include <smccc.h> +#include <test_helpers.h> +#include <tftf_lib.h> +#include <tftf.h> +#include <tsp.h> +#include <string.h> + +#ifdef __aarch64__ + +/* Number of ARMv8.3-PAuth keys */ +#define NUM_KEYS 5 + +static const char * const key_name[] = {"IA", "IB", "DA", "DB", "GA"}; + +static uint128_t pauth_keys_before[NUM_KEYS]; +static uint128_t pauth_keys_after[NUM_KEYS]; + +/* Check if ARMv8.3-PAuth key is enabled */ +static bool is_pauth_key_enabled(uint64_t key_bit) +{ + return (IS_IN_EL2() ? + ((read_sctlr_el2() & key_bit) != 0U) : + ((read_sctlr_el1() & key_bit) != 0U)); +} + +static test_result_t compare_pauth_keys(void) +{ + test_result_t result = TEST_RESULT_SUCCESS; + + for (unsigned int i = 0; i < NUM_KEYS; ++i) { + if (pauth_keys_before[i] != pauth_keys_after[i]) { + ERROR("AP%sKey_EL1 read 0x%llx:%llx " + "expected 0x%llx:%llx\n", key_name[i], + (uint64_t)(pauth_keys_after[i] >> 64), + (uint64_t)(pauth_keys_after[i]), + (uint64_t)(pauth_keys_before[i] >> 64), + (uint64_t)(pauth_keys_before[i])); + + result = TEST_RESULT_FAIL; + } + } + return result; +} + +/* + * Program or read ARMv8.3-PAuth keys (if already enabled) + * and store them in <pauth_keys_before> buffer + */ +static void set_store_pauth_keys(void) +{ + uint128_t plat_key; + + memset(pauth_keys_before, 0, NUM_KEYS * sizeof(uint128_t)); + + if (is_armv8_3_pauth_apa_api_present()) { + if (is_pauth_key_enabled(SCTLR_EnIA_BIT)) { + /* Read APIAKey_EL1 */ + plat_key = read_apiakeylo_el1() | + ((uint128_t)(read_apiakeyhi_el1()) << 64); + INFO("EnIA is set\n"); + } else { + /* Program APIAKey_EL1 */ + plat_key = init_apkey(); + write_apiakeylo_el1((uint64_t)plat_key); + write_apiakeyhi_el1((uint64_t)(plat_key >> 64)); + } + pauth_keys_before[0] = plat_key; + + if (is_pauth_key_enabled(SCTLR_EnIB_BIT)) { + /* Read APIBKey_EL1 */ + plat_key = read_apibkeylo_el1() | + ((uint128_t)(read_apibkeyhi_el1()) << 64); + INFO("EnIB is set\n"); + } else { + /* Program APIBKey_EL1 */ + plat_key = init_apkey(); + write_apibkeylo_el1((uint64_t)plat_key); + write_apibkeyhi_el1((uint64_t)(plat_key >> 64)); + } + pauth_keys_before[1] = plat_key; + + if (is_pauth_key_enabled(SCTLR_EnDA_BIT)) { + /* Read APDAKey_EL1 */ + plat_key = read_apdakeylo_el1() | + ((uint128_t)(read_apdakeyhi_el1()) << 64); + INFO("EnDA is set\n"); + } else { + /* Program APDAKey_EL1 */ + plat_key = init_apkey(); + write_apdakeylo_el1((uint64_t)plat_key); + write_apdakeyhi_el1((uint64_t)(plat_key >> 64)); + } + pauth_keys_before[2] = plat_key; + + if (is_pauth_key_enabled(SCTLR_EnDB_BIT)) { + /* Read APDBKey_EL1 */ + plat_key = read_apdbkeylo_el1() | + ((uint128_t)(read_apdbkeyhi_el1()) << 64); + INFO("EnDB is set\n"); + } else { + /* Program APDBKey_EL1 */ + plat_key = init_apkey(); + write_apdbkeylo_el1((uint64_t)plat_key); + write_apdbkeyhi_el1((uint64_t)(plat_key >> 64)); + } + pauth_keys_before[3] = plat_key; + } + + /* + * It is safe to assume that Generic Pointer authentication code key + * APGAKey_EL1 can be re-programmed, as this key is not set in + * TF-A Test suite and PACGA instruction is not used. + */ + if (is_armv8_3_pauth_gpa_gpi_present()) { + /* Program APGAKey_EL1 */ + plat_key = init_apkey(); + write_apgakeylo_el1((uint64_t)plat_key); + write_apgakeyhi_el1((uint64_t)(plat_key >> 64)); + pauth_keys_before[4] = plat_key; + } + + isb(); +} + +/* + * Read ARMv8.3-PAuth keys and store them in + * <pauth_keys_after> buffer + */ +static void read_pauth_keys(void) +{ + memset(pauth_keys_after, 0, NUM_KEYS * sizeof(uint128_t)); + + if (is_armv8_3_pauth_apa_api_present()) { + /* Read APIAKey_EL1 */ + pauth_keys_after[0] = read_apiakeylo_el1() | + ((uint128_t)(read_apiakeyhi_el1()) << 64); + + /* Read APIBKey_EL1 */ + pauth_keys_after[1] = read_apibkeylo_el1() | + ((uint128_t)(read_apibkeyhi_el1()) << 64); + + /* Read APDAKey_EL1 */ + pauth_keys_after[2] = read_apdakeylo_el1() | + ((uint128_t)(read_apdakeyhi_el1()) << 64); + + /* Read APDBKey_EL1 */ + pauth_keys_after[3] = read_apdbkeylo_el1() | + ((uint128_t)(read_apdbkeyhi_el1()) << 64); + } + + if (is_armv8_3_pauth_gpa_gpi_present()) { + /* Read APGAKey_EL1 */ + pauth_keys_after[4] = read_apgakeylo_el1() | + ((uint128_t)(read_apgakeyhi_el1()) << 64); + } +} +#endif /* __aarch64__ */ + +/* + * TF-A is expected to allow access to key registers from lower EL's, + * reading the keys excercises this, on failure this will trap to + * EL3 and crash. + */ +test_result_t test_pauth_reg_access(void) +{ + SKIP_TEST_IF_AARCH32(); +#ifdef __aarch64__ + SKIP_TEST_IF_PAUTH_NOT_SUPPORTED(); + read_pauth_keys(); + return TEST_RESULT_SUCCESS; +#endif /* __aarch64__ */ +} + +/* + * Makes a call to PSCI version, and checks that the EL3 pauth keys are not + * leaked when it returns + */ +test_result_t test_pauth_leakage(void) +{ + SKIP_TEST_IF_AARCH32(); +#ifdef __aarch64__ + SKIP_TEST_IF_PAUTH_NOT_SUPPORTED(); + set_store_pauth_keys(); + + tftf_get_psci_version(); + + read_pauth_keys(); + + return compare_pauth_keys(); +#endif /* __aarch64__ */ +} + +/* Test execution of ARMv8.3-PAuth instructions */ +test_result_t test_pauth_instructions(void) +{ + SKIP_TEST_IF_AARCH32(); +#ifdef __aarch64__ + SKIP_TEST_IF_PAUTH_NOT_SUPPORTED(); + +#if ARM_ARCH_AT_LEAST(8, 3) + /* Pointer authentication instructions */ + __asm__ volatile ( + "paciasp\n" + "autiasp\n" + "paciasp\n" + "xpaclri" + ); + return TEST_RESULT_SUCCESS; +#else + tftf_testcase_printf("Pointer Authentication instructions " + "are not supported on ARMv%u.%u\n", + ARM_ARCH_MAJOR, ARM_ARCH_MINOR); + return TEST_RESULT_SKIPPED; +#endif /* ARM_ARCH_AT_LEAST(8, 3) */ + +#endif /* __aarch64__ */ +} + +/* + * Makes a call to TSP ADD, and checks that the checks that the Secure World + * pauth keys are not leaked + */ +test_result_t test_pauth_leakage_tsp(void) +{ + SKIP_TEST_IF_AARCH32(); +#ifdef __aarch64__ + smc_args tsp_svc_params; + smc_ret_values tsp_result = {0}; + + SKIP_TEST_IF_PAUTH_NOT_SUPPORTED(); + SKIP_TEST_IF_TSP_NOT_PRESENT(); + + set_store_pauth_keys(); + + /* Standard SMC to ADD two numbers */ + tsp_svc_params.fid = TSP_STD_FID(TSP_ADD); + tsp_svc_params.arg1 = 4; + tsp_svc_params.arg2 = 6; + tsp_result = tftf_smc(&tsp_svc_params); + + /* + * Check the result of the addition-TSP_ADD will add + * the arguments to themselves and return + */ + if (tsp_result.ret0 != 0 || tsp_result.ret1 != 8 || + tsp_result.ret2 != 12) { + tftf_testcase_printf("TSP add returned wrong result: " + "got %d %d %d expected: 0 8 12\n", + (unsigned int)tsp_result.ret0, + (unsigned int)tsp_result.ret1, + (unsigned int)tsp_result.ret2); + return TEST_RESULT_FAIL; + } + + read_pauth_keys(); + + return compare_pauth_keys(); +#endif /* __aarch64__ */ +} diff --git a/tftf/tests/extensions/ptrauth/test_ptrauth.c b/tftf/tests/extensions/ptrauth/test_ptrauth.c deleted file mode 100644 index 564c56d9f..000000000 --- a/tftf/tests/extensions/ptrauth/test_ptrauth.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <psci.h> -#include <smccc.h> -#include <test_helpers.h> -#include <tftf_lib.h> -#include <tftf.h> -#include <tsp.h> -#include <string.h> - -/* The length of the array used to hold the pauth keys */ -#define LENGTH_KEYS 10 - -#ifndef AARCH32 -static void read_pauth_keys(uint64_t *pauth_keys, unsigned int len) -{ - assert(len >= LENGTH_KEYS); - - memset(pauth_keys, 0, len * sizeof(uint64_t)); - - if (is_armv8_3_pauth_apa_api_present()) { - /* read instruction keys a and b (both 128 bit) */ - pauth_keys[0] = read_apiakeylo_el1(); - pauth_keys[1] = read_apiakeyhi_el1(); - - pauth_keys[2] = read_apibkeylo_el1(); - pauth_keys[3] = read_apibkeyhi_el1(); - - /* read data keys a and b (both 128 bit) */ - pauth_keys[4] = read_apdakeylo_el1(); - pauth_keys[5] = read_apdakeyhi_el1(); - - pauth_keys[6] = read_apdbkeylo_el1(); - pauth_keys[7] = read_apdbkeyhi_el1(); - } - - if (is_armv8_3_pauth_gpa_gpi_present()) { - /* read generic key */ - pauth_keys[8] = read_apgakeylo_el1(); - pauth_keys[9] = read_apgakeyhi_el1(); - } - -} -#endif - -/* - * TF-A is expected to allow access to key registers from lower EL's, - * reading the keys excercises this, on failure this will trap to - * EL3 and crash. - */ -test_result_t test_pauth_reg_access(void) -{ - SKIP_TEST_IF_AARCH32(); -#ifndef AARCH32 - uint64_t pauth_keys[LENGTH_KEYS]; - SKIP_TEST_IF_PAUTH_NOT_SUPPORTED(); - read_pauth_keys(pauth_keys, LENGTH_KEYS); - return TEST_RESULT_SUCCESS; -#endif -} - -/* - * Makes a call to psci version, and checks that the EL3 pauth keys are not - * leaked when it returns - */ -#if (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 0)) && AARCH64 -__attribute__((target("sign-return-address=all"))) -#endif -test_result_t test_pauth_leakage(void) -{ - SKIP_TEST_IF_AARCH32(); -#ifndef AARCH32 - uint64_t pauth_keys_before[LENGTH_KEYS]; - uint64_t pauth_keys_after[LENGTH_KEYS]; - SKIP_TEST_IF_PAUTH_NOT_SUPPORTED(); - - read_pauth_keys(pauth_keys_before, LENGTH_KEYS); - - tftf_get_psci_version(); - - read_pauth_keys(pauth_keys_after, LENGTH_KEYS); - - if (memcmp(pauth_keys_before, pauth_keys_after, - LENGTH_KEYS * sizeof(uint64_t)) != 0) - return TEST_RESULT_FAIL; - return TEST_RESULT_SUCCESS; -#endif -} - -/* Uses the pauth instructions, this checks the enable PAUTH bit has been set */ -test_result_t test_pauth_instructions(void) -{ - SKIP_TEST_IF_AARCH32(); -#ifndef AARCH32 - SKIP_TEST_IF_PAUTH_NOT_SUPPORTED(); - /* - * Pointer authentication instructions (explicit encoding for compilers - * that do not recognize these instructions) - */ - /* paciasp */ - __asm__ volatile (".inst 0xD503233F"); - /* autiasp */ - __asm__ volatile (".inst 0xD50323BF"); - /* paciasp */ - __asm__ volatile (".inst 0xD503233F"); - /* xpaclri */ - __asm__ volatile (".inst 0xD50320FF"); - return TEST_RESULT_SUCCESS; -#endif -} - -/* - * Makes a call to TSP ADD, and checks that the checks that the Secure World - * pauth keys are not leaked - */ -#if (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 0)) && AARCH64 -__attribute__((target("sign-return-address=all"))) -#endif -test_result_t test_pauth_leakage_tsp(void) -{ - SKIP_TEST_IF_AARCH32(); -#ifndef AARCH32 - smc_args tsp_svc_params; - smc_ret_values tsp_result = {0}; - uint64_t pauth_keys_before[LENGTH_KEYS]; - uint64_t pauth_keys_after[LENGTH_KEYS]; - - SKIP_TEST_IF_PAUTH_NOT_SUPPORTED(); - SKIP_TEST_IF_TSP_NOT_PRESENT(); - - read_pauth_keys(pauth_keys_before, LENGTH_KEYS); - - /* Standard SMC to ADD two numbers */ - tsp_svc_params.fid = TSP_STD_FID(TSP_ADD); - tsp_svc_params.arg1 = 4; - tsp_svc_params.arg2 = 6; - tsp_result = tftf_smc(&tsp_svc_params); - - /* - * Check the result of the addition-TSP_ADD will add - * the arguments to themselves and return - */ - if (tsp_result.ret0 != 0 || tsp_result.ret1 != 8 || - tsp_result.ret2 != 12) { - tftf_testcase_printf("TSP add returned wrong result:" - "got %d %d %d expected: 0 8 12\n", - (unsigned int)tsp_result.ret0, - (unsigned int)tsp_result.ret1, - (unsigned int)tsp_result.ret2); - - return TEST_RESULT_FAIL; - } - read_pauth_keys(pauth_keys_after, LENGTH_KEYS); - - if (memcmp(pauth_keys_before, pauth_keys_after, - LENGTH_KEYS * sizeof(uint64_t)) != 0) - return TEST_RESULT_FAIL; - return TEST_RESULT_SUCCESS; -#endif -} diff --git a/tftf/tests/misc_tests/test_pmu_leakage.c b/tftf/tests/misc_tests/test_pmu_leakage.c new file mode 100644 index 000000000..09f4d510a --- /dev/null +++ b/tftf/tests/misc_tests/test_pmu_leakage.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * This file contains tests that try to leak information from the secure world + * to the non-secure world (EL2) by using the PMU counters. + * + * The tests assume that the PMU (PMUv3) is implemented on the target, since + * TF-A performs initialization of the PMU and guards against PMU counter + * leakage. + * + * The non-secure world can use system registers to configure the PMU such that + * it increments counters in the secure world. Depending on the implemented + * features, the secure world can prohibit counting via the following: + * -v8.2 Debug not implemented: + * |-- Prohibit general event counters and the cycle counter: + * MDCR_EL3.SPME == 0 && !ExternalSecureNoninvasiveDebugEnabled() + * Since ExternalSecureNoninvasiveDebugEnabled() is a hardware + * line, it is not available on FVP and will therefore cause the + * tests to fail. + * The only other way is to disable the PMCR_EL0.E bit. This will + * disable counting altogether, but since this fix is not desired + * in TF-A, the tests have to be skipped if v8.2 Debug is not + * implemented. + * + * -v8.2 Debug implemented: + * |-- Prohibit general event counters: MDCR_EL3.SPME == 0. This bit + * resets to 0, so by default general events should not be counted + * in the secure world. + * |-- Prohibit cycle counter: MDCR_EL3.SPME == 0 && PMCR_EL0.DP == 1. + * This counter is only affected by MDCR_EL3.SPME if the + * PMCR_EL0.DP bit is set. + * + * -v8.5 implemented: + * |-- Prohibit general event counters: as in v8.2 Debug. + * |-- Prohibit cycle counter: MDCR_EL3.SCCD == 1 + */ + +#include <drivers/arm/arm_gic.h> +#include <irq.h> +#include <platform.h> +#include <power_management.h> +#include <sgi.h> +#include <string.h> +#include <test_helpers.h> + +#ifdef AARCH64 +#define ITERATIONS_CNT 1000 + +/* + * A maximum of +10% deviation in event counts is tolerated. + * This is useful for testing on real hardware where event counts are usually + * not the same between runs. The large iteration count should cause the + * average event count to converge to values very close to baseline when the + * secure world successfully prohibits PMU counters from incrementing. + */ +#define ALLOWED_DEVIATION 10 + +/* + * An invalid SMC function number. + * Used to establish a base value for PMU counters on each test. + */ +#define INVALID_FN 0x666 + +struct pmu_event_info { + unsigned long long min; + unsigned long long max; + unsigned long long avg; +}; + +static inline void configure_pmu_cntr0(const uint32_t event) +{ + /* + * Disabling the P bit tells the counter to increment at EL1. + * Setting the NSK bit to be different from the P bit further tells the + * counter NOT to increment at non-secure EL1. Combined with the P bit, + * the effect is to tell the counter to increment at secure EL1. + * Setting the M bit to be equal to the P bit tells the counter to + * increment at EL3. + * Disabling the NSH bit tells the counter NOT to increment at + * non-secure EL2. + * Setting the SH bit to be different to the NSH bit tells the counter + * to increment at secure EL2. + * The counter therefore is told to count only at secure EL1, secure EL2 + * and EL3. This is to ensure maximum accuracy of the results, since we + * are only interested if the secure world is leaking PMU counters. + */ + write_pmevtyper0_el0( + (read_pmevtyper0_el0() | PMEVTYPER_EL0_NSK_BIT | + PMEVTYPER_EL0_SH_BIT) & + ~(PMEVTYPER_EL0_P_BIT | PMEVTYPER_EL0_NSH_BIT | + PMEVTYPER_EL0_M_BIT)); + + /* + * Write to the EVTCOUNT bits to tell the counter which event to + * monitor. + */ + write_pmevtyper0_el0( + (read_pmevtyper0_el0() & ~PMEVTYPER_EL0_EVTCOUNT_BITS) | event); + + /* Setting the P[n] bit enables counter n */ + write_pmcntenset_el0( + read_pmcntenset_el0() | PMCNTENSET_EL0_P_BIT(0)); +} + +static inline void configure_pmu_cycle_cntr(void) +{ + /* + * Disabling the P bit tells the counter to increment at EL1. + * Setting the NSK bit to be different from the P bit further tells the + * counter NOT to increment at non-secure EL1. Combined with the P bit, + * the effect is to tell the counter to increment at secure EL1. + * Setting the M bit to be equal to the P bit tells the counter to + * increment at EL3. + * Disabling the NSH bit tells the counter NOT to increment at + * non-secure EL2. + * Setting the SH bit to be different to the NSH bit tells the counter + * to increment at secure EL2. + * The counter therefore is told to count only at secure EL1, secure EL2 + * and EL3. This is to ensure maximum accuracy of the results, since we + * are only interested if the secure world is leaking PMU counters. + */ + write_pmccfiltr_el0( + (read_pmccfiltr_el0() | PMCCFILTR_EL0_NSK_BIT | + PMCCFILTR_EL0_SH_BIT) & + ~(PMCCFILTR_EL0_P_BIT | PMCCFILTR_EL0_NSH_BIT | + PMCCFILTR_EL0_M_BIT)); + + /* Setting the C bit enables the cycle counter in the PMU */ + write_pmcntenset_el0( + read_pmcntenset_el0() | PMCNTENSET_EL0_C_BIT); + + /* + * Disabling the DP bit makes the cycle counter increment where + * prohibited by MDCR_EL3.SPME. If higher execution levels don't save + * and restore PMCR_EL0, then PMU information will be leaked. + */ + write_pmcr_el0(read_pmcr_el0() & ~PMCR_EL0_DP_BIT); +} + +static inline void pmu_enable_counting(void) +{ + /* + * Setting the E bit gives [fine-grained] control to the PMCNTENSET_EL0 + * register, which controls which counters can increment. + */ + write_pmcr_el0(read_pmcr_el0() | PMCR_EL0_E_BIT); +} + +static unsigned long long profile_invalid_smc(u_register_t (*read_cntr_f)(void)) +{ + unsigned long long evt_cnt; + smc_args args = { INVALID_FN }; + + evt_cnt = (*read_cntr_f)(); + tftf_smc(&args); + evt_cnt = (*read_cntr_f)() - evt_cnt; + + return evt_cnt; +} + +static unsigned long long profile_cpu_suspend(u_register_t (*read_cntr_f)(void)) +{ + unsigned long long evt_cnt; + unsigned int power_state; + unsigned int stateid; + + tftf_psci_make_composite_state_id(MPIDR_AFFLVL0, + PSTATE_TYPE_STANDBY, &stateid); + power_state = tftf_make_psci_pstate(MPIDR_AFFLVL0, + PSTATE_TYPE_STANDBY, stateid); + + tftf_irq_enable(IRQ_NS_SGI_0, GIC_HIGHEST_NS_PRIORITY); + + /* + * Mask IRQ to prevent the interrupt handler being invoked + * and clearing the interrupt. A pending interrupt will cause this + * CPU to wake-up from suspend. + */ + disable_irq(); + + /* Configure an SGI to wake-up from suspend */ + tftf_send_sgi(IRQ_NS_SGI_0, + platform_get_core_pos(read_mpidr_el1() & MPID_MASK)); + + evt_cnt = (*read_cntr_f)(); + tftf_cpu_suspend(power_state); + evt_cnt = (*read_cntr_f)() - evt_cnt; + + /* Unmask the IRQ to let the interrupt handler to execute */ + enable_irq(); + isb(); + + tftf_irq_disable(IRQ_NS_SGI_0); + + return evt_cnt; +} + +static unsigned long long profile_fast_smc_add(u_register_t (*read_cntr_f)(void)) +{ + unsigned long long evt_cnt; + smc_args args = { TSP_FAST_FID(TSP_ADD), 4, 6 }; + + evt_cnt = (*read_cntr_f)(); + tftf_smc(&args); + evt_cnt = (*read_cntr_f)() - evt_cnt; + + return evt_cnt; +} + +static void measure_event(u_register_t (*read_cntr_func)(void), + unsigned long long (*profile_func)(u_register_t (*read_cntr_f)(void)), + struct pmu_event_info *info) +{ + unsigned long long evt_cnt; + unsigned long long min_cnt; + unsigned long long max_cnt; + unsigned long long avg_cnt; + unsigned long long cnt_sum = 0; + + min_cnt = UINT64_MAX; + max_cnt = 0; + + for (unsigned int i = 0; i < ITERATIONS_CNT; ++i) { + evt_cnt = (*profile_func)(read_cntr_func); + + min_cnt = MIN(min_cnt, evt_cnt); + max_cnt = MAX(max_cnt, evt_cnt); + + cnt_sum += evt_cnt; + + tftf_irq_disable(IRQ_NS_SGI_0); + } + + avg_cnt = cnt_sum / ITERATIONS_CNT; + + info->avg = avg_cnt; + info->min = min_cnt; + info->max = max_cnt; + + tftf_testcase_printf( + "Average count: %llu (ranging from %llu to %llu)\n", + avg_cnt, + min_cnt, + max_cnt); +} + +/* + * Checks that when requesting an SMC call after getting a baseline PMU event + * count the number of PMU events counted is either not greater than the + * baseline or it has increased by no more than ALLOWED_DEVIATION%. The first + * comparison is required because of underflow on unsigned types. + * This is used to determine if PMU timing information has been leaked from the + * secure world. + */ +static bool results_within_allowed_margin(unsigned long long baseline_cnt, + unsigned long long smc_cnt) +{ + return (smc_cnt <= baseline_cnt) || + (smc_cnt - baseline_cnt <= baseline_cnt / ALLOWED_DEVIATION); +} + +/* + * Measure the number of retired writes to the PC in the PSCI_SUSPEND SMC. + * This test only succeeds if no useful information about the PMU counters has + * been leaked. + */ +test_result_t smc_psci_suspend_pc_write_retired(void) +{ + struct pmu_event_info baseline, cpu_suspend; + + SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN( + ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED); + + configure_pmu_cntr0(PMU_EV_PC_WRITE_RETIRED); + pmu_enable_counting(); + + tftf_testcase_printf("Getting baseline event count:\n"); + measure_event(read_pmevcntr0_el0, profile_invalid_smc, &baseline); + tftf_testcase_printf("Profiling PSCI_SUSPEND_PC:\n"); + measure_event(read_pmevcntr0_el0, profile_cpu_suspend, &cpu_suspend); + + if (!results_within_allowed_margin(baseline.avg, cpu_suspend.avg)) + return TEST_RESULT_FAIL; + return TEST_RESULT_SUCCESS; +} + +/* + * Measure the CPU cycles count of the PSCI_SUSPEND SMC. + * This test only succeeds if no useful information about the PMU counters has + * been leaked. + */ +test_result_t smc_psci_suspend_cycles(void) +{ + struct pmu_event_info baseline, cpu_suspend; + + SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN( + ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED); + + configure_pmu_cycle_cntr(); + pmu_enable_counting(); + + tftf_testcase_printf("Getting baseline event count:\n"); + measure_event(read_pmccntr_el0, profile_invalid_smc, &baseline); + tftf_testcase_printf("Profiling PSCI_SUSPEND_PC:\n"); + measure_event(read_pmccntr_el0, profile_cpu_suspend, &cpu_suspend); + + if (!results_within_allowed_margin(baseline.avg, cpu_suspend.avg)) + return TEST_RESULT_FAIL; + return TEST_RESULT_SUCCESS; +} + +/* + * Measure the number of retired writes to the PC in the fast add SMC. + * This test only succeeds if no useful information about the PMU counters has + * been leaked. + */ +test_result_t fast_smc_add_pc_write_retired(void) +{ + struct pmu_event_info baseline, fast_smc_add; + + SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN( + ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED); + + SKIP_TEST_IF_TSP_NOT_PRESENT(); + + configure_pmu_cntr0(PMU_EV_PC_WRITE_RETIRED); + pmu_enable_counting(); + + tftf_testcase_printf("Getting baseline event count:\n"); + measure_event(read_pmevcntr0_el0, profile_invalid_smc, &baseline); + tftf_testcase_printf("Profiling Fast Add SMC:\n"); + measure_event(read_pmevcntr0_el0, profile_fast_smc_add, &fast_smc_add); + + if (!results_within_allowed_margin(baseline.avg, fast_smc_add.avg)) + return TEST_RESULT_FAIL; + return TEST_RESULT_SUCCESS; +} + +/* + * Measure the CPU cycles count of the fast add SMC. + * This test only succeeds if no useful information about the PMU counters has + * been leaked. + */ +test_result_t fast_smc_add_cycles(void) +{ + struct pmu_event_info baseline, fast_smc_add; + + SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN( + ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED); + + SKIP_TEST_IF_TSP_NOT_PRESENT(); + + configure_pmu_cycle_cntr(); + pmu_enable_counting(); + + tftf_testcase_printf("Getting baseline event count:\n"); + measure_event(read_pmccntr_el0, profile_invalid_smc, &baseline); + tftf_testcase_printf("Profiling Fast Add SMC:\n"); + measure_event(read_pmccntr_el0, profile_fast_smc_add, &fast_smc_add); + + if (!results_within_allowed_margin(baseline.avg, fast_smc_add.avg)) + return TEST_RESULT_FAIL; + return TEST_RESULT_SUCCESS; +} +#else +test_result_t smc_psci_suspend_pc_write_retired(void) +{ + INFO("%s skipped on AArch32\n", __func__); + return TEST_RESULT_SKIPPED; +} + +test_result_t smc_psci_suspend_cycles(void) +{ + INFO("%s skipped on AArch32\n", __func__); + return TEST_RESULT_SKIPPED; +} + +test_result_t fast_smc_add_pc_write_retired(void) +{ + INFO("%s skipped on AArch32\n", __func__); + return TEST_RESULT_SKIPPED; +} + +test_result_t fast_smc_add_cycles(void) +{ + INFO("%s skipped on AArch32\n", __func__); + return TEST_RESULT_SKIPPED; +} +#endif diff --git a/tftf/tests/runtime_services/standard_service/psci/api_tests/system_reset/test_system_reset.c b/tftf/tests/runtime_services/standard_service/psci/api_tests/system_reset/test_system_reset.c new file mode 100644 index 000000000..41eb7af18 --- /dev/null +++ b/tftf/tests/runtime_services/standard_service/psci/api_tests/system_reset/test_system_reset.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <psci.h> +#include <smccc.h> +#include <tftf_lib.h> + +/* + * @Test_Aim@ Validate the SYSTEM_RESET call. + * Test SUCCESS in case of system reset. + * Test FAIL in case of execution not terminated. + */ +test_result_t test_system_reset(void) +{ + smc_args args = { SMC_PSCI_SYSTEM_RESET }; + + if (tftf_is_rebooted() == 1) { + /* Successfully resumed from SYSTEM_RESET */ + return TEST_RESULT_SUCCESS; + } + + tftf_notify_reboot(); + tftf_smc(&args); + + /* The PSCI SYSTEM_RESET call is not supposed to return */ + tftf_testcase_printf("System didn't reboot properly\n"); + + return TEST_RESULT_FAIL; +} diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk index daf9528ab..9102b351d 100644 --- a/tftf/tests/tests-cpu-extensions.mk +++ b/tftf/tests/tests-cpu-extensions.mk @@ -6,9 +6,10 @@ TESTS_SOURCES += $(addprefix tftf/tests/, \ extensions/amu/test_amu.c \ + extensions/mte/test_mte.c \ extensions/sve/sve_operations.S \ extensions/sve/test_sve.c \ runtime_services/arm_arch_svc/smccc_arch_workaround_1.c \ runtime_services/arm_arch_svc/smccc_arch_workaround_2.c \ - extensions/ptrauth/test_ptrauth.c \ + extensions/pauth/test_pauth.c \ ) diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml index e64143782..158cb04f6 100644 --- a/tftf/tests/tests-cpu-extensions.xml +++ b/tftf/tests/tests-cpu-extensions.xml @@ -16,6 +16,8 @@ <testcase name="Use Pointer Authentication Instructions" function="test_pauth_instructions" /> <testcase name="Check for Pointer Authentication key leakage from EL3" function="test_pauth_leakage" /> <testcase name="Check for Pointer Authentication key leakage from TSP" function="test_pauth_leakage_tsp" /> + <testcase name="Use MTE Instructions" function="test_mte_instructions" /> + <testcase name="Check for MTE register leakage" function="test_mte_leakage" /> </testsuite> <testsuite name="ARM_ARCH_SVC" description="Arm Architecture Service tests"> diff --git a/tftf/tests/tests-extensive.xml b/tftf/tests/tests-extensive.xml index 67d2346be..773c19e0f 100644 --- a/tftf/tests/tests-extensive.xml +++ b/tftf/tests/tests-extensive.xml @@ -22,6 +22,7 @@ <!ENTITY tests-cpu-extensions SYSTEM "tests-cpu-extensions.xml"> <!ENTITY tests-performance SYSTEM "tests-performance.xml"> <!ENTITY tests-smc SYSTEM "tests-smc.xml"> + <!ENTITY tests-pmu-leakage SYSTEM "tests-pmu-leakage.xml"> ]> <testsuites> @@ -39,5 +40,6 @@ &tests-cpu-extensions; &tests-performance; &tests-smc; + &tests-pmu-leakage; </testsuites> diff --git a/tftf/tests/tests-manual.mk b/tftf/tests/tests-manual.mk index bd8132bb0..67e246090 100644 --- a/tftf/tests/tests-manual.mk +++ b/tftf/tests/tests-manual.mk @@ -1,11 +1,12 @@ # -# Copyright (c) 2018, Arm Limited. All rights reserved. +# Copyright (c) 2018-2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # TESTS_SOURCES += \ $(addprefix tftf/tests/runtime_services/standard_service/psci/api_tests/, \ + system_reset/test_system_reset.c \ mem_protect/test_mem_protect.c \ psci_stat/test_psci_stat.c \ reset2/reset2.c \ @@ -18,4 +19,4 @@ endif ifeq (${NEW_TEST_SESSION},1) $(error Manual tests require NEW_TEST_SESSION=0 to persist test results across reboots) -endif
\ No newline at end of file +endif diff --git a/tftf/tests/tests-manual.xml b/tftf/tests/tests-manual.xml index 0fd6e552b..f718fabb8 100644 --- a/tftf/tests/tests-manual.xml +++ b/tftf/tests/tests-manual.xml @@ -9,6 +9,10 @@ <testsuites> + <testsuite name="System Reset Test" description="Validate SYSTEM_RESET PSCI call"> + <testcase name="System Reset" function="test_system_reset" /> + </testsuite> + <testsuite name="PSCI STAT" description="Test PSCI STAT support System level"> <testcase name="for stats after system reset" function="test_psci_stats_after_reset" /> <testcase name="for stats after system shutdown" function="test_psci_stats_after_shutdown" /> diff --git a/tftf/tests/tests-pmu-leakage.mk b/tftf/tests/tests-pmu-leakage.mk new file mode 100644 index 000000000..2d46073fc --- /dev/null +++ b/tftf/tests/tests-pmu-leakage.mk @@ -0,0 +1,9 @@ +# +# Copyright (c) 2019, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +TESTS_SOURCES += $(addprefix tftf/tests/misc_tests/, \ + test_pmu_leakage.c \ + ) diff --git a/tftf/tests/tests-pmu-leakage.xml b/tftf/tests/tests-pmu-leakage.xml new file mode 100644 index 000000000..932c21fc4 --- /dev/null +++ b/tftf/tests/tests-pmu-leakage.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Copyright (c) 2018, Arm Limited. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause +--> + +<testsuites> + <testsuite name="PMU Leakage" description="Increment PMU counters in the secure world"> + <testcase name="Leak PMU PC_WRITE_RETIRED counter values from EL3 on PSCI suspend SMC" function="smc_psci_suspend_pc_write_retired" /> + <testcase name="Leak PMU CYCLE counter values from EL3 on PSCI suspend SMC" function="smc_psci_suspend_cycles" /> + <testcase name="Leak PMU PC_WRITE_RETIRED counter values from S_EL1 on fast SMC add" function="fast_smc_add_pc_write_retired" /> + <testcase name="Leak PMU CYCLE counter values from S_EL1 on fast SMC add" function="fast_smc_add_cycles" /> + </testsuite> +</testsuites> diff --git a/tftf/tests/tests-reboot.mk b/tftf/tests/tests-reboot.mk index b0f573841..ad80973ff 100644 --- a/tftf/tests/tests-reboot.mk +++ b/tftf/tests/tests-reboot.mk @@ -6,6 +6,7 @@ TESTS_SOURCES += \ $(addprefix tftf/tests/runtime_services/standard_service/psci/api_tests/, \ + system_reset/test_system_reset.c \ mem_protect/test_mem_protect.c \ psci_stat/test_psci_stat.c \ reset2/reset2.c \ diff --git a/tftf/tests/tests-reboot.xml b/tftf/tests/tests-reboot.xml index fa4da1373..a0728723e 100644 --- a/tftf/tests/tests-reboot.xml +++ b/tftf/tests/tests-reboot.xml @@ -9,6 +9,10 @@ <testsuites> + <testsuite name="System Reset Test" description="Validate SYSTEM_RESET PSCI call"> + <testcase name="System Reset" function="test_system_reset" /> + </testsuite> + <testsuite name="PSCI STAT" description="Test PSCI STAT support System level"> <testcase name="for stats after system reset" function="test_psci_stats_after_reset" /> </testsuite> diff --git a/tftf/tests/tests-standard.mk b/tftf/tests/tests-standard.mk index f249a373c..9ef75bb94 100644 --- a/tftf/tests/tests-standard.mk +++ b/tftf/tests/tests-standard.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, Arm Limited. All rights reserved. +# Copyright (c) 2018-2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -10,6 +10,7 @@ TESTS_MAKEFILE := $(addprefix tftf/tests/, \ tests-cpu-extensions.mk \ tests-el3-power-state.mk \ tests-performance.mk \ + tests-pmu-leakage.mk \ tests-psci.mk \ tests-runtime-instrumentation.mk \ tests-sdei.mk \ diff --git a/tftf/tests/tests-standard.xml b/tftf/tests/tests-standard.xml index a1323d555..fa5762173 100644 --- a/tftf/tests/tests-standard.xml +++ b/tftf/tests/tests-standard.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright (c) 2018, Arm Limited. All rights reserved. + Copyright (c) 2018-2019, Arm Limited. All rights reserved. SPDX-License-Identifier: BSD-3-Clause --> @@ -20,6 +20,7 @@ <!ENTITY tests-cpu-extensions SYSTEM "tests-cpu-extensions.xml"> <!ENTITY tests-performance SYSTEM "tests-performance.xml"> <!ENTITY tests-smc SYSTEM "tests-smc.xml"> + <!ENTITY tests-pmu-leakage SYSTEM "tests-pmu-leakage.xml"> ]> <testsuites> @@ -35,5 +36,6 @@ &tests-cpu-extensions; &tests-performance; &tests-smc; + &tests-pmu-leakage; </testsuites> |