Rev 1411 | Rev 1415 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1411 | Rev 1413 | ||
---|---|---|---|
Line 448... | Line 448... | ||
448 | mutex_unlock(&AS->lock); |
448 | mutex_unlock(&AS->lock); |
449 | interrupts_restore(ipl); |
449 | interrupts_restore(ipl); |
450 | return 0; |
450 | return 0; |
451 | } |
451 | } |
452 | 452 | ||
453 | /** Steal address space area from another task. |
453 | /** Share address space area with another or the same address space. |
454 | * |
454 | * |
455 | * Address space area is stolen from another task |
455 | * Address space area of anonymous memory is shared with a new address |
456 | * Moreover, any existing mapping |
456 | * space area. If the source address space area has not been shared so |
457 | * is copied as well, providing thus a mechanism |
457 | * far, a new sh_info is created and the original mapping is duplicated |
458 | * for sharing group of pages. The source address |
458 | * in its pagemap B+tree. The new address space are simply gets the |
459 | * space area and any associated mapping is preserved. |
459 | * sh_info of the source area. |
460 | * |
460 | * |
461 | * @param src_task Pointer of source task |
461 | * @param src_as Pointer to source address space |
462 | * @param src_base Base address of the source address space area. |
462 | * @param src_base Base address of the source address space area. |
463 | * @param acc_size Expected size of the source area |
463 | * @param acc_size Expected size of the source area |
464 | * @param dst_base Target base address |
464 | * @param dst_base Target base address |
465 | * |
465 | * |
466 | * @return Zero on success or ENOENT if there is no such task or |
466 | * @return Zero on success or ENOENT if there is no such task or |
467 | * if there is no such address space area, |
467 | * if there is no such address space area, |
468 | * EPERM if there was a problem in accepting the area or |
468 | * EPERM if there was a problem in accepting the area or |
469 | * ENOMEM if there was a problem in allocating destination |
469 | * ENOMEM if there was a problem in allocating destination |
470 | * address space area. |
470 | * address space area. ENOTSUP is returned if an attempt |
- | 471 | * to share non-anonymous address space area is detected. |
|
471 | */ |
472 | */ |
472 | int as_area_steal(task_t *src_task, __address src_base, size_t acc_size, |
473 | int as_area_share(as_t *src_as, __address src_base, size_t acc_size, |
473 | __address dst_base) |
474 | __address dst_base) |
474 | { |
475 | { |
475 | ipl_t ipl; |
476 | ipl_t ipl; |
476 | count_t i; |
- | |
477 | as_t *src_as; |
- | |
478 | int src_flags; |
477 | int src_flags; |
479 | size_t src_size; |
478 | size_t src_size; |
480 | as_area_t *src_area, *dst_area; |
479 | as_area_t *src_area, *dst_area; |
- | 480 | share_info_t *sh_info; |
|
- | 481 | link_t *cur; |
|
481 | 482 | ||
482 | ipl = interrupts_disable(); |
483 | ipl = interrupts_disable(); |
483 | spinlock_lock(&src_task->lock); |
- | |
484 | src_as = src_task->as; |
- | |
485 | - | ||
486 | mutex_lock(&src_as->lock); |
484 | mutex_lock(&src_as->lock); |
487 | src_area = find_area_and_lock(src_as, src_base); |
485 | src_area = find_area_and_lock(src_as, src_base); |
488 | if (!src_area) { |
486 | if (!src_area) { |
489 | /* |
487 | /* |
490 | * Could not find the source address space area. |
488 | * Could not find the source address space area. |
491 | */ |
489 | */ |
492 | spinlock_unlock(&src_task->lock); |
- | |
493 | mutex_unlock(&src_as->lock); |
490 | mutex_unlock(&src_as->lock); |
494 | interrupts_restore(ipl); |
491 | interrupts_restore(ipl); |
495 | return ENOENT; |
492 | return ENOENT; |
496 | } |
493 | } |
- | 494 | ||
497 | src_size = src_area->pages * PAGE_SIZE; |
495 | if (!src_area->backend || src_area->backend != &anon_backend) { |
- | 496 | /* |
|
498 | src_flags = src_area->flags; |
497 | * As of now, only anonymous address space areas can be shared. |
- | 498 | */ |
|
499 | mutex_unlock(&src_area->lock); |
499 | mutex_unlock(&src_area->lock); |
500 | mutex_unlock(&src_as->lock); |
500 | mutex_unlock(&src_as->lock); |
- | 501 | interrupts_restore(ipl); |
|
- | 502 | return ENOTSUP; |
|
- | 503 | } |
|
- | 504 | ||
- | 505 | src_size = src_area->pages * PAGE_SIZE; |
|
- | 506 | src_flags = src_area->flags; |
|
501 | 507 | ||
502 | if (src_size != acc_size) { |
508 | if (src_size != acc_size) { |
- | 509 | mutex_unlock(&src_area->lock); |
|
503 | spinlock_unlock(&src_task->lock); |
510 | mutex_unlock(&src_as->lock); |
504 | interrupts_restore(ipl); |
511 | interrupts_restore(ipl); |
505 | return EPERM; |
512 | return EPERM; |
506 | } |
513 | } |
- | 514 | ||
- | 515 | /* |
|
- | 516 | * Now we are committed to sharing the area. |
|
- | 517 | * First prepare the area for sharing. |
|
- | 518 | * Then it will be safe to unlock it. |
|
- | 519 | */ |
|
- | 520 | sh_info = src_area->sh_info; |
|
- | 521 | if (!sh_info) { |
|
- | 522 | sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0); |
|
- | 523 | mutex_initialize(&sh_info->lock); |
|
- | 524 | sh_info->refcount = 2; |
|
- | 525 | btree_create(&sh_info->pagemap); |
|
- | 526 | src_area->sh_info = sh_info; |
|
- | 527 | } else { |
|
- | 528 | mutex_lock(&sh_info->lock); |
|
- | 529 | sh_info->refcount++; |
|
- | 530 | mutex_unlock(&sh_info->lock); |
|
- | 531 | } |
|
- | 532 | ||
- | 533 | /* |
|
- | 534 | * Copy used portions of the area to sh_info's page map. |
|
- | 535 | */ |
|
- | 536 | mutex_lock(&sh_info->lock); |
|
- | 537 | for (cur = src_area->used_space.leaf_head.next; cur != &src_area->used_space.leaf_head; cur = cur->next) { |
|
- | 538 | btree_node_t *node; |
|
- | 539 | int i; |
|
- | 540 | ||
- | 541 | node = list_get_instance(cur, btree_node_t, leaf_link); |
|
- | 542 | for (i = 0; i < node->keys; i++) { |
|
- | 543 | __address base = node->key[i]; |
|
- | 544 | count_t count = (count_t) node->value[i]; |
|
- | 545 | int j; |
|
- | 546 | ||
- | 547 | for (j = 0; j < count; j++) { |
|
- | 548 | pte_t *pte; |
|
- | 549 | ||
- | 550 | page_table_lock(src_as, false); |
|
- | 551 | pte = page_mapping_find(src_as, base + j*PAGE_SIZE); |
|
- | 552 | ASSERT(pte && PTE_VALID(pte) && PTE_PRESENT(pte)); |
|
- | 553 | btree_insert(&sh_info->pagemap, (base + j*PAGE_SIZE) - src_area->base, |
|
- | 554 | (void *) PTE_GET_FRAME(pte), NULL); |
|
- | 555 | page_table_unlock(src_as, false); |
|
- | 556 | } |
|
- | 557 | ||
- | 558 | } |
|
- | 559 | } |
|
- | 560 | mutex_unlock(&sh_info->lock); |
|
- | 561 | ||
- | 562 | mutex_unlock(&src_area->lock); |
|
- | 563 | mutex_unlock(&src_as->lock); |
|
- | 564 | ||
507 | /* |
565 | /* |
508 | * Create copy of the source address space area. |
566 | * Create copy of the source address space area. |
509 | * The destination area is created with AS_AREA_ATTR_PARTIAL |
567 | * The destination area is created with AS_AREA_ATTR_PARTIAL |
510 | * attribute set which prevents race condition with |
568 | * attribute set which prevents race condition with |
511 | * preliminary as_page_fault() calls. |
569 | * preliminary as_page_fault() calls. |
Line 513... | Line 571... | ||
513 | dst_area = as_area_create(AS, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL, &anon_backend, NULL); |
571 | dst_area = as_area_create(AS, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL, &anon_backend, NULL); |
514 | if (!dst_area) { |
572 | if (!dst_area) { |
515 | /* |
573 | /* |
516 | * Destination address space area could not be created. |
574 | * Destination address space area could not be created. |
517 | */ |
575 | */ |
518 | spinlock_unlock(&src_task->lock); |
576 | sh_info_remove_reference(sh_info); |
- | 577 | ||
519 | interrupts_restore(ipl); |
578 | interrupts_restore(ipl); |
520 | return ENOMEM; |
579 | return ENOMEM; |
521 | } |
580 | } |
522 | 581 | ||
523 | spinlock_unlock(&src_task->lock); |
- | |
524 | - | ||
525 | /* |
- | |
526 | * Avoid deadlock by first locking the address space with lower address. |
- | |
527 | */ |
- | |
528 | if (AS < src_as) { |
- | |
529 | mutex_lock(&AS->lock); |
- | |
530 | mutex_lock(&src_as->lock); |
- | |
531 | } else { |
- | |
532 | mutex_lock(&AS->lock); |
- | |
533 | mutex_lock(&src_as->lock); |
- | |
534 | } |
- | |
535 | - | ||
536 | for (i = 0; i < SIZE2FRAMES(src_size); i++) { |
- | |
537 | pte_t *pte; |
- | |
538 | __address frame; |
- | |
539 | - | ||
540 | page_table_lock(src_as, false); |
- | |
541 | pte = page_mapping_find(src_as, src_base + i*PAGE_SIZE); |
- | |
542 | if (pte && PTE_VALID(pte)) { |
- | |
543 | ASSERT(PTE_PRESENT(pte)); |
- | |
544 | frame = PTE_GET_FRAME(pte); |
- | |
545 | if (!(src_flags & AS_AREA_DEVICE)) |
- | |
546 | frame_reference_add(ADDR2PFN(frame)); |
- | |
547 | page_table_unlock(src_as, false); |
- | |
548 | } else { |
- | |
549 | page_table_unlock(src_as, false); |
- | |
550 | continue; |
- | |
551 | } |
- | |
552 | - | ||
553 | page_table_lock(AS, false); |
- | |
554 | page_mapping_insert(AS, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(src_flags)); |
- | |
555 | page_table_unlock(AS, false); |
- | |
556 | } |
- | |
557 | - | ||
558 | /* |
582 | /* |
559 | * Now the destination address space area has been |
583 | * Now the destination address space area has been |
560 | * fully initialized. Clear the AS_AREA_ATTR_PARTIAL |
584 | * fully initialized. Clear the AS_AREA_ATTR_PARTIAL |
561 | * attribute. |
585 | * attribute and set the sh_info. |
562 | */ |
586 | */ |
563 | mutex_lock(&dst_area->lock); |
587 | mutex_lock(&dst_area->lock); |
564 | dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL; |
588 | dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL; |
- | 589 | dst_area->sh_info = sh_info; |
|
565 | mutex_unlock(&dst_area->lock); |
590 | mutex_unlock(&dst_area->lock); |
566 | 591 | ||
567 | mutex_unlock(&AS->lock); |
- | |
568 | mutex_unlock(&src_as->lock); |
- | |
569 | interrupts_restore(ipl); |
592 | interrupts_restore(ipl); |
570 | 593 | ||
571 | return 0; |
594 | return 0; |
572 | } |
595 | } |
573 | 596 | ||
Line 1476... | Line 1499... | ||
1476 | * in the pagemap of the address space area share info structure. |
1499 | * in the pagemap of the address space area share info structure. |
1477 | * In the case that the pagemap does not contain the respective |
1500 | * In the case that the pagemap does not contain the respective |
1478 | * mapping, a new frame is allocated and the mapping is created. |
1501 | * mapping, a new frame is allocated and the mapping is created. |
1479 | */ |
1502 | */ |
1480 | mutex_lock(&area->sh_info->lock); |
1503 | mutex_lock(&area->sh_info->lock); |
1481 | frame = (__address) btree_search(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE), &leaf); |
1504 | frame = (__address) btree_search(&area->sh_info->pagemap, |
- | 1505 | ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf); |
|
1482 | if (!frame) { |
1506 | if (!frame) { |
1483 | bool allocate = true; |
1507 | bool allocate = true; |
1484 | int i; |
1508 | int i; |
1485 | 1509 | ||
1486 | /* |
1510 | /* |
Line 1498... | Line 1522... | ||
1498 | memsetb(PA2KA(frame), FRAME_SIZE, 0); |
1522 | memsetb(PA2KA(frame), FRAME_SIZE, 0); |
1499 | 1523 | ||
1500 | /* |
1524 | /* |
1501 | * Insert the address of the newly allocated frame to the pagemap. |
1525 | * Insert the address of the newly allocated frame to the pagemap. |
1502 | */ |
1526 | */ |
1503 | btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE), (void *) frame, leaf); |
1527 | btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base, (void *) frame, leaf); |
1504 | } |
1528 | } |
1505 | } |
1529 | } |
1506 | mutex_unlock(&area->sh_info->lock); |
1530 | mutex_unlock(&area->sh_info->lock); |
1507 | } else { |
1531 | } else { |
1508 | 1532 |