source: mainline/uspace/lib/c/generic/ipc.c@ ab6edb6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ab6edb6 was eadaeae8, checked in by Jakub Jermar <jakub@…>, 7 years ago

Make capability handles type-safe

Define distinct pointer types for the handles of the supported
capability types and use them instead of integer handles. This makes it
virtually impossible to pass a non-handle or a handle of different type
instead of the proper handle. Also turn cap_handle_t into an "untyped"
capability handle that can be assigned to and from the "typed" handles.

This commit also fixes a bug in msim-con driver, which wrongly used the
IRQ number instead of the IRQ capability handle to unregister the IRQ.

This commit also fixes the wrong use of the capability handle instead
of error code in libusbhost.

  • Property mode set to 100644
File size: 11.2 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * Copyright (c) 2017 Jakub Jermar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libc
31 * @{
32 * @}
33 */
34
35/** @addtogroup libcipc IPC
36 * @brief HelenOS uspace IPC
37 * @{
38 * @ingroup libc
39 */
40/** @file
41 */
42
43#include <ipc/ipc.h>
44#include <libc.h>
45#include <stdlib.h>
46#include <errno.h>
47#include <adt/list.h>
48#include <futex.h>
49#include <fibril.h>
50#include <macros.h>
51
52/**
53 * Structures of this type are used for keeping track of sent asynchronous calls.
54 */
55typedef struct async_call {
56 ipc_async_callback_t callback;
57 void *private;
58
59 struct {
60 ipc_call_t data;
61 } msg;
62} async_call_t;
63
64/** Prologue for ipc_call_async_*() functions.
65 *
66 * @param private Argument for the answer/error callback.
67 * @param callback Answer/error callback.
68 *
69 * @return New, partially initialized async_call structure or NULL.
70 *
71 */
72static inline async_call_t *ipc_prepare_async(void *private,
73 ipc_async_callback_t callback)
74{
75 async_call_t *call =
76 (async_call_t *) malloc(sizeof(async_call_t));
77 if (!call) {
78 if (callback)
79 callback(private, ENOMEM, NULL);
80
81 return NULL;
82 }
83
84 call->callback = callback;
85 call->private = private;
86
87 return call;
88}
89
90/** Epilogue for ipc_call_async_*() functions.
91 *
92 * @param rc Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
93 * @param call Structure returned by ipc_prepare_async().
94 */
95static inline void ipc_finish_async(errno_t rc, async_call_t *call)
96{
97 if (!call) {
98 /* Nothing to do regardless if failed or not */
99 return;
100 }
101
102 if (rc != EOK) {
103 /* Call asynchronous handler with error code */
104 if (call->callback)
105 call->callback(call->private, ENOENT, NULL);
106
107 free(call);
108 return;
109 }
110}
111
112/** Fast asynchronous call.
113 *
114 * This function can only handle three arguments of payload. It is, however,
115 * faster than the more generic ipc_call_async_slow().
116 *
117 * Note that this function is a void function.
118 *
119 * During normal operation, answering this call will trigger the callback.
120 * In case of fatal error, the callback handler is called with the proper
121 * error code. If the call cannot be temporarily made, it is queued.
122 *
123 * @param phandle Phone handle for the call.
124 * @param imethod Requested interface and method.
125 * @param arg1 Service-defined payload argument.
126 * @param arg2 Service-defined payload argument.
127 * @param arg3 Service-defined payload argument.
128 * @param private Argument to be passed to the answer/error callback.
129 * @param callback Answer or error callback.
130 */
131void ipc_call_async_fast(cap_phone_handle_t phandle, sysarg_t imethod,
132 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, void *private,
133 ipc_async_callback_t callback)
134{
135 async_call_t *call = ipc_prepare_async(private, callback);
136 if (!call)
137 return;
138
139 errno_t rc = (errno_t) __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST,
140 CAP_HANDLE_RAW(phandle), imethod, arg1, arg2, arg3,
141 (sysarg_t) call);
142
143 ipc_finish_async(rc, call);
144}
145
146/** Asynchronous call transmitting the entire payload.
147 *
148 * Note that this function is a void function.
149 *
150 * During normal operation, answering this call will trigger the callback.
151 * In case of fatal error, the callback handler is called with the proper
152 * error code. If the call cannot be temporarily made, it is queued.
153 *
154 * @param phandle Phone handle for the call.
155 * @param imethod Requested interface and method.
156 * @param arg1 Service-defined payload argument.
157 * @param arg2 Service-defined payload argument.
158 * @param arg3 Service-defined payload argument.
159 * @param arg4 Service-defined payload argument.
160 * @param arg5 Service-defined payload argument.
161 * @param private Argument to be passed to the answer/error callback.
162 * @param callback Answer or error callback.
163 */
164void ipc_call_async_slow(cap_phone_handle_t phandle, sysarg_t imethod,
165 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
166 void *private, ipc_async_callback_t callback)
167{
168 async_call_t *call = ipc_prepare_async(private, callback);
169 if (!call)
170 return;
171
172 IPC_SET_IMETHOD(call->msg.data, imethod);
173 IPC_SET_ARG1(call->msg.data, arg1);
174 IPC_SET_ARG2(call->msg.data, arg2);
175 IPC_SET_ARG3(call->msg.data, arg3);
176 IPC_SET_ARG4(call->msg.data, arg4);
177 IPC_SET_ARG5(call->msg.data, arg5);
178
179 errno_t rc = (errno_t) __SYSCALL3(SYS_IPC_CALL_ASYNC_SLOW,
180 CAP_HANDLE_RAW(phandle), (sysarg_t) &call->msg.data,
181 (sysarg_t) call);
182
183 ipc_finish_async(rc, call);
184}
185
186/** Answer received call (fast version).
187 *
188 * The fast answer makes use of passing retval and first four arguments in
189 * registers. If you need to return more, use the ipc_answer_slow() instead.
190 *
191 * @param chandle Handle of the call being answered.
192 * @param retval Return value.
193 * @param arg1 First return argument.
194 * @param arg2 Second return argument.
195 * @param arg3 Third return argument.
196 * @param arg4 Fourth return argument.
197 *
198 * @return Zero on success.
199 * @return Value from @ref errno.h on failure.
200 *
201 */
202errno_t ipc_answer_fast(cap_call_handle_t chandle, errno_t retval,
203 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
204{
205 return (errno_t) __SYSCALL6(SYS_IPC_ANSWER_FAST,
206 CAP_HANDLE_RAW(chandle), (sysarg_t) retval, arg1, arg2, arg3, arg4);
207}
208
209/** Answer received call (entire payload).
210 *
211 * @param chandle Handle of the call being answered.
212 * @param retval Return value.
213 * @param arg1 First return argument.
214 * @param arg2 Second return argument.
215 * @param arg3 Third return argument.
216 * @param arg4 Fourth return argument.
217 * @param arg5 Fifth return argument.
218 *
219 * @return Zero on success.
220 * @return Value from @ref errno.h on failure.
221 *
222 */
223errno_t ipc_answer_slow(cap_call_handle_t chandle, errno_t retval,
224 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
225{
226 ipc_call_t data;
227
228 IPC_SET_RETVAL(data, retval);
229 IPC_SET_ARG1(data, arg1);
230 IPC_SET_ARG2(data, arg2);
231 IPC_SET_ARG3(data, arg3);
232 IPC_SET_ARG4(data, arg4);
233 IPC_SET_ARG5(data, arg5);
234
235 return (errno_t) __SYSCALL2(SYS_IPC_ANSWER_SLOW,
236 CAP_HANDLE_RAW(chandle), (sysarg_t) &data);
237}
238
239/** Handle received answer.
240 *
241 * @param data Call data of the answer.
242 */
243static void handle_answer(ipc_call_t *data)
244{
245 async_call_t *call = data->label;
246
247 if (!call)
248 return;
249
250 if (call->callback)
251 call->callback(call->private, IPC_GET_RETVAL(*data), data);
252 free(call);
253}
254
255/** Wait for first IPC call to come.
256 *
257 * @param[out] call Storage for the received call.
258 * @param[in] usec Timeout in microseconds
259 * @param[in[ flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
260 *
261 * @return Error code.
262 */
263errno_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec, unsigned int flags)
264{
265 errno_t rc = (errno_t) __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec,
266 flags);
267
268 /* Handle received answers */
269 if ((rc == EOK) && (call->cap_handle == CAP_NIL) &&
270 (call->flags & IPC_CALL_ANSWERED)) {
271 handle_answer(call);
272 }
273
274 return rc;
275}
276
277/** Interrupt one thread of this task from waiting for IPC.
278 *
279 */
280void ipc_poke(void)
281{
282 __SYSCALL0(SYS_IPC_POKE);
283}
284
285/** Wait for first IPC call to come.
286 *
287 * Only requests are returned, answers are processed internally.
288 *
289 * @param call Incoming call storage.
290 * @param usec Timeout in microseconds
291 *
292 * @return Error code.
293 *
294 */
295errno_t ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec)
296{
297 errno_t rc;
298
299 do {
300 rc = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
301 } while ((rc == EOK) && (call->cap_handle == CAP_NIL) &&
302 (call->flags & IPC_CALL_ANSWERED));
303
304 return rc;
305}
306
307/** Check if there is an IPC call waiting to be picked up.
308 *
309 * Only requests are returned, answers are processed internally.
310 *
311 * @param call Incoming call storage.
312 *
313 * @return Error code.
314 *
315 */
316errno_t ipc_trywait_for_call(ipc_call_t *call)
317{
318 errno_t rc;
319
320 do {
321 rc = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
322 SYNCH_FLAGS_NON_BLOCKING);
323 } while ((rc == EOK) && (call->cap_handle == CAP_NIL) &&
324 (call->flags & IPC_CALL_ANSWERED));
325
326 return rc;
327}
328
329/** Hang up a phone.
330 *
331 * @param phandle Handle of the phone to be hung up.
332 *
333 * @return Zero on success or an error code.
334 *
335 */
336errno_t ipc_hangup(cap_phone_handle_t phandle)
337{
338 return (errno_t) __SYSCALL1(SYS_IPC_HANGUP, CAP_HANDLE_RAW(phandle));
339}
340
341/** Forward a received call to another destination.
342 *
343 * For non-system methods, the old method, arg1 and arg2 are rewritten by the
344 * new values. For system methods, the new method, arg1 and arg2 are written to
345 * the old arg1, arg2 and arg3, respectivelly. Calls with immutable methods are
346 * forwarded verbatim.
347 *
348 * @param chandle Handle of the call to forward.
349 * @param phandle Phone handle to use for forwarding.
350 * @param imethod New interface and method for the forwarded call.
351 * @param arg1 New value of the first argument for the forwarded call.
352 * @param arg2 New value of the second argument for the forwarded call.
353 * @param mode Flags specifying mode of the forward operation.
354 *
355 * @return Zero on success or an error code.
356 *
357 */
358errno_t ipc_forward_fast(cap_call_handle_t chandle, cap_phone_handle_t phandle,
359 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
360{
361 return (errno_t) __SYSCALL6(SYS_IPC_FORWARD_FAST,
362 CAP_HANDLE_RAW(chandle), CAP_HANDLE_RAW(phandle), imethod, arg1,
363 arg2, mode);
364}
365
366errno_t ipc_forward_slow(cap_call_handle_t chandle, cap_phone_handle_t phandle,
367 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
368 sysarg_t arg4, sysarg_t arg5, unsigned int mode)
369{
370 ipc_call_t data;
371
372 IPC_SET_IMETHOD(data, imethod);
373 IPC_SET_ARG1(data, arg1);
374 IPC_SET_ARG2(data, arg2);
375 IPC_SET_ARG3(data, arg3);
376 IPC_SET_ARG4(data, arg4);
377 IPC_SET_ARG5(data, arg5);
378
379 return (errno_t) __SYSCALL4(SYS_IPC_FORWARD_SLOW,
380 CAP_HANDLE_RAW(chandle), CAP_HANDLE_RAW(phandle), (sysarg_t) &data,
381 mode);
382}
383
384/** Connect to a task specified by id.
385 *
386 */
387errno_t ipc_connect_kbox(task_id_t id, cap_phone_handle_t *phone)
388{
389 return (errno_t) __SYSCALL2(SYS_IPC_CONNECT_KBOX, (sysarg_t) &id, (sysarg_t) phone);
390}
391
392/** @}
393 */
Note: See TracBrowser for help on using the repository browser.