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