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

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

Add IPC_M_STATE_CHANGE_AUTHORIZE.

  • This message is used when two clients of the same server task want to achieve certain change in their state but that state is maintained externally in the server.
  • The typical situation is passing some sort of handle from the donor task to the acceptor task.
  • Property mode set to 100644
File size: 33.5 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 <proc/task.h>
[e3c762cd]37#include <proc/thread.h>
[2d5a54f3]38#include <errno.h>
39#include <memstr.h>
40#include <debug.h>
41#include <ipc/ipc.h>
[c0699467]42#include <abi/ipc/methods.h>
[2d5a54f3]43#include <ipc/sysipc.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>
[9a1b20c]49#include <udebug/udebug_ipc.h>
[5626277]50#include <arch/interrupt.h>
[e3c762cd]51#include <syscall/copy.h>
[2bb8648]52#include <security/cap.h>
[6b10dab]53#include <console/console.h>
[7c23af9]54#include <mm/as.h>
[253f35a1]55#include <print.h>
[2d5a54f3]56
[36d852c]57/**
58 * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
59 * requests.
60 */
[da1bafb]61#define DATA_XFER_LIMIT (64 * 1024)
62
63#define STRUCT_TO_USPACE(dst, src) copy_to_uspace((dst), (src), sizeof(*(src)))
[7918fce]64
[c9fff17]65/** Get phone from the current task by ID.
66 *
[da1bafb]67 * @param phoneid Phone ID.
68 * @param phone Place to store pointer to phone.
69 *
70 * @return EOK on success, EINVAL if ID is invalid.
71 *
[c9fff17]72 */
[96b02eb9]73static int phone_get(sysarg_t phoneid, phone_t **phone)
[c9fff17]74{
75 if (phoneid >= IPC_MAX_PHONES)
76 return EINVAL;
[da1bafb]77
[c9fff17]78 *phone = &TASK->phones[phoneid];
79 return EOK;
[ba81cab]80}
81
[228e490]82/** Decide if the interface and method is a system method.
[8b243f2]83 *
[228e490]84 * @param imethod Interface and method to be decided.
[da1bafb]85 *
[228e490]86 * @return True if the interface and method is a system
87 * interface and method.
[8b243f2]88 *
89 */
[228e490]90static inline bool method_is_system(sysarg_t imethod)
[2ba7810]91{
[228e490]92 if (imethod <= IPC_M_LAST_SYSTEM)
[da1bafb]93 return true;
94
95 return false;
[2ba7810]96}
97
[228e490]98/** Decide if the message with this interface and method is forwardable.
[2ba7810]99 *
[228e490]100 * Some system messages may be forwarded, for some of them
101 * it is useless.
[8b243f2]102 *
[228e490]103 * @param imethod Interface and method to be decided.
[da1bafb]104 *
[228e490]105 * @return True if the interface and method is forwardable.
[8b243f2]106 *
[2ba7810]107 */
[228e490]108static inline bool method_is_forwardable(sysarg_t imethod)
[2ba7810]109{
[228e490]110 switch (imethod) {
[2c0e5d2]111 case IPC_M_CONNECTION_CLONE:
112 case IPC_M_CONNECT_ME:
[7918fce]113 case IPC_M_PHONE_HUNGUP:
114 /* This message is meant only for the original recipient. */
[da1bafb]115 return false;
[7918fce]116 default:
[da1bafb]117 return true;
[7918fce]118 }
[2ba7810]119}
120
[228e490]121/** Decide if the message with this interface and method is immutable on forward.
[0dc4258]122 *
[228e490]123 * Some system messages may be forwarded but their content cannot be altered.
[0dc4258]124 *
[228e490]125 * @param imethod Interface and method to be decided.
[da1bafb]126 *
[228e490]127 * @return True if the interface and method is immutable on forward.
[0dc4258]128 *
129 */
[228e490]130static inline bool method_is_immutable(sysarg_t imethod)
[0dc4258]131{
[228e490]132 switch (imethod) {
[27d293a]133 case IPC_M_SHARE_OUT:
134 case IPC_M_SHARE_IN:
[36d852c]135 case IPC_M_DATA_WRITE:
136 case IPC_M_DATA_READ:
[fdd4898]137 case IPC_M_STATE_CHANGE_AUTHORIZE:
[da1bafb]138 return true;
[0dc4258]139 default:
[da1bafb]140 return false;
[0dc4258]141 }
142}
143
[2d5a54f3]144
[8b243f2]145/***********************************************************************
146 * Functions that preprocess answer before sending it to the recepient.
147 ***********************************************************************/
148
149/** Decide if the caller (e.g. ipc_answer()) should save the old call contents
150 * for answer_preprocess().
151 *
[da1bafb]152 * @param call Call structure to be decided.
153 *
154 * @return true if the old call contents should be saved.
[8b243f2]155 *
[2d5a54f3]156 */
[da1bafb]157static inline bool answer_need_old(call_t *call)
[2d5a54f3]158{
[228e490]159 switch (IPC_GET_IMETHOD(call->data)) {
[2c0e5d2]160 case IPC_M_CONNECTION_CLONE:
161 case IPC_M_CONNECT_ME:
[7918fce]162 case IPC_M_CONNECT_TO_ME:
163 case IPC_M_CONNECT_ME_TO:
[27d293a]164 case IPC_M_SHARE_OUT:
165 case IPC_M_SHARE_IN:
[36d852c]166 case IPC_M_DATA_WRITE:
167 case IPC_M_DATA_READ:
[fdd4898]168 case IPC_M_STATE_CHANGE_AUTHORIZE:
[da1bafb]169 return true;
[7918fce]170 default:
[da1bafb]171 return false;
[7918fce]172 }
[2d5a54f3]173}
174
[8b243f2]175/** Interpret process answer as control information.
176 *
177 * This function is called directly after sys_ipc_answer().
[46fc2f9]178 *
[da1bafb]179 * @param answer Call structure with the answer.
180 * @param olddata Saved data of the request.
181 *
182 * @return Return 0 on success or an error code.
[8b243f2]183 *
[46fc2f9]184 */
[7c23af9]185static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
[2d5a54f3]186{
[6c441cf8]187 if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
[ca687ad]188 /* In case of forward, hangup the forwared phone,
189 * not the originator
190 */
[ff48a15]191 mutex_lock(&answer->data.phone->lock);
[da1bafb]192 irq_spinlock_lock(&TASK->answerbox.lock, true);
[eb3d379]193 if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
[c4e4507]194 list_remove(&answer->data.phone->link);
[eb3d379]195 answer->data.phone->state = IPC_PHONE_SLAMMED;
[ca687ad]196 }
[da1bafb]197 irq_spinlock_unlock(&TASK->answerbox.lock, true);
[ff48a15]198 mutex_unlock(&answer->data.phone->lock);
[9f22213]199 }
[da1bafb]200
[9f22213]201 if (!olddata)
[7c23af9]202 return 0;
[da1bafb]203
[228e490]204 if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
[da1bafb]205 int phoneid = IPC_GET_ARG1(*olddata);
206 phone_t *phone = &TASK->phones[phoneid];
207
[2c0e5d2]208 if (IPC_GET_RETVAL(answer->data) != EOK) {
209 /*
210 * The recipient of the cloned phone rejected the offer.
211 * In this case, the connection was established at the
212 * request time and therefore we need to slam the phone.
213 * We don't merely hangup as that would result in
214 * sending IPC_M_HUNGUP to the third party on the
215 * other side of the cloned phone.
216 */
217 mutex_lock(&phone->lock);
218 if (phone->state == IPC_PHONE_CONNECTED) {
[da1bafb]219 irq_spinlock_lock(&phone->callee->lock, true);
[2c0e5d2]220 list_remove(&phone->link);
221 phone->state = IPC_PHONE_SLAMMED;
[da1bafb]222 irq_spinlock_unlock(&phone->callee->lock, true);
[2c0e5d2]223 }
224 mutex_unlock(&phone->lock);
225 }
[228e490]226 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME) {
[da1bafb]227 phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
228
[2c0e5d2]229 if (IPC_GET_RETVAL(answer->data) != EOK) {
230 /*
231 * The other party on the cloned phoned rejected our
232 * request for connection on the protocol level.
233 * We need to break the connection without sending
234 * IPC_M_HUNGUP back.
235 */
236 mutex_lock(&phone->lock);
237 if (phone->state == IPC_PHONE_CONNECTED) {
[da1bafb]238 irq_spinlock_lock(&phone->callee->lock, true);
[2c0e5d2]239 list_remove(&phone->link);
240 phone->state = IPC_PHONE_SLAMMED;
[da1bafb]241 irq_spinlock_unlock(&phone->callee->lock, true);
[2c0e5d2]242 }
243 mutex_unlock(&phone->lock);
244 }
[228e490]245 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
[da1bafb]246 int phoneid = IPC_GET_ARG5(*olddata);
247
[2c0e5d2]248 if (IPC_GET_RETVAL(answer->data) != EOK) {
[2d5a54f3]249 /* The connection was not accepted */
250 phone_dealloc(phoneid);
[2ba7810]251 } else {
[7c7aae16]252 /* The connection was accepted */
[51ec40f]253 phone_connect(phoneid, &answer->sender->answerbox);
[124c061]254 /* Set 'task hash' as arg4 of response */
255 IPC_SET_ARG4(answer->data, (sysarg_t) TASK);
[6364d3c]256 /* Set 'phone hash' as arg5 of response */
[38c706cc]257 IPC_SET_ARG5(answer->data,
[96b02eb9]258 (sysarg_t) &TASK->phones[phoneid]);
[2d5a54f3]259 }
[228e490]260 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
[37c57f2]261 /* If the users accepted call, connect */
[2c0e5d2]262 if (IPC_GET_RETVAL(answer->data) == EOK) {
[b61d47d]263 ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
[51ec40f]264 &TASK->answerbox);
[37c57f2]265 }
[228e490]266 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_OUT) {
[51ec40f]267 if (!IPC_GET_RETVAL(answer->data)) {
268 /* Accepted, handle as_area receipt */
[8d6bc2d5]269
[da1bafb]270 irq_spinlock_lock(&answer->sender->lock, true);
271 as_t *as = answer->sender->as;
272 irq_spinlock_unlock(&answer->sender->lock, true);
[8d6bc2d5]273
[da1bafb]274 int rc = as_area_share(as, IPC_GET_ARG1(*olddata),
[51ec40f]275 IPC_GET_ARG2(*olddata), AS,
276 IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
[76d7305]277 IPC_SET_RETVAL(answer->data, rc);
278 return rc;
[46fc2f9]279 }
[228e490]280 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
[46fc2f9]281 if (!IPC_GET_RETVAL(answer->data)) {
[da1bafb]282 irq_spinlock_lock(&answer->sender->lock, true);
283 as_t *as = answer->sender->as;
284 irq_spinlock_unlock(&answer->sender->lock, true);
[46fc2f9]285
[da1bafb]286 int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
[51ec40f]287 IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata),
288 IPC_GET_ARG2(answer->data));
[d6e5cbc]289 IPC_SET_RETVAL(answer->data, rc);
[7c23af9]290 }
[228e490]291 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_READ) {
[a55d5f9f]292 ASSERT(!answer->buffer);
293 if (!IPC_GET_RETVAL(answer->data)) {
294 /* The recipient agreed to send data. */
295 uintptr_t src = IPC_GET_ARG1(answer->data);
296 uintptr_t dst = IPC_GET_ARG1(*olddata);
297 size_t max_size = IPC_GET_ARG2(*olddata);
298 size_t size = IPC_GET_ARG2(answer->data);
[1a60feeb]299 if (size && size <= max_size) {
[a55d5f9f]300 /*
301 * Copy the destination VA so that this piece of
302 * information is not lost.
303 */
304 IPC_SET_ARG1(answer->data, dst);
[da1bafb]305
[a55d5f9f]306 answer->buffer = malloc(size, 0);
307 int rc = copy_from_uspace(answer->buffer,
308 (void *) src, size);
309 if (rc) {
310 IPC_SET_RETVAL(answer->data, rc);
311 free(answer->buffer);
312 answer->buffer = NULL;
313 }
[1a60feeb]314 } else if (!size) {
315 IPC_SET_RETVAL(answer->data, EOK);
[a55d5f9f]316 } else {
317 IPC_SET_RETVAL(answer->data, ELIMIT);
318 }
319 }
[228e490]320 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_WRITE) {
[654b7db]321 ASSERT(answer->buffer);
[7918fce]322 if (!IPC_GET_RETVAL(answer->data)) {
[a55d5f9f]323 /* The recipient agreed to receive data. */
[da1bafb]324 uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
325 size_t size = (size_t)IPC_GET_ARG2(answer->data);
326 size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
327
[a55d5f9f]328 if (size <= max_size) {
[da1bafb]329 int rc = copy_to_uspace((void *) dst,
[a55d5f9f]330 answer->buffer, size);
331 if (rc)
332 IPC_SET_RETVAL(answer->data, rc);
333 } else {
334 IPC_SET_RETVAL(answer->data, ELIMIT);
335 }
[7918fce]336 }
[654b7db]337 free(answer->buffer);
338 answer->buffer = NULL;
[fdd4898]339 } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_STATE_CHANGE_AUTHORIZE) {
340 if (!IPC_GET_RETVAL(answer->data)) {
341 /* The recipient authorized the change of state. */
342 phone_t *recipient_phone;
343 task_t *other_task_s;
344 task_t *other_task_r;
345 int rc;
346
347 rc = phone_get(IPC_GET_ARG1(answer->data),
348 &recipient_phone);
349 if (rc != EOK) {
350 IPC_SET_RETVAL(answer->data, ENOENT);
351 return ENOENT;
352 }
353
354 mutex_lock(&recipient_phone->lock);
355 if (recipient_phone->state != IPC_PHONE_CONNECTED) {
356 mutex_unlock(&recipient_phone->lock);
357 IPC_SET_RETVAL(answer->data, EINVAL);
358 return EINVAL;
359 }
360
361 other_task_r = recipient_phone->callee->task;
362 other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
363
364 /*
365 * See if both the sender and the recipient meant the
366 * same third party task.
367 */
368 if (other_task_r != other_task_s) {
369 IPC_SET_RETVAL(answer->data, EINVAL);
370 rc = EINVAL;
371 } else {
372 rc = event_task_notify_5(other_task_r,
373 EVENT_TASK_STATE_CHANGE, false,
374 IPC_GET_ARG1(*olddata),
375 IPC_GET_ARG2(*olddata),
376 IPC_GET_ARG3(*olddata),
377 (sysarg_t) olddata->task,
378 (sysarg_t) TASK);
379 IPC_SET_RETVAL(answer->data, rc);
380 }
381
382 mutex_unlock(&recipient_phone->lock);
383 return rc;
384 }
[2d5a54f3]385 }
[da1bafb]386
[7c23af9]387 return 0;
[2d5a54f3]388}
389
[bf1fb9f]390static void phones_lock(phone_t *p1, phone_t *p2)
391{
392 if (p1 < p2) {
393 mutex_lock(&p1->lock);
394 mutex_lock(&p2->lock);
395 } else if (p1 > p2) {
396 mutex_lock(&p2->lock);
397 mutex_lock(&p1->lock);
[da1bafb]398 } else
[bf1fb9f]399 mutex_lock(&p1->lock);
400}
401
402static void phones_unlock(phone_t *p1, phone_t *p2)
403{
404 mutex_unlock(&p1->lock);
405 if (p1 != p2)
406 mutex_unlock(&p2->lock);
407}
408
[8b243f2]409/** Called before the request is sent.
410 *
[da1bafb]411 * @param call Call structure with the request.
412 * @param phone Phone that the call will be sent through.
413 *
414 * @return Return 0 on success, ELIMIT or EPERM on error.
[7c7aae16]415 *
416 */
[9a1b20c]417static int request_preprocess(call_t *call, phone_t *phone)
[7c7aae16]418{
[228e490]419 switch (IPC_GET_IMETHOD(call->data)) {
[2c0e5d2]420 case IPC_M_CONNECTION_CLONE: {
421 phone_t *cloned_phone;
[c9fff17]422 if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
423 return ENOENT;
[da1bafb]424
[bf1fb9f]425 phones_lock(cloned_phone, phone);
[da1bafb]426
[2c0e5d2]427 if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
428 phone->state != IPC_PHONE_CONNECTED) {
[bf1fb9f]429 phones_unlock(cloned_phone, phone);
[2c0e5d2]430 return EINVAL;
431 }
[da1bafb]432
[2c0e5d2]433 /*
434 * We can be pretty sure now that both tasks exist and we are
435 * connected to them. As we continue to hold the phone locks,
436 * we are effectively preventing them from finishing their
437 * potential cleanup.
[da1bafb]438 *
[2c0e5d2]439 */
[da1bafb]440 int newphid = phone_alloc(phone->callee->task);
[2c0e5d2]441 if (newphid < 0) {
[bf1fb9f]442 phones_unlock(cloned_phone, phone);
[2c0e5d2]443 return ELIMIT;
444 }
[da1bafb]445
[2c0e5d2]446 ipc_phone_connect(&phone->callee->task->phones[newphid],
447 cloned_phone->callee);
[bf1fb9f]448 phones_unlock(cloned_phone, phone);
[da1bafb]449
[2c0e5d2]450 /* Set the new phone for the callee. */
451 IPC_SET_ARG1(call->data, newphid);
452 break;
453 }
454 case IPC_M_CONNECT_ME:
[96b02eb9]455 IPC_SET_ARG5(call->data, (sysarg_t) phone);
[2c0e5d2]456 break;
[da1bafb]457 case IPC_M_CONNECT_ME_TO: {
458 int newphid = phone_alloc(TASK);
[7c7aae16]459 if (newphid < 0)
460 return ELIMIT;
[da1bafb]461
[6364d3c]462 /* Set arg5 for server */
[96b02eb9]463 IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
[7c7aae16]464 call->flags |= IPC_CALL_CONN_ME_TO;
[0c1a5d8a]465 call->priv = newphid;
[7c7aae16]466 break;
[da1bafb]467 }
468 case IPC_M_SHARE_OUT: {
469 size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
[8b243f2]470 if (!size)
[7c23af9]471 return EPERM;
[da1bafb]472
[fd4d8c0]473 IPC_SET_ARG2(call->data, size);
[7c23af9]474 break;
[da1bafb]475 }
476 case IPC_M_DATA_READ: {
477 size_t size = IPC_GET_ARG2(call->data);
[f6bffee]478 if (size > DATA_XFER_LIMIT) {
479 int flags = IPC_GET_ARG3(call->data);
480 if (flags & IPC_XF_RESTRICT)
481 IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
482 else
483 return ELIMIT;
484 }
[a55d5f9f]485 break;
[da1bafb]486 }
487 case IPC_M_DATA_WRITE: {
488 uintptr_t src = IPC_GET_ARG1(call->data);
489 size_t size = IPC_GET_ARG2(call->data);
[7918fce]490
[f6bffee]491 if (size > DATA_XFER_LIMIT) {
492 int flags = IPC_GET_ARG3(call->data);
493 if (flags & IPC_XF_RESTRICT) {
494 size = DATA_XFER_LIMIT;
495 IPC_SET_ARG2(call->data, size);
496 } else
497 return ELIMIT;
498 }
[7918fce]499
500 call->buffer = (uint8_t *) malloc(size, 0);
[da1bafb]501 int rc = copy_from_uspace(call->buffer, (void *) src, size);
[7918fce]502 if (rc != 0) {
503 free(call->buffer);
504 return rc;
505 }
[da1bafb]506
[7918fce]507 break;
[da1bafb]508 }
[fdd4898]509 case IPC_M_STATE_CHANGE_AUTHORIZE: {
510 phone_t *sender_phone;
511 task_t *other_task_s;
512
513 if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
514 return ENOENT;
515
516 mutex_lock(&sender_phone->lock);
517 if (sender_phone->state != IPC_PHONE_CONNECTED) {
518 mutex_unlock(&sender_phone->lock);
519 return EINVAL;
520 }
521
522 other_task_s = sender_phone->callee->task;
523
524 mutex_unlock(&sender_phone->lock);
525
526 /* Remember the third party task hash. */
527 IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
528 break;
529 }
[9a1b20c]530#ifdef CONFIG_UDEBUG
[79ae36dd]531 case IPC_M_DEBUG:
[9a1b20c]532 return udebug_request_preprocess(call, phone);
533#endif
[7c7aae16]534 default:
535 break;
536 }
[da1bafb]537
[7c7aae16]538 return 0;
539}
540
[8b243f2]541/*******************************************************************************
542 * Functions called to process received call/answer before passing it to uspace.
543 *******************************************************************************/
[2d5a54f3]544
[8b243f2]545/** Do basic kernel processing of received call answer.
546 *
[da1bafb]547 * @param call Call structure with the answer.
548 *
[8b243f2]549 */
[7c7aae16]550static void process_answer(call_t *call)
[2d5a54f3]551{
[6c441cf8]552 if (((native_t) IPC_GET_RETVAL(call->data) == EHANGUP) &&
[51ec40f]553 (call->flags & IPC_CALL_FORWARDED))
[9f22213]554 IPC_SET_RETVAL(call->data, EFORWARD);
[da1bafb]555
[7c7aae16]556 if (call->flags & IPC_CALL_CONN_ME_TO) {
557 if (IPC_GET_RETVAL(call->data))
[0c1a5d8a]558 phone_dealloc(call->priv);
[7c7aae16]559 else
[b61d47d]560 IPC_SET_ARG5(call->data, call->priv);
[7c7aae16]561 }
[da1bafb]562
[a55d5f9f]563 if (call->buffer) {
[da1bafb]564 /*
565 * This must be an affirmative answer to IPC_M_DATA_READ
[79ae36dd]566 * or IPC_M_DEBUG/UDEBUG_M_MEM_READ...
[da1bafb]567 *
568 */
[a55d5f9f]569 uintptr_t dst = IPC_GET_ARG1(call->data);
570 size_t size = IPC_GET_ARG2(call->data);
571 int rc = copy_to_uspace((void *) dst, call->buffer, size);
572 if (rc)
573 IPC_SET_RETVAL(call->data, rc);
574 free(call->buffer);
575 call->buffer = NULL;
576 }
[2d5a54f3]577}
578
[8b243f2]579/** Do basic kernel processing of received call request.
580 *
[da1bafb]581 * @param box Destination answerbox structure.
582 * @param call Call structure with the request.
583 *
584 * @return 0 if the call should be passed to userspace.
585 * @return -1 if the call should be ignored.
[2d5a54f3]586 *
587 */
[51ec40f]588static int process_request(answerbox_t *box, call_t *call)
[2d5a54f3]589{
[228e490]590 if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME) {
[da1bafb]591 int phoneid = phone_alloc(TASK);
[2d5a54f3]592 if (phoneid < 0) { /* Failed to allocate phone */
593 IPC_SET_RETVAL(call->data, ELIMIT);
[8b243f2]594 ipc_answer(box, call);
[2d5a54f3]595 return -1;
596 }
[da1bafb]597
[38c706cc]598 IPC_SET_ARG5(call->data, phoneid);
[9a1b20c]599 }
[da1bafb]600
[228e490]601 switch (IPC_GET_IMETHOD(call->data)) {
[79ae36dd]602 case IPC_M_DEBUG:
[9a1b20c]603 return -1;
604 default:
605 break;
606 }
[da1bafb]607
[2d5a54f3]608 return 0;
609}
610
[8b243f2]611/** Make a fast call over IPC, wait for reply and return to user.
612 *
[2e51969]613 * This function can handle only three arguments of payload, but is faster than
614 * the generic function (i.e. sys_ipc_call_sync_slow()).
[2d5a54f3]615 *
[da1bafb]616 * @param phoneid Phone handle for the call.
[228e490]617 * @param imethod Interface and method of the call.
[da1bafb]618 * @param arg1 Service-defined payload argument.
619 * @param arg2 Service-defined payload argument.
620 * @param arg3 Service-defined payload argument.
[228e490]621 * @param data Address of user-space structure where the reply call will
[da1bafb]622 * be stored.
623 *
624 * @return 0 on success.
625 * @return ENOENT if there is no such phone handle.
[8b243f2]626 *
[2d5a54f3]627 */
[228e490]628sysarg_t sys_ipc_call_sync_fast(sysarg_t phoneid, sysarg_t imethod,
[96b02eb9]629 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, ipc_data_t *data)
[2d5a54f3]630{
631 phone_t *phone;
[c9fff17]632 if (phone_get(phoneid, &phone) != EOK)
633 return ENOENT;
[228e490]634
[da1bafb]635 call_t *call = ipc_call_alloc(0);
[228e490]636 IPC_SET_IMETHOD(call->data, imethod);
[35bb2e7]637 IPC_SET_ARG1(call->data, arg1);
638 IPC_SET_ARG2(call->data, arg2);
639 IPC_SET_ARG3(call->data, arg3);
[da1bafb]640
[8498915]641 /*
642 * To achieve deterministic behavior, zero out arguments that are beyond
643 * the limits of the fast version.
644 */
[35bb2e7]645 IPC_SET_ARG4(call->data, 0);
646 IPC_SET_ARG5(call->data, 0);
[da1bafb]647
648 int res = request_preprocess(call, phone);
649 int rc;
650
651 if (!res) {
[741fd16]652#ifdef CONFIG_UDEBUG
653 udebug_stoppable_begin();
654#endif
[35bb2e7]655 rc = ipc_call_sync(phone, call);
[741fd16]656#ifdef CONFIG_UDEBUG
657 udebug_stoppable_end();
658#endif
[da1bafb]659
[35bb2e7]660 if (rc != EOK) {
[33adc6ce]661 /* The call will be freed by ipc_cleanup(). */
[79872cd]662 return rc;
[35bb2e7]663 }
[da1bafb]664
[35bb2e7]665 process_answer(call);
[da1bafb]666 } else
[35bb2e7]667 IPC_SET_RETVAL(call->data, res);
[da1bafb]668
[35bb2e7]669 rc = STRUCT_TO_USPACE(&data->args, &call->data.args);
670 ipc_call_free(call);
[bc50fc42]671 if (rc != 0)
672 return rc;
[da1bafb]673
[2d5a54f3]674 return 0;
675}
676
[8b243f2]677/** Make a synchronous IPC call allowing to transmit the entire payload.
678 *
[228e490]679 * @param phoneid Phone handle for the call.
680 * @param request User-space address of call data with the request.
681 * @param reply User-space address of call data where to store the
682 * answer.
[da1bafb]683 *
684 * @return Zero on success or an error code.
[8b243f2]685 *
686 */
[228e490]687sysarg_t sys_ipc_call_sync_slow(sysarg_t phoneid, ipc_data_t *request,
[51ec40f]688 ipc_data_t *reply)
[2d5a54f3]689{
690 phone_t *phone;
[c9fff17]691 if (phone_get(phoneid, &phone) != EOK)
692 return ENOENT;
[228e490]693
[da1bafb]694 call_t *call = ipc_call_alloc(0);
[228e490]695 int rc = copy_from_uspace(&call->data.args, &request->args,
[35bb2e7]696 sizeof(call->data.args));
697 if (rc != 0) {
698 ipc_call_free(call);
[96b02eb9]699 return (sysarg_t) rc;
[35bb2e7]700 }
[da1bafb]701
702 int res = request_preprocess(call, phone);
703
704 if (!res) {
[741fd16]705#ifdef CONFIG_UDEBUG
706 udebug_stoppable_begin();
707#endif
[35bb2e7]708 rc = ipc_call_sync(phone, call);
[741fd16]709#ifdef CONFIG_UDEBUG
710 udebug_stoppable_end();
711#endif
[da1bafb]712
[35bb2e7]713 if (rc != EOK) {
[33adc6ce]714 /* The call will be freed by ipc_cleanup(). */
[79872cd]715 return rc;
[35bb2e7]716 }
[da1bafb]717
[35bb2e7]718 process_answer(call);
[da1bafb]719 } else
[35bb2e7]720 IPC_SET_RETVAL(call->data, res);
[da1bafb]721
[35bb2e7]722 rc = STRUCT_TO_USPACE(&reply->args, &call->data.args);
723 ipc_call_free(call);
[e3c762cd]724 if (rc != 0)
725 return rc;
[da1bafb]726
[2d5a54f3]727 return 0;
728}
729
[97d17fe]730/** Check that the task did not exceed the allowed limit of asynchronous calls
731 * made over a phone.
[2d5a54f3]732 *
[228e490]733 * @param phone Phone to check the limit against.
734 *
[da1bafb]735 * @return 0 if limit not reached or -1 if limit exceeded.
736 *
[2d5a54f3]737 */
[97d17fe]738static int check_call_limit(phone_t *phone)
[2d5a54f3]739{
[97d17fe]740 if (atomic_get(&phone->active_calls) >= IPC_MAX_ASYNC_CALLS)
[2d5a54f3]741 return -1;
[da1bafb]742
[2d5a54f3]743 return 0;
744}
745
[8b243f2]746/** Make a fast asynchronous call over IPC.
[2d5a54f3]747 *
[3209923]748 * This function can only handle four arguments of payload, but is faster than
749 * the generic function sys_ipc_call_async_slow().
[8b243f2]750 *
[da1bafb]751 * @param phoneid Phone handle for the call.
[228e490]752 * @param imethod Interface and method of the call.
[da1bafb]753 * @param arg1 Service-defined payload argument.
754 * @param arg2 Service-defined payload argument.
755 * @param arg3 Service-defined payload argument.
756 * @param arg4 Service-defined payload argument.
757 *
758 * @return Call hash on success.
759 * @return IPC_CALLRET_FATAL in case of a fatal error.
760 * @return IPC_CALLRET_TEMPORARY if there are too many pending
761 * asynchronous requests; answers should be handled first.
762 *
[2d5a54f3]763 */
[228e490]764sysarg_t sys_ipc_call_async_fast(sysarg_t phoneid, sysarg_t imethod,
[96b02eb9]765 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
[2d5a54f3]766{
[da1bafb]767 phone_t *phone;
[c9fff17]768 if (phone_get(phoneid, &phone) != EOK)
769 return IPC_CALLRET_FATAL;
[228e490]770
[97d17fe]771 if (check_call_limit(phone))
772 return IPC_CALLRET_TEMPORARY;
[da1bafb]773
774 call_t *call = ipc_call_alloc(0);
[228e490]775 IPC_SET_IMETHOD(call->data, imethod);
[2d5a54f3]776 IPC_SET_ARG1(call->data, arg1);
777 IPC_SET_ARG2(call->data, arg2);
[3209923]778 IPC_SET_ARG3(call->data, arg3);
779 IPC_SET_ARG4(call->data, arg4);
[da1bafb]780
[8498915]781 /*
782 * To achieve deterministic behavior, zero out arguments that are beyond
783 * the limits of the fast version.
784 */
785 IPC_SET_ARG5(call->data, 0);
[da1bafb]786
787 int res = request_preprocess(call, phone);
788
789 if (!res)
[7c7aae16]790 ipc_call(phone, call);
791 else
792 ipc_backsend_err(phone, call, res);
[da1bafb]793
[96b02eb9]794 return (sysarg_t) call;
[2d5a54f3]795}
796
[8b243f2]797/** Make an asynchronous IPC call allowing to transmit the entire payload.
798 *
[da1bafb]799 * @param phoneid Phone handle for the call.
800 * @param data Userspace address of call data with the request.
801 *
802 * @return See sys_ipc_call_async_fast().
[2d5a54f3]803 *
804 */
[96b02eb9]805sysarg_t sys_ipc_call_async_slow(sysarg_t phoneid, ipc_data_t *data)
[2d5a54f3]806{
[da1bafb]807 phone_t *phone;
[c9fff17]808 if (phone_get(phoneid, &phone) != EOK)
809 return IPC_CALLRET_FATAL;
[4e49572]810
[97d17fe]811 if (check_call_limit(phone))
812 return IPC_CALLRET_TEMPORARY;
813
[da1bafb]814 call_t *call = ipc_call_alloc(0);
815 int rc = copy_from_uspace(&call->data.args, &data->args,
[51ec40f]816 sizeof(call->data.args));
[f58af46]817 if (rc != 0) {
818 ipc_call_free(call);
[96b02eb9]819 return (sysarg_t) rc;
[f58af46]820 }
[da1bafb]821
822 int res = request_preprocess(call, phone);
823
824 if (!res)
[7c7aae16]825 ipc_call(phone, call);
826 else
827 ipc_backsend_err(phone, call, res);
[da1bafb]828
[96b02eb9]829 return (sysarg_t) call;
[2d5a54f3]830}
831
[da1bafb]832/** Forward a received call to another destination
833 *
834 * Common code for both the fast and the slow version.
835 *
836 * @param callid Hash of the call to forward.
837 * @param phoneid Phone handle to use for forwarding.
[228e490]838 * @param imethod New interface and method to use for the forwarded call.
[da1bafb]839 * @param arg1 New value of the first argument for the forwarded call.
840 * @param arg2 New value of the second argument for the forwarded call.
841 * @param arg3 New value of the third argument for the forwarded call.
842 * @param arg4 New value of the fourth argument for the forwarded call.
843 * @param arg5 New value of the fifth argument for the forwarded call.
844 * @param mode Flags that specify mode of the forward operation.
845 * @param slow If true, arg3, arg4 and arg5 are considered. Otherwise
846 * the function considers only the fast version arguments:
847 * i.e. arg1 and arg2.
848 *
849 * @return 0 on succes, otherwise an error code.
850 *
851 * Warning: Make sure that ARG5 is not rewritten for certain system IPC
852 *
[2ba7810]853 */
[96b02eb9]854static sysarg_t sys_ipc_forward_common(sysarg_t callid, sysarg_t phoneid,
[228e490]855 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
[96b02eb9]856 sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
[2ba7810]857{
[da1bafb]858 call_t *call = get_call(callid);
[2ba7810]859 if (!call)
860 return ENOENT;
[48daf64]861
[9f22213]862 call->flags |= IPC_CALL_FORWARDED;
[da1bafb]863
864 phone_t *phone;
[c9fff17]865 if (phone_get(phoneid, &phone) != EOK) {
[2ba7810]866 IPC_SET_RETVAL(call->data, EFORWARD);
867 ipc_answer(&TASK->answerbox, call);
868 return ENOENT;
[c9fff17]869 }
[da1bafb]870
[228e490]871 if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
[2ba7810]872 IPC_SET_RETVAL(call->data, EFORWARD);
873 ipc_answer(&TASK->answerbox, call);
874 return EPERM;
875 }
[da1bafb]876
[0dc4258]877 /*
[228e490]878 * Userspace is not allowed to change interface and method of system
879 * methods on forward, allow changing ARG1, ARG2, ARG3 and ARG4 by
880 * means of method, arg1, arg2 and arg3.
881 * If the interface and method is immutable, don't change anything.
[2ba7810]882 */
[228e490]883 if (!method_is_immutable(IPC_GET_IMETHOD(call->data))) {
884 if (method_is_system(IPC_GET_IMETHOD(call->data))) {
885 if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME)
[b61d47d]886 phone_dealloc(IPC_GET_ARG5(call->data));
[da1bafb]887
[228e490]888 IPC_SET_ARG1(call->data, imethod);
[0dc4258]889 IPC_SET_ARG2(call->data, arg1);
[b61d47d]890 IPC_SET_ARG3(call->data, arg2);
[da1bafb]891
[48daf64]892 if (slow) {
893 IPC_SET_ARG4(call->data, arg3);
894 /*
895 * For system methods we deliberately don't
896 * overwrite ARG5.
897 */
898 }
[0dc4258]899 } else {
[228e490]900 IPC_SET_IMETHOD(call->data, imethod);
[0dc4258]901 IPC_SET_ARG1(call->data, arg1);
[b61d47d]902 IPC_SET_ARG2(call->data, arg2);
[48daf64]903 if (slow) {
904 IPC_SET_ARG3(call->data, arg3);
905 IPC_SET_ARG4(call->data, arg4);
906 IPC_SET_ARG5(call->data, arg5);
907 }
[0dc4258]908 }
[2ba7810]909 }
[da1bafb]910
[d40a8ff]911 return ipc_forward(call, phone, &TASK->answerbox, mode);
[2ba7810]912}
913
[48daf64]914/** Forward a received call to another destination - fast version.
915 *
[228e490]916 * In case the original interface and method is a system method, ARG1, ARG2
917 * and ARG3 are overwritten in the forwarded message with the new method and
918 * the new arg1 and arg2, respectively. Otherwise the IMETHOD, ARG1 and ARG2
919 * are rewritten with the new interface and method, arg1 and arg2, respectively.
920 * Also note there is a set of immutable methods, for which the new method and
921 * arguments are not set and these values are ignored.
[da1bafb]922 *
923 * @param callid Hash of the call to forward.
924 * @param phoneid Phone handle to use for forwarding.
[228e490]925 * @param imethod New interface and method to use for the forwarded call.
[da1bafb]926 * @param arg1 New value of the first argument for the forwarded call.
927 * @param arg2 New value of the second argument for the forwarded call.
928 * @param mode Flags that specify mode of the forward operation.
929 *
930 * @return 0 on succes, otherwise an error code.
931 *
[48daf64]932 */
[96b02eb9]933sysarg_t sys_ipc_forward_fast(sysarg_t callid, sysarg_t phoneid,
[228e490]934 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
[48daf64]935{
[228e490]936 return sys_ipc_forward_common(callid, phoneid, imethod, arg1, arg2, 0, 0,
[48daf64]937 0, mode, false);
938}
939
940/** Forward a received call to another destination - slow version.
941 *
942 * This function is the slow verision of the sys_ipc_forward_fast interface.
[228e490]943 * It can copy all five new arguments and the new interface and method from
944 * the userspace. It naturally extends the functionality of the fast version.
945 * For system methods, it additionally stores the new value of arg3 to ARG4.
946 * For non-system methods, it additionally stores the new value of arg3, arg4
947 * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
[da1bafb]948 *
949 * @param callid Hash of the call to forward.
950 * @param phoneid Phone handle to use for forwarding.
951 * @param data Userspace address of the new IPC data.
952 * @param mode Flags that specify mode of the forward operation.
953 *
954 * @return 0 on succes, otherwise an error code.
955 *
[48daf64]956 */
[96b02eb9]957sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t phoneid,
[da1bafb]958 ipc_data_t *data, unsigned int mode)
[48daf64]959{
960 ipc_data_t newdata;
[da1bafb]961 int rc = copy_from_uspace(&newdata.args, &data->args,
[48daf64]962 sizeof(newdata.args));
[da1bafb]963 if (rc != 0)
[96b02eb9]964 return (sysarg_t) rc;
[da1bafb]965
[48daf64]966 return sys_ipc_forward_common(callid, phoneid,
[228e490]967 IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
[48daf64]968 IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
969 IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
970}
971
[8b243f2]972/** Answer an IPC call - fast version.
973 *
974 * This function can handle only two return arguments of payload, but is faster
975 * than the generic sys_ipc_answer().
976 *
[da1bafb]977 * @param callid Hash of the call to be answered.
978 * @param retval Return value of the answer.
979 * @param arg1 Service-defined return value.
980 * @param arg2 Service-defined return value.
981 * @param arg3 Service-defined return value.
982 * @param arg4 Service-defined return value.
983 *
984 * @return 0 on success, otherwise an error code.
[8b243f2]985 *
986 */
[96b02eb9]987sysarg_t sys_ipc_answer_fast(sysarg_t callid, sysarg_t retval,
988 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
[2d5a54f3]989{
[897f2e76]990 /* Do not answer notification callids */
991 if (callid & IPC_CALLID_NOTIFICATION)
992 return 0;
[da1bafb]993
994 call_t *call = get_call(callid);
[2ba7810]995 if (!call)
996 return ENOENT;
[da1bafb]997
998 ipc_data_t saved_data;
999 bool saved;
1000
[9f22213]1001 if (answer_need_old(call)) {
[2ba7810]1002 memcpy(&saved_data, &call->data, sizeof(call->data));
[da1bafb]1003 saved = true;
1004 } else
1005 saved = false;
1006
[2d5a54f3]1007 IPC_SET_RETVAL(call->data, retval);
1008 IPC_SET_ARG1(call->data, arg1);
1009 IPC_SET_ARG2(call->data, arg2);
[b74959bd]1010 IPC_SET_ARG3(call->data, arg3);
1011 IPC_SET_ARG4(call->data, arg4);
[da1bafb]1012
[8498915]1013 /*
1014 * To achieve deterministic behavior, zero out arguments that are beyond
1015 * the limits of the fast version.
1016 */
1017 IPC_SET_ARG5(call->data, 0);
[da1bafb]1018 int rc = answer_preprocess(call, saved ? &saved_data : NULL);
1019
[2d5a54f3]1020 ipc_answer(&TASK->answerbox, call);
[7c23af9]1021 return rc;
[2d5a54f3]1022}
1023
[8b243f2]1024/** Answer an IPC call.
1025 *
[da1bafb]1026 * @param callid Hash of the call to be answered.
1027 * @param data Userspace address of call data with the answer.
1028 *
1029 * @return 0 on success, otherwise an error code.
[8b243f2]1030 *
1031 */
[96b02eb9]1032sysarg_t sys_ipc_answer_slow(sysarg_t callid, ipc_data_t *data)
[2d5a54f3]1033{
[897f2e76]1034 /* Do not answer notification callids */
1035 if (callid & IPC_CALLID_NOTIFICATION)
1036 return 0;
[da1bafb]1037
1038 call_t *call = get_call(callid);
[2ba7810]1039 if (!call)
1040 return ENOENT;
[da1bafb]1041
1042 ipc_data_t saved_data;
1043 bool saved;
1044
[9f22213]1045 if (answer_need_old(call)) {
[2ba7810]1046 memcpy(&saved_data, &call->data, sizeof(call->data));
[da1bafb]1047 saved = true;
1048 } else
1049 saved = false;
1050
1051 int rc = copy_from_uspace(&call->data.args, &data->args,
[51ec40f]1052 sizeof(call->data.args));
[e3c762cd]1053 if (rc != 0)
1054 return rc;
[da1bafb]1055
1056 rc = answer_preprocess(call, saved ? &saved_data : NULL);
[2d5a54f3]1057
1058 ipc_answer(&TASK->answerbox, call);
[7c23af9]1059 return rc;
[2d5a54f3]1060}
1061
[8b243f2]1062/** Hang up a phone.
[2d5a54f3]1063 *
[da1bafb]1064 * @param Phone handle of the phone to be hung up.
1065 *
1066 * @return 0 on success or an error code.
[8b243f2]1067 *
[fbcfd458]1068 */
[96b02eb9]1069sysarg_t sys_ipc_hangup(sysarg_t phoneid)
[fbcfd458]1070{
1071 phone_t *phone;
[da1bafb]1072
[c9fff17]1073 if (phone_get(phoneid, &phone) != EOK)
1074 return ENOENT;
[da1bafb]1075
[d8f7362]1076 if (ipc_phone_hangup(phone))
[fbcfd458]1077 return -1;
[da1bafb]1078
[fbcfd458]1079 return 0;
1080}
1081
[8b243f2]1082/** Wait for an incoming IPC call or an answer.
[fbcfd458]1083 *
[da1bafb]1084 * @param calldata Pointer to buffer where the call/answer data is stored.
1085 * @param usec Timeout. See waitq_sleep_timeout() for explanation.
1086 * @param flags Select mode of sleep operation. See waitq_sleep_timeout()
1087 * for explanation.
1088 *
1089 * @return Hash of the call.
1090 * If IPC_CALLID_NOTIFICATION bit is set in the hash, the
1091 * call is a notification. IPC_CALLID_ANSWERED denotes an
1092 * answer.
[bd5a663]1093 *
[2d5a54f3]1094 */
[96b02eb9]1095sysarg_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
[da1bafb]1096 unsigned int flags)
[2d5a54f3]1097{
1098 call_t *call;
[da1bafb]1099
[741fd16]1100restart:
[da1bafb]1101
[741fd16]1102#ifdef CONFIG_UDEBUG
1103 udebug_stoppable_begin();
[da1bafb]1104#endif
1105
[51ec40f]1106 call = ipc_wait_for_call(&TASK->answerbox, usec,
1107 flags | SYNCH_FLAGS_INTERRUPTIBLE);
[da1bafb]1108
[741fd16]1109#ifdef CONFIG_UDEBUG
1110 udebug_stoppable_end();
1111#endif
[da1bafb]1112
[9f22213]1113 if (!call)
1114 return 0;
[da1bafb]1115
[5626277]1116 if (call->flags & IPC_CALL_NOTIF) {
[43752b6]1117 /* Set in_phone_hash to the interrupt counter */
[0c1a5d8a]1118 call->data.phone = (void *) call->priv;
[43752b6]1119
1120 STRUCT_TO_USPACE(calldata, &call->data);
[da1bafb]1121
[5626277]1122 ipc_call_free(call);
1123
[96b02eb9]1124 return ((sysarg_t) call) | IPC_CALLID_NOTIFICATION;
[5626277]1125 }
[da1bafb]1126
[2d5a54f3]1127 if (call->flags & IPC_CALL_ANSWERED) {
[7c7aae16]1128 process_answer(call);
[da1bafb]1129
[fbcfd458]1130 if (call->flags & IPC_CALL_DISCARD_ANSWER) {
1131 ipc_call_free(call);
1132 goto restart;
1133 }
[da1bafb]1134
[fbcfd458]1135 STRUCT_TO_USPACE(&calldata->args, &call->data.args);
[2d5a54f3]1136 ipc_call_free(call);
[da1bafb]1137
[96b02eb9]1138 return ((sysarg_t) call) | IPC_CALLID_ANSWERED;
[2d5a54f3]1139 }
[da1bafb]1140
[2d5a54f3]1141 if (process_request(&TASK->answerbox, call))
1142 goto restart;
[da1bafb]1143
[7c7aae16]1144 /* Include phone address('id') of the caller in the request,
1145 * copy whole call->data, not only call->data.args */
[bd55bbb]1146 if (STRUCT_TO_USPACE(calldata, &call->data)) {
[e06da7e]1147 /*
1148 * The callee will not receive this call and no one else has
1149 * a chance to answer it. Reply with the EPARTY error code.
[b11ee88]1150 */
[e06da7e]1151 ipc_data_t saved_data;
[da1bafb]1152 bool saved;
1153
[e06da7e]1154 if (answer_need_old(call)) {
1155 memcpy(&saved_data, &call->data, sizeof(call->data));
[da1bafb]1156 saved = true;
1157 } else
1158 saved = false;
[e06da7e]1159
1160 IPC_SET_RETVAL(call->data, EPARTY);
[da1bafb]1161 (void) answer_preprocess(call, saved ? &saved_data : NULL);
[e06da7e]1162 ipc_answer(&TASK->answerbox, call);
[bd55bbb]1163 return 0;
1164 }
[da1bafb]1165
[96b02eb9]1166 return (sysarg_t) call;
[2d5a54f3]1167}
[5626277]1168
[da1bafb]1169/** Interrupt one thread from sys_ipc_wait_for_call().
1170 *
1171 */
[96b02eb9]1172sysarg_t sys_ipc_poke(void)
[057d21a]1173{
[da1bafb]1174 waitq_unsleep(&TASK->answerbox.wq);
[057d21a]1175 return EOK;
1176}
1177
[8b243f2]1178/** Connect an IRQ handler to a task.
[2b017ba]1179 *
[228e490]1180 * @param inr IRQ number.
1181 * @param devno Device number.
1182 * @param imethod Interface and method to be associated with the notification.
1183 * @param ucode Uspace pointer to the top-half pseudocode.
[da1bafb]1184 *
1185 * @return EPERM or a return code returned by ipc_irq_register().
[2b017ba]1186 *
1187 */
[8add9ca5]1188sysarg_t sys_register_irq(inr_t inr, devno_t devno, sysarg_t imethod,
[51ec40f]1189 irq_code_t *ucode)
[5626277]1190{
[2bb8648]1191 if (!(cap_get(TASK) & CAP_IRQ_REG))
1192 return EPERM;
[da1bafb]1193
[228e490]1194 return ipc_irq_register(&TASK->answerbox, inr, devno, imethod, ucode);
[5626277]1195}
1196
[8b243f2]1197/** Disconnect an IRQ handler from a task.
1198 *
[da1bafb]1199 * @param inr IRQ number.
1200 * @param devno Device number.
1201 *
1202 * @return Zero on success or EPERM on error.
[2b017ba]1203 *
1204 */
[8add9ca5]1205sysarg_t sys_unregister_irq(inr_t inr, devno_t devno)
[5626277]1206{
[2bb8648]1207 if (!(cap_get(TASK) & CAP_IRQ_REG))
1208 return EPERM;
[da1bafb]1209
[2b017ba]1210 ipc_irq_unregister(&TASK->answerbox, inr, devno);
[da1bafb]1211
[5626277]1212 return 0;
1213}
[b45c443]1214
[6b10dab]1215#ifdef __32_BITS__
[9a1b20c]1216
[6b10dab]1217/** Syscall connect to a task by ID (32 bits)
[da1bafb]1218 *
1219 * @return Phone id on success, or negative error code.
[9a1b20c]1220 *
1221 */
[6b10dab]1222sysarg_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid)
[9a1b20c]1223{
1224#ifdef CONFIG_UDEBUG
[6b10dab]1225 sysarg64_t taskid;
1226 int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t));
[9a1b20c]1227 if (rc != 0)
[96b02eb9]1228 return (sysarg_t) rc;
[da1bafb]1229
[6b10dab]1230 return ipc_connect_kbox((task_id_t) taskid);
[9a1b20c]1231#else
[96b02eb9]1232 return (sysarg_t) ENOTSUP;
[9a1b20c]1233#endif
1234}
1235
[6b10dab]1236#endif /* __32_BITS__ */
1237
1238#ifdef __64_BITS__
1239
1240/** Syscall connect to a task by ID (64 bits)
1241 *
1242 * @return Phone id on success, or negative error code.
1243 *
1244 */
1245sysarg_t sys_ipc_connect_kbox(sysarg_t taskid)
1246{
1247#ifdef CONFIG_UDEBUG
1248 return ipc_connect_kbox((task_id_t) taskid);
1249#else
1250 return (sysarg_t) ENOTSUP;
1251#endif
1252}
1253
1254#endif /* __64_BITS__ */
1255
[cc73a8a1]1256/** @}
[b45c443]1257 */
Note: See TracBrowser for help on using the repository browser.