/trunk/kernel/generic/include/ipc/ipc.h |
---|
279,7 → 279,7 |
/** Data passed from/to userspace. */ |
ipc_data_t data; |
/** Buffer for IPC_M_DATA_SEND. */ |
/** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */ |
uint8_t *buffer; |
} call_t; |
/trunk/kernel/generic/src/ipc/sysipc.c |
---|
235,19 → 235,54 |
IPC_GET_ARG2(answer->data)); |
IPC_SET_RETVAL(answer->data, rc); |
} |
} else if (IPC_GET_METHOD(*olddata) == IPC_M_DATA_READ) { |
ASSERT(!answer->buffer); |
if (!IPC_GET_RETVAL(answer->data)) { |
/* The recipient agreed to send data. */ |
uintptr_t src = IPC_GET_ARG1(answer->data); |
uintptr_t dst = IPC_GET_ARG1(*olddata); |
size_t max_size = IPC_GET_ARG2(*olddata); |
size_t size = IPC_GET_ARG2(answer->data); |
if (size <= max_size) { |
/* |
* Copy the destination VA so that this piece of |
* information is not lost. |
*/ |
IPC_SET_ARG1(answer->data, dst); |
answer->buffer = malloc(size, 0); |
int rc = copy_from_uspace(answer->buffer, |
(void *) src, size); |
if (rc) { |
IPC_SET_RETVAL(answer->data, rc); |
free(answer->buffer); |
answer->buffer = NULL; |
} |
} else { |
IPC_SET_RETVAL(answer->data, ELIMIT); |
} |
} |
} else if (IPC_GET_METHOD(*olddata) == IPC_M_DATA_WRITE) { |
ASSERT(answer->buffer); |
if (!IPC_GET_RETVAL(answer->data)) { |
/* The recipient agreed to receive data. */ |
int rc; |
uintptr_t dst; |
uintptr_t size; |
uintptr_t max_size; |
dst = IPC_GET_ARG1(answer->data); |
size = IPC_GET_ARG3(answer->data); |
max_size = IPC_GET_ARG3(*olddata); |
rc = copy_to_uspace((void *) dst, answer->buffer, size); |
if (rc != 0) |
IPC_SET_RETVAL(answer->data, rc); |
if (size <= max_size) { |
rc = copy_to_uspace((void *) dst, |
answer->buffer, size); |
if (rc) |
IPC_SET_RETVAL(answer->data, rc); |
} else { |
IPC_SET_RETVAL(answer->data, ELIMIT); |
} |
} |
free(answer->buffer); |
answer->buffer = NULL; |
284,6 → 319,11 |
return EPERM; |
IPC_SET_ARG2(call->data, size); |
break; |
case IPC_M_DATA_READ: |
size = IPC_GET_ARG2(call->data); |
if ((size <= 0 || (size > DATA_XFER_LIMIT))) |
return ELIMIT; |
break; |
case IPC_M_DATA_WRITE: |
src = IPC_GET_ARG2(call->data); |
size = IPC_GET_ARG3(call->data); |
324,6 → 364,17 |
else |
IPC_SET_ARG5(call->data, call->priv); |
} |
if (call->buffer) { |
/* This must be an affirmative answer to IPC_M_DATA_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); |
if (rc) |
IPC_SET_RETVAL(call->data, rc); |
free(call->buffer); |
call->buffer = NULL; |
} |
} |
/** Do basic kernel processing of received call request. |
/trunk/kernel/generic/src/ipc/ipc.c |
---|
414,6 → 414,8 |
while (!list_empty(lst)) { |
call = list_get_instance(lst->next, call_t, link); |
if (call->buffer) |
free(call->buffer); |
list_remove(&call->link); |
IPC_SET_RETVAL(call->data, EHANGUP); |
/trunk/uspace/lib/libc/include/ipc/ipc.h |
---|
260,11 → 260,15 |
extern int ipc_unregister_irq(int inr, int devno); |
extern int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, |
ipcarg_t arg1, ipcarg_t arg2, int mode); |
extern int ipc_data_read_send(int phoneid, void *dst, size_t size); |
extern int ipc_data_read_receive(ipc_callid_t *callid, size_t *size); |
extern int ipc_data_read_deliver(ipc_callid_t callid, void *src, size_t size); |
extern int ipc_data_write_send(int phoneid, void *src, size_t size); |
extern int ipc_data_write_receive(ipc_callid_t *callid, void **dst, |
size_t *size); |
extern ipcarg_t ipc_data_write_deliver(ipc_callid_t callid, void *dst, |
size_t size); |
extern int ipc_data_write_deliver(ipc_callid_t callid, void *dst, size_t size); |
#endif |
/trunk/uspace/lib/libc/generic/ipc.c |
---|
666,6 → 666,64 |
arg2, mode); |
} |
/** Wrapper for making IPC_M_DATA_READ calls. |
* |
* @param phoneid Phone that will be used to contact the receiving side. |
* @param dst Address of the beginning of the destination buffer. |
* @param size Size of the destination buffer. |
* |
* @return Zero on success or a negative error code from errno.h. |
*/ |
int ipc_data_read_send(int phoneid, void *dst, size_t size) |
{ |
return ipc_call_sync_2_0(phoneid, IPC_M_DATA_READ, (ipcarg_t) dst, |
(ipcarg_t) size); |
} |
/** Wrapper for receiving the IPC_M_DATA_READ calls. |
* |
* This wrapper only makes it more comfortable to receive IPC_M_DATA_READ calls |
* so that the user doesn't have to remember the meaning of each IPC argument. |
* |
* So far, this wrapper is to be used from within a connection fibril. |
* |
* @param callid Storage where the hash of the IPC_M_DATA_READ call will |
* be stored. |
* @param size Storage where the maximum size will be stored. |
* |
* @return Non-zero on success, zero on failure. |
*/ |
int ipc_data_read_receive(ipc_callid_t *callid, size_t *size) |
{ |
ipc_call_t data; |
assert(callid); |
*callid = async_get_call(&data); |
if (IPC_GET_METHOD(data) != IPC_M_DATA_READ) |
return 0; |
assert(size); |
*size = (size_t) IPC_GET_ARG2(data); |
return 1; |
} |
/** Wrapper for answering the IPC_M_DATA_READ calls. |
* |
* This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls |
* so that the user doesn't have to remember the meaning of each IPC argument. |
* |
* @param callid Hash of the IPC_M_DATA_READ call to answer. |
* @param src Source address for the IPC_M_DATA_READ call. |
* @param size Size for the IPC_M_DATA_READ call. Can be smaller than |
* the maximum size announced by the sender. |
* |
* @return Zero on success or a value from @ref errno.h on failure. |
*/ |
int ipc_data_read_deliver(ipc_callid_t callid, void *src, size_t size) |
{ |
return ipc_answer_2(callid, EOK, (ipcarg_t) src, (ipcarg_t) size); |
} |
/** Wrapper for making IPC_M_DATA_WRITE calls. |
* |
* @param phoneid Phone that will be used to contact the receiving side. |
723,7 → 781,7 |
* |
* @return Zero on success or a value from @ref errno.h on failure. |
*/ |
ipcarg_t ipc_data_write_deliver(ipc_callid_t callid, void *dst, size_t size) |
int ipc_data_write_deliver(ipc_callid_t callid, void *dst, size_t size) |
{ |
return ipc_answer_3(callid, EOK, (ipcarg_t) dst, 0, (ipcarg_t) size); |
} |