feat(ras): test to verify SErros synchronized at EL3 boundry

Tests to verify SErrors which gets triggered as part of error
synchronization at EL3 entry.
In FFH mode, EL3 does nested exception handling while in KFH it
reflectes it back to TF-A Tests.

Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
Change-Id: I5a980ed49ee47ea2f0d5685ba8378d48393ad157
diff --git a/tftf/tests/misc_tests/test_ras_ffh_nested.c b/tftf/tests/misc_tests/test_ras_ffh_nested.c
new file mode 100644
index 0000000..99c71b75
--- /dev/null
+++ b/tftf/tests/misc_tests/test_ras_ffh_nested.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <arch_helpers.h>
+#include <arm_arch_svc.h>
+#include <psci.h>
+#include <sdei.h>
+#include <smccc.h>
+#include <tftf_lib.h>
+
+#ifdef __aarch64__
+static volatile uint64_t sdei_event_received;
+extern void inject_unrecoverable_ras_error(void);
+extern int serror_sdei_event_handler(int ev, uint64_t arg);
+
+int sdei_handler(int ev, uint64_t arg)
+{
+	sdei_event_received = 1;
+	tftf_testcase_printf("SError SDEI event received.\n");
+	return 0;
+}
+
+/*
+ * Test to verify nested exception handling of SErrors in EL3.
+ *
+ * This test exercises the path of EL3 nested exception handling of SErrors
+ * during SMC exception handling. In SMC exception handling vector path
+ * during synchronization of errors, a pending async EA is detected which
+ * gets handled in EL3 (as it is in FFH mode) as a nested exception. Original
+ * SMC call is handled after async EA is handled.
+ *
+ * This test works in conjunction with "ras_ffh_nested.patch"
+ * present in CI repository.
+ *
+ * Test steps:
+ *  1. TF-A is build for Firmware first handling for RAS errors.
+ *  2. Register/enable SDEI event notification for RAS error.
+ *  3. Make an SMC call to get the SMCCC version which will be used for
+ *     comparing later on, along with that it also changes SCR_EL3.EA=0 to
+ *     route SError to TFTF. This allow SError to be pended when next SMC
+ *     call is made.
+ *  4. Disable SError (PSTATE.A = 1)
+ *  5. Inject RAS error and give time for it to trigger.
+ *  6. At this point SError is pended (ISR_EL1 = 0x100)
+ *  7. Make SMC call to get the version
+ *  8. On entering EL3, sync_exception_vector entry, will find that SError is
+ *     pending.
+ *  9. Based on FFH routing model EL3 will call "handle_pending_async_ea" to
+ *     handle nested exception SError first.
+ *  10.RAS error will be handled by platform handler and be notified to TFTF
+ *     through SDEI handler.
+ *  12.Once the control returns back to vector entry of SMC, EL3 will continue
+ *     with original SMC request.
+ *
+ * Checks:
+ *  1. Ensure that we did recieve SDEI notification
+ *  2. Ensure that second SMC request was successful.
+ *
+ */
+test_result_t test_ras_ffh_nested(void)
+{
+	int64_t ret;
+	const int event_id = 5000;
+	smc_args args;
+	smc_ret_values smc_ret;
+	u_register_t expected_ver;
+
+        /* Register SDEI handler */
+        ret = sdei_event_register(event_id, serror_sdei_event_handler, 0,
+                        SDEI_REGF_RM_PE, read_mpidr_el1());
+        if (ret < 0) {
+                tftf_testcase_printf("SDEI event register failed: 0x%llx\n",
+                        ret);
+                return TEST_RESULT_FAIL;
+        }
+
+        ret = sdei_event_enable(event_id);
+        if (ret < 0) {
+                tftf_testcase_printf("SDEI event enable failed: 0x%llx\n", ret);
+                return TEST_RESULT_FAIL;
+        }
+
+        ret = sdei_pe_unmask();
+        if (ret < 0) {
+                tftf_testcase_printf("SDEI pe unmask failed: 0x%llx\n", ret);
+                return TEST_RESULT_FAIL;
+        }
+
+	/* Get the version to compare against */
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_VERSION;
+	smc_ret = tftf_smc(&args);
+	expected_ver = smc_ret.ret0;
+	smc_ret.ret0 = 0;
+
+	disable_serror();
+
+        inject_unrecoverable_ras_error();
+
+	waitms(50);
+
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_VERSION;
+
+	/* Ensure that we are testing reflection path, SMC before SError */
+	if (sdei_event_received == true) {
+		tftf_testcase_printf("SError was triggered before SMC\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	smc_ret = tftf_smc(&args);
+
+	tftf_testcase_printf("SMCCC Version = %d.%d\n",
+		(int)((smc_ret.ret0 >> SMCCC_VERSION_MAJOR_SHIFT) & SMCCC_VERSION_MAJOR_MASK),
+		(int)((smc_ret.ret0 >> SMCCC_VERSION_MINOR_SHIFT) & SMCCC_VERSION_MINOR_MASK));
+
+	if ((int32_t)smc_ret.ret0 != expected_ver) {
+		printf("Unexpected SMCCC version: 0x%x\n", (int)smc_ret.ret0);
+		return TEST_RESULT_FAIL;
+        }
+
+	if (sdei_event_received == false) {
+		tftf_testcase_printf("SError is not triggered\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+#else
+test_result_t test_ras_ffh_nested(void)
+{
+	tftf_testcase_printf("Not supported on AArch32.\n");
+	return TEST_RESULT_SKIPPED;
+}
+#endif
diff --git a/tftf/tests/misc_tests/test_ras_kfh_reflect.c b/tftf/tests/misc_tests/test_ras_kfh_reflect.c
new file mode 100644
index 0000000..d24fc47
--- /dev/null
+++ b/tftf/tests/misc_tests/test_ras_kfh_reflect.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <arch_helpers.h>
+#include <arm_arch_svc.h>
+#include <drivers/arm/arm_gic.h>
+#include <irq.h>
+#include <platform.h>
+#include <psci.h>
+#include <serror.h>
+#include <sgi.h>
+#include <smccc.h>
+#include <tftf_lib.h>
+
+#ifdef __aarch64__
+static volatile uint64_t serror_triggered;
+static volatile uint64_t irq_triggered;
+static u_register_t expected_ver;
+extern void inject_unrecoverable_ras_error(void);
+
+/*
+ * Tests to verify reflection of lower EL SErrors in RAS KFH mode.
+ *
+ * These tests exercises the path of EL3 reflection of SError back to lower
+ * EL, which gets triggered as part of error synchronization during EL3
+ * entry. This test works in conjunction with "ras_kfh_reflection.patch"
+ * present in CI repository.
+ *
+ * One test each to verify reflection in sync and async exception.
+ *
+ */
+static bool serror_handler(void)
+{
+	serror_triggered = 1;
+	tftf_testcase_printf("SError event received.\n");
+	return true;
+}
+
+static int irq_handler(void *data)
+{
+	irq_triggered = 1;
+	tftf_testcase_printf("IRQ received.\n");
+	return true;
+}
+
+/*
+ * Test Steps:
+ *  1. Register a custom SError handler for tftf
+ *  2. Make an SMC call to get the SMCCC version which will be used for
+ *     comparing later on, along with that it also changes SCR_EL3.I = 1
+ *     to route IRQ to EL3.
+ *  3. Disable SError (PSTATE.A = 1)
+ *  4. Inject RAS error and give time for it to trigger.
+ *  5. Register an SGI handler and inject SGI.
+ *  6. Becaue the IRQ is targeted to EL3 it will trap in EL3 irq_vector_entry
+ *  7. On entering EL3 it will find that SError is pending, So it will call
+ *     "reflect_pending_serror_to_lower_el" and eret.
+ *  8. TF-A will eret back from EL3(without handling IRQ) and during ERET
+ *     change SCR_EL3.I back to 0 along with unmasking SError for TFTF.
+ *     SPSR.PSTATE.A = 0.
+ *  9. At tftf entry it will see both IRQ and SError pending, so it can take
+ *     either of exception first (based on priority of SError/IRQ). The fvp model
+ *     on which it was tested, IRQ is taken first.
+ *  10.First IRQ handler will be called and then SError handler will called.
+ *
+ */
+test_result_t test_ras_kfh_reflect_irq(void)
+{
+	smc_args args;
+	unsigned int mpid = read_mpidr_el1();
+        unsigned int core_pos = platform_get_core_pos(mpid);
+        const unsigned int sgi_id = IRQ_NS_SGI_0;
+	smc_ret_values smc_ret;
+        int ret;
+
+	/* Get the SMCCC version to compare against */
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_VERSION;
+	smc_ret	= tftf_smc(&args);
+	expected_ver = smc_ret.ret0;
+
+	register_custom_serror_handler(serror_handler);
+	disable_serror();
+	inject_unrecoverable_ras_error();
+
+	waitms(50);
+
+	ret = tftf_irq_register_handler(sgi_id, irq_handler);
+	 if (ret != 0) {
+                tftf_testcase_printf("Failed to register initial IRQ handler\n");
+                return TEST_RESULT_FAIL;
+        }
+	tftf_irq_enable(sgi_id, GIC_HIGHEST_NS_PRIORITY);
+	tftf_send_sgi(sgi_id, core_pos);
+
+	if ((serror_triggered == false) || (irq_triggered == false)) {
+		tftf_testcase_printf("SError or IRQ is not triggered\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	ret = tftf_irq_unregister_handler(sgi_id);
+	if (ret != 0) {
+		tftf_testcase_printf("Failed to unregister IRQ handler\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	unregister_custom_serror_handler();
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Test Steps:
+ *  1. Register a custom SError handler for tftf
+ *  3. Disable SError (PSTATE.A = 1)
+ *  4. Inject RAS error and give time for it to trigger.
+ *  5. Ensure SError is not triggered before making SMC call.
+ *  7. On entering EL3 it will find that SError is pending, So it will call
+ *     "reflect_pending_serror_to_lower_el" and eret.
+ *  8. TF-A will eret back from EL3(without handling SMC) and during ERET
+ *     unmask SError for TFTF (SPSR.PSTATE.A = 0).
+ *  9 .At TFTF entry it will see an SError pending which will cause registered
+ *     SError handler to be called.
+ *  10.After retruning back from EL3 the original SMC request will be handled.
+ */
+test_result_t test_ras_kfh_reflect_sync(void)
+{
+	smc_args args;
+	smc_ret_values ret;
+
+	serror_triggered = 0;
+
+	register_custom_serror_handler(serror_handler);
+	disable_serror();
+	inject_unrecoverable_ras_error();
+
+	waitms(50);
+
+	/* Ensure that we are testing reflection path, SMC before SError */
+	if (serror_triggered == true) {
+		tftf_testcase_printf("SError was triggered before SMC\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_VERSION;
+	ret = tftf_smc(&args);
+	tftf_testcase_printf("SMCCC Version = %d.%d\n",
+		(int)((ret.ret0 >> SMCCC_VERSION_MAJOR_SHIFT) & SMCCC_VERSION_MAJOR_MASK),
+		(int)((ret.ret0 >> SMCCC_VERSION_MINOR_SHIFT) & SMCCC_VERSION_MINOR_MASK));
+
+	if ((int32_t)ret.ret0 != expected_ver) {
+		tftf_testcase_printf("Unexpected SMCCC version: 0x%x\n", (int)ret.ret0);
+		return TEST_RESULT_FAIL;
+        }
+
+	unregister_custom_serror_handler();
+
+	if (serror_triggered == false) {
+		tftf_testcase_printf("SError is not triggered\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+#else
+test_result_t test_ras_kfh_reflect_irq(void)
+{
+	tftf_testcase_printf("Not supported on AArch32.\n");
+	return TEST_RESULT_SKIPPED;
+}
+
+test_result_t test_ras_kfh_reflect_sync(void)
+{
+	tftf_testcase_printf("Not supported on AArch32.\n");
+	return TEST_RESULT_SKIPPED;
+}
+#endif
diff --git a/tftf/tests/tests-ras-ffh-nested.mk b/tftf/tests/tests-ras-ffh-nested.mk
new file mode 100644
index 0000000..1adcf80
--- /dev/null
+++ b/tftf/tests/tests-ras-ffh-nested.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES	+=	$(addprefix tftf/tests/misc_tests/,		\
+	inject_ras_error.S 						\
+	test_ras_ffh_nested.c						\
+)
diff --git a/tftf/tests/tests-ras-ffh-nested.xml b/tftf/tests/tests-ras-ffh-nested.xml
new file mode 100644
index 0000000..8dfb693
--- /dev/null
+++ b/tftf/tests/tests-ras-ffh-nested.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright (c) 2023, Arm Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+  <testsuite name="RAS FFH nested" description="RAS errors handled in EL3 as nested exception on top of SMC call">
+     <testcase name="Inject RAS error which gets handled as nested exception during SMC exception" function="test_ras_ffh_nested" />
+  </testsuite>
+</testsuites>
diff --git a/tftf/tests/tests-ras-kfh-reflect.mk b/tftf/tests/tests-ras-kfh-reflect.mk
new file mode 100644
index 0000000..bc8852f
--- /dev/null
+++ b/tftf/tests/tests-ras-kfh-reflect.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES	+=	$(addprefix tftf/tests/misc_tests/,		\
+	inject_ras_error.S 						\
+	test_ras_kfh_reflect.c							\
+)
diff --git a/tftf/tests/tests-ras-kfh-reflect.xml b/tftf/tests/tests-ras-kfh-reflect.xml
new file mode 100644
index 0000000..4150200
--- /dev/null
+++ b/tftf/tests/tests-ras-kfh-reflect.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright (c) 2023, Arm Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+  <testsuite name="RAS KFH Reflection" description="RAS errors reflected back from EL3">
+     <testcase name="Inject RAS error which gets reflected back during IRQ handling" function="test_ras_kfh_reflect_irq" />
+     <testcase name="Inject RAS error which gets reflected back during SMC call" function="test_ras_kfh_reflect_sync" />
+  </testsuite>
+</testsuites>