Subversion Repositories HelenOS

Rev

Rev 2949 | Rev 2962 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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