Subversion Repositories HelenOS

Rev

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

Rev 2932 Rev 2949
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
#define RTLD_BIAS 0x80000
-
 
48
//#define RTLD_BIAS 0
48
 
49
 
49
static char *error_codes[] = {
50
static char *error_codes[] = {
50
    "no error",
51
    "no error",
51
    "invalid image",
52
    "invalid image",
52
    "address space error",
53
    "address space error",
53
    "incompatible image",
54
    "incompatible image",
54
    "unsupported image type",
55
    "unsupported image type",
55
    "irrecoverable error"
56
    "irrecoverable error"
56
};
57
};
57
 
58
 
58
static int segment_header(int fd, elf_header_t *elf);
59
static int segment_header(int fd, elf_header_t *elf);
59
static int section_header(elf_section_header_t *entry, elf_header_t *elf);
60
static int section_header(elf_section_header_t *entry, elf_header_t *elf);
60
static int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf);
61
static int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf);
61
 
62
 
62
typedef void (*epoint_t)(void);
63
typedef void (*epoint_t)(void);
63
 
64
 
64
/** ELF loader
65
/** ELF loader
65
 *
66
 *
66
 * @param header Pointer to ELF header in memory
67
 * @param header Pointer to ELF header in memory
67
 * @return EE_OK on success
68
 * @return EE_OK on success
68
 */
69
 */
69
unsigned int elf_load(int fd, elf_header_t *header)
70
unsigned int elf_load(int fd, elf_header_t *header)
70
{
71
{
71
    int i, rc;
72
    int i, rc;
72
 
73
 
73
    rc = read(fd, header, sizeof(elf_header_t));
74
    rc = read(fd, header, sizeof(elf_header_t));
74
    if (rc < 0) {
75
    if (rc < 0) {
75
        printf("read error\n");
76
        printf("read error\n");
76
        return EE_INVALID;
77
        return EE_INVALID;
77
    }
78
    }
78
 
79
 
79
    printf("ELF-load:");
80
    printf("ELF-load:");
80
    /* Identify ELF */
81
    /* Identify ELF */
81
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
82
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
82
        header->e_ident[EI_MAG1] != ELFMAG1 ||
83
        header->e_ident[EI_MAG1] != ELFMAG1 ||
83
        header->e_ident[EI_MAG2] != ELFMAG2 ||
84
        header->e_ident[EI_MAG2] != ELFMAG2 ||
84
        header->e_ident[EI_MAG3] != ELFMAG3) {
85
        header->e_ident[EI_MAG3] != ELFMAG3) {
85
        printf("invalid header\n");
86
        printf("invalid header\n");
86
        return EE_INVALID;
87
        return EE_INVALID;
87
    }
88
    }
88
   
89
   
89
    /* Identify ELF compatibility */
90
    /* Identify ELF compatibility */
90
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
91
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
91
        header->e_machine != ELF_MACHINE ||
92
        header->e_machine != ELF_MACHINE ||
92
        header->e_ident[EI_VERSION] != EV_CURRENT ||
93
        header->e_ident[EI_VERSION] != EV_CURRENT ||
93
        header->e_version != EV_CURRENT ||
94
        header->e_version != EV_CURRENT ||
94
        header->e_ident[EI_CLASS] != ELF_CLASS) {
95
        header->e_ident[EI_CLASS] != ELF_CLASS) {
95
        printf("incompatible data/version/class\n");
96
        printf("incompatible data/version/class\n");
96
        return EE_INCOMPATIBLE;
97
        return EE_INCOMPATIBLE;
97
    }
98
    }
98
 
99
 
99
    if (header->e_phentsize != sizeof(elf_segment_header_t))
100
    if (header->e_phentsize != sizeof(elf_segment_header_t))
100
        return EE_INCOMPATIBLE;
101
        return EE_INCOMPATIBLE;
101
 
102
 
102
    if (header->e_shentsize != sizeof(elf_section_header_t))
103
    if (header->e_shentsize != sizeof(elf_section_header_t))
103
        return EE_INCOMPATIBLE;
104
        return EE_INCOMPATIBLE;
104
 
105
 
105
    /* Check if the object type is supported. */
106
    /* Check if the object type is supported. */
106
    if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
107
    if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
107
        printf("Object type %d is not supported\n", header->e_type);
108
        printf("Object type %d is not supported\n", header->e_type);
108
        return EE_UNSUPPORTED;
109
        return EE_UNSUPPORTED;
109
    }
110
    }
110
    if (header->e_type == ET_DYN) header->e_entry += RTLD_BIAS;
111
    if (header->e_type == ET_DYN) header->e_entry += RTLD_BIAS;
111
 
112
 
112
    printf("parse segments\n");
113
    printf("parse segments\n");
113
 
114
 
114
    /* Walk through all segment headers and process them. */
115
    /* Walk through all segment headers and process them. */
115
    for (i = 0; i < header->e_phnum; i++) {
116
    for (i = 0; i < header->e_phnum; i++) {
116
 
117
 
117
        /* Seek to start of header */
118
        /* Seek to start of header */
118
        lseek(fd, header->e_phoff + i * sizeof(elf_segment_header_t), SEEK_SET);
119
        lseek(fd, header->e_phoff + i * sizeof(elf_segment_header_t), SEEK_SET);
119
 
120
 
120
        rc = segment_header(fd, header);
121
        rc = segment_header(fd, header);
121
        if (rc != EE_OK)
122
        if (rc != EE_OK)
122
            return rc;
123
            return rc;
123
    }
124
    }
124
 
125
 
125
    printf("parse sections\n");
126
    printf("parse sections\n");
126
 
127
 
127
    /* Inspect all section headers and proccess them. */
128
    /* Inspect all section headers and proccess them. */
128
    for (i = 0; i < header->e_shnum; i++) {
129
    for (i = 0; i < header->e_shnum; i++) {
129
/*      elf_section_header_t *sechdr;
130
/*      elf_section_header_t *sechdr;
130
 
131
 
131
        sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
132
        sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
132
            header->e_shoff))[i];
133
            header->e_shoff))[i];
133
        rc = section_header(sechdr, header);
134
        rc = section_header(sechdr, header);
134
        if (rc != EE_OK)
135
        if (rc != EE_OK)
135
            return rc;*/
136
            return rc;*/
136
    }
137
    }
137
 
138
 
138
    printf("done\n");
139
    printf("done\n");
139
 
140
 
140
    return EE_OK;
141
    return EE_OK;
141
}
142
}
142
 
143
 
143
/** Print error message according to error code.
144
/** Print error message according to error code.
144
 *
145
 *
145
 * @param rc Return code returned by elf_load().
146
 * @param rc Return code returned by elf_load().
146
 *
147
 *
147
 * @return NULL terminated description of error.
148
 * @return NULL terminated description of error.
148
 */
149
 */
149
char *elf_error(unsigned int rc)
150
char *elf_error(unsigned int rc)
150
{
151
{
151
    assert(rc < sizeof(error_codes) / sizeof(char *));
152
    assert(rc < sizeof(error_codes) / sizeof(char *));
152
 
153
 
153
    return error_codes[rc];
154
    return error_codes[rc];
154
}
155
}
155
 
156
 
156
/** Process segment header.
157
/** Process segment header.
157
 *
158
 *
158
 * @param entry Segment header.
159
 * @param entry Segment header.
159
 * @param elf ELF header.
160
 * @param elf ELF header.
160
 *
161
 *
161
 * @return EE_OK on success, error code otherwise.
162
 * @return EE_OK on success, error code otherwise.
162
 */
163
 */
163
static int segment_header(int fd, elf_header_t *elf)
164
static int segment_header(int fd, elf_header_t *elf)
164
{
165
{
165
    static elf_segment_header_t entry_buf;
166
    static elf_segment_header_t entry_buf;
166
    elf_segment_header_t *entry = &entry_buf;
167
    elf_segment_header_t *entry = &entry_buf;
167
    int rc;
168
    int rc;
168
 
169
 
169
    rc = read(fd, entry, sizeof(elf_segment_header_t));
170
    rc = read(fd, entry, sizeof(elf_segment_header_t));
170
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }
171
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }
171
 
172
 
172
    switch (entry->p_type) {
173
    switch (entry->p_type) {
173
    case PT_NULL:
174
    case PT_NULL:
174
    case PT_PHDR:
175
    case PT_PHDR:
175
        break;
176
        break;
176
    case PT_LOAD:
177
    case PT_LOAD:
177
        return load_segment(fd, entry, elf);
178
        return load_segment(fd, entry, elf);
178
        break;
179
        break;
179
    case PT_DYNAMIC:
180
    case PT_DYNAMIC:
180
    case PT_INTERP:
181
    case PT_INTERP:
181
    case PT_SHLIB:
182
    case PT_SHLIB:
182
    case PT_NOTE:
183
    case PT_NOTE:
183
    case PT_LOPROC:
184
    case PT_LOPROC:
184
    case PT_HIPROC:
185
    case PT_HIPROC:
185
    default:
186
    default:
186
        printf("segment p_type %d unknown\n", entry->p_type);
187
        printf("segment p_type %d unknown\n", entry->p_type);
187
        return EE_UNSUPPORTED;
188
        return EE_UNSUPPORTED;
188
        break;
189
        break;
189
    }
190
    }
190
    return EE_OK;
191
    return EE_OK;
191
}
192
}
192
 
193
 
193
/** Load segment described by program header entry.
194
/** Load segment described by program header entry.
194
 *
195
 *
195
 * @param entry Program header entry describing segment to be loaded.
196
 * @param entry Program header entry describing segment to be loaded.
196
 * @param elf ELF header.
197
 * @param elf ELF header.
197
 *
198
 *
198
 * @return EE_OK on success, error code otherwise.
199
 * @return EE_OK on success, error code otherwise.
199
 */
200
 */
200
int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf)
201
int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf)
201
{
202
{
202
    void *a;
203
    void *a;
203
    int flags = 0;
204
    int flags = 0;
204
    uintptr_t bias;
205
    uintptr_t bias;
205
    int rc;
206
    int rc;
206
 
207
 
207
    printf("load segment at addr 0x%x, size 0x%x\n", entry->p_vaddr,
208
    printf("load segment at addr 0x%x, size 0x%x\n", entry->p_vaddr,
208
        entry->p_memsz);
209
        entry->p_memsz);
209
   
210
   
210
    bias = (elf->e_type == ET_DYN) ? RTLD_BIAS : 0;
211
    bias = (elf->e_type == ET_DYN) ? RTLD_BIAS : 0;
211
 
212
 
212
    if (entry->p_align > 1) {
213
    if (entry->p_align > 1) {
213
        if ((entry->p_offset % entry->p_align) !=
214
        if ((entry->p_offset % entry->p_align) !=
214
            (entry->p_vaddr % entry->p_align)) {
215
            (entry->p_vaddr % entry->p_align)) {
215
            printf("align check 1 failed offset%%align=%d, vaddr%%align=%d\n",
216
            printf("align check 1 failed offset%%align=%d, vaddr%%align=%d\n",
216
            entry->p_offset % entry->p_align,
217
            entry->p_offset % entry->p_align,
217
            entry->p_vaddr % entry->p_align
218
            entry->p_vaddr % entry->p_align
218
            );
219
            );
219
            return EE_INVALID;
220
            return EE_INVALID;
220
        }
221
        }
221
    }
222
    }
222
 
223
 
223
/*  if (entry->p_flags & PF_X)
224
/*  if (entry->p_flags & PF_X)
224
        flags |= AS_AREA_EXEC;
225
        flags |= AS_AREA_EXEC;
225
    if (entry->p_flags & PF_W)
226
    if (entry->p_flags & PF_W)
226
        flags |= AS_AREA_WRITE;
227
        flags |= AS_AREA_WRITE;
227
    if (entry->p_flags & PF_R)
228
    if (entry->p_flags & PF_R)
228
        flags |= AS_AREA_READ;
229
        flags |= AS_AREA_READ;
229
    flags |= AS_AREA_CACHEABLE;
230
    flags |= AS_AREA_CACHEABLE;
230
*/
231
*/
231
    /* FIXME: Kernel won't normally allow this, unless you "patch" it */
232
    /* 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;
233
//  flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_EXEC | AS_AREA_CACHEABLE;
-
 
234
    flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
233
 
235
 
234
    /*
236
    /*
235
     * Check if the virtual address starts on page boundary.
237
     * Check if the virtual address starts on page boundary.
236
     */
238
     */
237
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr) {
239
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr) {
238
        printf("align check 2 failed - not page-aligned\n");
240
        printf("align check 2 failed - not page-aligned\n");
239
        printf("vaddr = 0x%x, should be 0x%x\n",
241
        printf("vaddr = 0x%x, should be 0x%x\n",
240
            entry->p_vaddr, ALIGN_UP(entry->p_vaddr, PAGE_SIZE));
242
            entry->p_vaddr, ALIGN_UP(entry->p_vaddr, PAGE_SIZE));
241
        return EE_UNSUPPORTED;
243
        return EE_UNSUPPORTED;
242
    }
244
    }
243
   
245
   
244
    printf("map to p_vaddr=0x%x-0x%x...\n", entry->p_vaddr + bias,
246
    printf("map to p_vaddr=0x%x-0x%x...\n", entry->p_vaddr + bias,
245
    entry->p_vaddr + bias + ALIGN_UP(entry->p_memsz, PAGE_SIZE));
247
    entry->p_vaddr + bias + ALIGN_UP(entry->p_memsz, PAGE_SIZE));
246
 
248
 
247
    a = as_area_create((uint8_t *)entry->p_vaddr + bias,
249
    a = as_area_create((uint8_t *)entry->p_vaddr + bias,
248
        entry->p_memsz, flags);
250
        entry->p_memsz, flags);
249
    if (a == (void *)(-1)) {
251
    if (a == (void *)(-1)) {
250
        printf("memory mapping failed\n");
252
        printf("memory mapping failed\n");
251
        return EE_MEMORY;
253
        return EE_MEMORY;
252
    }
254
    }
253
 
255
 
254
    printf("as_area_create() -> 0x%x\n", (unsigned)a);
256
    printf("as_area_create(0x%x, 0x%x, %d) -> 0x%x\n",
-
 
257
        entry->p_vaddr+bias, entry->p_memsz, flags, (unsigned)a);
255
 
258
 
256
    /*
259
    /*
257
     * Load segment data
260
     * Load segment data
258
     */
261
     */
-
 
262
    printf("seek to %d\n", entry->p_offset);
259
    rc = lseek(fd, entry->p_offset, SEEK_SET);
263
    rc = lseek(fd, entry->p_offset, SEEK_SET);
260
    if (rc < 0) { printf("seek error\n"); return EE_INVALID; }
264
    if (rc < 0) { printf("seek error\n"); return EE_INVALID; }
261
 
265
 
-
 
266
    printf("read 0x%x bytes to address 0x%x\n", entry->p_filesz, entry->p_vaddr+bias);
262
    rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
267
/*  rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
-
 
268
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }*/
-
 
269
    unsigned left, now;
-
 
270
    uint8_t *dp;
-
 
271
 
-
 
272
    left = entry->p_filesz;
-
 
273
    dp = (uint8_t *)(entry->p_vaddr + bias);
-
 
274
 
-
 
275
    while (left > 0) {
-
 
276
        now = 4096;
-
 
277
        if (now > left) now=left;
-
 
278
        printf("read %d...", now);
-
 
279
        rc = read(fd, dp, now);
263
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }
280
        if (rc < 0) { printf("read error\n"); return EE_INVALID; }
-
 
281
        printf("->%d\n", rc);
-
 
282
        left -= now;
-
 
283
        dp += now;
-
 
284
    }
264
 
285
 
265
    return EE_OK;
286
    return EE_OK;
266
}
287
}
267
 
288
 
268
/** Process section header.
289
/** Process section header.
269
 *
290
 *
270
 * @param entry Segment header.
291
 * @param entry Segment header.
271
 * @param elf ELF header.
292
 * @param elf ELF header.
272
 *
293
 *
273
 * @return EE_OK on success, error code otherwise.
294
 * @return EE_OK on success, error code otherwise.
274
 */
295
 */
275
static int section_header(elf_section_header_t *entry, elf_header_t *elf)
296
static int section_header(elf_section_header_t *entry, elf_header_t *elf)
276
{
297
{
277
    switch (entry->sh_type) {
298
    switch (entry->sh_type) {
278
    case SHT_PROGBITS:
299
    case SHT_PROGBITS:
279
        if (entry->sh_flags & SHF_TLS) {
300
        if (entry->sh_flags & SHF_TLS) {
280
            /* .tdata */
301
            /* .tdata */
281
        }
302
        }
282
        break;
303
        break;
283
    case SHT_NOBITS:
304
    case SHT_NOBITS:
284
        if (entry->sh_flags & SHF_TLS) {
305
        if (entry->sh_flags & SHF_TLS) {
285
            /* .tbss */
306
            /* .tbss */
286
        }
307
        }
287
        break;
308
        break;
288
    default:
309
    default:
289
        break;
310
        break;
290
    }
311
    }
291
   
312
   
292
    return EE_OK;
313
    return EE_OK;
293
}
314
}
294
 
315
 
295
/** @}
316
/** @}
296
 */
317
 */
297
 
318