Subversion Repositories HelenOS

Rev

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

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