From 7455cd1721ec3b8671d6a2fae879f86ecfe497fb Mon Sep 17 00:00:00 2001 From: Govindraj Raja Date: Wed, 29 Jan 2025 15:01:10 -0600 Subject: [PATCH] fix(cpus): workaround for accessing ICH_VMCR_EL2 When ICH_VMCR_EL2.VBPR1 is written in Secure state (SCR_EL3.NS==0) and then subsequently read in Non-secure state (SCR_EL3.NS==1), a wrong value might be returned. The same issue exists in the opposite way. Adding workaround in EL3 software that performs context save/restore on a change of Security state to use a value of SCR_EL3.NS when accessing ICH_VMCR_EL2 that reflects the Security state that owns the data being saved or restored. For example, EL3 software should set SCR_EL3.NS to 1 when saving or restoring the value ICH_VMCR_EL2 for Non-secure(or Realm) state. EL3 software should clear SCR_EL3.NS to 0 when saving or restoring the value ICH_VMCR_EL2 for Secure state. SDEN documentation: https://developer.arm.com/documentation/SDEN-1775101/latest/ Change-Id: I9f0403601c6346276e925f02eab55908b009d957 Signed-off-by: Govindraj Raja --- include/lib/cpus/errata.h | 1 + lib/cpus/errata_common.c | 14 ++++++-- lib/el3_runtime/aarch64/context_mgmt.c | 46 ++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h index 18ddc836d..b9166f713 100644 --- a/include/lib/cpus/errata.h +++ b/include/lib/cpus/errata.h @@ -70,6 +70,7 @@ unsigned int check_if_affected_core(void); #endif int check_wa_cve_2024_7881(void); +bool errata_ich_vmcr_el2_applies(void); #else diff --git a/lib/cpus/errata_common.c b/lib/cpus/errata_common.c index a4515a9e2..4cd105e34 100644 --- a/lib/cpus/errata_common.c +++ b/lib/cpus/errata_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -8,9 +8,9 @@ #include #include +#include #include #include -#include #include #include @@ -40,3 +40,13 @@ bool errata_a75_764081_applies(void) return false; } #endif /* ERRATA_A75_764081 */ + +bool errata_ich_vmcr_el2_applies(void) +{ + switch (EXTRACT_PARTNUM(read_midr())) { + default: + break; + } + + return false; +} diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index 473190c11..f396752ef 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved. * Copyright (c) 2022, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -1291,12 +1291,13 @@ static void el2_sysregs_context_restore_mpam(el2_sysregs_t *ctx) * SCR_EL3.NS = 1 before accessing this register. * --------------------------------------------------------------------------- */ -static void el2_sysregs_context_save_gic(el2_sysregs_t *ctx) +static void el2_sysregs_context_save_gic(el2_sysregs_t *ctx, uint32_t security_state) { + u_register_t scr_el3 = read_scr_el3(); + #if defined(SPD_spmd) && SPMD_SPM_AT_SEL2 write_el2_ctx_common(ctx, icc_sre_el2, read_icc_sre_el2()); #else - u_register_t scr_el3 = read_scr_el3(); write_scr_el3(scr_el3 | SCR_NS_BIT); isb(); @@ -1306,15 +1307,31 @@ static void el2_sysregs_context_save_gic(el2_sysregs_t *ctx) isb(); #endif write_el2_ctx_common(ctx, ich_hcr_el2, read_ich_hcr_el2()); + + if (errata_ich_vmcr_el2_applies()) { + if (security_state == SECURE) { + write_scr_el3(scr_el3 & ~SCR_NS_BIT); + } else { + write_scr_el3(scr_el3 | SCR_NS_BIT); + } + isb(); + } + write_el2_ctx_common(ctx, ich_vmcr_el2, read_ich_vmcr_el2()); + + if (errata_ich_vmcr_el2_applies()) { + write_scr_el3(scr_el3); + isb(); + } } -static void el2_sysregs_context_restore_gic(el2_sysregs_t *ctx) +static void el2_sysregs_context_restore_gic(el2_sysregs_t *ctx, uint32_t security_state) { + u_register_t scr_el3 = read_scr_el3(); + #if defined(SPD_spmd) && SPMD_SPM_AT_SEL2 write_icc_sre_el2(read_el2_ctx_common(ctx, icc_sre_el2)); #else - u_register_t scr_el3 = read_scr_el3(); write_scr_el3(scr_el3 | SCR_NS_BIT); isb(); @@ -1324,7 +1341,22 @@ static void el2_sysregs_context_restore_gic(el2_sysregs_t *ctx) isb(); #endif write_ich_hcr_el2(read_el2_ctx_common(ctx, ich_hcr_el2)); + + if (errata_ich_vmcr_el2_applies()) { + if (security_state == SECURE) { + write_scr_el3(scr_el3 & ~SCR_NS_BIT); + } else { + write_scr_el3(scr_el3 | SCR_NS_BIT); + } + isb(); + } + write_ich_vmcr_el2(read_el2_ctx_common(ctx, ich_vmcr_el2)); + + if (errata_ich_vmcr_el2_applies()) { + write_scr_el3(scr_el3); + isb(); + } } /* ----------------------------------------------------- @@ -1416,7 +1448,7 @@ 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); - el2_sysregs_context_save_gic(el2_sysregs_ctx); + el2_sysregs_context_save_gic(el2_sysregs_ctx, security_state); if (is_feat_mte2_supported()) { write_el2_ctx_mte2(el2_sysregs_ctx, tfsr_el2, read_tfsr_el2()); @@ -1507,7 +1539,7 @@ 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); - el2_sysregs_context_restore_gic(el2_sysregs_ctx); + el2_sysregs_context_restore_gic(el2_sysregs_ctx, security_state); if (is_feat_mte2_supported()) { write_tfsr_el2(read_el2_ctx_mte2(el2_sysregs_ctx, tfsr_el2));