int connection_process(struct connection *conn, struct sk_buff *skb)
{
	int ret = 0;
	do {
		if (mutex_lock_interruptible(&(conn->data_lock))) {
			MCDRV_DBG_ERROR("Interrupted getting data semaphore!");
			ret = -1;
			break;
		}

		kfree_skb(conn->skb);

		/* Get a reference to the incomming skb */
		conn->skb = skb_get(skb);
		if (conn->skb) {
			conn->data_msg = nlmsg_hdr(conn->skb);
			conn->data_len = NLMSG_PAYLOAD(conn->data_msg, 0);
			conn->data_start = NLMSG_DATA(conn->data_msg);
			up(&(conn->data_available_sem));
		}
		mutex_unlock(&(conn->data_lock));
		ret = 0;
	} while (0);
	return ret;
}
static int log_worker(void *p)
{
	/* The thread should have never started */
	if (log_buf == NULL)
		return -EFAULT;

	while (!kthread_should_stop()) {
		if (log_buf->write_pos == log_pos)
			schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);

		switch (log_buf->version) {
		case 1:
			log_pos = process_v1log();
			break;
		case 2:
			log_pos = process_v2log();
			break;
		default:
			MCDRV_DBG_ERROR("Unknown Mobicore log data "
				"version %d logging disabled.",
				log_buf->version);
			log_pos = log_buf->write_pos;
			/* Stop the thread as we have no idea what
			 * happens next */
			return -EFAULT;
		}
	}
	MCDRV_DBG("Logging thread stopped!");
	return 0;
}
struct connection *connection_new(void)
{
	struct connection *conn;

	conn = kzalloc(sizeof(*conn), GFP_KERNEL);
	if (conn == NULL) {
		MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
		return NULL;
	}
	conn->sequence_magic = mcapi_unique_id();
	mutex_init(&conn->data_lock);
	sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);

	mcapi_insert_connection(conn);
	return conn;
}
static int mc_suspend_notifier(struct notifier_block *nb,
	unsigned long event, void *dummy)
{
	struct mc_mcp_buffer *mcp = ctx->mcp;
	/* We have noting to say if MobiCore is not initialized */
	if (!mcp)
		return 0;

#ifdef MC_MEM_TRACES
	mobicore_log_read();
#endif

	switch (event) {
	case PM_SUSPEND_PREPARE:
		/*
		 * Make sure we have finished all the work otherwise
		 * we end up in a race condition
		 */
		cancel_work_sync(&suspend_work);
		/*
		 * We can't go to sleep if MobiCore is not IDLE
		 * or not Ready to sleep
		 */
		dump_sleep_params(&mcp->flags);
		if (!sleep_ready()) {
			ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP;
			schedule_work_on(0, &suspend_work);
			flush_work(&suspend_work);
			if (!sleep_ready()) {
				dump_sleep_params(&mcp->flags);
				ctx->mcp->flags.sleep_mode.sleep_req = 0;
				MCDRV_DBG_ERROR(mcd, "MobiCore can't SLEEP!");
				return NOTIFY_BAD;
			}
		}
		break;
	case PM_POST_SUSPEND:
		MCDRV_DBG(mcd, "Resume MobiCore system!");
		ctx->mcp->flags.sleep_mode.sleep_req = 0;
		break;
	default:
		break;
	}
	return 0;
}
Beispiel #5
0
size_t connection_read_data(struct connection *conn, void *buffer, uint32_t len,
			    int32_t timeout)
{
	size_t ret = 0;

	MCDRV_ASSERT(buffer != NULL);
	MCDRV_ASSERT(conn->socket_descriptor != NULL);

	MCDRV_DBG_VERBOSE(mc_kapi, "read data len = %u for PID = %u",
			  len, conn->sequence_magic);
	do {
		/*
		 * Wait until data is available or timeout
		 * msecs_to_jiffies(-1) -> wait forever for the sem
		 */
		if (down_timeout(&(conn->data_available_sem),
				 msecs_to_jiffies(timeout))) {
			MCDRV_DBG_VERBOSE(mc_kapi,
					  "Timeout reading the data sem");
			ret = -2;
			break;
		}

		if (mutex_lock_interruptible(&(conn->data_lock))) {
			MCDRV_DBG_ERROR(mc_kapi,
					"interrupted reading the data sem");
			ret = -1;
			break;
		}

		/* Have data, use it */
		if (conn->data_len > 0)
			ret = connection_read_data_msg(conn, buffer, len);

		mutex_unlock(&(conn->data_lock));

		/* There is still some data left */
		if (conn->data_len > 0)
			up(&conn->data_available_sem);

	} while (0);

	return ret;
}
/* log_worker() - Worker thread processing the log_buf buffer. */
static int log_worker(void *p)
{
	int ret = 0;
	if (log_buf == NULL) {
		ret = -EFAULT;
		goto err_kthread;
	}

	while (!kthread_should_stop()) {
		if (log_buf->write_pos == log_pos)
			schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);

		switch (log_buf->version) {
		case 2:
			log_pos = process_log();
			break;
		default:
			MCDRV_DBG_ERROR(mcd, "Unknown Mobicore log data");
			log_pos = log_buf->write_pos;
			/*
			 * Stop the thread as we have no idea what
			 * happens next
			 */
			ret = -EFAULT;
			goto err_kthread;
		}
	}
err_kthread:
	MCDRV_DBG(mcd, "Logging thread stopped!");
	thread_err = ret;
	/*
	 * Wait until the next kthread_stop() is called, if it was already
	 * called we just slip through, if there is an error signal it and
	 * wait to get the signal
	 */
	set_current_state(TASK_INTERRUPTIBLE);
	while (!kthread_should_stop()) {
		schedule();
		set_current_state(TASK_INTERRUPTIBLE);
	}
	set_current_state(TASK_RUNNING);
	return ret;
}
/**
 * Setup mobicore kernel log. It assumes it's running on CORE 0!
 * The fastcall will complain is that is not the case!
 */
long mobicore_log_setup(void *data)
{
	unsigned long phys_log_buf;
	union fc_generic fc_log;

	long ret;
	log_pos = 0;
	log_buf = NULL;
	log_thread = NULL;
	log_line = NULL;
	log_line_len = 0;

	/* Sanity check for the log size */
	if (log_size < PAGE_SIZE)
		return -EFAULT;
	else
		log_size = PAGE_ALIGN(log_size);

	log_line = kzalloc(LOG_LINE_SIZE, GFP_KERNEL);
	if (IS_ERR(log_line)) {
		MCDRV_DBG_ERROR("failed to allocate log line!");
		return -ENOMEM;
	}

	log_thread = kthread_create(log_worker, NULL, "mobicore_log");
	if (IS_ERR(log_thread)) {
		MCDRV_DBG_ERROR("mobicore log thread creation failed!");
		ret = -EFAULT;
		goto mobicore_log_setup_log_line;
	}

	/* We are going to map this buffer into virtual address space in SWd.
	 * To reduce complexity there, we use a contiguous buffer. */
	log_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
					get_order(log_size));
	if (!log_buf) {
		MCDRV_DBG_ERROR("Failed to get page for logger!");
		ret = -ENOMEM;
		goto mobicore_log_setup_kthread;
	}
	phys_log_buf = virt_to_phys(log_buf);

	memset(&fc_log, 0, sizeof(fc_log));
	fc_log.as_in.cmd      = MC_FC_NWD_TRACE;
	fc_log.as_in.param[0] = phys_log_buf;
	fc_log.as_in.param[1] = log_size;

	MCDRV_DBG("fc_log virt=%p phys=%p ", log_buf, (void *)phys_log_buf);
	mc_fastcall(&fc_log);
	MCDRV_DBG("fc_log out ret=0x%08x", fc_log.as_out.ret);
	/* If the setup failed we must free the memory allocated */
	if (fc_log.as_out.ret) {
		MCDRV_DBG_ERROR("MobiCore shared traces setup failed!");
		free_pages((unsigned long)log_buf, get_order(log_size));
		log_buf = NULL;
		ret = -EIO;
		goto mobicore_log_setup_kthread;
	}

	MCDRV_DBG("fc_log Logger version %u\n", log_buf->version);
	return 0;

mobicore_log_setup_kthread:
	kthread_stop(log_thread);
	log_thread = NULL;
mobicore_log_setup_log_line:
	kfree(log_line);
	log_line = NULL;
	return ret;
}
Beispiel #8
0
/*
 * Setup MobiCore kernel log. It assumes it's running on CORE 0!
 * The fastcall will complain is that is not the case!
 */
long mobicore_log_setup(void)
{
	unsigned long phys_log_buf;
	union fc_generic fc_log;
	struct sched_param param = { .sched_priority = 1 };

	long ret;
	log_pos = 0;
	log_buf = NULL;
	log_thread = NULL;
	log_line = NULL;
	log_line_len = 0;

	/* Sanity check for the log size */
	if (log_size < PAGE_SIZE)
		return -EFAULT;
	else
		log_size = PAGE_ALIGN(log_size);

	log_line = kzalloc(LOG_LINE_SIZE, GFP_KERNEL);
	if (IS_ERR(log_line)) {
		MCDRV_DBG_ERROR(mcd, "failed to allocate log line!");
		return -ENOMEM;
	}

	log_thread = kthread_create(log_worker, NULL, "mobicore_log");
	if (IS_ERR(log_thread)) {
		MCDRV_DBG_ERROR(mcd, "MobiCore log thread creation failed!");
		ret = -EFAULT;
		goto mobicore_log_setup_log_line;
	}

	sched_setscheduler(log_thread, SCHED_IDLE, &param);
	/*
	 * We are going to map this buffer into virtual address space in SWd.
	 * To reduce complexity there, we use a contiguous buffer.
	 */
	log_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
					   get_order(log_size));
	if (!log_buf) {
		MCDRV_DBG_ERROR(mcd, "Failed to get page for logger!");
		ret = -ENOMEM;
		goto mobicore_log_setup_kthread;
	}
	phys_log_buf = virt_to_phys(log_buf);

	memset(&fc_log, 0, sizeof(fc_log));
	fc_log.as_in.cmd = MC_FC_NWD_TRACE;
	fc_log.as_in.param[0] = phys_log_buf;
	fc_log.as_in.param[1] = log_size;

	MCDRV_DBG(mcd, "fc_log virt=%p phys=%p ",
		  log_buf, (void *)phys_log_buf);
	mc_fastcall(&fc_log);
	MCDRV_DBG(mcd, "fc_log out ret=0x%08x", fc_log.as_out.ret);

	/* If the setup failed we must free the memory allocated */
	if (fc_log.as_out.ret) {
		MCDRV_DBG_ERROR(mcd, "MobiCore shared traces setup failed!");
		free_pages((unsigned long)log_buf, get_order(log_size));
		log_buf = NULL;
		ret = -EIO;
		goto mobicore_log_setup_kthread;
	}

	MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version);
	return 0;

mobicore_log_setup_kthread:
	kthread_stop(log_thread);
	log_thread = NULL;
mobicore_log_setup_log_line:
	kfree(log_line);
	log_line = NULL;
	return ret;
}

/*
 * Free kernel log components.
 * ATTN: We can't free the log buffer because it's also in use by MobiCore and
 * even if the module is unloaded MobiCore is still running.
 */
void mobicore_log_free(void)
{
	if (log_thread && !IS_ERR(log_thread)) {
		/* We don't really care what the thread returns for exit */
		kthread_stop(log_thread);
	}

	kfree(log_line);
}