blob: 1139e73bc0d91d68b465c791de35b23c1b6dba7f [file] [log] [blame]
Balint Dobszay3bd6ae92020-11-23 17:57:50 +01001/*
julhal01c3f4e9a2020-12-15 13:39:01 +00002 * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
Balint Dobszay3bd6ae92020-11-23 17:57:50 +01003 *
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
julhal01c3f4e9a2020-12-15 13:39:01 +000019static void set_resp_args(uint32_t *resp_args, uint32_t ifaceid_opcode, uint32_t data_len,
Balint Dobszay3bd6ae92020-11-23 17:57:50 +010020 rpc_status_t rpc_status, uint32_t opstatus)
21{
julhal01c3f4e9a2020-12-15 13:39:01 +000022 resp_args[FFA_CALL_ARGS_IFACE_ID_OPCODE] = ifaceid_opcode;
Balint Dobszay3bd6ae92020-11-23 17:57:50 +010023 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
julhal01c3f4e9a2020-12-15 13:39:01 +000028static void set_mgmt_resp_args(uint32_t *resp_args, uint32_t ifaceid_opcode,
Balint Dobszay3bd6ae92020-11-23 17:57:50 +010029 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 */
julhal01c3f4e9a2020-12-15 13:39:01 +000036 set_resp_args(resp_args, ifaceid_opcode, 0, rpc_status, 0);
Balint Dobszay3bd6ae92020-11-23 17:57:50 +010037}
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
julhal01c3f4e9a2020-12-15 13:39:01 +000071 set_mgmt_resp_args(resp_args, req_args[FFA_CALL_ARGS_IFACE_ID_OPCODE], rpc_status);
Balint Dobszay3bd6ae92020-11-23 17:57:50 +010072}
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
julhal01c3f4e9a2020-12-15 13:39:01 +000097 set_mgmt_resp_args(resp_args, req_args[FFA_CALL_ARGS_IFACE_ID_OPCODE], rpc_status);
Balint Dobszay3bd6ae92020-11-23 17:57:50 +010098}
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
julhal01c3f4e9a2020-12-15 13:39:01 +0000106 uint32_t ifaceid_opcode = req_args[FFA_CALL_ARGS_IFACE_ID_OPCODE];
107
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100108 call_req.caller_id = source_id;
julhal01c3f4e9a2020-12-15 13:39:01 +0000109 call_req.interface_id = FFA_CALL_ARGS_EXTRACT_IFACE(ifaceid_opcode);
110 call_req.opcode = FFA_CALL_ARGS_EXTRACT_OPCODE(ifaceid_opcode);
111 call_req.encoding = req_args[FFA_CALL_ARGS_ENCODING];
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100112
113 call_req.req_buf.data = call_ep->shmem_buf;
114 call_req.req_buf.data_len = req_args[FFA_CALL_ARGS_REQ_DATA_LEN];
115 call_req.req_buf.size = call_ep->shmem_buf_size;
116
117 call_req.resp_buf.data = call_ep->shmem_buf;
118 call_req.resp_buf.data_len = 0;
119 call_req.resp_buf.size = call_ep->shmem_buf_size;
120
julhal01c3f4e9a2020-12-15 13:39:01 +0000121 rpc_status = rpc_interface_receive(call_ep->iface, &call_req);
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100122
123 set_resp_args(resp_args,
julhal01c3f4e9a2020-12-15 13:39:01 +0000124 ifaceid_opcode,
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100125 call_req.resp_buf.data_len,
126 rpc_status,
127 call_req.opstatus);
128}
129
130static void handle_mgmt_msg(struct ffa_call_ep *call_ep, uint16_t source_id,
131 const uint32_t *req_args, uint32_t *resp_args)
132{
julhal01c3f4e9a2020-12-15 13:39:01 +0000133 uint32_t ifaceid_opcode = req_args[FFA_CALL_ARGS_IFACE_ID_OPCODE];
134 uint32_t opcode = FFA_CALL_ARGS_EXTRACT_OPCODE(ifaceid_opcode);
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100135
136 /*
137 * TODO: shouldn't this be used to keep track of multiple
138 * shared buffers for different endpoints?
139 */
140 (void)source_id;
141
142 switch (opcode) {
143 case FFA_CALL_OPCODE_SHARE_BUF:
144 init_shmem_buf(call_ep, source_id, req_args, resp_args);
145 break;
146 case FFA_CALL_OPCODE_UNSHARE_BUF:
147 deinit_shmem_buf(call_ep, req_args, resp_args);
148 break;
149 default:
julhal01c3f4e9a2020-12-15 13:39:01 +0000150 set_mgmt_resp_args(resp_args, ifaceid_opcode, TS_RPC_ERROR_INVALID_OPCODE);
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100151 break;
152 }
153}
154
julhal01c3f4e9a2020-12-15 13:39:01 +0000155void ffa_call_ep_init(struct ffa_call_ep *ffa_call_ep, struct rpc_interface *iface)
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100156{
julhal01c3f4e9a2020-12-15 13:39:01 +0000157 ffa_call_ep->iface = iface;
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100158 ffa_call_ep->shmem_buf_handle = 0;
159 ffa_call_ep->shmem_buf_size = 0;
160 ffa_call_ep->shmem_buf = NULL;
161}
162
163void ffa_call_ep_receive(struct ffa_call_ep *call_ep,
164 const struct ffa_direct_msg *req_msg,
165 struct ffa_direct_msg *resp_msg)
166{
167 const uint32_t *req_args = req_msg->args;
168 uint32_t *resp_args = resp_msg->args;
169
170 uint16_t source_id = req_msg->source_id;
julhal01c3f4e9a2020-12-15 13:39:01 +0000171 uint32_t ifaceid_opcode = req_args[FFA_CALL_ARGS_IFACE_ID_OPCODE];
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100172
julhal01c3f4e9a2020-12-15 13:39:01 +0000173 if (FFA_CALL_ARGS_EXTRACT_IFACE(ifaceid_opcode) == FFA_CALL_MGMT_IFACE_ID) {
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100174 /* It's an RPC layer management request */
175 handle_mgmt_msg(call_ep, source_id, req_args, resp_args);
176 } else {
177 /*
178 * Assume anything else is a service request. Service requests
179 * rely on a buffer being shared from the requesting client.
180 * If it hasn't been set-up, fail the request.
181 */
182 if (call_ep->shmem_buf)
183 handle_service_msg(call_ep, source_id, req_args, resp_args);
184 else
julhal01c3f4e9a2020-12-15 13:39:01 +0000185 set_mgmt_resp_args(resp_args, ifaceid_opcode, TS_RPC_ERROR_NOT_READY);
Balint Dobszay3bd6ae92020-11-23 17:57:50 +0100186 }
187}