1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3 * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4 */
5
6 #include "ffa_direct_msg_routing_extension.h"
7 #include "ffa_api.h"
8 #include <stdbool.h>
9
10 #define SP_ID_INVALID FFA_ID_GET_ID_MASK
11 #define FFA_ROUTING_EXT_RC_BIT BIT32(31)
12 #define FFA_ROUTING_EXT_ERROR_BIT BIT32(30)
13 #define FFA_ROUTING_EXT_BITS_MASK (FFA_ROUTING_EXT_RC_BIT | FFA_ROUTING_EXT_ERROR_BIT)
14
15 enum sp_rc_state { idle = 0, root, leaf, rc_root, internal, forwarding };
16
17 enum sp_rc_state state = idle;
18 static uint16_t own_id = SP_ID_INVALID;
19 static uint16_t caller_id = SP_ID_INVALID;
20 static uint16_t callee_id = SP_ID_INVALID;
21
is_rc_message(const struct ffa_direct_msg * msg)22 static bool is_rc_message(const struct ffa_direct_msg *msg)
23 {
24 return msg->args.args32[0] & FFA_ROUTING_EXT_RC_BIT;
25 }
26
is_error_message(const struct ffa_direct_msg * msg)27 static bool is_error_message(const struct ffa_direct_msg *msg)
28 {
29 return msg->args.args32[0] & FFA_ROUTING_EXT_ERROR_BIT;
30 }
31
get_error_code_from_message(const struct ffa_direct_msg * msg)32 static ffa_result get_error_code_from_message(const struct ffa_direct_msg *msg)
33 {
34 return (ffa_result)msg->args.args32[1];
35 }
36
send_rc_error_message(struct ffa_direct_msg * req,ffa_result error_code)37 static ffa_result send_rc_error_message(struct ffa_direct_msg *req,
38 ffa_result error_code)
39 {
40 return ffa_msg_send_direct_resp_32(req->destination_id, req->source_id,
41 (FFA_ROUTING_EXT_ERROR_BIT |
42 FFA_ROUTING_EXT_RC_BIT),
43 error_code, 0, 0, 0, req);
44 }
45
send_rc_error_message_to_rc_root(struct ffa_direct_msg * resp,ffa_result error_code)46 static ffa_result send_rc_error_message_to_rc_root(struct ffa_direct_msg *resp,
47 ffa_result error_code)
48 {
49 return ffa_msg_send_direct_req_32(own_id, callee_id,
50 (FFA_ROUTING_EXT_RC_BIT |
51 FFA_ROUTING_EXT_ERROR_BIT),
52 error_code, 0, 0, 0, resp);
53 }
54
deny_unexpected_rc_responses(struct ffa_direct_msg * req)55 static ffa_result deny_unexpected_rc_responses(struct ffa_direct_msg *req)
56 {
57 ffa_result ffa_res = FFA_OK;
58
59 while (is_rc_message(req)) {
60 ffa_res = send_rc_error_message(req, FFA_DENIED);
61 if (ffa_res != FFA_OK)
62 return ffa_res;
63 }
64
65 return FFA_OK;
66 }
67
deny_unexpected_requests(struct ffa_direct_msg * req)68 static ffa_result deny_unexpected_requests(struct ffa_direct_msg *req)
69 {
70 ffa_result ffa_res = FFA_OK;
71
72 while (!is_rc_message(req) || req->source_id != caller_id) {
73 ffa_res = send_rc_error_message(req, FFA_BUSY);
74 if (ffa_res != FFA_OK) {
75 /* Sending error message as a response to an invalid
76 * request has failed. Sending and FFA_MSG_WAIT to have
77 * a chance for receiving a valid message.
78 */
79 ffa_res = ffa_msg_wait(req);
80 if (ffa_res != FFA_OK) {
81 /* Even the FFA_MSG_WAIT failed so return. */
82 return ffa_res;
83 }
84 }
85 }
86
87 return FFA_OK;
88 }
89
request_received_hook(struct ffa_direct_msg * req)90 static ffa_result request_received_hook(struct ffa_direct_msg *req)
91 {
92 ffa_result ffa_res = FFA_OK;
93
94 ffa_res = deny_unexpected_rc_responses(req);
95 if (ffa_res != FFA_OK)
96 return ffa_res;
97
98 state = leaf;
99 own_id = req->destination_id;
100 caller_id = req->source_id;
101 callee_id = SP_ID_INVALID;
102
103 if (FFA_IS_32_BIT_FUNC(req->function_id))
104 req->args.args32[0] &= ~FFA_ROUTING_EXT_BITS_MASK;
105
106 return FFA_OK;
107 }
108
ffa_direct_msg_routing_ext_wait_post_hook(struct ffa_direct_msg * req)109 ffa_result ffa_direct_msg_routing_ext_wait_post_hook(struct ffa_direct_msg *req)
110 {
111 return request_received_hook(req);
112 }
113
ffa_direct_msg_routing_ext_req_pre_hook(struct ffa_direct_msg * req)114 ffa_result ffa_direct_msg_routing_ext_req_pre_hook(struct ffa_direct_msg *req)
115 {
116 if (FFA_IS_32_BIT_FUNC(req->function_id)) {
117 if (req->args.args32[0] & FFA_ROUTING_EXT_BITS_MASK)
118 return FFA_INVALID_PARAMETERS;
119 }
120
121 state = internal;
122 callee_id = req->destination_id;
123
124 return FFA_OK;
125 }
126
ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg * resp)127 ffa_result ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg *resp)
128 {
129 ffa_result ffa_res = FFA_OK;
130 struct ffa_direct_msg rc_resp = { 0 };
131
132 while (is_rc_message(resp)) {
133 if (is_error_message(resp)) {
134 /* The callee returned an error in an RC message. */
135 ffa_res = get_error_code_from_message(resp);
136 break;
137 }
138
139 /* Forwarding RC request towards the root (normal world) */
140 state = forwarding;
141
142 ffa_res = ffa_msg_send_direct_resp_32(own_id, caller_id,
143 resp->args.args32[0], resp->args.args32[1],
144 resp->args.args32[2], resp->args.args32[3],
145 resp->args.args32[4], &rc_resp);
146 if (ffa_res != FFA_OK)
147 goto forward_ffa_error_to_rc_root;
148
149 /*
150 * Denying messages which are not RC responses or came from a
151 * different endpoint than the original caller.
152 */
153 ffa_res = deny_unexpected_requests(&rc_resp);
154 if (ffa_res != FFA_OK)
155 goto forward_ffa_error_to_rc_root;
156
157 /* Forwarding RC response towards the RC root. */
158 state = internal;
159 ffa_res = ffa_msg_send_direct_req_32(
160 own_id, callee_id, rc_resp.args.args32[0], rc_resp.args.args32[1],
161 rc_resp.args.args32[2], rc_resp.args.args32[3], rc_resp.args.args32[4],
162 resp);
163
164 goto break_on_ffa_error;
165
166 /*
167 * At this point an FF-A error message was received while it was
168 * trying to forward the RC message. Forwarding erro to RC root.
169 */
170 forward_ffa_error_to_rc_root:
171 ffa_res = send_rc_error_message_to_rc_root(resp, ffa_res);
172
173 break_on_ffa_error:
174 if (ffa_res != FFA_OK) {
175 /* Exit loop, set leaf state and return with error. */
176 break;
177 }
178 }
179
180 /* Non-RC message was received or a non-recoverable error happened. */
181 state = leaf;
182 callee_id = SP_ID_INVALID;
183
184 return ffa_res;
185 }
186
ffa_direct_msg_routing_ext_req_error_hook(void)187 void ffa_direct_msg_routing_ext_req_error_hook(void)
188 {
189 state = leaf;
190 callee_id = SP_ID_INVALID;
191 }
192
ffa_direct_msg_routing_ext_resp_pre_hook(struct ffa_direct_msg * resp)193 ffa_result ffa_direct_msg_routing_ext_resp_pre_hook(struct ffa_direct_msg *resp)
194 {
195 if (FFA_IS_32_BIT_FUNC(resp->function_id)) {
196 if (resp->args.args32[0] & FFA_ROUTING_EXT_BITS_MASK)
197 return FFA_INVALID_PARAMETERS;
198 }
199
200 state = idle;
201 caller_id = SP_ID_INVALID;
202 callee_id = SP_ID_INVALID;
203
204 return FFA_OK;
205 }
206
ffa_direct_msg_routing_ext_resp_post_hook(struct ffa_direct_msg * req)207 ffa_result ffa_direct_msg_routing_ext_resp_post_hook(struct ffa_direct_msg *req)
208 {
209 return request_received_hook(req);
210 }
211
ffa_direct_msg_routing_ext_resp_error_hook(void)212 void ffa_direct_msg_routing_ext_resp_error_hook(void)
213 {
214 }
215
ffa_direct_msg_routing_ext_rc_req_pre_hook(struct ffa_direct_msg * req)216 ffa_result ffa_direct_msg_routing_ext_rc_req_pre_hook(struct ffa_direct_msg *req)
217 {
218 if (FFA_IS_32_BIT_FUNC(req->function_id)) {
219 if (req->args.args32[0] & FFA_ROUTING_EXT_BITS_MASK)
220 return FFA_INVALID_PARAMETERS;
221 }
222
223 req->args.args32[0] |= FFA_ROUTING_EXT_RC_BIT;
224 state = rc_root;
225
226 return FFA_OK;
227 }
228
229 ffa_result
ffa_direct_msg_routing_ext_rc_req_post_hook(struct ffa_direct_msg * resp)230 ffa_direct_msg_routing_ext_rc_req_post_hook(struct ffa_direct_msg *resp)
231 {
232 ffa_result ffa_res = FFA_OK;
233
234 ffa_res = deny_unexpected_requests(resp);
235 state = leaf;
236
237 if (is_error_message(resp))
238 ffa_res = get_error_code_from_message(resp);
239
240 return ffa_res;
241 }
242
ffa_direct_msg_routing_ext_rc_req_error_hook(void)243 void ffa_direct_msg_routing_ext_rc_req_error_hook(void)
244 {
245 state = leaf;
246 }
247