Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2661 → Rev 2662

/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);
}