feat: introduce UNDEF injection test

Test to verify UNDEF injection support in TF-A by trapping FGT register
access from tftf into EL3.

To trap FGT register access to EL3, run the test on model with FEAT_FGT
present but the traps from EL3 are not enabled (ENABLE_FEAT_FGT = 0).

Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
Change-Id: Ic58ef797c64aad6d17ea33d9fc34e14b4e1a7055
diff --git a/tftf/tests/misc_tests/test_undef_injection.c b/tftf/tests/misc_tests/test_undef_injection.c
new file mode 100644
index 0000000..2d925a2
--- /dev/null
+++ b/tftf/tests/misc_tests/test_undef_injection.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arm_arch_svc.h>
+#include <assert.h>
+#include <debug.h>
+#include <smccc.h>
+#include <sync.h>
+#include <tftf_lib.h>
+#include <platform_def.h>
+
+static volatile bool undef_injection_triggered;
+
+static bool undef_injection_handler(void)
+{
+	uint64_t esr_el2 = read_esr_el2();
+	if (EC_BITS(esr_el2) == EC_UNKNOWN) {
+		VERBOSE("UNDEF injection from EL3\n");
+		undef_injection_triggered = true;
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * Test to verify UNDEF injection support in TF-A
+ *
+ * This test tries to access FGT EL2 registers which traps to EL3 and then
+ * the error is injected back from EL3 to TFTF to ensure that injection
+ * logic in TF-A is working, it also ensures that EL3 is still functional
+ * after UNDEF injection.
+ *
+ * To trap FGT register access to EL3, we run this test on a model with
+ * FEAT_FGT present but the traps from EL3 are not disabled by setting
+ * ENABLE_FEAT_FGT = 0
+ */
+test_result_t test_undef_injection(void)
+{
+	undef_injection_triggered = false;
+
+	register_custom_sync_exception_handler(undef_injection_handler);
+
+	/* Try to access a register which traps to EL3 */
+	read_hfgitr_el2();
+
+	unregister_custom_sync_exception_handler();
+
+	/* Ensure that EL3 still functional */
+	smc_args args;
+	smc_ret_values smc_ret;
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_VERSION;
+	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 (undef_injection_triggered == false) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-undef-injection.mk b/tftf/tests/tests-undef-injection.mk
new file mode 100644
index 0000000..e13df17
--- /dev/null
+++ b/tftf/tests/tests-undef-injection.mk
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES	+=	tftf/tests/misc_tests/test_undef_injection.c
diff --git a/tftf/tests/tests-undef-injection.xml b/tftf/tests/tests-undef-injection.xml
new file mode 100644
index 0000000..0d43cdf
--- /dev/null
+++ b/tftf/tests/tests-undef-injection.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="UNDEF Injection" description="UNDEF injection from EL3 to lower EL">
+      <testcase name="UNDEF Injection to lower EL"
+                function="test_undef_injection" />
+  </testsuite>
+</testsuites>