test: load-address-relative-offset integration tests

Change-Id: If93a68dddffc8b2581d9da332c22714e59bbd39f
Signed-off-by: Karl Meakin <karl.meakin@arm.com>
diff --git a/test/hftest/service_common.c b/test/hftest/service_common.c
index 2ec6e16..6ff2c71 100644
--- a/test/hftest/service_common.c
+++ b/test/hftest/service_common.c
@@ -7,12 +7,14 @@
  */
 
 #include "hf/check.h"
+#include "hf/fdt.h"
 #include "hf/fdt_handler.h"
 #include "hf/ffa.h"
 #include "hf/memiter.h"
 #include "hf/mm.h"
 #include "hf/std.h"
 #include "hf/stdout.h"
+#include "hf/string.h"
 
 #include "vmapi/hf/call.h"
 
@@ -109,6 +111,7 @@
 	struct string mem_region_node_name = STRING_INIT("memory-regions");
 	struct string dev_region_node_name = STRING_INIT("device-regions");
 	struct memiter uuid;
+	struct memiter description;
 	uint32_t uuid_word = 0;
 	uint16_t j = 0;
 	uint16_t i = 0;
@@ -177,6 +180,14 @@
 				cur_region->base_address =
 					ctx->partition_manifest.load_addr +
 					number;
+				cur_region->is_relative = true;
+			}
+
+			if (fdt_read_property(&ffa_node, "description",
+					      &description)) {
+				EXPECT_EQ(string_init(&cur_region->description,
+						      &description),
+					  STRING_SUCCESS);
 			}
 
 			EXPECT_TRUE(fdt_read_number(&ffa_node, "attributes",
diff --git a/test/vmapi/primary_with_secondaries/boot.c b/test/vmapi/primary_with_secondaries/boot.c
index d2fc3f4..7eb4a54 100644
--- a/test/vmapi/primary_with_secondaries/boot.c
+++ b/test/vmapi/primary_with_secondaries/boot.c
@@ -7,6 +7,7 @@
  */
 
 #include "hf/dlog.h"
+#include "hf/ffa.h"
 
 #include "vmapi/hf/call.h"
 
@@ -73,3 +74,46 @@
 
 	EXPECT_FALSE(exception_received(&run_res, mb.recv));
 }
+
+TEST_PRECONDITION(boot, memory_manifest_relative, service1_is_not_vm)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+	struct ffa_value run_res;
+
+	SERVICE_SELECT(service1_info->vm_id, "boot_memory_manifest_relative",
+		       mb.send);
+	run_res = ffa_run(service1_info->vm_id, 0);
+
+	EXPECT_EQ(exception_received(&run_res, mb.recv), false);
+}
+
+TEST_PRECONDITION(boot, memory_manifest_relative_test_memory_ro,
+		  service1_is_not_vm)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+	struct ffa_value run_res;
+
+	SERVICE_SELECT(service1_info->vm_id,
+		       "boot_memory_manifest_relative_test_memory_ro", mb.send);
+	run_res = ffa_run(service1_info->vm_id, 0);
+
+	/* data abort exception expected due to accessing RO memory */
+	EXPECT_EQ(exception_received(&run_res, mb.recv), true);
+}
+
+TEST_PRECONDITION(boot, memory_manifest_relative_ro_secure_memory,
+		  service1_is_not_vm)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+	struct ffa_value run_res;
+
+	SERVICE_SELECT(service1_info->vm_id,
+		       "boot_memory_manifest_ro_secure_memory", mb.send);
+	run_res = ffa_run(service1_info->vm_id, 0);
+
+	/* data abort exception expected due to accessing RO memory */
+	EXPECT_EQ(exception_received(&run_res, mb.recv), true);
+}
diff --git a/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp1.dts b/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp1.dts
index a76ec66..32f0102 100644
--- a/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp1.dts
+++ b/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp1.dts
@@ -14,7 +14,7 @@
 
 	/* Properties */
 	ffa-version = <0x00010002>; /* 31:16 - Major, 15:0 - Minor */
-        uuid = <0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>;
+	uuid = <0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>;
 	execution-ctx-count = <8>;
 	exception-level = <2>; /* S-EL1 */
 	execution-state = <0>; /* AARCH64 */
@@ -37,25 +37,36 @@
 
 		compatible = "arm,ffa-manifest-memory-regions";
 
-		test-memory {
+		test-memory-rw {
+			description = "test-memory-rw";
 			load-address-relative-offset = <0x300000>; /* effective address = 0x6780000 */
 			pages-count = <1>;
-			attributes = <0x3>;
+			attributes = <0x3>; /* read-write */
+		};
+
+		test-memory-ro {
+			description = "test-memory-ro";
+			load-address-relative-offset = <0x400000>; /* effective address = 0x6780000 */
+			pages-count = <1>;
+			attributes = <0x1>; /* read-only */
 		};
 
 		secure-memory {
+			description = "secure-memory";
 			base-address = <0x00000000 0x7100000>;
 			pages-count = <1>;
 			attributes = <0x3>; /* read-write */
 		};
 
 		ro-secure-memory {
+			description = "ro-secure-memory";
 			base-address = <0x00000000 0x7200000>;
 			pages-count = <1>;
 			attributes = <0x1>; /* read-only */
 		};
 
 		ns-memory {
+			description = "ns-memory";
 			base-address = <0x00000000 0x9001F000>;
 			pages-count = <1>;
 			attributes = <0xb>; /* read-write and NS */
diff --git a/test/vmapi/primary_with_secondaries/services/boot.c b/test/vmapi/primary_with_secondaries/services/boot.c
index b474c25..710bbd9 100644
--- a/test/vmapi/primary_with_secondaries/services/boot.c
+++ b/test/vmapi/primary_with_secondaries/services/boot.c
@@ -169,3 +169,147 @@
 	}
 	ffa_yield();
 }
+
+static void read_memory_region(const volatile struct memory_region* region)
+{
+	/* NOLINTNEXTLINE(performance-no-int-to-ptr) */
+	const volatile uint8_t* ptr = (volatile uint8_t*)region->base_address;
+	size_t page_count = region->page_count;
+	uint64_t sum = 0;
+
+	for (size_t i = 0; i < page_count * PAGE_SIZE; ++i) {
+		sum += ptr[i];
+	}
+
+	ASSERT_NE(sum, 0);
+}
+
+static void write_memory_region(struct memory_region* region)
+{
+	/* NOLINTNEXTLINE(performance-no-int-to-ptr) */
+	volatile uint8_t* ptr = (volatile uint8_t*)region->base_address;
+	size_t page_count = region->page_count;
+	uint8_t val;
+
+	for (size_t i = 0; i < page_count * PAGE_SIZE; ++i) {
+		val = ptr[i];
+		ptr[i] += 1;
+		ASSERT_EQ(ptr[i], val + 1);
+	}
+}
+
+/*
+ * Validate all memory regions provided to the SP.
+ */
+TEST_SERVICE(boot_memory_manifest_relative)
+{
+	struct hftest_context* ctx = hftest_get_context();
+	struct ffa_partition_manifest* manifest = &ctx->partition_manifest;
+	struct memory_region* mem_region;
+
+	if (!ctx->is_ffa_manifest_parsed) {
+		panic("This test requires the running partition to have "
+		      "received and parsed its own FF-A manifest.\n");
+	}
+
+	exception_setup(NULL, exception_handler_yield_data_abort);
+
+	EXPECT_EQ(manifest->load_addr, 0x6480000);
+	EXPECT_EQ(manifest->mem_region_count, 5);
+
+	mem_region = &manifest->mem_regions[0];
+	EXPECT_STREQ(mem_region->description.data, "test-memory-rw");
+	EXPECT_EQ(mem_region->base_address, manifest->load_addr + 0x300000);
+	EXPECT_EQ(mem_region->is_relative, true);
+	EXPECT_EQ(mem_region->page_count, 0x1);
+	EXPECT_EQ(mem_region->attributes, 0x3); /* read-write */
+	write_memory_region(mem_region);
+
+	mem_region = &manifest->mem_regions[1];
+	EXPECT_STREQ(mem_region->description.data, "test-memory-ro");
+	EXPECT_EQ(mem_region->base_address, manifest->load_addr + 0x400000);
+	EXPECT_EQ(mem_region->is_relative, true);
+	EXPECT_EQ(mem_region->page_count, 0x1);
+	EXPECT_EQ(mem_region->attributes, 0x1); /* read-only */
+	read_memory_region(mem_region);
+
+	mem_region = &manifest->mem_regions[2];
+	EXPECT_STREQ(mem_region->description.data, "secure-memory");
+	EXPECT_EQ(mem_region->base_address, 0x7100000);
+	EXPECT_EQ(mem_region->is_relative, false);
+	EXPECT_EQ(mem_region->page_count, 0x1);
+	EXPECT_EQ(mem_region->attributes, 0x3); /* read-write */
+	write_memory_region(mem_region);
+
+	mem_region = &manifest->mem_regions[3];
+	EXPECT_STREQ(mem_region->description.data, "ro-secure-memory");
+	EXPECT_EQ(mem_region->base_address, 0x7200000);
+	EXPECT_EQ(mem_region->is_relative, false);
+	EXPECT_EQ(mem_region->page_count, 0x1);
+	EXPECT_EQ(mem_region->attributes, 0x1); /* read-only */
+	read_memory_region(mem_region);
+
+	ffa_yield();
+}
+
+/*
+ * Validate that attempting to write to "test-memory-ro" causes a
+ * fault because it is read-only.
+ */
+TEST_SERVICE(boot_memory_manifest_relative_test_memory_ro)
+{
+	struct hftest_context* ctx = hftest_get_context();
+	struct ffa_partition_manifest* manifest = &ctx->partition_manifest;
+	struct memory_region* mem_region;
+
+	if (!ctx->is_ffa_manifest_parsed) {
+		panic("This test requires the running partition to have "
+		      "received and parsed its own FF-A manifest.\n");
+	}
+
+	exception_setup(NULL, exception_handler_yield_data_abort);
+
+	EXPECT_EQ(manifest->load_addr, 0x6480000);
+	EXPECT_EQ(manifest->mem_region_count, 5);
+
+	mem_region = &manifest->mem_regions[1];
+	EXPECT_STREQ(mem_region->description.data, "test-memory-ro");
+	EXPECT_EQ(mem_region->base_address, manifest->load_addr + 0x400000);
+	EXPECT_EQ(mem_region->is_relative, true);
+	EXPECT_EQ(mem_region->page_count, 0x1);
+	EXPECT_EQ(mem_region->attributes, 0x1); /* read-only */
+	write_memory_region(mem_region);
+
+	ffa_yield();
+}
+
+/*
+ * Validate that attempting to write to "ro-secure-memory" causes a
+ * fault because it is read-only.
+ */
+TEST_SERVICE(boot_memory_manifest_ro_secure_memory)
+{
+	struct hftest_context* ctx = hftest_get_context();
+	struct ffa_partition_manifest* manifest = &ctx->partition_manifest;
+	struct memory_region* mem_region;
+
+	if (!ctx->is_ffa_manifest_parsed) {
+		panic("This test requires the running partition to have "
+		      "received and parsed its own FF-A manifest.\n");
+	}
+
+	exception_setup(NULL, exception_handler_yield_data_abort);
+
+	EXPECT_EQ(manifest->load_addr, 0x6480000);
+	EXPECT_EQ(manifest->mem_region_count, 5);
+
+	mem_region = &manifest->mem_regions[3];
+	EXPECT_STREQ(mem_region->description.data, "ro-secure-memory");
+	EXPECT_EQ(mem_region->base_address, 0x7200000);
+	EXPECT_EQ(mem_region->is_relative, false);
+	EXPECT_EQ(mem_region->page_count, 0x1);
+	EXPECT_EQ(mem_region->attributes, 0x1); /* read-only */
+	write_memory_region(mem_region);
+
+	ffa_yield();
+}