#include #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); d->free_file(d, h); struct task_state tstate; tstate.page_directory = pd; tstate.ret_addr = ehead.entry_vma; new_task(tstate); return true; }