feat(trbe): enable access to trace buffer control registers from lower NS EL
Introduced a build flag 'ENABLE_TRBE_FOR_NS' to enable trace buffer
control registers access in NS-EL2, or NS-EL1 (when NS-EL2 is
implemented but unused).
Change-Id: I285a672ccd395eebd377714c992bb21062a729cc
Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
diff --git a/Makefile b/Makefile
index b4bebf1..c8ffdab 100644
--- a/Makefile
+++ b/Makefile
@@ -964,6 +964,7 @@
ENABLE_FEAT_RNG \
ENABLE_FEAT_SB \
PSA_FWU_SUPPORT \
+ ENABLE_TRBE_FOR_NS \
)))
$(eval $(call assert_numerics,\
@@ -1064,6 +1065,7 @@
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 1fdf545..dc3d3c0 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -90,6 +90,10 @@
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 901a72a..57b880a 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -775,6 +775,12 @@
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 d71ec00..47e02ce 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 0000000..1753ab6
--- /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 1a765e7..9eb66ed 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -22,6 +22,7 @@
#include <lib/extensions/mpam.h>
#include <lib/extensions/spe.h>
#include <lib/extensions/sve.h>
+#include <lib/extensions/trbe.h>
#include <lib/extensions/twed.h>
#include <lib/utils.h>
@@ -348,6 +349,11 @@
#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 0000000..9f754d5
--- /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 <arch.h>
+#include <arch_helpers.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/extensions/trbe.h>
+
+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 72f84b5..e95d226 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -355,3 +355,14 @@
# 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