1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define TLOG_TAG "ipc_ql_tipc"
18
19 #include <lib/tidl/tidl.h>
20 #include <trusty/sysdeps.h>
21 #include <trusty/trusty_ipc.h>
22 #include <trusty/trusty_log.h>
23 #include <trusty/util.h>
24
25 #define TIDL_CHANNEL_MAX 8
26
27 static struct trusty_ipc_dev* tidl_dev = (struct trusty_ipc_dev*)NULL;
28 static struct trusty_ipc_chan tidl_channels[TIDL_CHANNEL_MAX];
29
__cxa_atexit(void (* destructor)(void *),void * arg,void * dso)30 extern "C" __attribute__((weak)) int __cxa_atexit(void (*destructor)(void*),
31 void* arg,
32 void* dso) {
33 (void)arg;
34 (void)dso;
35 return 0;
36 }
37
operator delete(void * ptr)38 __attribute__((weak)) void operator delete(void* ptr) noexcept {
39 if (ptr)
40 trusty_free(ptr);
41 }
42 namespace tidl {
43
reset()44 int handle::reset() {
45 if (mFd == INVALID_IPC_HANDLE) {
46 return NO_ERROR;
47 }
48 int rc = tidl_chan_close(mFd);
49 mFd = INVALID_IPC_HANDLE;
50 return rc;
51 }
52
reset(Handle fd)53 int handle::reset(Handle fd) {
54 if (mFd == INVALID_IPC_HANDLE) {
55 mFd = fd;
56 return NO_ERROR;
57 }
58 int rc = tidl_chan_close(mFd);
59 if (rc != NO_ERROR) {
60 mFd = INVALID_IPC_HANDLE;
61 return rc;
62 }
63 mFd = fd;
64 return rc;
65 }
get()66 Handle handle::get() {
67 return mFd;
68 }
69 namespace ipc {
70
tidl_get_channel(handle_t fd)71 static __inline__ struct trusty_ipc_chan* tidl_get_channel(handle_t fd) {
72 TLOGD("looking for channel %u\n", fd);
73 for (int i = 0; i < TIDL_CHANNEL_MAX; i++) {
74 TLOGD("channel[%d]=%u\n", i, tidl_channels[i].handle);
75 if (fd == tidl_channels[i].handle) {
76 return &tidl_channels[i];
77 }
78 }
79 if (fd == INVALID_IPC_HANDLE) {
80 TLOGE("tidl_get_channel failed, no available channel\n");
81 } else {
82 TLOGE("tidl_get_channel failed, channel not found!\n");
83 }
84 return (struct trusty_ipc_chan*)NULL;
85 }
86
binder_init_channels()87 static __inline__ void binder_init_channels() {
88 TLOGD("init channels\n");
89 for (int i = 0; i < TIDL_CHANNEL_MAX; i++) {
90 trusty_ipc_chan_init(&tidl_channels[i], tidl_dev);
91 }
92 }
93
binder_check_channels()94 static __inline__ void binder_check_channels() {
95 TLOGD("check that all channels have been closed\n");
96 for (int i = 0; i < TIDL_CHANNEL_MAX; i++) {
97 assert(tidl_channels[i].handle == INVALID_IPC_HANDLE);
98 }
99 }
100
101 /* TODO: create a TIDL sysdeps mapping to allow non lk-based bootloaders
102 * to map errors into their own system. For now tidl returns lk errors.
103 */
to_tidl_err(int err)104 static int to_tidl_err(int err) {
105 switch (err) {
106 case TRUSTY_ERR_NONE:
107 return NO_ERROR;
108
109 case TRUSTY_ERR_GENERIC:
110 return ERR_GENERIC;
111
112 case TRUSTY_ERR_NOT_SUPPORTED:
113 return ERR_NOT_SUPPORTED;
114
115 case TRUSTY_ERR_NO_MEMORY:
116 return ERR_NO_MEMORY;
117
118 case TRUSTY_ERR_INVALID_ARGS:
119 return ERR_INVALID_ARGS;
120
121 case TRUSTY_ERR_SECOS_ERR:
122 return ERR_GENERIC;
123
124 case TRUSTY_ERR_MSG_TOO_BIG:
125 return ERR_BAD_LEN;
126
127 case TRUSTY_ERR_NO_MSG:
128 return ERR_GENERIC;
129
130 case TRUSTY_ERR_CHANNEL_CLOSED:
131 return ERR_CHANNEL_CLOSED;
132
133 case TRUSTY_ERR_SEND_BLOCKED:
134 return ERR_GENERIC;
135
136 default:
137 return err;
138 }
139 }
140
tidl_init(struct trusty_ipc_dev * dev)141 extern "C" int tidl_init(struct trusty_ipc_dev* dev) {
142 assert(dev);
143 if (tidl_dev) {
144 assert(tidl_dev == dev);
145 return NO_ERROR;
146 }
147 tidl_dev = dev;
148 binder_init_channels();
149 return NO_ERROR;
150 }
151
152 /*
153 * Shutdown binder clients
154 *
155 */
tidl_shutdown(void)156 extern "C" void tidl_shutdown(void) {
157 tidl_dev = (struct trusty_ipc_dev*)NULL;
158 binder_check_channels();
159 }
160
tidl_chan_close(handle_t fd)161 extern "C" int tidl_chan_close(handle_t fd) {
162 struct trusty_ipc_chan* chan = tidl_get_channel(fd);
163 assert(chan);
164 TLOGD("tidl_chan_close fd (%u)\n", fd);
165 int rc = trusty_ipc_close(chan);
166 if (rc < 0) {
167 TLOGE("trusty_ipc_close error (%d)\n", rc);
168 }
169 return to_tidl_err(rc);
170 }
171
connect(const char * path,uint32_t flags,tidl::handle & out_fd)172 int connect(const char* path, uint32_t flags, tidl::handle& out_fd) {
173 (void)flags;
174 if (!tidl_dev) {
175 TLOGE("trusty::aidl::ipc::connect ERROR: device not initialised.\n");
176 return ERR_GENERIC;
177 }
178 struct trusty_ipc_chan* chan = tidl_get_channel(INVALID_IPC_HANDLE);
179 if (!chan) {
180 return ERR_GENERIC;
181 }
182 assert(chan->handle == INVALID_IPC_HANDLE);
183
184 TLOGD("Connecting to %s\n", path);
185 int rc = trusty_ipc_connect(chan, path, true);
186 if (rc < 0) {
187 TLOGE("failed (%d) to connect to '%s'\n", rc, path);
188 return to_tidl_err(rc);
189 }
190
191 TLOGD("channel (%u)\n", chan->handle);
192 out_fd.reset(chan->handle);
193 return NO_ERROR;
194 }
195
send_iovs(handle_t fd,const struct trusty_ipc_iovec * iovs,size_t iovs_cnt,handle_t * handles,uint32_t num_handles)196 static int send_iovs(handle_t fd,
197 const struct trusty_ipc_iovec* iovs,
198 size_t iovs_cnt,
199 handle_t* handles,
200 uint32_t num_handles) {
201 assert(num_handles == 0);
202 struct trusty_ipc_chan* chan = tidl_get_channel(fd);
203 assert(chan);
204 trusty_assert(chan->dev);
205 trusty_assert(chan->handle);
206 int rc = trusty_ipc_send(chan, iovs, iovs_cnt, true);
207 return to_tidl_err(rc);
208 }
209
send(handle_t fd,const void * hdr,size_t hdr_len,handle_t * handles,uint32_t num_handles)210 int send(handle_t fd,
211 const void* hdr,
212 size_t hdr_len,
213 handle_t* handles,
214 uint32_t num_handles) {
215 struct trusty_ipc_iovec iovs[] = {
216 {
217 .base = (void*)hdr,
218 .len = hdr_len,
219 },
220 };
221 return send_iovs(fd, iovs, 1, handles, num_handles);
222 }
223
recv_iovs(handle_t fd,struct trusty_ipc_iovec * iovs,size_t iovs_cnt,handle_t * handles,uint32_t num_handles)224 static int recv_iovs(handle_t fd,
225 struct trusty_ipc_iovec* iovs,
226 size_t iovs_cnt,
227 handle_t* handles,
228 uint32_t num_handles) {
229 assert(num_handles == 0);
230 struct trusty_ipc_chan* chan = tidl_get_channel(fd);
231 assert(chan);
232 trusty_assert(chan->dev);
233 trusty_assert(chan->handle);
234 int rc = trusty_ipc_recv(chan, iovs, iovs_cnt, true);
235 return to_tidl_err(rc);
236 }
237
recv(handle_t fd,size_t min_sz,void * buf,size_t buf_sz,handle_t * handles,uint32_t num_handles)238 int recv(handle_t fd,
239 size_t min_sz,
240 void* buf,
241 size_t buf_sz,
242 handle_t* handles,
243 uint32_t num_handles) {
244 (void)min_sz;
245 struct trusty_ipc_iovec iovs[] = {
246 {
247 .base = (void*)buf,
248 .len = buf_sz,
249 },
250 };
251 return recv_iovs(fd, iovs, 1, handles, num_handles);
252 }
253
send(handle_t fd,const void * hdr,size_t hdr_len,const void * payload1,size_t payload1_len,handle_t * handles,uint32_t num_handles)254 int send(handle_t fd,
255 const void* hdr,
256 size_t hdr_len,
257 const void* payload1,
258 size_t payload1_len,
259 handle_t* handles,
260 uint32_t num_handles) {
261 struct trusty_ipc_iovec iovs[] = {
262 {
263 .base = (void*)hdr,
264 .len = hdr_len,
265 },
266 {
267 .base = (void*)payload1,
268 .len = payload1_len,
269 },
270 };
271 return send_iovs(fd, iovs, 2, handles, num_handles);
272 }
273
recv(handle_t fd,size_t min_sz,void * buf1,size_t buf1_sz,void * buf2,size_t buf2_sz,handle_t * handles,uint32_t num_handles)274 int recv(handle_t fd,
275 size_t min_sz,
276 void* buf1,
277 size_t buf1_sz,
278 void* buf2,
279 size_t buf2_sz,
280 handle_t* handles,
281 uint32_t num_handles) {
282 assert(num_handles == 0);
283 struct trusty_ipc_iovec iovs[] = {
284 {
285 .base = buf1,
286 .len = buf1_sz,
287 },
288 {
289 .base = buf2,
290 .len = buf2_sz,
291 },
292 };
293 return recv_iovs(fd, iovs, 2, handles, num_handles);
294 }
295
send(handle_t fd,const void * hdr,size_t hdr_len,const void * payload1,size_t payload1_len,const void * payload2,size_t payload2_len,handle_t * handles,uint32_t num_handles)296 int send(handle_t fd,
297 const void* hdr,
298 size_t hdr_len,
299 const void* payload1,
300 size_t payload1_len,
301 const void* payload2,
302 size_t payload2_len,
303 handle_t* handles,
304 uint32_t num_handles) {
305 assert(num_handles == 0);
306 struct trusty_ipc_iovec iovs[] = {
307 {
308 .base = (void*)hdr,
309 .len = hdr_len,
310 },
311 {
312 .base = (void*)payload1,
313 .len = payload1_len,
314 },
315 {
316 .base = (void*)payload2,
317 .len = payload2_len,
318 },
319 };
320 return send_iovs(fd, iovs, 3, handles, num_handles);
321 }
322
recv(handle_t fd,size_t min_sz,void * buf1,size_t buf1_sz,void * buf2,size_t buf2_sz,void * buf3,size_t buf3_sz,handle_t * handles,uint32_t num_handles)323 int recv(handle_t fd,
324 size_t min_sz,
325 void* buf1,
326 size_t buf1_sz,
327 void* buf2,
328 size_t buf2_sz,
329 void* buf3,
330 size_t buf3_sz,
331 handle_t* handles,
332 uint32_t num_handles) {
333 assert(num_handles == 0);
334 struct trusty_ipc_iovec iovs[] = {
335 {
336 .base = buf1,
337 .len = buf1_sz,
338 },
339 {
340 .base = buf2,
341 .len = buf2_sz,
342 },
343 {
344 .base = buf3,
345 .len = buf3_sz,
346 },
347 };
348 return recv_iovs(fd, iovs, 3, handles, num_handles);
349 }
350
wait_for_msg(handle_t chan)351 int wait_for_msg(handle_t chan) {
352 (void)chan;
353 return NO_ERROR;
354 }
355
356 } // namespace ipc
357 } // namespace tidl
358