2 #include <lunaix/elf.h>
3 #include <lunaix/exec.h>
5 #include <lunaix/mm/mmap.h>
6 #include <lunaix/mm/valloc.h>
7 #include <lunaix/mm/vmm.h>
8 #include <lunaix/process.h>
9 #include <lunaix/spike.h>
10 #include <lunaix/status.h>
11 #include <lunaix/syscall.h>
12 #include <lunaix/syscall_utils.h>
14 #include <klibc/string.h>
17 exec_container(struct exec_container* param, struct proc_info* proc, ptr_t vms)
19 *param = (struct exec_container){ .proc = proc,
21 .executable = { .container = param } };
25 exec_str_size(const char** str_arr, size_t* length)
32 const char* chr = *str_arr;
33 size_t sz = 0, len = 0;
43 return sz + sizeof(char*);
46 // externed from mm/dmm.c
48 create_heap(struct proc_mm* pvms, ptr_t addr);
51 exec_load(struct exec_container* container,
52 struct v_file* executable,
59 size_t argv_len, envp_len;
60 size_t sz_argv = exec_str_size(argv, &argv_len);
61 size_t sz_envp = exec_str_size(envp, &envp_len);
62 size_t var_sz = ROUNDUP(sz_envp, PG_SIZE);
64 char* argv_extra[2] = { executable->dnode->name.value, 0 };
66 if (var_sz / PG_SIZE > MAX_VAR_PAGES) {
73 if ((errno = elf32_openat(&elf, executable))) {
77 if (!elf32_check_exec(&elf)) {
83 errno = elf32_find_loader(&elf, ldpath, 512);
90 if (errno != NO_LOADER) {
92 argv_extra[1] = ldpath;
95 if ((errno = elf32_close(&elf))) {
99 // open the loader instead
100 if ((errno = elf32_open(&elf, ldpath))) {
104 // Is this the valid loader?
105 if (!elf32_static_linked(&elf) || !elf32_check_exec(&elf)) {
107 goto done_close_elf32;
110 // TODO: relocate loader
113 if ((errno = elf32_load(&container->executable, &elf))) {
114 goto done_close_elf32;
117 struct proc_mm* pvms = &container->proc->mm;
119 // A dedicated place for process variables (e.g. envp)
120 struct mmap_param map_vars = { .pvms = pvms,
121 .vms_mnt = container->vms_mnt,
122 .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED,
123 .type = REGION_TYPE_VARS,
125 .mlen = MAX_VAR_PAGES * PG_SIZE };
130 mem_unmap_region(container->vms_mnt, pvms->heap);
134 if (!argv_extra[1]) {
135 // If loading a statically linked file, then heap remapping we can do,
136 // otherwise delayed.
137 create_heap(container->vms_mnt, PG_ALIGN(container->executable.end));
140 if ((errno = mem_map(&mapped, NULL, UMMAP_END, NULL, &map_vars))) {
141 goto done_close_elf32;
144 if (container->vms_mnt == VMS_SELF) {
145 // we are loading executable into current addr space
147 // make some handy infos available to user space
149 memcpy(mapped, (void*)envp, sz_envp);
151 void* ustack = (void*)USTACK_TOP;
154 ustack = (void*)((ptr_t)ustack - sz_argv);
155 memcpy(ustack, (void*)argv, sz_argv);
158 for (size_t i = 0; i < 2 && argv_extra[i]; i++, argv_len++) {
159 char* extra_arg = argv_extra[i];
160 size_t str_len = strlen(extra_arg);
162 ustack = (void*)((ptr_t)ustack - str_len);
163 memcpy(ustack, (void*)extra_arg, str_len);
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;
171 *exec_param = (struct uexec_param){
172 .argc = argv_len, .argv = ustack, .envc = envp_len, .envp = mapped
177 TODO need to find a way to inject argv and envp remotely
178 this is for the support of kernel level implementation of
182 1. Allocate a orphaned physical page (i.e., do not belong to any
184 2. Mounted to a temporary mount point in current VMA, (i.e.,
187 4. Unmount then mounted to the foreign VMA as the first stack
190 fail("not implemented");
201 exec_load_byname(struct exec_container* container,
202 const char* filename,
207 struct v_dnode* dnode;
210 if ((errno = vfs_walk_proc(filename, &dnode, NULL, 0))) {
214 if ((errno = vfs_open(dnode, &file))) {
218 errno = exec_load(container, file, argv, envp);
225 exec_kexecve(const char* filename, const char* argv[], const char* envp)
228 struct exec_container container;
229 exec_container(&container, __current, VMS_SELF);
231 errno = exec_load_byname(&container, filename, argv, envp);
237 j_usr(container.stack_top, container.entry);
240 __DEFINE_LXSYSCALL3(int,
250 struct exec_container container;
251 exec_container(&container, __current, VMS_SELF);
253 if (!(errno = exec_load_byname(&container, filename, argv, envp))) {
257 // we will jump to new entry point (_u_start) upon syscall's
258 // return so execve 'will not return' from the perspective of it's invoker
259 volatile struct exec_param* execp = __current->intr_ctx.execp;
260 execp->esp = container.stack_top;
261 execp->eip = container.entry;
265 store_retval(DO_STATUS(errno));
267 // Always yield the process that want execve!
270 // this will never get executed!