Subversion Repositories HelenOS

Rev

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

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