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

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

Destroy the phone capability on hangup

The capability must be destroyed at the time of the hangup otherwise the
phone would linger in the hungup state until the task is destroyed.

  • Property mode set to 100644
File size: 24.2 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#include <cap/cap.h>
56
57#define STRUCT_TO_USPACE(dst, src) copy_to_uspace((dst), (src), sizeof(*(src)))
58
59/** Decide if the interface and method is a system method.
60 *
61 * @param imethod Interface and method to be decided.
62 *
63 * @return True if the interface and method is a system
64 * interface and method.
65 *
66 */
67static inline bool method_is_system(sysarg_t imethod)
68{
69 if (imethod <= IPC_M_LAST_SYSTEM)
70 return true;
71
72 return false;
73}
74
75/** Decide if the message with this interface and method is forwardable.
76 *
77 * Some system messages may be forwarded, for some of them
78 * it is useless.
79 *
80 * @param imethod Interface and method to be decided.
81 *
82 * @return True if the interface and method is forwardable.
83 *
84 */
85static inline bool method_is_forwardable(sysarg_t imethod)
86{
87 switch (imethod) {
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_CONNECT_TO_ME:
137 case IPC_M_CONNECT_ME_TO:
138 case IPC_M_PAGE_IN:
139 case IPC_M_SHARE_OUT:
140 case IPC_M_SHARE_IN:
141 case IPC_M_DATA_WRITE:
142 case IPC_M_DATA_READ:
143 case IPC_M_STATE_CHANGE_AUTHORIZE:
144 return true;
145 default:
146 return false;
147 }
148}
149
150/** Interpret process answer as control information.
151 *
152 * This function is called directly after sys_ipc_answer().
153 *
154 * @param answer Call structure with the answer.
155 * @param olddata Saved data of the request.
156 *
157 * @return Return EOK on success or an error code.
158 *
159 */
160errno_t answer_preprocess(call_t *answer, ipc_data_t *olddata)
161{
162 errno_t rc = EOK;
163
164 spinlock_lock(&answer->forget_lock);
165 if (answer->forget) {
166 /*
167 * This is a forgotten call and answer->sender is not valid.
168 */
169 spinlock_unlock(&answer->forget_lock);
170
171 SYSIPC_OP(answer_cleanup, answer, olddata);
172 return rc;
173 } else {
174 assert(answer->active);
175
176 /*
177 * Mark the call as inactive to prevent _ipc_answer_free_call()
178 * from attempting to remove the call from the active list
179 * itself.
180 */
181 answer->active = false;
182
183 /*
184 * Remove the call from the sender's active call list.
185 * We enforce this locking order so that any potential
186 * concurrently executing forget operation is forced to
187 * release its active_calls_lock and lose the race to
188 * forget this soon to be answered call.
189 */
190 spinlock_lock(&answer->sender->active_calls_lock);
191 list_remove(&answer->ta_link);
192 spinlock_unlock(&answer->sender->active_calls_lock);
193 }
194 spinlock_unlock(&answer->forget_lock);
195
196 if ((errno_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
197 phone_t *phone = answer->caller_phone;
198 mutex_lock(&phone->lock);
199 if (phone->state == IPC_PHONE_CONNECTED) {
200 irq_spinlock_lock(&phone->callee->lock, true);
201 list_remove(&phone->link);
202 /* Drop callee->connected_phones reference */
203 kobject_put(phone->kobject);
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 errno_t 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 (((errno_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 handle Phone capability handle for the call.
266 * @param data[inout] Structure with request/reply data.
267 * @param priv Value to be stored in call->priv.
268 *
269 * @return EOK on success.
270 * @return ENOENT if there is no such phone handle.
271 *
272 */
273errno_t ipc_req_internal(cap_handle_t handle, ipc_data_t *data, sysarg_t priv)
274{
275 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
276 if (!kobj->phone)
277 return ENOENT;
278
279 call_t *call = ipc_call_alloc(0);
280 call->priv = priv;
281 memcpy(call->data.args, data->args, sizeof(data->args));
282
283 errno_t rc = request_preprocess(call, kobj->phone);
284 if (!rc) {
285#ifdef CONFIG_UDEBUG
286 udebug_stoppable_begin();
287#endif
288
289 kobject_add_ref(call->kobject);
290 rc = ipc_call_sync(kobj->phone, call);
291 spinlock_lock(&call->forget_lock);
292 bool forgotten = call->forget;
293 spinlock_unlock(&call->forget_lock);
294 kobject_put(call->kobject);
295
296#ifdef CONFIG_UDEBUG
297 udebug_stoppable_end();
298#endif
299
300 if (rc != EOK) {
301 if (!forgotten) {
302 /*
303 * There was an error, but it did not result
304 * in the call being forgotten. In fact, the
305 * call was not even sent. We are still
306 * its owners and are responsible for its
307 * deallocation.
308 */
309 kobject_put(call->kobject);
310 } else {
311 /*
312 * The call was forgotten and it changed hands.
313 * We are no longer expected to free it.
314 */
315 assert(rc == EINTR);
316 }
317 kobject_put(kobj);
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 kobject_put(call->kobject);
327 kobject_put(kobj);
328
329 return EOK;
330}
331
332/** Check that the task did not exceed the allowed limit of asynchronous calls
333 * made over a phone.
334 *
335 * @param phone Phone to check the limit against.
336 *
337 * @return 0 if limit not reached or -1 if limit exceeded.
338 *
339 */
340static int check_call_limit(phone_t *phone)
341{
342 if (atomic_get(&phone->active_calls) >= IPC_MAX_ASYNC_CALLS)
343 return -1;
344
345 return 0;
346}
347
348/** Make a fast asynchronous call over IPC.
349 *
350 * This function can only handle three arguments of payload, but is faster than
351 * the generic function sys_ipc_call_async_slow().
352 *
353 * @param handle Phone capability handle for the call.
354 * @param imethod Interface and method of the call.
355 * @param arg1 Service-defined payload argument.
356 * @param arg2 Service-defined payload argument.
357 * @param arg3 Service-defined payload argument.
358 * @param label User-defined label.
359 *
360 * @return EOK on success.
361 * @return An error code on error.
362 *
363 */
364sys_errno_t sys_ipc_call_async_fast(sysarg_t handle, sysarg_t imethod,
365 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t label)
366{
367 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
368 if (!kobj)
369 return ENOENT;
370
371 if (check_call_limit(kobj->phone)) {
372 kobject_put(kobj);
373 return ELIMIT;
374 }
375
376 call_t *call = ipc_call_alloc(0);
377 IPC_SET_IMETHOD(call->data, imethod);
378 IPC_SET_ARG1(call->data, arg1);
379 IPC_SET_ARG2(call->data, arg2);
380 IPC_SET_ARG3(call->data, arg3);
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 /* Set the user-defined label */
389 call->data.label = label;
390
391 errno_t res = request_preprocess(call, kobj->phone);
392
393 if (!res)
394 ipc_call(kobj->phone, call);
395 else
396 ipc_backsend_err(kobj->phone, call, res);
397
398 kobject_put(kobj);
399 return EOK;
400}
401
402/** Make an asynchronous IPC call allowing to transmit the entire payload.
403 *
404 * @param handle Phone capability for the call.
405 * @param data Userspace address of call data with the request.
406 * @param label User-defined label.
407 *
408 * @return See sys_ipc_call_async_fast().
409 *
410 */
411sys_errno_t sys_ipc_call_async_slow(sysarg_t handle, ipc_data_t *data,
412 sysarg_t label)
413{
414 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
415 if (!kobj)
416 return ENOENT;
417
418 if (check_call_limit(kobj->phone)) {
419 kobject_put(kobj);
420 return ELIMIT;
421 }
422
423 call_t *call = ipc_call_alloc(0);
424 errno_t rc = copy_from_uspace(&call->data.args, &data->args,
425 sizeof(call->data.args));
426 if (rc != EOK) {
427 kobject_put(call->kobject);
428 kobject_put(kobj);
429 return (sys_errno_t) rc;
430 }
431
432 /* Set the user-defined label */
433 call->data.label = label;
434
435 errno_t res = request_preprocess(call, kobj->phone);
436
437 if (!res)
438 ipc_call(kobj->phone, call);
439 else
440 ipc_backsend_err(kobj->phone, call, res);
441
442 kobject_put(kobj);
443 return EOK;
444}
445
446/** Forward a received call to another destination
447 *
448 * Common code for both the fast and the slow version.
449 *
450 * @param chandle Call handle of the forwarded call.
451 * @param phandle Phone handle to use for forwarding.
452 * @param imethod New interface and method to use for the forwarded call.
453 * @param arg1 New value of the first argument for the forwarded call.
454 * @param arg2 New value of the second argument for the forwarded call.
455 * @param arg3 New value of the third argument for the forwarded call.
456 * @param arg4 New value of the fourth argument for the forwarded call.
457 * @param arg5 New value of the fifth argument for the forwarded call.
458 * @param mode Flags that specify mode of the forward operation.
459 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise
460 * the function considers only the fast version arguments:
461 * i.e. arg1 and arg2.
462 *
463 * @return 0 on succes, otherwise an error code.
464 *
465 * Warning: Make sure that ARG5 is not rewritten for certain system IPC
466 *
467 */
468static sys_errno_t sys_ipc_forward_common(sysarg_t chandle, sysarg_t phandle,
469 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
470 sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
471{
472 kobject_t *ckobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
473 if (!ckobj)
474 return ENOENT;
475
476 call_t *call = ckobj->call;
477
478 ipc_data_t old;
479 bool need_old = answer_need_old(call);
480 if (need_old)
481 old = call->data;
482
483 bool after_forward = false;
484 errno_t rc;
485
486 kobject_t *pkobj = kobject_get(TASK, phandle, KOBJECT_TYPE_PHONE);
487 if (!pkobj) {
488 rc = ENOENT;
489 goto error;
490 }
491
492 if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
493 rc = EPERM;
494 goto error;
495 }
496
497 call->flags |= IPC_CALL_FORWARDED;
498
499 /*
500 * User space is not allowed to change interface and method of system
501 * methods on forward, allow changing ARG1, ARG2, ARG3 and ARG4 by
502 * means of imethod, arg1, arg2 and arg3.
503 * If the interface and method is immutable, don't change anything.
504 */
505 if (!method_is_immutable(IPC_GET_IMETHOD(call->data))) {
506 if (method_is_system(IPC_GET_IMETHOD(call->data))) {
507 if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME)
508 phone_dealloc(IPC_GET_ARG5(call->data));
509
510 IPC_SET_ARG1(call->data, imethod);
511 IPC_SET_ARG2(call->data, arg1);
512 IPC_SET_ARG3(call->data, arg2);
513
514 if (slow)
515 IPC_SET_ARG4(call->data, arg3);
516
517 /*
518 * For system methods we deliberately don't
519 * overwrite ARG5.
520 */
521 } else {
522 IPC_SET_IMETHOD(call->data, imethod);
523 IPC_SET_ARG1(call->data, arg1);
524 IPC_SET_ARG2(call->data, arg2);
525 if (slow) {
526 IPC_SET_ARG3(call->data, arg3);
527 IPC_SET_ARG4(call->data, arg4);
528 IPC_SET_ARG5(call->data, arg5);
529 }
530 }
531 }
532
533 rc = ipc_forward(call, pkobj->phone, &TASK->answerbox, mode);
534 if (rc != EOK) {
535 after_forward = true;
536 goto error;
537 }
538
539 cap_free(TASK, chandle);
540 kobject_put(ckobj);
541 kobject_put(pkobj);
542 return EOK;
543
544error:
545 IPC_SET_RETVAL(call->data, EFORWARD);
546 (void) answer_preprocess(call, need_old ? &old : NULL);
547 if (after_forward)
548 _ipc_answer_free_call(call, false);
549 else
550 ipc_answer(&TASK->answerbox, call);
551
552 /* Republish the capability so that the call does not get lost. */
553 cap_publish(TASK, chandle, ckobj);
554
555 if (pkobj)
556 kobject_put(pkobj);
557 return rc;
558}
559
560/** Forward a received call to another destination - fast version.
561 *
562 * In case the original interface and method is a system method, ARG1, ARG2
563 * and ARG3 are overwritten in the forwarded message with the new method and
564 * the new arg1 and arg2, respectively. Otherwise the IMETHOD, ARG1 and ARG2
565 * are rewritten with the new interface and method, arg1 and arg2, respectively.
566 * Also note there is a set of immutable methods, for which the new method and
567 * arguments are not set and these values are ignored.
568 *
569 * @param chandle Call handle of the call to forward.
570 * @param phandle Phone handle to use for forwarding.
571 * @param imethod New interface and method to use for the forwarded call.
572 * @param arg1 New value of the first argument for the forwarded call.
573 * @param arg2 New value of the second argument for the forwarded call.
574 * @param mode Flags that specify mode of the forward operation.
575 *
576 * @return 0 on succes, otherwise an error code.
577 *
578 */
579sys_errno_t sys_ipc_forward_fast(sysarg_t chandle, sysarg_t phandle,
580 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
581{
582 return sys_ipc_forward_common(chandle, phandle, imethod, arg1, arg2, 0,
583 0, 0, mode, false);
584}
585
586/** Forward a received call to another destination - slow version.
587 *
588 * This function is the slow verision of the sys_ipc_forward_fast interface.
589 * It can copy all five new arguments and the new interface and method from
590 * the userspace. It naturally extends the functionality of the fast version.
591 * For system methods, it additionally stores the new value of arg3 to ARG4.
592 * For non-system methods, it additionally stores the new value of arg3, arg4
593 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
594 *
595 * @param chandle Call handle of the call to forward.
596 * @param phandle Phone handle to use for forwarding.
597 * @param data Userspace address of the new IPC data.
598 * @param mode Flags that specify mode of the forward operation.
599 *
600 * @return 0 on succes, otherwise an error code.
601 *
602 */
603sys_errno_t sys_ipc_forward_slow(sysarg_t chandle, sysarg_t phandle,
604 ipc_data_t *data, unsigned int mode)
605{
606 ipc_data_t newdata;
607 errno_t rc = copy_from_uspace(&newdata.args, &data->args,
608 sizeof(newdata.args));
609 if (rc != EOK)
610 return (sys_errno_t) rc;
611
612 return sys_ipc_forward_common(chandle, phandle,
613 IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
614 IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
615 IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
616}
617
618/** Answer an IPC call - fast version.
619 *
620 * This function can handle only two return arguments of payload, but is faster
621 * than the generic sys_ipc_answer().
622 *
623 * @param chandle Call handle to be answered.
624 * @param retval Return value of the answer.
625 * @param arg1 Service-defined return value.
626 * @param arg2 Service-defined return value.
627 * @param arg3 Service-defined return value.
628 * @param arg4 Service-defined return value.
629 *
630 * @return 0 on success, otherwise an error code.
631 *
632 */
633sys_errno_t sys_ipc_answer_fast(sysarg_t chandle, sysarg_t retval, sysarg_t arg1,
634 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
635{
636 kobject_t *kobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
637 if (!kobj)
638 return ENOENT;
639
640 call_t *call = kobj->call;
641
642 ipc_data_t saved_data;
643 bool saved;
644
645 if (answer_need_old(call)) {
646 memcpy(&saved_data, &call->data, sizeof(call->data));
647 saved = true;
648 } else
649 saved = false;
650
651 IPC_SET_RETVAL(call->data, retval);
652 IPC_SET_ARG1(call->data, arg1);
653 IPC_SET_ARG2(call->data, arg2);
654 IPC_SET_ARG3(call->data, arg3);
655 IPC_SET_ARG4(call->data, arg4);
656
657 /*
658 * To achieve deterministic behavior, zero out arguments that are beyond
659 * the limits of the fast version.
660 */
661 IPC_SET_ARG5(call->data, 0);
662 errno_t rc = answer_preprocess(call, saved ? &saved_data : NULL);
663
664 ipc_answer(&TASK->answerbox, call);
665
666 kobject_put(kobj);
667 cap_free(TASK, chandle);
668
669 return rc;
670}
671
672/** Answer an IPC call.
673 *
674 * @param chandle Call handle to be answered.
675 * @param data Userspace address of call data with the answer.
676 *
677 * @return 0 on success, otherwise an error code.
678 *
679 */
680sys_errno_t sys_ipc_answer_slow(sysarg_t chandle, ipc_data_t *data)
681{
682 kobject_t *kobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
683 if (!kobj)
684 return ENOENT;
685
686 call_t *call = kobj->call;
687
688 ipc_data_t saved_data;
689 bool saved;
690
691 if (answer_need_old(call)) {
692 memcpy(&saved_data, &call->data, sizeof(call->data));
693 saved = true;
694 } else
695 saved = false;
696
697 errno_t rc = copy_from_uspace(&call->data.args, &data->args,
698 sizeof(call->data.args));
699 if (rc != EOK) {
700 /*
701 * Republish the capability so that the call does not get lost.
702 */
703 cap_publish(TASK, chandle, kobj);
704 return rc;
705 }
706
707 rc = answer_preprocess(call, saved ? &saved_data : NULL);
708
709 ipc_answer(&TASK->answerbox, call);
710
711 kobject_put(kobj);
712 cap_free(TASK, chandle);
713
714 return rc;
715}
716
717/** Hang up a phone.
718 *
719 * @param handle Phone capability handle of the phone to be hung up.
720 *
721 * @return 0 on success or an error code.
722 *
723 */
724sys_errno_t sys_ipc_hangup(sysarg_t handle)
725{
726 kobject_t *kobj = cap_unpublish(TASK, handle, KOBJECT_TYPE_PHONE);
727 if (!kobj)
728 return ENOENT;
729
730 errno_t rc = ipc_phone_hangup(kobj->phone);
731 kobject_put(kobj);
732 cap_free(TASK, handle);
733 return rc;
734}
735
736/** Wait for an incoming IPC call or an answer.
737 *
738 * @param calldata Pointer to buffer where the call/answer data is stored.
739 * @param usec Timeout. See waitq_sleep_timeout() for explanation.
740 * @param flags Select mode of sleep operation. See waitq_sleep_timeout()
741 * for explanation.
742 *
743 * @return An error code on error.
744 */
745sys_errno_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
746 unsigned int flags)
747{
748 call_t *call;
749
750restart:
751
752#ifdef CONFIG_UDEBUG
753 udebug_stoppable_begin();
754#endif
755
756 call = ipc_wait_for_call(&TASK->answerbox, usec,
757 flags | SYNCH_FLAGS_INTERRUPTIBLE);
758
759#ifdef CONFIG_UDEBUG
760 udebug_stoppable_end();
761#endif
762
763 if (!call) {
764 ipc_data_t data = {};
765 data.cap_handle = CAP_NIL;
766 STRUCT_TO_USPACE(calldata, &data);
767 return EOK;
768 }
769
770 call->data.flags = call->flags;
771 if (call->flags & IPC_CALL_NOTIF) {
772 /* Set in_phone_hash to the interrupt counter */
773 call->data.phone = (void *) call->priv;
774
775 call->data.cap_handle = CAP_NIL;
776
777 STRUCT_TO_USPACE(calldata, &call->data);
778 kobject_put(call->kobject);
779
780 return EOK;
781 }
782
783 if (call->flags & IPC_CALL_ANSWERED) {
784 process_answer(call);
785
786 if (call->flags & IPC_CALL_DISCARD_ANSWER) {
787 kobject_put(call->kobject);
788 goto restart;
789 }
790
791 call->data.cap_handle = CAP_NIL;
792
793 STRUCT_TO_USPACE(calldata, &call->data);
794 kobject_put(call->kobject);
795
796 return EOK;
797 }
798
799 if (process_request(&TASK->answerbox, call))
800 goto restart;
801
802 cap_handle_t handle;
803 errno_t rc = cap_alloc(TASK, &handle);
804 if (rc != EOK) {
805 goto error;
806 }
807
808 call->data.cap_handle = handle;
809
810 /*
811 * Include phone hash of the caller in the request, copy the whole
812 * call->data, not only call->data.args.
813 */
814 rc = STRUCT_TO_USPACE(calldata, &call->data);
815 if (rc != EOK)
816 goto error;
817
818 kobject_add_ref(call->kobject);
819 cap_publish(TASK, handle, call->kobject);
820 return EOK;
821
822error:
823 if (handle >= 0)
824 cap_free(TASK, handle);
825
826 /*
827 * The callee will not receive this call and no one else has a chance to
828 * answer it. Set the IPC_CALL_AUTO_REPLY flag and return the EPARTY
829 * error code.
830 */
831 ipc_data_t saved_data;
832 bool saved;
833
834 if (answer_need_old(call)) {
835 memcpy(&saved_data, &call->data, sizeof(call->data));
836 saved = true;
837 } else
838 saved = false;
839
840 IPC_SET_RETVAL(call->data, EPARTY);
841 (void) answer_preprocess(call, saved ? &saved_data : NULL);
842 call->flags |= IPC_CALL_AUTO_REPLY;
843 ipc_answer(&TASK->answerbox, call);
844
845 return rc;
846}
847
848/** Interrupt one thread from sys_ipc_wait_for_call().
849 *
850 */
851sys_errno_t sys_ipc_poke(void)
852{
853 waitq_unsleep(&TASK->answerbox.wq);
854 return EOK;
855}
856
857/** Connect an IRQ handler to a task.
858 *
859 * @param inr IRQ number.
860 * @param imethod Interface and method to be associated with the notification.
861 * @param ucode Uspace pointer to the top-half pseudocode.
862 *
863 * @param[out] uspace_handle Uspace pointer to IRQ kernel object capability
864 *
865 * @return EPERM
866 * @return Error code returned by ipc_irq_subscribe().
867 *
868 */
869sys_errno_t sys_ipc_irq_subscribe(inr_t inr, sysarg_t imethod, irq_code_t *ucode,
870 cap_handle_t *uspace_handle)
871{
872 if (!(perm_get(TASK) & PERM_IRQ_REG))
873 return EPERM;
874
875 return ipc_irq_subscribe(&TASK->answerbox, inr, imethod, ucode, uspace_handle);
876}
877
878/** Disconnect an IRQ handler from a task.
879 *
880 * @param inr IRQ number.
881 * @param devno Device number.
882 *
883 * @return Zero on success or EPERM on error.
884 *
885 */
886sys_errno_t sys_ipc_irq_unsubscribe(sysarg_t cap)
887{
888 if (!(perm_get(TASK) & PERM_IRQ_REG))
889 return EPERM;
890
891 ipc_irq_unsubscribe(&TASK->answerbox, cap);
892
893 return 0;
894}
895
896/** Syscall connect to a task by ID
897 *
898 * @return Error code.
899 *
900 */
901sys_errno_t sys_ipc_connect_kbox(task_id_t *uspace_taskid, cap_handle_t *uspace_phone)
902{
903#ifdef CONFIG_UDEBUG
904 task_id_t taskid;
905 cap_handle_t phone;
906
907 errno_t rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(task_id_t));
908 if (rc == EOK) {
909 rc = ipc_connect_kbox((task_id_t) taskid, &phone);
910 }
911
912 if (rc == EOK) {
913 rc = copy_to_uspace(uspace_phone, &phone, sizeof(cap_handle_t));
914 if (rc != EOK) {
915 // Clean up the phone on failure.
916 sys_ipc_hangup(phone);
917 }
918 }
919
920 return (sys_errno_t) rc;
921#else
922 return (sys_errno_t) ENOTSUP;
923#endif
924}
925
926/** @}
927 */
Note: See TracBrowser for help on using the repository browser.