feat(manifest): support FF-A v1.2 direct messages

Add additional messaging method parsing to indicate whether a partition
can send/receive messages via FFA_MSG_SEND_DIRECT_REQ2.

Also enforce that a manifest declaring an FF-A version < FF-A v1.2
cannot declare usage of FFA_MSG_SEND_DIRECT_REQ2.

Signed-off-by: Kathleen Capella <kathleen.capella@arm.com>
Change-Id: I56f8e15dd00f16932ab7059dc585e12a9ca28f09
diff --git a/inc/hf/ffa_partition_manifest.h b/inc/hf/ffa_partition_manifest.h
index 3345e9e..de68d30 100644
--- a/inc/hf/ffa_partition_manifest.h
+++ b/inc/hf/ffa_partition_manifest.h
@@ -158,7 +158,7 @@
 	struct rx_tx rxtx;
 
 	/** mandatory - direct/indirect msg or both */
-	uint8_t messaging_method;
+	uint16_t messaging_method;
 	/** mandatory - action in response to non secure interrupt */
 	uint8_t ns_interrupts_action;
 	/** optional - managed exit signaled through vIRQ */
diff --git a/inc/hf/vm.h b/inc/hf/vm.h
index 9b7f40e..3d28bf4 100644
--- a/inc/hf/vm.h
+++ b/inc/hf/vm.h
@@ -247,7 +247,7 @@
 		ipaddr_t blob_addr;
 	} boot_info;
 
-	uint8_t messaging_method;
+	uint16_t messaging_method;
 
 	/**
 	 * Action specified by a Partition through the manifest in response to
@@ -369,7 +369,7 @@
 			       uint32_t *ids_count, uint32_t *lists_sizes,
 			       uint32_t *lists_count,
 			       const uint32_t ids_max_count);
-bool vm_supports_messaging_method(struct vm *vm, uint8_t messaging_method);
+bool vm_supports_messaging_method(struct vm *vm, uint16_t messaging_method);
 void vm_notifications_set_npi_injected(struct vm_locked vm_locked,
 				       bool npi_injected);
 bool vm_notifications_is_npi_injected(struct vm_locked vm_locked);
diff --git a/inc/vmapi/hf/ffa.h b/inc/vmapi/hf/ffa.h
index 9e88ce3..1f22baa 100644
--- a/inc/vmapi/hf/ffa.h
+++ b/inc/vmapi/hf/ffa.h
@@ -722,15 +722,21 @@
  * Flags to determine the partition properties, as required by
  * FFA_PARTITION_INFO_GET.
  *
- * The values of the flags are specified in table 8.25 of DEN0077A FF-A 1.0 REL
+ * The values of the flags are specified in table 6.2 of DEN0077A FF-A 1.2 ALP0
  * specification, "Partition information descriptor, partition properties".
  */
 typedef uint32_t ffa_partition_properties_t;
 
-/** Partition property: partition supports receipt of direct requests. */
+/**
+ * Partition property: partition supports receipt of direct requests via the
+ * FFA_MSG_SEND_DIRECT_REQ ABI.
+ */
 #define FFA_PARTITION_DIRECT_REQ_RECV (UINT32_C(1) << 0)
 
-/** Partition property: partition can send direct requests. */
+/**
+ * Partition property: partition can send direct requests via the
+ * FFA_MSG_SEND_DIRECT_REQ ABI.
+ */
 #define FFA_PARTITION_DIRECT_REQ_SEND (UINT32_C(1) << 1)
 
 /** Partition property: partition can send and receive indirect messages. */
@@ -743,6 +749,18 @@
 #define FFA_PARTITION_AARCH64_EXEC (UINT32_C(1) << 8)
 
 /**
+ * Partition property: partition supports receipt of direct requests via the
+ * FFA_MSG_SEND_DIRECT_REQ2 ABI.
+ */
+#define FFA_PARTITION_DIRECT_REQ2_RECV (UINT32_C(1) << 9)
+
+/**
+ * Partition property: partition can send direct requests via the
+ * FFA_MSG_SEND_DIRECT_REQ2 ABI.
+ */
+#define FFA_PARTITION_DIRECT_REQ2_SEND (UINT32_C(1) << 10)
+
+/**
  * Holds information returned for each partition by the FFA_PARTITION_INFO_GET
  * interface.
  * This corresponds to table 13.37 "Partition information descriptor"
diff --git a/src/arch/aarch64/hypervisor/other_world.c b/src/arch/aarch64/hypervisor/other_world.c
index 5f80ab3..1457148 100644
--- a/src/arch/aarch64/hypervisor/other_world.c
+++ b/src/arch/aarch64/hypervisor/other_world.c
@@ -31,7 +31,18 @@
 
 	/* Enabling all communication methods for the other world. */
 	other_world_vm->messaging_method =
-		FFA_PARTITION_DIRECT_REQ_RECV | FFA_PARTITION_DIRECT_REQ_SEND;
+		FFA_PARTITION_DIRECT_REQ_SEND | FFA_PARTITION_DIRECT_REQ2_SEND;
+
+	/*
+	 * If Hafnium is NWd Hypervisor, allow other_world_VM (SPMC) to
+	 * receive requests.
+	 * When Hafnium is SPMC, other_world_vm not allowed to receive requests
+	 * from SPs.
+	 */
+#if SECURE_WORLD == 0
+	other_world_vm->messaging_method |= FFA_PARTITION_DIRECT_REQ2_RECV;
+	other_world_vm->messaging_method |= FFA_PARTITION_DIRECT_REQ_RECV;
+#endif
 
 	/* Map NS mem ranges to "Other world VM" Stage-2 PTs. */
 	for (i = 0; i < params->ns_mem_ranges_count; i++) {
diff --git a/src/manifest.c b/src/manifest.c
index 3065c72..6be414a 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -895,6 +895,9 @@
 	enum manifest_return_code ret_code = MANIFEST_SUCCESS;
 	const char *error_string = "specified in manifest is unsupported";
 	uint32_t k = 0;
+	bool using_req2 = (vm->partition.messaging_method &
+			   (FFA_PARTITION_DIRECT_REQ2_RECV |
+			    FFA_PARTITION_DIRECT_REQ2_SEND)) != 0;
 
 	/* ensure that the SPM version is compatible */
 	ffa_version_major = (vm->partition.ffa_version & 0xffff0000) >>
@@ -929,9 +932,16 @@
 		ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
 	}
 
+	if (vm->partition.ffa_version < MAKE_FFA_VERSION(1, 2) && using_req2) {
+		dlog_error("Messaging method %s: %x\n", error_string,
+			   vm->partition.messaging_method);
+		ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
+	}
+
 	if ((vm->partition.messaging_method &
 	     ~(FFA_PARTITION_DIRECT_REQ_RECV | FFA_PARTITION_DIRECT_REQ_SEND |
-	       FFA_PARTITION_INDIRECT_MSG)) != 0U) {
+	       FFA_PARTITION_INDIRECT_MSG | FFA_PARTITION_DIRECT_REQ2_RECV |
+	       FFA_PARTITION_DIRECT_REQ2_SEND)) != 0U) {
 		dlog_error("Messaging method %s: %x\n", error_string,
 			   vm->partition.messaging_method);
 		ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
@@ -1089,8 +1099,8 @@
 		vm->partition.rxtx.available = true;
 	}
 
-	TRY(read_uint8(&root, "messaging-method",
-		       (uint8_t *)&vm->partition.messaging_method));
+	TRY(read_uint16(&root, "messaging-method",
+			(uint16_t *)&vm->partition.messaging_method));
 	dlog_verbose("  Messaging method %u\n", vm->partition.messaging_method);
 
 	TRY(read_bool(&root, "managed-exit", &managed_exit_field_present));
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 3554e47..1adaa0e 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -243,7 +243,7 @@
 		Property("entrypoint-offset", "<0x00002000>");
 		Property("xlat-granule", "<0>");
 		Property("boot-order", "<0>");
-		Property("messaging-method", "<4>");
+		Property("messaging-method", "<0x4>");
 		Property("ns-interrupts-action", "<1>");
 		return *this;
 	}
@@ -911,7 +911,29 @@
 		  MANIFEST_ERROR_NOT_COMPATIBLE);
 	manifest_dealloc();
 
-	/* Incompatible messaging method */
+	/* Incompatible messaging method - unrecognized messaging-method. */
+	/* clang-format off */
+	dtb = ManifestDtBuilder()
+		.Compatible({ "arm,ffa-manifest-1.0" })
+		.Property("ffa-version", "<0x10002>")
+		.Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
+		.Property("execution-ctx-count", "<1>")
+		.Property("exception-level", "<2>")
+		.Property("execution-state", "<0>")
+		.Property("entrypoint-offset", "<0x00002000>")
+		.Property("xlat-granule", "<0>")
+		.Property("boot-order", "<0>")
+		.Property("messaging-method", "<0x272>")
+		.Property("ns-interrupts-action", "<0>")
+		.Build();
+	/* clang-format on */
+	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
+		  MANIFEST_ERROR_NOT_COMPATIBLE);
+	manifest_dealloc();
+
+	/* Incompatible messaging method - only endpoints using FF-A version >=
+	 * FF-A v1.2 are allowed to set FFA_PARTITION_DIRECT_REQ2_RECV and
+	 * FFA_PARTITION_DIRECT_REQ2_SEND. */
 	/* clang-format off */
 	dtb = ManifestDtBuilder()
 		.Compatible({ "arm,ffa-manifest-1.0" })
@@ -923,7 +945,7 @@
 		.Property("entrypoint-offset", "<0x00002000>")
 		.Property("xlat-granule", "<0>")
 		.Property("boot-order", "<0>")
-		.Property("messaging-method", "<16>")
+		.Property("messaging-method", "<0x204>")
 		.Property("ns-interrupts-action", "<0>")
 		.Build();
 	/* clang-format on */
diff --git a/src/vm.c b/src/vm.c
index 8a91a2b..d2f6ce6 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -955,7 +955,7 @@
 /**
  * Checks VM's messaging method support.
  */
-bool vm_supports_messaging_method(struct vm *vm, uint8_t msg_method)
+bool vm_supports_messaging_method(struct vm *vm, uint16_t msg_method)
 {
 	return (vm->messaging_method & msg_method) != 0;
 }