Subversion Repositories HelenOS-historic

Rev

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

Rev 1238 Rev 1239
Line 124... Line 124...
124
/** Create address space area of common attributes.
124
/** Create address space area of common attributes.
125
 *
125
 *
126
 * The created address space area is added to the target address space.
126
 * The created address space area is added to the target address space.
127
 *
127
 *
128
 * @param as Target address space.
128
 * @param as Target address space.
129
 * @param flags Flags of the area.
129
 * @param flags Flags of the area memory.
130
 * @param size Size of area.
130
 * @param size Size of area.
131
 * @param base Base address of area.
131
 * @param base Base address of area.
-
 
132
 * @param attrs Attributes of the area.
132
 *
133
 *
133
 * @return Address space area on success or NULL on failure.
134
 * @return Address space area on success or NULL on failure.
134
 */
135
 */
135
as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base)
136
as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base, int attrs)
136
{
137
{
137
    ipl_t ipl;
138
    ipl_t ipl;
138
    as_area_t *a;
139
    as_area_t *a;
139
   
140
   
140
    if (base % PAGE_SIZE)
141
    if (base % PAGE_SIZE)
Line 159... Line 160...
159
    a = (as_area_t *) malloc(sizeof(as_area_t), 0);
160
    a = (as_area_t *) malloc(sizeof(as_area_t), 0);
160
 
161
 
161
    spinlock_initialize(&a->lock, "as_area_lock");
162
    spinlock_initialize(&a->lock, "as_area_lock");
162
   
163
   
163
    a->flags = flags;
164
    a->flags = flags;
-
 
165
    a->attributes = attrs;
164
    a->pages = SIZE2FRAMES(size);
166
    a->pages = SIZE2FRAMES(size);
165
    a->base = base;
167
    a->base = base;
166
   
168
   
167
    btree_insert(&as->as_area_btree, base, (void *) a, NULL);
169
    btree_insert(&as->as_area_btree, base, (void *) a, NULL);
168
 
170
 
Line 287... Line 289...
287
 * source area. Moreover, any existing mapping
289
 * source area. Moreover, any existing mapping
288
 * is copied as well, providing thus a mechanism
290
 * is copied as well, providing thus a mechanism
289
 * for sharing group of pages. The source address
291
 * for sharing group of pages. The source address
290
 * space area and any associated mapping is preserved.
292
 * space area and any associated mapping is preserved.
291
 *
293
 *
292
 * @param id Task ID of the accepting task.
294
 * @param dst_id Task ID of the accepting task.
293
 * @param base Base address of the source address space area.
295
 * @param src_base Base address of the source address space area.
294
 *
296
 *
295
 * @return 0 on success or ENOENT if there is no such task or
297
 * @return 0 on success or ENOENT if there is no such task or
296
 *     if there is no such address space area,
298
 *     if there is no such address space area,
297
 *     EPERM if there was a problem in accepting the area or
299
 *     EPERM if there was a problem in accepting the area or
298
 *     ENOMEM if there was a problem in allocating destination
300
 *     ENOMEM if there was a problem in allocating destination
299
 *     address space area.
301
 *     address space area.
300
 */
302
 */
301
int as_area_send(task_id_t id, __address base)
303
int as_area_send(task_id_t dst_id, __address src_base)
302
{
304
{
303
    ipl_t ipl;
305
    ipl_t ipl;
304
    task_t *t;
306
    task_t *t;
305
    count_t i;
307
    count_t i;
306
    as_t *as;
308
    as_t *dst_as;
307
    __address dst_base;
309
    __address dst_base;
308
    int flags;
310
    int src_flags;
309
    size_t size;
311
    size_t src_size;
310
    as_area_t *area;
312
    as_area_t *src_area, *dst_area;
311
   
313
   
312
    ipl = interrupts_disable();
314
    ipl = interrupts_disable();
313
    spinlock_lock(&tasks_lock);
315
    spinlock_lock(&tasks_lock);
314
   
316
   
315
    t = task_find_by_id(id);
317
    t = task_find_by_id(dst_id);
316
    if (!NULL) {
318
    if (!NULL) {
317
        spinlock_unlock(&tasks_lock);
319
        spinlock_unlock(&tasks_lock);
318
        interrupts_restore(ipl);
320
        interrupts_restore(ipl);
319
        return ENOENT;
321
        return ENOENT;
320
    }
322
    }
321
 
323
 
322
    spinlock_lock(&t->lock);
324
    spinlock_lock(&t->lock);
323
    spinlock_unlock(&tasks_lock);
325
    spinlock_unlock(&tasks_lock);
324
 
326
 
325
    as = t->as;
327
    dst_as = t->as;
326
    dst_base = (__address) t->accept_arg.base;
328
    dst_base = (__address) t->accept_arg.base;
327
   
329
   
328
    if (as == AS) {
330
    if (dst_as == AS) {
329
        /*
331
        /*
330
         * The two tasks share the entire address space.
332
         * The two tasks share the entire address space.
331
         * Return error since there is no point in continuing.
333
         * Return error since there is no point in continuing.
332
         */
334
         */
333
        spinlock_unlock(&t->lock);
335
        spinlock_unlock(&t->lock);
334
        interrupts_restore(ipl);
336
        interrupts_restore(ipl);
335
        return EPERM;
337
        return EPERM;
336
    }
338
    }
337
   
339
   
338
    spinlock_lock(&AS->lock);
340
    spinlock_lock(&AS->lock);
339
    area = find_area_and_lock(AS, base);
341
    src_area = find_area_and_lock(AS, src_base);
340
    if (!area) {
342
    if (!src_area) {
341
        /*
343
        /*
342
         * Could not find the source address space area.
344
         * Could not find the source address space area.
343
         */
345
         */
344
        spinlock_unlock(&t->lock);
346
        spinlock_unlock(&t->lock);
345
        spinlock_unlock(&AS->lock);
347
        spinlock_unlock(&AS->lock);
346
        interrupts_restore(ipl);
348
        interrupts_restore(ipl);
347
        return ENOENT;
349
        return ENOENT;
348
    }
350
    }
349
    size = area->pages * PAGE_SIZE;
351
    src_size = src_area->pages * PAGE_SIZE;
350
    flags = area->flags;
352
    src_flags = src_area->flags;
351
    spinlock_unlock(&area->lock);
353
    spinlock_unlock(&src_area->lock);
352
    spinlock_unlock(&AS->lock);
354
    spinlock_unlock(&AS->lock);
353
 
355
 
354
    if ((t->accept_arg.task_id != TASK->taskid) || (t->accept_arg.size != size) ||
356
    if ((t->accept_arg.task_id != TASK->taskid) || (t->accept_arg.size != src_size) ||
355
        (t->accept_arg.flags != flags)) {
357
        (t->accept_arg.flags != src_flags)) {
356
        /*
358
        /*
357
         * Discrepancy in either task ID, size or flags.
359
         * Discrepancy in either task ID, size or flags.
358
         */
360
         */
359
        spinlock_unlock(&t->lock);
361
        spinlock_unlock(&t->lock);
360
        interrupts_restore(ipl);
362
        interrupts_restore(ipl);
361
        return EPERM;
363
        return EPERM;
362
    }
364
    }
363
   
365
   
364
    /*
366
    /*
365
     * Create copy of the address space area.
367
     * Create copy of the source address space area.
-
 
368
     * The destination area is created with AS_AREA_ATTR_PARTIAL
-
 
369
     * attribute set which prevents race condition with
-
 
370
     * preliminary as_page_fault() calls.
366
     */
371
     */
367
    if (!as_area_create(as, flags, size, dst_base)) {
372
    dst_area = as_area_create(dst_as, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL);
-
 
373
    if (!dst_area) {
368
        /*
374
        /*
369
         * Destination address space area could not be created.
375
         * Destination address space area could not be created.
370
         */
376
         */
371
        spinlock_unlock(&t->lock);
377
        spinlock_unlock(&t->lock);
372
        interrupts_restore(ipl);
378
        interrupts_restore(ipl);
373
        return ENOMEM;
379
        return ENOMEM;
374
    }
380
    }
375
   
381
   
376
    /*
-
 
377
     * NOTE: we have just introduced a race condition.
-
 
378
     * The destination task can try to attempt the newly
-
 
379
     * created area before its mapping is copied from
-
 
380
     * the source address space area. In result, frames
-
 
381
     * can get lost.
-
 
382
     *
-
 
383
     * Currently, this race is not solved, but one of the
-
 
384
     * possible solutions would be to sleep in as_page_fault()
-
 
385
     * when this situation is detected.
-
 
386
     */
-
 
387
 
-
 
388
    memsetb((__address) &t->accept_arg, sizeof(as_area_acptsnd_arg_t), 0);
382
    memsetb((__address) &t->accept_arg, sizeof(as_area_acptsnd_arg_t), 0);
389
    spinlock_unlock(&t->lock);
383
    spinlock_unlock(&t->lock);
390
   
384
   
391
    /*
385
    /*
392
     * Avoid deadlock by first locking the address space with lower address.
386
     * Avoid deadlock by first locking the address space with lower address.
393
     */
387
     */
394
    if (as < AS) {
388
    if (dst_as < AS) {
395
        spinlock_lock(&as->lock);
389
        spinlock_lock(&dst_as->lock);
396
        spinlock_lock(&AS->lock);
390
        spinlock_lock(&AS->lock);
397
    } else {
391
    } else {
398
        spinlock_lock(&AS->lock);
392
        spinlock_lock(&AS->lock);
399
        spinlock_lock(&as->lock);
393
        spinlock_lock(&dst_as->lock);
400
    }
394
    }
401
   
395
   
402
    for (i = 0; i < SIZE2FRAMES(size); i++) {
396
    for (i = 0; i < SIZE2FRAMES(src_size); i++) {
403
        pte_t *pte;
397
        pte_t *pte;
404
        __address frame;
398
        __address frame;
405
           
399
           
406
        page_table_lock(AS, false);
400
        page_table_lock(AS, false);
407
        pte = page_mapping_find(AS, base + i*PAGE_SIZE);
401
        pte = page_mapping_find(AS, src_base + i*PAGE_SIZE);
408
        if (pte && PTE_VALID(pte)) {
402
        if (pte && PTE_VALID(pte)) {
409
            ASSERT(PTE_PRESENT(pte));
403
            ASSERT(PTE_PRESENT(pte));
410
            frame = PTE_GET_FRAME(pte);
404
            frame = PTE_GET_FRAME(pte);
411
            if (!(flags & AS_AREA_DEVICE))
405
            if (!(src_flags & AS_AREA_DEVICE))
412
                frame_reference_add(ADDR2PFN(frame));
406
                frame_reference_add(ADDR2PFN(frame));
413
            page_table_unlock(AS, false);
407
            page_table_unlock(AS, false);
414
        } else {
408
        } else {
415
            page_table_unlock(AS, false);
409
            page_table_unlock(AS, false);
416
            continue;
410
            continue;
417
        }
411
        }
418
       
412
       
419
        page_table_lock(as, false);
413
        page_table_lock(dst_as, false);
420
        page_mapping_insert(as, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(flags));
414
        page_mapping_insert(dst_as, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(src_flags));
421
        page_table_unlock(as, false);
415
        page_table_unlock(dst_as, false);
422
    }
416
    }
-
 
417
 
-
 
418
    /*
-
 
419
     * Now the destination address space area has been
-
 
420
     * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
-
 
421
     * attribute.
-
 
422
     */
-
 
423
    spinlock_lock(&dst_area->lock);
-
 
424
    dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
-
 
425
    spinlock_unlock(&dst_area->lock);
423
   
426
   
424
    spinlock_unlock(&AS->lock);
427
    spinlock_unlock(&AS->lock);
425
    spinlock_unlock(&as->lock);
428
    spinlock_unlock(&dst_as->lock);
426
    interrupts_restore(ipl);
429
    interrupts_restore(ipl);
427
   
430
   
428
    return 0;
431
    return 0;
429
}
432
}
430
 
433
 
Line 484... Line 487...
484
         */
487
         */
485
        spinlock_unlock(&AS->lock);
488
        spinlock_unlock(&AS->lock);
486
        return 0;
489
        return 0;
487
    }
490
    }
488
 
491
 
-
 
492
    if (area->attributes & AS_AREA_ATTR_PARTIAL) {
-
 
493
        /*
-
 
494
         * The address space area is not fully initialized.
-
 
495
         * Avoid possible race by returning error.
-
 
496
         */
-
 
497
        spinlock_unlock(&area->lock);
-
 
498
        spinlock_unlock(&AS->lock);
-
 
499
        return 0;      
-
 
500
    }
-
 
501
 
489
    ASSERT(!(area->flags & AS_AREA_DEVICE));
502
    ASSERT(!(area->flags & AS_AREA_DEVICE));
490
 
503
 
491
    page_table_lock(AS, false);
504
    page_table_lock(AS, false);
492
   
505
   
493
    /*
506
    /*
Line 837... Line 850...
837
 */
850
 */
838
 
851
 
839
/** Wrapper for as_area_create(). */
852
/** Wrapper for as_area_create(). */
840
__native sys_as_area_create(__address address, size_t size, int flags)
853
__native sys_as_area_create(__address address, size_t size, int flags)
841
{
854
{
842
    if (as_area_create(AS, flags, size, address))
855
    if (as_area_create(AS, flags, size, address, AS_AREA_ATTR_NONE))
843
        return (__native) address;
856
        return (__native) address;
844
    else
857
    else
845
        return (__native) -1;
858
        return (__native) -1;
846
}
859
}
847
 
860