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