Esempio n. 1
0
/** Handle data requests.
 *
 * @param fun  ddf_fun_t function.
 * @param id   callid
 * @param call IPC request.
 *
 */
void default_handler(ddf_fun_t *fun, ipc_callid_t id, ipc_call_t *call)
{
    const sysarg_t method = IPC_GET_IMETHOD(*call);
    const size_t size = IPC_GET_ARG1(*call);

    switch (method) {
    case IPC_CHAR_READ:
        if (size <= 4 * sizeof(sysarg_t)) {
            sysarg_t message[4] = {};

            i8042_read(fun, (char *) message, size);
            async_answer_4(id, size, message[0], message[1],
                           message[2], message[3]);
        } else
            async_answer_0(id, ELIMIT);
        break;

    case IPC_CHAR_WRITE:
        if (size <= 3 * sizeof(sysarg_t)) {
            const sysarg_t message[3] = {
                IPC_GET_ARG2(*call),
                IPC_GET_ARG3(*call),
                IPC_GET_ARG4(*call)
            };

            i8042_write(fun, (char *) message, size);
            async_answer_0(id, size);
        } else
            async_answer_0(id, ELIMIT);

    default:
        async_answer_0(id, EINVAL);
    }
}
Esempio n. 2
0
static void notification_received(ipc_callid_t callid, ipc_call_t *call)
{
	switch (IPC_GET_IMETHOD(*call)) {
	case VFS_TASK_STATE_CHANGE:
		if (IPC_GET_ARG1(*call) == VFS_PASS_HANDLE)
			vfs_pass_handle(
			    (task_id_t) MERGE_LOUP32(IPC_GET_ARG4(*call),
			    IPC_GET_ARG5(*call)), call->in_task_id,
			    (int) IPC_GET_ARG2(*call));
		break;
	default:
		break;
	}
}
Esempio n. 3
0
/** Forward a received call to another destination - slow version.
 *
 * This function is the slow verision of the sys_ipc_forward_fast interface.
 * It can copy all five new arguments and the new interface and 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.
 *
 * @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 0 on succes, otherwise an error code.
 *
 */
sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t phoneid,
    ipc_data_t *data, unsigned int mode)
{
	ipc_data_t newdata;
	int rc = copy_from_uspace(&newdata.args, &data->args,
	    sizeof(newdata.args));
	if (rc != 0)
		return (sysarg_t) rc;
	
	return sys_ipc_forward_common(callid, phoneid,
	    IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
	    IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
	    IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true); 
}
Esempio n. 4
0
		
#ifdef __32_BITS__
		printf("%10p ", call);
#endif
		
#ifdef __64_BITS__
		printf("%18p ", call);
#endif
		
		spinlock_lock(&call->forget_lock);

		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
		    " %-6" PRIun " %-6" PRIun " %-7x",
		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
		    call->flags);

		if (call->forget) {
			printf(" ? (call forgotten)\n");
		} else {
			printf(" %" PRIu64 " (%s)\n",
			    call->sender->taskid, call->sender->name);
		}

		spinlock_unlock(&call->forget_lock);
	}
}

/** List answerbox contents.
 *
Esempio n. 5
0
/**
 * Server side implementation of the hound protocol. IPC connection handler.
 * @param iid initial call id
 * @param icall pointer to initial call structure.
 * @param arg (unused)
 */
void hound_connection_handler(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	/* Accept connection if there is a valid iface*/
	if (server_iface) {
		async_answer_0(iid, EOK);
	} else {
		async_answer_0(iid, ENOTSUP);
		return;
	}

	while (1) {
		ipc_call_t call;
		ipc_callid_t callid = async_get_call(&call);
		switch (IPC_GET_IMETHOD(call)) {
		case IPC_M_HOUND_CONTEXT_REGISTER: {
			/* check interface functions */
			if (!server_iface || !server_iface->add_context) {
				async_answer_0(callid, ENOTSUP);
				break;
			}
			bool record = IPC_GET_ARG1(call);
			void *name;

			/* Get context name */
			int ret =
			    async_data_write_accept(&name, true, 0, 0, 0, 0);
			if (ret != EOK) {
				async_answer_0(callid, ret);
				break;
			}
			hound_context_id_t id = 0;
			ret = server_iface->add_context(server_iface->server,
			    &id, name, record);
			/** new context should create a copy */
			free(name);
			if (ret != EOK) {
				async_answer_0(callid, ret);
			} else {
				async_answer_1(callid, EOK, id);
			}
			break;
		}
		case IPC_M_HOUND_CONTEXT_UNREGISTER: {
			/* check interface functions */
			if (!server_iface || !server_iface->rem_context) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			/* get id, 1st param */
			hound_context_id_t id = IPC_GET_ARG1(call);
			const int ret =
			    server_iface->rem_context(server_iface->server, id);
			async_answer_0(callid, ret);
			break;
		}
		case IPC_M_HOUND_GET_LIST: {
			/* check interface functions */
			if (!server_iface || !server_iface->get_list) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			const char **list = NULL;
			const int flags = IPC_GET_ARG1(call);
			size_t count = IPC_GET_ARG2(call);
			const bool conn = IPC_GET_ARG3(call);
			char *conn_name = NULL;
			int ret = EOK;

			/* get connected actor name if provided */
			if (conn)
				ret = async_data_write_accept(
				    (void**)&conn_name, true, 0, 0, 0, 0);

			if (ret == EOK)
				ret = server_iface->get_list(
				    server_iface->server, &list, &count,
				    conn_name, flags);
			free(conn_name);

			/* Alloc string sizes array */
			size_t *sizes = NULL;
			if (count)
				sizes = calloc(count, sizeof(size_t));
			if (count && !sizes)
				ret = ENOMEM;
			async_answer_1(callid, ret, count);

			/* We are done */
			if (count == 0 || ret != EOK)
				break;

			/* Prepare sizes table */
			for (unsigned i = 0; i < count; ++i)
				sizes[i] = str_size(list[i]);

			/* Send sizes table */
			ipc_callid_t id;
			if (async_data_read_receive(&id, NULL)) {
				ret = async_data_read_finalize(id, sizes,
				    count * sizeof(size_t));
			}
			free(sizes);

			/* Proceed to send names */
			for (unsigned i = 0; i < count; ++i) {
				size_t size = str_size(list[i]);
				ipc_callid_t id;
				if (ret == EOK &&
				    async_data_read_receive(&id, NULL)) {
					ret = async_data_read_finalize(id,
					    list[i], size);
				}
				free(list[i]);
			}
			free(list);
			break;
		}
		case IPC_M_HOUND_CONNECT: {
			/* check interface functions */
			if (!server_iface || !server_iface->connect) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			void *source = NULL;
			void *sink = NULL;

			/* read source name */
			int ret =
			    async_data_write_accept(&source, true, 0, 0, 0, 0);
			/* read sink name */
			if (ret == EOK)
				ret = async_data_write_accept(&sink,
				    true, 0, 0, 0, 0);

			if (ret == EOK)
				ret = server_iface->connect(
				    server_iface->server, source, sink);
			free(source);
			free(sink);
			async_answer_0(callid, ret);
			break;
		}
		case IPC_M_HOUND_DISCONNECT: {
			/* check interface functions */
			if (!server_iface || !server_iface->disconnect) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			void *source = NULL;
			void *sink = NULL;

			/* read source name */
			int ret =
			    async_data_write_accept(&source, true, 0, 0, 0, 0);
			/*read sink name */
			if (ret == EOK)
				ret = async_data_write_accept(&sink,
				    true, 0, 0, 0, 0);
			if (ret == EOK)
				ret = server_iface->connect(
				    server_iface->server, source, sink);
			free(source);
			free(sink);
			async_answer_0(callid, ret);
			break;
		}
		case IPC_M_HOUND_STREAM_ENTER: {
			/* check interface functions */
			if (!server_iface || !server_iface->is_record_context
			    || !server_iface->add_stream
			    || !server_iface->rem_stream) {
				async_answer_0(callid, ENOTSUP);
				break;
			}

			/* get parameters */
			hound_context_id_t id = IPC_GET_ARG1(call);
			const int flags = IPC_GET_ARG2(call);
			const format_convert_t c = {.arg = IPC_GET_ARG3(call)};
			const pcm_format_t f = {
			    .sampling_rate = c.f.rate * 100,
			    .channels = c.f.channels,
			    .sample_format = c.f.format,
			};
			size_t bsize = IPC_GET_ARG4(call);

			void *stream;
			int ret = server_iface->add_stream(server_iface->server,
			    id, flags, f, bsize, &stream);
			if (ret != EOK) {
				async_answer_0(callid, ret);
				break;
			}
			const bool rec = server_iface->is_record_context(
			    server_iface->server, id);
			if (rec) {
				if(server_iface->stream_data_read) {
					async_answer_0(callid, EOK);
					/* start answering read calls */
					hound_server_write_data(stream);
					server_iface->rem_stream(
					    server_iface->server, stream);
				} else {
					async_answer_0(callid, ENOTSUP);
				}
			} else {
				if (server_iface->stream_data_write) {
					async_answer_0(callid, EOK);
					/* accept write calls */
					hound_server_read_data(stream);
					server_iface->rem_stream(
					    server_iface->server, stream);
				} else {
					async_answer_0(callid, ENOTSUP);
				}
			}
			break;
		}
		case IPC_M_HOUND_STREAM_EXIT:
		case IPC_M_HOUND_STREAM_DRAIN:
			/* Stream exit/drain is only allowed in stream context*/
			async_answer_0(callid, EINVAL);
			break;
		default:
			async_answer_0(callid, ENOTSUP);
			return;
		}
	}
}

/**
 * Read data and push it to the stream.
 * @param stream target stream, will push data there.
 */
static void hound_server_read_data(void *stream)
{
	ipc_callid_t callid;
	ipc_call_t call;
	size_t size = 0;
	int ret_answer = EOK;
	/* accept data write or drain */
	while (async_data_write_receive_call(&callid, &call, &size)
	    || (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN)) {
		/* check drain first */
		if (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN) {
			int ret = ENOTSUP;
			if (server_iface->drain_stream)
				ret = server_iface->drain_stream(stream);
			async_answer_0(callid, ret);
			continue;
		}

		/* there was an error last time */
		if (ret_answer != EOK) {
			async_answer_0(callid, ret_answer);
			continue;
		}

		char *buffer = malloc(size);
		if (!buffer) {
			async_answer_0(callid, ENOMEM);
			continue;
		}
		const int ret = async_data_write_finalize(callid, buffer, size);
		if (ret == EOK) {
			/* push data to stream */
			ret_answer = server_iface->stream_data_write(
			    stream, buffer, size);
		}
	}
	const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT
	    ? EOK : EINVAL;

	async_answer_0(callid, ret);
}
Esempio n. 6
0
/** Perform a path lookup.
 *
 * @param path    Path to be resolved; it must be a NULL-terminated
 *                string.
 * @param lflag   Flags to be used during lookup.
 * @param result  Empty structure where the lookup result will be stored.
 *                Can be NULL.
 * @param altroot If non-empty, will be used instead of rootfs as the root
 *                of the whole VFS tree.
 *
 * @return EOK on success or an error code from errno.h.
 *
 */
int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
    vfs_pair_t *altroot, ...)
{
	vfs_pair_t *root;

	if (altroot)
		root = altroot;
	else
		root = &rootfs;

	if (!root->fs_handle)
		return ENOENT;
	
	size_t len;
	path = canonify(path, &len);
	if (!path)
		return EINVAL;
	
	fs_index_t index = 0;
	if (lflag & L_LINK) {
		va_list ap;

		va_start(ap, altroot);
		index = va_arg(ap, fs_index_t);
		va_end(ap);
	}
	
	fibril_mutex_lock(&plb_mutex);

	plb_entry_t entry;
	link_initialize(&entry.plb_link);
	entry.len = len;

	size_t first;	/* the first free index */
	size_t last;	/* the last free index */

	if (list_empty(&plb_entries)) {
		first = 0;
		last = PLB_SIZE - 1;
	} else {
		plb_entry_t *oldest = list_get_instance(
		    list_first(&plb_entries), plb_entry_t, plb_link);
		plb_entry_t *newest = list_get_instance(
		    list_last(&plb_entries), plb_entry_t, plb_link);

		first = (newest->index + newest->len) % PLB_SIZE;
		last = (oldest->index - 1) % PLB_SIZE;
	}

	if (first <= last) {
		if ((last - first) + 1 < len) {
			/*
			 * The buffer cannot absorb the path.
			 */
			fibril_mutex_unlock(&plb_mutex);
			return ELIMIT;
		}
	} else {
		if (PLB_SIZE - ((first - last) + 1) < len) {
			/*
			 * The buffer cannot absorb the path.
			 */
			fibril_mutex_unlock(&plb_mutex);
			return ELIMIT;
		}
	}

	/*
	 * We know the first free index in PLB and we also know that there is
	 * enough space in the buffer to hold our path.
	 */

	entry.index = first;
	entry.len = len;

	/*
	 * Claim PLB space by inserting the entry into the PLB entry ring
	 * buffer.
	 */
	list_append(&entry.plb_link, &plb_entries);
	
	fibril_mutex_unlock(&plb_mutex);

	/*
	 * Copy the path into PLB.
	 */
	size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
	size_t cnt2 = len - cnt1;
	
	memcpy(&plb[first], path, cnt1);
	memcpy(plb, &path[cnt1], cnt2);

	ipc_call_t answer;
	async_exch_t *exch = vfs_exchange_grab(root->fs_handle);
	aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first,
	    (sysarg_t) (first + len - 1) % PLB_SIZE,
	    (sysarg_t) root->service_id, (sysarg_t) lflag, (sysarg_t) index,
	    &answer);
	
	sysarg_t rc;
	async_wait_for(req, &rc);
	vfs_exchange_release(exch);
	
	fibril_mutex_lock(&plb_mutex);
	list_remove(&entry.plb_link);
	/*
	 * Erasing the path from PLB will come handy for debugging purposes.
	 */
	memset(&plb[first], 0, cnt1);
	memset(plb, 0, cnt2);
	fibril_mutex_unlock(&plb_mutex);
	
	if ((int) rc < EOK)
		return (int) rc;

	if (!result)
		return EOK;
	
	result->triplet.fs_handle = (fs_handle_t) rc;
	result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
	result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
	result->size =
	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
	result->lnkcnt = (unsigned int) IPC_GET_ARG5(answer);
	
	if (lflag & L_FILE)
		result->type = VFS_NODE_FILE;
	else if (lflag & L_DIRECTORY)
		result->type = VFS_NODE_DIRECTORY;
	else
		result->type = VFS_NODE_UNKNOWN;
	
	return EOK;
}