Subversion Repositories HelenOS-historic

Rev

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

Rev 1423 Rev 1424
Line 1... Line 1...
1
/*
1
/*
2
 * Copyright (C) 2006 Sergey Bondari
2
 * Copyright (C) 2006 Sergey Bondari
-
 
3
 * Copyright (C) 2006 Jakub Jermar
3
 * All rights reserved.
4
 * All rights reserved.
4
 *
5
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * are met:
Line 54... Line 55...
54
 
55
 
55
static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
56
static int segment_header(elf_segment_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);
57
static int section_header(elf_section_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);
58
static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as);
58
 
59
 
59
static int elf_page_fault(as_area_t *area, __address addr, pf_access_t access);
-
 
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
 
-
 
67
/** ELF loader
60
/** ELF loader
68
 *
61
 *
69
 * @param header Pointer to ELF header in memory
62
 * @param header Pointer to ELF header in memory
70
 * @param as Created and properly mapped address space
63
 * @param as Created and properly mapped address space
71
 * @return EE_OK on success
64
 * @return EE_OK on success
Line 167... Line 160...
167
 */
160
 */
168
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
161
int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as)
169
{
162
{
170
    as_area_t *a;
163
    as_area_t *a;
171
    int flags = 0;
164
    int flags = 0;
172
    void *backend_data[2] = { elf, entry };
165
    mem_backend_data_t backend_data = { .d1 = (__native) elf, .d2 = (__native) entry };
173
 
166
 
174
    if (entry->p_align > 1) {
167
    if (entry->p_align > 1) {
175
        if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
168
        if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) {
176
            return EE_INVALID;
169
            return EE_INVALID;
177
        }
170
        }
Line 181... Line 174...
181
        flags |= AS_AREA_EXEC;
174
        flags |= AS_AREA_EXEC;
182
    if (entry->p_flags & PF_W)
175
    if (entry->p_flags & PF_W)
183
        flags |= AS_AREA_WRITE;
176
        flags |= AS_AREA_WRITE;
184
    if (entry->p_flags & PF_R)
177
    if (entry->p_flags & PF_R)
185
        flags |= AS_AREA_READ;
178
        flags |= AS_AREA_READ;
-
 
179
    flags |= AS_AREA_CACHEABLE;
186
 
180
 
187
    /*
181
    /*
188
     * Check if the virtual address starts on page boundary.
182
     * Check if the virtual address starts on page boundary.
189
     */
183
     */
190
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
184
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr)
191
        return EE_UNSUPPORTED;
185
        return EE_UNSUPPORTED;
192
 
186
 
193
    a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE, &elf_backend, backend_data);
187
    a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE,
-
 
188
        &elf_backend, &backend_data);
194
    if (!a)
189
    if (!a)
195
        return EE_MEMORY;
190
        return EE_MEMORY;
196
   
191
   
197
    /*
192
    /*
198
     * The segment will be mapped on demand by elf_page_fault().
193
     * The segment will be mapped on demand by elf_page_fault().
Line 216... Line 211...
216
        break;
211
        break;
217
    }
212
    }
218
   
213
   
219
    return EE_OK;
214
    return EE_OK;
220
}
215
}
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
 * @param access Access mode that caused the fault (i.e. read/write/exec).
-
 
229
 *
-
 
230
 * @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e. serviced).
-
 
231
 */
-
 
232
int elf_page_fault(as_area_t *area, __address addr, pf_access_t access)
-
 
233
{
-
 
234
    elf_header_t *elf = (elf_header_t *) area->backend_data[0];
-
 
235
    elf_segment_header_t *entry = (elf_segment_header_t *) area->backend_data[1];
-
 
236
    __address base, frame;
-
 
237
    index_t i;
-
 
238
 
-
 
239
    if (!as_area_check_access(area, access))
-
 
240
        return AS_PF_FAULT;
-
 
241
 
-
 
242
    ASSERT((addr >= entry->p_vaddr) && (addr < entry->p_vaddr + entry->p_memsz));
-
 
243
    i = (addr - entry->p_vaddr) >> PAGE_WIDTH;
-
 
244
    base = (__address) (((void *) elf) + entry->p_offset);
-
 
245
    ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
-
 
246
   
-
 
247
    if (ALIGN_DOWN(addr, PAGE_SIZE) + PAGE_SIZE < entry->p_vaddr + entry->p_filesz) {
-
 
248
        /*
-
 
249
         * Initialized portion of the segment. The memory is backed
-
 
250
         * directly by the content of the ELF image. Pages are
-
 
251
         * only copied if the segment is writable so that there
-
 
252
         * can be more instantions of the same memory ELF image
-
 
253
         * used at a time. Note that this could be later done
-
 
254
         * as COW.
-
 
255
         */
-
 
256
        if (entry->p_flags & PF_W) {
-
 
257
            frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
258
            memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), FRAME_SIZE);
-
 
259
        } else {
-
 
260
            frame = KA2PA(base + i*FRAME_SIZE);
-
 
261
        }  
-
 
262
    } else if (ALIGN_DOWN(addr, PAGE_SIZE) >= ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
-
 
263
        /*
-
 
264
         * This is the uninitialized portion of the segment.
-
 
265
         * It is not physically present in the ELF image.
-
 
266
         * To resolve the situation, a frame must be allocated
-
 
267
         * and cleared.
-
 
268
         */
-
 
269
        frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
270
        memsetb(PA2KA(frame), FRAME_SIZE, 0);
-
 
271
    } else {
-
 
272
        size_t size;
-
 
273
        /*
-
 
274
         * The mixed case.
-
 
275
         * The lower part is backed by the ELF image and
-
 
276
         * the upper part is anonymous memory.
-
 
277
         */
-
 
278
        size = entry->p_filesz - (i<<PAGE_WIDTH);
-
 
279
        frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
-
 
280
        memsetb(PA2KA(frame) + size, FRAME_SIZE - size, 0);
-
 
281
        memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), size);
-
 
282
    }
-
 
283
   
-
 
284
    page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
-
 
285
        if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
-
 
286
                panic("Could not insert used space.\n");
-
 
287
 
-
 
288
    return AS_PF_OK;
-
 
289
}
-
 
290
 
-
 
291
/** Free a frame that is backed by the ELF backend.
-
 
292
 *
-
 
293
 * The address space area and page tables must be already locked.
-
 
294
 *
-
 
295
 * @param area Pointer to the address space area.
-
 
296
 * @param page Page that is mapped to frame. Must be aligned to PAGE_SIZE.
-
 
297
 * @param frame Frame to be released.
-
 
298
 *
-
 
299
 */
-
 
300
void elf_frame_free(as_area_t *area, __address page, __address frame)
-
 
301
{
-
 
302
    elf_header_t *elf = (elf_header_t *) area->backend_data[0];
-
 
303
    elf_segment_header_t *entry = (elf_segment_header_t *) area->backend_data[1];
-
 
304
    __address base;
-
 
305
    index_t i;
-
 
306
   
-
 
307
    ASSERT((page >= entry->p_vaddr) && (page < entry->p_vaddr + entry->p_memsz));
-
 
308
    i = (page - entry->p_vaddr) >> PAGE_WIDTH;
-
 
309
    base = (__address) (((void *) elf) + entry->p_offset);
-
 
310
    ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
-
 
311
   
-
 
312
    if (page + PAGE_SIZE < ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
-
 
313
        if (entry->p_flags & PF_W) {
-
 
314
            /*
-
 
315
             * Free the frame with the copy of writable segment data.
-
 
316
             */
-
 
317
            frame_free(ADDR2PFN(frame));
-
 
318
        }
-
 
319
    } else {
-
 
320
        /*
-
 
321
         * The frame is either anonymous memory or the mixed case (i.e. lower
-
 
322
         * part is backed by the ELF image and the upper is anonymous).
-
 
323
         * In any case, a frame needs to be freed.
-
 
324
         */
-
 
325
        frame_free(ADDR2PFN(frame));
-
 
326
    }
-
 
327
}
-