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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 314f4b59 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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