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> 1195511698STamas Ban #include <drivers/arm/mhu.h> 12e249e569STamas Ban #include <drivers/arm/rse_comms.h> 1395511698STamas Ban #include <psa/client.h> 14e249e569STamas Ban #include <rse_comms_protocol.h> 1595511698STamas Ban 1695511698STamas Ban /* Union as message space and reply space are never used at the same time, and this saves space as 1795511698STamas Ban * we can overlap them. 1895511698STamas Ban */ 19e249e569STamas Ban union __packed __attribute__((aligned(4))) rse_comms_io_buffer_t { 20e249e569STamas Ban struct serialized_rse_comms_msg_t msg; 21e249e569STamas Ban struct serialized_rse_comms_reply_t reply; 2295511698STamas Ban }; 2395511698STamas Ban 2495511698STamas Ban static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len, 2595511698STamas Ban const psa_outvec *out_vec, size_t out_len) 2695511698STamas Ban { 27*36416b1eSYann Gautier size_t comms_mbx_msg_size; 2895511698STamas Ban size_t comms_embed_msg_min_size; 2995511698STamas Ban size_t comms_embed_reply_min_size; 3095511698STamas Ban size_t in_size_total = 0; 3195511698STamas Ban size_t out_size_total = 0; 3295511698STamas Ban size_t i; 3395511698STamas Ban 3495511698STamas Ban for (i = 0U; i < in_len; ++i) { 3595511698STamas Ban in_size_total += in_vec[i].len; 3695511698STamas Ban } 3795511698STamas Ban for (i = 0U; i < out_len; ++i) { 3895511698STamas Ban out_size_total += out_vec[i].len; 3995511698STamas Ban } 4095511698STamas Ban 41*36416b1eSYann Gautier comms_mbx_msg_size = rse_mbx_get_max_message_size(); 4295511698STamas Ban 43e249e569STamas Ban comms_embed_msg_min_size = sizeof(struct serialized_rse_comms_header_t) + 44e249e569STamas Ban sizeof(struct rse_embed_msg_t) - 45e249e569STamas Ban PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE; 4695511698STamas Ban 47e249e569STamas Ban comms_embed_reply_min_size = sizeof(struct serialized_rse_comms_header_t) + 48e249e569STamas Ban sizeof(struct rse_embed_reply_t) - 49e249e569STamas Ban PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE; 5095511698STamas Ban 5195511698STamas Ban /* Use embed if we can pack into one message and reply, else use 52*36416b1eSYann Gautier * pointer_access. The underlying mailbox transport protocol uses a 5395511698STamas Ban * single uint32_t to track the length, so the amount of data that 54*36416b1eSYann Gautier * can be in a message is 4 bytes less than rse_mbx_get_max_message_size 5595511698STamas Ban * reports. 5695511698STamas Ban * 5795511698STamas Ban * TODO tune this with real performance numbers, it's possible a 5895511698STamas Ban * pointer_access message is less performant than multiple embed 5995511698STamas Ban * messages due to ATU configuration costs to allow access to the 6095511698STamas Ban * pointers. 6195511698STamas Ban */ 6295511698STamas Ban if ((comms_embed_msg_min_size + in_size_total > 63*36416b1eSYann Gautier comms_mbx_msg_size - sizeof(uint32_t)) || 6495511698STamas Ban (comms_embed_reply_min_size + out_size_total > 65*36416b1eSYann Gautier comms_mbx_msg_size - sizeof(uint32_t))) { 66e249e569STamas Ban return RSE_COMMS_PROTOCOL_POINTER_ACCESS; 6795511698STamas Ban } else { 68e249e569STamas Ban return RSE_COMMS_PROTOCOL_EMBED; 6995511698STamas Ban } 7095511698STamas Ban } 7195511698STamas Ban 7295511698STamas Ban psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len, 7395511698STamas Ban psa_outvec *out_vec, size_t out_len) 7495511698STamas Ban { 7595511698STamas Ban /* Declared statically to avoid using huge amounts of stack space. Maybe revisit if 7695511698STamas Ban * functions not being reentrant becomes a problem. 7795511698STamas Ban */ 78e249e569STamas Ban static union rse_comms_io_buffer_t io_buf; 79*36416b1eSYann Gautier int err; 8095511698STamas Ban psa_status_t status; 8195511698STamas Ban static uint8_t seq_num = 1U; 8295511698STamas Ban size_t msg_size; 8395511698STamas Ban size_t reply_size = sizeof(io_buf.reply); 8495511698STamas Ban psa_status_t return_val; 8595511698STamas Ban size_t idx; 8695511698STamas Ban 8795511698STamas Ban if (type > PSA_CALL_TYPE_MAX || type < PSA_CALL_TYPE_MIN || 8895511698STamas Ban in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) { 8995511698STamas Ban return PSA_ERROR_INVALID_ARGUMENT; 9095511698STamas Ban } 9195511698STamas Ban 9295511698STamas Ban io_buf.msg.header.seq_num = seq_num, 9395511698STamas Ban /* No need to distinguish callers (currently concurrent calls are not supported). */ 9495511698STamas Ban io_buf.msg.header.client_id = 1U, 9595511698STamas Ban io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len); 9695511698STamas Ban 97e249e569STamas Ban status = rse_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec, 9895511698STamas Ban out_len, &io_buf.msg, &msg_size); 9995511698STamas Ban if (status != PSA_SUCCESS) { 10095511698STamas Ban return status; 10195511698STamas Ban } 10295511698STamas Ban 103e249e569STamas Ban VERBOSE("[RSE-COMMS] Sending message\n"); 10495511698STamas Ban VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver); 10595511698STamas Ban VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num); 10695511698STamas Ban VERBOSE("client_id=%u\n", io_buf.msg.header.client_id); 10795511698STamas Ban for (idx = 0; idx < in_len; idx++) { 10895511698STamas Ban VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len); 10995511698STamas Ban VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base); 11095511698STamas Ban } 11195511698STamas Ban 112*36416b1eSYann Gautier err = rse_mbx_send_data((uint8_t *)&io_buf.msg, msg_size); 113*36416b1eSYann Gautier if (err != 0) { 11495511698STamas Ban return PSA_ERROR_COMMUNICATION_FAILURE; 11595511698STamas Ban } 11695511698STamas Ban 11795511698STamas Ban #if DEBUG 11895511698STamas Ban /* 11995511698STamas Ban * Poisoning the message buffer (with a known pattern). 120e249e569STamas Ban * Helps in detecting hypothetical RSE communication bugs. 12195511698STamas Ban */ 12295511698STamas Ban memset(&io_buf.msg, 0xA5, msg_size); 12395511698STamas Ban #endif 12495511698STamas Ban 125*36416b1eSYann Gautier err = rse_mbx_receive_data((uint8_t *)&io_buf.reply, &reply_size); 126*36416b1eSYann Gautier if (err != 0) { 12795511698STamas Ban return PSA_ERROR_COMMUNICATION_FAILURE; 12895511698STamas Ban } 12995511698STamas Ban 130e249e569STamas Ban VERBOSE("[RSE-COMMS] Received reply\n"); 13195511698STamas Ban VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver); 13295511698STamas Ban VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num); 13395511698STamas Ban VERBOSE("client_id=%u\n", io_buf.reply.header.client_id); 13495511698STamas Ban 135e249e569STamas Ban status = rse_protocol_deserialize_reply(out_vec, out_len, &return_val, 13695511698STamas Ban &io_buf.reply, reply_size); 13795511698STamas Ban if (status != PSA_SUCCESS) { 13895511698STamas Ban return status; 13995511698STamas Ban } 14095511698STamas Ban 14195511698STamas Ban VERBOSE("return_val=%d\n", return_val); 14295511698STamas Ban for (idx = 0U; idx < out_len; idx++) { 14395511698STamas Ban VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len); 14495511698STamas Ban VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base); 14595511698STamas Ban } 14695511698STamas Ban 147*36416b1eSYann Gautier /* Clear the mailbox message buffer to remove assets from memory */ 14895511698STamas Ban memset(&io_buf, 0x0, sizeof(io_buf)); 14995511698STamas Ban 15095511698STamas Ban seq_num++; 15195511698STamas Ban 15295511698STamas Ban return return_val; 15395511698STamas Ban } 15495511698STamas Ban 155e249e569STamas Ban int rse_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base) 15695511698STamas Ban { 15795511698STamas Ban enum mhu_error_t err; 15895511698STamas Ban 15995511698STamas Ban err = mhu_init_sender(mhu_sender_base); 16095511698STamas Ban if (err != MHU_ERR_NONE) { 16195511698STamas Ban if (err == MHU_ERR_ALREADY_INIT) { 162e249e569STamas Ban INFO("[RSE-COMMS] Host to RSE MHU driver already initialized\n"); 16395511698STamas Ban } else { 164e249e569STamas Ban ERROR("[RSE-COMMS] Host to RSE MHU driver initialization failed: %d\n", err); 16595511698STamas Ban return -1; 16695511698STamas Ban } 16795511698STamas Ban } 16895511698STamas Ban 16995511698STamas Ban err = mhu_init_receiver(mhu_receiver_base); 17095511698STamas Ban if (err != MHU_ERR_NONE) { 17195511698STamas Ban if (err == MHU_ERR_ALREADY_INIT) { 172e249e569STamas Ban INFO("[RSE-COMMS] RSE to Host MHU driver already initialized\n"); 17395511698STamas Ban } else { 174e249e569STamas Ban ERROR("[RSE-COMMS] RSE to Host MHU driver initialization failed: %d\n", err); 17595511698STamas Ban return -1; 17695511698STamas Ban } 17795511698STamas Ban } 17895511698STamas Ban 17995511698STamas Ban return 0; 18095511698STamas Ban } 181