rse_comms: Use carveout region for pointer access protocol
The Pointer access protocol requires sending physical addresses of
payload buffers. A carveout region is introduced to exchange the
payload with the RSE. Copy the invec buffers to the region, reserve
space for outvec buffers. The physical address of the region is known.
The physical address of the buffers in the region can be calculated.
Signed-off-by: Michael Zhao <michael.zhao2@arm.com>
Change-Id: Id8c0f1454d1826b23df58550fbce9807c7f9f4ae
diff --git a/components/messaging/rse_comms/sp/rse_comms_messenger.c b/components/messaging/rse_comms/sp/rse_comms_messenger.c
index 48988f1..1d5f16d 100644
--- a/components/messaging/rse_comms/sp/rse_comms_messenger.c
+++ b/components/messaging/rse_comms/sp/rse_comms_messenger.c
@@ -9,21 +9,29 @@
#include <stdlib.h>
#include <trace.h>
+#include "config/interface/config_store.h"
+#include "platform/interface/device_region.h"
#include "protocols/rpc/common/packed-c/status.h"
#include "rse_comms_messenger_api.h"
#include "rse_comms_platform_api.h"
-struct rse_comms_msg {
- uint8_t *req_buf;
- size_t req_len;
- uint8_t *resp_buf;
-};
+static struct device_region *rse_comms_messenger_protocol_init() {
+ static struct device_region carveout_region;
+
+ if (!config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION,
+ "rse-carveout",
+ 0, &carveout_region,
+ sizeof(carveout_region))) {
+ IMSG("rse-carveout is not set in SP configuration");
+ return NULL;
+ }
+
+ return &carveout_region;
+}
int rse_comms_messenger_init(struct rse_comms_messenger *rse_comms)
{
- int ret = 0;
-
- if (!rse_comms || rse_comms->msg || rse_comms->platform)
+ if (!rse_comms || rse_comms->msg || rse_comms->platform || rse_comms->protocol)
return -1;
rse_comms->msg = calloc(1, sizeof(struct rse_comms_msg));
@@ -35,9 +43,11 @@
EMSG("Platform init failed");
free(rse_comms->msg);
rse_comms->msg = NULL;
- return ret;
+ return -1;
}
+ rse_comms->protocol = rse_comms_messenger_protocol_init();
+
return 0;
}
@@ -62,6 +72,7 @@
rse_comms_platform_deinit(rse_comms->platform);
rse_comms->platform = NULL;
+ rse_comms->protocol = NULL;
}
int rse_comms_messenger_call_invoke(struct rse_comms_messenger *rse_comms, uint8_t **resp_buf,
diff --git a/components/messaging/rse_comms/sp/rse_comms_messenger_api.h b/components/messaging/rse_comms/sp/rse_comms_messenger_api.h
index fcf9c95..8f863bc 100644
--- a/components/messaging/rse_comms/sp/rse_comms_messenger_api.h
+++ b/components/messaging/rse_comms/sp/rse_comms_messenger_api.h
@@ -10,9 +10,16 @@
#include <stddef.h>
#include <stdint.h>
+struct rse_comms_msg {
+ uint8_t *req_buf;
+ size_t req_len;
+ uint8_t *resp_buf;
+};
+
struct rse_comms_messenger {
void *msg;
void *platform;
+ void *protocol;
};
int rse_comms_messenger_init(struct rse_comms_messenger *rse_comms);
diff --git a/components/rpc/rse_comms/caller/sp/rse_comms_caller.c b/components/rpc/rse_comms/caller/sp/rse_comms_caller.c
index 964b391..52c4fef 100644
--- a/components/rpc/rse_comms/caller/sp/rse_comms_caller.c
+++ b/components/rpc/rse_comms/caller/sp/rse_comms_caller.c
@@ -13,10 +13,6 @@
#include "rpc_caller.h"
#include "rpc_status.h"
-struct rse_comms_caller_context {
- struct rse_comms_messenger rse_comms;
-};
-
rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid, uint16_t endpoint_id)
{
return RPC_SUCCESS;
diff --git a/components/rpc/rse_comms/caller/sp/rse_comms_caller.h b/components/rpc/rse_comms/caller/sp/rse_comms_caller.h
index 7c8c38e..9c2b02f 100644
--- a/components/rpc/rse_comms/caller/sp/rse_comms_caller.h
+++ b/components/rpc/rse_comms/caller/sp/rse_comms_caller.h
@@ -10,6 +10,10 @@
#include "rpc_caller.h"
#include "rse_comms_messenger_api.h"
+struct rse_comms_caller_context {
+ struct rse_comms_messenger rse_comms;
+};
+
typedef void *rse_comms_call_handle;
rpc_status_t rse_comms_caller_init(struct rpc_caller_interface *rpc_caller);
diff --git a/components/rpc/rse_comms/caller/sp/rse_comms_protocol.c b/components/rpc/rse_comms/caller/sp/rse_comms_protocol.c
index 64a0bcc..591d994 100644
--- a/components/rpc/rse_comms/caller/sp/rse_comms_protocol.c
+++ b/components/rpc/rse_comms/caller/sp/rse_comms_protocol.c
@@ -8,7 +8,8 @@
#include "rse_comms_protocol.h"
-psa_status_t rse_protocol_serialize_msg(psa_handle_t handle,
+psa_status_t rse_protocol_serialize_msg(struct rpc_caller_interface *caller,
+ psa_handle_t handle,
int16_t type,
const struct psa_invec *in_vec,
uint8_t in_len,
@@ -32,7 +33,7 @@
}
break;
case RSE_COMMS_PROTOCOL_POINTER_ACCESS:
- status = rse_protocol_pointer_access_serialize_msg(handle, type, in_vec, in_len,
+ status = rse_protocol_pointer_access_serialize_msg(caller, handle, type, in_vec, in_len,
out_vec, out_len,
&msg->msg.pointer_access,
msg_len);
@@ -49,7 +50,8 @@
return PSA_SUCCESS;
}
-psa_status_t rse_protocol_deserialize_reply(struct psa_outvec *out_vec,
+psa_status_t rse_protocol_deserialize_reply(struct rpc_caller_interface *caller,
+ struct psa_outvec *out_vec,
uint8_t out_len,
psa_status_t *return_val,
const struct serialized_rse_comms_reply_t *reply,
@@ -63,7 +65,7 @@
return rse_protocol_embed_deserialize_reply(out_vec, out_len, return_val,
&reply->reply.embed, reply_size);
case RSE_COMMS_PROTOCOL_POINTER_ACCESS:
- return rse_protocol_pointer_access_deserialize_reply(out_vec, out_len, return_val,
+ return rse_protocol_pointer_access_deserialize_reply(caller, out_vec, out_len, return_val,
&reply->reply.pointer_access,
reply_size);
default:
diff --git a/components/rpc/rse_comms/caller/sp/rse_comms_protocol.h b/components/rpc/rse_comms/caller/sp/rse_comms_protocol.h
index 5c0f8a9..bccfcf3 100644
--- a/components/rpc/rse_comms/caller/sp/rse_comms_protocol.h
+++ b/components/rpc/rse_comms/caller/sp/rse_comms_protocol.h
@@ -44,7 +44,8 @@
} reply;
};
-psa_status_t rse_protocol_serialize_msg(psa_handle_t handle,
+psa_status_t rse_protocol_serialize_msg(struct rpc_caller_interface *caller,
+ psa_handle_t handle,
int16_t type,
const struct psa_invec *in_vec,
uint8_t in_len,
@@ -53,7 +54,8 @@
struct serialized_rse_comms_msg_t *msg,
size_t *msg_len);
-psa_status_t rse_protocol_deserialize_reply(struct psa_outvec *out_vec,
+psa_status_t rse_protocol_deserialize_reply(struct rpc_caller_interface *caller,
+ struct psa_outvec *out_vec,
uint8_t out_len,
psa_status_t *return_val,
const struct serialized_rse_comms_reply_t *reply,
diff --git a/components/rpc/rse_comms/caller/sp/rse_comms_protocol_common.h b/components/rpc/rse_comms/caller/sp/rse_comms_protocol_common.h
index 235ea92..fec1f45 100644
--- a/components/rpc/rse_comms/caller/sp/rse_comms_protocol_common.h
+++ b/components/rpc/rse_comms/caller/sp/rse_comms_protocol_common.h
@@ -32,4 +32,7 @@
((((uint32_t)(in_len)) << IN_LEN_OFFSET) & IN_LEN_MASK) | \
((((uint32_t)(out_len)) << OUT_LEN_OFFSET) & OUT_LEN_MASK))
+#define PARAM_UNPACK_IN_LEN(ctrl_param) \
+ ((size_t)(((ctrl_param) & IN_LEN_MASK) >> IN_LEN_OFFSET))
+
#endif /* RSE_COMMS_PROTOCOL_COMMON */
diff --git a/components/rpc/rse_comms/caller/sp/rse_comms_protocol_pointer_access.c b/components/rpc/rse_comms/caller/sp/rse_comms_protocol_pointer_access.c
index b6f817c..f34a9cd 100644
--- a/components/rpc/rse_comms/caller/sp/rse_comms_protocol_pointer_access.c
+++ b/components/rpc/rse_comms/caller/sp/rse_comms_protocol_pointer_access.c
@@ -5,11 +5,73 @@
*
*/
#include <assert.h>
+#include <string.h>
+#include "platform/interface/device_region.h"
+#include "rse_comms_caller.h"
+#include "rse_comms_protocol.h"
#include "rse_comms_protocol_common.h"
#include "rse_comms_protocol_pointer_access.h"
-psa_status_t rse_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+/*
+ * For the pointer access protocol, the pointers sent in the RSE message must be physical addresses.
+ * But the base addresses in the invec and outvec are virtual.
+ *
+ * A carveout memory region is used for exchanging the invec and outvec data with the RSE:
+ * - The invec payload data is copied to the carveout region, the physical address of the buffer
+ * in the carveout region is sent to the RSE.
+ * - The space for outvec payload data is reserved in the carveout region. The physical address of
+ * the reserved buffer is sent to the RSE. When a reply is received from the RSE, data has been
+ * written to the buffer. Copy the data from the carveout region to the outvec buffer.
+ *
+ * The physical address and virtual address of the region are available:
+ * - The carveout region is reserved via device tree
+ * - The physical address and size of the region is configurable
+ * - The virtual address of the region is obtained from SP input parameters
+ *
+ * Invec/Outvec buffer handling for RSE message:
+ * - Calculate the offset of the payload buffer in the carveout region
+ * - buffer_physical_address = carveout_physical_address + offset
+ * - buffer_virtual_address = carveout_virtual_address + offset
+ * - For invec buffer:
+ * - Copy the invec data to buffer_virtual_address
+ * - For outvec buffer:
+ * - Reserve the space from buffer_virtual_address in the carveout region to receive RSE output
+ *
+ * Outvec buffer handling for RSE reply:
+ * - Calculate the offset of the outvec payload in the carveout region
+ * - buffer_virtual_address = carveout_virtual_address + offset
+ * - Copy the payload from buffer_virtual_address to the outvec buffer
+ *
+ * Here is an example layout of the carveout region for an RSE message that has 2 invec buffers
+ * (0x100 and 0x200 in size) and 2 outvec buffers (0x300 and 0x400 in size).
+ *
+ * `#` area is invec data to RSE
+ * `.` area is reserved for RSE output
+ *
+ * Virtual Address | Physical Address
+ * +---------------+ <-- 0x4004C000 | 0xFFFFC000
+ * |###############|
+ * |## in_vec[0] ##|
+ * |###############|
+ * +---------------+ <-- 0x4004C100 | 0xFFFFC100
+ * |###############|
+ * |## in_vec[1] ##|
+ * |###############|
+ * +---------------+ <-- 0x4004C300 | 0xFFFFC300
+ * |...............|
+ * |.. out_vec[0] .|
+ * |...............|
+ * +---------------+ <-- 0x4004C600 | 0xFFFFC600
+ * |...............|
+ * |.. out_vec[1] .|
+ * |...............|
+ * +---------------+ <-- 0x4004CA00 | 0xFFFFCA00
+ *
+ */
+
+psa_status_t rse_protocol_pointer_access_serialize_msg(struct rpc_caller_interface *caller,
+ psa_handle_t handle,
int16_t type,
const struct psa_invec *in_vec,
uint8_t in_len,
@@ -18,23 +80,53 @@
struct rse_pointer_access_msg_t *msg,
size_t *msg_len)
{
+ struct rse_comms_caller_context *context =
+ (struct rse_comms_caller_context *)caller->context;
+ struct rse_comms_messenger *rse_comms = &context->rse_comms;
+ struct device_region *carveout_region =
+ (struct device_region *)rse_comms->protocol;
+ uint64_t carveout_phys_addr;
+ uint64_t carveout_virt_addr;
+ uint64_t offset_in_carveout = 0;
+ uint64_t virt_addr_in_carveout;
unsigned int i;
assert(msg != NULL);
assert(msg_len != NULL);
assert(in_vec != NULL);
+ assert(carveout_region != NULL);
+ carveout_phys_addr = carveout_region->phys_addr;
+ carveout_virt_addr = carveout_region->base_addr;
msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
msg->handle = handle;
- /* Fill msg iovec lengths */
+ /* Check if all the data can fit in the carveout region*/
for (i = 0U; i < in_len; ++i) {
- msg->io_sizes[i] = in_vec[i].len;
- msg->host_ptrs[i] = (uint64_t)in_vec[i].base;
+ offset_in_carveout += in_vec[i].len;
}
for (i = 0U; i < out_len; ++i) {
+ offset_in_carveout += out_vec[i].len;
+ }
+ if (offset_in_carveout > carveout_region->io_region_size) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ /* Fill msg iovec lengths */
+ offset_in_carveout = 0;
+ for (i = 0U; i < in_len; ++i) {
+ msg->host_ptrs[i] = carveout_phys_addr + offset_in_carveout;
+ msg->io_sizes[i] = in_vec[i].len;
+ virt_addr_in_carveout = carveout_virt_addr + offset_in_carveout;
+ memcpy((void *)virt_addr_in_carveout, psa_u32_to_ptr(in_vec[i].base),
+ in_vec[i].len);
+ offset_in_carveout += in_vec[i].len;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ msg->host_ptrs[in_len + i] =
+ carveout_phys_addr + offset_in_carveout;
msg->io_sizes[in_len + i] = out_vec[i].len;
- msg->host_ptrs[in_len + i] = (uint64_t)out_vec[i].base;
+ offset_in_carveout += out_vec[i].len;
}
*msg_len = sizeof(*msg);
@@ -42,19 +134,60 @@
return PSA_SUCCESS;
}
-psa_status_t rse_protocol_pointer_access_deserialize_reply(struct psa_outvec *out_vec,
- uint8_t out_len,
- psa_status_t *return_val,
- const struct rse_pointer_access_reply_t *reply,
- size_t reply_size)
+psa_status_t rse_protocol_pointer_access_deserialize_reply(struct rpc_caller_interface *caller,
+ struct psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rse_pointer_access_reply_t *reply,
+ size_t reply_size)
{
+ struct rse_comms_caller_context *context =
+ (struct rse_comms_caller_context *)caller->context;
+ struct rse_comms_messenger *rse_comms = &context->rse_comms;
+ struct device_region *carveout_region =
+ (struct device_region *)rse_comms->protocol;
+ struct rse_comms_msg *rse_comms_msg =
+ (struct rse_comms_msg *)rse_comms->msg;
+ struct serialized_rse_comms_msg_t *serialized_rse_comms_msg =
+ (struct serialized_rse_comms_msg_t *)rse_comms_msg->req_buf;
+ struct rse_pointer_access_msg_t *pointer_access_msg =
+ (struct rse_pointer_access_msg_t *)&serialized_rse_comms_msg->msg;
+ uint8_t in_len = PARAM_UNPACK_IN_LEN(pointer_access_msg->ctrl_param);
+ uint64_t carveout_phys_addr;
+ uint64_t carveout_virt_addr;
+ uint64_t offset_in_carveout = 0;
+ uint64_t virt_addr_in_carveout;
unsigned int i;
assert(reply != NULL);
assert(return_val != NULL);
+ assert(carveout_region != NULL);
+ carveout_phys_addr = carveout_region->phys_addr;
+ carveout_virt_addr = carveout_region->base_addr;
+
+ /* Check if the reply data is still in the carveout boundary */
+ for (i = 0U; i < in_len; ++i) {
+ offset_in_carveout += pointer_access_msg->io_sizes[i];
+ }
for (i = 0U; i < out_len; ++i) {
- out_vec[i].len = reply->out_sizes[i];
+ offset_in_carveout += reply->out_sizes[i];
+ }
+ if (offset_in_carveout > carveout_region->io_region_size) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (reply->return_val == PSA_SUCCESS) {
+ for (i = 0U; i < out_len; ++i) {
+ out_vec[i].len = reply->out_sizes[i];
+ virt_addr_in_carveout =
+ pointer_access_msg->host_ptrs[in_len + i] -
+ carveout_phys_addr +
+ carveout_virt_addr;
+ memcpy(psa_u32_to_ptr(out_vec[i].base),
+ (void *)virt_addr_in_carveout,
+ out_vec[i].len);
+ }
}
*return_val = reply->return_val;
diff --git a/components/rpc/rse_comms/caller/sp/rse_comms_protocol_pointer_access.h b/components/rpc/rse_comms/caller/sp/rse_comms_protocol_pointer_access.h
index 5a59477..87ac9ee 100644
--- a/components/rpc/rse_comms/caller/sp/rse_comms_protocol_pointer_access.h
+++ b/components/rpc/rse_comms/caller/sp/rse_comms_protocol_pointer_access.h
@@ -24,7 +24,8 @@
uint32_t out_sizes[PSA_MAX_IOVEC];
};
-psa_status_t rse_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+psa_status_t rse_protocol_pointer_access_serialize_msg(struct rpc_caller_interface *caller,
+ psa_handle_t handle,
int16_t type,
const struct psa_invec *in_vec,
uint8_t in_len,
@@ -33,7 +34,8 @@
struct rse_pointer_access_msg_t *msg,
size_t *msg_len);
-psa_status_t rse_protocol_pointer_access_deserialize_reply(struct psa_outvec *out_vec,
+psa_status_t rse_protocol_pointer_access_deserialize_reply(struct rpc_caller_interface *caller,
+ struct psa_outvec *out_vec,
uint8_t out_len,
psa_status_t *return_val,
const struct rse_pointer_access_reply_t *reply,
diff --git a/components/rpc/rse_comms/rse_comms.c b/components/rpc/rse_comms/rse_comms.c
index ac474f8..e087072 100644
--- a/components/rpc/rse_comms/rse_comms.c
+++ b/components/rpc/rse_comms/rse_comms.c
@@ -117,8 +117,8 @@
req->header.protocol_ver = protocol_ver;
- psa_status = rse_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec, out_len, req,
- &req_len);
+ psa_status = rse_protocol_serialize_msg(caller, handle, type, in_vec, in_len, out_vec,
+ out_len, req, &req_len);
if (psa_status != PSA_SUCCESS) {
EMSG("Serialize msg failed: %d", psa_status);
return psa_status;
@@ -143,7 +143,8 @@
DMSG("client_id=%u", reply->header.client_id);
DMSG("resp_len=%lu", resp_len);
- psa_status = rse_protocol_deserialize_reply(out_vec, out_len, &return_val, reply, resp_len);
+ psa_status = rse_protocol_deserialize_reply(caller, out_vec, out_len, &return_val, reply,
+ resp_len);
if (psa_status != PSA_SUCCESS) {
EMSG("Protocol deserialize reply failed: %d", psa_status);
return psa_status;