diff options
author | peter <peter@FreeBSD.org> | 2002-07-20 02:56:12 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2002-07-20 02:56:12 +0000 |
commit | cc7b2e42482d2eb35468c5dd11903248b12692b2 (patch) | |
tree | 442882c197085f1177ad99039e6387b24c60e44a /sys/kern | |
parent | c458732bcf221adf5c81f68d8d9044444c901a54 (diff) | |
download | FreeBSD-src-cc7b2e42482d2eb35468c5dd11903248b12692b2.zip FreeBSD-src-cc7b2e42482d2eb35468c5dd11903248b12692b2.tar.gz |
Infrastructure tweaks to allow having both an Elf32 and an Elf64 executable
handler in the kernel at the same time. Also, allow for the
exec_new_vmspace() code to build a different sized vmspace depending on
the executable environment. This is a big help for execing i386 binaries
on ia64. The ELF exec code grows the ability to map partial pages when
there is a page size difference, eg: emulating 4K pages on 8K or 16K
hardware pages.
Flesh out the i386 emulation support for ia64. At this point, the only
binary that I know of that fails is cvsup, because the cvsup runtime
tries to execute code in pages not marked executable.
Obtained from: dfr (mostly, many tweaks from me).
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/imgact_aout.c | 2 | ||||
-rw-r--r-- | sys/kern/imgact_elf.c | 455 | ||||
-rw-r--r-- | sys/kern/imgact_elf32.c | 38 | ||||
-rw-r--r-- | sys/kern/imgact_elf64.c | 38 | ||||
-rw-r--r-- | sys/kern/imgact_elfN.c | 51 | ||||
-rw-r--r-- | sys/kern/imgact_gzip.c | 2 | ||||
-rw-r--r-- | sys/kern/init_main.c | 9 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 29 |
8 files changed, 466 insertions, 158 deletions
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c index 16629d1..b13837e 100644 --- a/sys/kern/imgact_aout.c +++ b/sys/kern/imgact_aout.c @@ -178,7 +178,7 @@ exec_aout_imgact(imgp) /* * Destroy old process VM and create a new one (with a new stack) */ - exec_new_vmspace(imgp); + exec_new_vmspace(imgp, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS, USRSTACK); /* * The vm space can be changed by exec_new_vmspace diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index f2e1afc..1b35000 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -70,59 +70,30 @@ __ElfType(Brandinfo); __ElfType(Auxargs); -static int elf_check_header(const Elf_Ehdr *hdr); -static int elf_freebsd_fixup(register_t **stack_base, - struct image_params *imgp); -static int elf_load_file(struct proc *p, const char *file, u_long *addr, - u_long *entry); -static int elf_load_section(struct proc *p, +static int __elfN(check_header)(const Elf_Ehdr *hdr); +static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr, + u_long *entry, size_t pagesize); +static int __elfN(load_section)(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_object_t object, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, - vm_prot_t prot); -static int exec_elf_imgact(struct image_params *imgp); + vm_prot_t prot, size_t pagesize); +static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp); static int elf_trace = 0; -SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); - -struct sysentvec elf_freebsd_sysvec = { - SYS_MAXSYSCALL, - sysent, - 0, - 0, - 0, - 0, - 0, - 0, - elf_freebsd_fixup, - sendsig, - sigcode, - &szsigcode, - 0, - "FreeBSD ELF", - elf_coredump, - NULL, - MINSIGSTKSZ -}; +#if __ELF_WORD_SIZE == 32 +SYSCTL_INT(_debug, OID_AUTO, elf32_trace, CTLFLAG_RW, &elf_trace, 0, ""); +#else +SYSCTL_INT(_debug, OID_AUTO, elf64_trace, CTLFLAG_RW, &elf_trace, 0, ""); +#endif -static Elf_Brandinfo freebsd_brand_info = { - ELFOSABI_FREEBSD, - "FreeBSD", - "", - "/usr/libexec/ld-elf.so.1", - &elf_freebsd_sysvec - }; -static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { - &freebsd_brand_info, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL - }; +static Elf_Brandinfo *elf_brand_list[MAX_BRANDS]; int -elf_insert_brand_entry(Elf_Brandinfo *entry) +__elfN(insert_brand_entry)(Elf_Brandinfo *entry) { int i; - for (i=1; i<MAX_BRANDS; i++) { + for (i=0; i<MAX_BRANDS; i++) { if (elf_brand_list[i] == NULL) { elf_brand_list[i] = entry; break; @@ -134,11 +105,11 @@ elf_insert_brand_entry(Elf_Brandinfo *entry) } int -elf_remove_brand_entry(Elf_Brandinfo *entry) +__elfN(remove_brand_entry)(Elf_Brandinfo *entry) { int i; - for (i=1; i<MAX_BRANDS; i++) { + for (i=0; i<MAX_BRANDS; i++) { if (elf_brand_list[i] == entry) { elf_brand_list[i] = NULL; break; @@ -150,7 +121,7 @@ elf_remove_brand_entry(Elf_Brandinfo *entry) } int -elf_brand_inuse(Elf_Brandinfo *entry) +__elfN(brand_inuse)(Elf_Brandinfo *entry) { struct proc *p; int rval = FALSE; @@ -168,25 +139,165 @@ elf_brand_inuse(Elf_Brandinfo *entry) } static int -elf_check_header(const Elf_Ehdr *hdr) +__elfN(check_header)(const Elf_Ehdr *hdr) { + int i; + if (!IS_ELF(*hdr) || hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || hdr->e_ident[EI_DATA] != ELF_TARG_DATA || hdr->e_ident[EI_VERSION] != EV_CURRENT) return ENOEXEC; - if (!ELF_MACHINE_OK(hdr->e_machine)) + /* + * Make sure we have at least one brand for this machine. + */ + + for (i=0; i<MAX_BRANDS; i++) { + if (elf_brand_list[i]->machine == hdr->e_machine) + break; + } + if (i == MAX_BRANDS) return ENOEXEC; if (hdr->e_version != ELF_TARG_VER) return ENOEXEC; - + return 0; } static int -elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_object_t object, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) +__elfN(map_partial)(vm_map_t map, vm_object_t object, vm_ooffset_t offset, + vm_offset_t start, vm_offset_t end, vm_prot_t prot, + vm_prot_t max) +{ + int error, rv; + vm_offset_t off; + vm_offset_t data_buf = 0; + + /* + * Create the page if it doesn't exist yet. Ignore errors. + */ + vm_map_lock(map); + vm_map_insert(map, NULL, 0, trunc_page(start), round_page(end), + max, max, 0); + vm_map_unlock(map); + + /* + * Find the page from the underlying object. + */ + if (object) { + vm_object_reference(object); + rv = vm_map_find(exec_map, + object, + trunc_page(offset), + &data_buf, + PAGE_SIZE, + TRUE, + VM_PROT_READ, + VM_PROT_ALL, + MAP_COPY_ON_WRITE | MAP_PREFAULT_PARTIAL); + if (rv != KERN_SUCCESS) { + vm_object_deallocate(object); + return rv; + } + + off = offset - trunc_page(offset); + error = copyout((caddr_t)data_buf+off, (caddr_t)start, end - start); + vm_map_remove(exec_map, data_buf, data_buf + PAGE_SIZE); + if (error) { + return KERN_FAILURE; + } + } + + return KERN_SUCCESS; +} + +static int +__elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset, + vm_offset_t start, vm_offset_t end, vm_prot_t prot, + vm_prot_t max, int cow) +{ + int rv; + + if (start != trunc_page(start)) { + rv = __elfN(map_partial)(map, object, offset, + start, round_page(start), prot, max); + if (rv) + return rv; + offset += round_page(start) - start; + start = round_page(start); + } + if (end != round_page(end)) { + rv = __elfN(map_partial)(map, object, + offset + trunc_page(end) - start, + trunc_page(end), end, prot, max); + if (rv) + return rv; + end = trunc_page(end); + } + if (end > start) { + if (offset & PAGE_MASK) { + vm_offset_t data_buf, off; + vm_size_t sz; + int error; + + /* + * The mapping is not page aligned. This means we have + * to copy the data. Sigh. + */ + rv = vm_map_find(map, 0, 0, + &start, end - start, + FALSE, prot, max, 0); + if (rv) + return rv; + while (start < end) { + vm_object_reference(object); + rv = vm_map_find(exec_map, + object, + trunc_page(offset), + &data_buf, + 2*PAGE_SIZE, + TRUE, + VM_PROT_READ, + VM_PROT_ALL, + (MAP_COPY_ON_WRITE + | MAP_PREFAULT_PARTIAL)); + if (rv != KERN_SUCCESS) { + vm_object_deallocate(object); + return rv; + } + off = offset - trunc_page(offset); + sz = end - start; + if (sz > PAGE_SIZE) + sz = PAGE_SIZE; + error = copyout((caddr_t)data_buf+off, + (caddr_t)start, sz); + vm_map_remove(exec_map, data_buf, + data_buf + 2*PAGE_SIZE); + if (error) { + return KERN_FAILURE; + } + start += sz; + } + rv = KERN_SUCCESS; + } else { + vm_map_lock(map); + rv = vm_map_insert(map, object, offset, start, end, + prot, max, cow); + vm_map_unlock(map); + } + return rv; + } else { + return KERN_SUCCESS; + } +} + +static int +__elfN(load_section)(struct proc *p, struct vmspace *vmspace, + struct vnode *vp, vm_object_t object, vm_offset_t offset, + caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot, + size_t pagesize) { size_t map_len; vm_offset_t map_addr; @@ -214,8 +325,11 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_o return (ENOEXEC); } - map_addr = trunc_page((vm_offset_t)vmaddr); - file_addr = trunc_page(offset); +#define trunc_page_ps(va, ps) ((va) & ~(ps - 1)) +#define round_page_ps(va, ps) (((va) + (ps - 1)) & ~(ps - 1)) + + map_addr = trunc_page_ps((vm_offset_t)vmaddr, pagesize); + file_addr = trunc_page_ps(offset, pagesize); /* * We have two choices. We can either clear the data in the last page @@ -224,14 +338,13 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_o * choose the second.. */ if (memsz > filsz) - map_len = trunc_page(offset+filsz) - file_addr; + map_len = trunc_page_ps(offset+filsz, pagesize) - file_addr; else - map_len = round_page(offset+filsz) - file_addr; + map_len = round_page_ps(offset+filsz, pagesize) - file_addr; if (map_len != 0) { vm_object_reference(object); - vm_map_lock(&vmspace->vm_map); - rv = vm_map_insert(&vmspace->vm_map, + rv = __elfN(map_insert)(&vmspace->vm_map, object, file_addr, /* file offset */ map_addr, /* virtual start */ @@ -239,7 +352,6 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_o prot, VM_PROT_ALL, MAP_COPY_ON_WRITE | MAP_PREFAULT); - vm_map_unlock(&vmspace->vm_map); if (rv != KERN_SUCCESS) { vm_object_deallocate(object); return EINVAL; @@ -258,26 +370,25 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_o * segment in the file is extended to provide bss. It's a neat idea * to try and save a page, but it's a pain in the behind to implement. */ - copy_len = (offset + filsz) - trunc_page(offset + filsz); - map_addr = trunc_page((vm_offset_t)vmaddr + filsz); - map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr; + copy_len = (offset + filsz) - trunc_page_ps(offset + filsz, pagesize); + map_addr = trunc_page_ps((vm_offset_t)vmaddr + filsz, pagesize); + map_len = round_page_ps((vm_offset_t)vmaddr + memsz, pagesize) - map_addr; /* This had damn well better be true! */ - if (map_len != 0) { - vm_map_lock(&vmspace->vm_map); - rv = vm_map_insert(&vmspace->vm_map, NULL, 0, - map_addr, map_addr + map_len, - VM_PROT_ALL, VM_PROT_ALL, 0); - vm_map_unlock(&vmspace->vm_map); + if (map_len != 0) { + rv = __elfN(map_insert)(&vmspace->vm_map, NULL, 0, + map_addr, map_addr + map_len, + VM_PROT_ALL, VM_PROT_ALL, 0); if (rv != KERN_SUCCESS) { - return EINVAL; + return EINVAL; } } if (copy_len != 0) { + vm_offset_t off; vm_object_reference(object); rv = vm_map_find(exec_map, - object, + object, trunc_page(offset + filsz), &data_buf, PAGE_SIZE, @@ -291,7 +402,10 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_o } /* send the page fragment to user space */ - error = copyout((caddr_t)data_buf, (caddr_t)map_addr, copy_len); + off = trunc_page_ps(offset + filsz, pagesize) + - trunc_page(offset + filsz); + error = copyout((caddr_t)data_buf+off, (caddr_t)map_addr, + copy_len); vm_map_remove(exec_map, data_buf, data_buf + PAGE_SIZE); if (error) { return (error); @@ -299,10 +413,11 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_o } /* - * set it to the specified protection + * set it to the specified protection. + * XXX had better undo the damage from pasting over the cracks here! */ - vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, - FALSE); + vm_map_protect(&vmspace->vm_map, trunc_page(map_addr), + round_page(map_addr + map_len), prot, FALSE); return error; } @@ -320,7 +435,8 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_o * the entry point for the loaded file. */ static int -elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) +__elfN(load_file)(struct proc *p, const char *file, u_long *addr, + u_long *entry, size_t pagesize) { struct { struct nameidata nd; @@ -363,8 +479,8 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) } /* XXXKSE */ - NDINIT(nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, curthread); - + NDINIT(nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, curthread); + if ((error = namei(nd)) != 0) { nd->ni_vp = NULL; goto fail; @@ -393,10 +509,10 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) VOP_UNLOCK(nd->ni_vp, 0, curthread); /* XXXKSE */ if (error) - goto fail; + goto fail; hdr = (const Elf_Ehdr *)imgp->image_header; - if ((error = elf_check_header(hdr)) != 0) + if ((error = __elfN(check_header)(hdr)) != 0) goto fail; if (hdr->e_type == ET_DYN) rbase = *addr; @@ -426,13 +542,14 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) if (phdr[i].p_flags & PF_R) prot |= VM_PROT_READ; - if ((error = elf_load_section(p, vmspace, nd->ni_vp, - imgp->object, - phdr[i].p_offset, - (caddr_t)phdr[i].p_vaddr + - rbase, - phdr[i].p_memsz, - phdr[i].p_filesz, prot)) != 0) + if ((error = __elfN(load_section) + (p, vmspace, nd->ni_vp, + imgp->object, + phdr[i].p_offset, + (caddr_t)(uintptr_t)phdr[i].p_vaddr + + rbase, + phdr[i].p_memsz, + phdr[i].p_filesz, prot, pagesize)) != 0) goto fail; /* * Establish the base address if this is the @@ -463,20 +580,10 @@ fail: return error; } -/* - * non static, as it can be overridden by start_init() - */ -#ifdef __ia64__ -int fallback_elf_brand = ELFOSABI_FREEBSD; -#else -int fallback_elf_brand = -1; -#endif -SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, - &fallback_elf_brand, -1, - "ELF brand of last resort"); +extern int fallback_elf_brand; static int -exec_elf_imgact(struct image_params *imgp) +__CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) { const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; const Elf_Phdr *phdr; @@ -486,6 +593,7 @@ exec_elf_imgact(struct image_params *imgp) u_long text_size = 0, data_size = 0; u_long text_addr = 0, data_addr = 0; u_long addr, entry = 0, proghdr = 0; + vm_offset_t maxuser, usrstack, pagesize; int error, i; const char *interp = NULL; Elf_Brandinfo *brand_info; @@ -496,7 +604,7 @@ exec_elf_imgact(struct image_params *imgp) /* * Do we have a valid ELF header ? */ - if (elf_check_header(hdr) != 0 || hdr->e_type != ET_EXEC) + if (__elfN(check_header)(hdr) != 0 || hdr->e_type != ET_EXEC) return -1; /* @@ -510,7 +618,7 @@ exec_elf_imgact(struct image_params *imgp) return ENOEXEC; } phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff); - + /* * From this point on, we may have resources that need to be freed. */ @@ -528,7 +636,38 @@ exec_elf_imgact(struct image_params *imgp) if ((error = exec_extract_strings(imgp)) != 0) goto fail; - exec_new_vmspace(imgp); + /* + * Tentatively identify the brand based on the machine so that + * we can figure out VM ranges and page sizes. + */ + brand_info = NULL; + for (i = 0; i < MAX_BRANDS; i++) { + Elf_Brandinfo *bi = elf_brand_list[i]; + + if (bi != NULL && + hdr->e_machine == bi->machine && + (hdr->e_ident[EI_OSABI] == bi->brand + || 0 == + strncmp((const char *)&hdr->e_ident[OLD_EI_BRAND], + bi->compat_3_brand, strlen(bi->compat_3_brand)))) { + brand_info = bi; + break; + } + } + + pagesize = PAGE_SIZE; + maxuser = VM_MAXUSER_ADDRESS; + usrstack = USRSTACK; + if (brand_info) { + if (brand_info->sysvec->sv_pagesize) + pagesize = brand_info->sysvec->sv_pagesize; + if (brand_info->sysvec->sv_maxuser) + maxuser = brand_info->sysvec->sv_maxuser; + if (brand_info->sysvec->sv_usrstack) + usrstack = brand_info->sysvec->sv_usrstack; + } + + exec_new_vmspace(imgp, VM_MIN_ADDRESS, maxuser, usrstack); vmspace = imgp->proc->p_vmspace; @@ -544,13 +683,23 @@ exec_elf_imgact(struct image_params *imgp) if (phdr[i].p_flags & PF_R) prot |= VM_PROT_READ; - if ((error = elf_load_section(imgp->proc, - vmspace, imgp->vp, - imgp->object, - phdr[i].p_offset, - (caddr_t)phdr[i].p_vaddr, - phdr[i].p_memsz, - phdr[i].p_filesz, prot)) != 0) +#if defined(__ia64__) && __ELF_WORD_SIZE == 32 && defined(IA32_ME_HARDER) + /* + * Some x86 binaries assume read == executable, + * notably the M3 runtime and therefore cvsup + */ + if (prot & VM_PROT_READ) + prot |= VM_PROT_EXECUTE; +#endif + + if ((error = __elfN(load_section) + (imgp->proc, + vmspace, imgp->vp, + imgp->object, + phdr[i].p_offset, + (caddr_t)(uintptr_t)phdr[i].p_vaddr, + phdr[i].p_memsz, + phdr[i].p_filesz, prot, pagesize)) != 0) goto fail; /* @@ -611,10 +760,11 @@ exec_elf_imgact(struct image_params *imgp) for (i = 0; i < MAX_BRANDS; i++) { Elf_Brandinfo *bi = elf_brand_list[i]; - if (bi != NULL && + if (bi != NULL && + hdr->e_machine == bi->machine && (hdr->e_ident[EI_OSABI] == bi->brand - || 0 == - strncmp((const char *)&hdr->e_ident[OLD_EI_BRAND], + || 0 == + strncmp((const char *)&hdr->e_ident[OLD_EI_BRAND], bi->compat_3_brand, strlen(bi->compat_3_brand)))) { brand_info = bi; break; @@ -628,6 +778,7 @@ exec_elf_imgact(struct image_params *imgp) Elf_Brandinfo *bi = elf_brand_list[i]; if (bi != NULL && + hdr->e_machine == bi->machine && strcmp(interp, bi->interp_path) == 0) { brand_info = bi; break; @@ -640,7 +791,9 @@ exec_elf_imgact(struct image_params *imgp) for (i = 0; i < MAX_BRANDS; i++) { Elf_Brandinfo *bi = elf_brand_list[i]; - if (bi != NULL && fallback_elf_brand == bi->brand) { + if (bi != NULL && + hdr->e_machine == bi->machine && + fallback_elf_brand == bi->brand) { brand_info = bi; break; } @@ -657,17 +810,19 @@ exec_elf_imgact(struct image_params *imgp) imgp->proc->p_sysent = brand_info->sysvec; if (interp != NULL) { path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); - snprintf(path, MAXPATHLEN, "%s%s", + snprintf(path, MAXPATHLEN, "%s%s", brand_info->emul_path, interp); - if ((error = elf_load_file(imgp->proc, path, &addr, - &imgp->entry_addr)) != 0) { - if ((error = elf_load_file(imgp->proc, interp, &addr, - &imgp->entry_addr)) != 0) { - uprintf("ELF interpreter %s not found\n", path); + if ((error = __elfN(load_file)(imgp->proc, path, &addr, + &imgp->entry_addr, + pagesize)) != 0) { + if ((error = __elfN(load_file) + (imgp->proc, interp, &addr, + &imgp->entry_addr, pagesize)) != 0) { + uprintf("ELF interpreter %s not found\n", path); free(path, M_TEMP); goto fail; } - } + } free(path, M_TEMP); } @@ -692,13 +847,23 @@ fail: return error; } -static int -elf_freebsd_fixup(register_t **stack_base, struct image_params *imgp) +#if __ELF_WORD_SIZE == 32 +#define suword suword32 +#define stacktype u_int32_t +#else +#define suword suword64 +#define stacktype u_int64_t +#endif + +int +__elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp) { Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; - register_t *pos; + stacktype *base; + stacktype *pos; - pos = *stack_base + (imgp->argc + imgp->envc + 2); + base = (stacktype *)*stack_base; + pos = base + (imgp->argc + imgp->envc + 2); if (args->trace) { AUXARGS_ENTRY(pos, AT_DEBUG, 1); @@ -718,10 +883,11 @@ elf_freebsd_fixup(register_t **stack_base, struct image_params *imgp) free(imgp->auxargs, M_TEMP); imgp->auxargs = NULL; - (*stack_base)--; - suword(*stack_base, (long) imgp->argc); + base--; + suword(base, (long) imgp->argc); + *stack_base = (register_t *)base; return 0; -} +} /* * Code for generating ELF core dumps. @@ -744,17 +910,17 @@ struct sseg_closure { static void cb_put_phdr(vm_map_entry_t, void *); static void cb_size_segment(vm_map_entry_t, void *); static void each_writable_segment(struct proc *, segment_callback, void *); -static int elf_corehdr(struct thread *, struct vnode *, struct ucred *, +static int __elfN(corehdr)(struct thread *, struct vnode *, struct ucred *, int, void *, size_t); -static void elf_puthdr(struct proc *, void *, size_t *, +static void __elfN(puthdr)(struct proc *, void *, size_t *, const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int); -static void elf_putnote(void *, size_t *, const char *, int, +static void __elfN(putnote)(void *, size_t *, const char *, int, const void *, size_t); extern int osreldate; int -elf_coredump(td, vp, limit) +__elfN(coredump)(td, vp, limit) struct thread *td; register struct vnode *vp; off_t limit; @@ -777,7 +943,7 @@ elf_coredump(td, vp, limit) * size is calculated. */ hdrsize = 0; - elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize, + __elfN(puthdr)((struct proc *)NULL, (void *)NULL, &hdrsize, (const prstatus_t *)NULL, (const prfpregset_t *)NULL, (const prpsinfo_t *)NULL, seginfo.count); @@ -792,7 +958,7 @@ elf_coredump(td, vp, limit) if (hdr == NULL) { return EINVAL; } - error = elf_corehdr(td, vp, cred, seginfo.count, hdr, hdrsize); + error = __elfN(corehdr)(td, vp, cred, seginfo.count, hdr, hdrsize); /* Write the contents of all of the writable segments. */ if (error == 0) { @@ -803,8 +969,8 @@ elf_coredump(td, vp, limit) php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; offset = hdrsize; for (i = 0; i < seginfo.count; i++) { - error = vn_rdwr_inchunks(UIO_WRITE, vp, - (caddr_t)php->p_vaddr, + error = vn_rdwr_inchunks(UIO_WRITE, vp, + (caddr_t)(uintptr_t)php->p_vaddr, php->p_filesz, offset, UIO_USERSPACE, IO_UNIT | IO_DIRECT, cred, (int *)NULL, curthread); /* XXXKSE */ if (error != 0) @@ -814,7 +980,7 @@ elf_coredump(td, vp, limit) } } free(hdr, M_TEMP); - + return error; } @@ -918,7 +1084,7 @@ each_writable_segment(p, func, closure) * the page boundary. */ static int -elf_corehdr(td, vp, cred, numsegs, hdr, hdrsize) +__elfN(corehdr)(td, vp, cred, numsegs, hdr, hdrsize) struct thread *td; struct vnode *vp; struct ucred *cred; @@ -964,7 +1130,7 @@ elf_corehdr(td, vp, cred, numsegs, hdr, hdrsize) /* Fill in the header. */ bzero(hdr, hdrsize); off = 0; - elf_puthdr(p, hdr, &off, status, fpregset, psinfo, numsegs); + __elfN(puthdr)(p, hdr, &off, status, fpregset, psinfo, numsegs); free(tempdata, M_TEMP); @@ -974,7 +1140,7 @@ elf_corehdr(td, vp, cred, numsegs, hdr, hdrsize) } static void -elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, +__elfN(puthdr)(struct proc *p, void *dst, size_t *off, const prstatus_t *status, const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) { size_t ehoff; @@ -989,11 +1155,11 @@ elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, *off += (numsegs + 1) * sizeof(Elf_Phdr); noteoff = *off; - elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, + __elfN(putnote)(dst, off, "FreeBSD", NT_PRSTATUS, status, sizeof *status); - elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, + __elfN(putnote)(dst, off, "FreeBSD", NT_FPREGSET, fpregset, sizeof *fpregset); - elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, + __elfN(putnote)(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, sizeof *psinfo); notesz = *off - noteoff; @@ -1056,7 +1222,7 @@ elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, } static void -elf_putnote(void *dst, size_t *off, const char *name, int type, +__elfN(putnote)(void *dst, size_t *off, const char *name, int type, const void *desc, size_t descsz) { Elf_Note note; @@ -1078,5 +1244,10 @@ elf_putnote(void *dst, size_t *off, const char *name, int type, /* * Tell kern_execve.c about it, with a little help from the linker. */ -static struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; -EXEC_SET(elf, elf_execsw); +#if __ELF_WORD_SIZE == 32 +static struct execsw elf_execsw = {exec_elf32_imgact, "ELF32"}; +EXEC_SET(elf32, elf_execsw); +#else +static struct execsw elf_execsw = {exec_elf64_imgact, "ELF64"}; +EXEC_SET(elf64, elf_execsw); +#endif diff --git a/sys/kern/imgact_elf32.c b/sys/kern/imgact_elf32.c new file mode 100644 index 0000000..7fd99b7 --- /dev/null +++ b/sys/kern/imgact_elf32.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2002 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * There ought to be a better way of deciding this. + */ +#if defined(__i386__) || defined(__ia64__) || defined(__powerpc__) + +#define __ELF_WORD_SIZE 32 + +#include <kern/imgact_elf.c> + +#endif diff --git a/sys/kern/imgact_elf64.c b/sys/kern/imgact_elf64.c new file mode 100644 index 0000000..ea6d61d --- /dev/null +++ b/sys/kern/imgact_elf64.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2002 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * There ought to be a better way of deciding this. + */ +#if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__) + +#define __ELF_WORD_SIZE 64 + +#include <kern/imgact_elf.c> + +#endif diff --git a/sys/kern/imgact_elfN.c b/sys/kern/imgact_elfN.c new file mode 100644 index 0000000..fd8487f --- /dev/null +++ b/sys/kern/imgact_elfN.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2000 David O'Brien + * Copyright (c) 1995-1996 Søren Schmidt + * Copyright (c) 1996 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> + +#include <machine/elf.h> +#include <sys/elf_generic.h> + +/* + * non static, as it can be overridden by start_init() + */ +#ifdef __ia64__ +int fallback_elf_brand = ELFOSABI_FREEBSD; +#else +int fallback_elf_brand = -1; +#endif +SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, + &fallback_elf_brand, -1, + "ELF brand of last resort"); + diff --git a/sys/kern/imgact_gzip.c b/sys/kern/imgact_gzip.c index 57a5c1d..3268413 100644 --- a/sys/kern/imgact_gzip.c +++ b/sys/kern/imgact_gzip.c @@ -229,7 +229,7 @@ do_aout_hdr(struct imgact_gzip * gz) /* * Destroy old process VM and create a new one (with a new stack) */ - exec_new_vmspace(gz->ip); + exec_new_vmspace(gz->ip, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS, USRSTACK); vmspace = gz->ip->proc->p_vmspace; diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 6817bdc..aa87a18 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -252,6 +252,9 @@ set_boot_verbose(void *data __unused) } SYSINIT(boot_verbose, SI_SUB_TUNABLES, SI_ORDER_ANY, set_boot_verbose, NULL) +static struct sysentvec null_sysvec; + + /* *************************************************************************** **** @@ -317,11 +320,7 @@ proc0_init(void *dummy __unused) session0.s_count = 1; session0.s_leader = p; -#ifdef __ELF__ - p->p_sysent = &elf_freebsd_sysvec; -#else - p->p_sysent = &aout_sysvec; -#endif + p->p_sysent = &null_sysvec; /* * proc_linkup was already done in init_i386() or alphainit() etc. diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index c7df555..2ed3839 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -284,7 +284,10 @@ interpret: /* * Copy out strings (args and env) and initialize stack base */ - stack_base = exec_copyout_strings(imgp); + if (p->p_sysent->sv_copyout_strings) + stack_base = (*p->p_sysent->sv_copyout_strings)(imgp); + else + stack_base = exec_copyout_strings(imgp); /* * If custom stack fixup routine present for this process @@ -471,8 +474,12 @@ interpret: p->p_args = NULL; /* Set values passed into the program in registers. */ - setregs(td, imgp->entry_addr, (u_long)(uintptr_t)stack_base, - imgp->ps_strings); + if (p->p_sysent->sv_setregs) + (*p->p_sysent->sv_setregs)(td, imgp->entry_addr, + (u_long)(uintptr_t)stack_base, imgp->ps_strings); + else + setregs(td, imgp->entry_addr, (u_long)(uintptr_t)stack_base, + imgp->ps_strings); /* Cache arguments if they fit inside our allowance */ if (ps_arg_cache_limit >= i + sizeof(struct pargs)) { @@ -628,17 +635,19 @@ exec_unmap_first_page(imgp) * automatically in trap.c. */ int -exec_new_vmspace(imgp) +exec_new_vmspace(imgp, minuser, maxuser, stack_addr) struct image_params *imgp; + vm_offset_t minuser, maxuser, stack_addr; { int error; struct execlist *ep; struct proc *p = imgp->proc; struct vmspace *vmspace = p->p_vmspace; - vm_offset_t stack_addr = USRSTACK - maxssiz; GIANT_REQUIRED; + stack_addr = stack_addr - maxssiz; + imgp->vmspace_destroyed = 1; /* @@ -652,13 +661,15 @@ exec_new_vmspace(imgp) * otherwise, create a new VM space so that other threads are * not disrupted */ - if (vmspace->vm_refcnt == 1) { + if (vmspace->vm_refcnt == 1 + && vm_map_min(&vmspace->vm_map) == minuser + && vm_map_max(&vmspace->vm_map) == maxuser) { if (vmspace->vm_shm) shmexit(p); - pmap_remove_pages(vmspace_pmap(vmspace), 0, VM_MAXUSER_ADDRESS); - vm_map_remove(&vmspace->vm_map, 0, VM_MAXUSER_ADDRESS); + pmap_remove_pages(vmspace_pmap(vmspace), minuser, maxuser); + vm_map_remove(&vmspace->vm_map, minuser, maxuser); } else { - vmspace_exec(p); + vmspace_exec(p, minuser, maxuser); vmspace = p->p_vmspace; } |