fix(ff-a): add sender's memory attribute checks
Relayer has to ensure sender's attributes are less permissive or equal
to configured ones.
Hafnium only supports a subset of attributes and is currently non
configurable.
Checking that sender's attributes match what Hafnium expects and will
use in mappings: Normal Memory, Inner shareable, Write-Back
Read-Allocate Write-Allocate Cacheable.
Change-Id: I15ae747aeab39ec19423f9649f7b232a9b74b809
Signed-off-by: Federico Recanati <federico.recanati@arm.com>
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index 78a9574..c51db1d 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -1363,6 +1363,10 @@
uint32_t constituents_length;
enum ffa_data_access data_access;
enum ffa_instruction_access instruction_access;
+ ffa_memory_access_permissions_t attributes;
+ enum ffa_memory_type memory_type;
+ enum ffa_memory_cacheability memory_cacheability;
+ enum ffa_memory_shareability memory_shareability;
assert(permissions != NULL);
@@ -1490,6 +1494,33 @@
return ffa_error(FFA_INVALID_PARAMETERS);
}
+ /*
+ * Check that sender's memory attributes match Hafnium expectations:
+ * Normal Memory, Inner shareable, Write-Back Read-Allocate
+ * Write-Allocate Cacheable.
+ */
+ attributes = memory_region->attributes;
+ memory_type = ffa_get_memory_type_attr(attributes);
+ if (memory_type != FFA_MEMORY_NORMAL_MEM) {
+ dlog_verbose("Invalid memory type %#x, expected %#x.\n",
+ memory_type, FFA_MEMORY_NORMAL_MEM);
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ memory_cacheability = ffa_get_memory_cacheability_attr(attributes);
+ if (memory_cacheability != FFA_MEMORY_CACHE_WRITE_BACK) {
+ dlog_verbose("Invalid cacheability %#x, expected %#x.\n",
+ memory_cacheability, FFA_MEMORY_CACHE_WRITE_BACK);
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ memory_shareability = ffa_get_memory_shareability_attr(attributes);
+ if (memory_shareability != FFA_MEMORY_INNER_SHAREABLE) {
+ dlog_verbose("Invalid shareability %#x, expected %#x.\n",
+ memory_shareability, FFA_MEMORY_INNER_SHAREABLE);
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
return (struct ffa_value){.func = FFA_SUCCESS_32};
}
diff --git a/test/vmapi/el0_partitions/memory_sharing.c b/test/vmapi/el0_partitions/memory_sharing.c
index c9b3fe1..d3e4d5f 100644
--- a/test/vmapi/el0_partitions/memory_sharing.c
+++ b/test/vmapi/el0_partitions/memory_sharing.c
@@ -2033,6 +2033,67 @@
}
/**
+ * Memory can't be shared with arbitrary attributes because Hafnium maps pages
+ * with hardcoded values and doesn't support custom mappings.
+ */
+TEST(memory_sharing, ffa_validate_attributes)
+{
+ struct ffa_value ret;
+ struct mailbox_buffers mb = set_up_mailbox();
+ uint32_t msg_size;
+
+ struct ffa_value (*send_function[])(uint32_t, uint32_t) = {
+ ffa_mem_share,
+ ffa_mem_lend,
+ };
+
+ struct ffa_memory_region_constituent constituents[] = {
+ {.address = (uint64_t)pages, .page_count = 2},
+ {.address = (uint64_t)pages + PAGE_SIZE * 3, .page_count = 1},
+ };
+
+ struct {
+ enum ffa_memory_type memory_type;
+ enum ffa_memory_cacheability memory_cacheability;
+ enum ffa_memory_shareability memory_shareability;
+ } invalid_attributes[] = {
+ /* Invalid memory type */
+ {FFA_MEMORY_DEVICE_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_INNER_SHAREABLE},
+ /* Invalid cacheability */
+ {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_NON_CACHEABLE,
+ FFA_MEMORY_INNER_SHAREABLE},
+ /* Invalid shareability */
+ {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_SHARE_NON_SHAREABLE},
+ {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_OUTER_SHAREABLE}};
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(invalid_attributes); ++i) {
+ /* Prepare memory region, and set all flags */
+ EXPECT_EQ(ffa_memory_region_init(
+ mb.send, HF_MAILBOX_SIZE, HF_PRIMARY_VM_ID,
+ SERVICE_VM1, constituents,
+ ARRAY_SIZE(constituents), 0, 0,
+ FFA_DATA_ACCESS_RO,
+ FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+ invalid_attributes[i].memory_type,
+ invalid_attributes[i].memory_cacheability,
+ invalid_attributes[i].memory_shareability,
+ NULL, &msg_size),
+ 0);
+
+ /* Call the various mem send functions on the same region. */
+ for (uint32_t j = 0; j < ARRAY_SIZE(send_function); j++) {
+ ret = send_function[j](msg_size, msg_size);
+ EXPECT_EQ(ret.func, FFA_ERROR_32);
+ EXPECT_TRUE(ffa_error_code(ret) ==
+ FFA_INVALID_PARAMETERS);
+ }
+ }
+}
+
+/**
* Memory can't be shared if flags in the memory transaction description that
* Must Be Zero, are not.
*/
diff --git a/test/vmapi/primary_with_secondaries/memory_sharing.c b/test/vmapi/primary_with_secondaries/memory_sharing.c
index 66b9b5e..7b01986 100644
--- a/test/vmapi/primary_with_secondaries/memory_sharing.c
+++ b/test/vmapi/primary_with_secondaries/memory_sharing.c
@@ -2169,6 +2169,67 @@
}
/**
+ * Memory can't be shared with arbitrary attributes because Hafnium maps pages
+ * with hardcoded values and doesn't support custom mappings.
+ */
+TEST(memory_sharing, ffa_validate_attributes)
+{
+ struct ffa_value ret;
+ struct mailbox_buffers mb = set_up_mailbox();
+ uint32_t msg_size;
+
+ struct ffa_value (*send_function[])(uint32_t, uint32_t) = {
+ ffa_mem_share,
+ ffa_mem_lend,
+ };
+
+ struct ffa_memory_region_constituent constituents[] = {
+ {.address = (uint64_t)pages, .page_count = 2},
+ {.address = (uint64_t)pages + PAGE_SIZE * 3, .page_count = 1},
+ };
+
+ struct {
+ enum ffa_memory_type memory_type;
+ enum ffa_memory_cacheability memory_cacheability;
+ enum ffa_memory_shareability memory_shareability;
+ } invalid_attributes[] = {
+ /* Invalid memory type */
+ {FFA_MEMORY_DEVICE_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_INNER_SHAREABLE},
+ /* Invalid cacheability */
+ {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_NON_CACHEABLE,
+ FFA_MEMORY_INNER_SHAREABLE},
+ /* Invalid shareability */
+ {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_SHARE_NON_SHAREABLE},
+ {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_OUTER_SHAREABLE}};
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(invalid_attributes); ++i) {
+ /* Prepare memory region, and set all flags */
+ EXPECT_EQ(ffa_memory_region_init(
+ mb.send, HF_MAILBOX_SIZE, HF_PRIMARY_VM_ID,
+ SERVICE_VM1, constituents,
+ ARRAY_SIZE(constituents), 0, 0,
+ FFA_DATA_ACCESS_RO,
+ FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+ invalid_attributes[i].memory_type,
+ invalid_attributes[i].memory_cacheability,
+ invalid_attributes[i].memory_shareability,
+ NULL, &msg_size),
+ 0);
+
+ /* Call the various mem send functions on the same region. */
+ for (uint32_t j = 0; j < ARRAY_SIZE(send_function); j++) {
+ ret = send_function[j](msg_size, msg_size);
+ EXPECT_EQ(ret.func, FFA_ERROR_32);
+ EXPECT_TRUE(ffa_error_code(ret) ==
+ FFA_INVALID_PARAMETERS);
+ }
+ }
+}
+
+/**
* Memory can't be shared if flags in the memory transaction description that
* Must Be Zero, are not.
*/