feat(cactus): validate NPI injection

Cactus SP can now handle the Notification Pending Interrupt:
- Added `npi_handled` array to track the CPUs that have handled the
NPI. The NPI handler will set the index of related to the respective
core.
- Extended and refactored cactus command CACTUS_NOTIFICATION_GET_CMD,
such that the sender can specify that the NPI is to be validated.

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I2d5728ec4fe2d14fb9ba6f0ba5230ef652467f85
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index 544dc15..3bb27ed 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -402,10 +402,10 @@
 
 static inline smc_ret_values cactus_notification_get_send_cmd(
 	ffa_id_t source, ffa_id_t dest, ffa_id_t receiver,
-	uint32_t vcpu_id, uint32_t flags)
+	uint32_t vcpu_id, uint32_t flags, bool check_npi_handled)
 {
 	return cactus_send_cmd(source, dest, CACTUS_NOTIFICATION_GET_CMD,
-			       receiver, vcpu_id, 0, flags);
+			       receiver, vcpu_id, check_npi_handled, flags);
 }
 
 static inline uint32_t cactus_notification_get_vcpu(smc_ret_values ret)
@@ -436,6 +436,11 @@
 	return (uint64_t)ret.ret5;
 }
 
+static inline bool cactus_notifications_check_npi_handled(smc_ret_values ret)
+{
+	return (bool)ret.ret6;
+}
+
 /**
  * Request SP to set notifications. The arguments to use in ffa_notification_set
  * are propagated on the command to test erroneous uses of the interface.
diff --git a/spm/cactus/cactus_interrupt.c b/spm/cactus/cactus_interrupt.c
index 31c6a69..ef3d5cc 100644
--- a/spm/cactus/cactus_interrupt.c
+++ b/spm/cactus/cactus_interrupt.c
@@ -16,6 +16,10 @@
 
 #include <platform_def.h>
 
+#define NOTIFICATION_PENDING_INTERRUPT_INTID 5
+
+extern void notification_pending_interrupt_handler(void);
+
 extern ffa_id_t g_ffa_id;
 
 void cactus_interrupt_handler(void)
@@ -43,6 +47,9 @@
 		spm_interrupt_deactivate(intid);
 
 		break;
+	case NOTIFICATION_PENDING_INTERRUPT_INTID:
+		notification_pending_interrupt_handler();
+		break;
 	default:
 		/*
 		 * Currently the only source of secure interrupt is Trusted
diff --git a/spm/cactus/cactus_tests/cactus_test_notifications.c b/spm/cactus/cactus_tests/cactus_test_notifications.c
index 01839c5..52c226b 100644
--- a/spm/cactus/cactus_tests/cactus_test_notifications.c
+++ b/spm/cactus/cactus_tests/cactus_test_notifications.c
@@ -7,8 +7,41 @@
 #include "cactus_message_loop.h"
 #include "cactus_test_cmds.h"
 #include "cactus_tests.h"
-#include <debug.h>
 #include <ffa_helpers.h>
+#include <debug.h>
+#include <platform.h>
+
+/* Booleans to keep track of which CPUs handled NPI. */
+static bool npi_handled[PLATFORM_CORE_COUNT];
+
+/**
+ * Helper to access the above array and set the boolean for the specific CPU.
+ */
+void set_npi_handled(uint32_t vcpu_id, bool val)
+{
+	npi_handled[vcpu_id] = val;
+}
+
+/**
+ * Helper to get state of the boolean from `npi_handled` from the respective
+ * CPU.
+ */
+bool get_npi_handled(uint32_t vcpu_id)
+{
+	return npi_handled[vcpu_id];
+}
+
+void notification_pending_interrupt_handler(void)
+{
+	/* Get which core it is running from. */
+	unsigned int core_pos = platform_get_core_pos(
+						read_mpidr_el1() & MPID_MASK);
+
+	VERBOSE("NPI handled in core %u\n", core_pos);
+
+	set_npi_handled(core_pos, true);
+}
+
 
 CACTUS_CMD_HANDLER(notifications_bind, CACTUS_NOTIFICATION_BIND_CMD)
 {
@@ -79,6 +112,19 @@
 		ffa_notifications_get_from_sp(ret),
 		ffa_notifications_get_from_vm(ret));
 
+	/* If requested to check the status of NPI, for the respective CPU. */
+	if (cactus_notifications_check_npi_handled(*args)) {
+
+		/* If NPI hasn't been handled return error for this test. */
+		if (!get_npi_handled(vcpu_id)) {
+			return cactus_error_resp(vm_id, source,
+						 CACTUS_ERROR_TEST);
+		}
+
+		/* Reset NPI flag for the respective core. */
+		set_npi_handled(vcpu_id, false);
+	}
+
 	return cactus_notifications_get_success_resp(
 		vm_id, source, ffa_notifications_get_from_sp(ret),
 		ffa_notifications_get_from_vm(ret));
@@ -88,7 +134,8 @@
 {
 	ffa_id_t source = ffa_dir_msg_source(*args);
 	ffa_id_t vm_id = ffa_dir_msg_dest(*args);
-	ffa_notification_bitmap_t notifications = cactus_notification_get_notifications(*args);
+	ffa_notification_bitmap_t notifications =
+				 cactus_notification_get_notifications(*args);
 	ffa_id_t receiver = cactus_notifications_set_get_receiver(*args);
 	ffa_id_t sender = cactus_notifications_set_get_sender(*args);
 	ffa_id_t echo_dest = cactus_req_echo_get_echo_dest(*args);
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
index 007a774..7cccaaf 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
@@ -411,7 +411,7 @@
 
 	*response = cactus_notification_get_send_cmd(HYP_ID, cmd_dest,
 						     receiver, vcpu_id,
-						     flags);
+						     flags, false);
 
 	return is_ffa_direct_response(*response);
 }