source: mainline/kernel/generic/src/ipc/sysipc.c@ 43e2cbc

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

Implement interruptible wait for messages sent by the kernel

This pertains specifically to handling the IPC_M_PAGE_IN requests
sent by the kernel on behalf of the faulting thread. If the external
pager process does not respond for some reason, the user may decide to
kill the blocked client. That will result in interrupting the client
from the sleep. The kernel will then perform cleanup.

This changeset implements the cleanup by either forgetting the call
(i.e. donating it to the callee) or waiting for the arriving answer,
whichever of the two succeeds.

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