diff options
34 files changed, 1160 insertions, 223 deletions
@@ -224,7 +224,7 @@ TFTF_ASFLAGS += ${COMMON_ASFLAGS} TFTF_LDFLAGS += ${COMMON_LDFLAGS} ifeq (${ENABLE_PAUTH},1) -TFTF_CFLAGS += -msign-return-address=non-leaf +TFTF_CFLAGS += -mbranch-protection=pac-ret endif NS_BL1U_SOURCES += ${PLAT_SOURCES} ${LIBC_SRCS} diff --git a/docs/change-log.rst b/docs/change-log.rst index da749236f..29de0ed64 100644 --- a/docs/change-log.rst +++ b/docs/change-log.rst @@ -10,6 +10,114 @@ Firmware-A version for simplicity. At any point in time, TF-A Tests version Tests are not guaranteed to be compatible. This also means that a version upgrade on the TF-A-Tests side might not necessarily introduce any new feature. +Trusted Firmware-A Tests - version 2.2 +====================================== + +New features +------------ + +- A wide range of tests are made available in this release to help validate + the functionality of TF-A. + +- Various improvements to test framework and test suite. + +TFTF +```` + +- Enhancement to xlat table library synchronous to TF-A code base. + +- Enabled strict alignment checks (SCTLR.A & SCTLR.SA) in all images. + +- Support for a simple console driver. Currently it serves as a placeholder + with empty functions. + +- A topology helper API is added in the framework to get parent node info. + +- Support for FVP with clusters having upto 8 CPUs. + +- Enhanced linker script to separate code and RO data sections. + +- Relax SMC calls tests. The SMCCC specification recommends Trusted OSes to + mitigate the risk of leaking information by either preserving the register + state over the call, or returning a constant value, such as zero, in each + register. Tests only allowed the former behaviour and have been extended to + allow the latter as well. + +- Pointer Authentication enabled on warm boot path with individual APIAKey + generation for each CPU. + +- New tests: + + - Basic unit tests for xlat table library v2. + + - Tests for validating SVE support in TF-A. + + - Stress tests for dynamic xlat table library. + + - PSCI test to measure latencies when turning ON a cluster. + + - Series of AArch64 tests that stress the secure world to leak sensitive + counter values. + + - Test to validate PSCI SYSTEM_RESET call. + + - Basic tests to validate Memory Tagging Extensions are being enabled and + ensuring no undesired leak of sensitive data occurs. + +- Enhanced tests: + + - Improved tests for Pointer Authentication support. Checks are performed + to see if pointer authentication keys are accessible as well as validate + if secure keys are being leaked after a PSCI version call or TSP call. + + - Improved AMU test to remove unexecuted code iterating over Group1 counters + and fix the conditional check of AMU Group0 counter value. + +Secure partitions +````````````````` + +A new Secure Partition Quark is introduced in this release. + +Quark +''''''''' + +The Quark test secure partition provided is a simple service which returns a +magic number. Further, a simple test is added to test if Quark is functional. + +Issues resolved since last release +---------------------------------- + +- Bug fix in libc memchr implementation. + +- Bug fix in calculation of number of CPUs. + +- Streamlined SMC WORKAROUND_2 test and fixed a false fail on Cortex-A76 CPU. + +- Pointer Authentication support is now available for secondary CPUs and the + corresponding tests are stable in this release. + +Known issues and limitations +---------------------------- + +The sections below list the known issues and limitations of each test image +provided in this repository. Unless and otherwise stated, issues and limitations +stated in previous release continue to exist in this release. + +TFTF +```` + +Tests +''''' + +- Multicore spurious interrupt test is observed to have unstable behavior. As a + temporary solution, this test is skipped for AArch64 Juno configurations. + +- Generating SVE instructions requires `O3` compilation optimization. Since the + current build structure does not allow compilation flag modification for + specific files, the function which tests support for SVE has been pre-compiled + and added as an assembly file. + + Trusted Firmware-A Tests - version 2.1 ====================================== diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index 6a5abb727..9759c9865 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -361,20 +361,6 @@ each CPU is specified by the platform defined constant ``PLATFORM_STACK_SIZE``. Common implementation of this function is provided in ``plat/common/aarch64/platform_mp_stack.S``. -Function : plat_init_apiakey -```````````````````````````` - -:: - - Argument : void - Return : uint64_t * - -This function returns a pointer to an array with the values used to set the -``APIAKey{Hi,Lo}_EL1`` registers. - -This function is only needed if ARMv8.3 pointer authentication is used by -building with ``ENABLE_PAUTH=1``. - Function : tftf_platform_end() `````````````````````````````` diff --git a/docs/user-guide.rst b/docs/user-guide.rst index ef12c90fd..2e6f7bae5 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -401,7 +401,7 @@ TFTF build options - ``ENABLE_PAUTH``: Boolean option to enable ARMv8.3 Pointer Authentication (``ARMv8.3-PAuth``) support in the Trusted Firmware-A Test Framework itself. If enabled, it is needed to use a compiler that supports the option - ``-msign-return-address``. It defaults to 0. + ``-mbranch-protection`` (GCC 9 and later). It defaults to 0. - ``NEW_TEST_SESSION``: Choose whether a new test session should be started every time or whether the framework should determine whether a previous diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h index 2cf6e83d2..77cf7fd7d 100644 --- a/include/common/test_helpers.h +++ b/include/common/test_helpers.h @@ -109,6 +109,15 @@ typedef test_result_t (*test_function_arg_t)(void *arg); } \ } while (0) +#define SKIP_TEST_IF_MTE_SUPPORT_LESS_THAN(n) \ + do { \ + if (get_armv8_5_mte_support() < (n)) { \ + tftf_testcase_printf( \ + "Memory Tagging Extension not supported\n"); \ + return TEST_RESULT_SKIPPED; \ + } \ + } while (0) + #define SKIP_TEST_IF_MM_VERSION_LESS_THAN(major, minor) \ do { \ smc_args version_smc = { MM_VERSION_AARCH32 }; \ @@ -155,6 +164,20 @@ typedef test_result_t (*test_function_arg_t)(void *arg); } \ } while (0) +#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); \ + \ + if ((debug_ver >> ID_AA64DFR0_DEBUG_SHIFT) < version) { \ + tftf_testcase_printf("Debug version returned %d\n" \ + "The required version is %d\n", \ + debug_ver >> ID_AA64DFR0_DEBUG_SHIFT,\ + version); \ + return TEST_RESULT_SKIPPED; \ + } \ + } while (0) + /* Helper macro to verify if system suspend API is supported */ #define is_psci_sys_susp_supported() \ (tftf_get_psci_feature_info(SMC_PSCI_SYSTEM_SUSPEND) \ diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h index c839d1a6e..1d5cc11dc 100644 --- a/include/lib/aarch64/arch.h +++ b/include/lib/aarch64/arch.h @@ -148,6 +148,15 @@ #define ID_AA64DFR0_PMS_LENGTH U(4) #define ID_AA64DFR0_PMS_MASK ULL(0xf) +/* ID_AA64DFR0_EL1.DEBUG definitions */ +#define ID_AA64DFR0_DEBUG_SHIFT U(0) +#define ID_AA64DFR0_DEBUG_LENGTH U(4) +#define ID_AA64DFR0_DEBUG_MASK ULL(0xf) +#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) +#define ID_AA64DFR0_V8_4_DEBUG_ARCH_SUPPORTED U(9) + #define EL_IMPL_NONE ULL(0) #define EL_IMPL_A64ONLY ULL(1) #define EL_IMPL_A64_A32 ULL(2) @@ -213,6 +222,13 @@ #define SSBS_UNAVAILABLE ULL(0) /* No architectural SSBS support */ +#define ID_AA64PFR1_EL1_MTE_SHIFT U(8) +#define ID_AA64PFR1_EL1_MTE_MASK ULL(0xf) + +#define MTE_UNIMPLEMENTED ULL(0) +#define MTE_IMPLEMENTED_EL0 ULL(1) /* MTE is only implemented at EL0 */ +#define MTE_IMPLEMENTED_ELX ULL(2) /* MTE is implemented at all ELs */ + /* ID_PFR1_EL1 definitions */ #define ID_PFR1_VIRTEXT_SHIFT U(12) #define ID_PFR1_VIRTEXT_MASK U(0xf) @@ -269,6 +285,7 @@ /* SCR definitions */ #define SCR_RES1_BITS ((U(1) << 4) | (U(1) << 5)) +#define SCR_ATA_BIT (U(1) << 26) #define SCR_FIEN_BIT (U(1) << 21) #define SCR_API_BIT (U(1) << 17) #define SCR_APK_BIT (U(1) << 16) @@ -659,6 +676,31 @@ #define PMCR_EL0_DP_BIT (U(1) << 5) #define PMCR_EL0_X_BIT (U(1) << 4) #define PMCR_EL0_D_BIT (U(1) << 3) +#define PMCR_EL0_E_BIT (U(1) << 0) + +/* PMCNTENSET_EL0 definitions */ +#define PMCNTENSET_EL0_C_BIT (U(1) << 31) +#define PMCNTENSET_EL0_P_BIT(x) (U(1) << x) + +/* PMEVTYPER<n>_EL0 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_EL0 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) /******************************************************************************* * Definitions for system register interface to SVE @@ -869,4 +911,12 @@ ******************************************************************************/ #define SSBS S3_3_C4_C2_6 +/******************************************************************************* + * Armv8.5 - Memory Tagging Extension Registers + ******************************************************************************/ +#define TFSRE0_EL1 S3_0_C5_C6_1 +#define TFSR_EL1 S3_0_C5_C6_0 +#define RGSR_EL1 S3_0_C1_C0_5 +#define GCR_EL1 S3_0_C1_C0_6 + #endif /* ARCH_H */ diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h index 5891c7a71..86c0763b5 100644 --- a/include/lib/aarch64/arch_features.h +++ b/include/lib/aarch64/arch_features.h @@ -51,7 +51,7 @@ static inline bool is_armv8_3_pauth_apa_api_present(void) static inline bool is_armv8_3_pauth_gpa_gpi_present(void) { uint64_t mask = (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) | - (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT); + (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT); return (read_id_aa64isar1_el1() & mask) != 0U; } @@ -62,4 +62,10 @@ static inline bool is_armv8_4_ttst_present(void) ID_AA64MMFR2_EL1_ST_MASK) == 1U; } +static inline unsigned int get_armv8_5_mte_support(void) +{ + return ((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_MTE_SHIFT) & + ID_AA64PFR1_EL1_MTE_MASK); +} + #endif /* ARCH_FEATURES_H */ diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h index 151e5be94..d16960af8 100644 --- a/include/lib/aarch64/arch_helpers.h +++ b/include/lib/aarch64/arch_helpers.h @@ -395,6 +395,12 @@ DEFINE_SYSREG_RW_FUNCS(mdcr_el2) DEFINE_SYSREG_RW_FUNCS(mdcr_el3) DEFINE_SYSREG_RW_FUNCS(hstr_el2) DEFINE_SYSREG_RW_FUNCS(pmcr_el0) +DEFINE_SYSREG_RW_FUNCS(pmcntenset_el0) +DEFINE_SYSREG_READ_FUNC(pmccntr_el0) +DEFINE_SYSREG_RW_FUNCS(pmccfiltr_el0) + +DEFINE_SYSREG_RW_FUNCS(pmevtyper0_el0) +DEFINE_SYSREG_READ_FUNC(pmevcntr0_el0) /* GICv3 System Registers */ @@ -463,6 +469,12 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(apdbkeylo_el1, APDBKeyLo_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(apgakeyhi_el1, APGAKeyHi_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(apgakeylo_el1, APGAKeyLo_EL1) +/* MTE registers */ +DEFINE_RENAME_SYSREG_RW_FUNCS(tfsre0_el1, TFSRE0_EL1) +DEFINE_RENAME_SYSREG_RW_FUNCS(tfsr_el1, TFSR_EL1) +DEFINE_RENAME_SYSREG_RW_FUNCS(rgsr_el1, RGSR_EL1) +DEFINE_RENAME_SYSREG_RW_FUNCS(gcr_el1, GCR_EL1) + #define IS_IN_EL(x) \ (GET_EL(read_CurrentEl()) == MODE_EL##x) diff --git a/include/lib/extensions/pauth.h b/include/lib/extensions/pauth.h new file mode 100644 index 000000000..a4da00990 --- /dev/null +++ b/include/lib/extensions/pauth.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PAUTH_H +#define PAUTH_H + +#include <stdint.h> + +#ifdef __aarch64__ +/* Initialize 128-bit ARMv8.3-PAuth key */ +uint128_t init_apkey(void); + +/* Program APIAKey_EL1 key and enable ARMv8.3-PAuth */ +void pauth_init_enable(void); +#endif /* __aarch64__ */ + +#endif /* PAUTH_H */ diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index b30c41ebd..f3536bab7 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -67,9 +67,6 @@ int plat_crash_console_flush(void); /* Gets a handle for the initialised IO entity */ void plat_get_nvm_handle(uintptr_t *handle); -/* Initialize and get a pointer to a uint64_t[2] array with a 128-key */ -uint64_t *plat_init_apiakey(void); - /* * Returns the platform topology description array. The size of this * array should be PLATFORM_NUM_AFFS - PLATFORM_CORE_COUNT + 1. diff --git a/lib/extensions/pauth/aarch64/pauth.c b/lib/extensions/pauth/aarch64/pauth.c new file mode 100644 index 000000000..03de468b4 --- /dev/null +++ b/lib/extensions/pauth/aarch64/pauth.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <cdefs.h> +#include <stdint.h> + +/* + * This is only a toy implementation to generate a seemingly random + * 128-bit key from sp, x30 and cntpct_el0 values. + */ +uint128_t init_apkey(void) +{ + uint64_t return_addr = (uint64_t)__builtin_return_address(0U); + uint64_t frame_addr = (uint64_t)__builtin_frame_address(0U); + + uint64_t cntpct = read_cntpct_el0(); + + uint64_t key_lo = (return_addr << 13) ^ frame_addr ^ cntpct; + uint64_t key_hi = (frame_addr << 15) ^ return_addr ^ cntpct; + + return ((uint128_t)(key_hi) << 64) | key_lo; +} diff --git a/lib/extensions/pauth/aarch64/pauth_helpers.S b/lib/extensions/pauth/aarch64/pauth_helpers.S new file mode 100644 index 000000000..e15cac90f --- /dev/null +++ b/lib/extensions/pauth/aarch64/pauth_helpers.S @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> + + .global pauth_init_enable + +/* ----------------------------------------------------------- + * Program APIAKey_EL1 key and enable Pointer Authentication + * of instruction addresses in the current translation regime + * for the calling CPU. + * ----------------------------------------------------------- + */ +func pauth_init_enable + stp x29, x30, [sp, #-16]! + + /* Initialize platform key */ + bl init_apkey + + /* + * Program instruction key A used by + * the Trusted Firmware Test Framework + */ + msr APIAKeyLo_EL1, x0 + msr APIAKeyHi_EL1, x1 + + /* Detect Current Exception level */ + mrs x0, CurrentEL + cmp x0, #(MODE_EL1 << MODE_EL_SHIFT) + b.eq enable_el1 + + /* Enable EL2 pointer authentication */ + mrs x0, sctlr_el2 + orr x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el2, x0 + b enable_exit + + /* Enable EL1 pointer authentication */ +enable_el1: + mrs x0, sctlr_el1 + orr x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el1, x0 + +enable_exit: + isb + + ldp x29, x30, [sp], #16 + ret +endfunc pauth_init_enable diff --git a/lib/power_management/hotplug/hotplug.c b/lib/power_management/hotplug/hotplug.c index 37bfc06bf..76fa287b9 100644 --- a/lib/power_management/hotplug/hotplug.c +++ b/lib/power_management/hotplug/hotplug.c @@ -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 */ @@ -11,6 +11,7 @@ #include <drivers/arm/arm_gic.h> #include <drivers/console.h> #include <irq.h> +#include <pauth.h> #include <platform.h> #include <platform_def.h> #include <power_management.h> @@ -288,6 +289,16 @@ void __dead2 tftf_warm_boot_main(void) { /* Initialise the CPU */ tftf_arch_setup(); + +#if ENABLE_PAUTH + /* + * 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 */ + arm_gic_setup_local(); /* Enable the SGI used by the timer management framework */ diff --git a/lib/power_management/suspend/aarch64/asm_tftf_suspend.S b/lib/power_management/suspend/aarch64/asm_tftf_suspend.S index 692baded6..09950b5c0 100644 --- a/lib/power_management/suspend/aarch64/asm_tftf_suspend.S +++ b/lib/power_management/suspend/aarch64/asm_tftf_suspend.S @@ -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 */ @@ -54,6 +54,11 @@ func __tftf_suspend endfunc __tftf_suspend func __tftf_save_arch_context +#if ENABLE_PAUTH + mrs x1, APIAKeyLo_EL1 + mrs x2, APIAKeyHi_EL1 + stp x1, x2, [x0, #SUSPEND_CTX_APIAKEY_OFFSET] +#endif JUMP_EL1_OR_EL2 x1, 1f, 2f, dead 1: mrs x1, mair_el1 mrs x2, cpacr_el1 @@ -61,9 +66,9 @@ func __tftf_save_arch_context mrs x4, tcr_el1 mrs x5, vbar_el1 mrs x6, sctlr_el1 - stp x1, x2, [x0] - stp x3, x4, [x0, #16] - stp x5, x6, [x0, #32] + stp x1, x2, [x0, #SUSPEND_CTX_MAIR_OFFSET] + stp x3, x4, [x0, #SUSPEND_CTX_TTBR0_OFFSET] + stp x5, x6, [x0, #SUSPEND_CTX_VBAR_OFFSET] ret 2: mrs x1, mair_el2 @@ -72,9 +77,9 @@ func __tftf_save_arch_context mrs x4, tcr_el2 mrs x5, vbar_el2 mrs x6, sctlr_el2 - stp x1, x2, [x0] - stp x3, x4, [x0, #16] - stp x5, x6, [x0, #32] + stp x1, x2, [x0, #SUSPEND_CTX_MAIR_OFFSET] + stp x3, x4, [x0, #SUSPEND_CTX_TTBR0_OFFSET] + stp x5, x6, [x0, #SUSPEND_CTX_VBAR_OFFSET] ret endfunc __tftf_save_arch_context @@ -86,9 +91,9 @@ func __tftf_cpu_resume_ep JUMP_EL1_OR_EL2 x1, 1f, 2f, dead 1: /* Invalidate local tlb entries before turning on MMU */ tlbi vmalle1 - ldp x1, x2, [x0] - ldp x3, x4, [x0, #16] - ldp x5, x6, [x0, #32] + ldp x1, x2, [x0, #SUSPEND_CTX_MAIR_OFFSET] + ldp x3, x4, [x0, #SUSPEND_CTX_TTBR0_OFFSET] + ldp x5, x6, [x0, #SUSPEND_CTX_VBAR_OFFSET] msr mair_el1, x1 msr cpacr_el1, x2 msr ttbr0_el1, x3 @@ -101,13 +106,13 @@ func __tftf_cpu_resume_ep msr sctlr_el1, x6 /* Ensure the MMU enable takes effect immediately */ isb - b restore_callee_regs + b restore_callee_regs /* Invalidate local tlb entries before turning on MMU */ 2: tlbi alle2 - ldp x1, x2, [x0] - ldp x3, x4, [x0, #16] - ldp x5, x6, [x0, #32] + ldp x1, x2, [x0, #SUSPEND_CTX_MAIR_OFFSET] + ldp x3, x4, [x0, #SUSPEND_CTX_TTBR0_OFFSET] + ldp x5, x6, [x0, #SUSPEND_CTX_VBAR_OFFSET] msr mair_el2, x1 msr hcr_el2, x2 msr ttbr0_el2, x3 @@ -122,6 +127,11 @@ func __tftf_cpu_resume_ep isb restore_callee_regs: +#if ENABLE_PAUTH + ldp x1, x2, [x0, #SUSPEND_CTX_APIAKEY_OFFSET] + msr APIAKeyLo_EL1, x1 + msr APIAKeyHi_EL1, x2 +#endif ldr x2, [x0, #SUSPEND_CTX_SP_OFFSET] mov sp, x2 ldr w1, [x0, #SUSPEND_CTX_SAVE_SYSTEM_CTX_OFFSET] diff --git a/lib/power_management/suspend/suspend_private.h b/lib/power_management/suspend/suspend_private.h index b67bbab0b..bc2f3a600 100644 --- a/lib/power_management/suspend/suspend_private.h +++ b/lib/power_management/suspend/suspend_private.h @@ -9,11 +9,21 @@ /* * Number of system registers we need to save/restore across a CPU suspend: - * MAIR, CPACR_EL1/HCR_EL2, TTBR0, TCR, VBAR and SCTLR. + * MAIR, CPACR_EL1/HCR_EL2, TTBR0, TCR, VBAR, SCTLR, + * APIAKeyLo_EL1 and APIAKeyHi_EL1 (if enabled). */ +#if ENABLE_PAUTH +#define NR_CTX_REGS 8 +#else #define NR_CTX_REGS 6 +#endif /* Offsets of the fields in the context structure. Needed by asm code. */ +#define SUSPEND_CTX_MAIR_OFFSET 0 +#define SUSPEND_CTX_TTBR0_OFFSET 16 +#define SUSPEND_CTX_VBAR_OFFSET 32 +#define SUSPEND_CTX_APIAKEY_OFFSET 48 + #define SUSPEND_CTX_SP_OFFSET (8 * NR_CTX_REGS) #define SUSPEND_CTX_SAVE_SYSTEM_CTX_OFFSET (SUSPEND_CTX_SP_OFFSET + 8) diff --git a/plat/arm/fvp/platform.mk b/plat/arm/fvp/platform.mk index 9fb84c276..c014d6de7 100644 --- a/plat/arm/fvp/platform.mk +++ b/plat/arm/fvp/platform.mk @@ -23,8 +23,4 @@ CACTUS_SOURCES += plat/arm/fvp/${ARCH}/plat_helpers.S # Firmware update is implemented on FVP. FIRMWARE_UPDATE := 1 -ifeq (${ARCH},aarch64) -PLAT_SOURCES += plat/common/aarch64/pauth.c -endif - include plat/arm/common/arm_common.mk 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> |