From 16e3ddba1f049106387dfe21989243d2fc4cf061 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 3 Feb 2023 15:23:59 +0000 Subject: [PATCH 1/6] fix(spe): drop SPE EL2 context switch code At the moment we hardcode the SPE functionality to be available on the non-secure side only, by setting MDCR_EL3.NSPB accordingly. This also means that the secure world cannot use SPE, so there is no need to context switch the PMSCR_EL2 register. Drop the SPE bits from the EL2 context switch code. If any of the other EL2 worlds wish to start using SPE, this can be brought back. Change-Id: Ie0fedb2aeb722a2c9db316051fbbe57ca0e3c0c9 Signed-off-by: Andre Przywara --- include/lib/el3_runtime/aarch64/context.h | 4 ---- lib/el3_runtime/aarch64/context.S | 18 ------------------ lib/el3_runtime/aarch64/context_mgmt.c | 6 ------ 3 files changed, 28 deletions(-) diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h index 31d8f070c..4cbda36b6 100644 --- a/include/lib/el3_runtime/aarch64/context.h +++ b/include/lib/el3_runtime/aarch64/context.h @@ -514,10 +514,6 @@ void el1_sysregs_context_restore(el1_sysregs_t *regs); #if CTX_INCLUDE_EL2_REGS void el2_sysregs_context_save_common(el2_sysregs_t *regs); void el2_sysregs_context_restore_common(el2_sysregs_t *regs); -#if ENABLE_SPE_FOR_LOWER_ELS -void el2_sysregs_context_save_spe(el2_sysregs_t *regs); -void el2_sysregs_context_restore_spe(el2_sysregs_t *regs); -#endif /* ENABLE_SPE_FOR_LOWER_ELS */ #if CTX_INCLUDE_MTE_REGS void el2_sysregs_context_save_mte(el2_sysregs_t *regs); void el2_sysregs_context_restore_mte(el2_sysregs_t *regs); diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S index d43914848..b05833432 100644 --- a/lib/el3_runtime/aarch64/context.S +++ b/lib/el3_runtime/aarch64/context.S @@ -13,10 +13,6 @@ #if CTX_INCLUDE_EL2_REGS .global el2_sysregs_context_save_common .global el2_sysregs_context_restore_common -#if ENABLE_SPE_FOR_LOWER_ELS - .global el2_sysregs_context_save_spe - .global el2_sysregs_context_restore_spe -#endif /* ENABLE_SPE_FOR_LOWER_ELS */ #if CTX_INCLUDE_MTE_REGS .global el2_sysregs_context_save_mte .global el2_sysregs_context_restore_mte @@ -220,20 +216,6 @@ func el2_sysregs_context_restore_common ret endfunc el2_sysregs_context_restore_common -#if ENABLE_SPE_FOR_LOWER_ELS -func el2_sysregs_context_save_spe - mrs x13, PMSCR_EL2 - str x13, [x0, #CTX_PMSCR_EL2] - ret -endfunc el2_sysregs_context_save_spe - -func el2_sysregs_context_restore_spe - ldr x13, [x0, #CTX_PMSCR_EL2] - msr PMSCR_EL2, x13 - ret -endfunc el2_sysregs_context_restore_spe -#endif /* ENABLE_SPE_FOR_LOWER_ELS */ - #if CTX_INCLUDE_MTE_REGS func el2_sysregs_context_save_mte mrs x9, TFSR_EL2 diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index 507a8ce8a..e1c671d8b 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -856,9 +856,6 @@ void cm_el2_sysregs_context_save(uint32_t security_state) el2_sysregs_ctx = get_el2_sysregs_ctx(ctx); el2_sysregs_context_save_common(el2_sysregs_ctx); -#if ENABLE_SPE_FOR_LOWER_ELS - el2_sysregs_context_save_spe(el2_sysregs_ctx); -#endif #if CTX_INCLUDE_MTE_REGS el2_sysregs_context_save_mte(el2_sysregs_ctx); #endif @@ -919,9 +916,6 @@ void cm_el2_sysregs_context_restore(uint32_t security_state) el2_sysregs_ctx = get_el2_sysregs_ctx(ctx); el2_sysregs_context_restore_common(el2_sysregs_ctx); -#if ENABLE_SPE_FOR_LOWER_ELS - el2_sysregs_context_restore_spe(el2_sysregs_ctx); -#endif #if CTX_INCLUDE_MTE_REGS el2_sysregs_context_restore_mte(el2_sysregs_ctx); #endif From 90118bb5c180198db3386c3e1f5be8e32707c2cc Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 3 Feb 2023 15:30:14 +0000 Subject: [PATCH 2/6] refactor(cpufeat): rename ENABLE_SPE_FOR_LOWER_ELS to ENABLE_SPE_FOR_NS At the moment we hardcode the SPE functionality to be available on the non-secure side only, by setting MDCR_EL2.E2PB accordingly. This should be reflected in the feature selection symbol, so rename that to ENABLE_SPE_FOR_NS, to make it clearer that SPE is not supported in the secure world. Change-Id: I3f9b48eab1a45d6ccfcbb9c90a11eeb66867ad9a Signed-off-by: Andre Przywara --- Makefile | 4 ++-- bl31/bl31.mk | 2 +- docs/getting_started/build-options.rst | 2 +- lib/el3_runtime/aarch64/context_mgmt.c | 2 +- make_helpers/defaults.mk | 4 ++-- plat/allwinner/common/allwinner-common.mk | 2 +- plat/arm/board/fvp/fvp_pm.c | 2 +- plat/arm/board/tc/platform.mk | 2 +- plat/qti/msm8916/platform.mk | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index b9ca664e9..16279b603 100644 --- a/Makefile +++ b/Makefile @@ -1096,7 +1096,7 @@ $(eval $(call assert_booleans,\ ENABLE_RUNTIME_INSTRUMENTATION \ ENABLE_SME_FOR_NS \ ENABLE_SME_FOR_SWD \ - ENABLE_SPE_FOR_LOWER_ELS \ + ENABLE_SPE_FOR_NS \ ENABLE_SVE_FOR_NS \ ENABLE_SVE_FOR_SWD \ ERROR_DEPRECATED \ @@ -1237,7 +1237,7 @@ $(eval $(call add_defines,\ ENABLE_RUNTIME_INSTRUMENTATION \ ENABLE_SME_FOR_NS \ ENABLE_SME_FOR_SWD \ - ENABLE_SPE_FOR_LOWER_ELS \ + ENABLE_SPE_FOR_NS \ ENABLE_SVE_FOR_NS \ ENABLE_SVE_FOR_SWD \ ENCRYPT_BL31 \ diff --git a/bl31/bl31.mk b/bl31/bl31.mk index e9590d5d6..b639920e5 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -87,7 +87,7 @@ BL31_SOURCES += services/std_svc/trng/trng_main.c \ services/std_svc/trng/trng_entropy_pool.c endif -ifeq (${ENABLE_SPE_FOR_LOWER_ELS},1) +ifeq (${ENABLE_SPE_FOR_NS},1) BL31_SOURCES += lib/extensions/spe/spe.c endif diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst index abfc8eccc..9241c3912 100644 --- a/docs/getting_started/build-options.rst +++ b/docs/getting_started/build-options.rst @@ -428,7 +428,7 @@ Common build options handle context switching for SME, SVE, and FPU/SIMD registers to ensure that no data is leaked to non-secure world. This is experimental. Default is 0. -- ``ENABLE_SPE_FOR_LOWER_ELS`` : Boolean option to enable Statistical Profiling +- ``ENABLE_SPE_FOR_NS`` : Boolean option to enable Statistical Profiling extensions. This is an optional architectural feature for AArch64. The default is 1 but is automatically disabled when the target architecture is AArch32. diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index e1c671d8b..50fddc502 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -482,7 +482,7 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) static void manage_extensions_nonsecure(bool el2_unused, cpu_context_t *ctx) { #if IMAGE_BL31 -#if ENABLE_SPE_FOR_LOWER_ELS +#if ENABLE_SPE_FOR_NS spe_enable(el2_unused); #endif diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index d8c621078..63ac82e6d 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -355,11 +355,11 @@ V := 0 WARMBOOT_ENABLE_DCACHE_EARLY := 0 # Build option to enable/disable the Statistical Profiling Extensions -ENABLE_SPE_FOR_LOWER_ELS := 1 +ENABLE_SPE_FOR_NS := 1 # SPE is only supported on AArch64 so disable it on AArch32. ifeq (${ARCH},aarch32) - override ENABLE_SPE_FOR_LOWER_ELS := 0 + override ENABLE_SPE_FOR_NS := 0 endif # Include Memory Tagging Extension registers in cpu context. This must be set diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk index 61c1dbe3e..3164a255a 100644 --- a/plat/allwinner/common/allwinner-common.mk +++ b/plat/allwinner/common/allwinner-common.mk @@ -87,7 +87,7 @@ endif COLD_BOOT_SINGLE_CPU := 1 # Do not enable SPE (not supported on ARM v8.0). -ENABLE_SPE_FOR_LOWER_ELS := 0 +ENABLE_SPE_FOR_NS := 0 # Do not enable SVE (not supported on ARM v8.0). ENABLE_SVE_FOR_NS := 0 diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c index 6b9d6184c..9d9386230 100644 --- a/plat/arm/board/fvp/fvp_pm.c +++ b/plat/arm/board/fvp/fvp_pm.c @@ -53,7 +53,7 @@ static void fvp_cluster_pwrdwn_common(void) { uint64_t mpidr = read_mpidr_el1(); -#if ENABLE_SPE_FOR_LOWER_ELS +#if ENABLE_SPE_FOR_NS /* * On power down we need to disable statistical profiling extensions * before exiting coherency. diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk index 05dca915e..5f4148c17 100644 --- a/plat/arm/board/tc/platform.mk +++ b/plat/arm/board/tc/platform.mk @@ -161,7 +161,7 @@ override CTX_INCLUDE_AARCH32_REGS := 0 override CTX_INCLUDE_PAUTH_REGS := 1 -override ENABLE_SPE_FOR_LOWER_ELS := 0 +override ENABLE_SPE_FOR_NS := 0 override ENABLE_AMU := 1 override ENABLE_AMU_AUXILIARY_COUNTERS := 1 diff --git a/plat/qti/msm8916/platform.mk b/plat/qti/msm8916/platform.mk index e516ceadb..60fb25d41 100644 --- a/plat/qti/msm8916/platform.mk +++ b/plat/qti/msm8916/platform.mk @@ -44,7 +44,7 @@ WARMBOOT_ENABLE_DCACHE_EARLY := 1 # Disable features unsupported in ARMv8.0 ENABLE_AMU := 0 -ENABLE_SPE_FOR_LOWER_ELS := 0 +ENABLE_SPE_FOR_NS := 0 ENABLE_SVE_FOR_NS := 0 # MSM8916 uses ARM Cortex-A53 r0p0 so likely all the errata apply From 6437a09a2db5774438fb1a95c508ed6b0a9f0ef2 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 17 Nov 2022 16:42:09 +0000 Subject: [PATCH 3/6] refactor(spe): enable FEAT_SPE for FEAT_STATE_CHECKED At the moment we only support FEAT_SPE to be either unconditionally compiled in, or to be not supported at all. Add support for runtime detection (ENABLE_SPE_FOR_NS=2), by splitting is_armv8_2_feat_spe_present() into an ID register reading function and a second function to report the support status. That function considers both build time settings and runtime information (if needed), and is used before we access SPE related registers. Previously SPE was enabled unconditionally for all platforms, change this now to the runtime detection version. Change-Id: I830c094107ce6a398bf1f4aef7ffcb79d4f36552 Signed-off-by: Andre Przywara --- Makefile | 2 +- bl31/bl31.mk | 2 +- docs/getting_started/build-options.rst | 7 ++++--- include/arch/aarch32/arch_features.h | 6 ++++++ include/arch/aarch64/arch_features.h | 18 +++++++++++++++--- include/lib/extensions/spe.h | 10 +++++++++- lib/el3_runtime/aarch64/context_mgmt.c | 6 +++--- lib/extensions/spe/spe.c | 17 ++--------------- make_helpers/defaults.mk | 2 +- plat/arm/board/arm_fpga/fpga_bl31_setup.c | 2 +- plat/arm/board/fvp/fvp_pm.c | 7 ++++--- 11 files changed, 47 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 16279b603..797b2cfeb 100644 --- a/Makefile +++ b/Makefile @@ -1096,7 +1096,6 @@ $(eval $(call assert_booleans,\ ENABLE_RUNTIME_INSTRUMENTATION \ ENABLE_SME_FOR_NS \ ENABLE_SME_FOR_SWD \ - ENABLE_SPE_FOR_NS \ ENABLE_SVE_FOR_NS \ ENABLE_SVE_FOR_SWD \ ERROR_DEPRECATED \ @@ -1182,6 +1181,7 @@ $(eval $(call assert_numerics,\ ENABLE_FEAT_VHE \ ENABLE_MPAM_FOR_LOWER_ELS \ ENABLE_RME \ + ENABLE_SPE_FOR_NS \ ENABLE_TRF_FOR_NS \ FW_ENC_STATUS \ NR_OF_FW_BANKS \ diff --git a/bl31/bl31.mk b/bl31/bl31.mk index b639920e5..e000f4f7b 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -87,7 +87,7 @@ BL31_SOURCES += services/std_svc/trng/trng_main.c \ services/std_svc/trng/trng_entropy_pool.c endif -ifeq (${ENABLE_SPE_FOR_NS},1) +ifneq (${ENABLE_SPE_FOR_NS},0) BL31_SOURCES += lib/extensions/spe/spe.c endif diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst index 9241c3912..9415871df 100644 --- a/docs/getting_started/build-options.rst +++ b/docs/getting_started/build-options.rst @@ -428,10 +428,11 @@ Common build options handle context switching for SME, SVE, and FPU/SIMD registers to ensure that no data is leaked to non-secure world. This is experimental. Default is 0. -- ``ENABLE_SPE_FOR_NS`` : Boolean option to enable Statistical Profiling +- ``ENABLE_SPE_FOR_NS`` : Numeric value to enable Statistical Profiling extensions. This is an optional architectural feature for AArch64. - The default is 1 but is automatically disabled when the target architecture - is AArch32. + This flag can take the values 0 to 2, to align with the ``FEATURE_DETECTION`` + mechanism. The default is 2 but is automatically disabled when the target + architecture is AArch32. - ``ENABLE_SVE_FOR_NS``: Boolean option to enable Scalable Vector Extension (SVE) for the Non-secure world only. SVE is an optional architectural feature diff --git a/include/arch/aarch32/arch_features.h b/include/arch/aarch32/arch_features.h index a5a5e278b..12df6da4b 100644 --- a/include/arch/aarch32/arch_features.h +++ b/include/arch/aarch32/arch_features.h @@ -43,4 +43,10 @@ static inline bool is_feat_trf_supported(void) return read_feat_trf_id_field() != 0U; } +static inline bool is_feat_spe_supported(void) +{ + /* FEAT_SPE is AArch64 only */ + return false; +} + #endif /* ARCH_FEATURES_H */ diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h index 582aed12f..58b37521b 100644 --- a/include/arch/aarch64/arch_features.h +++ b/include/arch/aarch64/arch_features.h @@ -249,10 +249,22 @@ static inline bool is_armv8_0_feat_csv2_2_present(void) /********************************************************************************** * Function to identify the presence of FEAT_SPE (Statistical Profiling Extension) *********************************************************************************/ -static inline bool is_armv8_2_feat_spe_present(void) +static inline unsigned int read_feat_spe_id_field(void) { - return (((read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT) & - ID_AA64DFR0_PMS_MASK) != ID_AA64DFR0_SPE_NOT_SUPPORTED); + return ISOLATE_FIELD(read_id_aa64dfr0_el1(), ID_AA64DFR0_PMS); +} + +static inline bool is_feat_spe_supported(void) +{ + if (ENABLE_SPE_FOR_NS == FEAT_STATE_DISABLED) { + return false; + } + + if (ENABLE_SPE_FOR_NS == FEAT_STATE_ALWAYS) { + return true; + } + + return read_feat_spe_id_field() != 0U; } /******************************************************************************* diff --git a/include/lib/extensions/spe.h b/include/lib/extensions/spe.h index d4b925fe4..d443f18fb 100644 --- a/include/lib/extensions/spe.h +++ b/include/lib/extensions/spe.h @@ -9,8 +9,16 @@ #include -bool spe_supported(void); +#if ENABLE_SPE_FOR_NS void spe_enable(bool el2_unused); void spe_disable(void); +#else +void spe_enable(bool el2_unused) +{ +} +void spe_disable(void) +{ +} +#endif #endif /* SPE_H */ diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index 50fddc502..c5f20ad35 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -482,9 +482,9 @@ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) static void manage_extensions_nonsecure(bool el2_unused, cpu_context_t *ctx) { #if IMAGE_BL31 -#if ENABLE_SPE_FOR_NS - spe_enable(el2_unused); -#endif + if (is_feat_spe_supported()) { + spe_enable(el2_unused); + } #if ENABLE_AMU amu_enable(el2_unused, ctx); diff --git a/lib/extensions/spe/spe.c b/lib/extensions/spe/spe.c index d747efcd7..b1fe39f58 100644 --- a/lib/extensions/spe/spe.c +++ b/lib/extensions/spe/spe.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -20,21 +21,10 @@ static inline void psb_csync(void) __asm__ volatile("hint #17"); } -bool spe_supported(void) -{ - uint64_t features; - - features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; - return (features & ID_AA64DFR0_PMS_MASK) > 0ULL; -} - void spe_enable(bool el2_unused) { uint64_t v; - if (!spe_supported()) - return; - if (el2_unused) { /* * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical @@ -69,9 +59,6 @@ void spe_disable(void) { uint64_t v; - if (!spe_supported()) - return; - /* Drain buffered data */ psb_csync(); dsbnsh(); @@ -85,7 +72,7 @@ void spe_disable(void) static void *spe_drain_buffers_hook(const void *arg) { - if (!spe_supported()) + if (!is_feat_spe_supported()) return (void *)-1; /* Drain buffered data */ diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 63ac82e6d..b928fcf98 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -355,7 +355,7 @@ V := 0 WARMBOOT_ENABLE_DCACHE_EARLY := 0 # Build option to enable/disable the Statistical Profiling Extensions -ENABLE_SPE_FOR_NS := 1 +ENABLE_SPE_FOR_NS := 2 # SPE is only supported on AArch64 so disable it on AArch32. ifeq (${ARCH},aarch32) diff --git a/plat/arm/board/arm_fpga/fpga_bl31_setup.c b/plat/arm/board/arm_fpga/fpga_bl31_setup.c index e1b3abb28..5cc1e7645 100644 --- a/plat/arm/board/arm_fpga/fpga_bl31_setup.c +++ b/plat/arm/board/arm_fpga/fpga_bl31_setup.c @@ -364,7 +364,7 @@ static void fpga_prepare_dtb(void) fpga_dtb_update_clock(fdt, system_freq); /* Check whether we support the SPE PMU. Remove the DT node if not. */ - if (!spe_supported()) { + if (!is_feat_spe_supported()) { int node = fdt_node_offset_by_compatible(fdt, 0, "arm,statistical-profiling-extension-v1"); diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c index 9d9386230..3d53388e4 100644 --- a/plat/arm/board/fvp/fvp_pm.c +++ b/plat/arm/board/fvp/fvp_pm.c @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -53,13 +54,13 @@ static void fvp_cluster_pwrdwn_common(void) { uint64_t mpidr = read_mpidr_el1(); -#if ENABLE_SPE_FOR_NS /* * On power down we need to disable statistical profiling extensions * before exiting coherency. */ - spe_disable(); -#endif + if (is_feat_spe_supported()) { + spe_disable(); + } /* Disable coherency if this cluster is to be turned off */ fvp_interconnect_disable(); From 023f1bed1dde23564e3b66a99c4a45b09e38992b Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 21 Feb 2023 12:05:29 +0000 Subject: [PATCH 4/6] feat(libc): add support for fallthrough statement Modern C compilers warn about unannotated switch/case fallthrough code, and require either a comment with some magic words, or an explicit compiler attribute. Since some TF-A static analysis CI check suggests having a "fallthrough;" statement instead of a comment, introduce a macro that implements that statement, and emits the proper compiler attribute. Change-Id: Ib34e615fb48d0f4a340aabfad4472e08d5c70248 Signed-off-by: Andre Przywara --- include/lib/libc/cdefs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/lib/libc/cdefs.h b/include/lib/libc/cdefs.h index 423f0db7d..2423f3883 100644 --- a/include/lib/libc/cdefs.h +++ b/include/lib/libc/cdefs.h @@ -15,6 +15,7 @@ #define __maybe_unused __attribute__((__unused__)) #define __aligned(x) __attribute__((__aligned__(x))) #define __section(x) __attribute__((__section__(x))) +#define __fallthrough __attribute__((__fallthrough__)) #if RECLAIM_INIT_CODE /* * Add each function to a section that is unique so the functions can still From 9448f2b88e4afcea5ef671211882f09e7f64f9df Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 17 Nov 2022 16:42:09 +0000 Subject: [PATCH 5/6] refactor(mpam): enable FEAT_MPAM for FEAT_STATE_CHECKED At the moment we only support FEAT_MPAM to be either unconditionally compiled in, or to be not supported at all. Add support for runtime detection (ENABLE_MPAM_FOR_LOWER_ELS=2), by splitting get_mpam_version() into an ID register reading function and a second function to report the support status. That function considers both build time settings and runtime information (if needed), and is used before we access MPAM related registers. Also move the context saving code from assembly to C, and use the new is_feat_mpam_supported() function to guard its execution. ENABLE_MPAM_FOR_LOWER_ELS defaults to 0, so add a stub enable function to cover builds with compiler optimisations turned off. The unused mpam_enable() function call will normally be optimised away (because it would never be called), but with -O0 the compiler will leave the symbol in the object file. Change-Id: I531d87cb855a7c43471f861f625b5a6d4bc61313 Signed-off-by: Andre Przywara --- bl31/bl31.mk | 2 +- common/feat_detect.c | 13 +- include/arch/aarch64/arch.h | 6 +- include/arch/aarch64/arch_features.h | 15 +- include/arch/aarch64/arch_helpers.h | 22 ++- include/lib/el3_runtime/aarch64/context.h | 5 - include/lib/extensions/mpam.h | 6 + lib/el3_runtime/aarch64/context.S | 206 ---------------------- lib/el3_runtime/aarch64/context_mgmt.c | 108 +++++++++++- lib/extensions/mpam/mpam.c | 5 - plat/arm/board/fvp/platform.mk | 2 + 11 files changed, 142 insertions(+), 248 deletions(-) diff --git a/bl31/bl31.mk b/bl31/bl31.mk index e000f4f7b..91406cfc5 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -108,7 +108,7 @@ BL31_SOURCES += lib/extensions/sve/sve.c endif endif -ifeq (${ENABLE_MPAM_FOR_LOWER_ELS},1) +ifneq (${ENABLE_MPAM_FOR_LOWER_ELS},0) BL31_SOURCES += lib/extensions/mpam/mpam.c endif diff --git a/common/feat_detect.c b/common/feat_detect.c index 40997322a..a885107b8 100644 --- a/common/feat_detect.c +++ b/common/feat_detect.c @@ -130,16 +130,6 @@ static void read_feat_dit(void) #endif } -/**************************************************************************** - * Feature : FEAT_MPAM (Memory Partitioning and Monitoring (MPAM) Extension) - ***************************************************************************/ -static void read_feat_mpam(void) -{ -#if (ENABLE_MPAM_FOR_LOWER_ELS == FEAT_STATE_ALWAYS) - feat_detect_panic(get_mpam_version() != 0U, "MPAM"); -#endif -} - /************************************************************** * Feature : FEAT_NV2 (Enhanced Nested Virtualization Support) *************************************************************/ @@ -293,7 +283,8 @@ void detect_arch_features(void) read_feat_dit(); check_feature(ENABLE_FEAT_AMUv1, read_feat_amu_id_field(), "AMUv1", 1, 2); - read_feat_mpam(); + check_feature(ENABLE_MPAM_FOR_LOWER_ELS, read_feat_mpam_version(), + "MPAM", 1, 1); read_feat_nv2(); read_feat_sel2(); check_feature(ENABLE_TRF_FOR_NS, read_feat_trf_id_field(), diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h index b78652103..cafc1e8bc 100644 --- a/include/arch/aarch64/arch.h +++ b/include/arch/aarch64/arch.h @@ -1077,10 +1077,8 @@ #define MPAMHCR_EL2 S3_4_C10_C4_0 #define MPAM3_EL3 S3_6_C10_C5_0 -#define MPAMIDR_EL1_HAS_HCR_SHIFT ULL(0x11) -#define MPAMIDR_EL1_VPMR_MAX_SHIFT ULL(0x12) -#define MPAMIDR_EL1_VPMR_MAX_WIDTH ULL(0x3) -#define MPAMIDR_EL1_VPMR_MAX_POSSIBLE ULL(0x7) +#define MPAMIDR_EL1_VPMR_MAX_SHIFT ULL(18) +#define MPAMIDR_EL1_VPMR_MAX_MASK ULL(0x7) /******************************************************************************* * Definitions for system register interface to AMU for FEAT_AMUv1 ******************************************************************************/ diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h index 58b37521b..1bb6a8c2a 100644 --- a/include/arch/aarch64/arch_features.h +++ b/include/arch/aarch64/arch_features.h @@ -184,7 +184,7 @@ static inline bool is_armv8_6_feat_amuv1p1_present(void) * 0x11: v1.1 Armv8.4 or later * */ -static inline unsigned int get_mpam_version(void) +static inline unsigned int read_feat_mpam_version(void) { return (unsigned int)((((read_id_aa64pfr0_el1() >> ID_AA64PFR0_MPAM_SHIFT) & ID_AA64PFR0_MPAM_MASK) << 4) | @@ -192,6 +192,19 @@ static inline unsigned int get_mpam_version(void) ID_AA64PFR1_MPAM_FRAC_SHIFT) & ID_AA64PFR1_MPAM_FRAC_MASK)); } +static inline bool is_feat_mpam_supported(void) +{ + if (ENABLE_MPAM_FOR_LOWER_ELS == FEAT_STATE_DISABLED) { + return false; + } + + if (ENABLE_MPAM_FOR_LOWER_ELS == FEAT_STATE_ALWAYS) { + return true; + } + + return read_feat_mpam_version() != 0U; +} + static inline unsigned int read_feat_hcx_id_field(void) { return ISOLATE_FIELD(read_id_aa64mmfr1_el1(), ID_AA64MMFR1_EL1_HCX); diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h index 81e0e0643..e45fb8944 100644 --- a/include/arch/aarch64/arch_helpers.h +++ b/include/arch/aarch64/arch_helpers.h @@ -522,11 +522,6 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset0_el0, AMCNTENSET0_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr1_el0, AMCNTENCLR1_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset1_el0, AMCNTENSET1_EL0) -DEFINE_RENAME_SYSREG_READ_FUNC(mpamidr_el1, MPAMIDR_EL1) -DEFINE_RENAME_SYSREG_RW_FUNCS(mpam3_el3, MPAM3_EL3) -DEFINE_RENAME_SYSREG_RW_FUNCS(mpam2_el2, MPAM2_EL2) -DEFINE_RENAME_SYSREG_RW_FUNCS(mpamhcr_el2, MPAMHCR_EL2) - DEFINE_RENAME_SYSREG_RW_FUNCS(pmblimitr_el1, PMBLIMITR_EL1) DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el3, ZCR_EL3) @@ -545,9 +540,24 @@ DEFINE_RENAME_SYSREG_READ_FUNC(erxaddr_el1, ERXADDR_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc0_el1, ERXMISC0_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1) -/* Armv8.2 Registers */ +/* Armv8.2 ID Registers */ DEFINE_RENAME_IDREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1) +/* Armv8.2 MPAM Registers */ +DEFINE_RENAME_SYSREG_READ_FUNC(mpamidr_el1, MPAMIDR_EL1) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpam3_el3, MPAM3_EL3) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpam2_el2, MPAM2_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamhcr_el2, MPAMHCR_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpm0_el2, MPAMVPM0_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpm1_el2, MPAMVPM1_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpm2_el2, MPAMVPM2_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpm3_el2, MPAMVPM3_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpm4_el2, MPAMVPM4_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpm5_el2, MPAMVPM5_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpm6_el2, MPAMVPM6_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpm7_el2, MPAMVPM7_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(mpamvpmv_el2, MPAMVPMV_EL2) + /* Armv8.3 Pointer Authentication Registers */ DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeyhi_el1, APIAKeyHi_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeylo_el1, APIAKeyLo_EL1) diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h index 4cbda36b6..838e74484 100644 --- a/include/lib/el3_runtime/aarch64/context.h +++ b/include/lib/el3_runtime/aarch64/context.h @@ -193,7 +193,6 @@ // Only if MTE registers in use #define CTX_TFSR_EL2 U(0x100) -// Only if ENABLE_MPAM_FOR_LOWER_ELS==1 #define CTX_MPAM2_EL2 U(0x108) #define CTX_MPAMHCR_EL2 U(0x110) #define CTX_MPAMVPM0_EL2 U(0x118) @@ -518,10 +517,6 @@ void el2_sysregs_context_restore_common(el2_sysregs_t *regs); void el2_sysregs_context_save_mte(el2_sysregs_t *regs); void el2_sysregs_context_restore_mte(el2_sysregs_t *regs); #endif /* CTX_INCLUDE_MTE_REGS */ -#if ENABLE_MPAM_FOR_LOWER_ELS -void el2_sysregs_context_save_mpam(el2_sysregs_t *regs); -void el2_sysregs_context_restore_mpam(el2_sysregs_t *regs); -#endif /* ENABLE_MPAM_FOR_LOWER_ELS */ #if ENABLE_FEAT_ECV void el2_sysregs_context_save_ecv(el2_sysregs_t *regs); void el2_sysregs_context_restore_ecv(el2_sysregs_t *regs); diff --git a/include/lib/extensions/mpam.h b/include/lib/extensions/mpam.h index 414adcb4a..120a921d1 100644 --- a/include/lib/extensions/mpam.h +++ b/include/lib/extensions/mpam.h @@ -9,6 +9,12 @@ #include +#if ENABLE_MPAM_FOR_LOWER_ELS void mpam_enable(bool el2_unused); +#else +void mpam_enable(bool el2_unused) +{ +} +#endif #endif /* MPAM_H */ diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S index b05833432..7bb0f99a6 100644 --- a/lib/el3_runtime/aarch64/context.S +++ b/lib/el3_runtime/aarch64/context.S @@ -17,10 +17,6 @@ .global el2_sysregs_context_save_mte .global el2_sysregs_context_restore_mte #endif /* CTX_INCLUDE_MTE_REGS */ -#if ENABLE_MPAM_FOR_LOWER_ELS - .global el2_sysregs_context_save_mpam - .global el2_sysregs_context_restore_mpam -#endif /* ENABLE_MPAM_FOR_LOWER_ELS */ #if ENABLE_FEAT_ECV .global el2_sysregs_context_save_ecv .global el2_sysregs_context_restore_ecv @@ -230,208 +226,6 @@ func el2_sysregs_context_restore_mte endfunc el2_sysregs_context_restore_mte #endif /* CTX_INCLUDE_MTE_REGS */ -#if ENABLE_MPAM_FOR_LOWER_ELS -func el2_sysregs_context_save_mpam - mrs x10, MPAM2_EL2 - str x10, [x0, #CTX_MPAM2_EL2] - - mrs x10, MPAMIDR_EL1 - - /* - * The context registers that we intend to save would be part of the - * PE's system register frame only if MPAMIDR_EL1.HAS_HCR == 1. - */ - tbz w10, #MPAMIDR_EL1_HAS_HCR_SHIFT, 3f - - /* - * MPAMHCR_EL2, MPAMVPMV_EL2 and MPAMVPM0_EL2 would be present in the - * system register frame if MPAMIDR_EL1.HAS_HCR == 1. Proceed to save - * the context of these registers. - */ - mrs x11, MPAMHCR_EL2 - mrs x12, MPAMVPM0_EL2 - stp x11, x12, [x0, #CTX_MPAMHCR_EL2] - - mrs x13, MPAMVPMV_EL2 - str x13, [x0, #CTX_MPAMVPMV_EL2] - - /* - * MPAMIDR_EL1.VPMR_MAX has to be probed to obtain the maximum supported - * VPMR value. Proceed to save the context of registers from - * MPAMVPM1_EL2 to MPAMVPM_EL2 where x is VPMR_MAX. From MPAM spec, - * VPMR_MAX should not be zero if HAS_HCR == 1. - */ - ubfx x10, x10, #MPAMIDR_EL1_VPMR_MAX_SHIFT, \ - #MPAMIDR_EL1_VPMR_MAX_WIDTH - - /* - * Once VPMR_MAX has been identified, calculate the offset relative to - * PC to jump to so that relevant context can be saved. The offset is - * calculated as (VPMR_POSSIBLE_MAX - VPMR_MAX) * (instruction size for - * saving one VPM register) + (absolute address of label "1"). - */ - mov w11, #MPAMIDR_EL1_VPMR_MAX_POSSIBLE - sub w10, w11, w10 - - /* Calculate the size of one block of MPAMVPM*_EL2 save */ - adr x11, 1f - adr x12, 2f - sub x12, x12, x11 - - madd x10, x10, x12, x11 - br x10 - - /* - * The branch above would land properly on one of the blocks following - * label "1". Make sure that the order of save is retained. - */ -1: -#if ENABLE_BTI - bti j -#endif - mrs x10, MPAMVPM7_EL2 - str x10, [x0, #CTX_MPAMVPM7_EL2] -2: -#if ENABLE_BTI - bti j -#endif - mrs x11, MPAMVPM6_EL2 - str x11, [x0, #CTX_MPAMVPM6_EL2] - -#if ENABLE_BTI - bti j -#endif - mrs x12, MPAMVPM5_EL2 - str x12, [x0, #CTX_MPAMVPM5_EL2] - -#if ENABLE_BTI - bti j -#endif - mrs x13, MPAMVPM4_EL2 - str x13, [x0, #CTX_MPAMVPM4_EL2] - -#if ENABLE_BTI - bti j -#endif - mrs x14, MPAMVPM3_EL2 - str x14, [x0, #CTX_MPAMVPM3_EL2] - -#if ENABLE_BTI - bti j -#endif - mrs x15, MPAMVPM2_EL2 - str x15, [x0, #CTX_MPAMVPM2_EL2] - -#if ENABLE_BTI - bti j -#endif - mrs x16, MPAMVPM1_EL2 - str x16, [x0, #CTX_MPAMVPM1_EL2] - -3: ret -endfunc el2_sysregs_context_save_mpam - -func el2_sysregs_context_restore_mpam - ldr x10, [x0, #CTX_MPAM2_EL2] - msr MPAM2_EL2, x10 - - mrs x10, MPAMIDR_EL1 - /* - * The context registers that we intend to restore would be part of the - * PE's system register frame only if MPAMIDR_EL1.HAS_HCR == 1. - */ - tbz w10, #MPAMIDR_EL1_HAS_HCR_SHIFT, 3f - - /* - * MPAMHCR_EL2, MPAMVPMV_EL2 and MPAMVPM0_EL2 would be present in the - * system register frame if MPAMIDR_EL1.HAS_HCR == 1. Proceed to restore - * the context of these registers - */ - ldp x11, x12, [x0, #CTX_MPAMHCR_EL2] - msr MPAMHCR_EL2, x11 - msr MPAMVPM0_EL2, x12 - - ldr x13, [x0, #CTX_MPAMVPMV_EL2] - msr MPAMVPMV_EL2, x13 - - /* - * MPAMIDR_EL1.VPMR_MAX has to be probed to obtain the maximum supported - * VPMR value. Proceed to restore the context of registers from - * MPAMVPM1_EL2 to MPAMVPM_EL2 where x is VPMR_MAX. from MPAM spec, - * VPMR_MAX should not be zero if HAS_HCR == 1. - */ - ubfx x10, x10, #MPAMIDR_EL1_VPMR_MAX_SHIFT, \ - #MPAMIDR_EL1_VPMR_MAX_WIDTH - - /* - * Once VPMR_MAX has been identified, calculate the offset relative to - * PC to jump to so that relevant context can be restored. The offset is - * calculated as (VPMR_POSSIBLE_MAX - VPMR_MAX) * (instruction size for - * restoring one VPM register) + (absolute address of label "1"). - */ - mov w11, #MPAMIDR_EL1_VPMR_MAX_POSSIBLE - sub w10, w11, w10 - - /* Calculate the size of one block of MPAMVPM*_EL2 restore */ - adr x11, 1f - adr x12, 2f - sub x12, x12, x11 - - madd x10, x10, x12, x11 - br x10 - - /* - * The branch above would land properly on one of the blocks following - * label "1". Make sure that the order of restore is retained. - */ -1: - -#if ENABLE_BTI - bti j -#endif - ldr x10, [x0, #CTX_MPAMVPM7_EL2] - msr MPAMVPM7_EL2, x10 -2: -#if ENABLE_BTI - bti j -#endif - ldr x11, [x0, #CTX_MPAMVPM6_EL2] - msr MPAMVPM6_EL2, x11 - -#if ENABLE_BTI - bti j -#endif - ldr x12, [x0, #CTX_MPAMVPM5_EL2] - msr MPAMVPM5_EL2, x12 - -#if ENABLE_BTI - bti j -#endif - ldr x13, [x0, #CTX_MPAMVPM4_EL2] - msr MPAMVPM4_EL2, x13 - -#if ENABLE_BTI - bti j -#endif - ldr x14, [x0, #CTX_MPAMVPM3_EL2] - msr MPAMVPM3_EL2, x14 - -#if ENABLE_BTI - bti j -#endif - ldr x15, [x0, #CTX_MPAMVPM2_EL2] - msr MPAMVPM2_EL2, x15 - -#if ENABLE_BTI - bti j -#endif - ldr x16, [x0, #CTX_MPAMVPM1_EL2] - msr MPAMVPM1_EL2, x16 - -3: ret -endfunc el2_sysregs_context_restore_mpam -#endif /* ENABLE_MPAM_FOR_LOWER_ELS */ - #if ENABLE_FEAT_ECV func el2_sysregs_context_save_ecv mrs x11, CNTPOFF_EL2 diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index c5f20ad35..eb5d1dbf2 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -498,9 +498,9 @@ static void manage_extensions_nonsecure(bool el2_unused, cpu_context_t *ctx) sve_enable(ctx); #endif -#if ENABLE_MPAM_FOR_LOWER_ELS - mpam_enable(el2_unused); -#endif + if (is_feat_mpam_supported()) { + mpam_enable(el2_unused); + } if (is_feat_trbe_supported()) { trbe_enable(); @@ -834,6 +834,96 @@ static void el2_sysregs_context_restore_fgt(el2_sysregs_t *ctx) write_hfgwtr_el2(read_ctx_reg(ctx, CTX_HFGWTR_EL2)); } +static void el2_sysregs_context_save_mpam(el2_sysregs_t *ctx) +{ + u_register_t mpam_idr = read_mpamidr_el1(); + + write_ctx_reg(ctx, CTX_MPAM2_EL2, read_mpam2_el2()); + + /* + * The context registers that we intend to save would be part of the + * PE's system register frame only if MPAMIDR_EL1.HAS_HCR == 1. + */ + if ((mpam_idr & MPAMIDR_HAS_HCR_BIT) == 0U) { + return; + } + + /* + * MPAMHCR_EL2, MPAMVPMV_EL2 and MPAMVPM0_EL2 are always present if + * MPAMIDR_HAS_HCR_BIT == 1. + */ + write_ctx_reg(ctx, CTX_MPAMHCR_EL2, read_mpamhcr_el2()); + write_ctx_reg(ctx, CTX_MPAMVPM0_EL2, read_mpamvpm0_el2()); + write_ctx_reg(ctx, CTX_MPAMVPMV_EL2, read_mpamvpmv_el2()); + + /* + * The number of MPAMVPM registers is implementation defined, their + * number is stored in the MPAMIDR_EL1 register. + */ + switch ((mpam_idr >> MPAMIDR_EL1_VPMR_MAX_SHIFT) & MPAMIDR_EL1_VPMR_MAX_MASK) { + case 7: + write_ctx_reg(ctx, CTX_MPAMVPM7_EL2, read_mpamvpm7_el2()); + __fallthrough; + case 6: + write_ctx_reg(ctx, CTX_MPAMVPM6_EL2, read_mpamvpm6_el2()); + __fallthrough; + case 5: + write_ctx_reg(ctx, CTX_MPAMVPM5_EL2, read_mpamvpm5_el2()); + __fallthrough; + case 4: + write_ctx_reg(ctx, CTX_MPAMVPM4_EL2, read_mpamvpm4_el2()); + __fallthrough; + case 3: + write_ctx_reg(ctx, CTX_MPAMVPM3_EL2, read_mpamvpm3_el2()); + __fallthrough; + case 2: + write_ctx_reg(ctx, CTX_MPAMVPM2_EL2, read_mpamvpm2_el2()); + __fallthrough; + case 1: + write_ctx_reg(ctx, CTX_MPAMVPM1_EL2, read_mpamvpm1_el2()); + break; + } +} + +static void el2_sysregs_context_restore_mpam(el2_sysregs_t *ctx) +{ + u_register_t mpam_idr = read_mpamidr_el1(); + + write_mpam2_el2(read_ctx_reg(ctx, CTX_MPAM2_EL2)); + + if ((mpam_idr & MPAMIDR_HAS_HCR_BIT) == 0U) { + return; + } + + write_mpamhcr_el2(read_ctx_reg(ctx, CTX_MPAMHCR_EL2)); + write_mpamvpm0_el2(read_ctx_reg(ctx, CTX_MPAMVPM0_EL2)); + write_mpamvpmv_el2(read_ctx_reg(ctx, CTX_MPAMVPMV_EL2)); + + switch ((mpam_idr >> MPAMIDR_EL1_VPMR_MAX_SHIFT) & MPAMIDR_EL1_VPMR_MAX_MASK) { + case 7: + write_mpamvpm7_el2(read_ctx_reg(ctx, CTX_MPAMVPM7_EL2)); + __fallthrough; + case 6: + write_mpamvpm6_el2(read_ctx_reg(ctx, CTX_MPAMVPM6_EL2)); + __fallthrough; + case 5: + write_mpamvpm5_el2(read_ctx_reg(ctx, CTX_MPAMVPM5_EL2)); + __fallthrough; + case 4: + write_mpamvpm4_el2(read_ctx_reg(ctx, CTX_MPAMVPM4_EL2)); + __fallthrough; + case 3: + write_mpamvpm3_el2(read_ctx_reg(ctx, CTX_MPAMVPM3_EL2)); + __fallthrough; + case 2: + write_mpamvpm2_el2(read_ctx_reg(ctx, CTX_MPAMVPM2_EL2)); + __fallthrough; + case 1: + write_mpamvpm1_el2(read_ctx_reg(ctx, CTX_MPAMVPM1_EL2)); + break; + } +} + /******************************************************************************* * Save EL2 sysreg context ******************************************************************************/ @@ -859,9 +949,9 @@ void cm_el2_sysregs_context_save(uint32_t security_state) #if CTX_INCLUDE_MTE_REGS el2_sysregs_context_save_mte(el2_sysregs_ctx); #endif -#if ENABLE_MPAM_FOR_LOWER_ELS - el2_sysregs_context_save_mpam(el2_sysregs_ctx); -#endif + if (is_feat_mpam_supported()) { + el2_sysregs_context_save_mpam(el2_sysregs_ctx); + } if (is_feat_fgt_supported()) { el2_sysregs_context_save_fgt(el2_sysregs_ctx); @@ -919,9 +1009,9 @@ void cm_el2_sysregs_context_restore(uint32_t security_state) #if CTX_INCLUDE_MTE_REGS el2_sysregs_context_restore_mte(el2_sysregs_ctx); #endif -#if ENABLE_MPAM_FOR_LOWER_ELS - el2_sysregs_context_restore_mpam(el2_sysregs_ctx); -#endif + if (is_feat_mpam_supported()) { + el2_sysregs_context_restore_mpam(el2_sysregs_ctx); + } if (is_feat_fgt_supported()) { el2_sysregs_context_restore_fgt(el2_sysregs_ctx); diff --git a/lib/extensions/mpam/mpam.c b/lib/extensions/mpam/mpam.c index 884d480d5..62533fcac 100644 --- a/lib/extensions/mpam/mpam.c +++ b/lib/extensions/mpam/mpam.c @@ -13,11 +13,6 @@ void mpam_enable(bool el2_unused) { - /* Check if MPAM is implemented */ - if (get_mpam_version() == 0U) { - return; - } - /* * Enable MPAM, and disable trapping to EL3 when lower ELs access their * own MPAM registers. diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index 207e0d721..2e7ff480b 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -469,6 +469,8 @@ ENABLE_FEAT_FGT := 2 ENABLE_FEAT_HCX := 2 ENABLE_FEAT_TCR2 := 2 +ENABLE_MPAM_FOR_LOWER_ELS := 2 + ifeq (${SPMC_AT_EL3}, 1) PLAT_BL_COMMON_SOURCES += plat/arm/board/fvp/fvp_el3_spmc.c endif From ea735bf556f8768fd4c82a7b3c224b529aee057a Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 17 Nov 2022 16:42:09 +0000 Subject: [PATCH 6/6] refactor(cpufeat): enable FEAT_VHE for FEAT_STATE_CHECKED At the moment we only support FEAT_VHE to be either unconditionally compiled in, or to be not supported at all. Add support for runtime detection (ENABLE_FEAT_VHE=2), by splitting is_armv8_1_vhe_present() into an ID register reading function and a second function to report the support status. That function considers both build time settings and runtime information (if needed), and is used before we access VHE related registers. Also move the context saving code from assembly to C, and use the new is_feat_vhe_supported() function to guard its execution. Enable VHE in its runtime detection version for all FVP builds. Change-Id: Ib397cd0c83e8c709bd6fed603560e39901fa672b Signed-off-by: Andre Przywara --- common/feat_detect.c | 12 +--------- include/arch/aarch64/arch.h | 2 ++ include/arch/aarch64/arch_features.h | 18 ++++++++++++--- include/arch/aarch64/arch_helpers.h | 4 ++++ include/lib/el3_runtime/aarch64/context.h | 4 ---- lib/el3_runtime/aarch64/context.S | 28 ----------------------- lib/el3_runtime/aarch64/context_mgmt.c | 16 ++++++++----- plat/arm/board/fvp/platform.mk | 1 + services/std_svc/sdei/sdei_intr_mgmt.c | 2 +- 9 files changed, 34 insertions(+), 53 deletions(-) diff --git a/common/feat_detect.c b/common/feat_detect.c index a885107b8..abb6d718c 100644 --- a/common/feat_detect.c +++ b/common/feat_detect.c @@ -90,16 +90,6 @@ static void read_feat_pan(void) #endif } -/****************************************************** - * Feature : FEAT_VHE (Virtualization Host Extensions) - *****************************************************/ -static void read_feat_vhe(void) -{ -#if (ENABLE_FEAT_VHE == FEAT_STATE_ALWAYS) - feat_detect_panic(is_armv8_1_vhe_present(), "VHE"); -#endif -} - /******************************************************************************* * Feature : FEAT_RAS (Reliability, Availability, and Serviceability Extension) ******************************************************************************/ @@ -271,7 +261,7 @@ void detect_arch_features(void) /* v8.1 features */ read_feat_pan(); - read_feat_vhe(); + check_feature(ENABLE_FEAT_VHE, read_feat_vhe_id_field(), "VHE", 1, 1); /* v8.2 features */ read_feat_ras(); diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h index cafc1e8bc..85546ec47 100644 --- a/include/arch/aarch64/arch.h +++ b/include/arch/aarch64/arch.h @@ -121,6 +121,8 @@ #define TRFCR_EL2 S3_4_C1_C2_1 #define PMSCR_EL2 S3_4_C9_C9_0 #define TFSR_EL2 S3_4_C5_C6_0 +#define CONTEXTIDR_EL2 S3_4_C13_C0_1 +#define TTBR1_EL2 S3_4_C2_C0_1 /******************************************************************************* * Generic timer memory mapped registers & offsets diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h index 1bb6a8c2a..f1a13d290 100644 --- a/include/arch/aarch64/arch_features.h +++ b/include/arch/aarch64/arch_features.h @@ -27,10 +27,22 @@ static inline bool is_armv8_1_pan_present(void) ID_AA64MMFR1_EL1_PAN_MASK) != 0U; } -static inline bool is_armv8_1_vhe_present(void) +static inline unsigned int read_feat_vhe_id_field(void) { - return ((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_VHE_SHIFT) & - ID_AA64MMFR1_EL1_VHE_MASK) != 0U; + return ISOLATE_FIELD(read_id_aa64mmfr1_el1(), ID_AA64MMFR1_EL1_VHE); +} + +static inline bool is_feat_vhe_supported(void) +{ + if (ENABLE_FEAT_VHE == FEAT_STATE_DISABLED) { + return false; + } + + if (ENABLE_FEAT_VHE == FEAT_STATE_ALWAYS) { + return true; + } + + return read_feat_vhe_id_field() != 0U; } static inline bool is_armv8_2_ttcnp_present(void) diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h index e45fb8944..6d115c7e5 100644 --- a/include/arch/aarch64/arch_helpers.h +++ b/include/arch/aarch64/arch_helpers.h @@ -540,6 +540,10 @@ DEFINE_RENAME_SYSREG_READ_FUNC(erxaddr_el1, ERXADDR_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc0_el1, ERXMISC0_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1) +/* Armv8.1 VHE Registers */ +DEFINE_RENAME_SYSREG_RW_FUNCS(contextidr_el2, CONTEXTIDR_EL2) +DEFINE_RENAME_SYSREG_RW_FUNCS(ttbr1_el2, TTBR1_EL2) + /* Armv8.2 ID Registers */ DEFINE_RENAME_IDREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1) diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h index 838e74484..9b50f3319 100644 --- a/include/lib/el3_runtime/aarch64/context.h +++ b/include/lib/el3_runtime/aarch64/context.h @@ -521,10 +521,6 @@ void el2_sysregs_context_restore_mte(el2_sysregs_t *regs); void el2_sysregs_context_save_ecv(el2_sysregs_t *regs); void el2_sysregs_context_restore_ecv(el2_sysregs_t *regs); #endif /* ENABLE_FEAT_ECV */ -#if ENABLE_FEAT_VHE -void el2_sysregs_context_save_vhe(el2_sysregs_t *regs); -void el2_sysregs_context_restore_vhe(el2_sysregs_t *regs); -#endif /* ENABLE_FEAT_VHE */ #if RAS_EXTENSION void el2_sysregs_context_save_ras(el2_sysregs_t *regs); void el2_sysregs_context_restore_ras(el2_sysregs_t *regs); diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S index 7bb0f99a6..a5b64a5f2 100644 --- a/lib/el3_runtime/aarch64/context.S +++ b/lib/el3_runtime/aarch64/context.S @@ -21,10 +21,6 @@ .global el2_sysregs_context_save_ecv .global el2_sysregs_context_restore_ecv #endif /* ENABLE_FEAT_ECV */ -#if ENABLE_FEAT_VHE - .global el2_sysregs_context_save_vhe - .global el2_sysregs_context_restore_vhe -#endif /* ENABLE_FEAT_VHE */ #if RAS_EXTENSION .global el2_sysregs_context_save_ras .global el2_sysregs_context_restore_ras @@ -240,30 +236,6 @@ func el2_sysregs_context_restore_ecv endfunc el2_sysregs_context_restore_ecv #endif /* ENABLE_FEAT_ECV */ -#if ENABLE_FEAT_VHE -func el2_sysregs_context_save_vhe - /* - * CONTEXTIDR_EL2 register is saved only when FEAT_VHE or - * FEAT_Debugv8p2 (currently not in TF-A) is supported. - */ - mrs x9, contextidr_el2 - mrs x10, ttbr1_el2 - stp x9, x10, [x0, #CTX_CONTEXTIDR_EL2] - ret -endfunc el2_sysregs_context_save_vhe - -func el2_sysregs_context_restore_vhe - /* - * CONTEXTIDR_EL2 register is restored only when FEAT_VHE or - * FEAT_Debugv8p2 (currently not in TF-A) is supported. - */ - ldp x9, x10, [x0, #CTX_CONTEXTIDR_EL2] - msr contextidr_el2, x9 - msr ttbr1_el2, x10 - ret -endfunc el2_sysregs_context_restore_vhe -#endif /* ENABLE_FEAT_VHE */ - #if RAS_EXTENSION func el2_sysregs_context_save_ras /* diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index eb5d1dbf2..20eb5f67d 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -960,9 +960,12 @@ void cm_el2_sysregs_context_save(uint32_t security_state) #if ENABLE_FEAT_ECV el2_sysregs_context_save_ecv(el2_sysregs_ctx); #endif -#if ENABLE_FEAT_VHE - el2_sysregs_context_save_vhe(el2_sysregs_ctx); -#endif + if (is_feat_vhe_supported()) { + write_ctx_reg(el2_sysregs_ctx, CTX_CONTEXTIDR_EL2, + read_contextidr_el2()); + write_ctx_reg(el2_sysregs_ctx, CTX_TTBR1_EL2, + read_ttbr1_el2()); + } #if RAS_EXTENSION el2_sysregs_context_save_ras(el2_sysregs_ctx); #endif @@ -1020,9 +1023,10 @@ void cm_el2_sysregs_context_restore(uint32_t security_state) #if ENABLE_FEAT_ECV el2_sysregs_context_restore_ecv(el2_sysregs_ctx); #endif -#if ENABLE_FEAT_VHE - el2_sysregs_context_restore_vhe(el2_sysregs_ctx); -#endif + if (is_feat_vhe_supported()) { + write_contextidr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_CONTEXTIDR_EL2)); + write_ttbr1_el2(read_ctx_reg(el2_sysregs_ctx, CTX_TTBR1_EL2)); + } #if RAS_EXTENSION el2_sysregs_context_restore_ras(el2_sysregs_ctx); #endif diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index 2e7ff480b..435a35e3d 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -469,6 +469,7 @@ ENABLE_FEAT_FGT := 2 ENABLE_FEAT_HCX := 2 ENABLE_FEAT_TCR2 := 2 +ENABLE_FEAT_VHE := 2 ENABLE_MPAM_FOR_LOWER_ELS := 2 ifeq (${SPMC_AT_EL3}, 1) diff --git a/services/std_svc/sdei/sdei_intr_mgmt.c b/services/std_svc/sdei/sdei_intr_mgmt.c index 87a1fb7dc..9862e4f8d 100644 --- a/services/std_svc/sdei/sdei_intr_mgmt.c +++ b/services/std_svc/sdei/sdei_intr_mgmt.c @@ -270,7 +270,7 @@ static void sdei_set_elr_spsr(sdei_entry_t *se, sdei_dispatch_context_t *disp_ct * HCR_EL2.E2H = 1 and HCR_EL2.TGE = 1 */ u_register_t hcr_el2 = read_hcr(); - bool el_is_in_host = is_armv8_1_vhe_present() && + bool el_is_in_host = (read_feat_vhe_id_field() != 0U) && (hcr_el2 & HCR_TGE_BIT) && (hcr_el2 & HCR_E2H_BIT);