Subversion Repositories HelenOS-historic

Rev

Rev 1264 | Rev 1411 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1264 Rev 1409
Line 39... Line 39...
39
#include <mm/frame.h>
39
#include <mm/frame.h>
40
#include <mm/slab.h>
40
#include <mm/slab.h>
41
#include <align.h>
41
#include <align.h>
42
#include <memstr.h>
42
#include <memstr.h>
43
#include <macros.h>
43
#include <macros.h>
-
 
44
#include <arch.h>
44
 
45
 
45
static char *error_codes[] = {
46
static char *error_codes[] = {
46
    "no error",
47
    "no error",
47
    "invalid image",
48
    "invalid image",
48
    "address space error",
49
    "address space error",
Line 53... Line 54...
53
 
54
 
54
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
55
static int segment_header(elf_segment_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);
56
static int section_header(elf_section_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);
57
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
57
 
58
 
-
 
59
static int elf_page_fault(as_area_t *area, __address addr);
-
 
60
static void elf_frame_free(as_area_t *area, __address page, __address frame);
-
 
61
 
-
 
62
mem_backend_t elf_backend = {
-
 
63
    .backend_page_fault = elf_page_fault,
-
 
64
    .backend_frame_free = elf_frame_free
-
 
65
};
-
 
66
 
58
/** ELF loader
67
/** ELF loader
59
 *
68
 *
60
 * @param header Pointer to ELF header in memory
69
 * @param header Pointer to ELF header in memory
61
 * @param as Created and properly mapped address space
70
 * @param as Created and properly mapped address space
62
 * @return EE_OK on success
71
 * @return EE_OK on success
Line 157... Line 166...
157
 * @return EE_OK on success, error code otherwise.
166
 * @return EE_OK on success, error code otherwise.
158
 */
167
 */
159
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
168
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
160
{
169
{
161
    as_area_t *a;
170
    as_area_t *a;
162
    int i, flags = 0;
171
    int flags = 0;
163
    size_t segment_size;
172
    void *backend_data[2] = { elf, entry };
164
    __u8 *segment;
-
 
165
 
173
 
166
    if (entry->p_align > 1) {
174
    if (entry->p_align > 1) {
167
        if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
175
        if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
168
            return EE_INVALID;
176
            return EE_INVALID;
169
        }
177
        }
Line 180... Line 188...
180
     * Check if the virtual address starts on page boundary.
188
     * Check if the virtual address starts on page boundary.
181
     */
189
     */
182
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
190
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
183
        return EE_UNSUPPORTED;
191
        return EE_UNSUPPORTED;
184
 
192
 
185
    segment_size = ALIGN_UP(max(entry->p_filesz, entry->p_memsz), PAGE_SIZE);
-
 
186
    if ((entry->p_flags & PF_W)) {
-
 
187
        /* If writable, copy data (should be COW in the future) */
-
 
188
        segment = malloc(segment_size, 0);
-
 
189
        memsetb((__address) (segment + entry->p_filesz), segment_size - entry->p_filesz, 0);
-
 
190
        memcpy(segment, (void *) (((__address) elf) + entry->p_offset), entry->p_filesz);
-
 
191
    } else /* Map identically original data */
-
 
192
        segment = ((void *) elf) + entry->p_offset;
-
 
193
 
-
 
194
    a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE);
193
    a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE, &elf_backend, backend_data);
195
    if (!a)
194
    if (!a)
196
        return EE_MEMORY;
195
        return EE_MEMORY;
197
   
196
   
-
 
197
    /*
198
    for (i = 0; i < SIZE2FRAMES(entry->p_filesz); i++) {
198
     * The segment will be mapped on demand by elf_page_fault().
199
        as_set_mapping(as, entry->p_vaddr + i*PAGE_SIZE, KA2PA(((__address) segment) + i*PAGE_SIZE));
-
 
200
    }
199
     */
201
   
200
 
202
    return EE_OK;
201
    return EE_OK;
203
}
202
}
204
 
203
 
205
/** Process section header.
204
/** Process section header.
206
 *
205
 *
Line 217... Line 216...
217
        break;
216
        break;
218
    }
217
    }
219
   
218
   
220
    return EE_OK;
219
    return EE_OK;
221
}
220
}
-
 
221
 
-
 
222
/** Service a page fault in the ELF backend address space area.
-
 
223
 *
-
 
224
 * The address space area and page tables must be already locked.
-
 
225
 *
-
 
226
 * @param area Pointer to the address space area.
-
 
227
 * @param addr Faulting virtual address.
-
 
228
 *
-
 
229
 * @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e. serviced).
-
 
230
 */
-
 
231
int elf_page_fault(as_area_t *area, __address addr)
-
 
232
{
-
 
233
    elf_header_t *elf = (elf_header_t *) area->backend_data[0];
-
 
234
    elf_segment_header_t *entry = (elf_segment_header_t *) area->backend_data[1];
-
 
235
    __address base, frame;
-
 
236
    index_t i;
-
 
237
 
-
 
238
    ASSERT((addr >= entry->p_vaddr) && (addr < entry->p_vaddr + entry->p_memsz));
-
 
239
    i = (addr - entry->p_vaddr) >> PAGE_WIDTH;
-
 
240
    base = (__address) (((void *) elf) + entry->p_offset);
-
 
241
    ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
-
 
242
   
-
 
243
    if (ALIGN_DOWN(addr, PAGE_SIZE) + PAGE_SIZE < entry->p_vaddr + entry->p_filesz) {
-
 
244
        /*
-
 
245
         * Initialized portion of the segment. The memory is backed
-
 
246
         * directly by the content of the ELF image. Pages are
-
 
247
         * only copied if the segment is writable so that there
-
 
248
         * can be more instantions of the same memory ELF image
-
 
249
         * used at a time. Note that this could be later done
-
 
250
         * as COW.
-
 
251
         */
-
 
252
        if (entry->p_flags & PF_W) {
-
 
253
            frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
254
            memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), FRAME_SIZE);
-
 
255
        } else {
-
 
256
            frame = KA2PA(base + i*FRAME_SIZE);
-
 
257
        }  
-
 
258
    } else if (ALIGN_DOWN(addr, PAGE_SIZE) >= ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
-
 
259
        /*
-
 
260
         * This is the uninitialized portion of the segment.
-
 
261
         * It is not physically present in the ELF image.
-
 
262
         * To resolve the situation, a frame must be allocated
-
 
263
         * and cleared.
-
 
264
         */
-
 
265
        frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
266
        memsetb(PA2KA(frame), FRAME_SIZE, 0);
-
 
267
    } else {
-
 
268
        size_t size;
-
 
269
        /*
-
 
270
         * The mixed case.
-
 
271
         * The lower part is backed by the ELF image and
-
 
272
         * the upper part is anonymous memory.
-
 
273
         */
-
 
274
        size = entry->p_filesz - (i<<PAGE_WIDTH);
-
 
275
        frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
276
        memsetb(PA2KA(frame) + size, FRAME_SIZE - size, 0);
-
 
277
        memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), size);
-
 
278
    }
-
 
279
   
-
 
280
    page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
-
 
281
        if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
-
 
282
                panic("Could not insert used space.\n");
-
 
283
 
-
 
284
    return AS_PF_OK;
-
 
285
}
-
 
286
 
-
 
287
/** Free a frame that is backed by the ELF backend.
-
 
288
 *
-
 
289
 * The address space area and page tables must be already locked.
-
 
290
 *
-
 
291
 * @param area Pointer to the address space area.
-
 
292
 * @param page Page that is mapped to frame. Must be aligned to PAGE_SIZE.
-
 
293
 * @param frame Frame to be released.
-
 
294
 *
-
 
295
 */
-
 
296
void elf_frame_free(as_area_t *area, __address page, __address frame)
-
 
297
{
-
 
298
    elf_header_t *elf = (elf_header_t *) area->backend_data[0];
-
 
299
    elf_segment_header_t *entry = (elf_segment_header_t *) area->backend_data[1];
-
 
300
    __address base;
-
 
301
    index_t i;
-
 
302
   
-
 
303
    ASSERT((page >= entry->p_vaddr) && (page < entry->p_vaddr + entry->p_memsz));
-
 
304
    i = (page - entry->p_vaddr) >> PAGE_WIDTH;
-
 
305
    base = (__address) (((void *) elf) + entry->p_offset);
-
 
306
    ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
-
 
307
   
-
 
308
    if (page + PAGE_SIZE < ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
-
 
309
        if (entry->p_flags & PF_W) {
-
 
310
            /*
-
 
311
             * Free the frame with the copy of writable segment data.
-
 
312
             */
-
 
313
            frame_free(ADDR2PFN(frame));
-
 
314
        }
-
 
315
    } else {
-
 
316
        /*
-
 
317
         * The frame is either anonymous memory or the mixed case (i.e. lower
-
 
318
         * part is backed by the ELF image and the upper is anonymous).
-
 
319
         * In any case, a frame needs to be freed.
-
 
320
         */
-
 
321
        frame_free(ADDR2PFN(frame));
-
 
322
    }
-
 
323
}