diff options
author | Benji Dial <benji6283@gmail.com> | 2020-09-06 00:48:07 -0400 |
---|---|---|
committer | Benji Dial <benji6283@gmail.com> | 2020-09-06 00:48:07 -0400 |
commit | e8c6577617bffa4402c07c7aa20e3c24f03c1c20 (patch) | |
tree | 2fb9230b62d2344a44453117de9e656892219788 /src/kernel/elf.c | |
parent | 7ff724fe8f709440da9c730fdb8dcbaa4f989ed5 (diff) | |
download | portland-os-e8c6577617bffa4402c07c7aa20e3c24f03c1c20.tar.gz |
program loading, others
big kernel additions: paging, elf loading, separate kernel and user page allocation
it now properly loads and runs sd0:bin/init.elf
still need to determine which disk was booted from, and start the init on that disk
Diffstat (limited to 'src/kernel/elf.c')
-rw-r--r-- | src/kernel/elf.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/kernel/elf.c b/src/kernel/elf.c new file mode 100644 index 0000000..8cd659c --- /dev/null +++ b/src/kernel/elf.c @@ -0,0 +1,116 @@ +#include <stdint.h> +#include "drive.h" +#include "elf.h" +#include "task.h" +#include "util.h" +#include "paging.h" +#include "pmap.h" + +#define ELF_MAGIC 0x464c457f + +enum { + ELF_32 = 1, + ELF_64 = 2 +}; + +enum { + LITTLE_ENDIAN = 1, + BIG_ENDIAN = 2 +}; + +enum { + //... + ARCH_X86 = 0x03 + //... +}; + +struct elf_header { + uint32_t magic; + uint8_t word_size; + uint8_t endianness; + uint8_t elf_version; + uint8_t target_os;//ignored + uint8_t os_abi_version;//should be zero + uint8_t reserved[7]; + uint16_t object_type;//TODO + uint16_t architecture;//should be ARCH_X86 + uint32_t elf_version_2; + uint32_t entry_vma; + uint32_t phtable_fa; + uint32_t shtable_fa; + uint32_t flags; + uint16_t eh_size; + uint16_t phentry_size; + uint16_t phtable_count; + uint16_t shentry_size; + uint16_t shtable_count; + uint16_t sh_names_entry; +} __attribute__ ((packed)); + +enum { + PT_UNUSED = 0, + PT_LOADME = 1, + PT_DYNLINK = 2, + PT_INTERP = 3, + PT_COMMENT = 4, + PT_SHARED = 5, + PT_PHTABLE = 6, + PT_TL_TMPL = 7 +}; + +enum { + PH_WRITABLE = 0x02 +}; + +struct ph_entry { + uint32_t type; + uint32_t fa; + uint32_t vma;//must be page-aligned + uint32_t pma;//ignored + uint32_t fs; + uint32_t vms; + uint32_t flags; + uint32_t align; +} __attribute__ ((packed)); + +bool try_elf_run(const struct drive *d, const char *path) { + file_id_t h = d->get_file(d, path); + if (!h) + return false; + + struct elf_header ehead; + + fmcpy(&ehead, d, h, 0, sizeof(struct elf_header)); + + if ((ehead.magic != ELF_MAGIC) || + (ehead.word_size != ELF_32) || + (ehead.endianness != LITTLE_ENDIAN) || + ehead.os_abi_version) { + d->free_file(d, h); + return false; + } + + uint32_t phtable_size = ehead.phentry_size * ehead.phtable_count; + uint16_t phtable_pages = (phtable_size - 1) / 4096 + 1; + + void *phtable = allocate_kernel_pages(phtable_pages); + fmcpy(phtable, d, h, ehead.phtable_fa, phtable_size); + + void *pd = new_task_pd(); + + for (uint32_t phi = 0; phi < ehead.phtable_count; ++phi) { + struct ph_entry *entry = phtable + phi * ehead.phentry_size; + if (entry->type != PT_LOADME) + continue; + void *pma = pd_user_allocate(pd, entry->vma, (entry->vms - 1) / 4096 + 1, entry->flags & PH_WRITABLE); + fmcpy(pma, d, h, entry->fa, entry->fs); + } + + free_pages(phtable, phtable_pages); + + struct task_state tstate; + tstate.page_directory = pd; + tstate.ret_addr = ehead.entry_vma; + new_task(tstate); + return true; +}
\ No newline at end of file |