Subversion Repositories HelenOS-historic

Rev

Rev 1423 | Rev 1425 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1423 Rev 1424
1
/*
1
/*
2
 * Copyright (C) 2006 Sergey Bondari
2
 * Copyright (C) 2006 Sergey Bondari
-
 
3
 * Copyright (C) 2006 Jakub Jermar
3
 * All rights reserved.
4
 * All rights reserved.
4
 *
5
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * are met:
8
 *
9
 *
9
 * - Redistributions of source code must retain the above copyright
10
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *   derived from this software without specific prior written permission.
16
 *
17
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * (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.
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 */
28
 
29
 
29
/**
30
/**
30
 * @file    elf.c
31
 * @file    elf.c
31
 * @brief   Kernel ELF loader.
32
 * @brief   Kernel ELF loader.
32
 */
33
 */
33
 
34
 
34
#include <elf.h>
35
#include <elf.h>
35
#include <debug.h>
36
#include <debug.h>
36
#include <arch/types.h>
37
#include <arch/types.h>
37
#include <typedefs.h>
38
#include <typedefs.h>
38
#include <mm/as.h>
39
#include <mm/as.h>
39
#include <mm/frame.h>
40
#include <mm/frame.h>
40
#include <mm/slab.h>
41
#include <mm/slab.h>
41
#include <align.h>
42
#include <align.h>
42
#include <memstr.h>
43
#include <memstr.h>
43
#include <macros.h>
44
#include <macros.h>
44
#include <arch.h>
45
#include <arch.h>
45
 
46
 
46
static char *error_codes[] = {
47
static char *error_codes[] = {
47
    "no error",
48
    "no error",
48
    "invalid image",
49
    "invalid image",
49
    "address space error",
50
    "address space error",
50
    "incompatible image",
51
    "incompatible image",
51
    "unsupported image type",
52
    "unsupported image type",
52
    "irrecoverable error"
53
    "irrecoverable error"
53
};
54
};
54
 
55
 
55
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
56
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
56
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as);
57
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as);
57
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
58
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
58
 
59
 
59
static int elf_page_fault(as_area_t *area, __address addr, pf_access_t access);
-
 
60
static void elf_frame_free(as_area_t *area, __address page, __address frame);
-
 
61
 
-
 
62
mem_backend_t elf_backend = {
-
 
63
    .backend_page_fault = elf_page_fault,
-
 
64
    .backend_frame_free = elf_frame_free
-
 
65
};
-
 
66
 
-
 
67
/** ELF loader
60
/** ELF loader
68
 *
61
 *
69
 * @param header Pointer to ELF header in memory
62
 * @param header Pointer to ELF header in memory
70
 * @param as Created and properly mapped address space
63
 * @param as Created and properly mapped address space
71
 * @return EE_OK on success
64
 * @return EE_OK on success
72
 */
65
 */
73
int elf_load(elf_header_t *header, as_t * as)
66
int elf_load(elf_header_t *header, as_t * as)
74
{
67
{
75
    int i, rc;
68
    int i, rc;
76
 
69
 
77
    /* Identify ELF */
70
    /* Identify ELF */
78
    if (header->e_ident[EI_MAG0] != ELFMAG0 || header->e_ident[EI_MAG1] != ELFMAG1 ||
71
    if (header->e_ident[EI_MAG0] != ELFMAG0 || header->e_ident[EI_MAG1] != ELFMAG1 ||
79
        header->e_ident[EI_MAG2] != ELFMAG2 || header->e_ident[EI_MAG3] != ELFMAG3) {
72
        header->e_ident[EI_MAG2] != ELFMAG2 || header->e_ident[EI_MAG3] != ELFMAG3) {
80
        return EE_INVALID;
73
        return EE_INVALID;
81
    }
74
    }
82
   
75
   
83
    /* Identify ELF compatibility */
76
    /* Identify ELF compatibility */
84
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING || header->e_machine != ELF_MACHINE ||
77
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING || header->e_machine != ELF_MACHINE ||
85
        header->e_ident[EI_VERSION] != EV_CURRENT || header->e_version != EV_CURRENT ||
78
        header->e_ident[EI_VERSION] != EV_CURRENT || header->e_version != EV_CURRENT ||
86
        header->e_ident[EI_CLASS] != ELF_CLASS) {
79
        header->e_ident[EI_CLASS] != ELF_CLASS) {
87
        return EE_INCOMPATIBLE;
80
        return EE_INCOMPATIBLE;
88
    }
81
    }
89
 
82
 
90
    if (header->e_phentsize != sizeof(elf_segment_header_t))
83
    if (header->e_phentsize != sizeof(elf_segment_header_t))
91
        return EE_INCOMPATIBLE;
84
        return EE_INCOMPATIBLE;
92
 
85
 
93
    if (header->e_shentsize != sizeof(elf_section_header_t))
86
    if (header->e_shentsize != sizeof(elf_section_header_t))
94
        return EE_INCOMPATIBLE;
87
        return EE_INCOMPATIBLE;
95
 
88
 
96
    /* Check if the object type is supported. */
89
    /* Check if the object type is supported. */
97
    if (header->e_type != ET_EXEC)
90
    if (header->e_type != ET_EXEC)
98
        return EE_UNSUPPORTED;
91
        return EE_UNSUPPORTED;
99
 
92
 
100
    /* Walk through all segment headers and process them. */
93
    /* Walk through all segment headers and process them. */
101
    for (i = 0; i < header->e_phnum; i++) {
94
    for (i = 0; i < header->e_phnum; i++) {
102
        rc = segment_header(&((elf_segment_header_t *)(((__u8 *) header) + header->e_phoff))[i], header, as);
95
        rc = segment_header(&((elf_segment_header_t *)(((__u8 *) header) + header->e_phoff))[i], header, as);
103
        if (rc != EE_OK)
96
        if (rc != EE_OK)
104
            return rc;
97
            return rc;
105
    }
98
    }
106
 
99
 
107
    /* Inspect all section headers and proccess them. */
100
    /* Inspect all section headers and proccess them. */
108
    for (i = 0; i < header->e_shnum; i++) {
101
    for (i = 0; i < header->e_shnum; i++) {
109
        rc = section_header(&((elf_section_header_t *)(((__u8 *) header) + header->e_shoff))[i], header, as);
102
        rc = section_header(&((elf_section_header_t *)(((__u8 *) header) + header->e_shoff))[i], header, as);
110
        if (rc != EE_OK)
103
        if (rc != EE_OK)
111
            return rc;
104
            return rc;
112
    }
105
    }
113
 
106
 
114
    return EE_OK;
107
    return EE_OK;
115
}
108
}
116
 
109
 
117
/** Print error message according to error code.
110
/** Print error message according to error code.
118
 *
111
 *
119
 * @param rc Return code returned by elf_load().
112
 * @param rc Return code returned by elf_load().
120
 *
113
 *
121
 * @return NULL terminated description of error.
114
 * @return NULL terminated description of error.
122
 */
115
 */
123
char *elf_error(int rc)
116
char *elf_error(int rc)
124
{
117
{
125
    ASSERT(rc < sizeof(error_codes)/sizeof(char *));
118
    ASSERT(rc < sizeof(error_codes)/sizeof(char *));
126
 
119
 
127
    return error_codes[rc];
120
    return error_codes[rc];
128
}
121
}
129
 
122
 
130
/** Process segment header.
123
/** Process segment header.
131
 *
124
 *
132
 * @param entry Segment header.
125
 * @param entry Segment header.
133
 * @param elf ELF header.
126
 * @param elf ELF header.
134
 * @param as Address space into wich the ELF is being loaded.
127
 * @param as Address space into wich the ELF is being loaded.
135
 *
128
 *
136
 * @return EE_OK on success, error code otherwise.
129
 * @return EE_OK on success, error code otherwise.
137
 */
130
 */
138
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
131
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
139
{
132
{
140
    switch (entry->p_type) {
133
    switch (entry->p_type) {
141
        case PT_NULL:
134
        case PT_NULL:
142
        case PT_PHDR:
135
        case PT_PHDR:
143
        break;
136
        break;
144
        case PT_LOAD:
137
        case PT_LOAD:
145
        return load_segment(entry, elf, as);
138
        return load_segment(entry, elf, as);
146
        break;
139
        break;
147
        case PT_DYNAMIC:
140
        case PT_DYNAMIC:
148
        case PT_INTERP:
141
        case PT_INTERP:
149
        case PT_SHLIB:
142
        case PT_SHLIB:
150
        case PT_NOTE:
143
        case PT_NOTE:
151
        case PT_LOPROC:
144
        case PT_LOPROC:
152
        case PT_HIPROC:
145
        case PT_HIPROC:
153
        default:
146
        default:
154
        return EE_UNSUPPORTED;
147
        return EE_UNSUPPORTED;
155
        break;
148
        break;
156
    }
149
    }
157
    return EE_OK;
150
    return EE_OK;
158
}
151
}
159
 
152
 
160
/** Load segment described by program header entry.
153
/** Load segment described by program header entry.
161
 *
154
 *
162
 * @param entry Program header entry describing segment to be loaded.
155
 * @param entry Program header entry describing segment to be loaded.
163
 * @param elf ELF header.
156
 * @param elf ELF header.
164
 * @param as Address space into wich the ELF is being loaded.
157
 * @param as Address space into wich the ELF is being loaded.
165
 *
158
 *
166
 * @return EE_OK on success, error code otherwise.
159
 * @return EE_OK on success, error code otherwise.
167
 */
160
 */
168
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
161
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
169
{
162
{
170
    as_area_t *a;
163
    as_area_t *a;
171
    int flags = 0;
164
    int flags = 0;
172
    void *backend_data[2] = { elf, entry };
165
    mem_backend_data_t backend_data = { .d1 = (__native) elf, .d2 = (__native) entry };
173
 
166
 
174
    if (entry->p_align > 1) {
167
    if (entry->p_align > 1) {
175
        if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
168
        if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
176
            return EE_INVALID;
169
            return EE_INVALID;
177
        }
170
        }
178
    }
171
    }
179
 
172
 
180
    if (entry->p_flags & PF_X)
173
    if (entry->p_flags & PF_X)
181
        flags |= AS_AREA_EXEC;
174
        flags |= AS_AREA_EXEC;
182
    if (entry->p_flags & PF_W)
175
    if (entry->p_flags & PF_W)
183
        flags |= AS_AREA_WRITE;
176
        flags |= AS_AREA_WRITE;
184
    if (entry->p_flags & PF_R)
177
    if (entry->p_flags & PF_R)
185
        flags |= AS_AREA_READ;
178
        flags |= AS_AREA_READ;
-
 
179
    flags |= AS_AREA_CACHEABLE;
186
 
180
 
187
    /*
181
    /*
188
     * Check if the virtual address starts on page boundary.
182
     * Check if the virtual address starts on page boundary.
189
     */
183
     */
190
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
184
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
191
        return EE_UNSUPPORTED;
185
        return EE_UNSUPPORTED;
192
 
186
 
193
    a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE, &elf_backend, backend_data);
187
    a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE,
-
 
188
        &elf_backend, &backend_data);
194
    if (!a)
189
    if (!a)
195
        return EE_MEMORY;
190
        return EE_MEMORY;
196
   
191
   
197
    /*
192
    /*
198
     * The segment will be mapped on demand by elf_page_fault().
193
     * The segment will be mapped on demand by elf_page_fault().
199
     */
194
     */
200
 
195
 
201
    return EE_OK;
196
    return EE_OK;
202
}
197
}
203
 
198
 
204
/** Process section header.
199
/** Process section header.
205
 *
200
 *
206
 * @param entry Segment header.
201
 * @param entry Segment header.
207
 * @param elf ELF header.
202
 * @param elf ELF header.
208
 * @param as Address space into wich the ELF is being loaded.
203
 * @param as Address space into wich the ELF is being loaded.
209
 *
204
 *
210
 * @return EE_OK on success, error code otherwise.
205
 * @return EE_OK on success, error code otherwise.
211
 */
206
 */
212
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as)
207
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as)
213
{
208
{
214
    switch (entry->sh_type) {
209
    switch (entry->sh_type) {
215
        default:
210
        default:
216
        break;
211
        break;
217
    }
212
    }
218
   
213
   
219
    return EE_OK;
214
    return EE_OK;
220
}
215
}
221
 
-
 
222
/** Service a page fault in the ELF backend address space area.
-
 
223
 *
-
 
224
 * The address space area and page tables must be already locked.
-
 
225
 *
-
 
226
 * @param area Pointer to the address space area.
-
 
227
 * @param addr Faulting virtual address.
-
 
228
 * @param access Access mode that caused the fault (i.e. read/write/exec).
-
 
229
 *
-
 
230
 * @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e. serviced).
-
 
231
 */
-
 
232
int elf_page_fault(as_area_t *area, __address addr, pf_access_t access)
-
 
233
{
-
 
234
    elf_header_t *elf = (elf_header_t *) area->backend_data[0];
-
 
235
    elf_segment_header_t *entry = (elf_segment_header_t *) area->backend_data[1];
-
 
236
    __address base, frame;
-
 
237
    index_t i;
-
 
238
 
-
 
239
    if (!as_area_check_access(area, access))
-
 
240
        return AS_PF_FAULT;
-
 
241
 
-
 
242
    ASSERT((addr >= entry->p_vaddr) && (addr < entry->p_vaddr + entry->p_memsz));
-
 
243
    i = (addr - entry->p_vaddr) >> PAGE_WIDTH;
-
 
244
    base = (__address) (((void *) elf) + entry->p_offset);
-
 
245
    ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
-
 
246
   
-
 
247
    if (ALIGN_DOWN(addr, PAGE_SIZE) + PAGE_SIZE < entry->p_vaddr + entry->p_filesz) {
-
 
248
        /*
-
 
249
         * Initialized portion of the segment. The memory is backed
-
 
250
         * directly by the content of the ELF image. Pages are
-
 
251
         * only copied if the segment is writable so that there
-
 
252
         * can be more instantions of the same memory ELF image
-
 
253
         * used at a time. Note that this could be later done
-
 
254
         * as COW.
-
 
255
         */
-
 
256
        if (entry->p_flags & PF_W) {
-
 
257
            frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
258
            memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), FRAME_SIZE);
-
 
259
        } else {
-
 
260
            frame = KA2PA(base + i*FRAME_SIZE);
-
 
261
        }  
-
 
262
    } else if (ALIGN_DOWN(addr, PAGE_SIZE) >= ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
-
 
263
        /*
-
 
264
         * This is the uninitialized portion of the segment.
-
 
265
         * It is not physically present in the ELF image.
-
 
266
         * To resolve the situation, a frame must be allocated
-
 
267
         * and cleared.
-
 
268
         */
-
 
269
        frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
270
        memsetb(PA2KA(frame), FRAME_SIZE, 0);
-
 
271
    } else {
-
 
272
        size_t size;
-
 
273
        /*
-
 
274
         * The mixed case.
-
 
275
         * The lower part is backed by the ELF image and
-
 
276
         * the upper part is anonymous memory.
-
 
277
         */
-
 
278
        size = entry->p_filesz - (i<<PAGE_WIDTH);
-
 
279
        frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
280
        memsetb(PA2KA(frame) + size, FRAME_SIZE - size, 0);
-
 
281
        memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), size);
-
 
282
    }
-
 
283
   
-
 
284
    page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
-
 
285
        if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
-
 
286
                panic("Could not insert used space.\n");
-
 
287
 
-
 
288
    return AS_PF_OK;
-
 
289
}
-
 
290
 
-
 
291
/** Free a frame that is backed by the ELF backend.
-
 
292
 *
-
 
293
 * The address space area and page tables must be already locked.
-
 
294
 *
-
 
295
 * @param area Pointer to the address space area.
-
 
296
 * @param page Page that is mapped to frame. Must be aligned to PAGE_SIZE.
-
 
297
 * @param frame Frame to be released.
-
 
298
 *
-
 
299
 */
-
 
300
void elf_frame_free(as_area_t *area, __address page, __address frame)
-
 
301
{
-
 
302
    elf_header_t *elf = (elf_header_t *) area->backend_data[0];
-
 
303
    elf_segment_header_t *entry = (elf_segment_header_t *) area->backend_data[1];
-
 
304
    __address base;
-
 
305
    index_t i;
-
 
306
   
-
 
307
    ASSERT((page >= entry->p_vaddr) && (page < entry->p_vaddr + entry->p_memsz));
-
 
308
    i = (page - entry->p_vaddr) >> PAGE_WIDTH;
-
 
309
    base = (__address) (((void *) elf) + entry->p_offset);
-
 
310
    ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
-
 
311
   
-
 
312
    if (page + PAGE_SIZE < ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
-
 
313
        if (entry->p_flags & PF_W) {
-
 
314
            /*
-
 
315
             * Free the frame with the copy of writable segment data.
-
 
316
             */
-
 
317
            frame_free(ADDR2PFN(frame));
-
 
318
        }
-
 
319
    } else {
-
 
320
        /*
-
 
321
         * The frame is either anonymous memory or the mixed case (i.e. lower
-
 
322
         * part is backed by the ELF image and the upper is anonymous).
-
 
323
         * In any case, a frame needs to be freed.
-
 
324
         */
-
 
325
        frame_free(ADDR2PFN(frame));
-
 
326
    }
-
 
327
}
-
 
328
 
216