Index: generic/include/errno.h
===================================================================
--- generic/include/errno.h	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
+++ generic/include/errno.h	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005 Martin Decky
+ * 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 __ERRNO_H__
+#define __ERRNO_H__
+
+#define ENOENT    1
+
+#endif
Index: generic/include/ipc/ipc.h
===================================================================
--- generic/include/ipc/ipc.h	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
+++ generic/include/ipc/ipc.h	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2006 Ondrej Palkovsky
+ * 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 __IPC_H__
+#define __IPC_H__
+
+#define IPC_CALL_LEN    2
+
+/* Flags for calls */
+#define IPC_CALL_ANSWERED    1
+/* Flags for ipc_wait_for_call */
+#define IPC_WAIT_NONBLOCKING 1
+
+#ifdef KERNEL
+
+#include <synch/waitq.h>
+#include <synch/spinlock.h>
+#include <adt/list.h>
+
+#define IPC_MAX_PHONES  16
+
+
+typedef struct answerbox answerbox_t;
+
+typedef struct {
+	link_t list;
+	answerbox_t *callerbox;
+	int flags;
+	__native data[IPC_CALL_LEN];
+} call_t;
+
+struct answerbox {
+	SPINLOCK_DECLARE(lock);
+
+	waitq_t wq;
+
+	link_t connected_phones; /**< Phones connected to this answerbox */
+	link_t calls;            /**< Received calls */
+	link_t dispatched_calls; /* Should be hash table in the future */
+
+	link_t answers;          /**< Answered calls */
+};
+
+typedef struct {
+	SPINLOCK_DECLARE(lock);
+	link_t list;
+	answerbox_t *callee;
+} phone_t;
+
+extern void ipc_create_phonecompany(void);
+extern void ipc_init(void);
+extern call_t * ipc_wait_for_call(answerbox_t *box, int flags);
+extern void ipc_answer(answerbox_t *box, call_t *request);
+extern void ipc_call(phone_t *phone, call_t *request);
+extern void ipc_phone_destroy(phone_t *phone);
+extern void ipc_phone_init(phone_t *phone, answerbox_t *box);
+extern void ipc_call_free(call_t *call);
+extern call_t * ipc_call_alloc(void);
+void ipc_answerbox_init(answerbox_t *box);
+void ipc_phone_init(phone_t *phone, answerbox_t *box);
+
+extern answerbox_t *ipc_central_box;
+
+#endif
+
+#endif
Index: generic/include/mm/page.h
===================================================================
--- generic/include/mm/page.h	(revision 78a95d6fb3124b0f93e5fee3e3f45ceb1b695df6)
+++ generic/include/mm/page.h	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -33,4 +33,5 @@
 #include <arch/types.h>
 #include <typedefs.h>
+#include <memstr.h>
 
 #define PAGE_CACHEABLE_SHIFT		0
@@ -60,4 +61,16 @@
 #define PAGE_GLOBAL		(1<<PAGE_GLOBAL_SHIFT)
 
+
+/* TODO - check that userspace is OK, platform specific functions etc */
+static inline void copy_to_uspace(void *dst, void *src, count_t cnt)
+{
+	memcpy(dst, src, cnt);
+} 
+
+static inline void copy_to_kernel(void *dst, void *src, count_t cnt)
+{
+	memcpy(dst, src, cnt);
+}
+
 /** Operations to manipulate page mappings. */
 struct page_mapping_operations {
Index: generic/include/proc/task.h
===================================================================
--- generic/include/proc/task.h	(revision 78a95d6fb3124b0f93e5fee3e3f45ceb1b695df6)
+++ generic/include/proc/task.h	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -33,4 +33,5 @@
 #include <synch/spinlock.h>
 #include <adt/list.h>
+#include <ipc/ipc.h>
 
 /** Task structure. */
@@ -40,4 +41,6 @@
 	link_t tasks_link;	/**< Link to other tasks within the system. */
 	as_t *as;		/**< Address space. */
+	answerbox_t answerbox;  /**< Communication endpoint */
+	phone_t phones[IPC_MAX_PHONES];
 };
 
Index: generic/include/syscall/syscall.h
===================================================================
--- generic/include/syscall/syscall.h	(revision 78a95d6fb3124b0f93e5fee3e3f45ceb1b695df6)
+++ generic/include/syscall/syscall.h	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -30,18 +30,23 @@
 #define __SYSCALL_H__
 
-#include <typedefs.h>
-
 typedef enum {
 	SYS_CTL = 0,
 	SYS_IO	= 1,
+	SYS_IPC_CALL = 2,
+	SYS_IPC_ANSWER = 3,
+	SYS_IPC_WAIT = 4,
 	SYSCALL_END
 } syscall_t;
 
-typedef int (*syshandler_t)();
+#ifdef KERNEL
 
-extern int sys_ctl(void);
-extern int sys_io(int fd, const void *buf, size_t count);
+#include <arch/types.h>
+#include <typedefs.h>
+
+typedef __native (*syshandler_t)();
 
 extern syshandler_t syscall_table[SYSCALL_END];
 
 #endif
+
+#endif
Index: generic/src/ipc/ipc.c
===================================================================
--- generic/src/ipc/ipc.c	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
+++ generic/src/ipc/ipc.c	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2006 Ondrej Palkovsky
+ * 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.
+ */
+
+/* Lock ordering
+ *
+ * First the answerbox, then the phone
+ */
+
+#include <synch/waitq.h>
+#include <ipc/ipc.h>
+#include <errno.h>
+#include <mm/slab.h>
+#include <arch.h>
+#include <proc/task.h>
+#include <memstr.h>
+#include <debug.h>
+
+#include <print.h>
+#include <proc/thread.h>
+
+answerbox_t *ipc_central_box;
+
+static slab_cache_t *ipc_call_slab;
+
+/** Allocate & initialize call structure
+ * 
+ * The call is initialized, so that the reply will be directed
+ * to TASK->answerbox
+ */
+call_t * ipc_call_alloc(void)
+{
+	call_t *call;
+
+	call = slab_alloc(ipc_call_slab, 0);
+	memsetb((__address)call, sizeof(*call), 0);
+	call->callerbox = &TASK->answerbox;
+
+	return call;
+}
+
+/** Deallocate call stracuture */
+void ipc_call_free(call_t *call)
+{
+	slab_free(ipc_call_slab, call);
+}
+
+/** Initialize answerbox structure
+ */
+void ipc_answerbox_init(answerbox_t *box)
+{
+	spinlock_initialize(&box->lock, "abox_lock");
+	waitq_initialize(&box->wq);
+	list_initialize(&box->connected_phones);
+	list_initialize(&box->calls);
+	list_initialize(&box->dispatched_calls);
+	list_initialize(&box->answers);
+}
+
+/** Initialize phone structure and connect phone to naswerbox
+ */
+void ipc_phone_init(phone_t *phone, answerbox_t *box)
+{
+	spinlock_initialize(&phone->lock, "phone_lock");
+	
+	phone->callee = box;
+	spinlock_lock(&box->lock);
+	list_append(&phone->list, &box->connected_phones);
+	spinlock_unlock(&box->lock);
+}
+
+/** Disconnect phone from answerbox */
+void ipc_phone_destroy(phone_t *phone)
+{
+	answerbox_t *box = phone->callee;
+	
+	ASSERT(box);
+
+	spinlock_lock(&box->lock);
+	list_remove(&phone->list);
+	spinlock_unlock(&box->lock);
+}
+
+
+/** Send a request using phone to answerbox
+ *
+ * @param phone Phone connected to answerbox
+ * @param request Request to be sent
+ */
+void ipc_call(phone_t *phone, call_t *request)
+{
+	answerbox_t *box = phone->callee;
+
+	ASSERT(box);
+
+	spinlock_lock(&box->lock);
+	list_append(&request->list, &box->calls);
+	spinlock_unlock(&box->lock);
+	waitq_wakeup(&box->wq, 0);
+}
+
+/** Answer message back to phone
+ *
+ * @param box Answerbox that is answering the message
+ * @param request Modified request that is being sent back
+ */
+void ipc_answer(answerbox_t *box, call_t *request)
+{
+	answerbox_t *callerbox = request->callerbox;
+
+	request->flags |= IPC_CALL_ANSWERED;
+
+	spinlock_lock(&box->lock);
+	spinlock_lock(&callerbox->lock);
+
+	list_remove(&request->list);
+	list_append(&request->list, &callerbox->answers);
+	waitq_wakeup(&callerbox->wq, 0);
+
+	spinlock_unlock(&callerbox->lock);
+	spinlock_unlock(&box->lock);
+}
+
+/** Wait for phone call 
+ *
+ * @return Recived message address
+ * - to distinguish between call and answer, look at call->flags
+ */
+call_t * ipc_wait_for_call(answerbox_t *box, int flags)
+{
+	call_t *request;
+
+	if ((flags & IPC_WAIT_NONBLOCKING)) {
+		if (waitq_sleep_timeout(&box->wq,SYNCH_NO_TIMEOUT,SYNCH_NON_BLOCKING) == ESYNCH_WOULD_BLOCK)
+			return 0;
+	} else {
+		waitq_sleep(&box->wq);
+	}
+
+
+	// TODO - might need condition variable+mutex if we want to support
+	// removing of requests from queue before dispatch
+	spinlock_lock(&box->lock);
+	/* Handle answers first */
+	if (!list_empty(&box->answers)) {
+		request = list_get_instance(box->answers.next, call_t, list);
+		list_remove(&request->list);
+	} else {
+		ASSERT (! list_empty(&box->calls));
+		request = list_get_instance(box->calls.next, call_t, list);
+		list_remove(&request->list);
+		/* Append request to dispatch queue */
+		list_append(&request->list, &box->dispatched_calls);
+	}
+	spinlock_unlock(&box->lock);
+
+	return request;
+}
+
+/** Initilize ipc subsystem */
+void ipc_init(void)
+{
+	ipc_call_slab = slab_cache_create("ipc_call",
+					  sizeof(call_t),
+					  0,
+					  NULL, NULL, 0);
+}
+
+static void ipc_phonecompany_thread(void *data)
+{
+	call_t *call;
+
+	printf("Phone company started.\n");
+	while (1) {
+		call = ipc_wait_for_call(&TASK->answerbox, 0);
+		printf("Received phone call - %P %P\n",
+		       call->data[0], call->data[1]);
+		ipc_answer(&TASK->answerbox, call);
+		printf("Call answered.\n");
+	}
+}
+
+void ipc_create_phonecompany(void)
+{
+	thread_t *t;
+	
+	if ((t = thread_create(ipc_phonecompany_thread, "phonecompany", 
+			       TASK, 0)))
+		thread_ready(t);
+	else
+		panic("thread_create/phonecompany");
+
+	ipc_central_box = &TASK->answerbox;
+}
Index: generic/src/main/kinit.c
===================================================================
--- generic/src/main/kinit.c	(revision 78a95d6fb3124b0f93e5fee3e3f45ceb1b695df6)
+++ generic/src/main/kinit.c	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -139,4 +139,6 @@
 	interrupts_enable();
 
+	ipc_create_phonecompany();
+
 	if (config.init_size > 0) {
 		/*
Index: generic/src/main/main.c
===================================================================
--- generic/src/main/main.c	(revision 78a95d6fb3124b0f93e5fee3e3f45ceb1b695df6)
+++ generic/src/main/main.c	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -55,4 +55,5 @@
 #include <arch/faddr.h>
 #include <typedefs.h>
+#include <ipc/ipc.h>
 
 #ifdef CONFIG_SMP
@@ -191,5 +192,6 @@
 	if (config.init_size > 0)
 		printf("config.init_addr=%P, config.init_size=%d\n", config.init_addr, config.init_size);
-
+	
+	ipc_init();
 	/*
 	 * Create kernel task.
Index: generic/src/proc/task.c
===================================================================
--- generic/src/proc/task.c	(revision 78a95d6fb3124b0f93e5fee3e3f45ceb1b695df6)
+++ generic/src/proc/task.c	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -36,4 +36,6 @@
 #include <panic.h>
 #include <adt/list.h>
+#include <ipc/ipc.h>
+#include <memstr.h>
 
 SPINLOCK_INITIALIZE(tasks_lock);
@@ -71,4 +73,9 @@
 	list_initialize(&ta->tasks_link);
 	ta->as = as;
+
+	ipc_answerbox_init(&ta->answerbox);
+	memsetb((__address)&ta->phones, sizeof(ta->phones[0])*IPC_MAX_PHONES, 0);
+	if (ipc_central_box)
+		ipc_phone_init(&ta->phones[0], ipc_central_box);
 	
 	ipl = interrupts_disable();
Index: generic/src/syscall/syscall.c
===================================================================
--- generic/src/syscall/syscall.c	(revision 78a95d6fb3124b0f93e5fee3e3f45ceb1b695df6)
+++ generic/src/syscall/syscall.c	(revision 6d9c49ab8fb84fcd0bf9d37abca3ed194e992a74)
@@ -31,6 +31,11 @@
 #include <print.h>
 #include <putchar.h>
+#include <ipc/ipc.h>
+#include <errno.h>
+#include <proc/task.h>
+#include <arch.h>
+#include <debug.h>
 
-int sys_ctl(void) {
+static __native sys_ctl(void) {
 	printf("Thread finished\n");
 	thread_exit();
@@ -39,5 +44,5 @@
 }
 
-int sys_io(int fd, const void * buf, size_t count) {
+static __native sys_io(int fd, const void * buf, size_t count) {
 	
 	// TODO: buf sanity checks and a lot of other stuff ...
@@ -51,6 +56,75 @@
 }
 
+/** Send a call over syscall
+ *
+ * @return Call identification, returns -1 on fatal error, 
+           -2 on 'Too many async request, handle answers first
+ */
+static __native sys_ipc_call(__native phoneid, __native arg1, __native arg2)
+{
+	call_t *call;
+	phone_t *phone;
+
+	if (phoneid >= IPC_MAX_PHONES)
+		return -ENOENT;
+
+	phone = &TASK->phones[phoneid];
+	if (!phone->callee)
+		return -ENOENT;
+
+
+	/* TODO: Check that we did not exceed system imposed maximum
+	 * of asynchrnously sent messages
+	 * - the userspace should be able to handle it correctly
+	 */
+	call = ipc_call_alloc();
+	call->data[0] = arg1;
+	call->data[1] = arg2;
+	ipc_call(phone, call);
+
+	return (__native) call;
+}
+
+/** Send IPC answer */
+static __native sys_ipc_answer(__native callid, __native arg1, __native arg2)
+{
+	call_t *call;
+
+	/* Check that the user is not sending us answer callid */
+	ASSERT(! (callid & 1));
+	/* TODO: Check that the callid is in the dispatch table */
+	call = (call_t *) callid;
+
+	call->data[0] = arg1;
+	call->data[1] = arg2;
+
+	ipc_answer(&TASK->answerbox, call);
+	return 0;
+}
+
+/** Wait for incoming ipc call or answer
+ *
+ * @param result 
+ * @param flags
+ * @return Callid, if callid & 1, then the call is answer
+ */
+static __native sys_ipc_wait_for_call(__native *calldata, __native flags)
+{
+	call_t *call;
+	
+	call = ipc_wait_for_call(&TASK->answerbox, flags);
+	copy_to_uspace(calldata, &call->data, sizeof(__native) * IPC_CALL_LEN);
+
+	if (call->flags & IPC_CALL_ANSWERED)
+		return ((__native)call) | 1;
+	return (__native)call;
+}
+
+
 syshandler_t syscall_table[SYSCALL_END] = {
 	sys_ctl,
-	sys_io
+	sys_io,
+	sys_ipc_call,
+	sys_ipc_answer,
+	sys_ipc_wait_for_call
 };
