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

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

No need to hold the sender task when the call is going to be answered.
The sender may no longer forget the call and, in fact, must wait for it.

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