test(ff-a): bind and unbind notifications

Added tests to FFA_NOTIFICATION_BIND and FFA_NOTIFICATION_UNBIND calls:
- Cactus is requested to perform bind and unbind operations, using
test commands from previous commits.
- Use both calls in TFTF, to test use from VMs.

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I970882a8f5de960e661f1c7fba01fc4870d8c40f
diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h
index 621b000..df19f98 100644
--- a/include/runtime_services/ffa_svc.h
+++ b/include/runtime_services/ffa_svc.h
@@ -133,6 +133,8 @@
 	FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BITMAP_DESTROY)
 #define FFA_NOTIFICATION_BIND	FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BIND)
 #define FFA_NOTIFICATION_UNBIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_UNBIND)
+#define FFA_NOTIFICATION_SET	FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_SET)
+#define FFA_NOTIFICATION_GET	FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_GET)
 #define FFA_SPM_ID_GET		FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET)
 
 /* FFA SMC64 FIDs */
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 fb71f48..bc7e32b 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
@@ -15,6 +15,16 @@
 #include <spm_common.h>
 #include <test_helpers.h>
 
+static const struct ffa_uuid expected_sp_uuids[] = {
+		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+};
+
+static ffa_notification_bitmap_t g_notifications = FFA_NOTIFICATION(0)  |
+						   FFA_NOTIFICATION(1)  |
+						   FFA_NOTIFICATION(30) |
+						   FFA_NOTIFICATION(50) |
+						   FFA_NOTIFICATION(63);
+
 /**
  * Helper to create bitmap for NWd VMs.
  */
@@ -120,3 +130,235 @@
 
 	return TEST_RESULT_SUCCESS;
 }
+
+/**
+ * Helper function to test FFA_NOTIFICATION_BIND interface.
+ * Receives all arguments to use 'cactus_notification_bind_send_cmd', and
+ * expected response for the test command.
+ *
+ * Returns:
+ * - 'true' if response was obtained and it was as expected;
+ * - 'false' if there was an error with use of FFA_MSG_SEND_DIRECT_REQ, or
+ * the obtained response was not as expected.
+ */
+static bool request_notification_bind(
+	ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender,
+	ffa_notification_bitmap_t notifications, uint32_t flags,
+	uint32_t expected_resp, uint32_t error_code)
+{
+	smc_ret_values ret;
+
+	VERBOSE("TFTF requesting SP to bind notifications!\n");
+
+	ret = cactus_notification_bind_send_cmd(HYP_ID, cmd_dest, receiver,
+						sender, notifications, flags);
+
+	return is_expected_cactus_response(ret, expected_resp, error_code);
+}
+
+/**
+ * Helper function to test FFA_NOTIFICATION_UNBIND interface.
+ * Receives all arguments to use 'cactus_notification_unbind_send_cmd', and
+ * expected response for the test command.
+ *
+ * Returns:
+ * - 'true' if response was obtained and it was as expected;
+ * - 'false' if there was an error with use of FFA_MSG_SEND_DIRECT_REQ, or
+ * the obtained response was not as expected.
+ */
+static bool request_notification_unbind(
+	ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender,
+	ffa_notification_bitmap_t notifications, uint32_t expected_resp,
+	uint32_t error_code)
+{
+	smc_ret_values ret;
+
+	VERBOSE("TFTF requesting SP to unbind notifications!\n");
+
+	ret = cactus_notification_unbind_send_cmd(HYP_ID, cmd_dest, receiver,
+						  sender, notifications);
+
+	return is_expected_cactus_response(ret, expected_resp, error_code);
+}
+
+/**
+ * Test calls from SPs to the bind and unbind interfaces, expecting success
+ * returns.
+ * This test issues a request via direct messaging to the SP, which executes
+ * the test and responds with the result of the call.
+ */
+test_result_t test_ffa_notifications_sp_bind_unbind(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+	/** First bind... */
+	if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+				       g_notifications, 0, CACTUS_SUCCESS, 0)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	if (!request_notification_bind(SP_ID(1), SP_ID(1), 1,
+				       g_notifications, 0, CACTUS_SUCCESS, 0)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	/** ... then unbind using the same arguments. */
+	if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+					 g_notifications, CACTUS_SUCCESS, 0)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	if (!request_notification_unbind(SP_ID(1), SP_ID(1), 1,
+					 g_notifications, CACTUS_SUCCESS, 0)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test successful attempt of doing bind and unbind of the same set of
+ * notifications.
+ */
+test_result_t test_ffa_notifications_vm_bind_unbind(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+	const ffa_id_t vm_id = 1;
+	smc_ret_values ret;
+
+	if (!notifications_bitmap_create(vm_id, 1)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	ret = ffa_notification_bind(SP_ID(2), vm_id, 0, g_notifications);
+
+	if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	ret = ffa_notification_unbind(SP_ID(2), vm_id, g_notifications);
+
+	if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	if (!notifications_bitmap_destroy(vm_id)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test expected failure of using a NS FF-A ID for the sender.
+ */
+test_result_t test_ffa_notifications_vm_bind_vm(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+	const ffa_id_t vm_id = 1;
+	const ffa_id_t sender_id = 2;
+	smc_ret_values ret;
+
+	if (!notifications_bitmap_create(vm_id, 1)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	ret = ffa_notification_bind(sender_id, vm_id, 0, g_notifications);
+
+	if (!is_expected_ffa_error(ret, FFA_ERROR_INVALID_PARAMETER)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	if (!notifications_bitmap_destroy(vm_id)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test failure of both bind and unbind in case at least one notification is
+ * already bound to another FF-A endpoint.
+ * Expect error code FFA_ERROR_DENIED.
+ */
+test_result_t test_ffa_notifications_already_bound(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+	/** Bind first to test */
+	if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+				       g_notifications, 0, CACTUS_SUCCESS, 0)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	/** Attempt to bind notifications bound in above request. */
+	if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(3),
+				       g_notifications, 0, CACTUS_ERROR,
+				       FFA_ERROR_DENIED)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	/** Attempt to unbind notifications bound in initial request. */
+	if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(3),
+					 g_notifications, CACTUS_ERROR,
+					 FFA_ERROR_DENIED)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	/** Reset the state the SP's notifications state. */
+	if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+					 g_notifications, CACTUS_SUCCESS, 0)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Try to bind/unbind notifications spoofing the identity of the receiver.
+ * Commands will be sent to SP_ID(1), which will use SP_ID(3) as the receiver.
+ * Expect error code FFA_ERROR_INVALID_PARAMETER.
+ */
+test_result_t test_ffa_notifications_bind_unbind_spoofing(void)
+{
+	ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(8);
+
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+	if (!request_notification_bind(SP_ID(1), SP_ID(3), SP_ID(2),
+				       notifications, 0, CACTUS_ERROR,
+				       FFA_ERROR_INVALID_PARAMETER)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	if (!request_notification_unbind(SP_ID(1), SP_ID(3), SP_ID(2),
+					 notifications, CACTUS_ERROR,
+					 FFA_ERROR_INVALID_PARAMETER)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Call FFA_NOTIFICATION_BIND with notifications bitmap zeroed.
+ * Expecting error code FFA_ERROR_INVALID_PARAMETER.
+ */
+test_result_t test_ffa_notifications_bind_unbind_zeroed(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+	if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+				       0, 0, CACTUS_ERROR,
+				       FFA_ERROR_INVALID_PARAMETER)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+					 0, CACTUS_ERROR,
+					 FFA_ERROR_INVALID_PARAMETER)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 9746599..d5634d3 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -108,6 +108,18 @@
                function="test_ffa_notifications_destroy_not_created" />
      <testcase name="Notifications bitmap create after create"
                function="test_ffa_notifications_create_after_create" />
+     <testcase name="SP Notifications bind and unbind"
+               function="test_ffa_notifications_sp_bind_unbind" />
+     <testcase name="VM Notifications bind and unbind"
+               function="test_ffa_notifications_vm_bind_unbind" />
+     <testcase name="VM Notifications bind NS Sender"
+               function="test_ffa_notifications_vm_bind_vm" />
+     <testcase name="Notifications bind/unbind of bound Notifications"
+               function="test_ffa_notifications_already_bound" />
+     <testcase name="Notifications bind/unbind SPs spoofing receiver"
+               function="test_ffa_notifications_bind_unbind_spoofing" />
+     <testcase name="Notifications zeroed in bind and unbind"
+               function="test_ffa_notifications_bind_unbind_zeroed" />
   </testsuite>
 
 </testsuites>