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/sched.h>
9 #include <lunaix/spike.h>
10 #include <lunaix/status.h>
11 #include <lunaix/syscall.h>
12 #include <lunaix/syscall_utils.h>
15 #include <sys/mm/mm_defs.h>
17 #include <klibc/string.h>
20 exec_init_container(struct exec_container* param,
21 struct thread* thread,
26 assert(thread->ustack);
27 ptr_t ustack_top = align_stack(thread->ustack->end - 1);
28 *param = (struct exec_container){ .proc = thread->process,
30 .exe = { .container = param },
34 .stack_top = ustack_top };
38 args_ptr_size(const char** paramv)
46 return (sz + 1) * sizeof(ptr_t);
50 copy_to_ustack(ptr_t stack_top, ptr_t* paramv)
55 while ((ptr = *paramv)) {
56 sz = strlen((const char*)ptr) + 1;
59 memcpy((void*)stack_top, (const void*)ptr, sz);
69 save_process_cmd(struct proc_info* proc, ptr_t* argv)
71 ptr_t ptr, *_argv = argv;
73 while ((ptr = *_argv)) {
74 total_sz += strlen((const char*)ptr) + 1;
82 char* cmd_ = (char*)valloc(total_sz);
84 proc->cmd_len = total_sz;
86 while ((ptr = *argv)) {
87 cmd_ = strcpy(cmd_, (const char*)ptr);
94 // externed from mm/dmm.c
96 create_heap(struct proc_mm* pvms, ptr_t addr);
99 exec_load(struct exec_container* container, struct v_file* executable)
103 const char **argv = container->argv, **envp = container->envp;
104 const char** argv_extra = container->argv_pp;
106 argv_extra[0] = executable->dnode->name.value;
108 if ((errno = load_executable(&container->exe, executable))) {
112 struct proc_info* proc = container->proc;
113 struct proc_mm* pvms = vmspace(proc);
116 mem_unmap_region(container->vms_mnt, pvms->heap);
120 if (!argv_extra[1]) {
121 // If loading a statically linked file, then heap remapping we can do,
122 // otherwise delayed.
123 create_heap(vmspace(proc), va_align(container->exe.end));
126 if (container->vms_mnt == VMS_SELF) {
127 // we are loading executable into current addr space
129 ptr_t ustack = container->stack_top;
130 size_t argv_len = 0, envp_len = 0;
131 ptr_t argv_ptr = 0, envp_ptr = 0;
134 argv_len = args_ptr_size(envp);
138 memcpy((void*)ustack, (const void*)envp, envp_len);
139 ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
143 argv_len = args_ptr_size(argv);
146 memcpy((void*)ustack, (const void**)argv, argv_len);
149 for (size_t i = 0; i < 2 && argv_extra[i]; i++) {
150 ustack -= sizeof(ptr_t);
151 *((ptr_t*)ustack) = (ptr_t)argv_extra[i];
152 argv_len += sizeof(ptr_t);
156 ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
158 save_process_cmd(proc, (ptr_t*)argv_ptr);
160 // four args (arg{c|v}, env{c|p}) for main
161 struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1];
163 container->stack_top = (ptr_t)exec_param;
166 (struct uexec_param){ .argc = (argv_len - 1) / sizeof(ptr_t),
167 .argv = (char**)argv_ptr,
168 .envc = (envp_len - 1) / sizeof(ptr_t),
169 .envp = (char**)envp_ptr };
172 TODO Inject to remote user stack with our procvm_remote toolsets
173 Need a better way to factorise the argv/envp length calculating
175 fail("not implemented");
184 exec_load_byname(struct exec_container* container, const char* filename)
187 struct v_dnode* dnode;
190 if ((errno = vfs_walk_proc(filename, &dnode, NULL, 0))) {
194 if ((errno = vfs_open(dnode, &file))) {
198 errno = exec_load(container, file);
200 // It shouldn't matter which pid we passed. As the only reader is
201 // in current context and we must finish read at this point,
202 // therefore the dead-lock condition will not exist and the pid
203 // for arbitration has no use.
204 vfs_pclose(file, container->proc->pid);
211 exec_kexecve(const char* filename, const char* argv[], const char* envp[])
214 struct exec_container container;
216 exec_init_container(&container, current_thread, VMS_SELF, argv, envp);
218 errno = exec_load_byname(&container, filename);
224 ptr_t entry = container.exe.entry;
227 j_usr(container.stack_top, entry);
234 __DEFINE_LXSYSCALL3(int,
244 struct exec_container container;
247 &container, current_thread, VMS_SELF, argv, envp);
249 if ((errno = exec_load_byname(&container, filename))) {
253 // we will jump to new entry point (_u_start) upon syscall's
254 // return so execve 'will not return' from the perspective of it's invoker
255 eret_target(current_thread) = container.exe.entry;
256 eret_stack(current_thread) = container.stack_top;
258 // these become meaningless once execved!
259 current_thread->ustack_top = 0;
260 signal_reset_context(¤t_thread->sigctx);
261 signal_reset_register(__current->sigreg);
265 store_retval(DO_STATUS(errno));
267 // Always yield the process that want execve!
270 // this will never get executed!