Subversion Repositories HelenOS

Rev

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

Rev 3009 Rev 3107
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, int flags);
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
 * @param flags A combination of ELD_F_*
71
 * @return EE_OK on success
71
 * @return EE_OK on success
72
 */
72
 */
73
unsigned int elf_load(elf_header_t *header, as_t * as, int flags)
73
unsigned int elf_load(elf_header_t *header, as_t * as, int flags)
74
{
74
{
75
    int i, rc;
75
    int i, rc;
76
 
76
 
77
    /* Identify ELF */
77
    /* Identify ELF */
78
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
78
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
79
        header->e_ident[EI_MAG1] != ELFMAG1 ||
79
        header->e_ident[EI_MAG1] != ELFMAG1 ||
80
        header->e_ident[EI_MAG2] != ELFMAG2 ||
80
        header->e_ident[EI_MAG2] != ELFMAG2 ||
81
        header->e_ident[EI_MAG3] != ELFMAG3) {
81
        header->e_ident[EI_MAG3] != ELFMAG3) {
82
        return EE_INVALID;
82
        return EE_INVALID;
83
    }
83
    }
84
   
84
   
85
    /* Identify ELF compatibility */
85
    /* Identify ELF compatibility */
86
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
86
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
87
        header->e_machine != ELF_MACHINE ||
87
        header->e_machine != ELF_MACHINE ||
88
        header->e_ident[EI_VERSION] != EV_CURRENT ||
88
        header->e_ident[EI_VERSION] != EV_CURRENT ||
89
        header->e_version != EV_CURRENT ||
89
        header->e_version != EV_CURRENT ||
90
        header->e_ident[EI_CLASS] != ELF_CLASS) {
90
        header->e_ident[EI_CLASS] != ELF_CLASS) {
91
        return EE_INCOMPATIBLE;
91
        return EE_INCOMPATIBLE;
92
    }
92
    }
93
 
93
 
94
    if (header->e_phentsize != sizeof(elf_segment_header_t))
94
    if (header->e_phentsize != sizeof(elf_segment_header_t))
95
        return EE_INCOMPATIBLE;
95
        return EE_INCOMPATIBLE;
96
 
96
 
97
    if (header->e_shentsize != sizeof(elf_section_header_t))
97
    if (header->e_shentsize != sizeof(elf_section_header_t))
98
        return EE_INCOMPATIBLE;
98
        return EE_INCOMPATIBLE;
99
 
99
 
100
    /* Check if the object type is supported. */
100
    /* Check if the object type is supported. */
101
    if (header->e_type != ET_EXEC)
101
    if (header->e_type != ET_EXEC)
102
        return EE_UNSUPPORTED;
102
        return EE_UNSUPPORTED;
103
 
103
 
104
    /* Check if the ELF image starts on a page boundary */
104
    /* Check if the ELF image starts on a page boundary */
105
    if (ALIGN_UP((uintptr_t)header, PAGE_SIZE) != (uintptr_t)header)
105
    if (ALIGN_UP((uintptr_t)header, PAGE_SIZE) != (uintptr_t)header)
106
        return EE_UNSUPPORTED;
106
        return EE_UNSUPPORTED;
107
 
107
 
108
    /* Walk through all segment headers and process them. */
108
    /* Walk through all segment headers and process them. */
109
    for (i = 0; i < header->e_phnum; i++) {
109
    for (i = 0; i < header->e_phnum; i++) {
110
        elf_segment_header_t *seghdr;
110
        elf_segment_header_t *seghdr;
111
 
111
 
112
        seghdr = &((elf_segment_header_t *)(((uint8_t *) header) +
112
        seghdr = &((elf_segment_header_t *)(((uint8_t *) header) +
113
            header->e_phoff))[i];
113
            header->e_phoff))[i];
114
        rc = segment_header(seghdr, header, as, flags);
114
        rc = segment_header(seghdr, header, as, flags);
115
        if (rc != EE_OK)
115
        if (rc != EE_OK)
116
            return rc;
116
            return rc;
117
    }
117
    }
118
 
118
 
119
    /* Inspect all section headers and proccess them. */
119
    /* Inspect all section headers and proccess them. */
120
    for (i = 0; i < header->e_shnum; i++) {
120
    for (i = 0; i < header->e_shnum; i++) {
121
        elf_section_header_t *sechdr;
121
        elf_section_header_t *sechdr;
122
 
122
 
123
        sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
123
        sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
124
            header->e_shoff))[i];
124
            header->e_shoff))[i];
125
        rc = section_header(sechdr, header, as);
125
        rc = section_header(sechdr, header, as);
126
        if (rc != EE_OK)
126
        if (rc != EE_OK)
127
            return rc;
127
            return rc;
128
    }
128
    }
129
 
129
 
130
    return EE_OK;
130
    return EE_OK;
131
}
131
}
132
 
132
 
133
/** Print error message according to error code.
133
/** Print error message according to error code.
134
 *
134
 *
135
 * @param rc Return code returned by elf_load().
135
 * @param rc Return code returned by elf_load().
136
 *
136
 *
137
 * @return NULL terminated description of error.
137
 * @return NULL terminated description of error.
138
 */
138
 */
139
char *elf_error(unsigned int rc)
139
char *elf_error(unsigned int rc)
140
{
140
{
141
    ASSERT(rc < sizeof(error_codes) / sizeof(char *));
141
    ASSERT(rc < sizeof(error_codes) / sizeof(char *));
142
 
142
 
143
    return error_codes[rc];
143
    return error_codes[rc];
144
}
144
}
145
 
145
 
146
/** Process segment header.
146
/** Process segment header.
147
 *
147
 *
148
 * @param entry Segment header.
148
 * @param entry Segment header.
149
 * @param elf ELF header.
149
 * @param elf ELF header.
150
 * @param as Address space into wich the ELF is being loaded.
150
 * @param as Address space into wich the ELF is being loaded.
151
 *
151
 *
152
 * @return EE_OK on success, error code otherwise.
152
 * @return EE_OK on success, error code otherwise.
153
 */
153
 */
154
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,
155
    as_t *as, int flags)
155
    as_t *as, int flags)
156
{
156
{
157
    char *interp;
157
    char *interp;
158
 
158
 
159
    switch (entry->p_type) {
159
    switch (entry->p_type) {
160
    case PT_NULL:
160
    case PT_NULL:
161
    case PT_PHDR:
161
    case PT_PHDR:
162
        break;
162
        break;
163
    case PT_LOAD:
163
    case PT_LOAD:
164
        return load_segment(entry, elf, as);
164
        return load_segment(entry, elf, as);
165
        break;
165
        break;
166
    case PT_DYNAMIC:
166
    case PT_DYNAMIC:
167
    case PT_INTERP:
167
    case PT_INTERP:
168
        interp = (char *)elf + entry->p_offset;
168
        interp = (char *)elf + entry->p_offset;
-
 
169
        /* DO NOT COMMIT ME */
169
        if (memcmp(interp, ELF_INTERP_ZSTR, ELF_INTERP_ZLEN) != 0) {
170
        /*if (memcmp((uintptr_t)interp, (uintptr_t)ELF_INTERP_ZSTR,
-
 
171
            ELF_INTERP_ZLEN) != 0) {
170
            return EE_UNSUPPORTED;
172
            return EE_UNSUPPORTED;
171
        }
173
        }*/
172
        if ((flags & ELD_F_LOADER) == 0) {
174
        if ((flags & ELD_F_LOADER) == 0) {
173
            return EE_LOADER;
175
            return EE_LOADER;
174
        }
176
        }
175
        break;
177
        break;
176
    case PT_SHLIB:
178
    case PT_SHLIB:
177
    case PT_NOTE:
179
    case PT_NOTE:
178
    case PT_LOPROC:
180
    case PT_LOPROC:
179
    case PT_HIPROC:
181
    case PT_HIPROC:
180
    default:
182
    default:
181
        return EE_UNSUPPORTED;
183
        return EE_UNSUPPORTED;
182
        break;
184
        break;
183
    }
185
    }
184
    return EE_OK;
186
    return EE_OK;
185
}
187
}
186
 
188
 
187
/** Load segment described by program header entry.
189
/** Load segment described by program header entry.
188
 *
190
 *
189
 * @param entry Program header entry describing segment to be loaded.
191
 * @param entry Program header entry describing segment to be loaded.
190
 * @param elf ELF header.
192
 * @param elf ELF header.
191
 * @param as Address space into wich the ELF is being loaded.
193
 * @param as Address space into wich the ELF is being loaded.
192
 *
194
 *
193
 * @return EE_OK on success, error code otherwise.
195
 * @return EE_OK on success, error code otherwise.
194
 */
196
 */
195
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)
196
{
198
{
197
    as_area_t *a;
199
    as_area_t *a;
198
    int flags = 0;
200
    int flags = 0;
199
    mem_backend_data_t backend_data;
201
    mem_backend_data_t backend_data;
200
    uintptr_t base;
202
    uintptr_t base;
201
    size_t mem_sz;
203
    size_t mem_sz;
202
   
204
   
203
    backend_data.elf = elf;
205
    backend_data.elf = elf;
204
    backend_data.segment = entry;
206
    backend_data.segment = entry;
205
 
207
 
206
    if (entry->p_align > 1) {
208
    if (entry->p_align > 1) {
207
        if ((entry->p_offset % entry->p_align) !=
209
        if ((entry->p_offset % entry->p_align) !=
208
            (entry->p_vaddr % entry->p_align)) {
210
            (entry->p_vaddr % entry->p_align)) {
209
            return EE_INVALID;
211
            return EE_INVALID;
210
        }
212
        }
211
    }
213
    }
212
 
214
 
213
    if (entry->p_flags & PF_X)
215
    if (entry->p_flags & PF_X)
214
        flags |= AS_AREA_EXEC;
216
        flags |= AS_AREA_EXEC;
215
    if (entry->p_flags & PF_W)
217
    if (entry->p_flags & PF_W)
216
        flags |= AS_AREA_WRITE;
218
        flags |= AS_AREA_WRITE;
217
    if (entry->p_flags & PF_R)
219
    if (entry->p_flags & PF_R)
218
        flags |= AS_AREA_READ;
220
        flags |= AS_AREA_READ;
219
    flags |= AS_AREA_CACHEABLE;
221
    flags |= AS_AREA_CACHEABLE;
220
 
222
 
221
    /*
223
    /*
222
     * Align vaddr down, inserting a little "gap" at the beginning.
224
     * Align vaddr down, inserting a little "gap" at the beginning.
223
     * Adjust area size, so that its end remains in place.
225
     * Adjust area size, so that its end remains in place.
224
     */
226
     */
225
    base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
227
    base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
226
    mem_sz = entry->p_memsz + (entry->p_vaddr - base);
228
    mem_sz = entry->p_memsz + (entry->p_vaddr - base);
227
 
229
 
228
    a = as_area_create(as, flags, mem_sz, base,
230
    a = as_area_create(as, flags, mem_sz, base,
229
        AS_AREA_ATTR_NONE, &elf_backend, &backend_data);
231
        AS_AREA_ATTR_NONE, &elf_backend, &backend_data);
230
    if (!a)
232
    if (!a)
231
        return EE_MEMORY;
233
        return EE_MEMORY;
232
   
234
   
233
    /*
235
    /*
234
     * The segment will be mapped on demand by elf_page_fault().
236
     * The segment will be mapped on demand by elf_page_fault().
235
     */
237
     */
236
 
238
 
237
    return EE_OK;
239
    return EE_OK;
238
}
240
}
239
 
241
 
240
/** Process section header.
242
/** Process section header.
241
 *
243
 *
242
 * @param entry Segment header.
244
 * @param entry Segment header.
243
 * @param elf ELF header.
245
 * @param elf ELF header.
244
 * @param as Address space into wich the ELF is being loaded.
246
 * @param as Address space into wich the ELF is being loaded.
245
 *
247
 *
246
 * @return EE_OK on success, error code otherwise.
248
 * @return EE_OK on success, error code otherwise.
247
 */
249
 */
248
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,
249
    as_t *as)
251
    as_t *as)
250
{
252
{
251
    switch (entry->sh_type) {
253
    switch (entry->sh_type) {
252
    case SHT_PROGBITS:
254
    case SHT_PROGBITS:
253
        if (entry->sh_flags & SHF_TLS) {
255
        if (entry->sh_flags & SHF_TLS) {
254
            /* .tdata */
256
            /* .tdata */
255
        }
257
        }
256
        break;
258
        break;
257
    case SHT_NOBITS:
259
    case SHT_NOBITS:
258
        if (entry->sh_flags & SHF_TLS) {
260
        if (entry->sh_flags & SHF_TLS) {
259
            /* .tbss */
261
            /* .tbss */
260
        }
262
        }
261
        break;
263
        break;
262
    default:
264
    default:
263
        break;
265
        break;
264
    }
266
    }
265
   
267
   
266
    return EE_OK;
268
    return EE_OK;
267
}
269
}
268
 
270
 
269
/** @}
271
/** @}
270
 */
272
 */
271
 
273