aboutsummaryrefslogtreecommitdiff
path: root/tftf
diff options
context:
space:
mode:
Diffstat (limited to 'tftf')
-rw-r--r--tftf/framework/framework.mk9
-rw-r--r--tftf/framework/main.c20
-rw-r--r--tftf/tests/extensions/mte/test_mte.c57
-rw-r--r--tftf/tests/extensions/pauth/test_pauth.c267
-rw-r--r--tftf/tests/extensions/ptrauth/test_ptrauth.c164
-rw-r--r--tftf/tests/misc_tests/test_pmu_leakage.c393
-rw-r--r--tftf/tests/runtime_services/standard_service/psci/api_tests/system_reset/test_system_reset.c32
-rw-r--r--tftf/tests/tests-cpu-extensions.mk3
-rw-r--r--tftf/tests/tests-cpu-extensions.xml2
-rw-r--r--tftf/tests/tests-extensive.xml2
-rw-r--r--tftf/tests/tests-manual.mk5
-rw-r--r--tftf/tests/tests-manual.xml4
-rw-r--r--tftf/tests/tests-pmu-leakage.mk9
-rw-r--r--tftf/tests/tests-pmu-leakage.xml16
-rw-r--r--tftf/tests/tests-reboot.mk1
-rw-r--r--tftf/tests/tests-reboot.xml4
-rw-r--r--tftf/tests/tests-standard.mk3
-rw-r--r--tftf/tests/tests-standard.xml4
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>