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 <govindraj.raja@arm.com>
diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h
index 18ddc83..b9166f7 100644
--- a/include/lib/cpus/errata.h
+++ b/include/lib/cpus/errata.h
@@ -70,6 +70,7 @@
 #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 a4515a9..4cd105e 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 <arch.h>
 #include <arch_helpers.h>
+#include <cortex_a75.h>
 #include <cortex_a520.h>
 #include <cortex_x4.h>
-#include <cortex_a75.h>
 #include <lib/cpus/cpu_ops.h>
 #include <lib/cpus/errata.h>
 
@@ -40,3 +40,13 @@
 	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 473190c..f396752 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 @@
  * 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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));