blob: bb40cf37e57eccd905bb2c58805474c9e7a480ff [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_call_args.h"
8#include "ffarpc_call_ep.h"
9#include "ffarpc_call_ops.h"
10#include <ffa_api.h>
11#include <sp_memory_management.h>
12#include <protocols/rpc/common/packed-c/status.h>
13#include <trace.h>
14#include <stddef.h>
15
16/* TODO: remove this when own ID will be available in libsp */
17extern uint16_t own_id;
18
19static void set_resp_args(uint32_t *resp_args, uint32_t opcode, uint32_t data_len,
20 rpc_status_t rpc_status, uint32_t opstatus)
21{
22 resp_args[FFA_CALL_ARGS_OPCODE] = opcode;
23 resp_args[FFA_CALL_ARGS_RESP_DATA_LEN] = data_len;
24 resp_args[FFA_CALL_ARGS_RESP_RPC_STATUS] = rpc_status;
25 resp_args[FFA_CALL_ARGS_RESP_OP_STATUS] = opstatus;
26}
27
28static void set_mgmt_resp_args(uint32_t *resp_args, uint32_t opcode,
29 rpc_status_t rpc_status)
30{
31 /*
32 * Sets arguments for responses that originate from the ffa_call_ep
33 * rather than from a higher layer service. These responses are not
34 * associated with a shared buffer for any additional message payload.
35 */
36 set_resp_args(resp_args, opcode, 0, rpc_status, 0);
37}
38
39static void init_shmem_buf(struct ffa_call_ep *call_ep, uint16_t source_id,
40 const uint32_t *req_args, uint32_t *resp_args)
41{
42 sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
43 struct sp_memory_descriptor desc = { };
44 struct sp_memory_access_descriptor acc_desc = { };
45 struct sp_memory_region region = { };
46 uint32_t in_region_count = 1;
47 uint32_t out_region_count = 1;
48 uint64_t handle = 0;
49 rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
50
51 desc.sender_id = source_id;
52 desc.memory_type = sp_memory_type_not_specified;
53 desc.flags.transaction_type = sp_memory_transaction_type_share;
54 acc_desc.receiver_id = own_id;
55 acc_desc.data_access = sp_data_access_read_write;
56 handle = req_args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_MSW];
57 handle = (handle << 32) | req_args[FFA_CALL_ARGS_SHARE_MEM_HANDLE_LSW];
58
59 sp_res = sp_memory_retrieve(&desc, &acc_desc, &region, in_region_count,
60 &out_region_count, handle);
61
62 if (sp_res == SP_RESULT_OK) {
63 call_ep->shmem_buf = region.address;
64 call_ep->shmem_buf_handle = handle;
65 call_ep->shmem_buf_size = (size_t)req_args[FFA_CALL_ARGS_SHARE_MEM_SIZE];
66 rpc_status = TS_RPC_CALL_ACCEPTED;
67 } else {
68 EMSG("memory retrieve error: %d", sp_res);
69 }
70
71 set_mgmt_resp_args(resp_args, req_args[FFA_CALL_ARGS_OPCODE], rpc_status);
72}
73
74static void deinit_shmem_buf(struct ffa_call_ep *call_ep, const uint32_t *req_args,
75 uint32_t *resp_args)
76{
77 sp_result sp_res = SP_RESULT_INTERNAL_ERROR;
78 rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
79 uint64_t handle = call_ep->shmem_buf_handle;
80 uint16_t endpoints[1] = { own_id };
81 uint32_t endpoint_cnt = 1;
82 struct sp_memory_transaction_flags flags = {
83 .zero_memory = false,
84 .operation_time_slicing = false,
85 };
86
87 sp_res = sp_memory_relinquish(handle, endpoints, endpoint_cnt, &flags);
88 if (sp_res == SP_RESULT_OK) {
89 call_ep->shmem_buf = NULL;
90 call_ep->shmem_buf_handle = 0;
91 call_ep->shmem_buf_size = 0;
92 rpc_status = TS_RPC_CALL_ACCEPTED;
93 } else {
94 EMSG("memory relinquish error: %d", sp_res);
95 }
96
97 set_mgmt_resp_args(resp_args, req_args[FFA_CALL_ARGS_OPCODE], rpc_status);
98}
99
100static void handle_service_msg(struct ffa_call_ep *call_ep, uint16_t source_id,
101 const uint32_t *req_args, uint32_t *resp_args)
102{
103 rpc_status_t rpc_status;
104 struct call_req call_req;
105
106 call_req.caller_id = source_id;
107 call_req.opcode = req_args[FFA_CALL_ARGS_OPCODE];
108
109 call_req.req_buf.data = call_ep->shmem_buf;
110 call_req.req_buf.data_len = req_args[FFA_CALL_ARGS_REQ_DATA_LEN];
111 call_req.req_buf.size = call_ep->shmem_buf_size;
112
113 call_req.resp_buf.data = call_ep->shmem_buf;
114 call_req.resp_buf.data_len = 0;
115 call_req.resp_buf.size = call_ep->shmem_buf_size;
116
117 rpc_status = call_ep_receive(call_ep->call_ep, &call_req);
118
119 set_resp_args(resp_args,
120 call_req.opcode,
121 call_req.resp_buf.data_len,
122 rpc_status,
123 call_req.opstatus);
124}
125
126static void handle_mgmt_msg(struct ffa_call_ep *call_ep, uint16_t source_id,
127 const uint32_t *req_args, uint32_t *resp_args)
128{
129 uint32_t opcode = req_args[FFA_CALL_ARGS_OPCODE];
130
131 /*
132 * TODO: shouldn't this be used to keep track of multiple
133 * shared buffers for different endpoints?
134 */
135 (void)source_id;
136
137 switch (opcode) {
138 case FFA_CALL_OPCODE_SHARE_BUF:
139 init_shmem_buf(call_ep, source_id, req_args, resp_args);
140 break;
141 case FFA_CALL_OPCODE_UNSHARE_BUF:
142 deinit_shmem_buf(call_ep, req_args, resp_args);
143 break;
144 default:
145 set_mgmt_resp_args(resp_args, opcode, TS_RPC_ERROR_INVALID_OPCODE);
146 break;
147 }
148}
149
150void ffa_call_ep_init(struct ffa_call_ep *ffa_call_ep, struct call_ep *call_ep)
151{
152 ffa_call_ep->call_ep = call_ep;
153 ffa_call_ep->shmem_buf_handle = 0;
154 ffa_call_ep->shmem_buf_size = 0;
155 ffa_call_ep->shmem_buf = NULL;
156}
157
158void ffa_call_ep_receive(struct ffa_call_ep *call_ep,
159 const struct ffa_direct_msg *req_msg,
160 struct ffa_direct_msg *resp_msg)
161{
162 const uint32_t *req_args = req_msg->args;
163 uint32_t *resp_args = resp_msg->args;
164
165 uint16_t source_id = req_msg->source_id;
166 uint32_t opcode = req_args[FFA_CALL_ARGS_OPCODE];
167
168 if (FFA_CALL_OPCODE_IS_MGMT(opcode)) {
169 /* It's an RPC layer management request */
170 handle_mgmt_msg(call_ep, source_id, req_args, resp_args);
171 } else {
172 /*
173 * Assume anything else is a service request. Service requests
174 * rely on a buffer being shared from the requesting client.
175 * If it hasn't been set-up, fail the request.
176 */
177 if (call_ep->shmem_buf)
178 handle_service_msg(call_ep, source_id, req_args, resp_args);
179 else
180 set_mgmt_resp_args(resp_args, opcode, TS_RPC_ERROR_NOT_READY);
181 }
182}