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 
select_protocol_version(const psa_invec * in_vec,size_t in_len,const psa_outvec * out_vec,size_t out_len)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 
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)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 
rse_comms_init(uintptr_t mhu_sender_base,uintptr_t mhu_receiver_base)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