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

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

Copy entire ipc_data_t to uspace on answer

This is necessary so that we get the task ID of the other side when creating
callback connections via IPC_M_CONNECT_TO_ME.

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