test(security): add testcase for SMCCC_ARCH_WORKAROUND_4

Testing was conducted using FVP Version 11.26.11
on Cortex-X3, Cortex-X4, Neoverse-V2, Neoverse-V3
and Cortex-X925. Additionally, negative testing
was performed on Cortex-X2.

This patch tests SMCCC_ARCH_WORKAROUND_4 [1] for CVE_2024_7881 [2]
[1]: https://developer.arm.com/documentation/den0028/latest
[2]: https://developer.arm.com/Arm%20Security%20Center/Arm%20CPU%20Vulnerability%20CVE-2024-7881

Change-Id: I4c33b7a9372236ce3ef38f9d1786d5794bb7ddbc
Signed-off-by: Arvind Ram Prakash <arvind.ramprakash@arm.com>
(cherry picked from commit 43d421bb292984fdc56269fb3e87e619ca0892d3)
diff --git a/include/runtime_services/arm_arch_svc.h b/include/runtime_services/arm_arch_svc.h
index 0d2eb38..0468144 100644
--- a/include/runtime_services/arm_arch_svc.h
+++ b/include/runtime_services/arm_arch_svc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,5 +13,6 @@
 #define SMCCC_ARCH_WORKAROUND_1	0x80008000
 #define SMCCC_ARCH_WORKAROUND_2	0x80007FFF
 #define SMCCC_ARCH_WORKAROUND_3	0x80003FFF
+#define SMCCC_ARCH_WORKAROUND_4	0x80000004
 
 #endif /* __ARM_ARCH_SVC_H__ */
diff --git a/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_4.c b/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_4.c
new file mode 100644
index 0000000..98872a1
--- /dev/null
+++ b/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_4.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_arch_svc.h>
+#include <debug.h>
+#include <plat_topology.h>
+#include <power_management.h>
+#include <psci.h>
+#include <smccc.h>
+#include <string.h>
+#include <tftf_lib.h>
+
+#ifdef __aarch64__
+#define CORTEX_X2_MIDR		0x410FD480
+#define CORTEX_X3_MIDR		0x410FD4E0
+#define CORTEX_X4_MIDR		0x410FD821
+#define CORTEX_X925_MIDR	0x410FD850
+#define NEOVERSE_V2_MIDR	0x410FD4F0
+#define NEOVERSE_V3_MIDR	0x410FD840
+
+static int cortex_x2_test(void);
+static int cortex_x3_test(void);
+static int cortex_x4_test(void);
+static int cortex_x925_test(void);
+static int neoverse_v2_test(void);
+static int neoverse_v3_test(void);
+
+struct ent {
+	unsigned int midr;
+	int (*smc_ret)(void);
+};
+
+struct ent negative_entries[] = {
+	{ .midr = CORTEX_X2_MIDR, .smc_ret = cortex_x2_test }
+};
+
+struct ent positive_entries[] = {
+	{ .midr = CORTEX_X3_MIDR, .smc_ret = cortex_x3_test },
+	{ .midr = CORTEX_X4_MIDR, .smc_ret = cortex_x4_test },
+	{ .midr = CORTEX_X925_MIDR, .smc_ret = cortex_x925_test },
+	{ .midr = NEOVERSE_V2_MIDR, .smc_ret = neoverse_v2_test},
+	{ .midr = NEOVERSE_V3_MIDR, .smc_ret = neoverse_v3_test},
+};
+
+static int cortex_x2_test(void)
+{
+	return -1;
+}
+static int cortex_x3_test(void)
+{
+	return 0;
+}
+
+static int cortex_x4_test(void)
+{
+	return 0;
+}
+
+static int cortex_x925_test(void)
+{
+	return 0;
+}
+
+static int neoverse_v2_test(void)
+{
+	return 0;
+}
+
+static int neoverse_v3_test(void)
+{
+	return 0;
+}
+
+static test_result_t test_smccc_entrypoint(void)
+{
+	smc_args args;
+	smc_ret_values ret;
+	int32_t expected_ver;
+	unsigned int my_midr, midr_mask;
+	size_t i;
+
+	/* Check if SMCCC version is at least v1.1 */
+	expected_ver = MAKE_SMCCC_VERSION(1, 1);
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_VERSION;
+	ret = tftf_smc(&args);
+	if ((int32_t)ret.ret0 < expected_ver) {
+		tftf_testcase_printf("Unexpected SMCCC version: 0x%x\n",
+		       (int)ret.ret0);
+		return TEST_RESULT_SKIPPED;
+	}
+
+	/* Check if SMCCC_ARCH_WORKAROUND_4 is required or not */
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_ARCH_FEATURES;
+	args.arg1 = SMCCC_ARCH_WORKAROUND_4;
+	ret = tftf_smc(&args);
+
+	/*
+	 * Negetive test. Checks if select non-affected cores
+	 * return -1 (Not supported)
+	 */
+	my_midr = (unsigned int)read_midr_el1();
+	midr_mask = (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | (MIDR_PN_MASK << MIDR_PN_SHIFT);
+	for (i = 0; i < ARRAY_SIZE(negative_entries); i++) {
+		struct ent *entp = &negative_entries[i];
+		if ((my_midr & midr_mask) == (entp->midr & midr_mask)) {
+			if (entp->smc_ret() != -1) {
+				return TEST_RESULT_FAIL;
+			}
+			break;
+		}
+	}
+
+	if ((int)ret.ret0 == -1) {
+		tftf_testcase_printf("SMCCC_ARCH_WORKAROUND_4 is not implemented\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	/* Check if the SMC return value matches our expectations */
+	for (i = 0; i < ARRAY_SIZE(positive_entries); i++) {
+		struct ent *entp = &positive_entries[i];
+		if ((my_midr & midr_mask) == (entp->midr & midr_mask)) {
+			if (entp->smc_ret() != 0) {
+				return TEST_RESULT_FAIL;
+			}
+			break;
+		}
+	}
+
+	if ((i == ARRAY_SIZE(positive_entries)) && ((int)ret.ret0) == 0) {
+		tftf_testcase_printf("TFTF workaround table out of sync with TF-A\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Invoke the workaround to make sure nothing nasty happens */
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_ARCH_WORKAROUND_4;
+	tftf_smc(&args);
+	return TEST_RESULT_SUCCESS;
+}
+
+test_result_t test_smccc_arch_workaround_4(void)
+{
+	u_register_t lead_mpid, target_mpid;
+	int cpu_node, ret;
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+	/* Power on all the non-lead cores. */
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node);
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+		ret = tftf_cpu_on(target_mpid,
+		    (uintptr_t)test_smccc_entrypoint, 0);
+		if (ret != PSCI_E_SUCCESS) {
+			ERROR("CPU ON failed for 0x%llx\n",
+			    (unsigned long long)target_mpid);
+			return TEST_RESULT_FAIL;
+		}
+		/*
+		 * Wait for test_smccc_entrypoint to return
+		 * and the CPU to power down
+		 */
+		while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+			PSCI_STATE_OFF) {
+			continue;
+		}
+	}
+
+	return test_smccc_entrypoint();
+}
+#else
+test_result_t test_smccc_arch_workaround_4(void)
+{
+	INFO("%s skipped on AArch32\n", __func__);
+	return TEST_RESULT_SKIPPED;
+}
+#endif
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index 3616cf4..3771544 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -24,4 +24,5 @@
 	runtime_services/arm_arch_svc/smccc_arch_workaround_1.c		\
 	runtime_services/arm_arch_svc/smccc_arch_workaround_2.c		\
 	runtime_services/arm_arch_svc/smccc_arch_workaround_3.c		\
+	runtime_services/arm_arch_svc/smccc_arch_workaround_4.c		\
 )
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index d45cf62..7415bbf 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -35,6 +35,7 @@
      <testcase name="SMCCC_ARCH_WORKAROUND_1 test" function="test_smccc_arch_workaround_1" />
      <testcase name="SMCCC_ARCH_WORKAROUND_2 test" function="test_smccc_arch_workaround_2" />
      <testcase name="SMCCC_ARCH_WORKAROUND_3 test" function="test_smccc_arch_workaround_3" />
+     <testcase name="SMCCC_ARCH_WORKAROUND_4 test" function="test_smccc_arch_workaround_4" />
      <testcase name="SMCCC_ARCH_SOC_ID test" function="test_smccc_arch_soc_id" />
   </testsuite>