diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2016-03-09 23:58:17 -0800 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2016-03-09 23:58:17 -0800 |
commit | b94c7a4b07f96f24ae7411780abf874416549f7b (patch) | |
tree | b94ca015e49392f52e5abf1209ee184fcf874db4 /pk/elf.c | |
parent | f5a96732cb81571a3ba6b081b8556187d564f678 (diff) | |
download | riscv-pk-b94c7a4b07f96f24ae7411780abf874416549f7b.zip riscv-pk-b94c7a4b07f96f24ae7411780abf874416549f7b.tar.gz riscv-pk-b94c7a4b07f96f24ae7411780abf874416549f7b.tar.bz2 |
Refactor pk, bbl, machine into separate libraries
Yuck.
Diffstat (limited to 'pk/elf.c')
-rw-r--r-- | pk/elf.c | 137 |
1 files changed, 46 insertions, 91 deletions
@@ -1,9 +1,9 @@ // See LICENSE for license details. -#include "file.h" -#include "vm.h" +#include "mmap.h" #include "mtrap.h" #include "boot.h" +#include "bits.h" #include <sys/stat.h> #include <fcntl.h> #include <elf.h> @@ -15,100 +15,55 @@ void load_elf(const char* fn, elf_info* info) if (IS_ERR_VALUE(file)) goto fail; - Elf64_Ehdr eh64; - ssize_t ehdr_size = file_pread(file, &eh64, sizeof(eh64), 0); - if (ehdr_size < (ssize_t)sizeof(eh64) || - !(eh64.e_ident[0] == '\177' && eh64.e_ident[1] == 'E' && - eh64.e_ident[2] == 'L' && eh64.e_ident[3] == 'F')) + Elf_Ehdr eh; + ssize_t ehdr_size = file_pread(file, &eh, sizeof(eh), 0); + if (ehdr_size < (ssize_t)sizeof(eh) || + !(eh.e_ident[0] == '\177' && eh.e_ident[1] == 'E' && + eh.e_ident[2] == 'L' && eh.e_ident[3] == 'F')) goto fail; - uintptr_t min_vaddr = -1, max_vaddr = 0; - - #define LOAD_ELF do { \ - eh = (typeof(eh))&eh64; \ - size_t phdr_size = eh->e_phnum*sizeof(*ph); \ - if (phdr_size > info->phdr_size) \ - goto fail; \ - ssize_t ret = file_pread(file, (void*)info->phdr, phdr_size, eh->e_phoff); \ - if (ret < (ssize_t)phdr_size) \ - goto fail; \ - info->phnum = eh->e_phnum; \ - info->phent = sizeof(*ph); \ - ph = (typeof(ph))info->phdr; \ - info->is_supervisor = (eh->e_entry >> (8*sizeof(eh->e_entry)-1)) != 0; \ - if (info->is_supervisor) \ - info->first_free_paddr = ROUNDUP(info->first_free_paddr, SUPERPAGE_SIZE); \ - for (int i = 0; i < eh->e_phnum; i++) \ - if (ph[i].p_type == PT_LOAD && ph[i].p_memsz && ph[i].p_vaddr < min_vaddr) \ - min_vaddr = ph[i].p_vaddr; \ - if (info->is_supervisor) \ - min_vaddr = ROUNDDOWN(min_vaddr, SUPERPAGE_SIZE); \ - else \ - min_vaddr = ROUNDDOWN(min_vaddr, RISCV_PGSIZE); \ - uintptr_t bias = 0; \ - if (info->is_supervisor || eh->e_type == ET_DYN) \ - bias = info->first_free_paddr - min_vaddr; \ - info->entry = eh->e_entry; \ - if (!info->is_supervisor) { \ - info->entry += bias; \ - min_vaddr += bias; \ - } \ - info->bias = bias; \ - int flags = MAP_FIXED | MAP_PRIVATE; \ - if (info->is_supervisor) \ - flags |= MAP_POPULATE; \ - for (int i = eh->e_phnum - 1; i >= 0; i--) { \ - if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { \ - uintptr_t prepad = ph[i].p_vaddr % RISCV_PGSIZE; \ - uintptr_t vaddr = ph[i].p_vaddr + bias; \ - if (vaddr + ph[i].p_memsz > max_vaddr) \ - max_vaddr = vaddr + ph[i].p_memsz; \ - if (info->is_supervisor) { \ - if (!__valid_user_range(vaddr - prepad, vaddr + ph[i].p_memsz)) \ - goto fail; \ - ret = file_pread(file, (void*)vaddr, ph[i].p_filesz, ph[i].p_offset); \ - if (ret < (ssize_t)ph[i].p_filesz) \ - goto fail; \ - memset((void*)vaddr - prepad, 0, prepad); \ - memset((void*)vaddr + ph[i].p_filesz, 0, ph[i].p_memsz - ph[i].p_filesz); \ - } else { \ - int flags2 = flags | (prepad ? MAP_POPULATE : 0); \ - if (__do_mmap(vaddr - prepad, ph[i].p_filesz + prepad, -1, flags2, file, ph[i].p_offset - prepad) != vaddr - prepad) \ - goto fail; \ - memset((void*)vaddr - prepad, 0, prepad); \ - size_t mapped = ROUNDUP(ph[i].p_filesz + prepad, RISCV_PGSIZE) - prepad; \ - if (ph[i].p_memsz > mapped) \ - if (__do_mmap(vaddr + mapped, ph[i].p_memsz - mapped, -1, flags|MAP_ANONYMOUS, 0, 0) != vaddr + mapped) \ - goto fail; \ - } \ - } \ - } \ - } while(0) - - if (IS_ELF64(eh64)) - { -#ifndef __riscv64 - die("can't run 64-bit ELF on 32-bit arch"); -#endif - Elf64_Ehdr* eh; - Elf64_Phdr* ph; - LOAD_ELF; - } - else if (IS_ELF32(eh64)) - { #ifdef __riscv64 - die("can't run 32-bit ELF on 64-bit arch"); + assert(IS_ELF64(eh)); +#else + assert(IS_ELF32(eh)); #endif - Elf32_Ehdr* eh; - Elf32_Phdr* ph; - LOAD_ELF; - } - else - goto fail; - info->first_user_vaddr = min_vaddr; - info->first_vaddr_after_user = ROUNDUP(max_vaddr - info->bias, RISCV_PGSIZE); - info->brk_min = max_vaddr; + uintptr_t min_vaddr = -1; + size_t phdr_size = eh.e_phnum * sizeof(Elf_Phdr); + if (phdr_size > info->phdr_size) + goto fail; + ssize_t ret = file_pread(file, (void*)info->phdr, phdr_size, eh.e_phoff); + if (ret < (ssize_t)phdr_size) + goto fail; + info->phnum = eh.e_phnum; + info->phent = sizeof(Elf_Phdr); + Elf_Phdr* ph = (typeof(ph))info->phdr; + for (int i = 0; i < eh.e_phnum; i++) + if (ph[i].p_type == PT_LOAD && ph[i].p_memsz && ph[i].p_vaddr < min_vaddr) + min_vaddr = ph[i].p_vaddr; + min_vaddr = ROUNDDOWN(min_vaddr, RISCV_PGSIZE); + uintptr_t bias = 0; + if (eh.e_type == ET_DYN) + bias = first_free_paddr - min_vaddr; + min_vaddr += bias; + info->entry = eh.e_entry + bias; + int flags = MAP_FIXED | MAP_PRIVATE; + for (int i = eh.e_phnum - 1; i >= 0; i--) { + if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { + uintptr_t prepad = ph[i].p_vaddr % RISCV_PGSIZE; + uintptr_t vaddr = ph[i].p_vaddr + bias; + if (vaddr + ph[i].p_memsz > info->brk_min) + info->brk_min = vaddr + ph[i].p_memsz; + int flags2 = flags | (prepad ? MAP_POPULATE : 0); + if (__do_mmap(vaddr - prepad, ph[i].p_filesz + prepad, -1, flags2, file, ph[i].p_offset - prepad) != vaddr - prepad) + goto fail; + memset((void*)vaddr - prepad, 0, prepad); + size_t mapped = ROUNDUP(ph[i].p_filesz + prepad, RISCV_PGSIZE) - prepad; + if (ph[i].p_memsz > mapped) + if (__do_mmap(vaddr + mapped, ph[i].p_memsz - mapped, -1, flags|MAP_ANONYMOUS, 0, 0) != vaddr + mapped) + goto fail; + } + } file_decref(file); return; |