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; }
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; }
/* * 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, ¶m); /* * 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); }