xref: /rk3399_ARM-atf/drivers/arm/rse/rse_comms.c (revision ed0c801fc69f55103c597dcc29cadf4c7cb7d575)
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