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>
15 #include <klibc/string.h>
18 exec_container(struct exec_container* param,
19 struct proc_info* proc,
24 *param = (struct exec_container){ .proc = proc,
26 .exe = { .container = param },
33 args_ptr_size(const char** paramv)
41 return (sz + 1) * sizeof(ptr_t);
45 copy_to_ustack(ptr_t stack_top, ptr_t* paramv)
50 while ((ptr = *paramv)) {
51 sz = strlen((const char*)ptr) + 1;
54 memcpy((void*)stack_top, (const void*)ptr, sz);
63 // externed from mm/dmm.c
65 create_heap(struct proc_mm* pvms, ptr_t addr);
68 exec_load(struct exec_container* container, struct v_file* executable)
72 const char **argv = container->argv, **envp = container->envp;
73 const char** argv_extra = container->argv_pp;
75 argv_extra[0] = executable->dnode->name.value;
77 if ((errno = load_executable(&container->exe, executable))) {
81 struct proc_mm* pvms = &container->proc->mm;
84 mem_unmap_region(container->vms_mnt, pvms->heap);
89 // If loading a statically linked file, then heap remapping we can do,
91 create_heap(&container->proc->mm, PG_ALIGN(container->exe.end));
94 if (container->vms_mnt == VMS_SELF) {
95 // we are loading executable into current addr space
97 ptr_t ustack = USTACK_TOP;
98 size_t argv_len = 0, envp_len = 0;
99 ptr_t argv_ptr = 0, envp_ptr = 0;
102 argv_len = args_ptr_size(envp);
106 memcpy((void*)ustack, (const void*)envp, envp_len);
107 ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
111 argv_len = args_ptr_size(argv);
114 memcpy((void*)ustack, (const void**)argv, argv_len);
115 for (size_t i = 0; i < 2 && argv_extra[i]; i++) {
116 ustack -= sizeof(ptr_t);
117 *((ptr_t*)ustack) = (ptr_t)argv_extra[i];
118 argv_len += sizeof(ptr_t);
122 ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
125 // four args (arg{c|v}, env{c|p}) for main
126 struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1];
128 container->stack_top = (ptr_t)exec_param;
131 (struct uexec_param){ .argc = (argv_len - 1) / sizeof(ptr_t),
132 .argv = (char**)argv_ptr,
133 .envc = (envp_len - 1) / sizeof(ptr_t),
134 .envp = (char**)envp_ptr };
137 TODO need to find a way to inject argv and envp remotely
138 this is for the support of kernel level implementation of
142 1. Allocate a orphaned physical page (i.e., do not belong to any
144 2. Mounted to a temporary mount point in current VMA, (i.e.,
147 4. Unmount then mounted to the foreign VMA as the first stack
150 fail("not implemented");
158 exec_load_byname(struct exec_container* container, const char* filename)
161 struct v_dnode* dnode;
164 if ((errno = vfs_walk_proc(filename, &dnode, NULL, 0))) {
168 if ((errno = vfs_open(dnode, &file))) {
172 errno = exec_load(container, file);
179 exec_kexecve(const char* filename, const char* argv[], const char* envp[])
182 struct exec_container container;
185 &container, (struct proc_info*)__current, VMS_SELF, argv, envp);
187 errno = exec_load_byname(&container, filename);
193 ptr_t entry = container.exe.entry;
196 j_usr(container.stack_top, entry);
203 __DEFINE_LXSYSCALL3(int,
213 struct exec_container container;
216 &container, (struct proc_info*)__current, VMS_SELF, argv, envp);
218 if ((errno = exec_load_byname(&container, filename))) {
222 // we will jump to new entry point (_u_start) upon syscall's
223 // return so execve 'will not return' from the perspective of it's invoker
224 eret_target(__current) = container.exe.entry;
225 eret_stack(__current) = container.stack_top;
227 // these become meaningless once execved!
228 __current->ustack_top = 0;
229 proc_clear_signal(__current);
233 store_retval(DO_STATUS(errno));
235 // Always yield the process that want execve!
238 // this will never get executed!