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), page_aligned(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);
141 ustack -= sizeof(ptr_t);
142 *((ptr_t*)ustack) = 0;
146 argv_len = args_ptr_size(argv);
149 memcpy((void*)ustack, (const void**)argv, argv_len);
151 ustack -= sizeof(ptr_t);
152 *((ptr_t*)ustack) = 0;
155 for (size_t i = 0; i < 2 && argv_extra[i]; i++) {
156 ustack -= sizeof(ptr_t);
157 *((ptr_t*)ustack) = (ptr_t)argv_extra[i];
158 argv_len += sizeof(ptr_t);
162 ustack = copy_to_ustack(ustack, (ptr_t*)ustack);
164 save_process_cmd(proc, (ptr_t*)argv_ptr);
166 // four args (arg{c|v}, env{c|p}) for main
167 struct uexec_param* exec_param = &((struct uexec_param*)ustack)[-1];
169 container->stack_top = (ptr_t)exec_param;
172 (struct uexec_param){ .argc = (argv_len - 1) / sizeof(ptr_t),
173 .argv = (char**)argv_ptr,
174 .envc = (envp_len - 1) / sizeof(ptr_t),
175 .envp = (char**)envp_ptr };
178 TODO Inject to remote user stack with our procvm_remote toolsets
179 Need a better way to factorise the argv/envp length calculating
181 fail("not implemented");
190 exec_load_byname(struct exec_container* container, const char* filename)
193 struct v_dnode* dnode;
196 if ((errno = vfs_walk_proc(filename, &dnode, NULL, 0))) {
200 if ((errno = vfs_open(dnode, &file))) {
204 errno = exec_load(container, file);
206 // It shouldn't matter which pid we passed. As the only reader is
207 // in current context and we must finish read at this point,
208 // therefore the dead-lock condition will not exist and the pid
209 // for arbitration has no use.
210 vfs_pclose(file, container->proc->pid);
217 exec_kexecve(const char* filename, const char* argv[], const char* envp[])
220 struct exec_container container;
222 exec_init_container(&container, current_thread, VMS_SELF, argv, envp);
224 errno = exec_load_byname(&container, filename);
230 ptr_t entry = container.exe.entry;
233 j_usr(container.stack_top, entry);
240 __DEFINE_LXSYSCALL3(int,
250 struct exec_container container;
253 &container, current_thread, VMS_SELF, argv, envp);
255 if ((errno = exec_load_byname(&container, filename))) {
259 // we will jump to new entry point (_u_start) upon syscall's
260 // return so execve 'will not return' from the perspective of it's invoker
261 eret_target(current_thread) = container.exe.entry;
262 eret_stack(current_thread) = container.stack_top;
264 // these become meaningless once execved!
265 current_thread->ustack_top = 0;
266 signal_reset_context(¤t_thread->sigctx);
267 signal_reset_register(__current->sigreg);
271 store_retval(DO_STATUS(errno));
273 // Always yield the process that want execve!
276 // this will never get executed!