Index: kernel/generic/include/config.h
===================================================================
--- kernel/generic/include/config.h	(revision cc106e483d059603a58bf1afab2123168615a299)
+++ kernel/generic/include/config.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -47,4 +47,11 @@
 #define CONFIG_INIT_TASKS        32
 #define CONFIG_TASK_NAME_BUFLEN  32
+#define CONFIG_TASK_ARGUMENTS_BUFLEN 64
+
+/**
+ * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
+ * requests.
+ */
+#define DATA_XFER_LIMIT  (64 * 1024)
 
 #ifndef __ASM__
@@ -56,4 +63,5 @@
 	size_t size;
 	char name[CONFIG_TASK_NAME_BUFLEN];
+	char arguments[CONFIG_TASK_ARGUMENTS_BUFLEN];
 } init_task_t;
 
Index: kernel/generic/include/interrupt.h
===================================================================
--- kernel/generic/include/interrupt.h	(revision cc106e483d059603a58bf1afab2123168615a299)
+++ kernel/generic/include/interrupt.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -59,5 +59,6 @@
 extern exc_table_t exc_table[];
 
-extern void fault_from_uspace(istate_t *, const char *, ...);
+extern void fault_from_uspace(istate_t *, const char *, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 extern void fault_if_from_uspace(istate_t *, const char *, ...)
     PRINTF_ATTRIBUTE(2, 3);
Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision cc106e483d059603a58bf1afab2123168615a299)
+++ kernel/generic/include/ipc/ipc.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -65,4 +65,5 @@
 	mutex_t lock;
 	link_t link;
+	struct task *caller;
 	struct answerbox *callee;
 	ipc_phone_state_t state;
@@ -72,4 +73,7 @@
 typedef struct answerbox {
 	IRQ_SPINLOCK_DECLARE(lock);
+
+	/** Answerbox is active until it enters cleanup. */
+	bool active;
 	
 	struct task *task;
@@ -106,10 +110,43 @@
 
 typedef struct {
-	link_t link;
+	/**
+	 * Task link.
+	 * Valid only when the call is not forgotten.
+	 * Protected by the task's active_calls_lock.
+	 */
+	link_t ta_link;
+
+	atomic_t refcnt;
+
+	/** Answerbox link. */
+	link_t ab_link;
 	
 	unsigned int flags;
+
+	/** Protects the forget member. */
+	SPINLOCK_DECLARE(forget_lock);
+
+	/**
+	 * True if the caller 'forgot' this call and donated it to the callee.
+	 * Forgotten calls are discarded upon answering (the answer is not
+	 * delivered) and answered calls cannot be forgotten. Forgotten calls
+	 * also do not figure on the task's active call list.
+	 *
+	 * We keep this separate from the flags so that it is not necessary
+	 * to take a lock when accessing them.
+	 */
+	bool forget;
+
+	/** True if the call is in the active list. */
+	bool active;
 	
-	/** Identification of the caller. */
+	/**
+	 * Identification of the caller.
+	 * Valid only when the call is not forgotten.
+	 */
 	struct task *sender;
+	
+	/** Phone which was used to send the call. */
+	phone_t *caller_phone;
 	
 	/** Private data to internal IPC. */
@@ -118,14 +155,10 @@
 	/** Data passed from/to userspace. */
 	ipc_data_t data;
-	
+
+	/** Method as it was sent in the request. */
+	sysarg_t request_method;
+
 	/** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
 	uint8_t *buffer;
-	
-	/*
-	 * The forward operation can masquerade the caller phone. For those
-	 * cases, we must keep it aside so that the answer is processed
-	 * correctly.
-	 */
-	phone_t *caller_phone;
 } call_t;
 
@@ -136,4 +169,6 @@
 extern call_t *ipc_call_alloc(unsigned int);
 extern void ipc_call_free(call_t *);
+extern void ipc_call_hold(call_t *);
+extern void ipc_call_release(call_t *);
 
 extern int ipc_call(phone_t *, call_t *);
@@ -141,7 +176,8 @@
 extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int);
 extern void ipc_answer(answerbox_t *, call_t *);
+extern void _ipc_answer_free_call(call_t *, bool);
 
-extern void ipc_phone_init(phone_t *);
-extern void ipc_phone_connect(phone_t *, answerbox_t *);
+extern void ipc_phone_init(phone_t *, struct task *);
+extern bool ipc_phone_connect(phone_t *, answerbox_t *);
 extern int ipc_phone_hangup(phone_t *);
 
@@ -151,5 +187,5 @@
 extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t);
 extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
-extern void ipc_cleanup_call_list(list_t *);
+extern void ipc_cleanup_call_list(answerbox_t *, list_t *);
 
 extern void ipc_print_task(task_id_t);
Index: kernel/generic/include/ipc/ipcrsc.h
===================================================================
--- kernel/generic/include/ipc/ipcrsc.h	(revision cc106e483d059603a58bf1afab2123168615a299)
+++ kernel/generic/include/ipc/ipcrsc.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -40,6 +40,7 @@
 
 extern call_t *get_call(sysarg_t);
+extern int phone_get(sysarg_t, phone_t **);
 extern int phone_alloc(task_t *);
-extern void phone_connect(int, answerbox_t *);
+extern bool phone_connect(int, answerbox_t *);
 extern void phone_dealloc(int);
 
Index: kernel/generic/include/ipc/sysipc_ops.h
===================================================================
--- kernel/generic/include/ipc/sysipc_ops.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/include/ipc/sysipc_ops.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/** @addtogroup genericipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_SYSIPC_OPS_H_
+#define KERN_SYSIPC_OPS_H_
+
+#include <ipc/ipc.h>
+
+#define SYSIPC_OP(op, call, ...) \
+	({ \
+		int rc = EOK; \
+		\
+		sysipc_ops_t *ops; \
+		ops = sysipc_ops_get((call)->request_method); \
+		if (ops->op) \
+			rc = ops->op((call), ##__VA_ARGS__); \
+		rc; \
+	})
+
+/**
+ * This header declares the per-method IPC callbacks. Using these callbacks,
+ * each IPC method (but system methods in particular), can define actions that
+ * will be called at specific moments in the call life-cycle.
+ *
+ * Normally, the kernel will attempt to invoke the following callbacks in the
+ * following order on each call:
+ *
+ * request_preprocess()
+ * request_process()
+ * answer_preprocess()
+ * answer_process()
+ *
+ * This callback invocation sequence is a natural order of processing. Note,
+ * however, that due to various special circumstances, callbacks may be called
+ * also in a different than natural order of processing. This means that some
+ * callbacks may be skipped and some others may be called instead.
+ *
+ * The additional callbacks that may be called are as follows:
+ *
+ * request_forget()
+ * answer_cleanup()
+ *
+ * There are several notable scenarios in which some callbacks of the natural
+ * order of processing will be skipped.
+ *
+ * The request_process(), answer_preprocess() and answer_process() callbacks
+ * will be skipped if the call cannot be delivered to the callee. This may
+ * happen when e.g. the request_preprocess() callback fails or the connection
+ * to the callee is not functional. The next callback that will be invoked on
+ * the call is request_forget().
+ *
+ * The comments for each callback type describe the specifics of each callback
+ * such as the context in which it is invoked and various constraints.
+ */
+
+typedef struct {
+	/**
+	 * This callback is called from request_preprocess().
+	 * 
+	 * Context:		caller
+	 * Caller alive:	guaranteed
+	 * Races with:		N/A
+	 * Invoked on:		all calls
+	 */
+	int (* request_preprocess)(call_t *, phone_t *);
+
+	/**
+	 * This callback is called when the IPC cleanup code wins the race to
+	 * forget the call.
+	 *
+	 * Context:		caller
+	 * Caller alive:	guaranteed
+	 * Races with:		request_process(), answer_cleanup(),
+	 *			_ipc_answer_free_call()
+	 * Invoked on:		all forgotten calls
+	 */	
+	int (* request_forget)(call_t *);
+
+	/**
+	 * This callback is called from process_request().
+	 *
+	 * Context:		callee
+	 * Caller alive:	no guarantee
+	 * Races with:		request_forget()
+	 * Invoked on:		all calls delivered to the callee
+	 */	
+	int (* request_process)(call_t *, answerbox_t *);
+
+	/**
+	 * This callback is called when answer_preprocess() loses the race to
+	 * answer the call.
+	 *
+	 * Context:		callee
+	 * Caller alive:	no guarantee
+	 * Races with:		request_forget()
+	 * Invoked on:		all forgotten calls
+	 */
+	int (* answer_cleanup)(call_t *, ipc_data_t *);
+
+	/**
+	 * This callback is called when answer_preprocess() wins the race to
+	 * answer the call.
+	 *
+	 * Context:		callee
+	 * Caller alive:	guaranteed
+	 * Races with:		N/A
+	 * Invoked on:		all answered calls
+	 */
+	int (* answer_preprocess)(call_t *, ipc_data_t *);
+
+	/**
+	 * This callback is called from process_answer().
+	 *
+	 * Context:		caller
+	 * Caller alive:	guaranteed
+	 * Races with:		N/A
+	 * Invoked on:		all answered calls
+	 */
+	int (* answer_process)(call_t *);
+} sysipc_ops_t;
+
+extern sysipc_ops_t *sysipc_ops_get(sysarg_t);
+
+extern int null_request_preprocess(call_t *, phone_t *);
+extern int null_request_forget(call_t *);
+extern int null_request_process(call_t *, answerbox_t *);
+extern int null_answer_cleanup(call_t *, ipc_data_t *);
+extern int null_answer_preprocess(call_t *, ipc_data_t *);
+extern int null_answer_process(call_t *);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/ipc/sysipc_priv.h
===================================================================
--- kernel/generic/include/ipc/sysipc_priv.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/include/ipc/sysipc_priv.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/** @addtogroup genericipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_SYSIPC_PRIV_H_
+#define KERN_SYSIPC_PRIV_H_
+
+#include <ipc/ipc.h>
+
+extern int answer_preprocess(call_t *, ipc_data_t *);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/lib/elf_load.h
===================================================================
--- kernel/generic/include/lib/elf_load.h	(revision cc106e483d059603a58bf1afab2123168615a299)
+++ kernel/generic/include/lib/elf_load.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -42,16 +42,15 @@
  * ELF error return codes
  */
-#define EE_OK			0	/* No error */
-#define EE_INVALID		1	/* Invalid ELF image */
-#define	EE_MEMORY		2	/* Cannot allocate address space */
-#define EE_INCOMPATIBLE		3	/* ELF image is not compatible with current architecture */
-#define EE_UNSUPPORTED		4	/* Non-supported ELF (e.g. dynamic ELFs) */
-#define EE_LOADER		5	/* The image is actually a program loader. */
-#define EE_IRRECOVERABLE	6
+#define EE_OK             0  /* No error */
+#define EE_INVALID        1  /* Invalid ELF image */
+#define EE_MEMORY         2  /* Cannot allocate address space */
+#define EE_INCOMPATIBLE   3  /* ELF image is not compatible with current architecture */
+#define EE_UNSUPPORTED    4  /* Non-supported ELF (e.g. dynamic ELFs) */
+#define EE_LOADER         5  /* The image is actually a program loader. */
+#define EE_IRRECOVERABLE  6  /* Irrecoverable error. */
 
 /**
  * This flags is passed when running the loader, otherwise elf_load()
  * would return with a EE_LOADER error code.
- *
  */
 #define ELD_F_NONE    0
Index: kernel/generic/include/macros.h
===================================================================
--- kernel/generic/include/macros.h	(revision cc106e483d059603a58bf1afab2123168615a299)
+++ kernel/generic/include/macros.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -52,8 +52,19 @@
     uint64_t sz2)
 {
-	uint64_t e1 = s1 + sz1;
-	uint64_t e2 = s2 + sz2;
-	
-	return ((s1 < e2) && (s2 < e1));
+	uint64_t e1 = s1 + sz1 - 1;
+	uint64_t e2 = s2 + sz2 - 1;
+
+	/* both sizes are non-zero */
+	if (sz1 && sz2)
+		return ((s1 <= e2) && (s2 <= e1));
+
+	/* one size is non-zero */
+	if (sz2)
+		return ((s1 >= s2) && (s1 <= e2));
+	if (sz1)
+		return ((s2 >= s1) && (s2 <= e1));
+
+	/* both are zero */
+	return (s1 == s2);
 }
 
@@ -119,4 +130,12 @@
 	    | ((((uint64_t) (up)) & UINT32_C(0xffffffff)) << 32))
 
+/* Test for sum overflow. */
+#define overflows(a, b) \
+	((a) + (b) < (a))
+
+/* Test for sum overflow into positive numbers. */
+#define overflows_into_positive(a, b)	\
+	(overflows((a), (b)) && ((a) + (b) > 0))
+
 /** Pseudorandom generator
  *
Index: kernel/generic/include/print.h
===================================================================
--- kernel/generic/include/print.h	(revision cc106e483d059603a58bf1afab2123168615a299)
+++ kernel/generic/include/print.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -38,15 +38,5 @@
 #include <typedefs.h>
 #include <stdarg.h>
-
-#ifndef NVERIFY_PRINTF
-
-#define PRINTF_ATTRIBUTE(start, end) \
-	__attribute__((format(gnu_printf, start, end)))
-
-#else /* NVERIFY_PRINTF */
-
-#define PRINTF_ATTRIBUTE(start, end)
-
-#endif /* NVERIFY_PRINTF */
+#include <printf/verify.h>
 
 #define EOF  (-1)
Index: kernel/generic/include/printf/verify.h
===================================================================
--- kernel/generic/include/printf/verify.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
+++ kernel/generic/include/printf/verify.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_PRINTF_VERIFY_H_
+#define KERN_PRINTF_VERIFY_H_
+
+#ifndef NVERIFY_PRINTF
+
+#define PRINTF_ATTRIBUTE(start, end) \
+	__attribute__((format(gnu_printf, start, end)))
+
+#else /* NVERIFY_PRINTF */
+
+#define PRINTF_ATTRIBUTE(start, end)
+
+#endif /* NVERIFY_PRINTF */
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision cc106e483d059603a58bf1afab2123168615a299)
+++ kernel/generic/include/proc/task.h	(revision 33c29521d96b892e096419a2fd8beb867e2596f6)
@@ -95,8 +95,24 @@
 	
 	/* IPC stuff */
-	answerbox_t answerbox;  /**< Communication endpoint */
+
+	/** Receiving communication endpoint */
+	answerbox_t answerbox;
+
+	/** Sending communication endpoints */
 	phone_t phones[IPC_MAX_PHONES];
-	stats_ipc_t ipc_info;   /**< IPC statistics */
+
+	/** Spinlock protecting the active_calls list. */
+	SPINLOCK_DECLARE(active_calls_lock);
+
+	/**
+	 * List of all calls sent by this task that have not yet been
+	 * answered.
+	 */
+	list_t active_calls;
+
 	event_t events[EVENT_TASK_END - EVENT_END];
+
+	/** IPC statistics */
+	stats_ipc_t ipc_info;
 	
 #ifdef CONFIG_UDEBUG
