source: mainline/kernel/generic/src/ipc/sysipc.c@ 8a45bf09

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

Remove SYS_DEVICE_ASSIGN_DEVNO

  • Property mode set to 100644
File size: 23.3 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_CONNECTION_CLONE:
88 case IPC_M_CLONE_ESTABLISH:
89 case IPC_M_PHONE_HUNGUP:
90 /* This message is meant only for the original recipient. */
91 return false;
92 default:
93 return true;
94 }
95}
96
97/** Decide if the message with this interface and method is immutable on forward.
98 *
99 * Some system messages may be forwarded but their content cannot be altered.
100 *
101 * @param imethod Interface and method to be decided.
102 *
103 * @return True if the interface and method is immutable on forward.
104 *
105 */
106static inline bool method_is_immutable(sysarg_t imethod)
107{
108 switch (imethod) {
109 case IPC_M_PAGE_IN:
110 case IPC_M_SHARE_OUT:
111 case IPC_M_SHARE_IN:
112 case IPC_M_DATA_WRITE:
113 case IPC_M_DATA_READ:
114 case IPC_M_STATE_CHANGE_AUTHORIZE:
115 return true;
116 default:
117 return false;
118 }
119}
120
121
122/***********************************************************************
123 * Functions that preprocess answer before sending it to the recepient.
124 ***********************************************************************/
125
126/** Decide if the caller (e.g. ipc_answer()) should save the old call contents
127 * for answer_preprocess().
128 *
129 * @param call Call structure to be decided.
130 *
131 * @return true if the old call contents should be saved.
132 *
133 */
134static inline bool answer_need_old(call_t *call)
135{
136 switch (IPC_GET_IMETHOD(call->data)) {
137 case IPC_M_CONNECTION_CLONE:
138 case IPC_M_CLONE_ESTABLISH:
139 case IPC_M_CONNECT_TO_ME:
140 case IPC_M_CONNECT_ME_TO:
141 case IPC_M_PAGE_IN:
142 case IPC_M_SHARE_OUT:
143 case IPC_M_SHARE_IN:
144 case IPC_M_DATA_WRITE:
145 case IPC_M_DATA_READ:
146 case IPC_M_STATE_CHANGE_AUTHORIZE:
147 return true;
148 default:
149 return false;
150 }
151}
152
153/** Interpret process answer as control information.
154 *
155 * This function is called directly after sys_ipc_answer().
156 *
157 * @param answer Call structure with the answer.
158 * @param olddata Saved data of the request.
159 *
160 * @return Return EOK on success or a negative error code.
161 *
162 */
163int answer_preprocess(call_t *answer, ipc_data_t *olddata)
164{
165 int rc = EOK;
166
167 spinlock_lock(&answer->forget_lock);
168 if (answer->forget) {
169 /*
170 * This is a forgotten call and answer->sender is not valid.
171 */
172 spinlock_unlock(&answer->forget_lock);
173
174 SYSIPC_OP(answer_cleanup, answer, olddata);
175 return rc;
176 } else {
177 assert(answer->active);
178
179 /*
180 * Mark the call as inactive to prevent _ipc_answer_free_call()
181 * from attempting to remove the call from the active list
182 * itself.
183 */
184 answer->active = false;
185
186 /*
187 * Remove the call from the sender's active call list.
188 * We enforce this locking order so that any potential
189 * concurrently executing forget operation is forced to
190 * release its active_calls_lock and lose the race to
191 * forget this soon to be answered call.
192 */
193 spinlock_lock(&answer->sender->active_calls_lock);
194 list_remove(&answer->ta_link);
195 spinlock_unlock(&answer->sender->active_calls_lock);
196 }
197 spinlock_unlock(&answer->forget_lock);
198
199 if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
200 phone_t *phone = answer->caller_phone;
201 mutex_lock(&phone->lock);
202 if (phone->state == IPC_PHONE_CONNECTED) {
203 irq_spinlock_lock(&phone->callee->lock, true);
204 list_remove(&phone->link);
205 phone->state = IPC_PHONE_SLAMMED;
206 irq_spinlock_unlock(&phone->callee->lock, true);
207 }
208 mutex_unlock(&phone->lock);
209 }
210
211 if (!olddata)
212 return rc;
213
214 return SYSIPC_OP(answer_preprocess, answer, olddata);
215}
216
217/** Called before the request is sent.
218 *
219 * @param call Call structure with the request.
220 * @param phone Phone that the call will be sent through.
221 *
222 * @return Return 0 on success, ELIMIT or EPERM on error.
223 *
224 */
225static int request_preprocess(call_t *call, phone_t *phone)
226{
227 call->request_method = IPC_GET_IMETHOD(call->data);
228 return SYSIPC_OP(request_preprocess, call, phone);
229}
230
231/*******************************************************************************
232 * Functions called to process received call/answer before passing it to uspace.
233 *******************************************************************************/
234
235/** Do basic kernel processing of received call answer.
236 *
237 * @param call Call structure with the answer.
238 *
239 */
240static void process_answer(call_t *call)
241{
242 if (((native_t) IPC_GET_RETVAL(call->data) == EHANGUP) &&
243 (call->flags & IPC_CALL_FORWARDED))
244 IPC_SET_RETVAL(call->data, EFORWARD);
245
246 SYSIPC_OP(answer_process, call);
247}
248
249
250/** Do basic kernel processing of received call request.
251 *
252 * @param box Destination answerbox structure.
253 * @param call Call structure with the request.
254 *
255 * @return 0 if the call should be passed to userspace.
256 * @return -1 if the call should be ignored.
257 *
258 */
259static int process_request(answerbox_t *box, call_t *call)
260{
261 return SYSIPC_OP(request_process, call, box);
262}
263
264/** Make a call over IPC and wait for reply.
265 *
266 * @param phone_cap Phone capability for the call.
267 * @param data[inout] Structure with request/reply data.
268 * @param priv Value to be stored in call->priv.
269 *
270 * @return EOK on success.
271 * @return ENOENT if there is no such phone handle.
272 *
273 */
274int ipc_req_internal(int phone_cap, ipc_data_t *data, sysarg_t priv)
275{
276 phone_t *phone = phone_get_current(phone_cap);
277 if (!phone)
278 return ENOENT;
279
280 call_t *call = ipc_call_alloc(0);
281 call->priv = priv;
282 memcpy(call->data.args, data->args, sizeof(data->args));
283
284 int rc = request_preprocess(call, phone);
285 if (!rc) {
286#ifdef CONFIG_UDEBUG
287 udebug_stoppable_begin();
288#endif
289
290 ipc_call_hold(call);
291 rc = ipc_call_sync(phone, call);
292 spinlock_lock(&call->forget_lock);
293 bool forgotten = call->forget;
294 spinlock_unlock(&call->forget_lock);
295 ipc_call_release(call);
296
297#ifdef CONFIG_UDEBUG
298 udebug_stoppable_end();
299#endif
300
301 if (rc != EOK) {
302 if (!forgotten) {
303 /*
304 * There was an error, but it did not result
305 * in the call being forgotten. In fact, the
306 * call was not even sent. We are still
307 * its owners and are responsible for its
308 * deallocation.
309 */
310 ipc_call_free(call);
311 } else {
312 /*
313 * The call was forgotten and it changed hands.
314 * We are no longer expected to free it.
315 */
316 assert(rc == EINTR);
317 }
318 return rc;
319 }
320
321 process_answer(call);
322 } else
323 IPC_SET_RETVAL(call->data, rc);
324
325 memcpy(data->args, call->data.args, sizeof(data->args));
326 ipc_call_free(call);
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 four arguments of payload, but is faster than
350 * the generic function sys_ipc_call_async_slow().
351 *
352 * @param phone_cap Phone capability 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 arg4 Service-defined payload argument.
358 *
359 * @return Call hash on success.
360 * @return IPC_CALLRET_FATAL in case of a fatal error.
361 * @return IPC_CALLRET_TEMPORARY if there are too many pending
362 * asynchronous requests; answers should be handled first.
363 *
364 */
365sysarg_t sys_ipc_call_async_fast(sysarg_t phone_cap, sysarg_t imethod,
366 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
367{
368 phone_t *phone = phone_get_current(phone_cap);
369 if (!phone)
370 return IPC_CALLRET_FATAL;
371
372 if (check_call_limit(phone))
373 return IPC_CALLRET_TEMPORARY;
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 IPC_SET_ARG4(call->data, arg4);
381
382 /*
383 * To achieve deterministic behavior, zero out arguments that are beyond
384 * the limits of the fast version.
385 */
386 IPC_SET_ARG5(call->data, 0);
387
388 int res = request_preprocess(call, phone);
389
390 if (!res)
391 ipc_call(phone, call);
392 else
393 ipc_backsend_err(phone, call, res);
394
395 return (sysarg_t) call;
396}
397
398/** Make an asynchronous IPC call allowing to transmit the entire payload.
399 *
400 * @param phone_cap Phone capability for the call.
401 * @param data Userspace address of call data with the request.
402 *
403 * @return See sys_ipc_call_async_fast().
404 *
405 */
406sysarg_t sys_ipc_call_async_slow(sysarg_t phone_cap, ipc_data_t *data)
407{
408 phone_t *phone = phone_get_current(phone_cap);
409 if (!phone)
410 return IPC_CALLRET_FATAL;
411
412 if (check_call_limit(phone))
413 return IPC_CALLRET_TEMPORARY;
414
415 call_t *call = ipc_call_alloc(0);
416 int rc = copy_from_uspace(&call->data.args, &data->args,
417 sizeof(call->data.args));
418 if (rc != 0) {
419 ipc_call_free(call);
420 return (sysarg_t) rc;
421 }
422
423 int res = request_preprocess(call, phone);
424
425 if (!res)
426 ipc_call(phone, call);
427 else
428 ipc_backsend_err(phone, call, res);
429
430 return (sysarg_t) call;
431}
432
433/** Forward a received call to another destination
434 *
435 * Common code for both the fast and the slow version.
436 *
437 * @param callid Hash of the call to forward.
438 * @param phone_cap Phone capability to use for forwarding.
439 * @param imethod New interface and method to use for the forwarded call.
440 * @param arg1 New value of the first argument for the forwarded call.
441 * @param arg2 New value of the second argument for the forwarded call.
442 * @param arg3 New value of the third argument for the forwarded call.
443 * @param arg4 New value of the fourth argument for the forwarded call.
444 * @param arg5 New value of the fifth argument for the forwarded call.
445 * @param mode Flags that specify mode of the forward operation.
446 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise
447 * the function considers only the fast version arguments:
448 * i.e. arg1 and arg2.
449 *
450 * @return 0 on succes, otherwise an error code.
451 *
452 * Warning: Make sure that ARG5 is not rewritten for certain system IPC
453 *
454 */
455static sysarg_t sys_ipc_forward_common(sysarg_t callid, sysarg_t phone_cap,
456 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
457 sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
458{
459 call_t *call = get_call(callid);
460 if (!call)
461 return ENOENT;
462
463 ipc_data_t old;
464 bool need_old = answer_need_old(call);
465 if (need_old)
466 old = call->data;
467
468 bool after_forward = false;
469 int rc;
470
471 phone_t *phone = phone_get_current(phone_cap);
472 if (!phone) {
473 rc = ENOENT;
474 goto error;
475 }
476
477 if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
478 rc = EPERM;
479 goto error;
480 }
481
482 call->flags |= IPC_CALL_FORWARDED;
483
484 /*
485 * User space is not allowed to change interface and method of system
486 * methods on forward, allow changing ARG1, ARG2, ARG3 and ARG4 by
487 * means of imethod, arg1, arg2 and arg3.
488 * If the interface and method is immutable, don't change anything.
489 */
490 if (!method_is_immutable(IPC_GET_IMETHOD(call->data))) {
491 if (method_is_system(IPC_GET_IMETHOD(call->data))) {
492 if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME)
493 phone_dealloc(IPC_GET_ARG5(call->data));
494
495 IPC_SET_ARG1(call->data, imethod);
496 IPC_SET_ARG2(call->data, arg1);
497 IPC_SET_ARG3(call->data, arg2);
498
499 if (slow)
500 IPC_SET_ARG4(call->data, arg3);
501
502 /*
503 * For system methods we deliberately don't
504 * overwrite ARG5.
505 */
506 } else {
507 IPC_SET_IMETHOD(call->data, imethod);
508 IPC_SET_ARG1(call->data, arg1);
509 IPC_SET_ARG2(call->data, arg2);
510 if (slow) {
511 IPC_SET_ARG3(call->data, arg3);
512 IPC_SET_ARG4(call->data, arg4);
513 IPC_SET_ARG5(call->data, arg5);
514 }
515 }
516 }
517
518 rc = ipc_forward(call, phone, &TASK->answerbox, mode);
519 if (rc != EOK) {
520 after_forward = true;
521 goto error;
522 }
523
524 return EOK;
525
526error:
527 IPC_SET_RETVAL(call->data, EFORWARD);
528 (void) answer_preprocess(call, need_old ? &old : NULL);
529 if (after_forward)
530 _ipc_answer_free_call(call, false);
531 else
532 ipc_answer(&TASK->answerbox, call);
533
534 return rc;
535}
536
537/** Forward a received call to another destination - fast version.
538 *
539 * In case the original interface and method is a system method, ARG1, ARG2
540 * and ARG3 are overwritten in the forwarded message with the new method and
541 * the new arg1 and arg2, respectively. Otherwise the IMETHOD, ARG1 and ARG2
542 * are rewritten with the new interface and method, arg1 and arg2, respectively.
543 * Also note there is a set of immutable methods, for which the new method and
544 * arguments are not set and these values are ignored.
545 *
546 * @param callid Hash of the call to forward.
547 * @param phoneid Phone handle to use for forwarding.
548 * @param imethod New interface and method to use for the forwarded call.
549 * @param arg1 New value of the first argument for the forwarded call.
550 * @param arg2 New value of the second argument for the forwarded call.
551 * @param mode Flags that specify mode of the forward operation.
552 *
553 * @return 0 on succes, otherwise an error code.
554 *
555 */
556sysarg_t sys_ipc_forward_fast(sysarg_t callid, sysarg_t phoneid,
557 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
558{
559 return sys_ipc_forward_common(callid, phoneid, imethod, arg1, arg2, 0, 0,
560 0, mode, false);
561}
562
563/** Forward a received call to another destination - slow version.
564 *
565 * This function is the slow verision of the sys_ipc_forward_fast interface.
566 * It can copy all five new arguments and the new interface and method from
567 * the userspace. It naturally extends the functionality of the fast version.
568 * For system methods, it additionally stores the new value of arg3 to ARG4.
569 * For non-system methods, it additionally stores the new value of arg3, arg4
570 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
571 *
572 * @param callid Hash of the call to forward.
573 * @param phoneid Phone handle to use for forwarding.
574 * @param data Userspace address of the new IPC data.
575 * @param mode Flags that specify mode of the forward operation.
576 *
577 * @return 0 on succes, otherwise an error code.
578 *
579 */
580sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t phoneid,
581 ipc_data_t *data, unsigned int mode)
582{
583 ipc_data_t newdata;
584 int rc = copy_from_uspace(&newdata.args, &data->args,
585 sizeof(newdata.args));
586 if (rc != 0)
587 return (sysarg_t) rc;
588
589 return sys_ipc_forward_common(callid, phoneid,
590 IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
591 IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
592 IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
593}
594
595/** Answer an IPC call - fast version.
596 *
597 * This function can handle only two return arguments of payload, but is faster
598 * than the generic sys_ipc_answer().
599 *
600 * @param callid Hash of the call to be answered.
601 * @param retval Return value of the answer.
602 * @param arg1 Service-defined return value.
603 * @param arg2 Service-defined return value.
604 * @param arg3 Service-defined return value.
605 * @param arg4 Service-defined return value.
606 *
607 * @return 0 on success, otherwise an error code.
608 *
609 */
610sysarg_t sys_ipc_answer_fast(sysarg_t callid, sysarg_t retval,
611 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
612{
613 /* Do not answer notification callids */
614 if (callid & IPC_CALLID_NOTIFICATION)
615 return 0;
616
617 call_t *call = get_call(callid);
618 if (!call)
619 return ENOENT;
620
621 ipc_data_t saved_data;
622 bool saved;
623
624 if (answer_need_old(call)) {
625 memcpy(&saved_data, &call->data, sizeof(call->data));
626 saved = true;
627 } else
628 saved = false;
629
630 IPC_SET_RETVAL(call->data, retval);
631 IPC_SET_ARG1(call->data, arg1);
632 IPC_SET_ARG2(call->data, arg2);
633 IPC_SET_ARG3(call->data, arg3);
634 IPC_SET_ARG4(call->data, arg4);
635
636 /*
637 * To achieve deterministic behavior, zero out arguments that are beyond
638 * the limits of the fast version.
639 */
640 IPC_SET_ARG5(call->data, 0);
641 int rc = answer_preprocess(call, saved ? &saved_data : NULL);
642
643 ipc_answer(&TASK->answerbox, call);
644 return rc;
645}
646
647/** Answer an IPC call.
648 *
649 * @param callid Hash of the call to be answered.
650 * @param data Userspace address of call data with the answer.
651 *
652 * @return 0 on success, otherwise an error code.
653 *
654 */
655sysarg_t sys_ipc_answer_slow(sysarg_t callid, ipc_data_t *data)
656{
657 /* Do not answer notification callids */
658 if (callid & IPC_CALLID_NOTIFICATION)
659 return 0;
660
661 call_t *call = get_call(callid);
662 if (!call)
663 return ENOENT;
664
665 ipc_data_t saved_data;
666 bool saved;
667
668 if (answer_need_old(call)) {
669 memcpy(&saved_data, &call->data, sizeof(call->data));
670 saved = true;
671 } else
672 saved = false;
673
674 int rc = copy_from_uspace(&call->data.args, &data->args,
675 sizeof(call->data.args));
676 if (rc != 0)
677 return rc;
678
679 rc = answer_preprocess(call, saved ? &saved_data : NULL);
680
681 ipc_answer(&TASK->answerbox, call);
682 return rc;
683}
684
685/** Hang up a phone.
686 *
687 * @param phone_cap Phone capability of the phone to be hung up.
688 *
689 * @return 0 on success or an error code.
690 *
691 */
692sysarg_t sys_ipc_hangup(sysarg_t phone_cap)
693{
694 phone_t *phone = phone_get_current(phone_cap);
695 if (!phone)
696 return ENOENT;
697
698 if (ipc_phone_hangup(phone))
699 return -1;
700
701 return 0;
702}
703
704/** Wait for an incoming IPC call or an answer.
705 *
706 * @param calldata Pointer to buffer where the call/answer data is stored.
707 * @param usec Timeout. See waitq_sleep_timeout() for explanation.
708 * @param flags Select mode of sleep operation. See waitq_sleep_timeout()
709 * for explanation.
710 *
711 * @return Hash of the call.
712 * If IPC_CALLID_NOTIFICATION bit is set in the hash, the
713 * call is a notification. IPC_CALLID_ANSWERED denotes an
714 * answer.
715 *
716 */
717sysarg_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
718 unsigned int flags)
719{
720 call_t *call;
721
722restart:
723
724#ifdef CONFIG_UDEBUG
725 udebug_stoppable_begin();
726#endif
727
728 call = ipc_wait_for_call(&TASK->answerbox, usec,
729 flags | SYNCH_FLAGS_INTERRUPTIBLE);
730
731#ifdef CONFIG_UDEBUG
732 udebug_stoppable_end();
733#endif
734
735 if (!call)
736 return 0;
737
738 if (call->flags & IPC_CALL_NOTIF) {
739 /* Set in_phone_hash to the interrupt counter */
740 call->data.phone = (void *) call->priv;
741
742 STRUCT_TO_USPACE(calldata, &call->data);
743
744 ipc_call_free(call);
745
746 return ((sysarg_t) call) | IPC_CALLID_NOTIFICATION;
747 }
748
749 if (call->flags & IPC_CALL_ANSWERED) {
750 process_answer(call);
751
752 if (call->flags & IPC_CALL_DISCARD_ANSWER) {
753 ipc_call_free(call);
754 goto restart;
755 }
756
757 STRUCT_TO_USPACE(&calldata->args, &call->data.args);
758 ipc_call_free(call);
759
760 return ((sysarg_t) call) | IPC_CALLID_ANSWERED;
761 }
762
763 if (process_request(&TASK->answerbox, call))
764 goto restart;
765
766 /* Include phone address('id') of the caller in the request,
767 * copy whole call->data, not only call->data.args */
768 if (STRUCT_TO_USPACE(calldata, &call->data)) {
769 /*
770 * The callee will not receive this call and no one else has
771 * a chance to answer it. Reply with the EPARTY error code.
772 */
773 ipc_data_t saved_data;
774 bool saved;
775
776 if (answer_need_old(call)) {
777 memcpy(&saved_data, &call->data, sizeof(call->data));
778 saved = true;
779 } else
780 saved = false;
781
782 IPC_SET_RETVAL(call->data, EPARTY);
783 (void) answer_preprocess(call, saved ? &saved_data : NULL);
784 ipc_answer(&TASK->answerbox, call);
785 return 0;
786 }
787
788 return (sysarg_t) call;
789}
790
791/** Interrupt one thread from sys_ipc_wait_for_call().
792 *
793 */
794sysarg_t sys_ipc_poke(void)
795{
796 waitq_unsleep(&TASK->answerbox.wq);
797 return EOK;
798}
799
800/** Connect an IRQ handler to a task.
801 *
802 * @param inr IRQ number.
803 * @param imethod Interface and method to be associated with the notification.
804 * @param ucode Uspace pointer to the top-half pseudocode.
805 *
806 * @return IRQ kernel object capability
807 * @return EPERM
808 * @return Error code returned by ipc_irq_subscribe().
809 *
810 */
811sysarg_t sys_ipc_irq_subscribe(inr_t inr, sysarg_t imethod, irq_code_t *ucode)
812{
813 if (!(perm_get(TASK) & PERM_IRQ_REG))
814 return EPERM;
815
816 return ipc_irq_subscribe(&TASK->answerbox, inr, imethod, ucode);
817}
818
819/** Disconnect an IRQ handler from a task.
820 *
821 * @param inr IRQ number.
822 * @param devno Device number.
823 *
824 * @return Zero on success or EPERM on error.
825 *
826 */
827sysarg_t sys_ipc_irq_unsubscribe(sysarg_t cap)
828{
829 if (!(perm_get(TASK) & PERM_IRQ_REG))
830 return EPERM;
831
832 ipc_irq_unsubscribe(&TASK->answerbox, cap);
833
834 return 0;
835}
836
837#ifdef __32_BITS__
838
839/** Syscall connect to a task by ID (32 bits)
840 *
841 * @return Phone id on success, or negative error code.
842 *
843 */
844sysarg_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid)
845{
846#ifdef CONFIG_UDEBUG
847 sysarg64_t taskid;
848 int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t));
849 if (rc != 0)
850 return (sysarg_t) rc;
851
852 return ipc_connect_kbox((task_id_t) taskid);
853#else
854 return (sysarg_t) ENOTSUP;
855#endif
856}
857
858#endif /* __32_BITS__ */
859
860#ifdef __64_BITS__
861
862/** Syscall connect to a task by ID (64 bits)
863 *
864 * @return Phone id on success, or negative error code.
865 *
866 */
867sysarg_t sys_ipc_connect_kbox(sysarg_t taskid)
868{
869#ifdef CONFIG_UDEBUG
870 return ipc_connect_kbox((task_id_t) taskid);
871#else
872 return (sysarg_t) ENOTSUP;
873#endif
874}
875
876#endif /* __64_BITS__ */
877
878/** @}
879 */
Note: See TracBrowser for help on using the repository browser.