Rev 910 | Rev 952 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 910 | Rev 938 | ||
|---|---|---|---|
| Line 25... | Line 25... | ||
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | */ |
27 | */ |
| 28 | 28 | ||
| 29 | #include <elf.h> |
29 | #include <elf.h> |
| - | 30 | #include <debug.h> |
|
| - | 31 | #include <arch/types.h> |
|
| - | 32 | #include <typedefs.h> |
|
| - | 33 | #include <mm/as.h> |
|
| - | 34 | #include <mm/frame.h> |
|
| - | 35 | #include <print.h> |
|
| - | 36 | #include <align.h> |
|
| 30 | 37 | ||
| - | 38 | static char *error_codes[] = { |
|
| - | 39 | "no error", |
|
| - | 40 | "invalid image", |
|
| - | 41 | "address space error", |
|
| - | 42 | "incompatible image", |
|
| - | 43 | "unsupported image type", |
|
| - | 44 | "irrecoverable error" |
|
| - | 45 | }; |
|
| - | 46 | ||
| - | 47 | static int program_header_entry(elf_header_t *header, elf_ph_entry_t *entry, as_t *as); |
|
| - | 48 | static int load_segment(elf_header_t *header, elf_ph_entry_t *entry, as_t *as); |
|
| - | 49 | ||
| 31 | /** 32bit ELF loader |
50 | /** ELF loader |
| 32 | * |
51 | * |
| 33 | * @param header Pointer to ELF header in memory |
52 | * @param header Pointer to ELF header in memory |
| 34 | * @param as Created and properly mapped address space |
53 | * @param as Created and properly mapped address space |
| 35 | * @return EE_OK on success |
54 | * @return EE_OK on success |
| 36 | */ |
55 | */ |
| 37 | int elf32_load(__address header, as_t * as) { |
56 | int elf_load(elf_header_t *header, as_t * as) |
| - | 57 | { |
|
| 38 | elf32_header_t * e_header; |
58 | int i, rc; |
| 39 | 59 | ||
| 40 | e_header = (elf32_header_t *) header; |
- | |
| 41 | - | ||
| 42 | /* Identify ELF */ |
60 | /* Identify ELF */ |
| 43 | if ( e_header->e_ident[EI_MAG0] != ELFMAG0 || e_header->e_ident[EI_MAG1] != ELFMAG1 || |
61 | if (header->e_ident[EI_MAG0] != ELFMAG0 || header->e_ident[EI_MAG1] != ELFMAG1 || |
| 44 | e_header->e_ident[EI_MAG2] != ELFMAG2 || e_header->e_ident[EI_MAG3] != ELFMAG3 |
62 | header->e_ident[EI_MAG2] != ELFMAG2 || header->e_ident[EI_MAG3] != ELFMAG3) { |
| 45 | ) { |
- | |
| 46 | return EE_INVALID; |
63 | return EE_INVALID; |
| 47 | } |
64 | } |
| 48 | 65 | ||
| 49 | /* Identify ELF compatibility */ |
66 | /* Identify ELF compatibility */ |
| 50 | if ( e_header->e_ident[EI_DATA] != ELF_DATA_ENCODING || e_header->e_machine != ELF_MACHINE || |
67 | if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING || header->e_machine != ELF_MACHINE || |
| 51 | e_header->e_ident[EI_VERSION] != EV_CURRENT || e_header->e_ident[EI_CLASS] != ELF_CLASS |
68 | header->e_ident[EI_VERSION] != EV_CURRENT || header->e_version != EV_CURRENT || |
| - | 69 | header->e_ident[EI_CLASS] != ELF_CLASS) { |
|
| - | 70 | return EE_INCOMPATIBLE; |
|
| - | 71 | } |
|
| - | 72 | ||
| - | 73 | if (header->e_phentsize != sizeof(elf_ph_entry_t)) |
|
| - | 74 | return EE_INCOMPATIBLE; |
|
| - | 75 | ||
| - | 76 | /* Check if the object type is supported. */ |
|
| - | 77 | if (header->e_type != ET_EXEC) |
|
| - | 78 | return EE_UNSUPPORTED; |
|
| - | 79 | ||
| - | 80 | /* Walk through all program header entries and process them. */ |
|
| - | 81 | for (i = 0; i < header->e_phnum; i++) { |
|
| - | 82 | rc = program_header_entry(header, &((elf_ph_entry_t *)(((__u8 *) header) + header->e_phoff))[i], as); |
|
| - | 83 | if (rc != EE_OK) |
|
| - | 84 | return rc; |
|
| - | 85 | } |
|
| - | 86 | ||
| - | 87 | return EE_OK; |
|
| - | 88 | } |
|
| - | 89 | ||
| - | 90 | /** Print error message according to error code. |
|
| - | 91 | * |
|
| - | 92 | * @param rc Return code returned by elf_load(). |
|
| - | 93 | * |
|
| - | 94 | * @return NULL terminated description of error. |
|
| - | 95 | */ |
|
| - | 96 | char *elf_error(int rc) |
|
| - | 97 | { |
|
| - | 98 | ASSERT(rc < sizeof(error_codes)/sizeof(char *)); |
|
| - | 99 | ||
| - | 100 | return error_codes[rc]; |
|
| - | 101 | } |
|
| - | 102 | ||
| - | 103 | /** Process program header entry. |
|
| - | 104 | * |
|
| - | 105 | * @param entry Program header entry. |
|
| - | 106 | * @param as Address space into wich the ELF is being loaded. |
|
| - | 107 | * |
|
| - | 108 | * @return EE_OK on success, error code otherwise. |
|
| - | 109 | */ |
|
| - | 110 | static int program_header_entry(elf_header_t *header, elf_ph_entry_t *entry, as_t *as) |
|
| - | 111 | { |
|
| - | 112 | switch (entry->p_type) { |
|
| - | 113 | case PT_NULL: |
|
| - | 114 | case PT_PHDR: |
|
| - | 115 | break; |
|
| - | 116 | case PT_LOAD: |
|
| - | 117 | return load_segment(header, entry, as); |
|
| 52 | ) { |
118 | break; |
| - | 119 | case PT_DYNAMIC: |
|
| - | 120 | case PT_INTERP: |
|
| - | 121 | case PT_SHLIB: |
|
| - | 122 | case PT_NOTE: |
|
| - | 123 | case PT_LOPROC: |
|
| - | 124 | case PT_HIPROC: |
|
| - | 125 | default: |
|
| 53 | return EE_UNSUPPORTED; |
126 | return EE_UNSUPPORTED; |
| - | 127 | break; |
|
| 54 | } |
128 | } |
| - | 129 | return EE_OK; |
|
| - | 130 | } |
|
| - | 131 | ||
| - | 132 | /** Load segment described by program header entry. |
|
| - | 133 | * |
|
| - | 134 | * @param entry Program header entry describing segment to be loaded. |
|
| - | 135 | * @parma as Address space into wich the ELF is being loaded. |
|
| - | 136 | * |
|
| - | 137 | * @return EE_OK on success, error code otherwise. |
|
| - | 138 | */ |
|
| - | 139 | int load_segment(elf_header_t *header, elf_ph_entry_t *entry, as_t *as) |
|
| - | 140 | { |
|
| - | 141 | as_area_t *a; |
|
| - | 142 | int i, type = 0; |
|
| - | 143 | ||
| - | 144 | if (entry->p_align > 1) { |
|
| - | 145 | if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) { |
|
| - | 146 | return EE_INVALID; |
|
| - | 147 | } |
|
| - | 148 | } |
|
| - | 149 | ||
| - | 150 | /* |
|
| - | 151 | * Check if the segment doesn't interfere with kernel address space. |
|
| - | 152 | */ |
|
| - | 153 | if (entry->p_vaddr + ALIGN_UP(entry->p_memsz, PAGE_SIZE) >= USER_ADDRESS_SPACE_END) |
|
| - | 154 | return EE_MEMORY; |
|
| 55 | 155 | ||
| - | 156 | if (entry->p_flags & PF_X) { |
|
| - | 157 | type = AS_AREA_TEXT; |
|
| - | 158 | } else if (entry->p_flags & PF_W) { |
|
| - | 159 | type = AS_AREA_DATA; |
|
| - | 160 | } else { |
|
| - | 161 | return EE_UNSUPPORTED; |
|
| - | 162 | } |
|
| 56 | 163 | ||
| - | 164 | a = as_area_create(as, AS_AREA_TEXT, SIZE2FRAMES(entry->p_memsz), entry->p_vaddr); |
|
| - | 165 | if (!a) |
|
| 57 | return EE_UNSUPPORTED; |
166 | return EE_IRRECOVERABLE; |
| - | 167 | ||
| - | 168 | for (i = 0; i < SIZE2FRAMES(entry->p_filesz); i++) { |
|
| - | 169 | as_set_mapping(as, entry->p_vaddr + i*PAGE_SIZE, KA2PA(((__address) header) + entry->p_offset + i*PAGE_SIZE)); |
|
| - | 170 | } |
|
| - | 171 | ||
| - | 172 | return EE_OK; |
|
| 58 | } |
173 | } |