Subversion Repositories HelenOS-historic

Rev

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

Rev 1309 Rev 1329
Line 362... Line 362...
362
    spinlock_unlock(&AS->lock);
362
    spinlock_unlock(&AS->lock);
363
    interrupts_restore(ipl);
363
    interrupts_restore(ipl);
364
    return 0;
364
    return 0;
365
}
365
}
366
 
366
 
367
/** Send address space area to another task.
367
/** Steal address space area from another task.
368
 *
368
 *
369
 * Address space area is sent to the specified task.
369
 * Address space area is stolen from another task
370
 * If the destination task is willing to accept the
-
 
371
 * area, a new area is created according to the
-
 
372
 * source area. Moreover, any existing mapping
370
 * Moreover, any existing mapping
373
 * is copied as well, providing thus a mechanism
371
 * is copied as well, providing thus a mechanism
374
 * for sharing group of pages. The source address
372
 * for sharing group of pages. The source address
375
 * space area and any associated mapping is preserved.
373
 * space area and any associated mapping is preserved.
376
 *
374
 *
377
 * @param dst_id Task ID of the accepting task.
375
 * @param src_task Pointer of source task
378
 * @param src_base Base address of the source address space area.
376
 * @param src_base Base address of the source address space area.
-
 
377
 * @param acc_size Expected size of the source area
-
 
378
 * @param dst_base Target base address
379
 *
379
 *
380
 * @return Zero on success or ENOENT if there is no such task or
380
 * @return Zero on success or ENOENT if there is no such task or
381
 *     if there is no such address space area,
381
 *     if there is no such address space area,
382
 *     EPERM if there was a problem in accepting the area or
382
 *     EPERM if there was a problem in accepting the area or
383
 *     ENOMEM if there was a problem in allocating destination
383
 *     ENOMEM if there was a problem in allocating destination
384
 *     address space area.
384
 *     address space area.
385
 */
385
 */
386
int as_area_send(task_id_t dst_id, __address src_base)
386
int as_area_steal(task_t *src_task, __address src_base, size_t acc_size,
-
 
387
          __address dst_base)
387
{
388
{
388
    ipl_t ipl;
389
    ipl_t ipl;
389
    task_t *t;
-
 
390
    count_t i;
390
    count_t i;
391
    as_t *dst_as;
391
    as_t *src_as;      
392
    __address dst_base;
-
 
393
    int src_flags;
392
    int src_flags;
394
    size_t src_size;
393
    size_t src_size;
395
    as_area_t *src_area, *dst_area;
394
    as_area_t *src_area, *dst_area;
396
   
-
 
397
    ipl = interrupts_disable();
-
 
398
    spinlock_lock(&tasks_lock);
-
 
399
   
-
 
400
    t = task_find_by_id(dst_id);
-
 
401
    if (!NULL) {
-
 
402
        spinlock_unlock(&tasks_lock);
-
 
403
        interrupts_restore(ipl);
-
 
404
        return ENOENT;
-
 
405
    }
-
 
406
 
395
 
407
    spinlock_lock(&t->lock);
396
    ipl = interrupts_disable();
408
    spinlock_unlock(&tasks_lock);
397
    spinlock_lock(&src_task->lock);
409
 
-
 
410
    dst_as = t->as;
398
    src_as = src_task->as;
411
    dst_base = (__address) t->accept_arg.base;
-
 
412
   
-
 
413
    if (dst_as == AS) {
-
 
414
        /*
-
 
415
         * The two tasks share the entire address space.
-
 
416
         * Return error since there is no point in continuing.
-
 
417
         */
-
 
418
        spinlock_unlock(&t->lock);
-
 
419
        interrupts_restore(ipl);
-
 
420
        return EPERM;
-
 
421
    }
-
 
422
   
399
   
423
    spinlock_lock(&AS->lock);
400
    spinlock_lock(&src_as->lock);
424
    src_area = find_area_and_lock(AS, src_base);
401
    src_area = find_area_and_lock(src_as, src_base);
425
    if (!src_area) {
402
    if (!src_area) {
426
        /*
403
        /*
427
         * Could not find the source address space area.
404
         * Could not find the source address space area.
428
         */
405
         */
429
        spinlock_unlock(&t->lock);
406
        spinlock_unlock(&src_task->lock);
430
        spinlock_unlock(&AS->lock);
407
        spinlock_unlock(&src_as->lock);
431
        interrupts_restore(ipl);
408
        interrupts_restore(ipl);
432
        return ENOENT;
409
        return ENOENT;
433
    }
410
    }
434
    src_size = src_area->pages * PAGE_SIZE;
411
    src_size = src_area->pages * PAGE_SIZE;
435
    src_flags = src_area->flags;
412
    src_flags = src_area->flags;
436
    spinlock_unlock(&src_area->lock);
413
    spinlock_unlock(&src_area->lock);
437
    spinlock_unlock(&AS->lock);
414
    spinlock_unlock(&src_as->lock);
438
 
415
 
439
    if ((t->accept_arg.task_id != TASK->taskid) || (t->accept_arg.size != src_size) ||
-
 
440
        (t->accept_arg.flags != src_flags)) {
-
 
441
        /*
416
 
442
         * Discrepancy in either task ID, size or flags.
417
    if (src_size != acc_size) {
443
         */
-
 
444
        spinlock_unlock(&t->lock);
418
        spinlock_unlock(&src_task->lock);
445
        interrupts_restore(ipl);
419
        interrupts_restore(ipl);
446
        return EPERM;
420
        return EPERM;
447
    }
421
    }
448
   
-
 
449
    /*
422
    /*
450
     * Create copy of the source address space area.
423
     * Create copy of the source address space area.
451
     * The destination area is created with AS_AREA_ATTR_PARTIAL
424
     * The destination area is created with AS_AREA_ATTR_PARTIAL
452
     * attribute set which prevents race condition with
425
     * attribute set which prevents race condition with
453
     * preliminary as_page_fault() calls.
426
     * preliminary as_page_fault() calls.
454
     */
427
     */
455
    dst_area = as_area_create(dst_as, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL);
428
    dst_area = as_area_create(AS, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL);
456
    if (!dst_area) {
429
    if (!dst_area) {
457
        /*
430
        /*
458
         * Destination address space area could not be created.
431
         * Destination address space area could not be created.
459
         */
432
         */
460
        spinlock_unlock(&t->lock);
433
        spinlock_unlock(&src_task->lock);
461
        interrupts_restore(ipl);
434
        interrupts_restore(ipl);
462
        return ENOMEM;
435
        return ENOMEM;
463
    }
436
    }
464
   
437
   
465
    memsetb((__address) &t->accept_arg, sizeof(as_area_acptsnd_arg_t), 0);
-
 
466
    spinlock_unlock(&t->lock);
438
    spinlock_unlock(&src_task->lock);
467
   
439
   
468
    /*
440
    /*
469
     * Avoid deadlock by first locking the address space with lower address.
441
     * Avoid deadlock by first locking the address space with lower address.
470
     */
442
     */
471
    if (dst_as < AS) {
443
    if (AS < src_as) {
472
        spinlock_lock(&dst_as->lock);
-
 
473
        spinlock_lock(&AS->lock);
444
        spinlock_lock(&AS->lock);
-
 
445
        spinlock_lock(&src_as->lock);
474
    } else {
446
    } else {
475
        spinlock_lock(&AS->lock);
447
        spinlock_lock(&AS->lock);
476
        spinlock_lock(&dst_as->lock);
448
        spinlock_lock(&src_as->lock);
477
    }
449
    }
478
   
450
   
479
    for (i = 0; i < SIZE2FRAMES(src_size); i++) {
451
    for (i = 0; i < SIZE2FRAMES(src_size); i++) {
480
        pte_t *pte;
452
        pte_t *pte;
481
        __address frame;
453
        __address frame;
482
           
454
           
483
        page_table_lock(AS, false);
455
        page_table_lock(src_as, false);
484
        pte = page_mapping_find(AS, src_base + i*PAGE_SIZE);
456
        pte = page_mapping_find(src_as, src_base + i*PAGE_SIZE);
485
        if (pte && PTE_VALID(pte)) {
457
        if (pte && PTE_VALID(pte)) {
486
            ASSERT(PTE_PRESENT(pte));
458
            ASSERT(PTE_PRESENT(pte));
487
            frame = PTE_GET_FRAME(pte);
459
            frame = PTE_GET_FRAME(pte);
488
            if (!(src_flags & AS_AREA_DEVICE))
460
            if (!(src_flags & AS_AREA_DEVICE))
489
                frame_reference_add(ADDR2PFN(frame));
461
                frame_reference_add(ADDR2PFN(frame));
490
            page_table_unlock(AS, false);
462
            page_table_unlock(src_as, false);
491
        } else {
463
        } else {
492
            page_table_unlock(AS, false);
464
            page_table_unlock(src_as, false);
493
            continue;
465
            continue;
494
        }
466
        }
495
       
467
       
496
        page_table_lock(dst_as, false);
468
        page_table_lock(AS, false);
497
        page_mapping_insert(dst_as, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(src_flags));
469
        page_mapping_insert(AS, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(src_flags));
498
        page_table_unlock(dst_as, false);
470
        page_table_unlock(AS, false);
499
    }
471
    }
500
 
472
 
501
    /*
473
    /*
502
     * Now the destination address space area has been
474
     * Now the destination address space area has been
503
     * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
475
     * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
Line 506... Line 478...
506
    spinlock_lock(&dst_area->lock);
478
    spinlock_lock(&dst_area->lock);
507
    dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
479
    dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
508
    spinlock_unlock(&dst_area->lock);
480
    spinlock_unlock(&dst_area->lock);
509
   
481
   
510
    spinlock_unlock(&AS->lock);
482
    spinlock_unlock(&AS->lock);
511
    spinlock_unlock(&dst_as->lock);
483
    spinlock_unlock(&src_as->lock);
512
    interrupts_restore(ipl);
484
    interrupts_restore(ipl);
513
   
485
   
514
    return 0;
486
    return 0;
515
}
487
}
516
 
488
 
Line 943... Line 915...
943
    }
915
    }
944
 
916
 
945
    return true;
917
    return true;
946
}
918
}
947
 
919
 
-
 
920
/** Return size of address space of current task pointed to by base */
-
 
921
size_t as_get_size(__address base)
-
 
922
{
-
 
923
    ipl_t ipl;
-
 
924
    as_area_t *src_area;
-
 
925
    size_t size;
-
 
926
 
-
 
927
    ipl = interrupts_disable();
-
 
928
    src_area = find_area_and_lock(AS, base);
-
 
929
    if (src_area){
-
 
930
        size = src_area->pages * PAGE_SIZE;
-
 
931
        spinlock_unlock(&src_area->lock);
-
 
932
    } else {
-
 
933
        size = 0;
-
 
934
    }
-
 
935
    interrupts_restore(ipl);
-
 
936
    return size;
-
 
937
}
-
 
938
 
948
/*
939
/*
949
 * Address space related syscalls.
940
 * Address space related syscalls.
950
 */
941
 */
951
 
942
 
952
/** Wrapper for as_area_create(). */
943
/** Wrapper for as_area_create(). */
Line 968... Line 959...
968
__native sys_as_area_destroy(__address address)
959
__native sys_as_area_destroy(__address address)
969
{
960
{
970
    return (__native) as_area_destroy(AS, address);
961
    return (__native) as_area_destroy(AS, address);
971
}
962
}
972
 
963
 
973
/** Prepare task for accepting address space area from another task.
-
 
974
 *
-
 
975
 * @param uspace_accept_arg Accept structure passed from userspace.
-
 
976
 *
-
 
977
 * @return EPERM if the task ID encapsulated in @uspace_accept_arg references
-
 
978
 *     TASK. Otherwise zero is returned.
-
 
979
 */
-
 
980
__native sys_as_area_accept(as_area_acptsnd_arg_t *uspace_accept_arg)
-
 
981
{
-
 
982
    as_area_acptsnd_arg_t arg;
-
 
983
    int rc;
-
 
984
   
-
 
985
    rc = copy_from_uspace(&arg, uspace_accept_arg, sizeof(as_area_acptsnd_arg_t));
-
 
986
    if (rc != 0)
-
 
987
        return rc;
-
 
988
   
-
 
989
    if (!arg.size)
-
 
990
        return (__native) EPERM;
-
 
991
   
-
 
992
    if (arg.task_id == TASK->taskid) {
-
 
993
        /*
-
 
994
         * Accepting from itself is not allowed.
-
 
995
         */
-
 
996
        return (__native) EPERM;
-
 
997
    }
-
 
998
   
-
 
999
    memcpy(&TASK->accept_arg, &arg, sizeof(as_area_acptsnd_arg_t));
-
 
1000
   
-
 
1001
        return 0;
-
 
1002
}
-
 
1003
 
-
 
1004
/** Wrapper for as_area_send. */
-
 
1005
__native sys_as_area_send(as_area_acptsnd_arg_t *uspace_send_arg)
-
 
1006
{
-
 
1007
    as_area_acptsnd_arg_t arg;
-
 
1008
    int rc;
-
 
1009
   
-
 
1010
    rc = copy_from_uspace(&arg, uspace_send_arg, sizeof(as_area_acptsnd_arg_t));
-
 
1011
    if (rc != 0)
-
 
1012
        return rc;
-
 
1013
 
-
 
1014
    if (!arg.size)
-
 
1015
        return (__native) EPERM;
-
 
1016
   
-
 
1017
    if (arg.task_id == TASK->taskid) {
-
 
1018
        /*
-
 
1019
         * Sending to itself is not allowed.
-
 
1020
         */
-
 
1021
        return (__native) EPERM;
-
 
1022
    }
-
 
1023
 
-
 
1024
    return (__native) as_area_send(arg.task_id, (__address) arg.base);
-
 
1025
}
-