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