/** Syscall for creating a new loader instance from userspace. * * Creates a new task from the program loader image and sets * the task name. * * @param uspace_name Name to set on the new task (typically the same * as the command used to execute it). * @param name_len Length of the name. * * @return EOK on success or an error code from @ref errno.h. * */ sysarg_t sys_program_spawn_loader(char *uspace_name, size_t name_len) { /* Cap length of name and copy it from userspace. */ if (name_len > TASK_NAME_BUFLEN - 1) name_len = TASK_NAME_BUFLEN - 1; char namebuf[TASK_NAME_BUFLEN]; int rc = copy_from_uspace(namebuf, uspace_name, name_len); if (rc != 0) return (sysarg_t) rc; namebuf[name_len] = 0; /* Spawn the new task. */ program_t prg; rc = program_create_loader(&prg, namebuf); if (rc != 0) return rc; // FIXME: control the capabilities cap_set(prg.task, cap_get(TASK)); program_ready(&prg); return EOK; }
/** Return sysinfo keys determined by name from user space * * The path string passed from the user space has to be properly * null-terminated (the last passed character must be null). * * @param ptr Sysinfo path in the user address space. * @param size Size of the path string. * @param dry_run Do not actually get any generated * binary data, just calculate the size. * */ NO_TRACE static sysinfo_return_t sysinfo_get_keys_uspace(void *ptr, size_t size, bool dry_run) { sysinfo_return_t ret; ret.tag = SYSINFO_VAL_UNDEFINED; ret.data.data = NULL; ret.data.size = 0; if (size > SYSINFO_MAX_PATH) return ret; char *path = (char *) malloc(size + 1, 0); ASSERT(path); if ((copy_from_uspace(path, ptr, size + 1) == 0) && (path[size] == 0)) { /* * Prevent other functions from messing with sysinfo while we * are reading it. */ mutex_lock(&sysinfo_lock); ret = sysinfo_get_keys(path, NULL, dry_run); mutex_unlock(&sysinfo_lock); } free(path); return ret; }
/** Answer an IPC call. * * @param callid Hash of the call to be answered. * @param data Userspace address of call data with the answer. * * @return 0 on success, otherwise an error code. * */ sysarg_t sys_ipc_answer_slow(sysarg_t callid, ipc_data_t *data) { /* Do not answer notification callids */ if (callid & IPC_CALLID_NOTIFICATION) return 0; call_t *call = get_call(callid); if (!call) return ENOENT; ipc_data_t saved_data; bool saved; if (answer_need_old(call)) { memcpy(&saved_data, &call->data, sizeof(call->data)); saved = true; } else saved = false; int rc = copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args)); if (rc != 0) return rc; rc = answer_preprocess(call, saved ? &saved_data : NULL); ipc_answer(&TASK->answerbox, call); return rc; }
/** Make an asynchronous IPC call allowing to transmit the entire payload. * * @param phoneid Phone handle for the call. * @param data Userspace address of call data with the request. * * @return See sys_ipc_call_async_fast(). * */ sysarg_t sys_ipc_call_async_slow(sysarg_t phoneid, ipc_data_t *data) { phone_t *phone; if (phone_get(phoneid, &phone) != EOK) return IPC_CALLRET_FATAL; if (check_call_limit(phone)) return IPC_CALLRET_TEMPORARY; call_t *call = ipc_call_alloc(0); int rc = copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args)); if (rc != 0) { ipc_call_free(call); return (sysarg_t) rc; } int res = request_preprocess(call, phone); if (!res) ipc_call(phone, call); else ipc_backsend_err(phone, call, res); return (sysarg_t) call; }
/** Revoke capabilities from a task (32 bits) * * The calling task must have the CAP_CAP capability or the caller must * attempt to revoke capabilities from itself. * * @param uspace_taskid User-space pointer to destination task ID. * @param caps Capabilities to revoke. * * @return Zero on success or an error code from @ref errno.h. * */ sysarg_t sys_cap_revoke(sysarg64_t *uspace_taskid, cap_t caps) { sysarg64_t taskid; int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t)); if (rc != 0) return (sysarg_t) rc; return cap_revoke((task_id_t) taskid, caps); }
/** Syscall connect to a task by ID (32 bits) * * @return Phone id on success, or negative error code. * */ sysarg_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid) { #ifdef CONFIG_UDEBUG sysarg64_t taskid; int rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t)); if (rc != 0) return (sysarg_t) rc; return ipc_connect_kbox((task_id_t) taskid); #else return (sysarg_t) ENOTSUP; #endif }
/** 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); }
/** Control of the log from uspace * */ sysarg_t sys_klog(sysarg_t operation, void *buf, size_t size, sysarg_t level) { char *data; int rc; if (size > PAGE_SIZE) return (sysarg_t) ELIMIT; switch (operation) { case KLOG_WRITE: data = (char *) malloc(size + 1, 0); if (!data) return (sysarg_t) ENOMEM; rc = copy_from_uspace(data, buf, size); if (rc) { free(data); return (sysarg_t) rc; } data[size] = 0; if (level >= LVL_LIMIT) level = LVL_NOTE; log(LF_USPACE, level, "%s", data); free(data); return EOK; case KLOG_READ: data = (char *) malloc(size, 0); if (!data) return (sysarg_t) ENOMEM; size_t entry_len = 0; size_t copied = 0; rc = EOK; spinlock_lock(&log_lock); while (next_for_uspace < log_used) { size_t pos = (log_start + next_for_uspace) % LOG_LENGTH; log_copy_from((uint8_t *) &entry_len, pos, sizeof(size_t)); if (entry_len > PAGE_SIZE) { /* * Since we limit data transfer * to uspace to a maximum of PAGE_SIZE * bytes, skip any entries larger * than this limit to prevent * userspace being stuck trying to * read them. */ next_for_uspace += entry_len; continue; } if (size < copied + entry_len) { if (copied == 0) rc = EOVERFLOW; break; } log_copy_from((uint8_t *) (data + copied), pos, entry_len); copied += entry_len; next_for_uspace += entry_len; } spinlock_unlock(&log_lock); if (rc != EOK) { free(data); return (sysarg_t) rc; } rc = copy_to_uspace(buf, data, size); free(data); if (rc != EOK) return (sysarg_t) rc; return copied; default: return (sysarg_t) ENOTSUP; } }