Subversion Repositories HelenOS

Rev

Rev 2929 | Rev 2949 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2928 svoboda 1
/*
2
 * Copyright (c) 2006 Sergey Bondari
3
 * Copyright (c) 2006 Jakub Jermar
4
 * Copyright (c) 2008 Jiri Svoboda
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *
11
 * - Redistributions of source code must retain the above copyright
12
 *   notice, this list of conditions and the following disclaimer.
13
 * - Redistributions in binary form must reproduce the above copyright
14
 *   notice, this list of conditions and the following disclaimer in the
15
 *   documentation and/or other materials provided with the distribution.
16
 * - The name of the author may not be used to endorse or promote products
17
 *   derived from this software without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
 */
30
 
31
/** @addtogroup generic
32
 * @{
33
 */
34
 
35
/**
36
 * @file
37
 * @brief   Kernel ELF loader.
38
 */
39
 
40
#include <stdio.h>
41
#include <sys/types.h>
42
#include <align.h>
43
#include <assert.h>
44
#include <as.h>
45
#include "elf.h"
46
 
2932 svoboda 47
#define RTLD_BIAS 0x80000
2928 svoboda 48
 
49
static char *error_codes[] = {
50
    "no error",
51
    "invalid image",
52
    "address space error",
53
    "incompatible image",
54
    "unsupported image type",
55
    "irrecoverable error"
56
};
57
 
58
static int segment_header(int fd, elf_header_t *elf);
59
static int section_header(elf_section_header_t *entry, elf_header_t *elf);
60
static int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf);
61
 
62
typedef void (*epoint_t)(void);
63
 
64
/** ELF loader
65
 *
66
 * @param header Pointer to ELF header in memory
67
 * @return EE_OK on success
68
 */
69
unsigned int elf_load(int fd, elf_header_t *header)
70
{
71
    int i, rc;
72
 
73
    rc = read(fd, header, sizeof(elf_header_t));
74
    if (rc < 0) {
75
        printf("read error\n");
76
        return EE_INVALID;
77
    }
78
 
79
    printf("ELF-load:");
80
    /* Identify ELF */
81
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
82
        header->e_ident[EI_MAG1] != ELFMAG1 ||
83
        header->e_ident[EI_MAG2] != ELFMAG2 ||
84
        header->e_ident[EI_MAG3] != ELFMAG3) {
85
        printf("invalid header\n");
86
        return EE_INVALID;
87
    }
88
 
89
    /* Identify ELF compatibility */
90
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
91
        header->e_machine != ELF_MACHINE ||
92
        header->e_ident[EI_VERSION] != EV_CURRENT ||
93
        header->e_version != EV_CURRENT ||
94
        header->e_ident[EI_CLASS] != ELF_CLASS) {
95
        printf("incompatible data/version/class\n");
96
        return EE_INCOMPATIBLE;
97
    }
98
 
99
    if (header->e_phentsize != sizeof(elf_segment_header_t))
100
        return EE_INCOMPATIBLE;
101
 
102
    if (header->e_shentsize != sizeof(elf_section_header_t))
103
        return EE_INCOMPATIBLE;
104
 
105
    /* Check if the object type is supported. */
106
    if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
107
        printf("Object type %d is not supported\n", header->e_type);
108
        return EE_UNSUPPORTED;
109
    }
2932 svoboda 110
    if (header->e_type == ET_DYN) header->e_entry += RTLD_BIAS;
2928 svoboda 111
 
112
    printf("parse segments\n");
113
 
114
    /* Walk through all segment headers and process them. */
115
    for (i = 0; i < header->e_phnum; i++) {
116
 
117
        /* Seek to start of header */
118
        lseek(fd, header->e_phoff + i * sizeof(elf_segment_header_t), SEEK_SET);
119
 
120
        rc = segment_header(fd, header);
121
        if (rc != EE_OK)
122
            return rc;
123
    }
124
 
125
    printf("parse sections\n");
126
 
127
    /* Inspect all section headers and proccess them. */
128
    for (i = 0; i < header->e_shnum; i++) {
129
/*      elf_section_header_t *sechdr;
130
 
131
        sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
132
            header->e_shoff))[i];
133
        rc = section_header(sechdr, header);
134
        if (rc != EE_OK)
135
            return rc;*/
136
    }
137
 
138
    printf("done\n");
139
 
140
    return EE_OK;
141
}
142
 
143
/** Print error message according to error code.
144
 *
145
 * @param rc Return code returned by elf_load().
146
 *
147
 * @return NULL terminated description of error.
148
 */
149
char *elf_error(unsigned int rc)
150
{
151
    assert(rc < sizeof(error_codes) / sizeof(char *));
152
 
153
    return error_codes[rc];
154
}
155
 
156
/** Process segment header.
157
 *
158
 * @param entry Segment header.
159
 * @param elf ELF header.
160
 *
161
 * @return EE_OK on success, error code otherwise.
162
 */
163
static int segment_header(int fd, elf_header_t *elf)
164
{
165
    static elf_segment_header_t entry_buf;
166
    elf_segment_header_t *entry = &entry_buf;
167
    int rc;
168
 
169
    rc = read(fd, entry, sizeof(elf_segment_header_t));
170
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }
171
 
172
    switch (entry->p_type) {
173
    case PT_NULL:
174
    case PT_PHDR:
175
        break;
176
    case PT_LOAD:
177
        return load_segment(fd, entry, elf);
178
        break;
179
    case PT_DYNAMIC:
180
    case PT_INTERP:
181
    case PT_SHLIB:
182
    case PT_NOTE:
183
    case PT_LOPROC:
184
    case PT_HIPROC:
185
    default:
186
        printf("segment p_type %d unknown\n", entry->p_type);
187
        return EE_UNSUPPORTED;
188
        break;
189
    }
190
    return EE_OK;
191
}
192
 
193
/** Load segment described by program header entry.
194
 *
195
 * @param entry Program header entry describing segment to be loaded.
196
 * @param elf ELF header.
197
 *
198
 * @return EE_OK on success, error code otherwise.
199
 */
200
int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf)
201
{
202
    void *a;
203
    int flags = 0;
2932 svoboda 204
    uintptr_t bias;
2928 svoboda 205
    int rc;
206
 
207
    printf("load segment at addr 0x%x, size 0x%x\n", entry->p_vaddr,
208
        entry->p_memsz);
209
 
2932 svoboda 210
    bias = (elf->e_type == ET_DYN) ? RTLD_BIAS : 0;
2928 svoboda 211
 
212
    if (entry->p_align > 1) {
213
        if ((entry->p_offset % entry->p_align) !=
214
            (entry->p_vaddr % entry->p_align)) {
215
            printf("align check 1 failed offset%%align=%d, vaddr%%align=%d\n",
216
            entry->p_offset % entry->p_align,
217
            entry->p_vaddr % entry->p_align
218
            );
219
            return EE_INVALID;
220
        }
221
    }
222
 
223
/*  if (entry->p_flags & PF_X)
224
        flags |= AS_AREA_EXEC;
225
    if (entry->p_flags & PF_W)
226
        flags |= AS_AREA_WRITE;
227
    if (entry->p_flags & PF_R)
228
        flags |= AS_AREA_READ;
229
    flags |= AS_AREA_CACHEABLE;
230
*/
231
    /* FIXME: Kernel won't normally allow this, unless you "patch" it */
232
    flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_EXEC | AS_AREA_CACHEABLE;
233
 
234
    /*
235
     * Check if the virtual address starts on page boundary.
236
     */
237
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr) {
238
        printf("align check 2 failed - not page-aligned\n");
239
        printf("vaddr = 0x%x, should be 0x%x\n",
240
            entry->p_vaddr, ALIGN_UP(entry->p_vaddr, PAGE_SIZE));
241
        return EE_UNSUPPORTED;
242
    }
243
 
2932 svoboda 244
    printf("map to p_vaddr=0x%x-0x%x...\n", entry->p_vaddr + bias,
245
    entry->p_vaddr + bias + ALIGN_UP(entry->p_memsz, PAGE_SIZE));
2928 svoboda 246
 
2932 svoboda 247
    a = as_area_create((uint8_t *)entry->p_vaddr + bias,
2928 svoboda 248
        entry->p_memsz, flags);
249
    if (a == (void *)(-1)) {
250
        printf("memory mapping failed\n");
251
        return EE_MEMORY;
252
    }
253
 
254
    printf("as_area_create() -> 0x%x\n", (unsigned)a);
255
 
256
    /*
257
     * Load segment data
258
     */
259
    rc = lseek(fd, entry->p_offset, SEEK_SET);
260
    if (rc < 0) { printf("seek error\n"); return EE_INVALID; }
261
 
2932 svoboda 262
    rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
2928 svoboda 263
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }
264
 
265
    return EE_OK;
266
}
267
 
268
/** Process section header.
269
 *
270
 * @param entry Segment header.
271
 * @param elf ELF header.
272
 *
273
 * @return EE_OK on success, error code otherwise.
274
 */
275
static int section_header(elf_section_header_t *entry, elf_header_t *elf)
276
{
277
    switch (entry->sh_type) {
278
    case SHT_PROGBITS:
279
        if (entry->sh_flags & SHF_TLS) {
280
            /* .tdata */
281
        }
282
        break;
283
    case SHT_NOBITS:
284
        if (entry->sh_flags & SHF_TLS) {
285
            /* .tbss */
286
        }
287
        break;
288
    default:
289
        break;
290
    }
291
 
292
    return EE_OK;
293
}
294
 
295
/** @}
296
 */