static int __zero_segment (int envid, u_int start, u_int sz) { u_int temp_pages; assert (!(start & PGMASK)); temp_pages = (u_int)__malloc(PGROUNDUP(sz)); if (temp_pages == 0) return -1; /* alloc pages for this segment and map into our address space writeable */ if (__vm_alloc_region (temp_pages, sz, 0, PG_P|PG_U|PG_W) < 0) { __free((void*)temp_pages); return -1; } /* and map them into the other address space */ if (__vm_share_region (temp_pages, sz, 0, 0, envid, start) < 0) { __free((void*)temp_pages); return -1; } /* zero the pages */ bzero ((void *)temp_pages, sz); /* and remove our mapping of the pages */ if (__vm_free_region (temp_pages, sz, 0) < 0) { __free((void*)temp_pages); return -1; } __free((void*)temp_pages); return 0; }
int ShareAshRegion(u_int k, int envid) { /* printf("ShareAshRegion sz: %d\n",sizeof(struct ash_sh_network)); */ if (__vm_share_region(ADD_UVA(ASH_PKT_DATA_ADDR), sizeof(struct ash_sh_network), k, k, envid, ASH_PKT_DATA_ADDR + env_id2env(envid)->env_ashuva) < 0) { sys_env_free (k, envid); kprintf("ShareAshRegion: __vm_share_region failed\n"); return (-1); } return 0; }
static int exec_exos_aout(int fd, const char *path, char *const argv[], char *const envp[], struct Env *e, u_int flags) { u_int envid = e->env_id; struct exec hdr; u_int dynamic; int r; struct _exos_exec_args eea; if (lseek(fd, 0, SEEK_SET) == -1 || read(fd, &hdr, sizeof(hdr)) != sizeof(hdr) || lseek(fd, sizeof(hdr) + hdr.a_text, SEEK_SET) == -1 || read(fd, &dynamic, sizeof(dynamic)) != sizeof(dynamic)) return 0; if (N_GETMAGIC(hdr) != OMAGIC || N_GETMID(hdr) != MID_I386 || N_GETFLAG(hdr) != 0) return 0; if (!(flags & _EXEC_USE_FD)) { close(fd); fd = -1; } else if (lseek(fd, 0, SEEK_SET) == -1) return 0; if (dynamic < SHARED_LIBRARY_START) dynamic = 0; if (dynamic == 0 && (flags & _EXEC_SHLIB_ONLY)) { r = -EINVAL; goto err; } /* if static, then read in entire program... */ if (!dynamic) { u_int start_text_addr; if (flags & _EXEC_USE_FD) start_text_addr = __load_prog_fd(fd, 1, envid); else start_text_addr = __load_prog(path, argv[0], 1, envid); if (!start_text_addr) { r = -ENOEXEC; goto err; } /* set start address */ e->env_tf.tf_eip = start_text_addr; } /* if dynamic, then make sure shared library is available */ else if (dynamic) { struct stat sb; /* If flag so indicates, then require RO copy and use in mem version */ if (!(flags & _EXEC_SHLIB_ONLY)) { /* if the shared library is not already in memory, or if it's old */ /* then we need to (re)read it in */ if (stat(PATH_LIBEXOS, &sb)) { r = -errno; kprintf("error stat'ing sl: %d\n", errno); goto err; } /* if we don't have a RO copy or it's out of date... */ if (!isvamapped(SHARED_LIBRARY_START_RODATA) || memcmp(&sl_data->mod_time, &sb.st_mtimespec, sizeof(sb.st_mtimespec))) { int slfd; /* if it's out of date, then unmap it */ if (isvamapped(SHARED_LIBRARY_START_RODATA)) munmap((void*)SHARED_LIBRARY_START_RODATA, (sl_data->text_pages + sl_data->data_pages) * NBPG); slfd = open (PATH_LIBEXOS, O_RDONLY); if (slfd < 0) { r = -errno; kprintf("could not open shared library " PATH_LIBEXOS "\n"); goto err; } if ((r = __load_sl_image (slfd)) < 0) { kprintf("could not load library\n"); close(slfd); goto err; } *((struct timespec*)&sl_data->mod_time) = sb.st_mtimespec; assert(sys_self_mod_pte_range(0, PG_RO, PG_W, SHARED_LIBRARY_START_RODATA, 1) == 0); close (slfd); } } else { if (!isvamapped(SHARED_LIBRARY_START_RODATA)) { r = -EINVAL; goto err; } } /* share the text region read only/exec into child */ if (__vm_share_region(SHARED_LIBRARY_START_RODATA, sl_data->text_pages * NBPG, 0, 0, envid, SHARED_LIBRARY_START)) { kprintf ("__vm_share_region failed for text region\n"); r = -ENOEXEC; goto err; } /* share the read only data region into child cow */ if (__vm_share_region(SHARED_LIBRARY_START_RODATA + sl_data->text_pages * NBPG, sl_data->data_pages * NBPG, 0, 0, envid, SHARED_LIBRARY_START + sl_data->text_pages * NBPG)) { kprintf ("__vm_share_region failed for cow data region\n"); r = -ENOEXEC; goto err; } if (sys_mod_pte_range(0, PG_COW, PG_RO | PG_SHARED, SHARED_LIBRARY_START + sl_data->text_pages * NBPG, sl_data->data_pages, 0, envid) < 0) { kprintf ("sys_mod_pte_range failed for cow data region\n"); r = -ENOEXEC; goto err; } /* share the RO copy of the shared library */ if (__vm_share_region(SHARED_LIBRARY_START_RODATA, (sl_data->text_pages + sl_data->data_pages) * NBPG, 0, 0, envid, SHARED_LIBRARY_START_RODATA)) { kprintf ("__vm_share_region failed for read only text/data region\n"); r = -ENOEXEC; goto err; } /* demand alloc bss for sl or no? */ if (getenv("NO_BSS_DEMAND_ALLOC")) { /* zero the bss */ if (__zero_segment (envid, SHARED_LIBRARY_START + (sl_data->text_pages + sl_data->data_pages) * NBPG, sl_data->bss_pages * NBPG) < 0) { kprintf("could not create bss segment\n"); r = -ENOEXEC; goto err; } } /* otherwise the fault handler will deal with it */ /* set start address */ e->env_tf.tf_eip = SHARED_LIBRARY_START + sizeof(struct exec); } /* take care of args, etc */ if (flags & _EXEC_USE_FD) eea.eea_prog_fd = fd; else eea.eea_prog_fd = -1; if ((r = setup_new_stack(argv, envp, envid, &e->env_tf.tf_esp, &eea)) < 0) goto err; return 1; err: return r; }
static int setup_new_stack_simple(char *const argv[], char *const env[], u_int envid, u_int *newesp) { int len=0, argc=0, envc=0, pages_needed, i; void *pages; u_int p; char **argvstr; char **envstr; if (!argv || !env) return -EFAULT; /* figure out how much we'll be putting on the new stack */ /* size of new args */ while (argv[argc]) len += strlen(argv[argc++])+1; /* size of env vars */ while (env[envc]) len += strlen(env[envc++])+1; /* for the pointers to the args' null termination */ len += (argc + 1) * sizeof(void*); /* for the pointers to the env vars' null termination */ len += (envc + 1) * sizeof(void*); /* leave a space argc */ len += sizeof(int); /* leave a space for argv */ len += sizeof(char*); /* leave a space for env */ len += sizeof(char*); len = ALIGN(len); /* calculate how many pages we need, and always allocate at least 1 page */ pages_needed = PGNO(PGROUNDUP(len))+1; pages = __malloc(pages_needed*NBPG); if (!pages) return -ENOMEM; /* now we put things on the page */ p = (u_int)pages + pages_needed*NBPG - len; /* first, the argc */ *(int*)p = argc; p += sizeof(int); /* then, the argv pointer */ *(int*)p = (USTACKTOP - ((u_int)pages + pages_needed*NBPG - (p+sizeof(char*)+sizeof(char*)))); p += sizeof(char*); /* then, the env pointer */ *(int*)p = (USTACKTOP - ((u_int)pages + pages_needed*NBPG - (p+sizeof(char*)+(argc+1)*sizeof(char*)))); p += sizeof(char*); /* now, all the pointers to arguments */ argvstr = (char**)p; p += (argc+1)*sizeof(char*); /* then, all the pointers to env vars */ envstr = (char**)p; p += (envc+1)*sizeof(char*); /* copy in arguments, set up pointers to arguments */ for (i=0; i < argc; i++) { argvstr[i] = (char*)(USTACKTOP - ((u_int)pages + pages_needed*NBPG - p)); strcpy((char*)p, argv[i]); p += strlen(argv[i])+1; } argvstr[argc] = NULL; /* copy in env variables, set up pointers to env vars */ for (i=0; i < envc; i++) { envstr[i] = (char*)(USTACKTOP - ((u_int)pages + pages_needed*NBPG - p)); strcpy((char*)p, env[i]); p += strlen(env[i])+1; } envstr[envc] = NULL; /* now map the pages into the new process */ *(char*)pages = 0; if (__vm_share_region((u_int)pages, pages_needed*NBPG, 0, 0, envid, USTACKTOP-pages_needed*NBPG) == -1 || __vm_free_region((u_int)pages, pages_needed*NBPG, 0) == -1) { __free(pages); return -ENOMEM; } __free(pages); /* dude, this is totally a GCC thing: gcc convention says when starting * a program first argument is esp+4. That's the -4 here */ *newesp = USTACKTOP - len - 4; return 0; }
static int setup_new_stack(char *const argv[], char *const env[], u_int envid, u_int *newesp, struct _exos_exec_args *eea) { int len=0, envsize=0, argsize=0, argc=0, envc=0, pages_needed, i; void *pages; u_int p, padding, reserved_start; struct ps_strings *ps; char **argvstr, **envstr; /* XXX - sanity check ponters */ if (!argv || !env) return -EFAULT; /* figure out how much we'll be putting on the new stack */ len += sizeof(struct ps_strings); len = ALIGN(len); len += sizeof(struct _exos_exec_args); len = ALIGN(len); /* the reserved (mapped, but unused) pages */ padding = PGROUNDUP(len) - len; len += padding; len += NBPG * __RESERVED_PAGES; reserved_start = len; /* size of new args */ while (argv[argc]) argsize += strlen(argv[argc++])+1; /* size of new environment */ while (env[envc]) envsize += strlen(env[envc++])+1; len += envsize + argsize; len = ALIGN(len); /* for the pointers to the args & envs and their null termination */ len += (envc + 1 + argc + 1) * sizeof(void*); len += sizeof(int); /* the argc */ /* extra page so child has at least one totally free stack page */ pages_needed = PGNO(PGROUNDUP(len)) + 1; pages = __malloc(pages_needed*NBPG); if (!pages) return -ENOMEM; p = (u_int)pages + pages_needed*NBPG - len; *(int*)p = argc; p += sizeof(int); argvstr = (char**)p; p += (argc+1)*sizeof(char*); envstr = (char**)p; p += (envc+1)*sizeof(char*); for (i=0; i < argc; i++) { strcpy((char*)p, argv[i]); argvstr[i] = (char*)(USTACKTOP - ((u_int)pages + pages_needed*NBPG - p)); p += strlen(argv[i])+1; } argvstr[argc] = NULL; for (i=0; i < envc; i++) { strcpy((char*)p, env[i]); envstr[i] = (char*)(USTACKTOP - ((u_int)pages + pages_needed*NBPG - p)); p += strlen(env[i])+1; } envstr[envc] = NULL; /* map (via touching) the reserved pages */ for (i=0; i < __RESERVED_PAGES; i++) { *(u_int*)p = 0; p += NBPG; } p += padding; /* continue... */ eea->eea_reserved_pages = __RESERVED_PAGES; eea->eea_reserved_first = (char*)(USTACKTOP - reserved_start); p = ALIGN(p); *(struct _exos_exec_args*)p = *eea; p += sizeof(struct _exos_exec_args); p = ALIGN(p); ps = (struct ps_strings*)p; ps->ps_argvstr = (char**)(USTACKTOP - ((u_int)pages + pages_needed*NBPG - (u_int)argvstr)); ps->ps_nargvstr = argc; ps->ps_envstr = (char**)(USTACKTOP - ((u_int)pages + pages_needed*NBPG - (u_int)envstr)); ps->ps_nenvstr = envc; /* now map the pages into the new process */ /* XXX - touch clean page so it'll be mapped */ *(char*)pages = 0; if (__vm_share_region((u_int)pages, pages_needed*NBPG, 0, 0, envid, USTACKTOP-pages_needed*NBPG) == -1 || __vm_free_region((u_int)pages, pages_needed*NBPG, 0) == -1) { __free(pages); return -ENOMEM; } __free(pages); *newesp = USTACKTOP - len; return 0; }