diff --git a/Makefile b/Makefile index b4bebf17f..c8ffdab06 100644 --- a/Makefile +++ b/Makefile @@ -964,6 +964,7 @@ $(eval $(call assert_booleans,\ ENABLE_FEAT_RNG \ ENABLE_FEAT_SB \ PSA_FWU_SUPPORT \ + ENABLE_TRBE_FOR_NS \ ))) $(eval $(call assert_numerics,\ @@ -1064,6 +1065,7 @@ $(eval $(call add_defines,\ NR_OF_FW_BANKS \ NR_OF_IMAGES_IN_FW_BANK \ PSA_FWU_SUPPORT \ + ENABLE_TRBE_FOR_NS \ ))) ifeq (${SANITIZE_UB},trap) diff --git a/bl31/bl31.mk b/bl31/bl31.mk index 1fdf545da..dc3d3c0be 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -90,6 +90,10 @@ ifeq (${ENABLE_MPAM_FOR_LOWER_ELS},1) BL31_SOURCES += lib/extensions/mpam/mpam.c endif +ifeq (${ENABLE_TRBE_FOR_NS},1) +BL31_SOURCES += lib/extensions/trbe/trbe.c +endif + ifeq (${WORKAROUND_CVE_2017_5715},1) BL31_SOURCES += lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S \ lib/cpus/aarch64/wa_cve_2017_5715_mmu.S diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst index 901a72a9b..57b880a9f 100644 --- a/docs/getting_started/build-options.rst +++ b/docs/getting_started/build-options.rst @@ -775,6 +775,12 @@ Common build options functions that wait for an arbitrary time length (udelay and mdelay). The default value is 0. +- ``ENABLE_TRBE_FOR_NS``: This flag is used to enable access of trace buffer + control registers from NS ELs, NS-EL2 or NS-EL1(when NS-EL2 is implemented + but unused) when FEAT_TRBE is implemented. TRBE is an optional architectural + feature for AArch64. The default is 0 and it is automatically disabled when + the target architecture is AArch32. + GICv3 driver options -------------------- diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h index d71ec00c9..47e02ce43 100644 --- a/include/arch/aarch64/arch.h +++ b/include/arch/aarch64/arch.h @@ -192,6 +192,11 @@ #define ID_AA64DFR0_PMS_SHIFT U(32) #define ID_AA64DFR0_PMS_MASK ULL(0xf) +/* ID_AA64DFR0_EL1.TraceBuffer definitions */ +#define ID_AA64DFR0_TRACEBUFFER_SHIFT U(44) +#define ID_AA64DFR0_TRACEBUFFER_MASK ULL(0xf) +#define ID_AA64DFR0_TRACEBUFFER_SUPPORTED ULL(1) + /* ID_AA64DFR0_EL1.MTPMU definitions (for ARMv8.6+) */ #define ID_AA64DFR0_MTPMU_SHIFT U(48) #define ID_AA64DFR0_MTPMU_MASK ULL(0xf) diff --git a/include/lib/extensions/trbe.h b/include/lib/extensions/trbe.h new file mode 100644 index 000000000..1753ab6bf --- /dev/null +++ b/include/lib/extensions/trbe.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TRBE_H +#define TRBE_H + +void trbe_enable(void); + +#endif /* TRBE_H */ diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index 1a765e739..9eb66ed84 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -348,6 +349,11 @@ static void enable_extensions_nonsecure(bool el2_unused, cpu_context_t *ctx) #if ENABLE_MPAM_FOR_LOWER_ELS mpam_enable(el2_unused); #endif + +#if ENABLE_TRBE_FOR_NS + trbe_enable(); +#endif /* ENABLE_TRBE_FOR_NS */ + #endif } diff --git a/lib/extensions/trbe/trbe.c b/lib/extensions/trbe/trbe.c new file mode 100644 index 000000000..9f754d521 --- /dev/null +++ b/lib/extensions/trbe/trbe.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +static void tsb_csync(void) +{ + /* + * The assembler does not yet understand the tsb csync mnemonic + * so use the equivalent hint instruction. + */ + __asm__ volatile("hint #18"); +} + +static bool trbe_supported(void) +{ + uint64_t features; + + features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEBUFFER_SHIFT; + return ((features & ID_AA64DFR0_TRACEBUFFER_MASK) == + ID_AA64DFR0_TRACEBUFFER_SUPPORTED); +} + +void trbe_enable(void) +{ + uint64_t val; + + if (trbe_supported()) { + /* + * MDCR_EL3.NSTB = 0b11 + * Allow access of trace buffer control registers from NS-EL1 + * and NS-EL2, tracing is prohibited in Secure and Realm state + * (if implemented). + */ + val = read_mdcr_el3(); + val |= MDCR_NSTB(MDCR_NSTB_EL1); + write_mdcr_el3(val); + } +} + +static void *trbe_drain_trace_buffers_hook(const void *arg __unused) +{ + if (trbe_supported()) { + /* + * Before switching from normal world to secure world + * the trace buffers need to be drained out to memory. This is + * required to avoid an invalid memory access when TTBR is switched + * for entry to S-EL1. + */ + tsb_csync(); + dsbnsh(); + } + + return (void *)0; +} + +SUBSCRIBE_TO_EVENT(cm_entering_secure_world, trbe_drain_trace_buffers_hook); diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 72f84b52e..e95d2268f 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -355,3 +355,14 @@ NR_OF_IMAGES_IN_FW_BANK := 1 # Disable Firmware update support by default PSA_FWU_SUPPORT := 0 + +# By default, disable access of trace buffer control registers from NS +# lower ELs i.e. NS-EL2, or NS-EL1 if NS-EL2 implemented but unused +# if FEAT_TRBE is implemented. +# Note FEAT_TRBE is only supported on AArch64 - therefore do not enable in +# AArch32. +ifneq (${ARCH},aarch32) + ENABLE_TRBE_FOR_NS := 0 +else + override ENABLE_TRBE_FOR_NS := 0 +endif