#include <lunaix/mm/valloc.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/process.h>
+#include <lunaix/sched.h>
#include <lunaix/spike.h>
#include <lunaix/status.h>
#include <lunaix/syscall.h>
#include <lunaix/syscall_utils.h>
-#include <sys/abi.h>
+#include <asm/abi.h>
+#include <asm/mm_defs.h>
#include <klibc/string.h>
+#define _push(ptr, type, val) \
+ do { \
+ ptr = __ptr(&((type*)ptr)[-1]); \
+ *((type*)ptr) = (val); \
+ } while(0)
+
+static int
+__place_arrayptrs(struct exec_host* container, struct exec_arrptr* param)
+{
+ int len;
+ ptr_t usp, usp_top;
+ ptr_t* ptrs;
+ unsigned int* reloc_off;
+
+ usp_top = container->stack_top;
+ usp = usp_top;
+ ptrs = (ptr_t*)param->raw;
+
+ if (!param->len) {
+ _push(usp, unsigned int, 0);
+
+ goto done;
+ }
+
+ len = param->len;
+ reloc_off = valloc(len * sizeof(unsigned int));
+
+ char* el;
+ size_t el_sz, sz_acc = 0;
+ for (int i = 0; i < len; i++)
+ {
+ el= (char*)ptrs[i];
+ el_sz = strnlen(el, MAX_PARAM_SIZE) + 1;
+
+ usp -= el_sz;
+ sz_acc += el_sz;
+ strncpy((char*)usp, el, el_sz);
+
+ reloc_off[i] = sz_acc;
+ }
+
+ param->size = sz_acc;
+
+ ptr_t* toc = (ptr_t*)(usp) - 1;
+ toc[0] = 0;
+
+ toc = &toc[-1];
+ for (int i = 0, j = len - 1; i < len; i++, j--)
+ {
+ toc[-i] = usp_top - (ptr_t)reloc_off[j];
+ }
+
+ toc[-len] = (ptr_t)len;
+
+ usp = __ptr(&toc[-len]);
+ param->copied = __ptr(&toc[-len + 1]);
+
+ vfree(reloc_off);
+
+done:
+ container->stack_top = usp;
+ return 0;
+}
+
void
-exec_container(struct exec_container* param,
- struct proc_info* proc,
+exec_init_container(struct exec_host* param,
+ struct thread* thread,
ptr_t vms,
const char** argv,
const char** envp)
{
- *param = (struct exec_container){ .proc = proc,
- .vms_mnt = vms,
- .exe = { .container = param },
- .argv_pp = { 0, 0 },
- .argv = argv,
- .envp = envp };
+ assert(thread->ustack);
+ ptr_t ustack_top = align_stack(thread->ustack->end - 1);
+ *param = (struct exec_host)
+ {
+ .proc = thread->process,
+ .vms_mnt = vms,
+ .exe = {
+ .container = param
+ },
+ .argv = {
+ .raw = __ptr(argv)
+ },
+ .envp = {
+ .raw = __ptr(envp)
+ },
+ .stack_top = ustack_top
+ };
}
-size_t
-args_ptr_size(const char** paramv)
+int
+count_length(struct exec_arrptr* param)
{
- size_t sz = 0;
- while (*paramv) {
- sz++;
- paramv++;
+ int i = 0;
+ ptr_t* arr = (ptr_t*)param->raw;
+
+ if (!arr) {
+ param->len = 0;
+ return 0;
}
- return (sz + 1) * sizeof(ptr_t);
+ for (; i < MAX_PARAM_LEN && arr[i]; i++);
+
+ param->len = i;
+ return i > 0 && arr[i] ? E2BIG : 0;
}
-ptr_t
-copy_to_ustack(ptr_t stack_top, ptr_t* paramv)
+static void
+save_process_cmd(struct proc_info* proc, struct exec_arrptr* argv)
{
- ptr_t ptr;
- size_t sz = 0;
+ ptr_t ptr, *argv_ptrs;
+ char* cmd_;
- while ((ptr = *paramv)) {
- sz = strlen((const char*)ptr) + 1;
+ if (proc->cmd) {
+ vfree(proc->cmd);
+ }
- stack_top -= sz;
- memcpy((void*)stack_top, (const void*)ptr, sz);
- *paramv = stack_top;
+ argv_ptrs = (ptr_t*)argv->copied;
+ cmd_ = (char*)valloc(argv->size);
- paramv++;
+ proc->cmd = cmd_;
+ while ((ptr = *argv_ptrs)) {
+ cmd_ = strcpy(cmd_, (const char*)ptr);
+ cmd_[-1] = ' ';
+ argv_ptrs++;
}
-
- return stack_top;
+ cmd_[-1] = '\0';
+
+ proc->cmd_len = argv->size;
}
-// externed from mm/dmm.c
-extern int
-create_heap(struct proc_mm* pvms, ptr_t addr);
-int
-exec_load(struct exec_container* container, struct v_file* executable)
+static int
+__place_params(struct exec_host* container)
{
int errno = 0;
- const char **argv = container->argv, **envp = container->envp;
- const char** argv_extra = container->argv_pp;
-
- argv_extra[0] = executable->dnode->name.value;
-
- if ((errno = load_executable(&container->exe, executable))) {
+ errno = __place_arrayptrs(container, &container->envp);
+ if (errno) {
goto done;
}
- struct proc_mm* pvms = &container->proc->mm;
+ errno = __place_arrayptrs(container, &container->argv);
- if (pvms->heap) {
- mem_unmap_region(container->vms_mnt, pvms->heap);
- pvms->heap = NULL;
- }
-
- if (!argv_extra[1]) {
- // If loading a statically linked file, then heap remapping we can do,
- // otherwise delayed.
- create_heap(&container->proc->mm, PG_ALIGN(container->exe.end));
- }
+done:
+ return errno;
+}
- if (container->vms_mnt == VMS_SELF) {
- // we are loading executable into current addr space
+int
+exec_load(struct exec_host* container, struct v_file* executable)
+{
+ int errno = 0;
- ptr_t ustack = USTACK_TOP;
- size_t argv_len = 0, envp_len = 0;
- ptr_t argv_ptr = 0, envp_ptr = 0;
+ struct exec_arrptr* argv = &container->argv;
+ struct exec_arrptr* envp = &container->envp;
- if (envp) {
- argv_len = args_ptr_size(envp);
- ustack -= envp_len;
- envp_ptr = ustack;
+ struct proc_info* proc = container->proc;
+ struct proc_mm* pvms = vmspace(proc);
- memcpy((void*)ustack, (const void*)envp, envp_len);
- ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
- }
+ if (pvms->heap) {
+ mem_unmap_region(container->vms_mnt, pvms->heap);
+ pvms->heap = NULL;
+ }
- if (argv) {
- argv_len = args_ptr_size(argv);
- ustack -= argv_len;
+ if (!active_vms(container->vms_mnt)) {
+ /*
+ TODO Setup remote mapping of user stack for later use
+ */
+ fail("not implemented");
- memcpy((void*)ustack, (const void**)argv, argv_len);
- for (size_t i = 0; i < 2 && argv_extra[i]; i++) {
- ustack -= sizeof(ptr_t);
- *((ptr_t*)ustack) = (ptr_t)argv_extra[i];
- argv_len += sizeof(ptr_t);
- }
+ }
- argv_ptr = ustack;
- ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
- }
+ if ((errno = count_length(argv))) {
+ goto done;
+ }
- // four args (arg{c|v}, env{c|p}) for main
- struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1];
+ if ((errno = count_length(envp))) {
+ goto done;
+ }
- container->stack_top = (ptr_t)exec_param;
+ errno = __place_params(container);
+ if (errno) {
+ goto done;
+ }
- *exec_param =
- (struct uexec_param){ .argc = (argv_len - 1) / sizeof(ptr_t),
- .argv = (char**)argv_ptr,
- .envc = (envp_len - 1) / sizeof(ptr_t),
- .envp = (char**)envp_ptr };
- } else {
- /*
- TODO need to find a way to inject argv and envp remotely
- this is for the support of kernel level implementation of
- posix_spawn
-
- IDEA
- 1. Allocate a orphaned physical page (i.e., do not belong to any
- VMA)
- 2. Mounted to a temporary mount point in current VMA, (i.e.,
- PG_MOUNT_*)
- 3. Do setup there.
- 4. Unmount then mounted to the foreign VMA as the first stack
- page.
- */
- fail("not implemented");
+ save_process_cmd(proc, argv);
+
+ errno = load_executable(&container->exe, executable);
+ if (errno) {
+ goto done;
}
done:
}
int
-exec_load_byname(struct exec_container* container, const char* filename)
+exec_load_byname(struct exec_host* container, const char* filename)
{
int errno = 0;
struct v_dnode* dnode;
goto done;
}
+ if (!check_itype_any(dnode->inode, F_FILE)) {
+ errno = EISDIR;
+ goto done;
+ }
+
errno = exec_load(container, file);
+ // It shouldn't matter which pid we passed. As the only reader is
+ // in current context and we must finish read at this point,
+ // therefore the dead-lock condition will not exist and the pid
+ // for arbitration has no use.
+ vfs_pclose(file, container->proc->pid);
+
done:
return errno;
}
exec_kexecve(const char* filename, const char* argv[], const char* envp[])
{
int errno = 0;
- struct exec_container container;
+ struct exec_host container;
- exec_container(
- &container, (struct proc_info*)__current, VMS_SELF, argv, envp);
+ assert(argv && envp);
+
+ exec_init_container(&container, current_thread, VMS_SELF, argv, envp);
errno = exec_load_byname(&container, filename);
envp[])
{
int errno = 0;
- struct exec_container container;
+ struct exec_host container;
+
+ if (!argv || !envp) {
+ errno = EINVAL;
+ goto done;
+ }
- exec_container(
- &container, (struct proc_info*)__current, VMS_SELF, argv, envp);
+ exec_init_container(
+ &container, current_thread, VMS_SELF, argv, envp);
if ((errno = exec_load_byname(&container, filename))) {
goto done;
// we will jump to new entry point (_u_start) upon syscall's
// return so execve 'will not return' from the perspective of it's invoker
- eret_target(__current) = container.exe.entry;
- eret_stack(__current) = container.stack_top;
+ exec_arch_prepare_entry(current_thread, &container);
// these become meaningless once execved!
- __current->ustack_top = 0;
- proc_clear_signal(__current);
+ current_thread->ustack_top = 0;
+ signal_reset_context(¤t_thread->sigctx);
+ signal_reset_registry(__current->sigreg);
done:
// set return value