source: mainline/kernel/generic/src/ipc/sysipc.c@ 503ffce

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

Return IPC_CALLID_* in call data instead of callid

Callid will be replaced by capability handles soon so the API needs
to be cleanup up and any flags passed together with callid must be
passed using some other way.

  • Property mode set to 100644
File size: 23.5 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup genericipc
30 * @{
31 */
32/** @file
33 */
34
35#include <arch.h>
36#include <assert.h>
37#include <errno.h>
38#include <mem.h>
39#include <ipc/ipc.h>
40#include <abi/ipc/methods.h>
41#include <ipc/sysipc.h>
42#include <ipc/sysipc_ops.h>
43#include <ipc/sysipc_priv.h>
44#include <ipc/irq.h>
45#include <ipc/ipcrsc.h>
46#include <ipc/event.h>
47#include <ipc/kbox.h>
48#include <synch/waitq.h>
49#include <arch/interrupt.h>
50#include <syscall/copy.h>
51#include <security/perm.h>
52#include <console/console.h>
53#include <print.h>
54#include <macros.h>
55
56#define STRUCT_TO_USPACE(dst, src) copy_to_uspace((dst), (src), sizeof(*(src)))
57
58/** Decide if the interface and method is a system method.
59 *
60 * @param imethod Interface and method to be decided.
61 *
62 * @return True if the interface and method is a system
63 * interface and method.
64 *
65 */
66static inline bool method_is_system(sysarg_t imethod)
67{
68 if (imethod <= IPC_M_LAST_SYSTEM)
69 return true;
70
71 return false;
72}
73
74/** Decide if the message with this interface and method is forwardable.
75 *
76 * Some system messages may be forwarded, for some of them
77 * it is useless.
78 *
79 * @param imethod Interface and method to be decided.
80 *
81 * @return True if the interface and method is forwardable.
82 *
83 */
84static inline bool method_is_forwardable(sysarg_t imethod)
85{
86 switch (imethod) {
87 case IPC_M_PHONE_HUNGUP:
88 /* This message is meant only for the original recipient. */
89 return false;
90 default:
91 return true;
92 }
93}
94
95/** Decide if the message with this interface and method is immutable on forward.
96 *
97 * Some system messages may be forwarded but their content cannot be altered.
98 *
99 * @param imethod Interface and method to be decided.
100 *
101 * @return True if the interface and method is immutable on forward.
102 *
103 */
104static inline bool method_is_immutable(sysarg_t imethod)
105{
106 switch (imethod) {
107 case IPC_M_PAGE_IN:
108 case IPC_M_SHARE_OUT:
109 case IPC_M_SHARE_IN:
110 case IPC_M_DATA_WRITE:
111 case IPC_M_DATA_READ:
112 case IPC_M_STATE_CHANGE_AUTHORIZE:
113 return true;
114 default:
115 return false;
116 }
117}
118
119
120/***********************************************************************
121 * Functions that preprocess answer before sending it to the recepient.
122 ***********************************************************************/
123
124/** Decide if the caller (e.g. ipc_answer()) should save the old call contents
125 * for answer_preprocess().
126 *
127 * @param call Call structure to be decided.
128 *
129 * @return true if the old call contents should be saved.
130 *
131 */
132static inline bool answer_need_old(call_t *call)
133{
134 switch (IPC_GET_IMETHOD(call->data)) {
135 case IPC_M_CONNECT_TO_ME:
136 case IPC_M_CONNECT_ME_TO:
137 case IPC_M_PAGE_IN:
138 case IPC_M_SHARE_OUT:
139 case IPC_M_SHARE_IN:
140 case IPC_M_DATA_WRITE:
141 case IPC_M_DATA_READ:
142 case IPC_M_STATE_CHANGE_AUTHORIZE:
143 return true;
144 default:
145 return false;
146 }
147}
148
149/** Interpret process answer as control information.
150 *
151 * This function is called directly after sys_ipc_answer().
152 *
153 * @param answer Call structure with the answer.
154 * @param olddata Saved data of the request.
155 *
156 * @return Return EOK on success or a negative error code.
157 *
158 */
159int answer_preprocess(call_t *answer, ipc_data_t *olddata)
160{
161 int rc = EOK;
162
163 spinlock_lock(&answer->forget_lock);
164 if (answer->forget) {
165 /*
166 * This is a forgotten call and answer->sender is not valid.
167 */
168 spinlock_unlock(&answer->forget_lock);
169
170 SYSIPC_OP(answer_cleanup, answer, olddata);
171 return rc;
172 } else {
173 assert(answer->active);
174
175 /*
176 * Mark the call as inactive to prevent _ipc_answer_free_call()
177 * from attempting to remove the call from the active list
178 * itself.
179 */
180 answer->active = false;
181
182 /*
183 * Remove the call from the sender's active call list.
184 * We enforce this locking order so that any potential
185 * concurrently executing forget operation is forced to
186 * release its active_calls_lock and lose the race to
187 * forget this soon to be answered call.
188 */
189 spinlock_lock(&answer->sender->active_calls_lock);
190 list_remove(&answer->ta_link);
191 spinlock_unlock(&answer->sender->active_calls_lock);
192 }
193 spinlock_unlock(&answer->forget_lock);
194
195 if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
196 phone_t *phone = answer->caller_phone;
197 mutex_lock(&phone->lock);
198 if (phone->state == IPC_PHONE_CONNECTED) {
199 irq_spinlock_lock(&phone->callee->lock, true);
200 list_remove(&phone->link);
201 /* Drop callee->connected_phones reference */
202 kobject_put(phone->kobject);
203 phone->state = IPC_PHONE_SLAMMED;
204 irq_spinlock_unlock(&phone->callee->lock, true);
205 }
206 mutex_unlock(&phone->lock);
207 }
208
209 if (!olddata)
210 return rc;
211
212 return SYSIPC_OP(answer_preprocess, answer, olddata);
213}
214
215/** Called before the request is sent.
216 *
217 * @param call Call structure with the request.
218 * @param phone Phone that the call will be sent through.
219 *
220 * @return Return 0 on success, ELIMIT or EPERM on error.
221 *
222 */
223static int request_preprocess(call_t *call, phone_t *phone)
224{
225 call->request_method = IPC_GET_IMETHOD(call->data);
226 return SYSIPC_OP(request_preprocess, call, phone);
227}
228
229/*******************************************************************************
230 * Functions called to process received call/answer before passing it to uspace.
231 *******************************************************************************/
232
233/** Do basic kernel processing of received call answer.
234 *
235 * @param call Call structure with the answer.
236 *
237 */
238static void process_answer(call_t *call)
239{
240 if (((native_t) IPC_GET_RETVAL(call->data) == EHANGUP) &&
241 (call->flags & IPC_CALL_FORWARDED))
242 IPC_SET_RETVAL(call->data, EFORWARD);
243
244 SYSIPC_OP(answer_process, call);
245}
246
247
248/** Do basic kernel processing of received call request.
249 *
250 * @param box Destination answerbox structure.
251 * @param call Call structure with the request.
252 *
253 * @return 0 if the call should be passed to userspace.
254 * @return -1 if the call should be ignored.
255 *
256 */
257static int process_request(answerbox_t *box, call_t *call)
258{
259 return SYSIPC_OP(request_process, call, box);
260}
261
262/** Make a call over IPC and wait for reply.
263 *
264 * @param handle Phone capability handle for the call.
265 * @param data[inout] Structure with request/reply data.
266 * @param priv Value to be stored in call->priv.
267 *
268 * @return EOK on success.
269 * @return ENOENT if there is no such phone handle.
270 *
271 */
272int ipc_req_internal(cap_handle_t handle, ipc_data_t *data, sysarg_t priv)
273{
274 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
275 if (!kobj->phone)
276 return ENOENT;
277
278 call_t *call = ipc_call_alloc(0);
279 call->priv = priv;
280 memcpy(call->data.args, data->args, sizeof(data->args));
281
282 int rc = request_preprocess(call, kobj->phone);
283 if (!rc) {
284#ifdef CONFIG_UDEBUG
285 udebug_stoppable_begin();
286#endif
287
288 kobject_add_ref(call->kobject);
289 rc = ipc_call_sync(kobj->phone, call);
290 spinlock_lock(&call->forget_lock);
291 bool forgotten = call->forget;
292 spinlock_unlock(&call->forget_lock);
293 kobject_put(call->kobject);
294
295#ifdef CONFIG_UDEBUG
296 udebug_stoppable_end();
297#endif
298
299 if (rc != EOK) {
300 if (!forgotten) {
301 /*
302 * There was an error, but it did not result
303 * in the call being forgotten. In fact, the
304 * call was not even sent. We are still
305 * its owners and are responsible for its
306 * deallocation.
307 */
308 kobject_put(call->kobject);
309 } else {
310 /*
311 * The call was forgotten and it changed hands.
312 * We are no longer expected to free it.
313 */
314 assert(rc == EINTR);
315 }
316 kobject_put(kobj);
317 return rc;
318 }
319
320 process_answer(call);
321 } else
322 IPC_SET_RETVAL(call->data, rc);
323
324 memcpy(data->args, call->data.args, sizeof(data->args));
325 kobject_put(call->kobject);
326 kobject_put(kobj);
327
328 return EOK;
329}
330
331/** Check that the task did not exceed the allowed limit of asynchronous calls
332 * made over a phone.
333 *
334 * @param phone Phone to check the limit against.
335 *
336 * @return 0 if limit not reached or -1 if limit exceeded.
337 *
338 */
339static int check_call_limit(phone_t *phone)
340{
341 if (atomic_get(&phone->active_calls) >= IPC_MAX_ASYNC_CALLS)
342 return -1;
343
344 return 0;
345}
346
347/** Make a fast asynchronous call over IPC.
348 *
349 * This function can only handle three arguments of payload, but is faster than
350 * the generic function sys_ipc_call_async_slow().
351 *
352 * @param handle Phone capability handle for the call.
353 * @param imethod Interface and method of the call.
354 * @param arg1 Service-defined payload argument.
355 * @param arg2 Service-defined payload argument.
356 * @param arg3 Service-defined payload argument.
357 * @param label User-defined label.
358 *
359 * @return Call hash on success.
360 * @return IPC_CALLRET_FATAL in case of a fatal error.
361 *
362 */
363sysarg_t sys_ipc_call_async_fast(sysarg_t handle, sysarg_t imethod,
364 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t label)
365{
366 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
367 if (!kobj)
368 return IPC_CALLRET_FATAL;
369
370 if (check_call_limit(kobj->phone)) {
371 kobject_put(kobj);
372 return IPC_CALLRET_FATAL;
373 }
374
375 call_t *call = ipc_call_alloc(0);
376 IPC_SET_IMETHOD(call->data, imethod);
377 IPC_SET_ARG1(call->data, arg1);
378 IPC_SET_ARG2(call->data, arg2);
379 IPC_SET_ARG3(call->data, arg3);
380
381 /*
382 * To achieve deterministic behavior, zero out arguments that are beyond
383 * the limits of the fast version.
384 */
385 IPC_SET_ARG5(call->data, 0);
386
387 /* Set the user-defined label */
388 call->data.label = label;
389
390 int res = request_preprocess(call, kobj->phone);
391
392 if (!res)
393 ipc_call(kobj->phone, call);
394 else
395 ipc_backsend_err(kobj->phone, call, res);
396
397 kobject_put(kobj);
398 return (sysarg_t) call;
399}
400
401/** Make an asynchronous IPC call allowing to transmit the entire payload.
402 *
403 * @param handle Phone capability for the call.
404 * @param data Userspace address of call data with the request.
405 * @param label User-defined label.
406 *
407 * @return See sys_ipc_call_async_fast().
408 *
409 */
410sysarg_t sys_ipc_call_async_slow(sysarg_t handle, ipc_data_t *data,
411 sysarg_t label)
412{
413 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
414 if (!kobj)
415 return IPC_CALLRET_FATAL;
416
417 if (check_call_limit(kobj->phone)) {
418 kobject_put(kobj);
419 return IPC_CALLRET_FATAL;
420 }
421
422 call_t *call = ipc_call_alloc(0);
423 int rc = copy_from_uspace(&call->data.args, &data->args,
424 sizeof(call->data.args));
425 if (rc != 0) {
426 kobject_put(call->kobject);
427 kobject_put(kobj);
428 return (sysarg_t) rc;
429 }
430
431 /* Set the user-defined label */
432 call->data.label = label;
433
434 int res = request_preprocess(call, kobj->phone);
435
436 if (!res)
437 ipc_call(kobj->phone, call);
438 else
439 ipc_backsend_err(kobj->phone, call, res);
440
441 kobject_put(kobj);
442 return (sysarg_t) call;
443}
444
445/** Forward a received call to another destination
446 *
447 * Common code for both the fast and the slow version.
448 *
449 * @param callid Hash of the call to forward.
450 * @param handle Phone capability to use for forwarding.
451 * @param imethod New interface and method to use for the forwarded call.
452 * @param arg1 New value of the first argument for the forwarded call.
453 * @param arg2 New value of the second argument for the forwarded call.
454 * @param arg3 New value of the third argument for the forwarded call.
455 * @param arg4 New value of the fourth argument for the forwarded call.
456 * @param arg5 New value of the fifth argument for the forwarded call.
457 * @param mode Flags that specify mode of the forward operation.
458 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise
459 * the function considers only the fast version arguments:
460 * i.e. arg1 and arg2.
461 *
462 * @return 0 on succes, otherwise an error code.
463 *
464 * Warning: Make sure that ARG5 is not rewritten for certain system IPC
465 *
466 */
467static sysarg_t sys_ipc_forward_common(sysarg_t callid, sysarg_t handle,
468 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
469 sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
470{
471 call_t *call = get_call(callid);
472 if (!call)
473 return ENOENT;
474
475 ipc_data_t old;
476 bool need_old = answer_need_old(call);
477 if (need_old)
478 old = call->data;
479
480 bool after_forward = false;
481 int rc;
482
483 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
484 if (!kobj) {
485 rc = ENOENT;
486 goto error;
487 }
488
489 if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
490 rc = EPERM;
491 goto error;
492 }
493
494 call->flags |= IPC_CALL_FORWARDED;
495
496 /*
497 * User space is not allowed to change interface and method of system
498 * methods on forward, allow changing ARG1, ARG2, ARG3 and ARG4 by
499 * means of imethod, arg1, arg2 and arg3.
500 * If the interface and method is immutable, don't change anything.
501 */
502 if (!method_is_immutable(IPC_GET_IMETHOD(call->data))) {
503 if (method_is_system(IPC_GET_IMETHOD(call->data))) {
504 if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME)
505 phone_dealloc(IPC_GET_ARG5(call->data));
506
507 IPC_SET_ARG1(call->data, imethod);
508 IPC_SET_ARG2(call->data, arg1);
509 IPC_SET_ARG3(call->data, arg2);
510
511 if (slow)
512 IPC_SET_ARG4(call->data, arg3);
513
514 /*
515 * For system methods we deliberately don't
516 * overwrite ARG5.
517 */
518 } else {
519 IPC_SET_IMETHOD(call->data, imethod);
520 IPC_SET_ARG1(call->data, arg1);
521 IPC_SET_ARG2(call->data, arg2);
522 if (slow) {
523 IPC_SET_ARG3(call->data, arg3);
524 IPC_SET_ARG4(call->data, arg4);
525 IPC_SET_ARG5(call->data, arg5);
526 }
527 }
528 }
529
530 rc = ipc_forward(call, kobj->phone, &TASK->answerbox, mode);
531 if (rc != EOK) {
532 after_forward = true;
533 goto error;
534 }
535
536 kobject_put(kobj);
537 return EOK;
538
539error:
540 IPC_SET_RETVAL(call->data, EFORWARD);
541 (void) answer_preprocess(call, need_old ? &old : NULL);
542 if (after_forward)
543 _ipc_answer_free_call(call, false);
544 else
545 ipc_answer(&TASK->answerbox, call);
546
547 if (kobj)
548 kobject_put(kobj);
549 return rc;
550}
551
552/** Forward a received call to another destination - fast version.
553 *
554 * In case the original interface and method is a system method, ARG1, ARG2
555 * and ARG3 are overwritten in the forwarded message with the new method and
556 * the new arg1 and arg2, respectively. Otherwise the IMETHOD, ARG1 and ARG2
557 * are rewritten with the new interface and method, arg1 and arg2, respectively.
558 * Also note there is a set of immutable methods, for which the new method and
559 * arguments are not set and these values are ignored.
560 *
561 * @param callid Hash of the call to forward.
562 * @param handle Phone handle to use for forwarding.
563 * @param imethod New interface and method to use for the forwarded call.
564 * @param arg1 New value of the first argument for the forwarded call.
565 * @param arg2 New value of the second argument for the forwarded call.
566 * @param mode Flags that specify mode of the forward operation.
567 *
568 * @return 0 on succes, otherwise an error code.
569 *
570 */
571sysarg_t sys_ipc_forward_fast(sysarg_t callid, sysarg_t handle,
572 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
573{
574 return sys_ipc_forward_common(callid, handle, imethod, arg1, arg2, 0, 0,
575 0, mode, false);
576}
577
578/** Forward a received call to another destination - slow version.
579 *
580 * This function is the slow verision of the sys_ipc_forward_fast interface.
581 * It can copy all five new arguments and the new interface and method from
582 * the userspace. It naturally extends the functionality of the fast version.
583 * For system methods, it additionally stores the new value of arg3 to ARG4.
584 * For non-system methods, it additionally stores the new value of arg3, arg4
585 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
586 *
587 * @param callid Hash of the call to forward.
588 * @param handle Phone handle to use for forwarding.
589 * @param data Userspace address of the new IPC data.
590 * @param mode Flags that specify mode of the forward operation.
591 *
592 * @return 0 on succes, otherwise an error code.
593 *
594 */
595sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t handle,
596 ipc_data_t *data, unsigned int mode)
597{
598 ipc_data_t newdata;
599 int rc = copy_from_uspace(&newdata.args, &data->args,
600 sizeof(newdata.args));
601 if (rc != 0)
602 return (sysarg_t) rc;
603
604 return sys_ipc_forward_common(callid, handle,
605 IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
606 IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
607 IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
608}
609
610/** Answer an IPC call - fast version.
611 *
612 * This function can handle only two return arguments of payload, but is faster
613 * than the generic sys_ipc_answer().
614 *
615 * @param callid Hash of the call to be answered.
616 * @param retval Return value of the answer.
617 * @param arg1 Service-defined return value.
618 * @param arg2 Service-defined return value.
619 * @param arg3 Service-defined return value.
620 * @param arg4 Service-defined return value.
621 *
622 * @return 0 on success, otherwise an error code.
623 *
624 */
625sysarg_t sys_ipc_answer_fast(sysarg_t callid, sysarg_t retval,
626 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
627{
628 /* Do not answer notification callids */
629 if (callid & IPC_CALLID_NOTIFICATION)
630 return 0;
631
632 call_t *call = get_call(callid);
633 if (!call)
634 return ENOENT;
635
636 ipc_data_t saved_data;
637 bool saved;
638
639 if (answer_need_old(call)) {
640 memcpy(&saved_data, &call->data, sizeof(call->data));
641 saved = true;
642 } else
643 saved = false;
644
645 IPC_SET_RETVAL(call->data, retval);
646 IPC_SET_ARG1(call->data, arg1);
647 IPC_SET_ARG2(call->data, arg2);
648 IPC_SET_ARG3(call->data, arg3);
649 IPC_SET_ARG4(call->data, arg4);
650
651 /*
652 * To achieve deterministic behavior, zero out arguments that are beyond
653 * the limits of the fast version.
654 */
655 IPC_SET_ARG5(call->data, 0);
656 int rc = answer_preprocess(call, saved ? &saved_data : NULL);
657
658 ipc_answer(&TASK->answerbox, call);
659 return rc;
660}
661
662/** Answer an IPC call.
663 *
664 * @param callid Hash of the call to be answered.
665 * @param data Userspace address of call data with the answer.
666 *
667 * @return 0 on success, otherwise an error code.
668 *
669 */
670sysarg_t sys_ipc_answer_slow(sysarg_t callid, ipc_data_t *data)
671{
672 /* Do not answer notification callids */
673 if (callid & IPC_CALLID_NOTIFICATION)
674 return 0;
675
676 call_t *call = get_call(callid);
677 if (!call)
678 return ENOENT;
679
680 ipc_data_t saved_data;
681 bool saved;
682
683 if (answer_need_old(call)) {
684 memcpy(&saved_data, &call->data, sizeof(call->data));
685 saved = true;
686 } else
687 saved = false;
688
689 int rc = copy_from_uspace(&call->data.args, &data->args,
690 sizeof(call->data.args));
691 if (rc != 0)
692 return rc;
693
694 rc = answer_preprocess(call, saved ? &saved_data : NULL);
695
696 ipc_answer(&TASK->answerbox, call);
697 return rc;
698}
699
700/** Hang up a phone.
701 *
702 * @param handle Phone capability handle of the phone to be hung up.
703 *
704 * @return 0 on success or an error code.
705 *
706 */
707sysarg_t sys_ipc_hangup(sysarg_t handle)
708{
709 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
710 if (!kobj)
711 return ENOENT;
712
713 if (ipc_phone_hangup(kobj->phone)) {
714 kobject_put(kobj);
715 return -1;
716 }
717
718 kobject_put(kobj);
719 return 0;
720}
721
722/** Wait for an incoming IPC call or an answer.
723 *
724 * @param calldata Pointer to buffer where the call/answer data is stored.
725 * @param usec Timeout. See waitq_sleep_timeout() for explanation.
726 * @param flags Select mode of sleep operation. See waitq_sleep_timeout()
727 * for explanation.
728 *
729 * @return Hash of the call.
730 */
731sysarg_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
732 unsigned int flags)
733{
734 call_t *call;
735
736restart:
737
738#ifdef CONFIG_UDEBUG
739 udebug_stoppable_begin();
740#endif
741
742 call = ipc_wait_for_call(&TASK->answerbox, usec,
743 flags | SYNCH_FLAGS_INTERRUPTIBLE);
744
745#ifdef CONFIG_UDEBUG
746 udebug_stoppable_end();
747#endif
748
749 if (!call)
750 return 0;
751
752 if (call->flags & IPC_CALL_NOTIF) {
753 /* Set in_phone_hash to the interrupt counter */
754 call->data.phone = (void *) call->priv;
755
756 call->data.flags = IPC_CALLID_NOTIFICATION;
757
758 STRUCT_TO_USPACE(calldata, &call->data);
759 kobject_put(call->kobject);
760
761 return (sysarg_t) call;
762 }
763
764 if (call->flags & IPC_CALL_ANSWERED) {
765 process_answer(call);
766
767 if (call->flags & IPC_CALL_DISCARD_ANSWER) {
768 kobject_put(call->kobject);
769 goto restart;
770 }
771
772 call->data.flags = IPC_CALLID_ANSWERED;
773
774 STRUCT_TO_USPACE(calldata, &call->data);
775 kobject_put(call->kobject);
776
777 return (sysarg_t) call;
778 }
779
780 if (process_request(&TASK->answerbox, call))
781 goto restart;
782
783 /* Include phone address('id') of the caller in the request,
784 * copy whole call->data, not only call->data.args */
785 if (STRUCT_TO_USPACE(calldata, &call->data)) {
786 /*
787 * The callee will not receive this call and no one else has
788 * a chance to answer it. Reply with the EPARTY error code.
789 */
790 ipc_data_t saved_data;
791 bool saved;
792
793 if (answer_need_old(call)) {
794 memcpy(&saved_data, &call->data, sizeof(call->data));
795 saved = true;
796 } else
797 saved = false;
798
799 IPC_SET_RETVAL(call->data, EPARTY);
800 (void) answer_preprocess(call, saved ? &saved_data : NULL);
801 ipc_answer(&TASK->answerbox, call);
802 return 0;
803 }
804
805 return (sysarg_t) call;
806}
807
808/** Interrupt one thread from sys_ipc_wait_for_call().
809 *
810 */
811sysarg_t sys_ipc_poke(void)
812{
813 waitq_unsleep(&TASK->answerbox.wq);
814 return EOK;
815}
816
817/** Connect an IRQ handler to a task.
818 *
819 * @param inr IRQ number.
820 * @param imethod Interface and method to be associated with the notification.
821 * @param ucode Uspace pointer to the top-half pseudocode.
822 *
823 * @return IRQ kernel object capability
824 * @return EPERM
825 * @return Error code returned by ipc_irq_subscribe().
826 *
827 */
828sysarg_t sys_ipc_irq_subscribe(inr_t inr, sysarg_t imethod, irq_code_t *ucode)
829{
830 if (!(perm_get(TASK) & PERM_IRQ_REG))
831 return EPERM;
832
833 return ipc_irq_subscribe(&TASK->answerbox, inr, imethod, ucode);
834}
835
836/** Disconnect an IRQ handler from a task.
837 *
838 * @param inr IRQ number.
839 * @param devno Device number.
840 *
841 * @return Zero on success or EPERM on error.
842 *
843 */
844sysarg_t sys_ipc_irq_unsubscribe(sysarg_t cap)
845{
846 if (!(perm_get(TASK) & PERM_IRQ_REG))
847 return EPERM;
848
849 ipc_irq_unsubscribe(&TASK->answerbox, cap);
850
851 return 0;
852}
853
854#ifdef __32_BITS__
855
856/** Syscall connect to a task by ID (32 bits)
857 *
858 * @return Phone id on success, or negative error code.
859 *
860 */
861sysarg_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid)
862{
863#ifdef CONFIG_UDEBUG
864 sysarg64_t taskid;
865 int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t));
866 if (rc != 0)
867 return (sysarg_t) rc;
868
869 return ipc_connect_kbox((task_id_t) taskid);
870#else
871 return (sysarg_t) ENOTSUP;
872#endif
873}
874
875#endif /* __32_BITS__ */
876
877#ifdef __64_BITS__
878
879/** Syscall connect to a task by ID (64 bits)
880 *
881 * @return Phone id on success, or negative error code.
882 *
883 */
884sysarg_t sys_ipc_connect_kbox(sysarg_t taskid)
885{
886#ifdef CONFIG_UDEBUG
887 return ipc_connect_kbox((task_id_t) taskid);
888#else
889 return (sysarg_t) ENOTSUP;
890#endif
891}
892
893#endif /* __64_BITS__ */
894
895/** @}
896 */
Note: See TracBrowser for help on using the repository browser.