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