1 /* 2 * Copyright (c) 2022, 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/rss_comms.h> 13 #include <psa/client.h> 14 #include <rss_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))) rss_comms_io_buffer_t { 20 struct serialized_rss_comms_msg_t msg; 21 struct serialized_rss_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_rss_comms_header_t) + 44 sizeof(struct rss_embed_msg_t) - 45 PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE; 46 47 comms_embed_reply_min_size = sizeof(struct serialized_rss_comms_header_t) + 48 sizeof(struct rss_embed_reply_t) - 49 PLAT_RSS_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 > comms_mhu_msg_size - sizeof(uint32_t)) 63 || (comms_embed_reply_min_size + out_size_total > comms_mhu_msg_size) - sizeof(uint32_t)) { 64 return RSS_COMMS_PROTOCOL_POINTER_ACCESS; 65 } else { 66 return RSS_COMMS_PROTOCOL_EMBED; 67 } 68 } 69 70 psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len, 71 psa_outvec *out_vec, size_t out_len) 72 { 73 /* Declared statically to avoid using huge amounts of stack space. Maybe revisit if 74 * functions not being reentrant becomes a problem. 75 */ 76 static union rss_comms_io_buffer_t io_buf; 77 enum mhu_error_t err; 78 psa_status_t status; 79 static uint8_t seq_num = 1U; 80 size_t msg_size; 81 size_t reply_size = sizeof(io_buf.reply); 82 psa_status_t return_val; 83 size_t idx; 84 85 if (type > INT16_MAX || type < INT16_MIN || in_len > PSA_MAX_IOVEC 86 || out_len > PSA_MAX_IOVEC) { 87 return PSA_ERROR_INVALID_ARGUMENT; 88 } 89 90 io_buf.msg.header.seq_num = seq_num, 91 /* No need to distinguish callers (currently concurrent calls are not supported). */ 92 io_buf.msg.header.client_id = 1U, 93 io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len); 94 95 status = rss_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec, 96 out_len, &io_buf.msg, &msg_size); 97 if (status != PSA_SUCCESS) { 98 return status; 99 } 100 101 VERBOSE("[RSS-COMMS] Sending message\n"); 102 VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver); 103 VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num); 104 VERBOSE("client_id=%u\n", io_buf.msg.header.client_id); 105 for (idx = 0; idx < in_len; idx++) { 106 VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len); 107 VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base); 108 } 109 110 err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size); 111 if (err != MHU_ERR_NONE) { 112 return PSA_ERROR_COMMUNICATION_FAILURE; 113 } 114 115 #if DEBUG 116 /* 117 * Poisoning the message buffer (with a known pattern). 118 * Helps in detecting hypothetical RSS communication bugs. 119 */ 120 memset(&io_buf.msg, 0xA5, msg_size); 121 #endif 122 123 err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size); 124 if (err != MHU_ERR_NONE) { 125 return PSA_ERROR_COMMUNICATION_FAILURE; 126 } 127 128 VERBOSE("[RSS-COMMS] Received reply\n"); 129 VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver); 130 VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num); 131 VERBOSE("client_id=%u\n", io_buf.reply.header.client_id); 132 133 status = rss_protocol_deserialize_reply(out_vec, out_len, &return_val, 134 &io_buf.reply, reply_size); 135 if (status != PSA_SUCCESS) { 136 return status; 137 } 138 139 VERBOSE("return_val=%d\n", return_val); 140 for (idx = 0U; idx < out_len; idx++) { 141 VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len); 142 VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base); 143 } 144 145 /* Clear the MHU message buffer to remove assets from memory */ 146 memset(&io_buf, 0x0, sizeof(io_buf)); 147 148 seq_num++; 149 150 return return_val; 151 } 152 153 int rss_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base) 154 { 155 enum mhu_error_t err; 156 157 err = mhu_init_sender(mhu_sender_base); 158 if (err != MHU_ERR_NONE) { 159 if (err == MHU_ERR_ALREADY_INIT) { 160 INFO("[RSS-COMMS] Host to RSS MHU driver already initialized\n"); 161 } else { 162 ERROR("[RSS-COMMS] Host to RSS MHU driver initialization failed: %d\n", err); 163 return -1; 164 } 165 } 166 167 err = mhu_init_receiver(mhu_receiver_base); 168 if (err != MHU_ERR_NONE) { 169 if (err == MHU_ERR_ALREADY_INIT) { 170 INFO("[RSS-COMMS] RSS to Host MHU driver already initialized\n"); 171 } else { 172 ERROR("[RSS-COMMS] RSS to Host MHU driver initialization failed: %d\n", err); 173 return -1; 174 } 175 } 176 177 return 0; 178 } 179