42,8 → 42,9 |
#include <ipc/sysipc.h> |
#include <ipc/irq.h> |
#include <ipc/ipcrsc.h> |
#include <ipc/kbox.h> |
#include <udebug/udebug_ipc.h> |
#include <arch/interrupt.h> |
#include <print.h> |
#include <syscall/copy.h> |
#include <security/cap.h> |
#include <mm/as.h> |
270,12 → 271,12 |
/* The recipient agreed to receive data. */ |
int rc; |
uintptr_t dst; |
uintptr_t size; |
uintptr_t max_size; |
size_t size; |
size_t max_size; |
|
dst = IPC_GET_ARG1(answer->data); |
size = IPC_GET_ARG2(answer->data); |
max_size = IPC_GET_ARG2(*olddata); |
dst = (uintptr_t)IPC_GET_ARG1(answer->data); |
size = (size_t)IPC_GET_ARG2(answer->data); |
max_size = (size_t)IPC_GET_ARG2(*olddata); |
|
if (size <= max_size) { |
rc = copy_to_uspace((void *) dst, |
295,10 → 296,11 |
/** Called before the request is sent. |
* |
* @param call Call structure with the request. |
* @param phone Phone that the call will be sent through. |
* |
* @return Return 0 on success, ELIMIT or EPERM on error. |
*/ |
static int request_preprocess(call_t *call) |
static int request_preprocess(call_t *call, phone_t *phone) |
{ |
int newphid; |
size_t size; |
340,6 → 342,10 |
return rc; |
} |
break; |
#ifdef CONFIG_UDEBUG |
case IPC_M_DEBUG_ALL: |
return udebug_request_preprocess(call, phone); |
#endif |
default: |
break; |
} |
369,6 → 375,7 |
|
if (call->buffer) { |
/* This must be an affirmative answer to IPC_M_DATA_READ. */ |
/* or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ... */ |
uintptr_t dst = IPC_GET_ARG1(call->data); |
size_t size = IPC_GET_ARG2(call->data); |
int rc = copy_to_uspace((void *) dst, call->buffer, size); |
399,7 → 406,13 |
return -1; |
} |
IPC_SET_ARG5(call->data, phoneid); |
} |
} |
switch (IPC_GET_METHOD(call->data)) { |
case IPC_M_DEBUG_ALL: |
return -1; |
default: |
break; |
} |
return 0; |
} |
|
426,7 → 439,7 |
phone_t *phone; |
int res; |
int rc; |
|
|
GET_CHECK_PHONE(phone, phoneid, return ENOENT); |
|
ipc_call_static_init(&call); |
441,9 → 454,18 |
IPC_SET_ARG4(call.data, 0); |
IPC_SET_ARG5(call.data, 0); |
|
if (!(res = request_preprocess(&call))) { |
ipc_call_sync(phone, &call); |
if (!(res = request_preprocess(&call, phone))) { |
#ifdef CONFIG_UDEBUG |
udebug_stoppable_begin(); |
#endif |
rc = ipc_call_sync(phone, &call); |
#ifdef CONFIG_UDEBUG |
udebug_stoppable_end(); |
#endif |
if (rc != EOK) |
return rc; |
process_answer(&call); |
|
} else { |
IPC_SET_RETVAL(call.data, res); |
} |
479,8 → 501,16 |
|
GET_CHECK_PHONE(phone, phoneid, return ENOENT); |
|
if (!(res = request_preprocess(&call))) { |
ipc_call_sync(phone, &call); |
if (!(res = request_preprocess(&call, phone))) { |
#ifdef CONFIG_UDEBUG |
udebug_stoppable_begin(); |
#endif |
rc = ipc_call_sync(phone, &call); |
#ifdef CONFIG_UDEBUG |
udebug_stoppable_end(); |
#endif |
if (rc != EOK) |
return rc; |
process_answer(&call); |
} else |
IPC_SET_RETVAL(call.data, res); |
546,7 → 576,7 |
*/ |
IPC_SET_ARG5(call->data, 0); |
|
if (!(res = request_preprocess(call))) |
if (!(res = request_preprocess(call, phone))) |
ipc_call(phone, call); |
else |
ipc_backsend_err(phone, call, res); |
580,7 → 610,7 |
ipc_call_free(call); |
return (unative_t) rc; |
} |
if (!(res = request_preprocess(call))) |
if (!(res = request_preprocess(call, phone))) |
ipc_call(phone, call); |
else |
ipc_backsend_err(phone, call, res); |
588,7 → 618,8 |
return (unative_t) call; |
} |
|
/** Forward a received call to another destination. |
/** Forward a received call to another destination - common code for both the |
* fast and the slow version. |
* |
* @param callid Hash of the call to forward. |
* @param phoneid Phone handle to use for forwarding. |
595,23 → 626,21 |
* @param method New method to use for the forwarded call. |
* @param arg1 New value of the first argument for the forwarded call. |
* @param arg2 New value of the second argument for the forwarded call. |
* @param arg3 New value of the third argument for the forwarded call. |
* @param arg4 New value of the fourth argument for the forwarded call. |
* @param arg5 New value of the fifth argument for the forwarded call. |
* @param mode Flags that specify mode of the forward operation. |
* @param slow If true, arg3, arg4 and arg5 are considered. Otherwise |
* the function considers only the fast version arguments: |
* i.e. arg1 and arg2. |
* |
* @return Return 0 on succes, otherwise return an error code. |
* |
* In case the original method is a system method, ARG1, ARG2 and ARG3 are |
* overwritten in the forwarded message with the new method and the new arg1 and |
* arg2, respectively. Otherwise the METHOD, ARG1 and ARG2 are rewritten with |
* the new method, arg1 and arg2, respectively. Also note there is a set of |
* immutable methods, for which the new method and argument is not set and |
* these values are ignored. |
* |
* Warning: When implementing support for changing additional payload |
* arguments, make sure that ARG5 is not rewritten for certain |
* system IPC |
* Warning: Make sure that ARG5 is not rewritten for certain system IPC |
*/ |
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid, |
unative_t method, unative_t arg1, unative_t arg2, int mode) |
static unative_t sys_ipc_forward_common(unative_t callid, unative_t phoneid, |
unative_t method, unative_t arg1, unative_t arg2, unative_t arg3, |
unative_t arg4, unative_t arg5, int mode, bool slow) |
{ |
call_t *call; |
phone_t *phone; |
619,7 → 648,7 |
call = get_call(callid); |
if (!call) |
return ENOENT; |
|
|
call->flags |= IPC_CALL_FORWARDED; |
|
GET_CHECK_PHONE(phone, phoneid, { |
626,7 → 655,7 |
IPC_SET_RETVAL(call->data, EFORWARD); |
ipc_answer(&TASK->answerbox, call); |
return ENOENT; |
}); |
}); |
|
if (!method_is_forwardable(IPC_GET_METHOD(call->data))) { |
IPC_SET_RETVAL(call->data, EFORWARD); |
636,8 → 665,8 |
|
/* |
* Userspace is not allowed to change method of system methods on |
* forward, allow changing ARG1, ARG2 and ARG3 by means of method, |
* arg1 and arg2. |
* forward, allow changing ARG1, ARG2, ARG3 and ARG4 by means of method, |
* arg1, arg2 and arg3. |
* If the method is immutable, don't change anything. |
*/ |
if (!method_is_immutable(IPC_GET_METHOD(call->data))) { |
648,10 → 677,22 |
IPC_SET_ARG1(call->data, method); |
IPC_SET_ARG2(call->data, arg1); |
IPC_SET_ARG3(call->data, arg2); |
if (slow) { |
IPC_SET_ARG4(call->data, arg3); |
/* |
* For system methods we deliberately don't |
* overwrite ARG5. |
*/ |
} |
} else { |
IPC_SET_METHOD(call->data, method); |
IPC_SET_ARG1(call->data, arg1); |
IPC_SET_ARG2(call->data, arg2); |
if (slow) { |
IPC_SET_ARG3(call->data, arg3); |
IPC_SET_ARG4(call->data, arg4); |
IPC_SET_ARG5(call->data, arg5); |
} |
} |
} |
|
658,6 → 699,64 |
return ipc_forward(call, phone, &TASK->answerbox, mode); |
} |
|
/** Forward a received call to another destination - fast version. |
* |
* @param callid Hash of the call to forward. |
* @param phoneid Phone handle to use for forwarding. |
* @param method New method to use for the forwarded call. |
* @param arg1 New value of the first argument for the forwarded call. |
* @param arg2 New value of the second argument for the forwarded call. |
* @param mode Flags that specify mode of the forward operation. |
* |
* @return Return 0 on succes, otherwise return an error code. |
* |
* In case the original method is a system method, ARG1, ARG2 and ARG3 are |
* overwritten in the forwarded message with the new method and the new |
* arg1 and arg2, respectively. Otherwise the METHOD, ARG1 and ARG2 are |
* rewritten with the new method, arg1 and arg2, respectively. Also note there |
* is a set of immutable methods, for which the new method and arguments are not |
* set and these values are ignored. |
*/ |
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid, |
unative_t method, unative_t arg1, unative_t arg2, int mode) |
{ |
return sys_ipc_forward_common(callid, phoneid, method, arg1, arg2, 0, 0, |
0, mode, false); |
} |
|
/** Forward a received call to another destination - slow version. |
* |
* @param callid Hash of the call to forward. |
* @param phoneid Phone handle to use for forwarding. |
* @param data Userspace address of the new IPC data. |
* @param mode Flags that specify mode of the forward operation. |
* |
* @return Return 0 on succes, otherwise return an error code. |
* |
* This function is the slow verision of the sys_ipc_forward_fast interface. |
* It can copy all five new arguments and the new method from the userspace. |
* It naturally extends the functionality of the fast version. For system |
* methods, it additionally stores the new value of arg3 to ARG4. For non-system |
* methods, it additionally stores the new value of arg3, arg4 and arg5, |
* respectively, to ARG3, ARG4 and ARG5, respectively. |
*/ |
unative_t sys_ipc_forward_slow(unative_t callid, unative_t phoneid, |
ipc_data_t *data, int mode) |
{ |
ipc_data_t newdata; |
int rc; |
|
rc = copy_from_uspace(&newdata.args, &data->args, |
sizeof(newdata.args)); |
if (rc != 0) |
return (unative_t) rc; |
|
return sys_ipc_forward_common(callid, phoneid, |
IPC_GET_METHOD(newdata), IPC_GET_ARG1(newdata), |
IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata), |
IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true); |
} |
|
/** Answer an IPC call - fast version. |
* |
* This function can handle only two return arguments of payload, but is faster |
781,9 → 880,17 |
{ |
call_t *call; |
|
restart: |
restart: |
|
#ifdef CONFIG_UDEBUG |
udebug_stoppable_begin(); |
#endif |
call = ipc_wait_for_call(&TASK->answerbox, usec, |
flags | SYNCH_FLAGS_INTERRUPTIBLE); |
|
#ifdef CONFIG_UDEBUG |
udebug_stoppable_end(); |
#endif |
if (!call) |
return 0; |
|
805,11 → 912,16 |
|
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC)); |
|
atomic_dec(&TASK->active_calls); |
|
if (call->flags & IPC_CALL_DISCARD_ANSWER) { |
ipc_call_free(call); |
goto restart; |
} else { |
/* |
* Decrement the counter of active calls only if the |
* call is not an answer to IPC_M_PHONE_HUNGUP, |
* which doesn't contribute to the counter. |
*/ |
atomic_dec(&TASK->active_calls); |
} |
|
STRUCT_TO_USPACE(&calldata->args, &call->data.args); |
824,6 → 936,21 |
/* Include phone address('id') of the caller in the request, |
* copy whole call->data, not only call->data.args */ |
if (STRUCT_TO_USPACE(calldata, &call->data)) { |
/* |
* The callee will not receive this call and no one else has |
* a chance to answer it. Reply with the EPARTY error code. |
*/ |
ipc_data_t saved_data; |
int saveddata = 0; |
|
if (answer_need_old(call)) { |
memcpy(&saved_data, &call->data, sizeof(call->data)); |
saveddata = 1; |
} |
|
IPC_SET_RETVAL(call->data, EPARTY); |
(void) answer_preprocess(call, saveddata ? &saved_data : NULL); |
ipc_answer(&TASK->answerbox, call); |
return 0; |
} |
return (unative_t)call; |
864,5 → 991,30 |
return 0; |
} |
|
#include <console/console.h> |
|
/** |
* Syscall connect to a task by id. |
* |
* @return Phone id on success, or negative error code. |
*/ |
unative_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid_arg) |
{ |
#ifdef CONFIG_UDEBUG |
sysarg64_t taskid_arg; |
int rc; |
|
rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t)); |
if (rc != 0) |
return (unative_t) rc; |
|
LOG("sys_ipc_connect_kbox(%" PRIu64 ")\n", taskid_arg.value); |
|
return ipc_connect_kbox(taskid_arg.value); |
#else |
return (unative_t) ENOTSUP; |
#endif |
} |
|
/** @} |
*/ |