PSA FF-A: add memory-region parsing support
This patch implements support for parsing memory regions described in
Section 3.1, Table 10 of PSA FF-A EAC specification.
A maximum of 8 memory-regions can be defined for a given partition.
Change-Id: I348be5aa3510ef02b4b990dbbba07d443750eae7
Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
diff --git a/src/manifest.c b/src/manifest.c
index 8b40795..879ed12 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -290,6 +290,53 @@
return MANIFEST_SUCCESS;
}
+static enum manifest_return_code parse_ffa_memory_region_node(
+ struct fdt_node *mem_node, struct memory_region *mem_regions)
+{
+ unsigned int i = 0;
+
+ dlog_verbose(" Partition memory regions\n");
+
+ if (!fdt_is_compatible(mem_node, "arm,ffa-manifest-memory-regions")) {
+ return MANIFEST_ERROR_NOT_COMPATIBLE;
+ }
+
+ if (!fdt_first_child(mem_node)) {
+ return MANIFEST_ERROR_MEMORY_REGION_NODE_EMPTY;
+ }
+
+ do {
+ dlog_verbose(" Memory Region[%u]\n", i);
+
+ TRY(read_optional_string(mem_node, "description",
+ &mem_regions[i].name));
+ dlog_verbose(" Name: %s\n",
+ string_data(&mem_regions[i].name));
+
+ TRY(read_optional_uint64(mem_node, "base-address",
+ MANIFEST_INVALID_ADDRESS,
+ &mem_regions[i].base_address));
+ dlog_verbose(" Base address: %#x\n",
+ mem_regions[i].base_address);
+
+ TRY(read_uint32(mem_node, "pages-count",
+ &mem_regions[i].page_count));
+ dlog_verbose(" Pages_count: %u\n",
+ mem_regions[i].page_count);
+
+ TRY(read_uint32(mem_node, "attributes",
+ &mem_regions[i].attributes));
+ mem_regions[i].attributes &= MM_PERM_MASK;
+ dlog_verbose(" Attributes: %u\n",
+ mem_regions[i].attributes);
+ i++;
+ } while (fdt_next_sibling(mem_node) && (i < SP_MAX_MEMORY_REGIONS));
+
+ dlog_verbose(" Total %u memory regions found\n", i);
+
+ return MANIFEST_SUCCESS;
+}
+
static enum manifest_return_code parse_ffa_manifest(struct fdt *fdt,
struct manifest_vm *vm)
{
@@ -299,6 +346,7 @@
struct fdt_node root;
struct fdt_node ffa_node;
struct string rxtx_node_name = STRING_INIT("rx_tx-info");
+ struct string mem_region_node_name = STRING_INIT("memory-regions");
if (!fdt_find_node(fdt, "/", &root)) {
return MANIFEST_ERROR_NO_ROOT_NODE;
@@ -369,6 +417,13 @@
(uint8_t *)&vm->sp.messaging_method));
dlog_verbose(" SP messaging method %d\n", vm->sp.messaging_method);
+ /* 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));
+ }
+
return MANIFEST_SUCCESS;
}
@@ -626,6 +681,8 @@
return "Malformed integer list property";
case MANIFEST_ERROR_MALFORMED_BOOLEAN:
return "Malformed boolean property";
+ case MANIFEST_ERROR_MEMORY_REGION_NODE_EMPTY:
+ return "Memory-region node should have at least one entry";
}
panic("Unexpected manifest return code.");
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 5ac6a31..fcd109e 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -160,6 +160,11 @@
return StringProperty("debug_name", value);
}
+ ManifestDtBuilder &Description(const std::string_view &value)
+ {
+ return StringProperty("description", value);
+ }
+
ManifestDtBuilder &KernelFilename(const std::string_view &value)
{
return StringProperty("kernel_filename", value);
@@ -812,6 +817,50 @@
MANIFEST_ERROR_NOT_COMPATIBLE);
}
+TEST(manifest, ffa_validate_mem_regions)
+{
+ struct manifest m;
+
+ /* Not Compatible */
+ /* clang-format off */
+ std::vector<char> dtb = ManifestDtBuilder()
+ .FfaValidManifest()
+ .StartChild("memory-regions")
+ .Compatible({ "foo,bar" })
+ .EndChild()
+ .Build();
+ /* clang-format on */
+ ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
+ MANIFEST_ERROR_NOT_COMPATIBLE);
+
+ /* Memory regions unavailable */
+ /* clang-format off */
+ dtb = ManifestDtBuilder()
+ .FfaValidManifest()
+ .StartChild("memory-regions")
+ .Compatible({ "arm,ffa-manifest-memory-regions" })
+ .EndChild()
+ .Build();
+ /* clang-format on */
+ ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
+ MANIFEST_ERROR_MEMORY_REGION_NODE_EMPTY);
+
+ /* Missing Properties */
+ /* clang-format off */
+ dtb = ManifestDtBuilder()
+ .FfaValidManifest()
+ .StartChild("memory-regions")
+ .Compatible({ "arm,ffa-manifest-memory-regions" })
+ .StartChild("test-memory")
+ .Description("test-memory")
+ .EndChild()
+ .EndChild()
+ .Build();
+ /* clang-format on */
+ ASSERT_EQ(ffa_manifest_from_vec(&m, dtb),
+ MANIFEST_ERROR_PROPERTY_NOT_FOUND);
+}
+
TEST(manifest, ffa_valid)
{
struct manifest m;
@@ -819,6 +868,15 @@
/* clang-format off */
std::vector<char> dtb = ManifestDtBuilder()
.FfaValidManifest()
+ .StartChild("memory-regions")
+ .Compatible({ "arm,ffa-manifest-memory-regions" })
+ .StartChild("test-memory")
+ .Description("test-memory")
+ .Property("base-address", "<0x7100000>")
+ .Property("pages-count", "<4>")
+ .Property("attributes", "<7>")
+ .EndChild()
+ .EndChild()
.Build();
/* clang-format on */
@@ -835,6 +893,9 @@
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.messaging_method, INDIRECT_MESSAGING);
+ 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);
}
} /* namespace */