Index: generic/include/mm/as.h
===================================================================
--- generic/include/mm/as.h	(revision dbbeb263a0a4a4e72142ee94c6c579f349ba17af)
+++ generic/include/mm/as.h	(revision df0103f7b38d6ac53512fd7880952c2d3a01c7d1)
@@ -30,4 +30,5 @@
 #define __AS_H__
 
+#include <mm/as_arg.h>
 #include <arch/mm/page.h>
 #include <arch/mm/as.h>
@@ -114,4 +115,5 @@
 extern as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base);
 extern __address as_area_resize(as_t *as, __address address, size_t size, int flags);
+int as_area_send(task_id_t id, __address base, size_t size, int flags);
 extern void as_set_mapping(as_t *as, __address page, __address frame);
 extern int as_page_fault(__address page);
@@ -124,3 +126,9 @@
 #endif /* !def as_install_arch */
 
+/* Address space area related syscalls. */
+extern __native sys_as_area_create(__address address, size_t size, int flags);
+extern __native sys_as_area_resize(__address address, size_t size, int flags);
+extern __native sys_as_area_accept(as_area_acptsnd_arg_t *uspace_accept_arg);
+extern __native sys_as_area_send(as_area_acptsnd_arg_t *uspace_send_arg);
+
 #endif
Index: generic/include/mm/as_arg.h
===================================================================
--- generic/include/mm/as_arg.h	(revision df0103f7b38d6ac53512fd7880952c2d3a01c7d1)
+++ generic/include/mm/as_arg.h	(revision df0103f7b38d6ac53512fd7880952c2d3a01c7d1)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __AS_ARG_H__
+#define __AS_ARG_H__
+
+/** Structure passed by SYS_AS_AREA_ACCEPT and SYS_AS_AREA_SEND syscalls. */
+typedef struct {
+	/**
+	 * Task ID of the allowed sender in case of SYS_AS_AREA_ACCEPT
+	 * or task ID of the recipient in case of SYS_AS_AREA_SEND.
+	 * @task_id must be different for corresponding SYS_AS_AREA_ACCEPT
+	 * and SYS_AS_AREA_SEND.
+	 */
+	unsigned long long task_id;
+	
+	/**
+	 * Destination address in case of SYS_AS_AREA_ACCEPT,
+	 * source address in case of SYS_AS_AREA_SEND.
+	 */
+	void *base;
+	
+	unsigned long size;	/**< Size of memory being sent/accepted must match. */
+	int flags;		/**< Address space area flags of sender and acceptor must match. */
+} as_area_acptsnd_arg_t;
+
+#endif
Index: generic/include/proc/task.h
===================================================================
--- generic/include/proc/task.h	(revision dbbeb263a0a4a4e72142ee94c6c579f349ba17af)
+++ generic/include/proc/task.h	(revision df0103f7b38d6ac53512fd7880952c2d3a01c7d1)
@@ -36,4 +36,5 @@
 #include <ipc/ipc.h>
 #include <security/cap.h>
+#include <mm/as_arg.h>
 #include <arch/proc/task.h>
 
@@ -52,4 +53,7 @@
 	phone_t phones[IPC_MAX_PHONES];
 	atomic_t active_calls;  /**< Active asynchronous messages */
+	
+	/** Accept argument of SYS_AS_AREA_ACCEPT. */
+	as_area_acptsnd_arg_t accept_arg;
 	
 	task_arch_t arch;	/**< Architecture specific task data. */
Index: generic/src/mm/as.c
===================================================================
--- generic/src/mm/as.c	(revision dbbeb263a0a4a4e72142ee94c6c579f349ba17af)
+++ generic/src/mm/as.c	(revision df0103f7b38d6ac53512fd7880952c2d3a01c7d1)
@@ -44,17 +44,19 @@
 #include <mm/asid.h>
 #include <arch/mm/asid.h>
-#include <arch/types.h>
-#include <typedefs.h>
 #include <synch/spinlock.h>
-#include <config.h>
 #include <adt/list.h>
 #include <adt/btree.h>
+#include <proc/task.h>
+#include <arch/asm.h>
 #include <panic.h>
-#include <arch/asm.h>
 #include <debug.h>
+#include <print.h>
 #include <memstr.h>
 #include <macros.h>
 #include <arch.h>
-#include <print.h>
+#include <errno.h>
+#include <config.h>
+#include <arch/types.h>
+#include <typedefs.h>
 
 as_operations_t *as_operations = NULL;
@@ -72,4 +74,5 @@
 as_t *AS_KERNEL = NULL;
 
+static int area_flags_to_page_flags(int aflags);
 static int get_area_flags(as_area_t *a);
 static as_area_t *find_area_and_lock(as_t *as, __address va);
@@ -168,4 +171,244 @@
 
 	return a;
+}
+
+/** Find address space area and change it.
+ *
+ * @param as Address space.
+ * @param address Virtual address belonging to the area to be changed. Must be page-aligned.
+ * @param size New size of the virtual memory block starting at address. 
+ * @param flags Flags influencing the remap operation. Currently unused.
+ *
+ * @return address on success, (__address) -1 otherwise.
+ */ 
+__address as_area_resize(as_t *as, __address address, size_t size, int flags)
+{
+	as_area_t *area = NULL;
+	ipl_t ipl;
+	size_t pages;
+	
+	ipl = interrupts_disable();
+	spinlock_lock(&as->lock);
+	
+	/*
+	 * Locate the area.
+	 */
+	area = find_area_and_lock(as, address);
+	if (!area) {
+		spinlock_unlock(&as->lock);
+		interrupts_restore(ipl);
+		return (__address) -1;
+	}
+
+	if (area->flags & AS_AREA_DEVICE) {
+		/*
+		 * Remapping of address space areas associated
+		 * with memory mapped devices is not supported.
+		 */
+		spinlock_unlock(&area->lock);
+		spinlock_unlock(&as->lock);
+		interrupts_restore(ipl);
+		return (__address) -1;
+	}
+
+	pages = SIZE2FRAMES((address - area->base) + size);
+	if (!pages) {
+		/*
+		 * Zero size address space areas are not allowed.
+		 */
+		spinlock_unlock(&area->lock);
+		spinlock_unlock(&as->lock);
+		interrupts_restore(ipl);
+		return (__address) -1;
+	}
+	
+	if (pages < area->pages) {
+		int i;
+
+		/*
+		 * Shrinking the area.
+		 * No need to check for overlaps.
+		 */
+		for (i = pages; i < area->pages; i++) {
+			pte_t *pte;
+			
+			/*
+			 * Releasing physical memory.
+			 * This depends on the fact that the memory was allocated using frame_alloc().
+			 */
+			page_table_lock(as, false);
+			pte = page_mapping_find(as, area->base + i*PAGE_SIZE);
+			if (pte && PTE_VALID(pte)) {
+				__address frame;
+
+				ASSERT(PTE_PRESENT(pte));
+				frame = PTE_GET_FRAME(pte);
+				page_mapping_remove(as, area->base + i*PAGE_SIZE);
+				page_table_unlock(as, false);
+
+				frame_free(ADDR2PFN(frame));
+			} else {
+				page_table_unlock(as, false);
+			}
+		}
+		/*
+		 * Invalidate TLB's.
+		 */
+		tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base + pages*PAGE_SIZE, area->pages - pages);
+		tlb_invalidate_pages(AS->asid, area->base + pages*PAGE_SIZE, area->pages - pages);
+		tlb_shootdown_finalize();
+	} else {
+		/*
+		 * Growing the area.
+		 * Check for overlaps with other address space areas.
+		 */
+		if (!check_area_conflicts(as, address, pages * PAGE_SIZE, area)) {
+			spinlock_unlock(&area->lock);
+			spinlock_unlock(&as->lock);		
+			interrupts_restore(ipl);
+			return (__address) -1;
+		}
+	} 
+
+	area->pages = pages;
+	
+	spinlock_unlock(&area->lock);
+	spinlock_unlock(&as->lock);
+	interrupts_restore(ipl);
+
+	return address;
+}
+
+/** Send address space area to another task.
+ *
+ * Address space area is sent to the specified task.
+ * If the destination task is willing to accept the
+ * area, a new area is created according to the
+ * source area. Moreover, any existing mapping
+ * is copied as well, providing thus a mechanism
+ * for sharing group of pages. The source address
+ * space area and any associated mapping is preserved.
+ *
+ * @param id Task ID of the accepting task.
+ * @param base Base address of the source address space area.
+ * @param size Size of the source address space area.
+ * @param flags Flags of the source address space area.
+ *
+ * @return 0 on success or ENOENT if there is no such task or
+ *	   if there is no such address space area,
+ *	   EPERM if there was a problem in accepting the area or
+ *	   ENOMEM if there was a problem in allocating destination
+ *	   address space area.
+ */
+int as_area_send(task_id_t id, __address base, size_t size, int flags)
+{
+	ipl_t ipl;
+	task_t *t;
+	count_t i;
+	as_t *as;
+	__address dst_base;
+	
+	ipl = interrupts_disable();
+	spinlock_lock(&tasks_lock);
+	
+	t = task_find_by_id(id);
+	if (!NULL) {
+		spinlock_unlock(&tasks_lock);
+		interrupts_restore(ipl);
+		return ENOENT;
+	}
+
+	spinlock_lock(&t->lock);
+	spinlock_unlock(&tasks_lock);
+
+	as = t->as;
+	dst_base = (__address) t->accept_arg.base;
+	
+	if (as == AS) {
+		/*
+		 * The two tasks share the entire address space.
+		 * Return error since there is no point in continuing.
+		 */
+		spinlock_unlock(&t->lock);
+		interrupts_restore(ipl);
+		return EPERM;
+	}
+
+	if ((t->accept_arg.task_id != TASK->taskid) || (t->accept_arg.size != size) ||
+	    (t->accept_arg.flags != flags)) {
+		/*
+		 * Discrepancy in either task ID, size or flags.
+		 */
+		spinlock_unlock(&t->lock);
+		interrupts_restore(ipl);
+		return EPERM;
+	}
+	
+	/*
+	 * Create copy of the address space area.
+	 */
+	if (!as_area_create(as, flags, size, dst_base)) {
+		/*
+		 * Destination address space area could not be created.
+		 */
+		spinlock_unlock(&t->lock);
+		interrupts_restore(ipl);
+		return ENOMEM;
+	}
+	
+	/*
+	 * NOTE: we have just introduced a race condition.
+	 * The destination task can try to attempt the newly
+	 * created area before its mapping is copied from
+	 * the source address space area. In result, frames
+	 * can get lost.
+	 *
+	 * Currently, this race is not solved, but one of the
+	 * possible solutions would be to sleep in as_page_fault()
+	 * when this situation is detected.
+	 */
+
+	memsetb((__address) &t->accept_arg, sizeof(as_area_acptsnd_arg_t), 0);
+	spinlock_unlock(&t->lock);
+	
+	/*
+	 * Avoid deadlock by first locking the address space with lower address.
+	 */
+	if (as < AS) {
+		spinlock_lock(&as->lock);
+		spinlock_lock(&AS->lock);
+	} else {
+		spinlock_lock(&AS->lock);
+		spinlock_lock(&as->lock);
+	}
+	
+	for (i = 0; i < SIZE2FRAMES(size); i++) {
+		pte_t *pte;
+		__address frame;
+			
+		page_table_lock(AS, false);
+		pte = page_mapping_find(AS, base + i*PAGE_SIZE);
+		if (pte && PTE_VALID(pte)) {
+			ASSERT(PTE_PRESENT(pte));
+			frame = PTE_GET_FRAME(pte);
+			if (!(flags & AS_AREA_DEVICE)) {
+				/* TODO: increment frame reference count */
+			}
+			page_table_unlock(AS, false);
+		} else {
+			page_table_unlock(AS, false);
+			continue;
+		}
+		
+		page_table_lock(as, false);
+		page_mapping_insert(as, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(flags));
+		page_table_unlock(as, false);
+	}
+	
+	spinlock_unlock(&AS->lock);
+	spinlock_unlock(&as->lock);
+	interrupts_restore(ipl);
+	
+	return 0;
 }
 
@@ -345,14 +588,11 @@
 }
 
-/** Compute flags for virtual address translation subsytem.
- *
- * The address space area must be locked.
- * Interrupts must be disabled.
- *
- * @param a Address space area.
- *
- * @return Flags to be used in page_mapping_insert().
- */
-int get_area_flags(as_area_t *a)
+/** Convert address space area flags to page flags.
+ *
+ * @param aflags Flags of some address space area.
+ *
+ * @return Flags to be passed to page_mapping_insert().
+ */
+int area_flags_to_page_flags(int aflags)
 {
 	int flags;
@@ -360,17 +600,31 @@
 	flags = PAGE_USER | PAGE_PRESENT;
 	
-	if (a->flags & AS_AREA_READ)
+	if (aflags & AS_AREA_READ)
 		flags |= PAGE_READ;
 		
-	if (a->flags & AS_AREA_WRITE)
+	if (aflags & AS_AREA_WRITE)
 		flags |= PAGE_WRITE;
 	
-	if (a->flags & AS_AREA_EXEC)
+	if (aflags & AS_AREA_EXEC)
 		flags |= PAGE_EXEC;
 	
-	if (!(a->flags & AS_AREA_DEVICE))
+	if (!(aflags & AS_AREA_DEVICE))
 		flags |= PAGE_CACHEABLE;
 		
 	return flags;
+}
+
+/** Compute flags for virtual address translation subsytem.
+ *
+ * The address space area must be locked.
+ * Interrupts must be disabled.
+ *
+ * @param a Address space area.
+ *
+ * @return Flags to be used in page_mapping_insert().
+ */
+int get_area_flags(as_area_t *a)
+{
+	return area_flags_to_page_flags(a->flags);
 }
 
@@ -425,110 +679,4 @@
 }
 
-/** Find address space area and change it.
- *
- * @param as Address space.
- * @param address Virtual address belonging to the area to be changed. Must be page-aligned.
- * @param size New size of the virtual memory block starting at address. 
- * @param flags Flags influencing the remap operation. Currently unused.
- *
- * @return address on success, (__address) -1 otherwise.
- */ 
-__address as_area_resize(as_t *as, __address address, size_t size, int flags)
-{
-	as_area_t *area = NULL;
-	ipl_t ipl;
-	size_t pages;
-	
-	ipl = interrupts_disable();
-	spinlock_lock(&as->lock);
-	
-	/*
-	 * Locate the area.
-	 */
-	area = find_area_and_lock(as, address);
-	if (!area) {
-		spinlock_unlock(&as->lock);
-		interrupts_restore(ipl);
-		return (__address) -1;
-	}
-
-	if (area->flags & AS_AREA_DEVICE) {
-		/*
-		 * Remapping of address space areas associated
-		 * with memory mapped devices is not supported.
-		 */
-		spinlock_unlock(&area->lock);
-		spinlock_unlock(&as->lock);
-		interrupts_restore(ipl);
-		return (__address) -1;
-	}
-
-	pages = SIZE2FRAMES((address - area->base) + size);
-	if (!pages) {
-		/*
-		 * Zero size address space areas are not allowed.
-		 */
-		spinlock_unlock(&area->lock);
-		spinlock_unlock(&as->lock);
-		interrupts_restore(ipl);
-		return (__address) -1;
-	}
-	
-	if (pages < area->pages) {
-		int i;
-
-		/*
-		 * Shrinking the area.
-		 * No need to check for overlaps.
-		 */
-		for (i = pages; i < area->pages; i++) {
-			pte_t *pte;
-			
-			/*
-			 * Releasing physical memory.
-			 * This depends on the fact that the memory was allocated using frame_alloc().
-			 */
-			page_table_lock(as, false);
-			pte = page_mapping_find(as, area->base + i*PAGE_SIZE);
-			if (pte && PTE_VALID(pte)) {
-				__address frame;
-
-				ASSERT(PTE_PRESENT(pte));
-				frame = PTE_GET_FRAME(pte);
-				page_mapping_remove(as, area->base + i*PAGE_SIZE);
-				page_table_unlock(as, false);
-
-				frame_free(ADDR2PFN(frame));
-			} else {
-				page_table_unlock(as, false);
-			}
-		}
-		/*
-		 * Invalidate TLB's.
-		 */
-		tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base + pages*PAGE_SIZE, area->pages - pages);
-		tlb_invalidate_pages(AS->asid, area->base + pages*PAGE_SIZE, area->pages - pages);
-		tlb_shootdown_finalize();
-	} else {
-		/*
-		 * Growing the area.
-		 * Check for overlaps with other address space areas.
-		 */
-		if (!check_area_conflicts(as, address, pages * PAGE_SIZE, area)) {
-			spinlock_unlock(&area->lock);
-			spinlock_unlock(&as->lock);		
-			interrupts_restore(ipl);
-			return (__address) -1;
-		}
-	} 
-
-	area->pages = pages;
-	
-	spinlock_unlock(&area->lock);
-	spinlock_unlock(&as->lock);
-	interrupts_restore(ipl);
-
-	return address;
-}
 
 /** Find address space area and lock it.
@@ -668,2 +816,69 @@
 	return true;
 }
+
+/*
+ * Address space related syscalls.
+ */
+
+/** Wrapper for as_area_create(). */
+__native sys_as_area_create(__address address, size_t size, int flags)
+{
+	if (as_area_create(AS, flags, size, address))
+		return (__native) address;
+	else
+		return (__native) -1;
+}
+
+/** Wrapper for as_area_resize. */
+__native sys_as_area_resize(__address address, size_t size, int flags)
+{
+	return as_area_resize(AS, address, size, 0);
+}
+
+/** Prepare task for accepting address space area from another task.
+ *
+ * @param uspace_accept_arg Accept structure passed from userspace.
+ *
+ * @return EPERM if the task ID encapsulated in @uspace_accept_arg references
+ *	   TASK. Otherwise zero is returned.
+ */
+__native sys_as_area_accept(as_area_acptsnd_arg_t *uspace_accept_arg)
+{
+	as_area_acptsnd_arg_t arg;
+	
+	copy_from_uspace(&arg, uspace_accept_arg, sizeof(as_area_acptsnd_arg_t));
+	
+	if (!arg.size)
+		return (__native) EPERM;
+	
+	if (arg.task_id == TASK->taskid) {
+		/*
+		 * Accepting from itself is not allowed.
+		 */
+		return (__native) EPERM;
+	}
+	
+	memcpy(&TASK->accept_arg, &arg, sizeof(as_area_acptsnd_arg_t));
+	
+        return 0;
+}
+
+/** Wrapper for as_area_send. */
+__native sys_as_area_send(as_area_acptsnd_arg_t *uspace_send_arg)
+{
+	as_area_acptsnd_arg_t arg;
+	
+	copy_from_uspace(&arg, uspace_send_arg, sizeof(as_area_acptsnd_arg_t));
+
+	if (!arg.size)
+		return (__native) EPERM;
+	
+	if (arg.task_id == TASK->taskid) {
+		/*
+		 * Sending to itself is not allowed.
+		 */
+		return (__native) EPERM;
+	}
+
+	return (__native) as_area_send(arg.task_id, (__address) arg.base, arg.size, arg.flags);
+}
Index: generic/src/proc/task.c
===================================================================
--- generic/src/proc/task.c	(revision dbbeb263a0a4a4e72142ee94c6c579f349ba17af)
+++ generic/src/proc/task.c	(revision df0103f7b38d6ac53512fd7880952c2d3a01c7d1)
@@ -32,4 +32,5 @@
 #include <proc/uarg.h>
 #include <mm/as.h>
+#include <mm/as_arg.h>
 #include <mm/slab.h>
 #include <synch/spinlock.h>
@@ -98,4 +99,6 @@
 		ipc_phone_connect(&ta->phones[0], ipc_phone_0);
 	atomic_set(&ta->active_calls, 0);
+	
+	memsetb((__address) &ta->accept_arg, sizeof(as_area_acptsnd_arg_t), 0);
 	
 	ipl = interrupts_disable();
Index: generic/src/syscall/syscall.c
===================================================================
--- generic/src/syscall/syscall.c	(revision dbbeb263a0a4a4e72142ee94c6c579f349ba17af)
+++ generic/src/syscall/syscall.c	(revision df0103f7b38d6ac53512fd7880952c2d3a01c7d1)
@@ -52,27 +52,4 @@
 }
 
-static __native sys_as_area_create(void *address, size_t size, int flags)
-{
-	if (as_area_create(AS, flags, size, (__address) address))
-		return (__native) address;
-	else
-		return (__native) -1;
-}
-
-static __native sys_as_area_resize(void *address, size_t size, int flags)
-{
-	return as_area_resize(AS, (__address) address, size, 0);
-}
-
-static __native sys_as_area_share_approve()
-{
-	return 0;
-}
-
-static __native sys_as_area_share_perform()
-{
-	return 0;
-}
-
 static __native sys_int_control(int enable)
 {
@@ -94,13 +71,21 @@
 	sys_tls_set,
 	sys_int_control,
+
+	/* Thread and task related syscalls. */
 	sys_thread_create,
 	sys_thread_exit,
 	sys_task_get_id,
+	
+	/* Synchronization related syscalls. */
 	sys_futex_sleep_timeout,
 	sys_futex_wakeup,
+	
+	/* Address space related syscalls. */
 	sys_as_area_create,
 	sys_as_area_resize,
-	sys_as_area_share_approve,
-	sys_as_area_share_perform,
+	sys_as_area_accept,
+	sys_as_area_send,
+
+	/* IPC related syscalls. */
 	sys_ipc_call_sync_fast,
 	sys_ipc_call_sync,
@@ -112,4 +97,6 @@
 	sys_ipc_wait_for_call,
 	sys_ipc_hangup,
+	
+	/* DDI related syscalls. */
 	sys_physmem_map,
 	sys_iospace_enable
