Subversion Repositories HelenOS-historic

Rev

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

Rev 1248 Rev 1264
1
/*
1
/*
2
 * Copyright (C) 2006 Sergey Bondari
2
 * Copyright (C) 2006 Sergey Bondari
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
-
 
29
/**
-
 
30
 * @file    elf.c
-
 
31
 * @brief   Kernel ELF loader.
-
 
32
 */
-
 
33
 
29
#include <elf.h>
34
#include <elf.h>
30
#include <debug.h>
35
#include <debug.h>
31
#include <arch/types.h>
36
#include <arch/types.h>
32
#include <typedefs.h>
37
#include <typedefs.h>
33
#include <mm/as.h>
38
#include <mm/as.h>
34
#include <mm/frame.h>
39
#include <mm/frame.h>
35
#include <mm/slab.h>
40
#include <mm/slab.h>
36
#include <align.h>
41
#include <align.h>
37
#include <memstr.h>
42
#include <memstr.h>
38
#include <macros.h>
43
#include <macros.h>
39
 
44
 
40
static char *error_codes[] = {
45
static char *error_codes[] = {
41
    "no error",
46
    "no error",
42
    "invalid image",
47
    "invalid image",
43
    "address space error",
48
    "address space error",
44
    "incompatible image",
49
    "incompatible image",
45
    "unsupported image type",
50
    "unsupported image type",
46
    "irrecoverable error"
51
    "irrecoverable error"
47
};
52
};
48
 
53
 
49
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
54
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
50
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as);
55
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as);
51
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
56
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
52
 
57
 
53
/** ELF loader
58
/** ELF loader
54
 *
59
 *
55
 * @param header Pointer to ELF header in memory
60
 * @param header Pointer to ELF header in memory
56
 * @param as Created and properly mapped address space
61
 * @param as Created and properly mapped address space
57
 * @return EE_OK on success
62
 * @return EE_OK on success
58
 */
63
 */
59
int elf_load(elf_header_t *header, as_t * as)
64
int elf_load(elf_header_t *header, as_t * as)
60
{
65
{
61
    int i, rc;
66
    int i, rc;
62
 
67
 
63
    /* Identify ELF */
68
    /* Identify ELF */
64
    if (header->e_ident[EI_MAG0] != ELFMAG0 || header->e_ident[EI_MAG1] != ELFMAG1 ||
69
    if (header->e_ident[EI_MAG0] != ELFMAG0 || header->e_ident[EI_MAG1] != ELFMAG1 ||
65
        header->e_ident[EI_MAG2] != ELFMAG2 || header->e_ident[EI_MAG3] != ELFMAG3) {
70
        header->e_ident[EI_MAG2] != ELFMAG2 || header->e_ident[EI_MAG3] != ELFMAG3) {
66
        return EE_INVALID;
71
        return EE_INVALID;
67
    }
72
    }
68
   
73
   
69
    /* Identify ELF compatibility */
74
    /* Identify ELF compatibility */
70
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING || header->e_machine != ELF_MACHINE ||
75
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING || header->e_machine != ELF_MACHINE ||
71
        header->e_ident[EI_VERSION] != EV_CURRENT || header->e_version != EV_CURRENT ||
76
        header->e_ident[EI_VERSION] != EV_CURRENT || header->e_version != EV_CURRENT ||
72
        header->e_ident[EI_CLASS] != ELF_CLASS) {
77
        header->e_ident[EI_CLASS] != ELF_CLASS) {
73
        return EE_INCOMPATIBLE;
78
        return EE_INCOMPATIBLE;
74
    }
79
    }
75
 
80
 
76
    if (header->e_phentsize != sizeof(elf_segment_header_t))
81
    if (header->e_phentsize != sizeof(elf_segment_header_t))
77
        return EE_INCOMPATIBLE;
82
        return EE_INCOMPATIBLE;
78
 
83
 
79
    if (header->e_shentsize != sizeof(elf_section_header_t))
84
    if (header->e_shentsize != sizeof(elf_section_header_t))
80
        return EE_INCOMPATIBLE;
85
        return EE_INCOMPATIBLE;
81
 
86
 
82
    /* Check if the object type is supported. */
87
    /* Check if the object type is supported. */
83
    if (header->e_type != ET_EXEC)
88
    if (header->e_type != ET_EXEC)
84
        return EE_UNSUPPORTED;
89
        return EE_UNSUPPORTED;
85
 
90
 
86
    /* Walk through all segment headers and process them. */
91
    /* Walk through all segment headers and process them. */
87
    for (i = 0; i < header->e_phnum; i++) {
92
    for (i = 0; i < header->e_phnum; i++) {
88
        rc = segment_header(&((elf_segment_header_t *)(((__u8 *) header) + header->e_phoff))[i], header, as);
93
        rc = segment_header(&((elf_segment_header_t *)(((__u8 *) header) + header->e_phoff))[i], header, as);
89
        if (rc != EE_OK)
94
        if (rc != EE_OK)
90
            return rc;
95
            return rc;
91
    }
96
    }
92
 
97
 
93
    /* Inspect all section headers and proccess them. */
98
    /* Inspect all section headers and proccess them. */
94
    for (i = 0; i < header->e_shnum; i++) {
99
    for (i = 0; i < header->e_shnum; i++) {
95
        rc = section_header(&((elf_section_header_t *)(((__u8 *) header) + header->e_shoff))[i], header, as);
100
        rc = section_header(&((elf_section_header_t *)(((__u8 *) header) + header->e_shoff))[i], header, as);
96
        if (rc != EE_OK)
101
        if (rc != EE_OK)
97
            return rc;
102
            return rc;
98
    }
103
    }
99
 
104
 
100
    return EE_OK;
105
    return EE_OK;
101
}
106
}
102
 
107
 
103
/** Print error message according to error code.
108
/** Print error message according to error code.
104
 *
109
 *
105
 * @param rc Return code returned by elf_load().
110
 * @param rc Return code returned by elf_load().
106
 *
111
 *
107
 * @return NULL terminated description of error.
112
 * @return NULL terminated description of error.
108
 */
113
 */
109
char *elf_error(int rc)
114
char *elf_error(int rc)
110
{
115
{
111
    ASSERT(rc < sizeof(error_codes)/sizeof(char *));
116
    ASSERT(rc < sizeof(error_codes)/sizeof(char *));
112
 
117
 
113
    return error_codes[rc];
118
    return error_codes[rc];
114
}
119
}
115
 
120
 
116
/** Process segment header.
121
/** Process segment header.
117
 *
122
 *
118
 * @param entry Segment header.
123
 * @param entry Segment header.
119
 * @param elf ELF header.
124
 * @param elf ELF header.
120
 * @param as Address space into wich the ELF is being loaded.
125
 * @param as Address space into wich the ELF is being loaded.
121
 *
126
 *
122
 * @return EE_OK on success, error code otherwise.
127
 * @return EE_OK on success, error code otherwise.
123
 */
128
 */
124
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
129
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
125
{
130
{
126
    switch (entry->p_type) {
131
    switch (entry->p_type) {
127
        case PT_NULL:
132
        case PT_NULL:
128
        case PT_PHDR:
133
        case PT_PHDR:
129
        break;
134
        break;
130
        case PT_LOAD:
135
        case PT_LOAD:
131
        return load_segment(entry, elf, as);
136
        return load_segment(entry, elf, as);
132
        break;
137
        break;
133
        case PT_DYNAMIC:
138
        case PT_DYNAMIC:
134
        case PT_INTERP:
139
        case PT_INTERP:
135
        case PT_SHLIB:
140
        case PT_SHLIB:
136
        case PT_NOTE:
141
        case PT_NOTE:
137
        case PT_LOPROC:
142
        case PT_LOPROC:
138
        case PT_HIPROC:
143
        case PT_HIPROC:
139
        default:
144
        default:
140
        return EE_UNSUPPORTED;
145
        return EE_UNSUPPORTED;
141
        break;
146
        break;
142
    }
147
    }
143
    return EE_OK;
148
    return EE_OK;
144
}
149
}
145
 
150
 
146
/** Load segment described by program header entry.
151
/** Load segment described by program header entry.
147
 *
152
 *
148
 * @param entry Program header entry describing segment to be loaded.
153
 * @param entry Program header entry describing segment to be loaded.
149
 * @param elf ELF header.
154
 * @param elf ELF header.
150
 * @param as Address space into wich the ELF is being loaded.
155
 * @param as Address space into wich the ELF is being loaded.
151
 *
156
 *
152
 * @return EE_OK on success, error code otherwise.
157
 * @return EE_OK on success, error code otherwise.
153
 */
158
 */
154
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
159
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
155
{
160
{
156
    as_area_t *a;
161
    as_area_t *a;
157
    int i, flags = 0;
162
    int i, flags = 0;
158
    size_t segment_size;
163
    size_t segment_size;
159
    __u8 *segment;
164
    __u8 *segment;
160
 
165
 
161
    if (entry->p_align > 1) {
166
    if (entry->p_align > 1) {
162
        if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
167
        if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
163
            return EE_INVALID;
168
            return EE_INVALID;
164
        }
169
        }
165
    }
170
    }
166
 
171
 
167
    if (entry->p_flags & PF_X)
172
    if (entry->p_flags & PF_X)
168
        flags |= AS_AREA_EXEC;
173
        flags |= AS_AREA_EXEC;
169
    if (entry->p_flags & PF_W)
174
    if (entry->p_flags & PF_W)
170
        flags |= AS_AREA_WRITE;
175
        flags |= AS_AREA_WRITE;
171
    if (entry->p_flags & PF_R)
176
    if (entry->p_flags & PF_R)
172
        flags |= AS_AREA_READ;
177
        flags |= AS_AREA_READ;
173
 
178
 
174
    /*
179
    /*
175
     * Check if the virtual address starts on page boundary.
180
     * Check if the virtual address starts on page boundary.
176
     */
181
     */
177
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
182
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
178
        return EE_UNSUPPORTED;
183
        return EE_UNSUPPORTED;
179
 
184
 
180
    segment_size = ALIGN_UP(max(entry->p_filesz, entry->p_memsz), PAGE_SIZE);
185
    segment_size = ALIGN_UP(max(entry->p_filesz, entry->p_memsz), PAGE_SIZE);
181
    if ((entry->p_flags & PF_W)) {
186
    if ((entry->p_flags & PF_W)) {
182
        /* If writable, copy data (should be COW in the future) */
187
        /* If writable, copy data (should be COW in the future) */
183
        segment = malloc(segment_size, 0);
188
        segment = malloc(segment_size, 0);
184
        memsetb((__address) (segment + entry->p_filesz), segment_size - entry->p_filesz, 0);
189
        memsetb((__address) (segment + entry->p_filesz), segment_size - entry->p_filesz, 0);
185
        memcpy(segment, (void *) (((__address) elf) + entry->p_offset), entry->p_filesz);
190
        memcpy(segment, (void *) (((__address) elf) + entry->p_offset), entry->p_filesz);
186
    } else /* Map identically original data */
191
    } else /* Map identically original data */
187
        segment = ((void *) elf) + entry->p_offset;
192
        segment = ((void *) elf) + entry->p_offset;
188
 
193
 
189
    a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE);
194
    a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE);
190
    if (!a)
195
    if (!a)
191
        return EE_MEMORY;
196
        return EE_MEMORY;
192
   
197
   
193
    for (i = 0; i < SIZE2FRAMES(entry->p_filesz); i++) {
198
    for (i = 0; i < SIZE2FRAMES(entry->p_filesz); i++) {
194
        as_set_mapping(as, entry->p_vaddr + i*PAGE_SIZE, KA2PA(((__address) segment) + i*PAGE_SIZE));
199
        as_set_mapping(as, entry->p_vaddr + i*PAGE_SIZE, KA2PA(((__address) segment) + i*PAGE_SIZE));
195
    }
200
    }
196
   
201
   
197
    return EE_OK;
202
    return EE_OK;
198
}
203
}
199
 
204
 
200
/** Process section header.
205
/** Process section header.
201
 *
206
 *
202
 * @param entry Segment header.
207
 * @param entry Segment header.
203
 * @param elf ELF header.
208
 * @param elf ELF header.
204
 * @param as Address space into wich the ELF is being loaded.
209
 * @param as Address space into wich the ELF is being loaded.
205
 *
210
 *
206
 * @return EE_OK on success, error code otherwise.
211
 * @return EE_OK on success, error code otherwise.
207
 */
212
 */
208
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as)
213
static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as)
209
{
214
{
210
    switch (entry->sh_type) {
215
    switch (entry->sh_type) {
211
        default:
216
        default:
212
        break;
217
        break;
213
    }
218
    }
214
   
219
   
215
    return EE_OK;
220
    return EE_OK;
216
}
221
}
217
 
222