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

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 95658c9 was 5a5269d, checked in by GitHub <noreply@…>, 6 years ago

Change type of uspace pointers in kernel from pointer type to numeric (#170)

From kernel's perspective, userspace addresses are not valid pointers,
and can only be used in calls to copy_to/from_uspace().
Therefore, we change the type of those arguments and variables to
uspace_addr_t which is an alias for sysarg_t.

This allows the compiler to catch accidental direct accesses to
userspace addresses.

Additionally, to avoid losing the type information in code,
a macro uspace_ptr(type) is used that translates to uspace_addr_t.
I makes no functional difference, but allows keeping the type information
in code in case we implement some sort of static checking for it in the future.

However, ccheck doesn't like that, so instead of using uspace_ptr(char),
we use uspace_ptr_char which is defined as
#define uspace_ptr_char uspace_ptr(char).

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