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

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

Enable forwarding of IPC_M_AS_AREA_SEND, IPC_M_AS_AREA_RECV, IPC_M_DATA_SEND
calls. In order to prevent the forwarder from cloberring the call data (i.e.
source and destination address, and size) by treating these three methods as
immutable on forward. This feature is experimental, but has huge benefits in
that it can significantly reduce the amount of data sharing (the middle man need
not modify its address space mappings) or the amount of data copying (the middle
man need not receive the data from the sender and then resend them to the next
recipient). As a result, it can reduce N such calls for a communication channel
with N tasks along the way to 1 such call.

  • Property mode set to 100644
File size: 20.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 <proc/task.h>
37#include <proc/thread.h>
38#include <errno.h>
39#include <memstr.h>
40#include <debug.h>
41#include <ipc/ipc.h>
42#include <ipc/sysipc.h>
43#include <ipc/irq.h>
44#include <ipc/ipcrsc.h>
45#include <arch/interrupt.h>
46#include <print.h>
47#include <syscall/copy.h>
48#include <security/cap.h>
49#include <mm/as.h>
50#include <print.h>
51
52/** Maximum buffer size allowed for IPC_M_DATA_SEND requests. */
53#define DATA_SEND_LIMIT (64 * 1024)
54
55#define GET_CHECK_PHONE(phone, phoneid, err) \
56{ \
57 if (phoneid > IPC_MAX_PHONES) { \
58 err; \
59 } \
60 phone = &TASK->phones[phoneid]; \
61}
62
63#define STRUCT_TO_USPACE(dst, src) copy_to_uspace(dst, src, sizeof(*(src)))
64
65/** Decide if the method is a system method.
66 *
67 * @param method Method to be decided.
68 *
69 * @return Return 1 if the method is a system method.
70 * Otherwise return 0.
71 */
72static inline int method_is_system(unative_t method)
73{
74 if (method <= IPC_M_LAST_SYSTEM)
75 return 1;
76 return 0;
77}
78
79/** Decide if the message with this method is forwardable.
80 *
81 * - some system messages may be forwarded, for some of them
82 * it is useless
83 *
84 * @param method Method to be decided.
85 *
86 * @return Return 1 if the method is forwardable.
87 * Otherwise return 0.
88 */
89static inline int method_is_forwardable(unative_t method)
90{
91 switch (method) {
92 case IPC_M_PHONE_HUNGUP:
93 /* This message is meant only for the original recipient. */
94 return 0;
95 default:
96 return 1;
97 }
98}
99
100/** Decide if the message with this method is immutable on forward.
101 *
102 * - some system messages may be forwarded, for some of them
103 * it is useless
104 *
105 * @param method Method to be decided.
106 *
107 * @return Return 1 if the method is immutable on forward.
108 * Otherwise return 0.
109 */
110static inline int method_is_immutable(unative_t method)
111{
112 switch (method) {
113 case IPC_M_AS_AREA_SEND:
114 case IPC_M_AS_AREA_RECV:
115 case IPC_M_DATA_SEND:
116 return 1;
117 break;
118 default:
119 return 0;
120 }
121}
122
123
124/***********************************************************************
125 * Functions that preprocess answer before sending it to the recepient.
126 ***********************************************************************/
127
128/** Decide if the caller (e.g. ipc_answer()) should save the old call contents
129 * for answer_preprocess().
130 *
131 * @param call Call structure to be decided.
132 *
133 * @return Return 1 if the old call contents should be saved.
134 * Return 0 otherwise.
135 */
136static inline int answer_need_old(call_t *call)
137{
138 switch (IPC_GET_METHOD(call->data)) {
139 case IPC_M_CONNECT_TO_ME:
140 case IPC_M_CONNECT_ME_TO:
141 case IPC_M_AS_AREA_SEND:
142 case IPC_M_AS_AREA_RECV:
143 case IPC_M_DATA_SEND:
144 return 1;
145 default:
146 return 0;
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 0 on success or an error code.
158 */
159static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
160{
161 int phoneid;
162
163 if (IPC_GET_RETVAL(answer->data) == EHANGUP) {
164 /* In case of forward, hangup the forwared phone,
165 * not the originator
166 */
167 spinlock_lock(&answer->data.phone->lock);
168 spinlock_lock(&TASK->answerbox.lock);
169 if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
170 list_remove(&answer->data.phone->link);
171 answer->data.phone->state = IPC_PHONE_SLAMMED;
172 }
173 spinlock_unlock(&TASK->answerbox.lock);
174 spinlock_unlock(&answer->data.phone->lock);
175 }
176
177 if (!olddata)
178 return 0;
179
180 if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
181 phoneid = IPC_GET_ARG3(*olddata);
182 if (IPC_GET_RETVAL(answer->data)) {
183 /* The connection was not accepted */
184 phone_dealloc(phoneid);
185 } else {
186 /* The connection was accepted */
187 phone_connect(phoneid, &answer->sender->answerbox);
188 /* Set 'phone hash' as arg3 of response */
189 IPC_SET_ARG3(answer->data,
190 (unative_t) &TASK->phones[phoneid]);
191 }
192 } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
193 /* If the users accepted call, connect */
194 if (!IPC_GET_RETVAL(answer->data)) {
195 ipc_phone_connect((phone_t *) IPC_GET_ARG3(*olddata),
196 &TASK->answerbox);
197 }
198 } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_SEND) {
199 if (!IPC_GET_RETVAL(answer->data)) {
200 /* Accepted, handle as_area receipt */
201 ipl_t ipl;
202 int rc;
203 as_t *as;
204
205 ipl = interrupts_disable();
206 spinlock_lock(&answer->sender->lock);
207 as = answer->sender->as;
208 spinlock_unlock(&answer->sender->lock);
209 interrupts_restore(ipl);
210
211 rc = as_area_share(as, IPC_GET_ARG1(*olddata),
212 IPC_GET_ARG2(*olddata), AS,
213 IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
214 IPC_SET_RETVAL(answer->data, rc);
215 return rc;
216 }
217 } else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_RECV) {
218 if (!IPC_GET_RETVAL(answer->data)) {
219 ipl_t ipl;
220 as_t *as;
221 int rc;
222
223 ipl = interrupts_disable();
224 spinlock_lock(&answer->sender->lock);
225 as = answer->sender->as;
226 spinlock_unlock(&answer->sender->lock);
227 interrupts_restore(ipl);
228
229 rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
230 IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata),
231 IPC_GET_ARG2(answer->data));
232 IPC_SET_RETVAL(answer->data, rc);
233 }
234 } else if (IPC_GET_METHOD(*olddata) == IPC_M_DATA_SEND) {
235 if (!IPC_GET_RETVAL(answer->data)) {
236 int rc;
237 uintptr_t dst;
238 uintptr_t size;
239
240 ASSERT(answer->buffer);
241
242 dst = IPC_GET_ARG1(answer->data);
243 size = IPC_GET_ARG3(answer->data);
244
245 rc = copy_to_uspace((void *) dst, answer->buffer, size);
246 if (rc != 0)
247 IPC_SET_RETVAL(answer->data, rc);
248 free(answer->buffer);
249 answer->buffer = NULL;
250 }
251 }
252 return 0;
253}
254
255/** Called before the request is sent.
256 *
257 * @param call Call structure with the request.
258 *
259 * @return Return 0 on success, ELIMIT or EPERM on error.
260 */
261static int request_preprocess(call_t *call)
262{
263 int newphid;
264 size_t size;
265 uintptr_t src;
266 int rc;
267
268 switch (IPC_GET_METHOD(call->data)) {
269 case IPC_M_CONNECT_ME_TO:
270 newphid = phone_alloc();
271 if (newphid < 0)
272 return ELIMIT;
273 /* Set arg3 for server */
274 IPC_SET_ARG3(call->data, (unative_t) &TASK->phones[newphid]);
275 call->flags |= IPC_CALL_CONN_ME_TO;
276 call->priv = newphid;
277 break;
278 case IPC_M_AS_AREA_SEND:
279 size = as_area_get_size(IPC_GET_ARG1(call->data));
280 if (!size)
281 return EPERM;
282 IPC_SET_ARG2(call->data, size);
283 break;
284 case IPC_M_DATA_SEND:
285 src = IPC_GET_ARG2(call->data);
286 size = IPC_GET_ARG3(call->data);
287
288 if ((size <= 0) || (size > DATA_SEND_LIMIT))
289 return ELIMIT;
290
291 call->buffer = (uint8_t *) malloc(size, 0);
292 rc = copy_from_uspace(call->buffer, (void *) src, size);
293 if (rc != 0) {
294 free(call->buffer);
295 return rc;
296 }
297 break;
298 default:
299 break;
300 }
301 return 0;
302}
303
304/*******************************************************************************
305 * Functions called to process received call/answer before passing it to uspace.
306 *******************************************************************************/
307
308/** Do basic kernel processing of received call answer.
309 *
310 * @param call Call structure with the answer.
311 */
312static void process_answer(call_t *call)
313{
314 if (IPC_GET_RETVAL(call->data) == EHANGUP &&
315 (call->flags & IPC_CALL_FORWARDED))
316 IPC_SET_RETVAL(call->data, EFORWARD);
317
318 if (call->flags & IPC_CALL_CONN_ME_TO) {
319 if (IPC_GET_RETVAL(call->data))
320 phone_dealloc(call->priv);
321 else
322 IPC_SET_ARG3(call->data, call->priv);
323 }
324}
325
326/** Do basic kernel processing of received call request.
327 *
328 * @param box Destination answerbox structure.
329 * @param call Call structure with the request.
330 *
331 * @return Return 0 if the call should be passed to userspace.
332 * Return -1 if the call should be ignored.
333 */
334static int process_request(answerbox_t *box, call_t *call)
335{
336 int phoneid;
337
338 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
339 phoneid = phone_alloc();
340 if (phoneid < 0) { /* Failed to allocate phone */
341 IPC_SET_RETVAL(call->data, ELIMIT);
342 ipc_answer(box, call);
343 return -1;
344 }
345 IPC_SET_ARG3(call->data, phoneid);
346 }
347 return 0;
348}
349
350/** Make a fast call over IPC, wait for reply and return to user.
351 *
352 * This function can handle only one argument of payload, but is faster than
353 * the generic function (i.e. sys_ipc_call_sync()).
354 *
355 * @param phoneid Phone handle for the call.
356 * @param method Method of the call.
357 * @param arg1 Service-defined payload argument.
358 * @param data Address of userspace structure where the reply call will
359 * be stored.
360 *
361 * @return Returns 0 on success.
362 * Return ENOENT if there is no such phone handle.
363 */
364unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
365 unative_t arg1, ipc_data_t *data)
366{
367 call_t call;
368 phone_t *phone;
369 int res;
370
371 GET_CHECK_PHONE(phone, phoneid, return ENOENT);
372
373 ipc_call_static_init(&call);
374 IPC_SET_METHOD(call.data, method);
375 IPC_SET_ARG1(call.data, arg1);
376
377 if (!(res = request_preprocess(&call))) {
378 ipc_call_sync(phone, &call);
379 process_answer(&call);
380 } else {
381 IPC_SET_RETVAL(call.data, res);
382 }
383 STRUCT_TO_USPACE(&data->args, &call.data.args);
384
385 return 0;
386}
387
388/** Make a synchronous IPC call allowing to transmit the entire payload.
389 *
390 * @param phoneid Phone handle for the call.
391 * @param question Userspace address of call data with the request.
392 * @param reply Userspace address of call data where to store the
393 * answer.
394 *
395 * @return Zero on success or an error code.
396 */
397unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
398 ipc_data_t *reply)
399{
400 call_t call;
401 phone_t *phone;
402 int res;
403 int rc;
404
405 ipc_call_static_init(&call);
406 rc = copy_from_uspace(&call.data.args, &question->args,
407 sizeof(call.data.args));
408 if (rc != 0)
409 return (unative_t) rc;
410
411 GET_CHECK_PHONE(phone, phoneid, return ENOENT);
412
413 if (!(res = request_preprocess(&call))) {
414 ipc_call_sync(phone, &call);
415 process_answer(&call);
416 } else
417 IPC_SET_RETVAL(call.data, res);
418
419 rc = STRUCT_TO_USPACE(&reply->args, &call.data.args);
420 if (rc != 0)
421 return rc;
422
423 return 0;
424}
425
426/** Check that the task did not exceed the allowed limit of asynchronous calls.
427 *
428 * @return Return 0 if limit not reached or -1 if limit exceeded.
429 */
430static int check_call_limit(void)
431{
432 if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
433 atomic_dec(&TASK->active_calls);
434 return -1;
435 }
436 return 0;
437}
438
439/** Make a fast asynchronous call over IPC.
440 *
441 * This function can only handle two arguments of payload, but is faster than
442 * the generic function sys_ipc_call_async().
443 *
444 * @param phoneid Phone handle for the call.
445 * @param method Method of the call.
446 * @param arg1 Service-defined payload argument.
447 * @param arg2 Service-defined payload argument.
448 *
449 * @return Return call hash on success.
450 * Return IPC_CALLRET_FATAL in case of a fatal error and
451 * IPC_CALLRET_TEMPORARY if there are too many pending
452 * asynchronous requests; answers should be handled first.
453 */
454unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
455 unative_t arg1, unative_t arg2)
456{
457 call_t *call;
458 phone_t *phone;
459 int res;
460
461 if (check_call_limit())
462 return IPC_CALLRET_TEMPORARY;
463
464 GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
465
466 call = ipc_call_alloc(0);
467 IPC_SET_METHOD(call->data, method);
468 IPC_SET_ARG1(call->data, arg1);
469 IPC_SET_ARG2(call->data, arg2);
470 IPC_SET_ARG3(call->data, 0);
471
472 if (!(res = request_preprocess(call)))
473 ipc_call(phone, call);
474 else
475 ipc_backsend_err(phone, call, res);
476
477 return (unative_t) call;
478}
479
480/** Make an asynchronous IPC call allowing to transmit the entire payload.
481 *
482 * @param phoneid Phone handle for the call.
483 * @param data Userspace address of call data with the request.
484 *
485 * @return See sys_ipc_call_async_fast().
486 */
487unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data)
488{
489 call_t *call;
490 phone_t *phone;
491 int res;
492 int rc;
493
494 if (check_call_limit())
495 return IPC_CALLRET_TEMPORARY;
496
497 GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
498
499 call = ipc_call_alloc(0);
500 rc = copy_from_uspace(&call->data.args, &data->args,
501 sizeof(call->data.args));
502 if (rc != 0) {
503 ipc_call_free(call);
504 return (unative_t) rc;
505 }
506 if (!(res = request_preprocess(call)))
507 ipc_call(phone, call);
508 else
509 ipc_backsend_err(phone, call, res);
510
511 return (unative_t) call;
512}
513
514/** Forward a received call to another destination.
515 *
516 * @param callid Hash of the call to forward.
517 * @param phoneid Phone handle to use for forwarding.
518 * @param method New method to use for the forwarded call.
519 * @param arg1 New value of the first argument for the forwarded call.
520 *
521 * @return Return 0 on succes, otherwise return an error code.
522 *
523 * In case the original method is a system method, ARG1 and ARG2 are overwritten
524 * in the forwarded message with the new method and the new arg1, respectively.
525 * Otherwise the METHOD and ARG1 are rewritten with the new method and arg1,
526 * respectively. Also note there is a set of immutable methods, for which the
527 * new method and argument is not set and these values are ignored.
528 *
529 * Warning: If implementing non-fast version, make sure that
530 * ARG3 is not rewritten for certain system IPC
531 */
532unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
533 unative_t method, unative_t arg1)
534{
535 call_t *call;
536 phone_t *phone;
537
538 call = get_call(callid);
539 if (!call)
540 return ENOENT;
541
542 call->flags |= IPC_CALL_FORWARDED;
543
544 GET_CHECK_PHONE(phone, phoneid, {
545 IPC_SET_RETVAL(call->data, EFORWARD);
546 ipc_answer(&TASK->answerbox, call);
547 return ENOENT;
548 });
549
550 if (!method_is_forwardable(IPC_GET_METHOD(call->data))) {
551 IPC_SET_RETVAL(call->data, EFORWARD);
552 ipc_answer(&TASK->answerbox, call);
553 return EPERM;
554 }
555
556 /*
557 * Userspace is not allowed to change method of system methods on
558 * forward, allow changing ARG1 and ARG2 by means of method and arg1.
559 * If the method is immutable, don't change anything.
560 */
561 if (!method_is_immutable(IPC_GET_METHOD(call->data))) {
562 if (method_is_system(IPC_GET_METHOD(call->data))) {
563 if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
564 phone_dealloc(IPC_GET_ARG3(call->data));
565
566 IPC_SET_ARG1(call->data, method);
567 IPC_SET_ARG2(call->data, arg1);
568 } else {
569 IPC_SET_METHOD(call->data, method);
570 IPC_SET_ARG1(call->data, arg1);
571 }
572 }
573
574 return ipc_forward(call, phone, &TASK->answerbox);
575}
576
577/** Answer an IPC call - fast version.
578 *
579 * This function can handle only two return arguments of payload, but is faster
580 * than the generic sys_ipc_answer().
581 *
582 * @param callid Hash of the call to be answered.
583 * @param retval Return value of the answer.
584 * @param arg1 Service-defined return value.
585 * @param arg2 Service-defined return value.
586 *
587 * @return Return 0 on success, otherwise return an error code.
588 */
589unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
590 unative_t arg1, unative_t arg2)
591{
592 call_t *call;
593 ipc_data_t saved_data;
594 int saveddata = 0;
595 int rc;
596
597 /* Do not answer notification callids */
598 if (callid & IPC_CALLID_NOTIFICATION)
599 return 0;
600
601 call = get_call(callid);
602 if (!call)
603 return ENOENT;
604
605 if (answer_need_old(call)) {
606 memcpy(&saved_data, &call->data, sizeof(call->data));
607 saveddata = 1;
608 }
609
610 IPC_SET_RETVAL(call->data, retval);
611 IPC_SET_ARG1(call->data, arg1);
612 IPC_SET_ARG2(call->data, arg2);
613 rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
614
615 ipc_answer(&TASK->answerbox, call);
616 return rc;
617}
618
619/** Answer an IPC call.
620 *
621 * @param callid Hash of the call to be answered.
622 * @param data Userspace address of call data with the answer.
623 *
624 * @return Return 0 on success, otherwise return an error code.
625 */
626unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data)
627{
628 call_t *call;
629 ipc_data_t saved_data;
630 int saveddata = 0;
631 int rc;
632
633 /* Do not answer notification callids */
634 if (callid & IPC_CALLID_NOTIFICATION)
635 return 0;
636
637 call = get_call(callid);
638 if (!call)
639 return ENOENT;
640
641 if (answer_need_old(call)) {
642 memcpy(&saved_data, &call->data, sizeof(call->data));
643 saveddata = 1;
644 }
645 rc = copy_from_uspace(&call->data.args, &data->args,
646 sizeof(call->data.args));
647 if (rc != 0)
648 return rc;
649
650 rc = answer_preprocess(call, saveddata ? &saved_data : NULL);
651
652 ipc_answer(&TASK->answerbox, call);
653
654 return rc;
655}
656
657/** Hang up a phone.
658 *
659 * @param Phone handle of the phone to be hung up.
660 *
661 * @return Return 0 on success or an error code.
662 */
663unative_t sys_ipc_hangup(int phoneid)
664{
665 phone_t *phone;
666
667 GET_CHECK_PHONE(phone, phoneid, return ENOENT);
668
669 if (ipc_phone_hangup(phone))
670 return -1;
671
672 return 0;
673}
674
675/** Wait for an incoming IPC call or an answer.
676 *
677 * @param calldata Pointer to buffer where the call/answer data is stored.
678 * @param usec Timeout. See waitq_sleep_timeout() for explanation.
679 * @param flags Select mode of sleep operation. See waitq_sleep_timeout()
680 * for explanation.
681 *
682 * @return Hash of the call.
683 * If IPC_CALLID_NOTIFICATION bit is set in the hash, the
684 * call is a notification. IPC_CALLID_ANSWERED denotes an
685 * answer.
686 */
687unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags)
688{
689 call_t *call;
690
691restart:
692 call = ipc_wait_for_call(&TASK->answerbox, usec,
693 flags | SYNCH_FLAGS_INTERRUPTIBLE);
694 if (!call)
695 return 0;
696
697 if (call->flags & IPC_CALL_NOTIF) {
698 ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
699
700 /* Set in_phone_hash to the interrupt counter */
701 call->data.phone = (void *) call->priv;
702
703 STRUCT_TO_USPACE(calldata, &call->data);
704
705 ipc_call_free(call);
706
707 return ((unative_t) call) | IPC_CALLID_NOTIFICATION;
708 }
709
710 if (call->flags & IPC_CALL_ANSWERED) {
711 process_answer(call);
712
713 ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
714
715 atomic_dec(&TASK->active_calls);
716
717 if (call->flags & IPC_CALL_DISCARD_ANSWER) {
718 ipc_call_free(call);
719 goto restart;
720 }
721
722 STRUCT_TO_USPACE(&calldata->args, &call->data.args);
723 ipc_call_free(call);
724
725 return ((unative_t) call) | IPC_CALLID_ANSWERED;
726 }
727
728 if (process_request(&TASK->answerbox, call))
729 goto restart;
730
731 /* Include phone address('id') of the caller in the request,
732 * copy whole call->data, not only call->data.args */
733 if (STRUCT_TO_USPACE(calldata, &call->data)) {
734 return 0;
735 }
736 return (unative_t)call;
737}
738
739/** Connect an IRQ handler to a task.
740 *
741 * @param inr IRQ number.
742 * @param devno Device number.
743 * @param method Method to be associated with the notification.
744 * @param ucode Uspace pointer to the top-half pseudocode.
745 *
746 * @return EPERM or a return code returned by ipc_irq_register().
747 */
748unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method,
749 irq_code_t *ucode)
750{
751 if (!(cap_get(TASK) & CAP_IRQ_REG))
752 return EPERM;
753
754 return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode);
755}
756
757/** Disconnect an IRQ handler from a task.
758 *
759 * @param inr IRQ number.
760 * @param devno Device number.
761 *
762 * @return Zero on success or EPERM on error..
763 */
764unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno)
765{
766 if (!(cap_get(TASK) & CAP_IRQ_REG))
767 return EPERM;
768
769 ipc_irq_unregister(&TASK->answerbox, inr, devno);
770
771 return 0;
772}
773
774/** @}
775 */
Note: See TracBrowser for help on using the repository browser.