diff options
author | Manish Pandey <manish.pandey2@arm.com> | 2021-12-10 11:48:02 +0100 |
---|---|---|
committer | TrustedFirmware Code Review <review@review.trustedfirmware.org> | 2021-12-10 11:48:02 +0100 |
commit | bbcfa984bb78c2ea63ba9929cf8c89754ccef05e (patch) | |
tree | f1add8aaa13d17471448bcc888551783ee31140b | |
parent | 2e861262afc341212f2b208ff2da2137a810056e (diff) | |
parent | 50ccb55f7782e2b5c3c551abc8a5e26e05e5bc36 (diff) | |
download | tf-a-tests-bbcfa984bb78c2ea63ba9929cf8c89754ccef05e.tar.gz |
Merge "feat(sme): add basic SME tests"
-rw-r--r-- | include/lib/aarch64/arch.h | 36 | ||||
-rw-r--r-- | include/lib/aarch64/arch_helpers.h | 5 | ||||
-rw-r--r-- | include/lib/extensions/sme.h | 22 | ||||
-rw-r--r-- | lib/extensions/sme/aarch64/sme.c | 117 | ||||
-rw-r--r-- | lib/extensions/sme/aarch64/sme_helpers.S | 39 | ||||
-rw-r--r-- | tftf/framework/framework.mk | 4 | ||||
-rw-r--r-- | tftf/tests/extensions/sme/test_sme.c | 104 | ||||
-rw-r--r-- | tftf/tests/tests-cpu-extensions.mk | 1 | ||||
-rw-r--r-- | tftf/tests/tests-cpu-extensions.xml | 1 |
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"> |