Aarch32: Secure PMU counter leak tests
This patch adds Aarch32 support to the PMU counter leak tests.
These tests attempt to profile the Secure world by configuring
EL0 system registers such that the PMU is told to increment
counters at Secure EL1, Secure EL2 and EL3. The tests fail if
useful information was leaked.
The Secure world defends against this type of attack with a
combination of configuring EL3 system registers and saving/restoring
EL0 PMU registers. Exactly which defense is employed depends on the
architecture version.
Signed-off-by: Petre-Ionut Tudor <petre-ionut.tudor@arm.com>
Change-Id: I2dcc9e786a18d9859ac089f8008b060d277bee3a
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 77cf7fd..205d203 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -166,13 +166,12 @@
#define SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(version) \
do { \
- uint32_t debug_ver = read_id_aa64dfr0_el1() & \
- (ID_AA64DFR0_DEBUG_MASK << ID_AA64DFR0_DEBUG_SHIFT); \
+ uint32_t debug_ver = arch_get_debug_version(); \
\
- if ((debug_ver >> ID_AA64DFR0_DEBUG_SHIFT) < version) { \
+ if (debug_ver < version) { \
tftf_testcase_printf("Debug version returned %d\n" \
"The required version is %d\n", \
- debug_ver >> ID_AA64DFR0_DEBUG_SHIFT,\
+ debug_ver, \
version); \
return TEST_RESULT_SKIPPED; \
} \
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 3c2a517..dcc4243 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -405,11 +405,45 @@
#define MAX_CACHE_LINE_SIZE U(0x800) /* 2KB */
/* PMCR definitions */
-#define PMCR_N_SHIFT U(11)
-#define PMCR_N_MASK U(0x1f)
-#define PMCR_N_BITS (PMCR_N_MASK << PMCR_N_SHIFT)
-#define PMCR_LC_BIT (U(1) << 6)
-#define PMCR_DP_BIT (U(1) << 5)
+#define PMCR_EL0_N_SHIFT U(11)
+#define PMCR_EL0_N_MASK U(0x1f)
+#define PMCR_EL0_N_BITS (PMCR_EL0_N_MASK << PMCR_EL0_N_SHIFT)
+#define PMCR_EL0_LC_BIT (U(1) << 6)
+#define PMCR_EL0_DP_BIT (U(1) << 5)
+#define PMCR_EL0_E_BIT (U(1) << 0)
+
+/* PMCNTENSET definitions */
+#define PMCNTENSET_EL0_C_BIT (U(1) << 31)
+#define PMCNTENSET_EL0_P_BIT(x) (U(1) << x)
+
+/* PMEVTYPER<n> definitions */
+#define PMEVTYPER_EL0_P_BIT (U(1) << 31)
+#define PMEVTYPER_EL0_NSK_BIT (U(1) << 29)
+#define PMEVTYPER_EL0_NSH_BIT (U(1) << 27)
+#define PMEVTYPER_EL0_M_BIT (U(1) << 26)
+#define PMEVTYPER_EL0_MT_BIT (U(1) << 25)
+#define PMEVTYPER_EL0_SH_BIT (U(1) << 24)
+#define PMEVTYPER_EL0_EVTCOUNT_BITS U(0x000003FF)
+
+/* PMCCFILTR definitions */
+#define PMCCFILTR_EL0_P_BIT (U(1) << 31)
+#define PMCCFILTR_EL0_NSK_BIT (U(1) << 29)
+#define PMCCFILTR_EL0_NSH_BIT (U(1) << 27)
+#define PMCCFILTR_EL0_M_BIT (U(1) << 26)
+#define PMCCFILTR_EL0_MT_BIT (U(1) << 25)
+#define PMCCFILTR_EL0_SH_BIT (U(1) << 24)
+
+/* PMU event counter ID definitions */
+#define PMU_EV_PC_WRITE_RETIRED U(0x000C)
+
+/* DBGDIDR definitions */
+#define DBGDIDR_VERSION_SHIFT U(16)
+#define DBGDIDR_VERSION_MASK U(0xf)
+#define DBGDIDR_VERSION_BITS (DBGDIDR_VERSION_MASK << DBGDIDR_VERSION_SHIFT)
+#define DBGDIDR_V8_DEBUG_ARCH_SUPPORTED U(6)
+#define DBGDIDR_V8_DEBUG_ARCH_VHE_SUPPORTED U(7)
+#define DBGDIDR_V8_2_DEBUG_ARCH_SUPPORTED U(8)
+#define DBGDIDR_V8_4_DEBUG_ARCH_SUPPORTED U(9)
/*******************************************************************************
* Definitions of register offsets, fields and macros for CPU system
@@ -522,6 +556,12 @@
/* Debug register defines. The format is: coproc, opt1, CRn, CRm, opt2 */
#define HDCR p15, 4, c1, c1, 1
#define PMCR p15, 0, c9, c12, 0
+#define PMCNTENSET p15, 0, c9, c12, 1
+#define PMCCFILTR p15, 0, c14, c15, 7
+#define PMCCNTR p15, 0, c9, c13, 0
+#define PMEVTYPER0 p15, 0, c14, c12, 0
+#define PMEVCNTR0 p15, 0, c14, c8, 0
+#define DBGDIDR p14, 0, c0, c0, 0
#define CNTHP_TVAL p15, 4, c14, c2, 0
#define CNTHP_CTL p15, 4, c14, c2, 1
diff --git a/include/lib/aarch32/arch_features.h b/include/lib/aarch32/arch_features.h
index b953db7..e2c2f2c 100644
--- a/include/lib/aarch32/arch_features.h
+++ b/include/lib/aarch32/arch_features.h
@@ -29,4 +29,10 @@
ID_MMFR4_CNP_MASK) != 0U;
}
+static inline uint32_t arch_get_debug_version(void)
+{
+ return ((read_dbgdidr() & DBGDIDR_VERSION_BITS) >>
+ DBGDIDR_VERSION_SHIFT);
+}
+
#endif /* ARCH_FEATURES_H */
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
index e983554..f2e3e00 100644
--- a/include/lib/aarch32/arch_helpers.h
+++ b/include/lib/aarch32/arch_helpers.h
@@ -277,7 +277,13 @@
DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR)
DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL)
-DEFINE_COPROCR_READ_FUNC(pmcr, PMCR)
+DEFINE_COPROCR_RW_FUNCS(pmcr, PMCR)
+DEFINE_COPROCR_RW_FUNCS(pmcntenset, PMCNTENSET)
+DEFINE_COPROCR_RW_FUNCS(pmccfiltr, PMCCFILTR)
+DEFINE_COPROCR_READ_FUNC(pmccntr, PMCCNTR)
+DEFINE_COPROCR_RW_FUNCS(pmevtyper0, PMEVTYPER0)
+DEFINE_COPROCR_READ_FUNC(pmevcntr0, PMEVCNTR0)
+DEFINE_COPROCR_READ_FUNC(dbgdidr, DBGDIDR)
/*
* Address translation
@@ -377,6 +383,22 @@
#define read_ctr_el0() read_ctr()
+#define read_pmcr_el0() read_pmcr()
+#define write_pmcr_el0(_v) write_pmcr(_v)
+
+#define read_pmcntenset_el0() read_pmcntenset()
+#define write_pmcntenset_el0(_v) write_pmcntenset(_v)
+
+#define read_pmccfiltr_el0() read_pmccfiltr()
+#define write_pmccfiltr_el0(_v) write_pmccfiltr(_v)
+
+#define read_pmevtyper0_el0() read_pmevtyper0()
+#define write_pmevtyper0_el0(_v) write_pmevtyper0(_v)
+
+#define read_pmccntr_el0 read_pmccntr
+
+#define read_pmevcntr0_el0 read_pmevcntr0
+
#define write_icc_sgi0r_el1(_v) write64_icc_sgi0r_el1(_v)
#define read_daif() read_cpsr()
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 1d5cc11..4e9c03b 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -152,6 +152,8 @@
#define ID_AA64DFR0_DEBUG_SHIFT U(0)
#define ID_AA64DFR0_DEBUG_LENGTH U(4)
#define ID_AA64DFR0_DEBUG_MASK ULL(0xf)
+#define ID_AA64DFR0_DEBUG_BITS (ID_AA64DFR0_DEBUG_MASK << \
+ ID_AA64DFR0_DEBUG_SHIFT)
#define ID_AA64DFR0_V8_DEBUG_ARCH_SUPPORTED U(6)
#define ID_AA64DFR0_V8_DEBUG_ARCH_VHE_SUPPORTED U(7)
#define ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED U(8)
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index 86c0763..20433fd 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -68,4 +68,10 @@
ID_AA64PFR1_EL1_MTE_MASK);
}
+static inline uint32_t arch_get_debug_version(void)
+{
+ return ((read_id_aa64dfr0_el1() & ID_AA64DFR0_DEBUG_BITS) >>
+ ID_AA64DFR0_DEBUG_SHIFT);
+}
+
#endif /* ARCH_FEATURES_H */
diff --git a/tftf/tests/misc_tests/test_pmu_leakage.c b/tftf/tests/misc_tests/test_pmu_leakage.c
index 09f4d51..da28999 100644
--- a/tftf/tests/misc_tests/test_pmu_leakage.c
+++ b/tftf/tests/misc_tests/test_pmu_leakage.c
@@ -37,6 +37,11 @@
* -v8.5 implemented:
* |-- Prohibit general event counters: as in v8.2 Debug.
* |-- Prohibit cycle counter: MDCR_EL3.SCCD == 1
+ *
+ * In Aarch32 state the PMU registers have identical names (apart from the
+ * '_EL0' suffix) and bit fields. As far as the PMU is concerned, the Aarch32
+ * counterpart of MDCR_EL3 is the SDCR register, which has both the SCCD and
+ * SPME bits.
*/
#include <drivers/arm/arm_gic.h>
@@ -47,7 +52,6 @@
#include <string.h>
#include <test_helpers.h>
-#ifdef AARCH64
#define ITERATIONS_CNT 1000
/*
@@ -71,6 +75,12 @@
unsigned long long avg;
};
+#ifdef AARCH64
+#define V8_2_DEBUG_ARCH_SUPPORTED ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED
+#else
+#define V8_2_DEBUG_ARCH_SUPPORTED DBGDIDR_V8_2_DEBUG_ARCH_SUPPORTED
+#endif
+
static inline void configure_pmu_cntr0(const uint32_t event)
{
/*
@@ -270,10 +280,13 @@
*/
test_result_t smc_psci_suspend_pc_write_retired(void)
{
+#if ARM_ARCH_MAJOR < 8
+ INFO("%s skipped on ARMv7 and earlier\n", __func__);
+ return TEST_RESULT_SKIPPED;
+#else
struct pmu_event_info baseline, cpu_suspend;
- SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(
- ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED);
+ SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(V8_2_DEBUG_ARCH_SUPPORTED);
configure_pmu_cntr0(PMU_EV_PC_WRITE_RETIRED);
pmu_enable_counting();
@@ -286,6 +299,7 @@
if (!results_within_allowed_margin(baseline.avg, cpu_suspend.avg))
return TEST_RESULT_FAIL;
return TEST_RESULT_SUCCESS;
+#endif
}
/*
@@ -295,10 +309,13 @@
*/
test_result_t smc_psci_suspend_cycles(void)
{
+#if ARM_ARCH_MAJOR < 8
+ INFO("%s skipped on ARMv7 and earlier\n", __func__);
+ return TEST_RESULT_SKIPPED;
+#else
struct pmu_event_info baseline, cpu_suspend;
- SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(
- ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED);
+ SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(V8_2_DEBUG_ARCH_SUPPORTED);
configure_pmu_cycle_cntr();
pmu_enable_counting();
@@ -311,6 +328,7 @@
if (!results_within_allowed_margin(baseline.avg, cpu_suspend.avg))
return TEST_RESULT_FAIL;
return TEST_RESULT_SUCCESS;
+#endif
}
/*
@@ -320,10 +338,13 @@
*/
test_result_t fast_smc_add_pc_write_retired(void)
{
+#if ARM_ARCH_MAJOR < 8
+ INFO("%s skipped on ARMv7 and earlier\n", __func__);
+ return TEST_RESULT_SKIPPED;
+#else
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_ARCH_DEBUG_VERSION_LESS_THAN(V8_2_DEBUG_ARCH_SUPPORTED);
SKIP_TEST_IF_TSP_NOT_PRESENT();
@@ -338,6 +359,7 @@
if (!results_within_allowed_margin(baseline.avg, fast_smc_add.avg))
return TEST_RESULT_FAIL;
return TEST_RESULT_SUCCESS;
+#endif
}
/*
@@ -347,10 +369,13 @@
*/
test_result_t fast_smc_add_cycles(void)
{
+#if ARM_ARCH_MAJOR < 8
+ INFO("%s skipped on ARMv7 and earlier\n", __func__);
+ return TEST_RESULT_SKIPPED;
+#else
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_ARCH_DEBUG_VERSION_LESS_THAN(V8_2_DEBUG_ARCH_SUPPORTED);
SKIP_TEST_IF_TSP_NOT_PRESENT();
@@ -365,29 +390,5 @@
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
+}