195511698STamas Ban /*
2*36416b1eSYann Gautier * Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
395511698STamas Ban *
495511698STamas Ban * SPDX-License-Identifier: BSD-3-Clause
595511698STamas Ban */
695511698STamas Ban
795511698STamas Ban #include <stdint.h>
895511698STamas Ban #include <string.h>
995511698STamas Ban
1095511698STamas Ban #include <common/debug.h>
11e249e569STamas Ban #include <drivers/arm/rse_comms.h>
1295511698STamas Ban #include <psa/client.h>
13e249e569STamas Ban #include <rse_comms_protocol.h>
1495511698STamas Ban
1595511698STamas Ban /* Union as message space and reply space are never used at the same time, and this saves space as
1695511698STamas Ban * we can overlap them.
1795511698STamas Ban */
18e249e569STamas Ban union __packed __attribute__((aligned(4))) rse_comms_io_buffer_t {
19e249e569STamas Ban struct serialized_rse_comms_msg_t msg;
20e249e569STamas Ban struct serialized_rse_comms_reply_t reply;
2195511698STamas Ban };
2295511698STamas Ban
select_protocol_version(const psa_invec * in_vec,size_t in_len,const psa_outvec * out_vec,size_t out_len)2395511698STamas Ban static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len,
2495511698STamas Ban const psa_outvec *out_vec, size_t out_len)
2595511698STamas Ban {
26*36416b1eSYann Gautier size_t comms_mbx_msg_size;
2795511698STamas Ban size_t comms_embed_msg_min_size;
2895511698STamas Ban size_t comms_embed_reply_min_size;
2995511698STamas Ban size_t in_size_total = 0;
3095511698STamas Ban size_t out_size_total = 0;
3195511698STamas Ban size_t i;
3295511698STamas Ban
3395511698STamas Ban for (i = 0U; i < in_len; ++i) {
3495511698STamas Ban in_size_total += in_vec[i].len;
3595511698STamas Ban }
3695511698STamas Ban for (i = 0U; i < out_len; ++i) {
3795511698STamas Ban out_size_total += out_vec[i].len;
3895511698STamas Ban }
3995511698STamas Ban
40*36416b1eSYann Gautier comms_mbx_msg_size = rse_mbx_get_max_message_size();
4195511698STamas Ban
42e249e569STamas Ban comms_embed_msg_min_size = sizeof(struct serialized_rse_comms_header_t) +
43e249e569STamas Ban sizeof(struct rse_embed_msg_t) -
44e249e569STamas Ban PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE;
4595511698STamas Ban
46e249e569STamas Ban comms_embed_reply_min_size = sizeof(struct serialized_rse_comms_header_t) +
47e249e569STamas Ban sizeof(struct rse_embed_reply_t) -
48e249e569STamas Ban PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE;
4995511698STamas Ban
5095511698STamas Ban /* Use embed if we can pack into one message and reply, else use
51*36416b1eSYann Gautier * pointer_access. The underlying mailbox transport protocol uses a
5295511698STamas Ban * single uint32_t to track the length, so the amount of data that
53*36416b1eSYann Gautier * can be in a message is 4 bytes less than rse_mbx_get_max_message_size
5495511698STamas Ban * reports.
5595511698STamas Ban *
5695511698STamas Ban * TODO tune this with real performance numbers, it's possible a
5795511698STamas Ban * pointer_access message is less performant than multiple embed
5895511698STamas Ban * messages due to ATU configuration costs to allow access to the
5995511698STamas Ban * pointers.
6095511698STamas Ban */
6195511698STamas Ban if ((comms_embed_msg_min_size + in_size_total >
62*36416b1eSYann Gautier comms_mbx_msg_size - sizeof(uint32_t)) ||
6395511698STamas Ban (comms_embed_reply_min_size + out_size_total >
64*36416b1eSYann Gautier comms_mbx_msg_size - sizeof(uint32_t))) {
65e249e569STamas Ban return RSE_COMMS_PROTOCOL_POINTER_ACCESS;
6695511698STamas Ban } else {
67e249e569STamas Ban return RSE_COMMS_PROTOCOL_EMBED;
6895511698STamas Ban }
6995511698STamas Ban }
7095511698STamas Ban
psa_call(psa_handle_t handle,int32_t type,const psa_invec * in_vec,size_t in_len,psa_outvec * out_vec,size_t out_len)7195511698STamas Ban psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
7295511698STamas Ban psa_outvec *out_vec, size_t out_len)
7395511698STamas Ban {
7495511698STamas Ban /* Declared statically to avoid using huge amounts of stack space. Maybe revisit if
7595511698STamas Ban * functions not being reentrant becomes a problem.
7695511698STamas Ban */
77e249e569STamas Ban static union rse_comms_io_buffer_t io_buf;
78*36416b1eSYann Gautier int err;
7995511698STamas Ban psa_status_t status;
8095511698STamas Ban static uint8_t seq_num = 1U;
8195511698STamas Ban size_t msg_size;
8295511698STamas Ban size_t reply_size = sizeof(io_buf.reply);
8395511698STamas Ban psa_status_t return_val;
8495511698STamas Ban size_t idx;
8595511698STamas Ban
8695511698STamas Ban if (type > PSA_CALL_TYPE_MAX || type < PSA_CALL_TYPE_MIN ||
8795511698STamas Ban in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
8895511698STamas Ban return PSA_ERROR_INVALID_ARGUMENT;
8995511698STamas Ban }
9095511698STamas Ban
9195511698STamas Ban io_buf.msg.header.seq_num = seq_num,
9295511698STamas Ban /* No need to distinguish callers (currently concurrent calls are not supported). */
9395511698STamas Ban io_buf.msg.header.client_id = 1U,
9495511698STamas Ban io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
9595511698STamas Ban
96e249e569STamas Ban status = rse_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec,
9795511698STamas Ban out_len, &io_buf.msg, &msg_size);
9895511698STamas Ban if (status != PSA_SUCCESS) {
9995511698STamas Ban return status;
10095511698STamas Ban }
10195511698STamas Ban
102e249e569STamas Ban VERBOSE("[RSE-COMMS] Sending message\n");
10395511698STamas Ban VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver);
10495511698STamas Ban VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num);
10595511698STamas Ban VERBOSE("client_id=%u\n", io_buf.msg.header.client_id);
10695511698STamas Ban for (idx = 0; idx < in_len; idx++) {
10795511698STamas Ban VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
10895511698STamas Ban VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
10995511698STamas Ban }
11095511698STamas Ban
111*36416b1eSYann Gautier err = rse_mbx_send_data((uint8_t *)&io_buf.msg, msg_size);
112*36416b1eSYann Gautier if (err != 0) {
11395511698STamas Ban return PSA_ERROR_COMMUNICATION_FAILURE;
11495511698STamas Ban }
11595511698STamas Ban
11695511698STamas Ban #if DEBUG
11795511698STamas Ban /*
11895511698STamas Ban * Poisoning the message buffer (with a known pattern).
119e249e569STamas Ban * Helps in detecting hypothetical RSE communication bugs.
12095511698STamas Ban */
12195511698STamas Ban memset(&io_buf.msg, 0xA5, msg_size);
12295511698STamas Ban #endif
12395511698STamas Ban
124*36416b1eSYann Gautier err = rse_mbx_receive_data((uint8_t *)&io_buf.reply, &reply_size);
125*36416b1eSYann Gautier if (err != 0) {
12695511698STamas Ban return PSA_ERROR_COMMUNICATION_FAILURE;
12795511698STamas Ban }
12895511698STamas Ban
129e249e569STamas Ban VERBOSE("[RSE-COMMS] Received reply\n");
13095511698STamas Ban VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver);
13195511698STamas Ban VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num);
13295511698STamas Ban VERBOSE("client_id=%u\n", io_buf.reply.header.client_id);
13395511698STamas Ban
134e249e569STamas Ban status = rse_protocol_deserialize_reply(out_vec, out_len, &return_val,
13595511698STamas Ban &io_buf.reply, reply_size);
13695511698STamas Ban if (status != PSA_SUCCESS) {
13795511698STamas Ban return status;
13895511698STamas Ban }
13995511698STamas Ban
14095511698STamas Ban VERBOSE("return_val=%d\n", return_val);
14195511698STamas Ban for (idx = 0U; idx < out_len; idx++) {
14295511698STamas Ban VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
14395511698STamas Ban VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
14495511698STamas Ban }
14595511698STamas Ban
146*36416b1eSYann Gautier /* Clear the mailbox message buffer to remove assets from memory */
14795511698STamas Ban memset(&io_buf, 0x0, sizeof(io_buf));
14895511698STamas Ban
14995511698STamas Ban seq_num++;
15095511698STamas Ban
15195511698STamas Ban return return_val;
15295511698STamas Ban }
153