Rev 1411 | Rev 1415 | Go to most recent revision | Show entire file | Ignore 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 | ||
| - | 495 | if (!src_area->backend || src_area->backend != &anon_backend) { |
|
| - | 496 | /* |
|
| - | 497 | * As of now, only anonymous address space areas can be shared. |
|
| - | 498 | */ |
|
| - | 499 | mutex_unlock(&src_area->lock); |
|
| - | 500 | mutex_unlock(&src_as->lock); |
|
| - | 501 | interrupts_restore(ipl); |
|
| - | 502 | return ENOTSUP; |
|
| - | 503 | } |
|
| - | 504 | ||
| 497 | src_size = src_area->pages * PAGE_SIZE; |
505 | src_size = src_area->pages * PAGE_SIZE; |
| 498 | src_flags = src_area->flags; |
506 | src_flags = src_area->flags; |
| 499 | mutex_unlock(&src_area->lock); |
- | |
| 500 | mutex_unlock(&src_as->lock); |
- | |
| 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 | ||