195511698STamas Ban /* 295511698STamas Ban * Copyright (c) 2022-2024, Arm Limited. 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> 12*e249e569STamas Ban #include <drivers/arm/rse_comms.h> 1395511698STamas Ban #include <psa/client.h> 14*e249e569STamas 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 */ 19*e249e569STamas Ban union __packed __attribute__((aligned(4))) rse_comms_io_buffer_t { 20*e249e569STamas Ban struct serialized_rse_comms_msg_t msg; 21*e249e569STamas 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 { 2795511698STamas Ban size_t comms_mhu_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 4195511698STamas Ban comms_mhu_msg_size = mhu_get_max_message_size(); 4295511698STamas Ban 43*e249e569STamas Ban comms_embed_msg_min_size = sizeof(struct serialized_rse_comms_header_t) + 44*e249e569STamas Ban sizeof(struct rse_embed_msg_t) - 45*e249e569STamas Ban PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE; 4695511698STamas Ban 47*e249e569STamas Ban comms_embed_reply_min_size = sizeof(struct serialized_rse_comms_header_t) + 48*e249e569STamas Ban sizeof(struct rse_embed_reply_t) - 49*e249e569STamas Ban PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE; 5095511698STamas Ban 5195511698STamas Ban /* Use embed if we can pack into one message and reply, else use 5295511698STamas Ban * pointer_access. The underlying MHU transport protocol uses a 5395511698STamas Ban * single uint32_t to track the length, so the amount of data that 5495511698STamas Ban * can be in a message is 4 bytes less than mhu_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 > 6395511698STamas Ban comms_mhu_msg_size - sizeof(uint32_t)) || 6495511698STamas Ban (comms_embed_reply_min_size + out_size_total > 6595511698STamas Ban comms_mhu_msg_size - sizeof(uint32_t))) { 66*e249e569STamas Ban return RSE_COMMS_PROTOCOL_POINTER_ACCESS; 6795511698STamas Ban } else { 68*e249e569STamas 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 */ 78*e249e569STamas Ban static union rse_comms_io_buffer_t io_buf; 7995511698STamas Ban enum mhu_error_t 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 97*e249e569STamas 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 103*e249e569STamas 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 11295511698STamas Ban err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size); 11395511698STamas Ban if (err != MHU_ERR_NONE) { 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). 120*e249e569STamas Ban * Helps in detecting hypothetical RSE communication bugs. 12195511698STamas Ban */ 12295511698STamas Ban memset(&io_buf.msg, 0xA5, msg_size); 12395511698STamas Ban #endif 12495511698STamas Ban 12595511698STamas Ban err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size); 12695511698STamas Ban if (err != MHU_ERR_NONE) { 12795511698STamas Ban return PSA_ERROR_COMMUNICATION_FAILURE; 12895511698STamas Ban } 12995511698STamas Ban 130*e249e569STamas 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 135*e249e569STamas 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 14795511698STamas Ban /* Clear the MHU 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 155*e249e569STamas 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) { 162*e249e569STamas Ban INFO("[RSE-COMMS] Host to RSE MHU driver already initialized\n"); 16395511698STamas Ban } else { 164*e249e569STamas 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) { 172*e249e569STamas Ban INFO("[RSE-COMMS] RSE to Host MHU driver already initialized\n"); 17395511698STamas Ban } else { 174*e249e569STamas 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