1 /* 2 * Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdint.h> 8 #include <string.h> 9 10 #include <common/debug.h> 11 #include <drivers/arm/rse_comms.h> 12 #include <psa/client.h> 13 #include <rse_comms_protocol.h> 14 15 /* Union as message space and reply space are never used at the same time, and this saves space as 16 * we can overlap them. 17 */ 18 union __packed __attribute__((aligned(4))) rse_comms_io_buffer_t { 19 struct serialized_rse_comms_msg_t msg; 20 struct serialized_rse_comms_reply_t reply; 21 }; 22 23 static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len, 24 const psa_outvec *out_vec, size_t out_len) 25 { 26 size_t comms_mbx_msg_size; 27 size_t comms_embed_msg_min_size; 28 size_t comms_embed_reply_min_size; 29 size_t in_size_total = 0; 30 size_t out_size_total = 0; 31 size_t i; 32 33 for (i = 0U; i < in_len; ++i) { 34 in_size_total += in_vec[i].len; 35 } 36 for (i = 0U; i < out_len; ++i) { 37 out_size_total += out_vec[i].len; 38 } 39 40 comms_mbx_msg_size = rse_mbx_get_max_message_size(); 41 42 comms_embed_msg_min_size = sizeof(struct serialized_rse_comms_header_t) + 43 sizeof(struct rse_embed_msg_t) - 44 PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE; 45 46 comms_embed_reply_min_size = sizeof(struct serialized_rse_comms_header_t) + 47 sizeof(struct rse_embed_reply_t) - 48 PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE; 49 50 /* Use embed if we can pack into one message and reply, else use 51 * pointer_access. The underlying mailbox transport protocol uses a 52 * single uint32_t to track the length, so the amount of data that 53 * can be in a message is 4 bytes less than rse_mbx_get_max_message_size 54 * reports. 55 * 56 * TODO tune this with real performance numbers, it's possible a 57 * pointer_access message is less performant than multiple embed 58 * messages due to ATU configuration costs to allow access to the 59 * pointers. 60 */ 61 if ((comms_embed_msg_min_size + in_size_total > 62 comms_mbx_msg_size - sizeof(uint32_t)) || 63 (comms_embed_reply_min_size + out_size_total > 64 comms_mbx_msg_size - sizeof(uint32_t))) { 65 return RSE_COMMS_PROTOCOL_POINTER_ACCESS; 66 } else { 67 return RSE_COMMS_PROTOCOL_EMBED; 68 } 69 } 70 71 psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len, 72 psa_outvec *out_vec, size_t out_len) 73 { 74 /* Declared statically to avoid using huge amounts of stack space. Maybe revisit if 75 * functions not being reentrant becomes a problem. 76 */ 77 static union rse_comms_io_buffer_t io_buf; 78 int err; 79 psa_status_t status; 80 static uint8_t seq_num = 1U; 81 size_t msg_size; 82 size_t reply_size = sizeof(io_buf.reply); 83 psa_status_t return_val; 84 size_t idx; 85 86 if (type > PSA_CALL_TYPE_MAX || type < PSA_CALL_TYPE_MIN || 87 in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) { 88 return PSA_ERROR_INVALID_ARGUMENT; 89 } 90 91 io_buf.msg.header.seq_num = seq_num, 92 /* No need to distinguish callers (currently concurrent calls are not supported). */ 93 io_buf.msg.header.client_id = 1U, 94 io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len); 95 96 status = rse_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec, 97 out_len, &io_buf.msg, &msg_size); 98 if (status != PSA_SUCCESS) { 99 return status; 100 } 101 102 VERBOSE("[RSE-COMMS] Sending message\n"); 103 VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver); 104 VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num); 105 VERBOSE("client_id=%u\n", io_buf.msg.header.client_id); 106 for (idx = 0; idx < in_len; idx++) { 107 VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len); 108 VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base); 109 } 110 111 err = rse_mbx_send_data((uint8_t *)&io_buf.msg, msg_size); 112 if (err != 0) { 113 return PSA_ERROR_COMMUNICATION_FAILURE; 114 } 115 116 #if DEBUG 117 /* 118 * Poisoning the message buffer (with a known pattern). 119 * Helps in detecting hypothetical RSE communication bugs. 120 */ 121 memset(&io_buf.msg, 0xA5, msg_size); 122 #endif 123 124 err = rse_mbx_receive_data((uint8_t *)&io_buf.reply, &reply_size); 125 if (err != 0) { 126 return PSA_ERROR_COMMUNICATION_FAILURE; 127 } 128 129 VERBOSE("[RSE-COMMS] Received reply\n"); 130 VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver); 131 VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num); 132 VERBOSE("client_id=%u\n", io_buf.reply.header.client_id); 133 134 status = rse_protocol_deserialize_reply(out_vec, out_len, &return_val, 135 &io_buf.reply, reply_size); 136 if (status != PSA_SUCCESS) { 137 return status; 138 } 139 140 VERBOSE("return_val=%d\n", return_val); 141 for (idx = 0U; idx < out_len; idx++) { 142 VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len); 143 VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base); 144 } 145 146 /* Clear the mailbox message buffer to remove assets from memory */ 147 memset(&io_buf, 0x0, sizeof(io_buf)); 148 149 seq_num++; 150 151 return return_val; 152 } 153