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 | } |