PSA FF-A: update RX/TX buffer as per spec

PSA FF-A v1.0 spec describes RX/TX buffers as reference to memory-region
entries in the partition manifest which is described as RX/TX buffers.
In device tree terms, RX/TX nodes points to entries in memory-region
node using phandle.

This patch introduces RX and TX pointers which points to memory-region
type structure and is populated when memory-region node is parsed.

Change-Id: Ia04b9d082bacf3e6cb227e74dbf875c5e0680648
Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
diff --git a/src/manifest.c b/src/manifest.c
index e5076b6..9c98b5f 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -305,8 +305,10 @@
 }
 
 static enum manifest_return_code parse_ffa_memory_region_node(
-	struct fdt_node *mem_node, struct memory_region *mem_regions)
+	struct fdt_node *mem_node, struct memory_region *mem_regions,
+	struct rx_tx *rxtx)
 {
+	uint32_t phandle;
 	unsigned int i = 0;
 
 	dlog_verbose("  Partition memory regions\n");
@@ -343,6 +345,18 @@
 		mem_regions[i].attributes &= MM_PERM_MASK;
 		dlog_verbose("      Attributes:  %u\n",
 			     mem_regions[i].attributes);
+
+		TRY(read_optional_uint32(mem_node, "phandle",
+					 (uint32_t)MANIFEST_INVALID_ADDRESS,
+					 &phandle));
+		if (phandle == rxtx->rx_phandle) {
+			dlog_verbose("      Assigned as RX buffer\n");
+			rxtx->rx_buffer = &mem_regions[i];
+		} else if (phandle == rxtx->tx_phandle) {
+			dlog_verbose("      Assigned as TX buffer\n");
+			rxtx->tx_buffer = &mem_regions[i];
+		}
+
 		i++;
 	} while (fdt_next_sibling(mem_node) && (i < SP_MAX_MEMORY_REGIONS));
 
@@ -517,16 +531,17 @@
 			return MANIFEST_ERROR_NOT_COMPATIBLE;
 		}
 
-		TRY(read_uint64(&ffa_node, "base-address",
-				&vm->sp.rxtx.base_address));
+		/*
+		 * Read only phandles for now, it will be used to update buffers
+		 * while parsing memory regions.
+		 */
+		TRY(read_uint32(&ffa_node, "rx-buffer",
+				&vm->sp.rxtx.rx_phandle));
 
-		TRY(read_uint16(&ffa_node, "pages-count",
-				&vm->sp.rxtx.pages_count));
+		TRY(read_uint32(&ffa_node, "tx-buffer",
+				&vm->sp.rxtx.tx_phandle));
 
-		TRY(read_uint16(&ffa_node, "attributes",
-				&vm->sp.rxtx.attributes));
-
-		vm->sp.rxtx.rxtx_found = true;
+		vm->sp.rxtx.available = true;
 	}
 
 	TRY(read_uint8(&root, "messaging-method",
@@ -536,8 +551,8 @@
 	/* Parse memory-regions */
 	ffa_node = root;
 	if (fdt_find_child(&ffa_node, &mem_region_node_name)) {
-		TRY(parse_ffa_memory_region_node(&ffa_node,
-						 vm->sp.mem_regions));
+		TRY(parse_ffa_memory_region_node(&ffa_node, vm->sp.mem_regions,
+						 &vm->sp.rxtx));
 	}
 
 	/* Parse Device-regions */
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index d58cb70..7b039f9 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -217,6 +217,12 @@
 		return *this;
 	}
 
+	ManifestDtBuilder &Label(const std::string_view &name)
+	{
+		dts_ << name << ": ";
+		return *this;
+	}
+
 	ManifestDtBuilder &FfaValidManifest()
 	{
 		Compatible({"arm,ffa-manifest-1.0"});
@@ -817,6 +823,35 @@
 		  MANIFEST_ERROR_NOT_COMPATIBLE);
 }
 
+TEST(manifest, ffa_validate_rxtx_info)
+{
+	struct manifest m;
+
+	/* Not Compatible */
+	/* clang-format off */
+	std::vector<char>  dtb = ManifestDtBuilder()
+		.FfaValidManifest()
+		.StartChild("rx_tx-info")
+			.Compatible({ "foo,bar" })
+		.EndChild()
+		.Build();
+	/* clang-format on */
+	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
+		  MANIFEST_ERROR_NOT_COMPATIBLE);
+
+	/* Missing Properties */
+	/* clang-format off */
+	dtb = ManifestDtBuilder()
+		.FfaValidManifest()
+		.StartChild("rx_tx-info")
+			.Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
+		.EndChild()
+		.Build();
+	/* clang-format on */
+	ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
+		  MANIFEST_ERROR_PROPERTY_NOT_FOUND);
+}
+
 TEST(manifest, ffa_validate_mem_regions)
 {
 	struct manifest m;
@@ -933,6 +968,11 @@
 	/* clang-format off */
 	std::vector<char>  dtb = ManifestDtBuilder()
 		.FfaValidManifest()
+		.StartChild("rx_tx-info")
+			.Compatible({ "arm,ffa-manifest-rx_tx-buffer" })
+			.Property("rx-buffer", "<&rx>")
+			.Property("tx-buffer", "<&tx>")
+		.EndChild()
 		.StartChild("memory-regions")
 			.Compatible({ "arm,ffa-manifest-memory-regions" })
 			.StartChild("test-memory")
@@ -941,6 +981,20 @@
 				.Property("pages-count", "<4>")
 				.Property("attributes", "<7>")
 			.EndChild()
+			.Label("rx")
+			.StartChild("rx")
+				.Description("rx-buffer")
+				.Property("base-address", "<0x7300000>")
+				.Property("pages-count", "<1>")
+				.Property("attributes", "<1>")
+			.EndChild()
+			.Label("tx")
+			.StartChild("tx")
+				.Description("tx-buffer")
+				.Property("base-address", "<0x7310000>")
+				.Property("pages-count", "<1>")
+				.Property("attributes", "<3>")
+			.EndChild()
 		.EndChild()
 		.StartChild("device-regions")
 			.Compatible({ "arm,ffa-manifest-device-regions" })
@@ -973,6 +1027,13 @@
 	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);
+	ASSERT_EQ(m.vm[0].sp.rxtx.available, true);
+	ASSERT_EQ(m.vm[0].sp.rxtx.rx_buffer->base_address, 0x7300000);
+	ASSERT_EQ(m.vm[0].sp.rxtx.rx_buffer->page_count, 1);
+	ASSERT_EQ(m.vm[0].sp.rxtx.rx_buffer->attributes, 1);
+	ASSERT_EQ(m.vm[0].sp.rxtx.tx_buffer->base_address, 0x7310000);
+	ASSERT_EQ(m.vm[0].sp.rxtx.tx_buffer->page_count, 1);
+	ASSERT_EQ(m.vm[0].sp.rxtx.tx_buffer->attributes, 3);
 	ASSERT_EQ(m.vm[0].sp.dev_regions[0].base_address, 0x7200000);
 	ASSERT_EQ(m.vm[0].sp.dev_regions[0].page_count, 16);
 	/* Attribute is ORed with MM_MODE_D */