arm-trusted-firmware/drivers/arm/rss/rss_comms.c
Vijayenthiran Subramaniam f754bd4667 fix(rss): fix bound check during protocol selection
Fix the wrong placement of the closing parenthesis in the second
condition check that resulted in the incorrect calculation of the MHU
message size. Also, format the code for readability.

Signed-off-by: Vijayenthiran Subramaniam <vijayenthiran.subramaniam@arm.com>
Change-Id: I0e012f3ff00bae2dfc12cdb1c2c636fc6c0a0b55
2024-02-06 17:42:24 +01:00

180 lines
5.4 KiB
C

/*
* Copyright (c) 2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <string.h>
#include <common/debug.h>
#include <drivers/arm/mhu.h>
#include <drivers/arm/rss_comms.h>
#include <psa/client.h>
#include <rss_comms_protocol.h>
/* Union as message space and reply space are never used at the same time, and this saves space as
* we can overlap them.
*/
union __packed __attribute__((aligned(4))) rss_comms_io_buffer_t {
struct serialized_rss_comms_msg_t msg;
struct serialized_rss_comms_reply_t reply;
};
static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len,
const psa_outvec *out_vec, size_t out_len)
{
size_t comms_mhu_msg_size;
size_t comms_embed_msg_min_size;
size_t comms_embed_reply_min_size;
size_t in_size_total = 0;
size_t out_size_total = 0;
size_t i;
for (i = 0U; i < in_len; ++i) {
in_size_total += in_vec[i].len;
}
for (i = 0U; i < out_len; ++i) {
out_size_total += out_vec[i].len;
}
comms_mhu_msg_size = mhu_get_max_message_size();
comms_embed_msg_min_size = sizeof(struct serialized_rss_comms_header_t) +
sizeof(struct rss_embed_msg_t) -
PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
comms_embed_reply_min_size = sizeof(struct serialized_rss_comms_header_t) +
sizeof(struct rss_embed_reply_t) -
PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
/* Use embed if we can pack into one message and reply, else use
* pointer_access. The underlying MHU transport protocol uses a
* single uint32_t to track the length, so the amount of data that
* can be in a message is 4 bytes less than mhu_get_max_message_size
* reports.
*
* TODO tune this with real performance numbers, it's possible a
* pointer_access message is less performant than multiple embed
* messages due to ATU configuration costs to allow access to the
* pointers.
*/
if ((comms_embed_msg_min_size + in_size_total >
comms_mhu_msg_size - sizeof(uint32_t)) ||
(comms_embed_reply_min_size + out_size_total >
comms_mhu_msg_size - sizeof(uint32_t))) {
return RSS_COMMS_PROTOCOL_POINTER_ACCESS;
} else {
return RSS_COMMS_PROTOCOL_EMBED;
}
}
psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
psa_outvec *out_vec, size_t out_len)
{
/* Declared statically to avoid using huge amounts of stack space. Maybe revisit if
* functions not being reentrant becomes a problem.
*/
static union rss_comms_io_buffer_t io_buf;
enum mhu_error_t err;
psa_status_t status;
static uint8_t seq_num = 1U;
size_t msg_size;
size_t reply_size = sizeof(io_buf.reply);
psa_status_t return_val;
size_t idx;
if (type > INT16_MAX || type < INT16_MIN || in_len > PSA_MAX_IOVEC
|| out_len > PSA_MAX_IOVEC) {
return PSA_ERROR_INVALID_ARGUMENT;
}
io_buf.msg.header.seq_num = seq_num,
/* No need to distinguish callers (currently concurrent calls are not supported). */
io_buf.msg.header.client_id = 1U,
io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
status = rss_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec,
out_len, &io_buf.msg, &msg_size);
if (status != PSA_SUCCESS) {
return status;
}
VERBOSE("[RSS-COMMS] Sending message\n");
VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver);
VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num);
VERBOSE("client_id=%u\n", io_buf.msg.header.client_id);
for (idx = 0; idx < in_len; idx++) {
VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
}
err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size);
if (err != MHU_ERR_NONE) {
return PSA_ERROR_COMMUNICATION_FAILURE;
}
#if DEBUG
/*
* Poisoning the message buffer (with a known pattern).
* Helps in detecting hypothetical RSS communication bugs.
*/
memset(&io_buf.msg, 0xA5, msg_size);
#endif
err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size);
if (err != MHU_ERR_NONE) {
return PSA_ERROR_COMMUNICATION_FAILURE;
}
VERBOSE("[RSS-COMMS] Received reply\n");
VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver);
VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num);
VERBOSE("client_id=%u\n", io_buf.reply.header.client_id);
status = rss_protocol_deserialize_reply(out_vec, out_len, &return_val,
&io_buf.reply, reply_size);
if (status != PSA_SUCCESS) {
return status;
}
VERBOSE("return_val=%d\n", return_val);
for (idx = 0U; idx < out_len; idx++) {
VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
}
/* Clear the MHU message buffer to remove assets from memory */
memset(&io_buf, 0x0, sizeof(io_buf));
seq_num++;
return return_val;
}
int rss_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base)
{
enum mhu_error_t err;
err = mhu_init_sender(mhu_sender_base);
if (err != MHU_ERR_NONE) {
if (err == MHU_ERR_ALREADY_INIT) {
INFO("[RSS-COMMS] Host to RSS MHU driver already initialized\n");
} else {
ERROR("[RSS-COMMS] Host to RSS MHU driver initialization failed: %d\n", err);
return -1;
}
}
err = mhu_init_receiver(mhu_receiver_base);
if (err != MHU_ERR_NONE) {
if (err == MHU_ERR_ALREADY_INIT) {
INFO("[RSS-COMMS] RSS to Host MHU driver already initialized\n");
} else {
ERROR("[RSS-COMMS] RSS to Host MHU driver initialization failed: %d\n", err);
return -1;
}
}
return 0;
}