fix(ff-a): use messaging info from the manifest

Adds a messaging method to the VM structure. Refactor messaging info
field in the manifest to comply with information in specification. In
particular - distinguish between the direct message send/receive.
Use messaging method from the manifest to populate partition info for
FFA_PARTITION_INFO_GET ABI. Populates partition info based on the
caller id (SP can send direct messages to other SPs).
Refactors managed exit check to use messaging method value.

Signed-off-by: Maksims Svecovs <maksims.svecovs@arm.com>
Change-Id: Id0734c18d14879b89ba3517b8ff4b3b41b53b56f
diff --git a/src/api.c b/src/api.c
index 250c78d..6679c7e 100644
--- a/src/api.c
+++ b/src/api.c
@@ -228,7 +228,7 @@
  */
 static bool api_ffa_is_managed_exit_ongoing(struct vcpu_locked vcpu_locked)
 {
-	return (vcpu_locked.vcpu->vm->supports_managed_exit &&
+	return (vm_managed_exit_supported(vcpu_locked.vcpu->vm) &&
 		vcpu_locked.vcpu->processing_managed_exit);
 }
 
@@ -375,7 +375,8 @@
 			partitions[vm_count].vm_id = vm->id;
 			partitions[vm_count].vcpu_count = vm->vcpu_count;
 			partitions[vm_count].properties =
-				arch_vm_partition_properties(vm->id);
+				plat_ffa_partition_properties(current_vm->id,
+							      vm);
 
 			++vm_count;
 		}
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 414167f..dcfb507 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -920,7 +920,7 @@
 	struct vcpu *current_vcpu = current();
 	int ret;
 
-	if (current_vcpu->vm->supports_managed_exit) {
+	if (vm_managed_exit_supported(current_vcpu->vm)) {
 		/* Mask all interrupts */
 		plat_interrupts_set_priority_mask(0x0);
 
diff --git a/src/arch/aarch64/hypervisor/vm.c b/src/arch/aarch64/hypervisor/vm.c
index bd9c222..5f7f4db 100644
--- a/src/arch/aarch64/hypervisor/vm.c
+++ b/src/arch/aarch64/hypervisor/vm.c
@@ -50,24 +50,3 @@
 		vm->arch.trapped_features |= HF_FEATURE_PAUTH;
 	}
 }
-
-ffa_partition_properties_t arch_vm_partition_properties(ffa_vm_id_t id)
-{
-#if SECURE_WORLD == 0
-	/*
-	 * VMs supports indirect messaging.
-	 * PVM supports sending direct messages.
-	 * Secondary VMs support receiving direct messages.
-	 */
-	return FFA_PARTITION_INDIRECT_MSG | (id == HF_PRIMARY_VM_ID)
-		       ? FFA_PARTITION_DIRECT_SEND
-		       : FFA_PARTITION_DIRECT_RECV;
-#else
-	(void)id;
-
-	/*
-	 * SPs only support receiving direct messages.
-	 */
-	return FFA_PARTITION_DIRECT_RECV;
-#endif
-}
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 141e97e..f33d5e9 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -7,9 +7,18 @@
  */
 
 #include "hf/ffa.h"
+#include "hf/vm.h"
 
 struct ffa_value plat_ffa_spmc_id_get(void)
 {
 	return (struct ffa_value){.func = FFA_ERROR_32,
 				  .arg2 = FFA_NOT_SUPPORTED};
 }
+
+ffa_partition_properties_t plat_ffa_partition_properties(
+	ffa_vm_id_t current_id, const struct vm *target)
+{
+	(void)current_id;
+	(void)target;
+	return 0;
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 9bdf0ab..825c080 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -7,6 +7,7 @@
  */
 
 #include "hf/ffa.h"
+#include "hf/vm.h"
 
 #include "smc.h"
 
@@ -15,3 +16,24 @@
 	/* Fetch the SPMC ID from the SPMD using FFA_SPM_ID_GET. */
 	return smc_ffa_call((struct ffa_value){.func = FFA_SPM_ID_GET_32});
 }
+
+ffa_partition_properties_t plat_ffa_partition_properties(
+	ffa_vm_id_t vm_id, const struct vm *target)
+{
+	ffa_partition_properties_t result =
+		target->messaging_method | ~FFA_PARTITION_MANAGED_EXIT;
+	/*
+	 * VMs support indirect messaging only in the Normal World.
+	 * Primary VM cannot receive direct requests.
+	 * Secondary VMs cannot send direct requests.
+	 */
+	if (!vm_id_is_current_world(vm_id)) {
+		result &= ~FFA_PARTITION_INDIRECT_MSG;
+	}
+	if (target->id == HF_PRIMARY_VM_ID) {
+		result &= ~FFA_PARTITION_DIRECT_REQ_RECV;
+	} else {
+		result &= ~FFA_PARTITION_DIRECT_REQ_SEND;
+	}
+	return result;
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index fae06f1..9861663 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -102,3 +102,20 @@
 	return (handle & FFA_MEMORY_HANDLE_ALLOCATOR_MASK) ==
 	       FFA_MEMORY_HANDLE_ALLOCATOR_SPMC;
 }
+
+ffa_partition_properties_t plat_ffa_partition_properties(
+	ffa_vm_id_t vm_id, const struct vm *target)
+{
+	ffa_partition_properties_t result =
+		(target->messaging_method | ~(FFA_PARTITION_MANAGED_EXIT));
+	/*
+	 * SPs support full direct messaging communication with other SPs,
+	 * and are allowed to only receive direct requests from the other world.
+	 * SPs cannot send direct requests to the other world.
+	 */
+	if (vm_id_is_current_world(vm_id)) {
+		return result & (FFA_PARTITION_DIRECT_REQ_RECV |
+				 FFA_PARTITION_DIRECT_REQ_SEND);
+	}
+	return result & FFA_PARTITION_DIRECT_REQ_RECV;
+}
diff --git a/src/arch/fake/hypervisor/BUILD.gn b/src/arch/fake/hypervisor/BUILD.gn
index cd0db5f..a845532 100644
--- a/src/arch/fake/hypervisor/BUILD.gn
+++ b/src/arch/fake/hypervisor/BUILD.gn
@@ -8,7 +8,6 @@
   sources = [
     "cpu.c",
     "ffa.c",
-    "vm.c",
   ]
   deps = [
     "//src/arch/fake:arch",
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index cacc1b2..5cf3d28 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -62,3 +62,11 @@
 	(void)handle;
 	return false;
 }
+
+ffa_partition_properties_t plat_ffa_partition_properties(
+	ffa_vm_id_t current_id, const struct vm *target)
+{
+	(void)current_id;
+	(void)target;
+	return 0;
+}
diff --git a/src/arch/fake/hypervisor/vm.c b/src/arch/fake/hypervisor/vm.c
deleted file mode 100644
index 48398ac..0000000
--- a/src/arch/fake/hypervisor/vm.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2020 The Hafnium Authors.
- *
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file or at
- * https://opensource.org/licenses/BSD-3-Clause.
- */
-
-#include "hf/arch/vm.h"
-
-ffa_partition_properties_t arch_vm_partition_properties(ffa_vm_id_t id)
-{
-	(void)id;
-
-	return 0;
-}
diff --git a/src/load.c b/src/load.c
index b071bab..4521e1a 100644
--- a/src/load.c
+++ b/src/load.c
@@ -149,12 +149,8 @@
 			}
 		}
 
-		if (manifest_vm->sp.messaging_method ==
-			    DIRECT_MESSAGING_MANAGED_EXIT ||
-		    manifest_vm->sp.messaging_method ==
-			    BOTH_MESSAGING_MANAGED_EXIT) {
-			vm_locked.vm->supports_managed_exit = true;
-		}
+		vm_locked.vm->messaging_method =
+			manifest_vm->sp.messaging_method;
 
 		vm_locked.vm->boot_order = manifest_vm->sp.boot_order;
 		/* Updating boot list according to boot_order */
diff --git a/src/manifest.c b/src/manifest.c
index f2e8bf5..8883659 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -667,9 +667,10 @@
 		ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
 	}
 
-	if (vm->sp.messaging_method != INDIRECT_MESSAGING &&
-	    vm->sp.messaging_method != DIRECT_MESSAGING &&
-	    vm->sp.messaging_method != DIRECT_MESSAGING_MANAGED_EXIT) {
+	if ((vm->sp.messaging_method &
+	     ~(FFA_PARTITION_DIRECT_REQ_RECV | FFA_PARTITION_DIRECT_REQ_SEND |
+	       FFA_PARTITION_INDIRECT_MSG | FFA_PARTITION_MANAGED_EXIT)) !=
+	    0U) {
 		dlog_error("Messaging method %s: %x\n", error_string,
 			   vm->sp.messaging_method);
 		ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 5f85fca..c73f843 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -235,7 +235,7 @@
 		Property("entrypoint-offset", "<0x00001000>");
 		Property("xlat-granule", "<0>");
 		Property("boot-order", "<0>");
-		Property("messaging-method", "<1>");
+		Property("messaging-method", "<4>");
 		return *this;
 	}
 
@@ -818,7 +818,7 @@
 		.Property("entrypoint-offset", "<0x00001000>")
 		.Property("xlat-granule", "<0>")
 		.Property("boot-order", "<0>")
-		.Property("messaging-method", "<5>")
+		.Property("messaging-method", "<16>")
 		.Build();
 	/* clang-format on */
 	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
@@ -1056,7 +1056,7 @@
 	ASSERT_EQ(m.vm[0].sp.ep_offset, 0x00001000);
 	ASSERT_EQ(m.vm[0].sp.xlat_granule, PAGE_4KB);
 	ASSERT_EQ(m.vm[0].sp.boot_order, 0);
-	ASSERT_EQ(m.vm[0].sp.messaging_method, INDIRECT_MESSAGING);
+	ASSERT_EQ(m.vm[0].sp.messaging_method, FFA_PARTITION_INDIRECT_MSG);
 	ASSERT_EQ(m.vm[0].sp.mem_regions[0].base_address, 0x7100000);
 	ASSERT_EQ(m.vm[0].sp.mem_regions[0].page_count, 4);
 	ASSERT_EQ(m.vm[0].sp.mem_regions[0].attributes, 7);
diff --git a/src/vm.c b/src/vm.c
index 96e1212..116de09 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -331,3 +331,11 @@
 
 	vm->next_boot = current;
 }
+
+/**
+ * Returns true if VM supports a managed exit.
+ */
+bool vm_managed_exit_supported(struct vm *vm)
+{
+	return (vm->messaging_method & FFA_PARTITION_MANAGED_EXIT) != 0U;
+}