1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
| #include "exec.h" #include "../thread/thread.h" #include "stdio-kernel.h" #include "../fs/fs.h" #include "string.h" #include "global.h" #include "memory.h"
extern void intr_exit(void); typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off; typedef uint16_t Elf32_Half;
struct Elf32_Ehdr { unsigned char e_ident[16]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; };
struct Elf32_Phdr { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; };
enum segment_type { PT_NULL, PT_LOAD, PT_DYNAMIC, PT_INTERP, PT_NOTE, PT_SHLIB, PT_PHDR };
static bool segment_load(int32_t fd, uint32_t offset, uint32_t filesz, uint32_t vaddr) { uint32_t vaddr_first_page = vaddr & 0xfffff000; uint32_t size_in_first_page = PG_SIZE - (vaddr & 0x00000fff); uint32_t occupy_pages = 0; if (filesz > size_in_first_page) { uint32_t left_size = filesz - size_in_first_page; occupy_pages = DIV_ROUND_UP(left_size, PG_SIZE) + 1; } else { occupy_pages = 1; }
uint32_t page_idx = 0; uint32_t vaddr_page = vaddr_first_page; while (page_idx < occupy_pages) { uint32_t* pde = pde_ptr(vaddr_page); uint32_t* pte = pte_ptr(vaddr_page);
if (!(*pde & 0x00000001) || !(*pte & 0x00000001)) { if (get_a_page(PF_USER, vaddr_page) == NULL) { return false; } } vaddr_page += PG_SIZE; page_idx++; } sys_lseek(fd, offset, SEEK_SET); sys_read(fd, (void*)vaddr, filesz); return true; }
static int32_t load(const char* pathname) { int32_t ret = -1; struct Elf32_Ehdr elf_header; struct Elf32_Phdr prog_header; memset(&elf_header, 0, sizeof(struct Elf32_Ehdr));
int32_t fd = sys_open(pathname, O_RDONLY); if (fd == -1) { return -1; }
if (sys_read(fd, &elf_header, sizeof(struct Elf32_Ehdr)) != sizeof(struct Elf32_Ehdr)) { ret = -1; goto done; }
if (memcmp(elf_header.e_ident, "\177ELF\1\1\1", 7) \ || elf_header.e_type != 2 \ || elf_header.e_machine != 3 \ || elf_header.e_version != 1 \ || elf_header.e_phnum > 1024 \ || elf_header.e_phentsize != sizeof(struct Elf32_Phdr)) { ret = -1; goto done; }
Elf32_Off prog_header_offset = elf_header.e_phoff; Elf32_Half prog_header_size = elf_header.e_phentsize;
uint32_t prog_idx = 0; while (prog_idx < elf_header.e_phnum) { memset(&prog_header, 0, prog_header_size); sys_lseek(fd, prog_header_offset, SEEK_SET);
if (sys_read(fd, &prog_header, prog_header_size) != prog_header_size) { ret = -1; goto done; }
if (PT_LOAD == prog_header.p_type) { if (!segment_load(fd, prog_header.p_offset, prog_header.p_filesz, prog_header.p_vaddr)) { ret = -1; goto done; } }
prog_header_offset += elf_header.e_phentsize; prog_idx++; } ret = elf_header.e_entry; done: sys_close(fd); return ret; }
int32_t sys_execv(const char* path, const char* argv[]) { uint32_t argc = 0; while (argv[argc]) { argc++; } int32_t entry_point = load(path); if (entry_point == -1) { return -1; } struct task_struct* cur = running_thread(); memcpy(cur->name, path, TASK_NAME_LEN);
struct intr_stack* intr_0_stack = (struct intr_stack*)((uint32_t)cur + PG_SIZE - sizeof(struct intr_stack)); intr_0_stack->ebx = (int32_t)argv; intr_0_stack->ecx = argc; intr_0_stack->eip = (void*)entry_point; intr_0_stack->esp = (void*)0xc0000000;
asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (intr_0_stack) : "memory"); return 0; }
|