blob: af86664a83b4d3adb99925583b78462ac2dd97c1 [file] [log] [blame]
Balint Dobszay3bd6ae92020-11-23 17:57:50 +01001/*
2 * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "ffarpc_caller.h"
8#include <external/ffa_tool/buf_common.h>
9#include <rpc/ffarpc/endpoint/ffarpc_call_args.h>
10#include <rpc/ffarpc/endpoint/ffarpc_call_ops.h>
11#include <protocols/rpc/common/packed-c/status.h>
12#include <fcntl.h>
13#include <sys/ioctl.h>
14#include <stdio.h>
15#include <unistd.h>
16#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
20#define DEFAULT_SHMEM_BUF_SIZE (4096)
21
22static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len);
23static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
24 int *opstatus, uint8_t **resp_buf, size_t *resp_len);
25static void call_end(void *context, rpc_call_handle handle);
26
27static int kernel_write_req_buf(struct ffarpc_caller *s);
28static int kernel_read_resp_buf(struct ffarpc_caller *s);
29static int share_mem_with_partition(struct ffarpc_caller *s);
30static int unshare_mem_with_partition(struct ffarpc_caller *s);
31
32
33
34struct rpc_caller *ffarpc_caller_init(struct ffarpc_caller *s, const char *device_path)
35{
36 struct rpc_caller *base = &s->rpc_caller;
37
38 base->context = s;
39 base->call_begin = call_begin;
40 base->call_invoke = call_invoke;
41 base->call_end = call_end;
42
43 s->device_path = device_path;
44 s->fd = -1;
45 s->call_ep_id = 0;
46 s->shared_mem_handle = 0;
47 s->shared_mem_required_size = DEFAULT_SHMEM_BUF_SIZE;
48 s->req_buf = NULL;
49 s->req_len = 0;
50 s->resp_buf = NULL;
51 s->resp_len = 0;
52 s->is_call_transaction_in_progess = false;
53
54 return base;
55}
56
57void ffarpc_caller_deinit(struct ffarpc_caller *s)
58{
59 s->rpc_caller.context = NULL;
60 s->rpc_caller.call_begin = NULL;
61 s->rpc_caller.call_invoke = NULL;
62 s->rpc_caller.call_end = NULL;
63
64 call_end(s, s);
65 ffarpc_caller_close(s);
66}
67
68size_t ffarpc_caller_discover(const struct ffarpc_caller *s, const uint8_t *uuid,
69 uint16_t *partition_ids, size_t discover_limit)
70{
71 size_t discover_count = 0;
72
73 if (uuid && partition_ids && s->device_path) {
74 int fd;
75
76 fd = open(s->device_path, O_RDWR);
77
78 if (fd >= 0) {
79 int ioctl_status;
80 struct endpoint_id discovered_partition;
81
82 discovered_partition.uuid_0 = uuid[3] << 24 | uuid[2] << 16 | uuid[1] << 8 | uuid[0];
83 discovered_partition.uuid_1 = uuid[7] << 24 | uuid[6] << 16 | uuid[5] << 8 | uuid[4];
84 discovered_partition.uuid_2 = uuid[11] << 24 | uuid[10] << 16 | uuid[9] << 8 | uuid[8];
85 discovered_partition.uuid_3 = uuid[15] << 24 | uuid[14] << 16 | uuid[13] << 8 | uuid[12];
86 discovered_partition.id = 0;
87
88 ioctl_status = ioctl(fd, GET_PART_ID, &discovered_partition);
89
90 if ((ioctl_status == 0) && (discover_count < discover_limit)) {
91 partition_ids[discover_count] = discovered_partition.id;
92 ++discover_count;
93 }
94
95 close(fd);
96 }
97 }
98
99 return discover_count;
100}
101
102int ffarpc_caller_open(struct ffarpc_caller *s, uint16_t call_ep_id)
103{
104 int ioctl_status = -1;
105
106 if (s->device_path) {
107
108 s->fd = open(s->device_path, O_RDWR);
109
110 if (s->fd >= 0) {
111 /* Allocate resource for session */
112 ioctl_status = ioctl(s->fd, SHARE_INIT, &s->shared_mem_handle);
113
114 if (ioctl_status == 0) {
115 /* Session successfully opened */
116 s->call_ep_id = call_ep_id;
117 ioctl_status = share_mem_with_partition(s);
118 }
119
120 if (ioctl_status != 0) {
121 /* Resource allocation or sharing error */
122 close(s->fd);
123 s->fd = -1;
124 }
125 }
126 }
127
128 return ioctl_status;
129}
130
131int ffarpc_caller_close(struct ffarpc_caller *s)
132{
133 int ioctl_status = -1;
134
135 if (s->fd >= 0) {
136
137 unshare_mem_with_partition(s);
138 ioctl_status = ioctl(s->fd, SHARE_DEINIT);
139 close(s->fd);
140 s->fd = -1;
141 s->call_ep_id = 0;
142 }
143
144 return ioctl_status;
145}
146
147static rpc_call_handle call_begin(void *context, uint8_t **req_buf, size_t req_len)
148{
149 rpc_call_handle handle = NULL;
150 struct ffarpc_caller *s = (struct ffarpc_caller*)context;
151
152 if (!s->is_call_transaction_in_progess) {
153
154 s->is_call_transaction_in_progess = true;
155 handle = s;
156
157 if (req_len > 0) {
158
159 s->req_buf = malloc(req_len);
160
161 if (s->req_buf) {
162
163 *req_buf = s->req_buf;
164 s->req_len = req_len;
165 }
166 else {
167 /* Failed to allocate req buffer */
168 handle = NULL;
169 s->is_call_transaction_in_progess = false;
170 }
171 }
172 else {
173
174 *req_buf = NULL;
175 s->req_buf = NULL;
176 s->req_len = req_len;
177 }
178 }
179
180 return handle;
181}
182
183static rpc_status_t call_invoke(void *context, rpc_call_handle handle, uint32_t opcode,
184 int *opstatus, uint8_t **resp_buf, size_t *resp_len)
185{
186 rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
187 struct ffarpc_caller *s = (struct ffarpc_caller*)context;
188
189 if ((handle == s) && s->is_call_transaction_in_progess) {
190 int kernel_op_status = 0;
191
192 if (s->req_len > 0) {
193 kernel_op_status = kernel_write_req_buf(s);
194 }
195
196 if (kernel_op_status == 0) {
197 /* Make direct call to send the request */
198 struct msg_args direct_msg;
199 memset(&direct_msg, 0, sizeof(direct_msg));
200
201 direct_msg.dst_id = s->call_ep_id;
202 direct_msg.args[FFA_CALL_ARGS_OPCODE] = (uint64_t)opcode;
203 direct_msg.args[FFA_CALL_ARGS_REQ_DATA_LEN] = (uint64_t)s->req_len;
204
205 kernel_op_status = ioctl(s->fd, SEND_SYNC_MSG, &direct_msg);
206
207 if (kernel_op_status == 0) {
208 /* Send completed normally - ffa return args in msg_args struct */
209 s->resp_len = (size_t)direct_msg.args[FFA_CALL_ARGS_RESP_DATA_LEN];
210 rpc_status = (int)direct_msg.args[FFA_CALL_ARGS_RESP_RPC_STATUS];
211 *opstatus = (int)direct_msg.args[FFA_CALL_ARGS_RESP_OP_STATUS];
212
213 if (s->resp_len > 0) {
214 s->resp_buf = malloc(s->resp_len);
215
216 if (s->resp_buf) {
217 kernel_op_status = kernel_read_resp_buf(s);
218
219 if (kernel_op_status != 0) {
220 /* Failed to read response buffer */
221 rpc_status = TS_RPC_ERROR_INTERNAL;
222 }
223 }
224 else {
225 /* Failed to allocate response buffer */
226 s->resp_len = 0;
227 rpc_status = TS_RPC_ERROR_INTERNAL;
228 }
229 }
230 else {
231 /* No response parameters */
232 s->resp_buf = NULL;
233 }
234
235 *resp_len = s->resp_len;
236 *resp_buf = s->resp_buf;
237 }
238 }
239 }
240
241 return rpc_status;
242}
243
244static void call_end(void *context, rpc_call_handle handle)
245{
246 struct ffarpc_caller *s = (struct ffarpc_caller*)context;
247
248 if ((handle == s) && s->is_call_transaction_in_progess) {
249
250 /* Call transaction complete so free resource */
251 free(s->req_buf);
252 s->req_buf = NULL;
253 s->req_len = 0;
254
255 free(s->resp_buf);
256 s->resp_buf = NULL;
257 s->resp_len = 0;
258
259 s->is_call_transaction_in_progess = false;
260 }
261}
262
263static int kernel_write_req_buf(struct ffarpc_caller *s) {
264
265 int ioctl_status;
266 struct buf_descr req_descr;
267
268 req_descr.buf = s->req_buf;
269 req_descr.length = s->req_len;
270 ioctl_status = ioctl(s->fd, SHARE_WRITE, &req_descr);
271
272 return ioctl_status;
273}
274
275
276static int kernel_read_resp_buf(struct ffarpc_caller *s) {
277
278 int ioctl_status;
279 struct buf_descr resp_descr;
280
281 resp_descr.buf = s->resp_buf;
282 resp_descr.length = s->resp_len;
283 ioctl_status = ioctl(s->fd, SHARE_READ, &resp_descr);
284
285 return ioctl_status;
286}
287
288static int share_mem_with_partition(struct ffarpc_caller *s) {
289
290 int ioctl_status;
291 struct msg_args direct_msg;
292 memset(&direct_msg, 0, sizeof(direct_msg));
293
294 direct_msg.dst_id = s->call_ep_id;
295 direct_msg.args[FFA_CALL_ARGS_OPCODE] = (uint64_t)FFA_CALL_OPCODE_SHARE_BUF;
296 direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_LSW] = (uint32_t)s->shared_mem_handle;
297 direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_MSW] = (uint32_t)(s->shared_mem_handle >> 32);
298 direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_SIZE] = (uint64_t)s->shared_mem_required_size;
299
300 ioctl_status = ioctl(s->fd, SEND_SYNC_MSG, &direct_msg);
301
302 return ioctl_status;
303}
304
305static int unshare_mem_with_partition(struct ffarpc_caller *s) {
306
307 int ioctl_status;
308 struct msg_args direct_msg;
309 memset(&direct_msg, 0, sizeof(direct_msg));
310
311 direct_msg.dst_id = s->call_ep_id;
312 direct_msg.args[FFA_CALL_ARGS_OPCODE] = (uint64_t)FFA_CALL_OPCODE_UNSHARE_BUF;
313 direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_LSW] = (uint32_t)s->shared_mem_handle;
314 direct_msg.args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_MSW] = (uint32_t)(s->shared_mem_handle >> 32);
315
316 ioctl_status = ioctl(s->fd, SEND_SYNC_MSG, &direct_msg);
317
318 return ioctl_status;
319}