fix(memory share): memory attributes on FFA_MEM_RETRIEVE_REQ
Validate that the memory attributes provided in memory region
descriptor when invoking FFA_MEM_RETRIEVE_REQ are those supported by
Hafnium, only if those are specified. If memory attributes are not
specified, skip validation, as the caller expects to receive them in the
FFA_MEM_RETRIEVE_RESP response.
Implemented test to validate that memory can be shared if no memory
type attributes are specified, and that the response contain the
attributes expected to be implemented by hafnium.
Change-Id: Id64489923d8bd58e4ba2a20767b4111f0a4b36ff
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index 1cd8c5e..048cca9 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -2467,14 +2467,18 @@
"be checked before this point.");
}
- /*
- * Ensure receiver's attributes are compatible with how Hafnium maps
- * memory: Normal Memory, Inner shareable, Write-Back Read-Allocate
- * Write-Allocate Cacheable.
- */
- ret = ffa_memory_attributes_validate(retrieve_request->attributes);
- if (ret.func != FFA_SUCCESS_32) {
- goto out;
+ if (ffa_get_memory_type_attr(retrieve_request->attributes) !=
+ FFA_MEMORY_NOT_SPECIFIED_MEM) {
+ /*
+ * Ensure receiver's attributes are compatible with how Hafnium
+ * maps memory: Normal Memory, Inner shareable, Write-Back
+ * Read-Allocate Write-Allocate Cacheable.
+ */
+ ret = ffa_memory_attributes_validate(
+ retrieve_request->attributes);
+ if (ret.func != FFA_SUCCESS_32) {
+ goto out;
+ }
}
memory_to_attributes = ffa_memory_permissions_to_mode(
diff --git a/test/vmapi/primary_with_secondaries/memory_sharing.c b/test/vmapi/primary_with_secondaries/memory_sharing.c
index aa07e79..bd94b95 100644
--- a/test/vmapi/primary_with_secondaries/memory_sharing.c
+++ b/test/vmapi/primary_with_secondaries/memory_sharing.c
@@ -332,6 +332,65 @@
}
/**
+ * Perform memory share operation, and propagate retrieve request to the
+ * receiver that doesn't specify the memory type. Hafnium should skip its
+ * internal validation, and provide the right memory attributes in the
+ * FFA_MEM_RETRIEVE_RESP. The receiver will validate the arguments are as
+ * expected.
+ */
+TEST(memory_sharing, share_retrieve_memory_type_not_specified)
+{
+ struct mailbox_buffers mb = set_up_mailbox();
+ uint8_t *ptr = pages;
+ struct ffa_memory_region_constituent constituents[] = {
+ {.address = (uint64_t)pages, .page_count = 1},
+ };
+ uint32_t msg_size;
+ struct ffa_value ret;
+ ffa_memory_handle_t handle;
+
+ SERVICE_SELECT(SERVICE_VM1, "memory_increment_check_mem_attr", mb.send);
+
+ memset_s(ptr, sizeof(pages), 'a', PAGE_SIZE);
+
+ 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_RW,
+ FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+ FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_INNER_SHAREABLE, NULL, &msg_size),
+ 0);
+
+ /* Call base function's test. */
+ ret = ffa_mem_share(msg_size, msg_size);
+ EXPECT_EQ(ret.func, FFA_SUCCESS_32);
+ handle = ffa_mem_success_handle(ret);
+
+ /*
+ * Send the appropriate retrieve request to the VM so that it can use it
+ * to retrieve the memory.
+ * The retrieve request doesn't specify the memory type.
+ */
+ msg_size = ffa_memory_retrieve_request_init(
+ mb.send, handle, HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0,
+ FFA_DATA_ACCESS_RW, FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+ FFA_MEMORY_NOT_SPECIFIED_MEM, 0, 0);
+
+ EXPECT_LE(msg_size, HF_MAILBOX_SIZE);
+ EXPECT_EQ(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, msg_size, 0).func,
+ FFA_SUCCESS_32);
+
+ EXPECT_EQ(ffa_run(SERVICE_VM1, 0).func, FFA_YIELD_32);
+ EXPECT_EQ(ffa_run(SERVICE_VM1, 0).func, FFA_MSG_SEND_32);
+ EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
+
+ for (int i = 0; i < PAGE_SIZE; ++i) {
+ EXPECT_EQ(pages[i], 'b');
+ }
+}
+
+/**
* Sharing memory concurrently gives both VMs access to the memory so it can be
* used for communication.
*/
diff --git a/test/vmapi/primary_with_secondaries/services/memory.c b/test/vmapi/primary_with_secondaries/services/memory.c
index 2e421ca..2c319e3 100644
--- a/test/vmapi/primary_with_secondaries/services/memory.c
+++ b/test/vmapi/primary_with_secondaries/services/memory.c
@@ -59,6 +59,56 @@
}
}
+TEST_SERVICE(memory_increment_check_mem_attr)
+{
+ /* Loop, writing message to the shared memory. */
+ for (;;) {
+ size_t i;
+ void *recv_buf = SERVICE_RECV_BUFFER();
+ void *send_buf = SERVICE_SEND_BUFFER();
+
+ struct ffa_value ret = ffa_msg_wait();
+ struct ffa_memory_region *memory_region =
+ (struct ffa_memory_region *)retrieve_buffer;
+ ffa_vm_id_t sender = retrieve_memory_from_message(
+ recv_buf, send_buf, ret, NULL, memory_region,
+ HF_MAILBOX_SIZE);
+ struct ffa_composite_memory_region *composite =
+ ffa_memory_region_get_composite(memory_region, 0);
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ uint8_t *ptr = (uint8_t *)composite->constituents[0].address;
+
+ ASSERT_EQ(memory_region->receiver_count, 1);
+ ASSERT_NE(memory_region->receivers[0]
+ .composite_memory_region_offset,
+ 0);
+
+ /*
+ * Validate retrieve response contains the memory attributes
+ * hafnium implements.
+ */
+ ASSERT_EQ(ffa_get_memory_type_attr(memory_region->attributes),
+ FFA_MEMORY_NORMAL_MEM);
+ ASSERT_EQ(ffa_get_memory_shareability_attr(
+ memory_region->attributes),
+ FFA_MEMORY_INNER_SHAREABLE);
+ ASSERT_EQ(ffa_get_memory_cacheability_attr(
+ memory_region->attributes),
+ FFA_MEMORY_CACHE_WRITE_BACK);
+
+ /* Allow the memory to be populated. */
+ EXPECT_EQ(ffa_yield().func, FFA_SUCCESS_32);
+
+ /* Increment each byte of memory. */
+ for (i = 0; i < PAGE_SIZE; ++i) {
+ ++ptr[i];
+ }
+
+ /* Signal completion and reset. */
+ ffa_msg_send(hf_vm_get_id(), sender, sizeof(ptr), 0);
+ }
+}
+
TEST_SERVICE(give_memory_and_fault)
{
void *send_buf = SERVICE_SEND_BUFFER();