refactor: hypervisor retrieve request helpers
Factored out of hypervisor_retrieve_request the looping
part, for retrieving the fragments of a fragmented
retrieve request. This is to aid testing hypervisor retrieve
request, when it faults in the middle of the operation.
Also added two helpers to access the size of a fragment
and the total size for both ABIs:
- FFA_MEM_RETRIEVE_RESP.
- FFA_MEM_FRAG_TX.
Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I49d12d69eff8c132b0a29954772dd6634f590f88
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index 917885f..4dc3f53 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -867,6 +867,21 @@
void ffa_hypervisor_retrieve_request_init(struct ffa_memory_region *region,
ffa_memory_handle_t handle);
+static inline uint32_t ffa_mem_retrieve_res_total_size(struct ffa_value ret)
+{
+ return ret.arg1;
+}
+
+static inline uint32_t ffa_mem_retrieve_res_frag_size(struct ffa_value ret)
+{
+ return ret.arg2;
+}
+
+static inline uint32_t ffa_mem_frag_tx_frag_size(struct ffa_value ret)
+{
+ return ret.arg3;
+}
+
uint32_t ffa_memory_region_init(
struct ffa_memory_region *memory_region, size_t memory_region_max_size,
ffa_id_t sender, struct ffa_memory_access receivers[],
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 3fe154a..c794cb0 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -116,6 +116,10 @@
uint32_t receiver_count, ffa_memory_region_flags_t flags,
bool is_normal_memory);
+bool hypervisor_retrieve_request_continue(
+ struct mailbox_buffers *mb, uint64_t handle, void *out, uint32_t out_size,
+ uint32_t total_size, uint32_t fragment_offset, bool release_rx);
+
bool hypervisor_retrieve_request(struct mailbox_buffers *mb, uint64_t handle,
void *out, uint32_t out_size);
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index 39c13b1..753d491 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -333,6 +333,99 @@
return true;
}
+/**
+ * Looping part of the fragmented retrieve request.
+ */
+bool hypervisor_retrieve_request_continue(
+ struct mailbox_buffers *mb, uint64_t handle, void *out, uint32_t out_size,
+ uint32_t total_size, uint32_t fragment_offset, bool release_rx)
+{
+ struct ffa_value ret;
+ uint32_t fragment_size;
+
+ if (mb == NULL) {
+ ERROR("Invalid parameters, please provide valid mailbox.\n");
+ return false;
+ }
+
+ while (fragment_offset < total_size) {
+ VERBOSE("Calling again. frag offset: %d; total: %d\n",
+ fragment_offset, total_size);
+
+ /* The first time it is called is controlled through arguments. */
+ if (release_rx) {
+ ret = ffa_rx_release();
+ if (ret.fid != FFA_SUCCESS_SMC32) {
+ ERROR("ffa_rx_release() failed: %d\n",
+ ffa_error_code(ret));
+ return false;
+ }
+ } else {
+ release_rx = true;
+ }
+
+ ret = ffa_mem_frag_rx(handle, fragment_offset);
+ if (ret.fid != FFA_MEM_FRAG_TX) {
+ ERROR("ffa_mem_frag_rx() failed: %d\n",
+ ffa_error_code(ret));
+ return false;
+ }
+
+ if (ffa_frag_handle(ret) != handle) {
+ ERROR("%s: fragment handle mismatch: expected %llu, got "
+ "%llu\n",
+ __func__, handle, ffa_frag_handle(ret));
+ return false;
+ }
+
+ /* Sender MBZ at physical instance. */
+ if (ffa_frag_sender(ret) != 0) {
+ ERROR("%s: fragment sender mismatch: expected %d, got "
+ "%d\n",
+ __func__, 0, ffa_frag_sender(ret));
+ return false;
+ }
+
+ fragment_size = ffa_mem_frag_tx_frag_size(ret);
+
+ if (fragment_size == 0) {
+ ERROR("%s: fragment size must not be 0\n", __func__);
+ return false;
+ }
+
+ if (out != NULL) {
+ if (fragment_offset + fragment_size > out_size) {
+ ERROR("%s: fragment is too big to fit in out buffer "
+ "(%d > %d)\n",
+ __func__, fragment_offset + fragment_size,
+ out_size);
+ return false;
+ }
+
+ VERBOSE("Copying fragment at offset %d with size %d\n",
+ fragment_offset, fragment_size);
+ memcpy((uint8_t *)out + fragment_offset, mb->recv,
+ fragment_size);
+ }
+
+ fragment_offset += fragment_size;
+ }
+
+ if (fragment_offset != total_size) {
+ ERROR("%s: fragment size mismatch: expected %d, got %d\n",
+ __func__, total_size, fragment_offset);
+ return false;
+ }
+
+ ret = ffa_rx_release();
+ if (ret.fid != FFA_SUCCESS_SMC32) {
+ ERROR("ffa_rx_release() failed: %d\n", ffa_error_code(ret));
+ return false;
+ }
+
+ return true;
+}
+
bool hypervisor_retrieve_request(struct mailbox_buffers *mb, uint64_t handle,
void *out, uint32_t out_size)
{
@@ -342,8 +435,8 @@
uint32_t fragment_offset;
struct ffa_memory_region *region_out = out;
- if (out == NULL || mb == NULL) {
- ERROR("Invalid parameters!\n");
+ if (mb == NULL) {
+ ERROR("Invalid parameters, please provide valid mailbox.\n");
return false;
}
@@ -363,112 +456,49 @@
* fragments is equal to total_size, the memory transaction has been
* completed.
*/
- total_size = ret.arg1;
- fragment_size = ret.arg2;
+ total_size = ffa_mem_retrieve_res_total_size(ret);
+ fragment_size = ffa_mem_retrieve_res_frag_size(ret);
+
fragment_offset = fragment_size;
VERBOSE("total_size=%d, fragment_size=%d, fragment_offset=%d\n",
total_size, fragment_size, fragment_offset);
- if (fragment_size > PAGE_SIZE) {
- ERROR("Fragment should be smaller than RX buffer!\n");
- return false;
- }
- if (total_size > out_size) {
- ERROR("output buffer is not large enough to store all "
- "fragments (total_size=%d, max_size=%d)\n",
- total_size, out_size);
- return false;
- }
-
- /*
- * Copy the received message to the out buffer. This is necessary
- * because `mb->recv` will be overwritten if sending a fragmented
- * message.
- */
- memcpy(out, mb->recv, fragment_size);
-
- if (region_out->receiver_count == 0) {
- VERBOSE("copied region has no recivers\n");
- return false;
- }
-
- if (region_out->receiver_count > MAX_MEM_SHARE_RECIPIENTS) {
- VERBOSE("SPMC memory sharing operations support max of %u "
- "receivers!\n",
- MAX_MEM_SHARE_RECIPIENTS);
- return false;
- }
-
- while (fragment_offset < total_size) {
- VERBOSE("Calling again. frag offset: %d; total: %d\n",
- fragment_offset, total_size);
- ret = ffa_rx_release();
- if (ret.fid != FFA_SUCCESS_SMC32) {
- ERROR("ffa_rx_release() failed: %d\n",
- ffa_error_code(ret));
+ if (out != NULL) {
+ if (fragment_size > PAGE_SIZE) {
+ ERROR("Fragment should be smaller than RX buffer!\n");
+ return false;
+ }
+ if (total_size > out_size) {
+ ERROR("Output buffer is not large enough to store all "
+ "fragments (total_size=%d, max_size=%d)\n",
+ total_size, out_size);
return false;
}
- ret = ffa_mem_frag_rx(handle, fragment_offset);
- if (ret.fid != FFA_MEM_FRAG_TX) {
- ERROR("ffa_mem_frag_rx() failed: %d\n",
- ffa_error_code(ret));
+ /*
+ * Copy the received message to the out buffer. This is necessary
+ * because `mb->recv` will be overwritten if sending a fragmented
+ * message.
+ */
+ memcpy(out, mb->recv, fragment_size);
+
+ if (region_out->receiver_count == 0) {
+ VERBOSE("Copied region has no recivers\n");
return false;
}
- if (ffa_frag_handle(ret) != handle) {
- ERROR("%s: fragment handle mismatch: expected %llu, "
- "got "
- "%llu\n",
- __func__, handle, ffa_frag_handle(ret));
+ if (region_out->receiver_count > MAX_MEM_SHARE_RECIPIENTS) {
+ VERBOSE("SPMC memory sharing operations support max of %u "
+ "receivers!\n",
+ MAX_MEM_SHARE_RECIPIENTS);
return false;
}
-
- /* Sender MBZ at physical instance. */
- if (ffa_frag_sender(ret) != 0) {
- ERROR("%s: fragment sender mismatch: expected %d, got "
- "%d\n",
- __func__, 0, ffa_frag_sender(ret));
- return false;
- }
-
- fragment_size = ret.arg2;
- if (fragment_size == 0) {
- ERROR("%s: fragment size must not be 0\n", __func__);
- return false;
- }
-
- if (fragment_offset + fragment_size > out_size) {
- ERROR("%s: fragment is too big to fit in out buffer "
- "(%d > %d)\n",
- __func__, fragment_offset + fragment_size,
- out_size);
- return false;
- }
-
- VERBOSE("copying fragment at offset %d with size %d\n",
- fragment_offset, fragment_size);
- memcpy((uint8_t *)out + fragment_offset, mb->recv,
- fragment_size);
-
- fragment_offset += fragment_size;
+ } else {
+ VERBOSE("%s: No output buffer provided...\n", __func__);
}
- if (fragment_offset != total_size) {
- ERROR("%s: fragment size mismatch: expected %d, got %d\n",
- __func__, total_size, fragment_offset);
- return false;
- }
-
- ret = ffa_rx_release();
- if (ret.fid != FFA_SUCCESS_SMC32) {
- ERROR("ffa_rx_release() failed: %d\n", ffa_error_code(ret));
- return false;
- }
-
- VERBOSE("Memory Retrieved!\n");
-
- return true;
+ return hypervisor_retrieve_request_continue(
+ mb, handle, out, out_size, total_size, fragment_offset, false);
}
bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,