Subversion Repositories HelenOS

Rev

Rev 3007 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3007 Rev 3222
1
/*
1
/*
2
 * Copyright (c) 2006 Sergey Bondari
2
 * Copyright (c) 2006 Sergey Bondari
3
 * Copyright (c) 2006 Jakub Jermar
3
 * Copyright (c) 2006 Jakub Jermar
4
 * All rights reserved.
4
 * All rights reserved.
5
 *
5
 *
6
 * Redistribution and use in source and binary forms, with or without
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
7
 * modification, are permitted provided that the following conditions
8
 * are met:
8
 * are met:
9
 *
9
 *
10
 * - Redistributions of source code must retain the above copyright
10
 * - Redistributions of source code must retain the above copyright
11
 *   notice, this list of conditions and the following disclaimer.
11
 *   notice, this list of conditions and the following disclaimer.
12
 * - Redistributions in binary form must reproduce the above copyright
12
 * - Redistributions in binary form must reproduce the above copyright
13
 *   notice, this list of conditions and the following disclaimer in the
13
 *   notice, this list of conditions and the following disclaimer in the
14
 *   documentation and/or other materials provided with the distribution.
14
 *   documentation and/or other materials provided with the distribution.
15
 * - 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
16
 *   derived from this software without specific prior written permission.
16
 *   derived from this software without specific prior written permission.
17
 *
17
 *
18
 * 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
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
 * 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,
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
 * 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,
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (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
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
28
 */
29
 
29
 
30
/** @addtogroup generic
30
/** @addtogroup generic
31
 * @{
31
 * @{
32
 */
32
 */
33
 
33
 
34
/**
34
/**
35
 * @file
35
 * @file
36
 * @brief   Kernel ELF loader.
36
 * @brief   Kernel ELF loader.
37
 */
37
 */
38
 
38
 
39
#include <lib/elf.h>
39
#include <lib/elf.h>
40
#include <debug.h>
40
#include <debug.h>
41
#include <arch/types.h>
41
#include <arch/types.h>
42
#include <mm/as.h>
42
#include <mm/as.h>
43
#include <mm/frame.h>
43
#include <mm/frame.h>
44
#include <mm/slab.h>
44
#include <mm/slab.h>
45
#include <align.h>
45
#include <align.h>
46
#include <memstr.h>
46
#include <memstr.h>
47
#include <macros.h>
47
#include <macros.h>
48
#include <arch.h>
48
#include <arch.h>
49
 
49
 
50
static char *error_codes[] = {
50
static char *error_codes[] = {
51
    "no error",
51
    "no error",
52
    "invalid image",
52
    "invalid image",
53
    "address space error",
53
    "address space error",
54
    "incompatible image",
54
    "incompatible image",
55
    "unsupported image type",
55
    "unsupported image type",
56
    "irrecoverable error"
56
    "irrecoverable error"
57
};
57
};
58
 
58
 
59
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf,
59
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf,
60
    as_t *as);
60
    as_t *as, int flags);
61
static int section_header(elf_section_header_t *entry, elf_header_t *elf,
61
static int section_header(elf_section_header_t *entry, elf_header_t *elf,
62
    as_t *as);
62
    as_t *as);
63
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf,
63
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf,
64
    as_t *as);
64
    as_t *as);
65
 
65
 
66
/** ELF loader
66
/** ELF loader
67
 *
67
 *
68
 * @param header Pointer to ELF header in memory
68
 * @param header Pointer to ELF header in memory
69
 * @param as Created and properly mapped address space
69
 * @param as Created and properly mapped address space
-
 
70
 * @param flags A combination of ELD_F_*
70
 * @return EE_OK on success
71
 * @return EE_OK on success
71
 */
72
 */
72
unsigned int elf_load(elf_header_t *header, as_t * as)
73
unsigned int elf_load(elf_header_t *header, as_t * as, int flags)
73
{
74
{
74
    int i, rc;
75
    int i, rc;
75
 
76
 
76
    /* Identify ELF */
77
    /* Identify ELF */
77
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
78
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
78
        header->e_ident[EI_MAG1] != ELFMAG1 ||
79
        header->e_ident[EI_MAG1] != ELFMAG1 ||
79
        header->e_ident[EI_MAG2] != ELFMAG2 ||
80
        header->e_ident[EI_MAG2] != ELFMAG2 ||
80
        header->e_ident[EI_MAG3] != ELFMAG3) {
81
        header->e_ident[EI_MAG3] != ELFMAG3) {
81
        return EE_INVALID;
82
        return EE_INVALID;
82
    }
83
    }
83
   
84
   
84
    /* Identify ELF compatibility */
85
    /* Identify ELF compatibility */
85
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
86
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
86
        header->e_machine != ELF_MACHINE ||
87
        header->e_machine != ELF_MACHINE ||
87
        header->e_ident[EI_VERSION] != EV_CURRENT ||
88
        header->e_ident[EI_VERSION] != EV_CURRENT ||
88
        header->e_version != EV_CURRENT ||
89
        header->e_version != EV_CURRENT ||
89
        header->e_ident[EI_CLASS] != ELF_CLASS) {
90
        header->e_ident[EI_CLASS] != ELF_CLASS) {
90
        return EE_INCOMPATIBLE;
91
        return EE_INCOMPATIBLE;
91
    }
92
    }
92
 
93
 
93
    if (header->e_phentsize != sizeof(elf_segment_header_t))
94
    if (header->e_phentsize != sizeof(elf_segment_header_t))
94
        return EE_INCOMPATIBLE;
95
        return EE_INCOMPATIBLE;
95
 
96
 
96
    if (header->e_shentsize != sizeof(elf_section_header_t))
97
    if (header->e_shentsize != sizeof(elf_section_header_t))
97
        return EE_INCOMPATIBLE;
98
        return EE_INCOMPATIBLE;
98
 
99
 
99
    /* Check if the object type is supported. */
100
    /* Check if the object type is supported. */
100
    if (header->e_type != ET_EXEC)
101
    if (header->e_type != ET_EXEC)
101
        return EE_UNSUPPORTED;
102
        return EE_UNSUPPORTED;
102
 
103
 
103
    /* Check if the ELF image starts on a page boundary */
104
    /* Check if the ELF image starts on a page boundary */
104
    if (ALIGN_UP((uintptr_t)header, PAGE_SIZE) != (uintptr_t)header)
105
    if (ALIGN_UP((uintptr_t)header, PAGE_SIZE) != (uintptr_t)header)
105
        return EE_UNSUPPORTED;
106
        return EE_UNSUPPORTED;
106
 
107
 
107
    /* Walk through all segment headers and process them. */
108
    /* Walk through all segment headers and process them. */
108
    for (i = 0; i < header->e_phnum; i++) {
109
    for (i = 0; i < header->e_phnum; i++) {
109
        elf_segment_header_t *seghdr;
110
        elf_segment_header_t *seghdr;
110
 
111
 
111
        seghdr = &((elf_segment_header_t *)(((uint8_t *) header) +
112
        seghdr = &((elf_segment_header_t *)(((uint8_t *) header) +
112
            header->e_phoff))[i];
113
            header->e_phoff))[i];
113
        rc = segment_header(seghdr, header, as);
114
        rc = segment_header(seghdr, header, as, flags);
114
        if (rc != EE_OK)
115
        if (rc != EE_OK)
115
            return rc;
116
            return rc;
116
    }
117
    }
117
 
118
 
118
    /* Inspect all section headers and proccess them. */
119
    /* Inspect all section headers and proccess them. */
119
    for (i = 0; i < header->e_shnum; i++) {
120
    for (i = 0; i < header->e_shnum; i++) {
120
        elf_section_header_t *sechdr;
121
        elf_section_header_t *sechdr;
121
 
122
 
122
        sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
123
        sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
123
            header->e_shoff))[i];
124
            header->e_shoff))[i];
124
        rc = section_header(sechdr, header, as);
125
        rc = section_header(sechdr, header, as);
125
        if (rc != EE_OK)
126
        if (rc != EE_OK)
126
            return rc;
127
            return rc;
127
    }
128
    }
128
 
129
 
129
    return EE_OK;
130
    return EE_OK;
130
}
131
}
131
 
132
 
132
/** Print error message according to error code.
133
/** Print error message according to error code.
133
 *
134
 *
134
 * @param rc Return code returned by elf_load().
135
 * @param rc Return code returned by elf_load().
135
 *
136
 *
136
 * @return NULL terminated description of error.
137
 * @return NULL terminated description of error.
137
 */
138
 */
138
char *elf_error(unsigned int rc)
139
char *elf_error(unsigned int rc)
139
{
140
{
140
    ASSERT(rc < sizeof(error_codes) / sizeof(char *));
141
    ASSERT(rc < sizeof(error_codes) / sizeof(char *));
141
 
142
 
142
    return error_codes[rc];
143
    return error_codes[rc];
143
}
144
}
144
 
145
 
145
/** Process segment header.
146
/** Process segment header.
146
 *
147
 *
147
 * @param entry Segment header.
148
 * @param entry Segment header.
148
 * @param elf ELF header.
149
 * @param elf ELF header.
149
 * @param as Address space into wich the ELF is being loaded.
150
 * @param as Address space into wich the ELF is being loaded.
150
 *
151
 *
151
 * @return EE_OK on success, error code otherwise.
152
 * @return EE_OK on success, error code otherwise.
152
 */
153
 */
153
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf,
154
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf,
154
    as_t *as)
155
    as_t *as, int flags)
155
{
156
{
-
 
157
    char *interp;
-
 
158
 
156
    switch (entry->p_type) {
159
    switch (entry->p_type) {
157
    case PT_NULL:
160
    case PT_NULL:
158
    case PT_PHDR:
161
    case PT_PHDR:
159
        break;
162
        break;
160
    case PT_LOAD:
163
    case PT_LOAD:
161
        return load_segment(entry, elf, as);
164
        return load_segment(entry, elf, as);
162
        break;
165
        break;
163
    case PT_DYNAMIC:
166
    case PT_DYNAMIC:
164
    case PT_INTERP:
167
    case PT_INTERP:
-
 
168
        interp = (char *)elf + entry->p_offset;
-
 
169
        /* FIXME */
-
 
170
        /*if (memcmp((uintptr_t)interp, (uintptr_t)ELF_INTERP_ZSTR,
-
 
171
            ELF_INTERP_ZLEN) != 0) {
-
 
172
            return EE_UNSUPPORTED;
-
 
173
        }*/
-
 
174
        if ((flags & ELD_F_LOADER) == 0) {
-
 
175
            return EE_LOADER;
-
 
176
        }
-
 
177
        break;
165
    case PT_SHLIB:
178
    case PT_SHLIB:
166
    case PT_NOTE:
179
    case PT_NOTE:
167
    case PT_LOPROC:
180
    case PT_LOPROC:
168
    case PT_HIPROC:
181
    case PT_HIPROC:
169
    default:
182
    default:
170
        return EE_UNSUPPORTED;
183
        return EE_UNSUPPORTED;
171
        break;
184
        break;
172
    }
185
    }
173
    return EE_OK;
186
    return EE_OK;
174
}
187
}
175
 
188
 
176
/** Load segment described by program header entry.
189
/** Load segment described by program header entry.
177
 *
190
 *
178
 * @param entry Program header entry describing segment to be loaded.
191
 * @param entry Program header entry describing segment to be loaded.
179
 * @param elf ELF header.
192
 * @param elf ELF header.
180
 * @param as Address space into wich the ELF is being loaded.
193
 * @param as Address space into wich the ELF is being loaded.
181
 *
194
 *
182
 * @return EE_OK on success, error code otherwise.
195
 * @return EE_OK on success, error code otherwise.
183
 */
196
 */
184
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
197
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
185
{
198
{
186
    as_area_t *a;
199
    as_area_t *a;
187
    int flags = 0;
200
    int flags = 0;
188
    mem_backend_data_t backend_data;
201
    mem_backend_data_t backend_data;
189
    uintptr_t base;
202
    uintptr_t base;
190
    size_t mem_sz;
203
    size_t mem_sz;
191
   
204
   
192
    backend_data.elf = elf;
205
    backend_data.elf = elf;
193
    backend_data.segment = entry;
206
    backend_data.segment = entry;
194
 
207
 
195
    if (entry->p_align > 1) {
208
    if (entry->p_align > 1) {
196
        if ((entry->p_offset % entry->p_align) !=
209
        if ((entry->p_offset % entry->p_align) !=
197
            (entry->p_vaddr % entry->p_align)) {
210
            (entry->p_vaddr % entry->p_align)) {
198
            return EE_INVALID;
211
            return EE_INVALID;
199
        }
212
        }
200
    }
213
    }
201
 
214
 
202
    if (entry->p_flags & PF_X)
215
    if (entry->p_flags & PF_X)
203
        flags |= AS_AREA_EXEC;
216
        flags |= AS_AREA_EXEC;
204
    if (entry->p_flags & PF_W)
217
    if (entry->p_flags & PF_W)
205
        flags |= AS_AREA_WRITE;
218
        flags |= AS_AREA_WRITE;
206
    if (entry->p_flags & PF_R)
219
    if (entry->p_flags & PF_R)
207
        flags |= AS_AREA_READ;
220
        flags |= AS_AREA_READ;
208
    flags |= AS_AREA_CACHEABLE;
221
    flags |= AS_AREA_CACHEABLE;
209
 
222
 
210
    /*
223
    /*
211
     * Align vaddr down, inserting a little "gap" at the beginning.
224
     * Align vaddr down, inserting a little "gap" at the beginning.
212
     * Adjust area size, so that its end remains in place.
225
     * Adjust area size, so that its end remains in place.
213
     */
226
     */
214
    base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
227
    base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
215
    mem_sz = entry->p_memsz + (entry->p_vaddr - base);
228
    mem_sz = entry->p_memsz + (entry->p_vaddr - base);
216
 
229
 
217
    a = as_area_create(as, flags, mem_sz, base,
230
    a = as_area_create(as, flags, mem_sz, base,
218
        AS_AREA_ATTR_NONE, &elf_backend, &backend_data);
231
        AS_AREA_ATTR_NONE, &elf_backend, &backend_data);
219
    if (!a)
232
    if (!a)
220
        return EE_MEMORY;
233
        return EE_MEMORY;
221
   
234
   
222
    /*
235
    /*
223
     * The segment will be mapped on demand by elf_page_fault().
236
     * The segment will be mapped on demand by elf_page_fault().
224
     */
237
     */
225
 
238
 
226
    return EE_OK;
239
    return EE_OK;
227
}
240
}
228
 
241
 
229
/** Process section header.
242
/** Process section header.
230
 *
243
 *
231
 * @param entry Segment header.
244
 * @param entry Segment header.
232
 * @param elf ELF header.
245
 * @param elf ELF header.
233
 * @param as Address space into wich the ELF is being loaded.
246
 * @param as Address space into wich the ELF is being loaded.
234
 *
247
 *
235
 * @return EE_OK on success, error code otherwise.
248
 * @return EE_OK on success, error code otherwise.
236
 */
249
 */
237
static int section_header(elf_section_header_t *entry, elf_header_t *elf,
250
static int section_header(elf_section_header_t *entry, elf_header_t *elf,
238
    as_t *as)
251
    as_t *as)
239
{
252
{
240
    switch (entry->sh_type) {
253
    switch (entry->sh_type) {
241
    case SHT_PROGBITS:
254
    case SHT_PROGBITS:
242
        if (entry->sh_flags & SHF_TLS) {
255
        if (entry->sh_flags & SHF_TLS) {
243
            /* .tdata */
256
            /* .tdata */
244
        }
257
        }
245
        break;
258
        break;
246
    case SHT_NOBITS:
259
    case SHT_NOBITS:
247
        if (entry->sh_flags & SHF_TLS) {
260
        if (entry->sh_flags & SHF_TLS) {
248
            /* .tbss */
261
            /* .tbss */
249
        }
262
        }
250
        break;
263
        break;
251
    default:
264
    default:
252
        break;
265
        break;
253
    }
266
    }
254
   
267
   
255
    return EE_OK;
268
    return EE_OK;
256
}
269
}
257
 
270
 
258
/** @}
271
/** @}
259
 */
272
 */
260
 
273