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

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

Make capability handles type-safe

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

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

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

  • Property mode set to 100644
File size: 24.4 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
274ipc_req_internal(cap_phone_handle_t handle, ipc_data_t *data, sysarg_t priv)
275{
276 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
277 if (!kobj->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 errno_t rc = request_preprocess(call, kobj->phone);
285 if (!rc) {
286#ifdef CONFIG_UDEBUG
287 udebug_stoppable_begin();
288#endif
289
290 kobject_add_ref(call->kobject);
291 rc = ipc_call_sync(kobj->phone, call);
292 spinlock_lock(&call->forget_lock);
293 bool forgotten = call->forget;
294 spinlock_unlock(&call->forget_lock);
295 kobject_put(call->kobject);
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 kobject_put(call->kobject);
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 kobject_put(kobj);
319 return rc;
320 }
321
322 process_answer(call);
323 } else
324 IPC_SET_RETVAL(call->data, rc);
325
326 memcpy(data->args, call->data.args, sizeof(data->args));
327 kobject_put(call->kobject);
328 kobject_put(kobj);
329
330 return EOK;
331}
332
333/** Check that the task did not exceed the allowed limit of asynchronous calls
334 * made over a phone.
335 *
336 * @param phone Phone to check the limit against.
337 *
338 * @return 0 if limit not reached or -1 if limit exceeded.
339 *
340 */
341static int check_call_limit(phone_t *phone)
342{
343 if (atomic_get(&phone->active_calls) >= IPC_MAX_ASYNC_CALLS)
344 return -1;
345
346 return 0;
347}
348
349/** Make a fast asynchronous call over IPC.
350 *
351 * This function can only handle three arguments of payload, but is faster than
352 * the generic function sys_ipc_call_async_slow().
353 *
354 * @param handle Phone capability handle for the call.
355 * @param imethod Interface and method of the call.
356 * @param arg1 Service-defined payload argument.
357 * @param arg2 Service-defined payload argument.
358 * @param arg3 Service-defined payload argument.
359 * @param label User-defined label.
360 *
361 * @return EOK on success.
362 * @return An error code on error.
363 *
364 */
365sys_errno_t sys_ipc_call_async_fast(cap_phone_handle_t handle, sysarg_t imethod,
366 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t label)
367{
368 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
369 if (!kobj)
370 return ENOENT;
371
372 if (check_call_limit(kobj->phone)) {
373 kobject_put(kobj);
374 return ELIMIT;
375 }
376
377 call_t *call = ipc_call_alloc(0);
378 IPC_SET_IMETHOD(call->data, imethod);
379 IPC_SET_ARG1(call->data, arg1);
380 IPC_SET_ARG2(call->data, arg2);
381 IPC_SET_ARG3(call->data, arg3);
382
383 /*
384 * To achieve deterministic behavior, zero out arguments that are beyond
385 * the limits of the fast version.
386 */
387 IPC_SET_ARG5(call->data, 0);
388
389 /* Set the user-defined label */
390 call->data.label = label;
391
392 errno_t res = request_preprocess(call, kobj->phone);
393
394 if (!res)
395 ipc_call(kobj->phone, call);
396 else
397 ipc_backsend_err(kobj->phone, call, res);
398
399 kobject_put(kobj);
400 return EOK;
401}
402
403/** Make an asynchronous IPC call allowing to transmit the entire payload.
404 *
405 * @param handle Phone capability for the call.
406 * @param data Userspace address of call data with the request.
407 * @param label User-defined label.
408 *
409 * @return See sys_ipc_call_async_fast().
410 *
411 */
412sys_errno_t sys_ipc_call_async_slow(cap_phone_handle_t handle, ipc_data_t *data,
413 sysarg_t label)
414{
415 kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
416 if (!kobj)
417 return ENOENT;
418
419 if (check_call_limit(kobj->phone)) {
420 kobject_put(kobj);
421 return ELIMIT;
422 }
423
424 call_t *call = ipc_call_alloc(0);
425 errno_t rc = copy_from_uspace(&call->data.args, &data->args,
426 sizeof(call->data.args));
427 if (rc != EOK) {
428 kobject_put(call->kobject);
429 kobject_put(kobj);
430 return (sys_errno_t) rc;
431 }
432
433 /* Set the user-defined label */
434 call->data.label = label;
435
436 errno_t res = request_preprocess(call, kobj->phone);
437
438 if (!res)
439 ipc_call(kobj->phone, call);
440 else
441 ipc_backsend_err(kobj->phone, call, res);
442
443 kobject_put(kobj);
444 return EOK;
445}
446
447/** Forward a received call to another destination
448 *
449 * Common code for both the fast and the slow version.
450 *
451 * @param chandle Call handle of the forwarded call.
452 * @param phandle Phone handle to use for forwarding.
453 * @param imethod New interface and method to use for the forwarded call.
454 * @param arg1 New value of the first argument for the forwarded call.
455 * @param arg2 New value of the second argument for the forwarded call.
456 * @param arg3 New value of the third argument for the forwarded call.
457 * @param arg4 New value of the fourth argument for the forwarded call.
458 * @param arg5 New value of the fifth argument for the forwarded call.
459 * @param mode Flags that specify mode of the forward operation.
460 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise
461 * the function considers only the fast version arguments:
462 * i.e. arg1 and arg2.
463 *
464 * @return 0 on succes, otherwise an error code.
465 *
466 * Warning: Make sure that ARG5 is not rewritten for certain system IPC
467 *
468 */
469static sys_errno_t sys_ipc_forward_common(cap_call_handle_t chandle,
470 cap_phone_handle_t phandle, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
471 sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
472{
473 kobject_t *ckobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
474 if (!ckobj)
475 return ENOENT;
476
477 call_t *call = ckobj->call;
478
479 ipc_data_t old;
480 bool need_old = answer_need_old(call);
481 if (need_old)
482 old = call->data;
483
484 bool after_forward = false;
485 errno_t rc;
486
487 kobject_t *pkobj = kobject_get(TASK, phandle, KOBJECT_TYPE_PHONE);
488 if (!pkobj) {
489 rc = ENOENT;
490 goto error;
491 }
492
493 if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
494 rc = EPERM;
495 goto error;
496 }
497
498 call->flags |= IPC_CALL_FORWARDED;
499
500 /*
501 * User space is not allowed to change interface and method of system
502 * methods on forward, allow changing ARG1, ARG2, ARG3 and ARG4 by
503 * means of imethod, arg1, arg2 and arg3.
504 * If the interface and method is immutable, don't change anything.
505 */
506 if (!method_is_immutable(IPC_GET_IMETHOD(call->data))) {
507 if (method_is_system(IPC_GET_IMETHOD(call->data))) {
508 if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME)
509 phone_dealloc((cap_phone_handle_t)
510 IPC_GET_ARG5(call->data));
511
512 IPC_SET_ARG1(call->data, imethod);
513 IPC_SET_ARG2(call->data, arg1);
514 IPC_SET_ARG3(call->data, arg2);
515
516 if (slow)
517 IPC_SET_ARG4(call->data, arg3);
518
519 /*
520 * For system methods we deliberately don't
521 * overwrite ARG5.
522 */
523 } else {
524 IPC_SET_IMETHOD(call->data, imethod);
525 IPC_SET_ARG1(call->data, arg1);
526 IPC_SET_ARG2(call->data, arg2);
527 if (slow) {
528 IPC_SET_ARG3(call->data, arg3);
529 IPC_SET_ARG4(call->data, arg4);
530 IPC_SET_ARG5(call->data, arg5);
531 }
532 }
533 }
534
535 rc = ipc_forward(call, pkobj->phone, &TASK->answerbox, mode);
536 if (rc != EOK) {
537 after_forward = true;
538 goto error;
539 }
540
541 cap_free(TASK, chandle);
542 kobject_put(ckobj);
543 kobject_put(pkobj);
544 return EOK;
545
546error:
547 IPC_SET_RETVAL(call->data, EFORWARD);
548 (void) answer_preprocess(call, need_old ? &old : NULL);
549 if (after_forward)
550 _ipc_answer_free_call(call, false);
551 else
552 ipc_answer(&TASK->answerbox, call);
553
554 /* Republish the capability so that the call does not get lost. */
555 cap_publish(TASK, chandle, ckobj);
556
557 if (pkobj)
558 kobject_put(pkobj);
559 return rc;
560}
561
562/** Forward a received call to another destination - fast version.
563 *
564 * In case the original interface and method is a system method, ARG1, ARG2
565 * and ARG3 are overwritten in the forwarded message with the new method and
566 * the new arg1 and arg2, respectively. Otherwise the IMETHOD, ARG1 and ARG2
567 * are rewritten with the new interface and method, arg1 and arg2, respectively.
568 * Also note there is a set of immutable methods, for which the new method and
569 * arguments are not set and these values are ignored.
570 *
571 * @param chandle Call handle of the call to forward.
572 * @param phandle Phone handle to use for forwarding.
573 * @param imethod New interface and method to use for the forwarded call.
574 * @param arg1 New value of the first argument for the forwarded call.
575 * @param arg2 New value of the second argument for the forwarded call.
576 * @param mode Flags that specify mode of the forward operation.
577 *
578 * @return 0 on succes, otherwise an error code.
579 *
580 */
581sys_errno_t sys_ipc_forward_fast(cap_call_handle_t chandle,
582 cap_phone_handle_t phandle, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
583 unsigned int mode)
584{
585 return sys_ipc_forward_common(chandle, phandle, imethod, arg1, arg2, 0,
586 0, 0, mode, false);
587}
588
589/** Forward a received call to another destination - slow version.
590 *
591 * This function is the slow verision of the sys_ipc_forward_fast interface.
592 * It can copy all five new arguments and the new interface and method from
593 * the userspace. It naturally extends the functionality of the fast version.
594 * For system methods, it additionally stores the new value of arg3 to ARG4.
595 * For non-system methods, it additionally stores the new value of arg3, arg4
596 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
597 *
598 * @param chandle Call handle of the call to forward.
599 * @param phandle Phone handle to use for forwarding.
600 * @param data Userspace address of the new IPC data.
601 * @param mode Flags that specify mode of the forward operation.
602 *
603 * @return 0 on succes, otherwise an error code.
604 *
605 */
606sys_errno_t sys_ipc_forward_slow(cap_call_handle_t chandle,
607 cap_phone_handle_t phandle, ipc_data_t *data, unsigned int mode)
608{
609 ipc_data_t newdata;
610 errno_t rc = copy_from_uspace(&newdata.args, &data->args,
611 sizeof(newdata.args));
612 if (rc != EOK)
613 return (sys_errno_t) rc;
614
615 return sys_ipc_forward_common(chandle, phandle,
616 IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
617 IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
618 IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
619}
620
621/** Answer an IPC call - fast version.
622 *
623 * This function can handle only two return arguments of payload, but is faster
624 * than the generic sys_ipc_answer().
625 *
626 * @param chandle Call handle to be answered.
627 * @param retval Return value of the answer.
628 * @param arg1 Service-defined return value.
629 * @param arg2 Service-defined return value.
630 * @param arg3 Service-defined return value.
631 * @param arg4 Service-defined return value.
632 *
633 * @return 0 on success, otherwise an error code.
634 *
635 */
636sys_errno_t sys_ipc_answer_fast(cap_call_handle_t chandle, sysarg_t retval,
637 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
638{
639 kobject_t *kobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
640 if (!kobj)
641 return ENOENT;
642
643 call_t *call = kobj->call;
644
645 ipc_data_t saved_data;
646 bool saved;
647
648 if (answer_need_old(call)) {
649 memcpy(&saved_data, &call->data, sizeof(call->data));
650 saved = true;
651 } else
652 saved = false;
653
654 IPC_SET_RETVAL(call->data, retval);
655 IPC_SET_ARG1(call->data, arg1);
656 IPC_SET_ARG2(call->data, arg2);
657 IPC_SET_ARG3(call->data, arg3);
658 IPC_SET_ARG4(call->data, arg4);
659
660 /*
661 * To achieve deterministic behavior, zero out arguments that are beyond
662 * the limits of the fast version.
663 */
664 IPC_SET_ARG5(call->data, 0);
665 errno_t rc = answer_preprocess(call, saved ? &saved_data : NULL);
666
667 ipc_answer(&TASK->answerbox, call);
668
669 kobject_put(kobj);
670 cap_free(TASK, chandle);
671
672 return rc;
673}
674
675/** Answer an IPC call.
676 *
677 * @param chandle Call handle to be answered.
678 * @param data Userspace address of call data with the answer.
679 *
680 * @return 0 on success, otherwise an error code.
681 *
682 */
683sys_errno_t sys_ipc_answer_slow(cap_call_handle_t chandle, ipc_data_t *data)
684{
685 kobject_t *kobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
686 if (!kobj)
687 return ENOENT;
688
689 call_t *call = kobj->call;
690
691 ipc_data_t saved_data;
692 bool saved;
693
694 if (answer_need_old(call)) {
695 memcpy(&saved_data, &call->data, sizeof(call->data));
696 saved = true;
697 } else
698 saved = false;
699
700 errno_t rc = copy_from_uspace(&call->data.args, &data->args,
701 sizeof(call->data.args));
702 if (rc != EOK) {
703 /*
704 * Republish the capability so that the call does not get lost.
705 */
706 cap_publish(TASK, chandle, kobj);
707 return rc;
708 }
709
710 rc = answer_preprocess(call, saved ? &saved_data : NULL);
711
712 ipc_answer(&TASK->answerbox, call);
713
714 kobject_put(kobj);
715 cap_free(TASK, chandle);
716
717 return rc;
718}
719
720/** Hang up a phone.
721 *
722 * @param handle Phone capability handle of the phone to be hung up.
723 *
724 * @return 0 on success or an error code.
725 *
726 */
727sys_errno_t sys_ipc_hangup(cap_phone_handle_t handle)
728{
729 kobject_t *kobj = cap_unpublish(TASK, handle, KOBJECT_TYPE_PHONE);
730 if (!kobj)
731 return ENOENT;
732
733 errno_t rc = ipc_phone_hangup(kobj->phone);
734 kobject_put(kobj);
735 cap_free(TASK, handle);
736 return rc;
737}
738
739/** Wait for an incoming IPC call or an answer.
740 *
741 * @param calldata Pointer to buffer where the call/answer data is stored.
742 * @param usec Timeout. See waitq_sleep_timeout() for explanation.
743 * @param flags Select mode of sleep operation. See waitq_sleep_timeout()
744 * for explanation.
745 *
746 * @return An error code on error.
747 */
748sys_errno_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
749 unsigned int flags)
750{
751 call_t *call;
752
753restart:
754
755#ifdef CONFIG_UDEBUG
756 udebug_stoppable_begin();
757#endif
758
759 call = ipc_wait_for_call(&TASK->answerbox, usec,
760 flags | SYNCH_FLAGS_INTERRUPTIBLE);
761
762#ifdef CONFIG_UDEBUG
763 udebug_stoppable_end();
764#endif
765
766 if (!call) {
767 ipc_data_t data = {};
768 data.cap_handle = CAP_NIL;
769 STRUCT_TO_USPACE(calldata, &data);
770 return EOK;
771 }
772
773 call->data.flags = call->flags;
774 if (call->flags & IPC_CALL_NOTIF) {
775 /* Set in_phone_hash to the interrupt counter */
776 call->data.phone = (void *) call->priv;
777
778 call->data.cap_handle = CAP_NIL;
779
780 STRUCT_TO_USPACE(calldata, &call->data);
781 kobject_put(call->kobject);
782
783 return EOK;
784 }
785
786 if (call->flags & IPC_CALL_ANSWERED) {
787 process_answer(call);
788
789 if (call->flags & IPC_CALL_DISCARD_ANSWER) {
790 kobject_put(call->kobject);
791 goto restart;
792 }
793
794 call->data.cap_handle = CAP_NIL;
795
796 STRUCT_TO_USPACE(calldata, &call->data);
797 kobject_put(call->kobject);
798
799 return EOK;
800 }
801
802 if (process_request(&TASK->answerbox, call))
803 goto restart;
804
805 cap_handle_t handle = CAP_NIL;
806 errno_t rc = cap_alloc(TASK, &handle);
807 if (rc != EOK) {
808 goto error;
809 }
810
811 call->data.cap_handle = handle;
812
813 /*
814 * Include phone hash of the caller in the request, copy the whole
815 * call->data, not only call->data.args.
816 */
817 rc = STRUCT_TO_USPACE(calldata, &call->data);
818 if (rc != EOK)
819 goto error;
820
821 kobject_add_ref(call->kobject);
822 cap_publish(TASK, handle, call->kobject);
823 return EOK;
824
825error:
826 if (CAP_HANDLE_VALID(handle))
827 cap_free(TASK, handle);
828
829 /*
830 * The callee will not receive this call and no one else has a chance to
831 * answer it. Set the IPC_CALL_AUTO_REPLY flag and return the EPARTY
832 * error code.
833 */
834 ipc_data_t saved_data;
835 bool saved;
836
837 if (answer_need_old(call)) {
838 memcpy(&saved_data, &call->data, sizeof(call->data));
839 saved = true;
840 } else
841 saved = false;
842
843 IPC_SET_RETVAL(call->data, EPARTY);
844 (void) answer_preprocess(call, saved ? &saved_data : NULL);
845 call->flags |= IPC_CALL_AUTO_REPLY;
846 ipc_answer(&TASK->answerbox, call);
847
848 return rc;
849}
850
851/** Interrupt one thread from sys_ipc_wait_for_call().
852 *
853 */
854sys_errno_t sys_ipc_poke(void)
855{
856 waitq_unsleep(&TASK->answerbox.wq);
857 return EOK;
858}
859
860/** Connect an IRQ handler to a task.
861 *
862 * @param inr IRQ number.
863 * @param imethod Interface and method to be associated with the notification.
864 * @param ucode Uspace pointer to the top-half pseudocode.
865 *
866 * @param[out] uspace_handle Uspace pointer to IRQ capability handle
867 *
868 * @return EPERM
869 * @return Error code returned by ipc_irq_subscribe().
870 *
871 */
872sys_errno_t sys_ipc_irq_subscribe(inr_t inr, sysarg_t imethod,
873 irq_code_t *ucode, cap_irq_handle_t *uspace_handle)
874{
875 if (!(perm_get(TASK) & PERM_IRQ_REG))
876 return EPERM;
877
878 return ipc_irq_subscribe(&TASK->answerbox, inr, imethod, ucode, uspace_handle);
879}
880
881/** Disconnect an IRQ handler from a task.
882 *
883 * @param handle IRQ capability handle.
884 *
885 * @return Zero on success or EPERM on error.
886 *
887 */
888sys_errno_t sys_ipc_irq_unsubscribe(cap_irq_handle_t handle)
889{
890 if (!(perm_get(TASK) & PERM_IRQ_REG))
891 return EPERM;
892
893 ipc_irq_unsubscribe(&TASK->answerbox, handle);
894
895 return 0;
896}
897
898/** Syscall connect to a task by ID
899 *
900 * @return Error code.
901 *
902 */
903sys_errno_t sys_ipc_connect_kbox(task_id_t *uspace_taskid,
904 cap_phone_handle_t *uspace_phone)
905{
906#ifdef CONFIG_UDEBUG
907 task_id_t taskid;
908 cap_phone_handle_t phone;
909
910 errno_t rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(task_id_t));
911 if (rc == EOK) {
912 rc = ipc_connect_kbox((task_id_t) taskid, &phone);
913 }
914
915 if (rc == EOK) {
916 rc = copy_to_uspace(uspace_phone, &phone, sizeof(cap_handle_t));
917 if (rc != EOK) {
918 // Clean up the phone on failure.
919 sys_ipc_hangup(phone);
920 }
921 }
922
923 return (sys_errno_t) rc;
924#else
925 return (sys_errno_t) ENOTSUP;
926#endif
927}
928
929/** @}
930 */
Note: See TracBrowser for help on using the repository browser.