aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManish Pandey <manish.pandey2@arm.com>2021-12-10 11:48:02 +0100
committerTrustedFirmware Code Review <review@review.trustedfirmware.org>2021-12-10 11:48:02 +0100
commitbbcfa984bb78c2ea63ba9929cf8c89754ccef05e (patch)
treef1add8aaa13d17471448bcc888551783ee31140b
parent2e861262afc341212f2b208ff2da2137a810056e (diff)
parent50ccb55f7782e2b5c3c551abc8a5e26e05e5bc36 (diff)
downloadtf-a-tests-bbcfa984bb78c2ea63ba9929cf8c89754ccef05e.tar.gz
Merge "feat(sme): add basic SME tests"
-rw-r--r--include/lib/aarch64/arch.h36
-rw-r--r--include/lib/aarch64/arch_helpers.h5
-rw-r--r--include/lib/extensions/sme.h22
-rw-r--r--lib/extensions/sme/aarch64/sme.c117
-rw-r--r--lib/extensions/sme/aarch64/sme_helpers.S39
-rw-r--r--tftf/framework/framework.mk4
-rw-r--r--tftf/tests/extensions/sme/test_sme.c104
-rw-r--r--tftf/tests/tests-cpu-extensions.mk1
-rw-r--r--tftf/tests/tests-cpu-extensions.xml1
9 files changed, 328 insertions, 1 deletions
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index daab0d862..d9bc33c22 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -282,6 +282,9 @@
#define MTE_IMPLEMENTED_EL0 ULL(1) /* MTE is only implemented at EL0 */
#define MTE_IMPLEMENTED_ELX ULL(2) /* MTE is implemented at all ELs */
+#define ID_AA64PFR1_EL1_SME_SHIFT U(24)
+#define ID_AA64PFR1_EL1_SME_MASK ULL(0xf)
+
/* ID_PFR1_EL1 definitions */
#define ID_PFR1_VIRTEXT_SHIFT U(12)
#define ID_PFR1_VIRTEXT_MASK U(0xf)
@@ -437,6 +440,7 @@
#define TCPAC_BIT (U(1) << 31)
#define TAM_BIT (U(1) << 30)
#define TTA_BIT (U(1) << 20)
+#define ESM_BIT (U(1) << 12)
#define TFP_BIT (U(1) << 10)
#define CPTR_EZ_BIT (U(1) << 8)
#define CPTR_EL3_RESET_VAL U(0x0)
@@ -445,7 +449,10 @@
#define CPTR_EL2_RES1 ((ULL(3) << 12) | (ULL(1) << 9) | (ULL(0xff)))
#define CPTR_EL2_TCPAC_BIT (ULL(1) << 31)
#define CPTR_EL2_TAM_BIT (ULL(1) << 30)
+#define CPTR_EL2_SMEN_MASK ULL(0x3)
+#define CPTR_EL2_SMEN_SHIFT U(24)
#define CPTR_EL2_TTA_BIT (ULL(1) << 20)
+#define CPTR_EL2_TSM_BIT (ULL(1) << 12)
#define CPTR_EL2_TFP_BIT (ULL(1) << 10)
#define CPTR_EL2_TZ_BIT (ULL(1) << 8)
#define CPTR_EL2_RESET_VAL CPTR_EL2_RES1
@@ -772,6 +779,35 @@
#define ZCR_EL2_LEN_MASK U(0xf)
/*******************************************************************************
+ * Definitions for system register interface to SME
+ ******************************************************************************/
+#define ID_AA64SMFR0_EL1 S3_0_C0_C4_5
+#define SVCR S3_3_C4_C2_2
+#define TPIDR2_EL0 S3_3_C13_C0_5
+#define SMCR_EL2 S3_4_C1_C2_6
+
+/* ID_AA64SMFR0_EL1 definitions */
+#define ID_AA64SMFR0_EL1_FA64_BIT (UL(1) << 63)
+
+/* SVCR definitions */
+#define SVCR_ZA_BIT (U(1) << 1)
+#define SVCR_SM_BIT (U(1) << 0)
+
+/* SMPRI_EL1 definitions */
+#define SMPRI_EL1_PRIORITY_SHIFT U(0)
+#define SMPRI_EL1_PRIORITY_MASK U(0xf)
+
+/* SMPRIMAP_EL2 definitions */
+/* Register is composed of 16 priority map fields of 4 bits numbered 0-15. */
+#define SMPRIMAP_EL2_MAP_SHIFT(pri) U((pri) * 4)
+#define SMPRIMAP_EL2_MAP_MASK U(0xf)
+
+/* SMCR_ELx definitions */
+#define SMCR_ELX_LEN_SHIFT U(0)
+#define SMCR_ELX_LEN_MASK U(0x1ff)
+#define SMCR_ELX_FA64_BIT (U(1) << 31)
+
+/*******************************************************************************
* Definitions of MAIR encodings for device and normal memory
******************************************************************************/
/*
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index d4f0f9eb9..05f6779c8 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -444,6 +444,11 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(pmblimitr_el1, PMBLIMITR_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el3, ZCR_EL3)
DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el2, ZCR_EL2)
+DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64smfr0_el1, ID_AA64SMFR0_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(svcr, SVCR)
+DEFINE_RENAME_SYSREG_RW_FUNCS(tpidr2_el0, TPIDR2_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(smcr_el2, SMCR_EL2)
+
DEFINE_RENAME_SYSREG_READ_FUNC(erridr_el1, ERRIDR_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(errselr_el1, ERRSELR_EL1)
diff --git a/include/lib/extensions/sme.h b/include/lib/extensions/sme.h
new file mode 100644
index 000000000..5a6cc4310
--- /dev/null
+++ b/include/lib/extensions/sme.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AMU_H
+#define AMU_H
+
+#define SME_SMCR_LEN_MAX U(0x1FF)
+
+bool feat_sme_supported(void);
+bool feat_sme_fa64_supported(void);
+int sme_enable(void);
+void sme_smstart(bool enable_za);
+void sme_smstop(bool disable_za);
+
+/* Assembly function prototypes */
+uint64_t sme_rdvl_1(void);
+void sme_try_illegal_instruction(void);
+
+#endif /* AMU_H */
diff --git a/lib/extensions/sme/aarch64/sme.c b/lib/extensions/sme/aarch64/sme.c
new file mode 100644
index 000000000..28ddcd664
--- /dev/null
+++ b/lib/extensions/sme/aarch64/sme.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/extensions/sme.h>
+
+#ifdef __aarch64__
+
+/*
+ * feat_sme_supported
+ * Check if SME is supported on this platform.
+ * Return
+ * true if SME supported, false if not.
+ */
+bool feat_sme_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_SME_SHIFT;
+ return (features & ID_AA64PFR1_EL1_SME_MASK) != 0U;
+}
+
+/*
+ * feat_sme_fa64_supported
+ * Check if FEAT_SME_FA64 is supported.
+ * Return
+ * True if supported, false if not.
+ */
+bool feat_sme_fa64_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64smfr0_el1();
+ return (features & ID_AA64SMFR0_EL1_FA64_BIT) != 0U;
+}
+
+/*
+ * sme_enable
+ * Enable SME for nonsecure use at EL2 for TFTF cases.
+ * Return
+ * 0 if successful.
+ */
+int sme_enable(void)
+{
+ u_register_t reg;
+
+ /* Make sure SME is supported. */
+ if (!feat_sme_supported()) {
+ return -1;
+ }
+
+ /*
+ * Make sure SME accesses don't cause traps by setting appropriate fields
+ * in CPTR_EL2.
+ */
+ reg = read_cptr_el2();
+ if ((read_hcr_el2() & HCR_E2H_BIT) == 0U) {
+ /* When HCR_EL2.E2H == 0, clear TSM bit in CPTR_EL2. */
+ reg = reg & ~CPTR_EL2_TSM_BIT;
+ } else {
+ /* When HCR_EL2.E2H == 1, set SMEN bits in CPTR_EL2. */
+ reg = reg | (CPTR_EL2_SMEN_MASK << CPTR_EL2_SMEN_SHIFT);
+ }
+ write_cptr_el2(reg);
+
+ return 0;
+}
+
+/*
+ * sme_smstart
+ * This function enables streaming mode and optinally enables ZA array access
+ * at the same time.
+ * Parameters
+ * enable_za: If set, ZA access is enabled. If cleared, ZA bit is untouched.
+ */
+void sme_smstart(bool enable_za)
+{
+ u_register_t svcr = SVCR_SM_BIT;
+
+ if (enable_za) {
+ svcr |= SVCR_ZA_BIT;
+ }
+
+ write_svcr(read_svcr() | svcr);
+}
+
+/*
+ * sme_smstop
+ * This function disables streaming mode OR disables ZA array access but not
+ * both. It might seem strange but this is the functionality of the SMSTOP
+ * assembly instruction.
+ * Parameters
+ * disable_za: If set, ZA access is disabled but streaming mode is not
+ * affected. If clear, streaming mode is exited and ZA bit is
+ * left alone.
+ */
+void sme_smstop(bool disable_za)
+{
+ u_register_t svcr;
+
+ if (disable_za) {
+ svcr = ~SVCR_ZA_BIT;
+ } else {
+ svcr = ~SVCR_SM_BIT;
+ }
+
+ write_svcr(read_svcr() & svcr);
+}
+
+#endif /* __aarch64__ */
diff --git a/lib/extensions/sme/aarch64/sme_helpers.S b/lib/extensions/sme/aarch64/sme_helpers.S
new file mode 100644
index 000000000..6261c90ac
--- /dev/null
+++ b/lib/extensions/sme/aarch64/sme_helpers.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+#ifdef __aarch64__
+
+ .arch armv8-a+sve
+ .globl sme_rdvl_1
+ .globl sme_try_illegal_instruction
+
+/*
+ * uint64_t sme_rdvl_1(void);
+ *
+ * Run rdvl instruction with imm #1.
+ */
+func sme_rdvl_1
+ rdvl x0, #1
+ ret
+endfunc sme_rdvl_1
+
+/*
+ * void sme_try_illegal_instruction(void);
+ *
+ * This function tests that illegal instructions are allowed to run when
+ * FA64 is supported. RDFFR is explicitly stated to be illegal in the SME
+ * specification section F1.1.2 unless FA64 is supported and enabled.
+ */
+func sme_try_illegal_instruction
+ rdffr p0.b
+ ret
+endfunc sme_try_illegal_instruction
+
+#endif /* __aarch64__ */
diff --git a/tftf/framework/framework.mk b/tftf/framework/framework.mk
index 8ec18ea9a..2965926f0 100644
--- a/tftf/framework/framework.mk
+++ b/tftf/framework/framework.mk
@@ -80,7 +80,9 @@ ifeq (${ARCH},aarch64)
# ARMv8.3 Pointer Authentication support files
FRAMEWORK_SOURCES += \
lib/extensions/pauth/aarch64/pauth.c \
- lib/extensions/pauth/aarch64/pauth_helpers.S
+ lib/extensions/pauth/aarch64/pauth_helpers.S \
+ lib/extensions/sme/aarch64/sme.c \
+ lib/extensions/sme/aarch64/sme_helpers.S
endif
TFTF_LINKERFILE := tftf/framework/tftf.ld.S
diff --git a/tftf/tests/extensions/sme/test_sme.c b/tftf/tests/extensions/sme/test_sme.c
new file mode 100644
index 000000000..4bf6e59ed
--- /dev/null
+++ b/tftf/tests/extensions/sme/test_sme.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/extensions/sme.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+test_result_t test_sme_support(void)
+{
+ /* SME is an AArch64-only feature.*/
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ u_register_t reg;
+ unsigned int current_vector_len;
+ unsigned int requested_vector_len;
+ unsigned int len_max;
+
+ /* Skip the test if SME is not supported. */
+ if (!feat_sme_supported()) {
+ INFO("SME not supported, skipping.\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* Enable SME for use at NS EL2. */
+ if (sme_enable() != 0) {
+ ERROR("Could not enable SME.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure TPIDR2_EL0 is accessible. */
+ write_tpidr2_el0(0);
+ if (read_tpidr2_el0() != 0) {
+ ERROR("Could not read TPIDR2_EL0.\n");
+ return TEST_RESULT_FAIL;
+ }
+ write_tpidr2_el0(0xb0bafe77);
+ if (read_tpidr2_el0() != 0xb0bafe77) {
+ ERROR("Could not write TPIDR2_EL0.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure we can start and stop streaming mode. */
+ VERBOSE("Entering Streaming SVE mode.\n");
+ sme_smstart(false);
+ read_smcr_el2();
+ sme_smstop(false);
+ sme_smstart(true);
+ read_smcr_el2();
+ sme_smstop(true);
+
+ /*
+ * Iterate through values for LEN to detect supported vector lengths.
+ * SME instructions aren't supported by GCC yet so for now this is all
+ * we'll do.
+ */
+ sme_smstart(false);
+
+ /* Write SMCR_EL2 with the LEN max to find implemented width. */
+ write_smcr_el2(SME_SMCR_LEN_MAX);
+ len_max = (unsigned int)read_smcr_el2();
+ VERBOSE("Maximum SMCR_EL2.LEN value: 0x%x\n", len_max);
+ VERBOSE("Enumerating supported vector lengths...\n");
+ for (unsigned int i = 0; i <= len_max; i++) {
+ /* Load new value into SMCR_EL2.LEN */
+ reg = read_smcr_el2();
+ reg &= ~(SMCR_ELX_LEN_MASK << SMCR_ELX_LEN_SHIFT);
+ reg |= (i << SMCR_ELX_LEN_SHIFT);
+ write_smcr_el2(reg);
+
+ /* Compute current and requested vector lengths in bits. */
+ current_vector_len = ((unsigned int)sme_rdvl_1() * 8U);
+ requested_vector_len = (i+1U)*128U;
+
+ /*
+ * We count down from the maximum SMLEN value, so if the values
+ * match, we've found the largest supported value for SMLEN.
+ */
+ if (current_vector_len == requested_vector_len) {
+ VERBOSE("SUPPORTED: %u bits (LEN=%u)\n", requested_vector_len, i);
+ } else {
+ VERBOSE("NOT SUPPORTED: %u bits (LEN=%u)\n", requested_vector_len, i);
+ }
+ }
+ sme_smstop(false);
+
+ /* If FEAT_SME_FA64 then attempt to execute an illegal instruction. */
+ if (feat_sme_fa64_supported()) {
+ VERBOSE("FA64 supported, trying illegal instruction.\n");
+ sme_try_illegal_instruction();
+ }
+
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index 5ceb34000..6563b2a28 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -18,4 +18,5 @@ TESTS_SOURCES += $(addprefix tftf/tests/, \
runtime_services/arm_arch_svc/smccc_arch_soc_id.c \
runtime_services/arm_arch_svc/smccc_arch_workaround_1.c \
runtime_services/arm_arch_svc/smccc_arch_workaround_2.c \
+ extensions/sme/test_sme.c \
)
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index a1e3f8f14..990ab9fa1 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -23,6 +23,7 @@
<testcase name="Use trace buffer control Registers" function="test_trbe_enabled" />
<testcase name="Use trace filter control Registers" function="test_trf_enabled" />
<testcase name="Use trace system Registers" function="test_sys_reg_trace_enabled" />
+ <testcase name="SME support" function="test_sme_support" />
</testsuite>
<testsuite name="ARM_ARCH_SVC" description="Arm Architecture Service tests">