#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, const char *pass_old_vma) { 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); const char *pass = vma_to_pma(active_task->page_directory, pass_old_vma); uint32_t pass_l = 0; while (pass[pass_l++]) ; void *pass_vma; void *pass_pma; user_allocate_anywhere_readonly_together(pd, ((pass_l - 1) >> 12) + 1, &pass_vma, &pass_pma); //TODO: handle error condition memcpy(pass_pma, pass, pass_l); struct task_state tstate; tstate.page_directory = pd; tstate.ret_addr = ehead.entry_vma; tstate.edx = (uint32_t)pass_vma; const char *path_end_start = path; for (const char *i = path; *i; ++i) if (*i == '/') path_end_start = i + 1; uint8_t i; for (i = 0; i < TASK_NAME_LEN; ++i) { if (!path_end_start[i]) break; tstate.name[i] = path_end_start[i]; } tstate.name[i] = '\0'; new_task(tstate); return true; }