1 #include <lunaix/exec.h>
3 #include <lunaix/load.h>
4 #include <lunaix/mm/mmap.h>
5 #include <lunaix/mm/valloc.h>
6 #include <lunaix/mm/vmm.h>
7 #include <lunaix/process.h>
8 #include <lunaix/spike.h>
9 #include <lunaix/status.h>
10 #include <lunaix/syscall.h>
11 #include <lunaix/syscall_utils.h>
14 #include <sys/mm/mempart.h>
16 #include <klibc/string.h>
19 exec_container(struct exec_container* param,
20 struct proc_info* proc,
25 *param = (struct exec_container){ .proc = proc,
27 .exe = { .container = param },
34 args_ptr_size(const char** paramv)
42 return (sz + 1) * sizeof(ptr_t);
46 copy_to_ustack(ptr_t stack_top, ptr_t* paramv)
51 while ((ptr = *paramv)) {
52 sz = strlen((const char*)ptr) + 1;
55 memcpy((void*)stack_top, (const void*)ptr, sz);
64 // externed from mm/dmm.c
66 create_heap(struct proc_mm* pvms, ptr_t addr);
69 exec_load(struct exec_container* container, struct v_file* executable)
73 const char **argv = container->argv, **envp = container->envp;
74 const char** argv_extra = container->argv_pp;
76 argv_extra[0] = executable->dnode->name.value;
78 if ((errno = load_executable(&container->exe, executable))) {
82 struct proc_mm* pvms = &container->proc->mm;
85 mem_unmap_region(container->vms_mnt, pvms->heap);
90 // If loading a statically linked file, then heap remapping we can do,
92 create_heap(&container->proc->mm, PG_ALIGN(container->exe.end));
95 if (container->vms_mnt == VMS_SELF) {
96 // we are loading executable into current addr space
98 ptr_t ustack = USR_STACK_END;
99 size_t argv_len = 0, envp_len = 0;
100 ptr_t argv_ptr = 0, envp_ptr = 0;
103 argv_len = args_ptr_size(envp);
107 memcpy((void*)ustack, (const void*)envp, envp_len);
108 ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
112 argv_len = args_ptr_size(argv);
115 memcpy((void*)ustack, (const void**)argv, argv_len);
116 for (size_t i = 0; i < 2 && argv_extra[i]; i++) {
117 ustack -= sizeof(ptr_t);
118 *((ptr_t*)ustack) = (ptr_t)argv_extra[i];
119 argv_len += sizeof(ptr_t);
123 ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
126 // four args (arg{c|v}, env{c|p}) for main
127 struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1];
129 container->stack_top = (ptr_t)exec_param;
132 (struct uexec_param){ .argc = (argv_len - 1) / sizeof(ptr_t),
133 .argv = (char**)argv_ptr,
134 .envc = (envp_len - 1) / sizeof(ptr_t),
135 .envp = (char**)envp_ptr };
138 TODO need to find a way to inject argv and envp remotely
139 this is for the support of kernel level implementation of
143 1. Allocate a orphaned physical page (i.e., do not belong to any
145 2. Mounted to a temporary mount point in current VMA, (i.e.,
148 4. Unmount then mounted to the foreign VMA as the first stack
151 fail("not implemented");
159 exec_load_byname(struct exec_container* container, const char* filename)
162 struct v_dnode* dnode;
165 if ((errno = vfs_walk_proc(filename, &dnode, NULL, 0))) {
169 if ((errno = vfs_open(dnode, &file))) {
173 errno = exec_load(container, file);
180 exec_kexecve(const char* filename, const char* argv[], const char* envp[])
183 struct exec_container container;
186 &container, (struct proc_info*)__current, VMS_SELF, argv, envp);
188 errno = exec_load_byname(&container, filename);
194 ptr_t entry = container.exe.entry;
197 j_usr(container.stack_top, entry);
204 __DEFINE_LXSYSCALL3(int,
214 struct exec_container container;
217 &container, (struct proc_info*)__current, VMS_SELF, argv, envp);
219 if ((errno = exec_load_byname(&container, filename))) {
223 // we will jump to new entry point (_u_start) upon syscall's
224 // return so execve 'will not return' from the perspective of it's invoker
225 eret_target(__current) = container.exe.entry;
226 eret_stack(__current) = container.stack_top;
228 // these become meaningless once execved!
229 __current->ustack_top = 0;
230 proc_clear_signal(__current);
234 store_retval(DO_STATUS(errno));
236 // Always yield the process that want execve!
239 // this will never get executed!