Handle VM availability messages

Add handling for the FF-A VM availability messages to libsp. Currently
this is only a skeleton implementation that calls an empty callback in
the SPs.

Signed-off-by: Balint Dobszay <balint.dobszay@arm.com>
Change-Id: I037f7a67121b7b02ceb1775baf4508abb9455fcd
diff --git a/components/messaging/ffa/libsp/ffa.c b/components/messaging/ffa/libsp/ffa.c
index 89fd8fe..76f0eda 100644
--- a/components/messaging/ffa/libsp/ffa.c
+++ b/components/messaging/ffa/libsp/ffa.c
@@ -238,6 +238,41 @@
 	return FFA_OK;
 }
 
+static void handle_framework_msg(struct ffa_params *result)
+{
+	if (result->a0 == FFA_INTERRUPT) {
+		ffa_interrupt_handler(result->a2);
+		ffa_return_from_interrupt(result);
+	} else if (result->a0 == FFA_MSG_SEND_DIRECT_REQ_32 && FFA_IS_FRAMEWORK_MSG(result->a2)) {
+		ffa_result res = FFA_OK;
+		uint16_t src_id = result->a1 >> 16;
+		uint16_t dst_id = result->a1;
+		uint64_t handle = reg_pair_to_64(result->a4, result->a3);
+		uint16_t vm_id = result->a5;
+
+		switch (result->a2 & FFA_FRAMEWORK_MSG_TYPE_MASK) {
+		case FFA_FRAMEWORK_MSG_VM_CREATED:
+			res = ffa_vm_created_handler(vm_id, handle);
+			ffa_svc(FFA_MSG_SEND_DIRECT_RESP_32, ((uint32_t)dst_id << 16) | src_id,
+				FFA_MSG_FLAG_FRAMEWORK | FFA_FRAMEWORK_MSG_VM_CREATED_ACK,
+				(uint64_t)res, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+				FFA_PARAM_MBZ, result);
+			break;
+		case FFA_FRAMEWORK_MSG_VM_DESTROYED:
+			res = ffa_vm_destroyed_handler(vm_id, handle);
+			ffa_svc(FFA_MSG_SEND_DIRECT_RESP_32, ((uint32_t)dst_id << 16) | src_id,
+				FFA_MSG_FLAG_FRAMEWORK | FFA_FRAMEWORK_MSG_VM_DESTROYED_ACK,
+				(uint64_t)res, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+				FFA_PARAM_MBZ, result);
+			break;
+		default:
+			ffa_svc(FFA_ERROR, FFA_PARAM_MBZ, FFA_INVALID_PARAMETERS, FFA_PARAM_MBZ,
+				FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ, result);
+			break;
+		}
+	}
+}
+
 ffa_result ffa_msg_wait(struct ffa_direct_msg *msg)
 {
 	struct ffa_params result = {0};
@@ -246,9 +281,10 @@
 		FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
 		&result);
 
-	while (result.a0 == FFA_INTERRUPT) {
-		ffa_interrupt_handler(result.a2);
-		ffa_return_from_interrupt(&result);
+	/* FF-A framework messages are handled outside of the main partition message handler loop */
+	while ((result.a0 == FFA_INTERRUPT) ||
+		(result.a0 == FFA_MSG_SEND_DIRECT_REQ_32 && FFA_IS_FRAMEWORK_MSG(result.a2))) {
+		handle_framework_msg(&result);
 	}
 
 	if (result.a0 == FFA_ERROR) {
@@ -325,9 +361,10 @@
 		SHIFT_U32(source, FFA_MSG_SEND_DIRECT_RESP_SOURCE_ID_SHIFT) |
 		dest, FFA_PARAM_MBZ, a0, a1, a2, a3, a4, &result);
 
-	while (result.a0 == FFA_INTERRUPT) {
-		ffa_interrupt_handler(result.a2);
-		ffa_return_from_interrupt(&result);
+	/* FF-A framework messages are handled outside of the main partition message handler loop */
+	while ((result.a0 == FFA_INTERRUPT) ||
+		(result.a0 == FFA_MSG_SEND_DIRECT_REQ_32 && FFA_IS_FRAMEWORK_MSG(result.a2))) {
+		handle_framework_msg(&result);
 	}
 
 	if (result.a0 == FFA_ERROR) {
diff --git a/components/messaging/ffa/libsp/include/ffa_api.h b/components/messaging/ffa/libsp/include/ffa_api.h
index 82541f7..2175d8f 100644
--- a/components/messaging/ffa/libsp/include/ffa_api.h
+++ b/components/messaging/ffa/libsp/include/ffa_api.h
@@ -412,6 +412,28 @@
  */
 void ffa_interrupt_handler(uint32_t interrupt_id);
 
+/**
+ * @brief      VM created message handler prototype. Must be implemented by
+ *             another component.
+ *
+ * @param[in]  vm_id  ID of VM that has been created
+ * @param[in]  handle Globally unique Handle to identify a memory region that
+ *                    contains information associated with the created VM
+ * @return            The FF-A error status code
+ */
+ffa_result ffa_vm_created_handler(uint16_t vm_id, uint64_t handle);
+
+/**
+ * @brief      VM destroyed message handler prototype. Must be implemented by
+ *             another component.
+ *
+ * @param[in]  vm_id  ID of VM that has been destroyed
+ * @param[in]  handle Globally unique Handle to identify a memory region that
+ *                    contains information associated with the destroyed VM
+ * @return            The FF-A error status code
+ */
+ffa_result ffa_vm_destroyed_handler(uint16_t vm_id, uint64_t handle);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/components/messaging/ffa/libsp/include/ffa_api_defines.h b/components/messaging/ffa/libsp/include/ffa_api_defines.h
index a007749..23389a5 100644
--- a/components/messaging/ffa/libsp/include/ffa_api_defines.h
+++ b/components/messaging/ffa/libsp/include/ffa_api_defines.h
@@ -195,6 +195,17 @@
 #define FFA_MSG_SEND_DIRECT_RESP_DEST_ID_MASK		GENMASK_32(15, 0)
 #define FFA_MSG_SEND_DIRECT_RESP_DEST_ID_SHIFT		UINT32_C(0)
 
+/* FF-A direct message flags */
+#define FFA_MSG_FLAG_FRAMEWORK				BIT32(31)
+#define FFA_FRAMEWORK_MSG_TYPE_SHIFT			UINT32_C(0)
+#define FFA_FRAMEWORK_MSG_TYPE_MASK			GENMASK_32(7, 0)
+#define FFA_FRAMEWORK_MSG_PSCI				UINT32_C(0x0)
+#define FFA_FRAMEWORK_MSG_VM_CREATED			UINT32_C(0x4)
+#define FFA_FRAMEWORK_MSG_VM_CREATED_ACK		UINT32_C(0x5)
+#define FFA_FRAMEWORK_MSG_VM_DESTROYED			UINT32_C(0x6)
+#define FFA_FRAMEWORK_MSG_VM_DESTROYED_ACK		UINT32_C(0x7)
+#define FFA_IS_FRAMEWORK_MSG(x)				(((x) & FFA_MSG_FLAG_FRAMEWORK) != 0)
+
 /* Table 5.15: Memory access permissions descriptor */
 
 /* Memory access permissions */
diff --git a/components/messaging/ffa/libsp/test/test_ffa_api.cpp b/components/messaging/ffa/libsp/test/test_ffa_api.cpp
index 3c51e60..9660599 100644
--- a/components/messaging/ffa/libsp/test/test_ffa_api.cpp
+++ b/components/messaging/ffa/libsp/test/test_ffa_api.cpp
@@ -23,6 +23,38 @@
 		.withUnsignedIntParameter("id", id);
 }
 
+void expect_ffa_vm_created_handler(uint16_t vm_id, uint64_t handle, ffa_result result)
+{
+	mock().expectOneCall("ffa_vm_created_handler")
+		.withUnsignedIntParameter("vm_id", vm_id)
+		.withUnsignedLongIntParameter("handle", handle)
+		.andReturnValue(result);
+}
+
+ffa_result ffa_vm_created_handler(uint16_t vm_id, uint64_t handle)
+{
+	return mock().actualCall("ffa_vm_created_handler")
+		.withUnsignedIntParameter("vm_id", vm_id)
+		.withUnsignedLongIntParameter("handle", handle)
+		.returnIntValue();
+}
+
+void expect_ffa_vm_destroyed_handler(uint16_t vm_id, uint64_t handle, ffa_result result)
+{
+	mock().expectOneCall("ffa_vm_destroyed_handler")
+		.withUnsignedIntParameter("vm_id", vm_id)
+		.withUnsignedLongIntParameter("handle", handle)
+		.andReturnValue(result);
+}
+
+ffa_result ffa_vm_destroyed_handler(uint16_t vm_id, uint64_t handle)
+{
+	return mock().actualCall("ffa_vm_destroyed_handler")
+		.withUnsignedIntParameter("vm_id", vm_id)
+		.withUnsignedLongIntParameter("handle", handle)
+		.returnIntValue();
+}
+
 TEST_GROUP(ffa_api)
 {
 	TEST_SETUP()
@@ -551,6 +583,157 @@
 	msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
 }
 
+TEST(ffa_api, ffa_msg_wait_vm_created_success)
+{
+	const uint16_t source_id = 0;
+	const uint16_t dest_id = 0x8001;
+	const uint16_t vm_id = 0x1234;
+	const uint64_t handle = 0x0123456789abcdefULL;
+	const uint32_t handle_hi = 0x01234567;
+	const uint32_t handle_lo = 0x89abcdef;
+	struct ffa_params vm_created_msg;
+
+	vm_created_msg.a0 = 0x8400006F;
+	vm_created_msg.a1 = ((uint32_t)source_id << 16) | dest_id;
+	vm_created_msg.a2 = FFA_MSG_FLAG_FRAMEWORK |
+			(FFA_FRAMEWORK_MSG_VM_CREATED << FFA_FRAMEWORK_MSG_TYPE_SHIFT);
+	vm_created_msg.a3 = handle_lo;
+	vm_created_msg.a4 = handle_hi;
+	vm_created_msg.a5 = vm_id;
+	expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &vm_created_msg);
+	expect_ffa_vm_created_handler(vm_id, handle, FFA_OK);
+
+	svc_result.a0 = 0x84000061;
+	expect_ffa_svc(0x84000070, ((uint32_t)dest_id) << 16 | source_id, FFA_MSG_FLAG_FRAMEWORK |
+		       (FFA_FRAMEWORK_MSG_VM_CREATED_ACK << FFA_FRAMEWORK_MSG_TYPE_SHIFT), 0, 0,
+		       0, 0, 0, &svc_result);
+
+	ffa_result result = ffa_msg_wait(&msg);
+	LONGS_EQUAL(0, result);
+	msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+}
+
+TEST(ffa_api, ffa_msg_wait_vm_destroyed_success)
+{
+	const uint16_t source_id = 0;
+	const uint16_t dest_id = 0x8001;
+	const uint16_t vm_id = 0x1234;
+	const uint64_t handle = 0x0123456789abcdefULL;
+	const uint32_t handle_hi = 0x01234567;
+	const uint32_t handle_lo = 0x89abcdef;
+	struct ffa_params vm_destroyed_msg;
+
+	vm_destroyed_msg.a0 = 0x8400006F;
+	vm_destroyed_msg.a1 = ((uint32_t)source_id << 16) | dest_id;
+	vm_destroyed_msg.a2 = FFA_MSG_FLAG_FRAMEWORK |
+			(FFA_FRAMEWORK_MSG_VM_DESTROYED << FFA_FRAMEWORK_MSG_TYPE_SHIFT);
+	vm_destroyed_msg.a3 = handle_lo;
+	vm_destroyed_msg.a4 = handle_hi;
+	vm_destroyed_msg.a5 = vm_id;
+	expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &vm_destroyed_msg);
+	expect_ffa_vm_destroyed_handler(vm_id, handle, FFA_OK);
+
+	svc_result.a0 = 0x84000061;
+	expect_ffa_svc(0x84000070, ((uint32_t)dest_id) << 16 | source_id, FFA_MSG_FLAG_FRAMEWORK |
+		       (FFA_FRAMEWORK_MSG_VM_DESTROYED_ACK << FFA_FRAMEWORK_MSG_TYPE_SHIFT), 0, 0,
+		       0, 0, 0, &svc_result);
+
+	ffa_result result = ffa_msg_wait(&msg);
+	LONGS_EQUAL(0, result);
+	msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+}
+
+TEST(ffa_api, ffa_msg_wait_vm_created_destroyed_success)
+{
+	const uint16_t source_id = 0;
+	const uint16_t dest_id = 0x8001;
+	const uint16_t vm_id = 0x1234;
+	const uint64_t handle = 0x0123456789abcdefULL;
+	const uint32_t handle_hi = 0x01234567;
+	const uint32_t handle_lo = 0x89abcdef;
+	struct ffa_params vm_created_msg;
+	struct ffa_params vm_destroyed_msg;
+
+	vm_created_msg.a0 = 0x8400006F;
+	vm_created_msg.a1 = ((uint32_t)source_id << 16) | dest_id;
+	vm_created_msg.a2 = FFA_MSG_FLAG_FRAMEWORK |
+			(FFA_FRAMEWORK_MSG_VM_CREATED << FFA_FRAMEWORK_MSG_TYPE_SHIFT);
+	vm_created_msg.a3 = handle_lo;
+	vm_created_msg.a4 = handle_hi;
+	vm_created_msg.a5 = vm_id;
+	expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &vm_created_msg);
+	expect_ffa_vm_created_handler(vm_id, handle, FFA_OK);
+
+	vm_destroyed_msg.a0 = 0x8400006F;
+	vm_destroyed_msg.a1 = ((uint32_t)source_id << 16) | dest_id;
+	vm_destroyed_msg.a2 = FFA_MSG_FLAG_FRAMEWORK |
+			(FFA_FRAMEWORK_MSG_VM_DESTROYED << FFA_FRAMEWORK_MSG_TYPE_SHIFT);
+	vm_destroyed_msg.a3 = handle_lo;
+	vm_destroyed_msg.a4 = handle_hi;
+	vm_destroyed_msg.a5 = vm_id;
+	expect_ffa_svc(0x84000070, ((uint32_t)dest_id) << 16 | source_id, FFA_MSG_FLAG_FRAMEWORK |
+		       (FFA_FRAMEWORK_MSG_VM_CREATED_ACK << FFA_FRAMEWORK_MSG_TYPE_SHIFT), 0, 0,
+		       0, 0, 0, &vm_destroyed_msg);
+	expect_ffa_vm_destroyed_handler(vm_id, handle, FFA_OK);
+
+	svc_result.a0 = 0x84000061;
+	expect_ffa_svc(0x84000070, ((uint32_t)dest_id) << 16 | source_id, FFA_MSG_FLAG_FRAMEWORK |
+		       (FFA_FRAMEWORK_MSG_VM_DESTROYED_ACK << FFA_FRAMEWORK_MSG_TYPE_SHIFT), 0, 0,
+		       0, 0, 0, &svc_result);
+	ffa_result result = ffa_msg_wait(&msg);
+	LONGS_EQUAL(0, result);
+	msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+}
+
+TEST(ffa_api, ffa_msg_wait_vm_created_interrupt_destroyed_success)
+{
+	const uint16_t source_id = 0;
+	const uint16_t dest_id = 0x8001;
+	const uint16_t vm_id = 0x1234;
+	const uint64_t handle = 0x0123456789abcdefULL;
+	const uint32_t handle_hi = 0x01234567;
+	const uint32_t handle_lo = 0x89abcdef;
+	const uint32_t interrupt_id = 0x12345678;
+	struct ffa_params vm_created_msg;
+	struct ffa_params vm_destroyed_msg;
+	struct ffa_params interrupt_params;
+
+	vm_created_msg.a0 = 0x8400006F;
+	vm_created_msg.a1 = ((uint32_t)source_id << 16) | dest_id;
+	vm_created_msg.a2 = FFA_MSG_FLAG_FRAMEWORK |
+			(FFA_FRAMEWORK_MSG_VM_CREATED << FFA_FRAMEWORK_MSG_TYPE_SHIFT);
+	vm_created_msg.a3 = handle_lo;
+	vm_created_msg.a4 = handle_hi;
+	vm_created_msg.a5 = vm_id;
+	expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &vm_created_msg);
+	expect_ffa_vm_created_handler(vm_id, handle, FFA_OK);
+
+	interrupt_params.a0 = 0x84000062;
+	interrupt_params.a2 = interrupt_id;
+	expect_ffa_svc(0x84000070, ((uint32_t)dest_id) << 16 | source_id, FFA_MSG_FLAG_FRAMEWORK |
+		       (FFA_FRAMEWORK_MSG_VM_CREATED_ACK << FFA_FRAMEWORK_MSG_TYPE_SHIFT), 0, 0,
+		       0, 0, 0, &interrupt_params);
+	expect_ffa_interrupt_handler(interrupt_id);
+
+	vm_destroyed_msg.a0 = 0x8400006F;
+	vm_destroyed_msg.a1 = ((uint32_t)source_id << 16) | dest_id;
+	vm_destroyed_msg.a2 = FFA_MSG_FLAG_FRAMEWORK |
+			(FFA_FRAMEWORK_MSG_VM_DESTROYED << FFA_FRAMEWORK_MSG_TYPE_SHIFT);
+	vm_destroyed_msg.a3 = handle_lo;
+	vm_destroyed_msg.a4 = handle_hi;
+	vm_destroyed_msg.a5 = vm_id;
+	expect_ffa_svc(0x8400006B, 0, 0, 0, 0, 0, 0, 0, &vm_destroyed_msg);
+	expect_ffa_vm_destroyed_handler(vm_id, handle, FFA_OK);
+
+	svc_result.a0 = 0x84000061;
+	expect_ffa_svc(0x84000070, ((uint32_t)dest_id) << 16 | source_id, FFA_MSG_FLAG_FRAMEWORK |
+		       (FFA_FRAMEWORK_MSG_VM_DESTROYED_ACK << FFA_FRAMEWORK_MSG_TYPE_SHIFT), 0, 0,
+		       0, 0, 0, &svc_result);
+	ffa_result result = ffa_msg_wait(&msg);
+	LONGS_EQUAL(0, result);
+	msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+}
+
 TEST(ffa_api, ffa_msg_wait_unknown_response)
 {
 	assert_environment_t assert_env;
@@ -1046,6 +1229,43 @@
 	msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
 }
 
+TEST(ffa_api, ffa_msg_send_direct_resp_32_vm_created_success)
+{
+	const uint16_t source_id = 0x1122;
+	const uint16_t dest_id = 0x3344;
+	const uint16_t nwd_id = 0;
+	const uint32_t arg0 = 0x01234567ULL;
+	const uint32_t arg1 = 0x12345678ULL;
+	const uint32_t arg2 = 0x23456789ULL;
+	const uint32_t arg3 = 0x3456789aULL;
+	const uint32_t arg4 = 0x456789abULL;
+	const uint16_t vm_id = 0x1234;
+	const uint64_t handle = 0x0123456789abcdefULL;
+	const uint32_t handle_hi = 0x01234567;
+	const uint32_t handle_lo = 0x89abcdef;
+	struct ffa_params vm_created_msg;
+
+	vm_created_msg.a0 = 0x8400006F;
+	vm_created_msg.a1 = ((uint32_t)nwd_id << 16) | source_id;
+	vm_created_msg.a2 = FFA_MSG_FLAG_FRAMEWORK |
+			(FFA_FRAMEWORK_MSG_VM_CREATED << FFA_FRAMEWORK_MSG_TYPE_SHIFT);
+	vm_created_msg.a3 = handle_lo;
+	vm_created_msg.a4 = handle_hi;
+	vm_created_msg.a5 = vm_id;
+	expect_ffa_svc(0x84000070, ((uint32_t)source_id << 16) | dest_id, 0,
+		       arg0, arg1, arg2, arg3, arg4, &vm_created_msg);
+	expect_ffa_vm_created_handler(vm_id, handle, FFA_OK);
+
+	svc_result.a0 = 0x84000061;
+	expect_ffa_svc(0x84000070, ((uint32_t)source_id) << 16 | nwd_id, FFA_MSG_FLAG_FRAMEWORK |
+		       (FFA_FRAMEWORK_MSG_VM_CREATED_ACK << FFA_FRAMEWORK_MSG_TYPE_SHIFT), 0, 0,
+		       0, 0, 0, &svc_result);
+	ffa_result result = ffa_msg_send_direct_resp_32(
+		source_id, dest_id, arg0, arg1, arg2, arg3, arg4, &msg);
+	LONGS_EQUAL(0, result);
+	msg_equal_32(0x84000061, 0, 0, 0, 0, 0, 0, 0);
+}
+
 TEST(ffa_api, ffa_msg_send_direct_resp_32_unknown_response)
 {
 	const uint16_t source_id = 0x1122;