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 | } |
- |