1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #include <trusty/trusty_ipc.h>
26 #include <trusty/util.h>
27 
28 #define LOCAL_LOG 0
29 
sync_ipc_on_connect_complete(struct trusty_ipc_chan * chan)30 static int sync_ipc_on_connect_complete(struct trusty_ipc_chan* chan) {
31     trusty_assert(chan);
32 
33     chan->complete = 1;
34     return TRUSTY_EVENT_HANDLED;
35 }
36 
sync_ipc_on_message(struct trusty_ipc_chan * chan)37 static int sync_ipc_on_message(struct trusty_ipc_chan* chan) {
38     trusty_assert(chan);
39 
40     chan->complete = 1;
41     return TRUSTY_EVENT_HANDLED;
42 }
43 
sync_ipc_on_disconnect(struct trusty_ipc_chan * chan)44 static int sync_ipc_on_disconnect(struct trusty_ipc_chan* chan) {
45     trusty_assert(chan);
46 
47     chan->complete = TRUSTY_ERR_CHANNEL_CLOSED;
48     return TRUSTY_EVENT_HANDLED;
49 }
50 
wait_for_complete(struct trusty_ipc_chan * chan)51 static int wait_for_complete(struct trusty_ipc_chan* chan) {
52     int rc;
53 
54     chan->complete = 0;
55     for (;;) {
56         rc = trusty_ipc_poll_for_event(chan->dev);
57         if (rc < 0)
58             return rc;
59 
60         if (chan->complete)
61             break;
62 
63         if (rc == TRUSTY_EVENT_NONE && !trusty_ipc_dev_has_event(chan->dev, 0))
64             trusty_ipc_dev_idle(chan->dev, true);
65     }
66 
67     return chan->complete;
68 }
69 
wait_for_connect(struct trusty_ipc_chan * chan)70 static int wait_for_connect(struct trusty_ipc_chan* chan) {
71     trusty_debug("%s: chan %x: waiting for connect\n", __func__,
72                  (int)chan->handle);
73     return wait_for_complete(chan);
74 }
75 
wait_for_send(struct trusty_ipc_chan * chan)76 static int wait_for_send(struct trusty_ipc_chan* chan) {
77     trusty_debug("%s: chan %d: waiting for send\n", __func__, chan->handle);
78     return wait_for_complete(chan);
79 }
80 
wait_for_reply(struct trusty_ipc_chan * chan)81 static int wait_for_reply(struct trusty_ipc_chan* chan) {
82     trusty_debug("%s: chan %d: waiting for reply\n", __func__, chan->handle);
83     return wait_for_complete(chan);
84 }
85 
86 static struct trusty_ipc_ops sync_ipc_ops = {
87         .on_connect_complete = sync_ipc_on_connect_complete,
88         .on_message = sync_ipc_on_message,
89         .on_disconnect = sync_ipc_on_disconnect,
90 };
91 
trusty_ipc_chan_init(struct trusty_ipc_chan * chan,struct trusty_ipc_dev * dev)92 void trusty_ipc_chan_init(struct trusty_ipc_chan* chan,
93                           struct trusty_ipc_dev* dev) {
94     trusty_assert(chan);
95     trusty_assert(dev);
96 
97     trusty_memset(chan, 0, sizeof(*chan));
98 
99     chan->handle = INVALID_IPC_HANDLE;
100     chan->dev = dev;
101     chan->ops = &sync_ipc_ops;
102     chan->ops_ctx = chan;
103 }
104 
trusty_ipc_connect(struct trusty_ipc_chan * chan,const char * port,bool wait)105 int trusty_ipc_connect(struct trusty_ipc_chan* chan,
106                        const char* port,
107                        bool wait) {
108     int rc;
109 
110     trusty_assert(chan);
111     trusty_assert(chan->dev);
112     trusty_assert(chan->handle == INVALID_IPC_HANDLE);
113     trusty_assert(port);
114 
115     rc = trusty_ipc_dev_connect(chan->dev, port, (uint64_t)(uintptr_t)chan);
116     if (rc < 0) {
117         trusty_error("%s: init connection failed (%d)\n", __func__, rc);
118         return rc;
119     }
120     chan->handle = (handle_t)rc;
121     trusty_debug("chan->handle: %x\n", (int)chan->handle);
122 
123     /* got valid channel */
124     if (wait) {
125         rc = wait_for_connect(chan);
126         if (rc < 0) {
127             trusty_error("%s: wait for connect failed (%d)\n", __func__, rc);
128             trusty_ipc_close(chan);
129         }
130     }
131 
132     return rc;
133 }
134 
trusty_ipc_close(struct trusty_ipc_chan * chan)135 int trusty_ipc_close(struct trusty_ipc_chan* chan) {
136     int rc;
137 
138     trusty_assert(chan);
139 
140     rc = trusty_ipc_dev_close(chan->dev, chan->handle);
141     chan->handle = INVALID_IPC_HANDLE;
142 
143     return rc;
144 }
145 
trusty_ipc_send(struct trusty_ipc_chan * chan,const struct trusty_ipc_iovec * iovs,size_t iovs_cnt,bool wait)146 int trusty_ipc_send(struct trusty_ipc_chan* chan,
147                     const struct trusty_ipc_iovec* iovs,
148                     size_t iovs_cnt,
149                     bool wait) {
150     int rc;
151 
152     trusty_assert(chan);
153     trusty_assert(chan->dev);
154     trusty_assert(chan->handle);
155 
156 Again:
157     rc = trusty_ipc_dev_send(chan->dev, chan->handle, iovs, iovs_cnt);
158     if (rc == TRUSTY_ERR_SEND_BLOCKED) {
159         if (wait) {
160             rc = wait_for_send(chan);
161             if (rc < 0) {
162                 trusty_error("%s: wait to send failed (%d)\n", __func__, rc);
163                 return rc;
164             }
165             goto Again;
166         }
167     }
168     return rc;
169 }
170 
trusty_ipc_recv(struct trusty_ipc_chan * chan,const struct trusty_ipc_iovec * iovs,size_t iovs_cnt,bool wait)171 int trusty_ipc_recv(struct trusty_ipc_chan* chan,
172                     const struct trusty_ipc_iovec* iovs,
173                     size_t iovs_cnt,
174                     bool wait) {
175     int rc;
176     trusty_assert(chan);
177     trusty_assert(chan->dev);
178     trusty_assert(chan->handle);
179 
180     if (wait) {
181         rc = wait_for_reply(chan);
182         if (rc < 0) {
183             trusty_error("%s: wait to reply failed (%d)\n", __func__, rc);
184             return rc;
185         }
186     }
187 
188     rc = trusty_ipc_dev_recv(chan->dev, chan->handle, iovs, iovs_cnt);
189     if (rc < 0)
190         trusty_error("%s: ipc recv failed (%d)\n", __func__, rc);
191 
192     return rc;
193 }
194 
trusty_ipc_poll_for_event(struct trusty_ipc_dev * ipc_dev)195 int trusty_ipc_poll_for_event(struct trusty_ipc_dev* ipc_dev) {
196     int rc;
197     struct trusty_ipc_event evt;
198     struct trusty_ipc_chan* chan;
199 
200     trusty_assert(ipc_dev);
201 
202     rc = trusty_ipc_dev_get_event(ipc_dev, 0, &evt);
203     if (rc) {
204         trusty_error("%s: get event failed (%d)\n", __func__, rc);
205         return rc;
206     }
207 
208     /* check if we have an event */
209     if (!evt.event) {
210         trusty_debug("%s: no event\n", __func__);
211         return TRUSTY_EVENT_NONE;
212     }
213 
214     chan = (struct trusty_ipc_chan*)(uintptr_t)evt.cookie;
215     trusty_assert(chan && chan->ops);
216 
217     /* check if we have raw event handler */
218     if (chan->ops->on_raw_event) {
219         /* invoke it first */
220         rc = chan->ops->on_raw_event(chan, &evt);
221         if (rc < 0) {
222             trusty_error("%s: chan %d: raw event cb returned (%d)\n", __func__,
223                          chan->handle, rc);
224             return rc;
225         }
226         if (rc > 0)
227             return rc; /* handled */
228     }
229 
230     if (evt.event & IPC_HANDLE_POLL_ERROR) {
231         /* something is very wrong */
232         trusty_error("%s: chan %d: chan in error state\n", __func__,
233                      chan->handle);
234         return TRUSTY_ERR_GENERIC;
235     }
236 
237     /* send unblocked should be handled first as it is edge truggered event */
238     if (evt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
239         if (chan->ops->on_send_unblocked) {
240             rc = chan->ops->on_send_unblocked(chan);
241             if (rc < 0) {
242                 trusty_error("%s: chan %d: send unblocked cb returned (%d)\n",
243                              __func__, chan->handle, rc);
244                 return rc;
245             }
246             if (rc > 0)
247                 return rc; /* handled */
248         }
249     }
250 
251     /* check for connection complete */
252     if (evt.event & IPC_HANDLE_POLL_READY) {
253         if (chan->ops->on_connect_complete) {
254             rc = chan->ops->on_connect_complete(chan);
255             if (rc < 0) {
256                 trusty_error("%s: chan %d: ready cb returned (%d)\n", __func__,
257                              chan->handle, rc);
258                 return rc;
259             }
260             if (rc > 0)
261                 return rc; /* handled */
262         }
263     }
264 
265     /* check for incomming messages */
266     if (evt.event & IPC_HANDLE_POLL_MSG) {
267         if (chan->ops->on_message) {
268             rc = chan->ops->on_message(chan);
269             if (rc < 0) {
270                 trusty_error("%s: chan %d: msg cb returned (%d)\n", __func__,
271                              chan->handle, rc);
272                 return rc;
273             }
274             if (rc > 0)
275                 return rc;
276         }
277     }
278 
279     /* check for hangups */
280     if (evt.event & IPC_HANDLE_POLL_HUP) {
281         if (chan->ops->on_disconnect) {
282             rc = chan->ops->on_disconnect(chan);
283             if (rc < 0) {
284                 trusty_error("%s: chan %d: hup cb returned (%d)\n", __func__,
285                              chan->handle, rc);
286                 return rc;
287             }
288             if (rc > 0)
289                 return rc;
290         }
291     }
292 
293     return TRUSTY_ERR_NONE;
294 }
295