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