Index: Makefile
===================================================================
--- Makefile	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ Makefile	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -123,4 +123,5 @@
 	generic/src/console/console.c \
 	generic/src/console/kconsole.c \
+	generic/src/console/klog.c \
 	generic/src/console/cmd.c \
 	generic/src/cpu/cpu.c \
Index: arch/amd64/include/interrupt.h
===================================================================
--- arch/amd64/include/interrupt.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/amd64/include/interrupt.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -87,7 +87,17 @@
 };
 
+/** Return true if exception happened while in userspace */
+static inline int istate_from_uspace(istate_t *istate)
+{
+	return !(istate->rip & 0x8000000000000000);
+}
+
 static inline void istate_set_retaddr(istate_t *istate, __address retaddr)
 {
 	istate->rip = retaddr;
+}
+static inline __native istate_get_pc(istate_t *istate)
+{
+	return istate->rip;
 }
 
Index: arch/amd64/src/interrupt.c
===================================================================
--- arch/amd64/src/interrupt.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/amd64/src/interrupt.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -80,4 +80,5 @@
 void null_interrupt(int n, istate_t *istate)
 {
+	fault_if_from_uspace(istate, "unserviced interrupt: %d", n);
 	print_info_errcode(n, istate);
 	panic("unserviced interrupt\n");
@@ -105,4 +106,5 @@
 			return;
 		}
+		fault_if_from_uspace(istate, "general protection fault");
 	}
 
@@ -113,4 +115,5 @@
 void ss_fault(int n, istate_t *istate)
 {
+	fault_if_from_uspace(istate, "stack fault");
 	print_info_errcode(n, istate);
 	panic("stack fault\n");
@@ -122,4 +125,5 @@
 	scheduler_fpu_lazy_request();
 #else
+	fault_if_from_uspace(istate, "fpu fault");
 	panic("fpu fault");
 #endif
Index: arch/amd64/src/mm/page.c
===================================================================
--- arch/amd64/src/mm/page.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/amd64/src/mm/page.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -184,4 +184,6 @@
 	
 	if (as_page_fault(page, access, istate) == AS_PF_FAULT) {
+		fault_if_from_uspace(istate, "Page fault: %#x", page);
+
 		print_info_errcode(n, istate);
 		printf("Page fault address: %llX\n", page);
Index: arch/ia32/include/interrupt.h
===================================================================
--- arch/ia32/include/interrupt.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/ia32/include/interrupt.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -84,7 +84,18 @@
 };
 
+/** Return true if exception happened while in userspace */
+static inline int istate_from_uspace(istate_t *istate)
+{
+	return !(istate->eip & 0x80000000);
+}
+
 static inline void istate_set_retaddr(istate_t *istate, __address retaddr)
 {
 	istate->eip = retaddr;
+}
+
+static inline __native istate_get_pc(istate_t *istate)
+{
+	return istate->eip;
 }
 
Index: arch/ia32/src/interrupt.c
===================================================================
--- arch/ia32/src/interrupt.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/ia32/src/interrupt.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -80,4 +80,6 @@
 void null_interrupt(int n, istate_t *istate)
 {
+	fault_if_from_uspace(istate, "unserviced interrupt: %d", n);
+
 	PRINT_INFO_ERRCODE(istate);
 	panic("unserviced interrupt: %d\n", n);
@@ -105,4 +107,5 @@
 			return;
 		}
+		fault_if_from_uspace(istate, "general protection fault");
 	}
 
@@ -113,4 +116,6 @@
 void ss_fault(int n, istate_t *istate)
 {
+	fault_if_from_uspace(istate, "stack fault");
+
 	PRINT_INFO_ERRCODE(istate);
 	panic("stack fault\n");
@@ -119,6 +124,4 @@
 void simd_fp_exception(int n, istate_t *istate)
 {
-
-	PRINT_INFO_ERRCODE(istate);
 	__u32 mxcsr;
 	asm
@@ -127,4 +130,8 @@
 		:"=m"(mxcsr)
 	);
+	fault_if_from_uspace(istate, "SIMD FP exception(19), MXCSR: %#zX",
+			     (__native)mxcsr);
+
+	PRINT_INFO_ERRCODE(istate);
 	printf("MXCSR: %#zX\n",(__native)(mxcsr));
 	panic("SIMD FP exception(19)\n");
@@ -136,4 +143,5 @@
 	scheduler_fpu_lazy_request();
 #else
+	fault_if_from_uspace(istate, "fpu fault");
 	panic("fpu fault");
 #endif
Index: arch/ia32/src/mm/page.c
===================================================================
--- arch/ia32/src/mm/page.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/ia32/src/mm/page.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -104,4 +104,6 @@
 
         if (as_page_fault(page, access, istate) == AS_PF_FAULT) {
+		fault_if_from_uspace(istate, "Page fault: %#x", page);
+
                 PRINT_INFO_ERRCODE(istate);
                 printf("page fault address: %#x\n", page);
Index: arch/ia64/include/interrupt.h
===================================================================
--- arch/ia64/include/interrupt.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/ia64/include/interrupt.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -114,4 +114,15 @@
 }
 
+static inline __native istate_get_pc(istate_t *istate)
+{
+	return istate->cr_iip;
+}
+#include <panic.h>
+static inline int istate_from_uspace(istate_t *istate)
+{
+	panic("TODO: istate_from_uspace not yet implemented");
+	return 0;
+}
+
 extern void *ivt;
 
Index: arch/ia64/src/interrupt.c
===================================================================
--- arch/ia64/src/interrupt.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/ia64/src/interrupt.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -47,4 +47,5 @@
 #include <ipc/irq.h>
 #include <ipc/ipc.h>
+#include <interrupt.h>
 
 
@@ -151,6 +152,4 @@
 	char *desc = "";
 
-	dump_interrupted_context(istate);
-
 	switch (istate->cr_isr.ge_code) {
 	    case GE_ILLEGALOP:
@@ -177,4 +176,7 @@
 	}
 
+	fault_if_from_uspace(istate, "General Exception (%s)", desc);
+
+	dump_interrupted_context(istate);
 	panic("General Exception (%s)\n", desc);
 }
@@ -187,4 +189,5 @@
 	scheduler_fpu_lazy_request();	
 #else
+	fault_if_from_uspace(istate, "Interruption: %#hx (%s)", (__u16) vector, vector_to_string(vector));
 	dump_interrupted_context(istate);
 	panic("Interruption: %#hx (%s)\n", (__u16) vector, vector_to_string(vector));
@@ -268,5 +271,2 @@
 	/* TODO */
 }
-
-
-
Index: arch/mips32/include/arg.h
===================================================================
--- arch/mips32/include/arg.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/mips32/include/arg.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -45,4 +45,6 @@
 	(((type *)((ap) = (va_list)( (sizeof(type) <= 4) ? ((__address)((ap) + 2*4 - 1) & (~3)) : ((__address)((ap) + 2*8 -1) & (~7)) )))[-1])
 
+#define va_copy(dst,src) ((dst)=(src))
+
 #define va_end(ap)
 
Index: arch/mips32/include/exception.h
===================================================================
--- arch/mips32/include/exception.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/mips32/include/exception.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -35,4 +35,5 @@
 
 #include <typedefs.h>
+#include <arch/cp0.h>
 
 #define EXC_Int		0
@@ -99,4 +100,14 @@
 }
 
+/** Return true if exception happened while in userspace */
+static inline int istate_from_uspace(istate_t *istate)
+{
+	return istate->status & cp0_status_um_bit;
+}
+static inline __native istate_get_pc(istate_t *istate)
+{
+	return istate->epc;
+}
+
 extern void exception(istate_t *istate);
 extern void tlb_refill_entry(void);
Index: arch/mips32/src/exception.c
===================================================================
--- arch/mips32/src/exception.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/mips32/src/exception.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -79,4 +79,6 @@
 static void unhandled_exception(int n, istate_t *istate)
 {
+	fault_if_from_uspace(istate, "unhandled exception %s", exctable[n]);
+	
 	print_regdump(istate);
 	panic("unhandled exception %s\n", exctable[n]);
@@ -120,6 +122,8 @@
 	if (cp0_cause_coperr(cp0_cause_read()) == fpu_cop_id)
 		scheduler_fpu_lazy_request();
-	else
+	else {
+		fault_if_from_uspace(istate, "unhandled Coprocessor Unusable Exception");
 		panic("unhandled Coprocessor Unusable Exception\n");
+	}
 }
 #endif
Index: arch/mips32/src/mm/tlb.c
===================================================================
--- arch/mips32/src/mm/tlb.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/mips32/src/mm/tlb.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -40,4 +40,5 @@
 #include <debug.h>
 #include <align.h>
+#include <interrupt.h>
 
 static void tlb_refill_fail(istate_t *istate);
@@ -337,4 +338,6 @@
 	if (s)
 		sym2 = s;
+
+	fault_if_from_uspace(istate, "TLB Refill Exception on %P", cp0_badvaddr_read());
 	panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), istate->epc, symbol, sym2);
 }
@@ -348,4 +351,5 @@
 	if (s)
 		symbol = s;
+	fault_if_from_uspace(istate, "TLB Invalid Exception on %P", cp0_badvaddr_read());
 	panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), istate->epc, symbol);
 }
@@ -358,4 +362,5 @@
 	if (s)
 		symbol = s;
+	fault_if_from_uspace(istate, "TLB Modified Exception on %P", cp0_badvaddr_read());
 	panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), istate->epc, symbol);
 }
Index: arch/ppc32/include/exception.h
===================================================================
--- arch/ppc32/include/exception.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/ppc32/include/exception.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -81,4 +81,15 @@
 	istate->pc = retaddr;
 }
+/** Return true if exception happened while in userspace */
+#include <panic.h>
+static inline int istate_from_uspace(istate_t *istate)
+{
+	panic("istate_from_uspace not yet implemented");
+	return 0;
+}
+static inline __native istate_get_pc(istate_t *istate)
+{
+	return istate->pc;
+}
 
 #endif
Index: arch/ppc32/src/interrupt.c
===================================================================
--- arch/ppc32/src/interrupt.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/ppc32/src/interrupt.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -67,5 +67,4 @@
 }
 
-#include <print.h>
 /** Handler of externul interrupts */
 void extint_handler(int n, istate_t *istate)
Index: arch/ppc64/include/exception.h
===================================================================
--- arch/ppc64/include/exception.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/ppc64/include/exception.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -81,4 +81,15 @@
 	istate->pc = retaddr;
 }
+/** Return true if exception happened while in userspace */
+#include <panic.h>
+static inline int istate_from_uspace(istate_t *istate)
+{
+	panic("istate_from_uspace not yet implemented");
+	return 0;
+}
+static inline __native istate_get_pc(istate_t *istate)
+{
+	return istate->pc;
+}
 
 #endif
Index: arch/sparc64/include/interrupt.h
===================================================================
--- arch/sparc64/include/interrupt.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ arch/sparc64/include/interrupt.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -52,4 +52,13 @@
 	/* TODO */
 }
+static inline int istate_from_uspace(istate_t *istate)
+{
+	/* TODO */
+}
+static inline __native istate_get_pc(istate_t *istate)
+{
+	/* TODO */
+}
+
 
 extern void interrupt_register(int n, const char *name, iroutine f);
Index: generic/include/console/klog.h
===================================================================
--- generic/include/console/klog.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
+++ generic/include/console/klog.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -0,0 +1,35 @@
+/*
+ * 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 _KLOG_H_
+#define _KLOG_H_
+
+void klog_init(void);
+void klog_printf(const char *fmt, ...);
+
+#endif
Index: generic/include/interrupt.h
===================================================================
--- generic/include/interrupt.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/include/interrupt.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -33,4 +33,9 @@
 #include <typedefs.h>
 #include <arch/types.h>
+#include <proc/task.h>
+#include <proc/thread.h>
+#include <arch.h>
+#include <console/klog.h>
+#include <ipc/irq.h>
 
 #ifndef IVT_ITEMS
@@ -42,4 +47,15 @@
 #endif
 
+#define fault_if_from_uspace(istate, cmd, ...) \
+{ \
+	if (istate_from_uspace(istate)) { \
+                klog_printf(cmd, ##__VA_ARGS__); \
+                klog_printf("Task %lld got exception at PC:%P. Task killed.", TASK->taskid, istate_get_pc(istate)); \
+		task_kill(TASK->taskid); \
+		thread_exit(); \
+	} \
+}
+
+
 extern iroutine exc_register(int n, const char *name, iroutine f);
 extern void exc_dispatch(int n, istate_t *t);
Index: generic/include/ipc/irq.h
===================================================================
--- generic/include/ipc/irq.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/include/ipc/irq.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -30,5 +30,11 @@
 #define __IRQ_H__
 
+/** Maximum length of IPC IRQ program */
 #define IRQ_MAX_PROG_SIZE 10
+
+/** Reserved 'virtual' messages for kernel notifications */
+#define IPC_IRQ_RESERVED_VIRTUAL 10
+
+#define IPC_IRQ_KLOG  (-1)
 
 typedef enum {
@@ -60,7 +66,10 @@
 #ifdef KERNEL
 
+#include <ipc/ipc.h>
+
 extern void ipc_irq_make_table(int irqcount);
 extern int ipc_irq_register(answerbox_t *box, int irq, irq_code_t *ucode);
 extern void ipc_irq_send_notif(int irq);
+extern void ipc_irq_send_msg(int irq, __native a2, __native a3);
 extern void ipc_irq_unregister(answerbox_t *box, int irq);
 extern void irq_ipc_bind_arch(__native irq);
Index: generic/include/ipc/sysipc.h
===================================================================
--- generic/include/ipc/sysipc.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/include/ipc/sysipc.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -48,6 +48,6 @@
 			      __native method, __native arg1);
 __native sys_ipc_hangup(int phoneid);
-__native sys_ipc_register_irq(__native irq, irq_code_t *ucode);
-__native sys_ipc_unregister_irq(__native irq);
+__native sys_ipc_register_irq(int irq, irq_code_t *ucode);
+__native sys_ipc_unregister_irq(int irq);
 
 #endif
Index: generic/include/proc/thread.h
===================================================================
--- generic/include/proc/thread.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/include/proc/thread.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -151,5 +151,5 @@
 extern thread_t *thread_create(void (* func)(void *), void *arg, task_t *task, int flags, char *name);
 extern void thread_ready(thread_t *t);
-extern void thread_exit(void);
+extern void thread_exit(void) __attribute__((noreturn));
 
 #ifndef thread_create_arch
Index: generic/include/stackarg.h
===================================================================
--- generic/include/stackarg.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/include/stackarg.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -50,4 +50,5 @@
 	(*((type *)((ap).last + ((ap).pos  += sizeof(type) ) - sizeof(type))))
 
+#define va_copy(dst,src)       dst=src
 #define va_end(ap)
 
Index: generic/include/stdarg.h
===================================================================
--- generic/include/stdarg.h	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/include/stdarg.h	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -41,4 +41,5 @@
 #define va_arg(ap, type) 		__builtin_va_arg(ap, type)
 #define va_end(ap)			__builtin_va_end(ap)
+#define va_copy(dst,src)		__builtin_va_copy(dst,src)
 
 #endif
Index: generic/src/console/klog.c
===================================================================
--- generic/src/console/klog.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
+++ generic/src/console/klog.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#include <mm/frame.h>
+#include <sysinfo/sysinfo.h>
+#include <console/klog.h>
+#include <print.h>
+#include <ipc/irq.h>
+
+/* Order of frame to be allocated for klog communication */
+#define KLOG_ORDER 0
+
+static char *klog;
+static int klogsize;
+static int klogpos;
+
+SPINLOCK_INITIALIZE(klog_lock);
+
+/** Initialize kernel loggin facility
+ *
+ * Allocate pages that are to be shared if uspace for console data
+ */
+void klog_init(void)
+{
+	void *faddr;
+
+	faddr = (void *)PFN2ADDR(frame_alloc(KLOG_ORDER, FRAME_ATOMIC));
+	if (!faddr)
+		panic("Cannot allocate page for klog");
+	klog = (char *)PA2KA(faddr);
+	
+	sysinfo_set_item_val("klog.faddr", NULL, (__native)faddr);
+	sysinfo_set_item_val("klog.pages", NULL, 1 << KLOG_ORDER);
+
+	klogsize = PAGE_SIZE << KLOG_ORDER;
+	klogpos = 0;
+}
+
+static void klog_vprintf(const char *fmt, va_list args)
+{
+	int ret;
+	va_list atst;
+
+	va_copy(atst, args);
+	spinlock_lock(&klog_lock);
+
+	ret = vsnprintf(klog+klogpos, klogsize-klogpos, fmt, atst);
+	// Workaround around bad return value from vsnprintf
+	if (ret+klogpos < klogsize)
+		ret = 100;
+	if (ret == klogsize-klogpos) {
+		klogpos = 0;
+		ret = vsnprintf(klog+klogpos, klogsize-klogpos, fmt, args);
+		ret = 100;
+		if (ret == klogsize)
+			goto out;
+	}
+	ipc_irq_send_msg(IPC_IRQ_KLOG, klogpos, ret);
+	klogpos += ret;
+	if (klogpos >= klogsize)
+		klogpos = 0;
+out:
+	spinlock_unlock(&klog_lock);
+	va_end(atst);
+}
+
+/** Printf a message to kernel-uspace log */
+void klog_printf(const char *fmt, ...)
+{
+	va_list args;
+	
+	va_start(args, fmt);
+	
+	klog_vprintf(fmt, args);
+
+	va_end(args);
+}
Index: generic/src/interrupt/interrupt.c
===================================================================
--- generic/src/interrupt/interrupt.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/src/interrupt/interrupt.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -91,4 +91,5 @@
 static void exc_undef(int n, istate_t *istate)
 {
+	fault_if_from_uspace(istate, "Unhandled exception %d.", n);
 	panic("Unhandled exception %d.", n);
 }
Index: generic/src/ipc/ipc.c
===================================================================
--- generic/src/ipc/ipc.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/src/ipc/ipc.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -336,8 +336,5 @@
 		list_append(&request->link, &box->dispatched_calls);
 	} else {
-		/* This can happen regularly after ipc_cleanup, remove
-		 * the warning in the future when the IPC is
-		 * more debugged */
-		printf("WARNING: Spurious IPC wakeup.\n");
+		/* This can happen regularly after ipc_cleanup */
 		spinlock_unlock(&box->lock);
 		goto restart;
Index: generic/src/ipc/irq.c
===================================================================
--- generic/src/ipc/irq.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/src/ipc/irq.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -157,14 +157,15 @@
 {
 	ipl_t ipl;
+	int mq = irq + IPC_IRQ_RESERVED_VIRTUAL;
 
 	ipl = interrupts_disable();
-	spinlock_lock(&irq_conns[irq].lock);
-	if (irq_conns[irq].box == box) {
-		irq_conns[irq].box = NULL;
-		code_free(irq_conns[irq].code);
-		irq_conns[irq].code = NULL;
-	}
-
-	spinlock_unlock(&irq_conns[irq].lock);
+	spinlock_lock(&irq_conns[mq].lock);
+	if (irq_conns[mq].box == box) {
+		irq_conns[mq].box = NULL;
+		code_free(irq_conns[mq].code);
+		irq_conns[mq].code = NULL;
+	}
+
+	spinlock_unlock(&irq_conns[mq].lock);
 	interrupts_restore(ipl);
 }
@@ -175,4 +176,5 @@
 	ipl_t ipl;
 	irq_code_t *code;
+	int mq = irq + IPC_IRQ_RESERVED_VIRTUAL;
 
 	ASSERT(irq_conns);
@@ -186,16 +188,16 @@
 
 	ipl = interrupts_disable();
-	spinlock_lock(&irq_conns[irq].lock);
-
-	if (irq_conns[irq].box) {
-		spinlock_unlock(&irq_conns[irq].lock);
+	spinlock_lock(&irq_conns[mq].lock);
+
+	if (irq_conns[mq].box) {
+		spinlock_unlock(&irq_conns[mq].lock);
 		interrupts_restore(ipl);
 		code_free(code);
 		return EEXISTS;
 	}
-	irq_conns[irq].box = box;
-	irq_conns[irq].code = code;
-	atomic_set(&irq_conns[irq].counter, 0);
-	spinlock_unlock(&irq_conns[irq].lock);
+	irq_conns[mq].box = box;
+	irq_conns[mq].code = code;
+	atomic_set(&irq_conns[mq].counter, 0);
+	spinlock_unlock(&irq_conns[mq].lock);
 	interrupts_restore(ipl);
 
@@ -203,19 +205,30 @@
 }
 
-/** Notify process that an irq had happend
- *
- * We expect interrupts to be disabled
- */
-void ipc_irq_send_notif(int irq)
+/** Add call to proper answerbox queue
+ *
+ * Assume irq_conns[mq].lock is locked */
+static void send_call(int mq, call_t *call)
+{
+	spinlock_lock(&irq_conns[mq].box->irq_lock);
+	list_append(&call->link, &irq_conns[mq].box->irq_notifs);
+	spinlock_unlock(&irq_conns[mq].box->irq_lock);
+		
+	waitq_wakeup(&irq_conns[mq].box->wq, 0);
+}
+
+/** Send notification message
+ *
+ */
+void ipc_irq_send_msg(int irq, __native a2, __native a3)
 {
 	call_t *call;
-
-	ASSERT(irq_conns);
-	spinlock_lock(&irq_conns[irq].lock);
-
-	if (irq_conns[irq].box) {
+	int mq = irq + IPC_IRQ_RESERVED_VIRTUAL;
+
+	spinlock_lock(&irq_conns[mq].lock);
+
+	if (irq_conns[mq].box) {
 		call = ipc_call_alloc(FRAME_ATOMIC);
 		if (!call) {
-			spinlock_unlock(&irq_conns[irq].lock);
+			spinlock_unlock(&irq_conns[mq].lock);
 			return;
 		}
@@ -223,24 +236,54 @@
 		IPC_SET_METHOD(call->data, IPC_M_INTERRUPT);
 		IPC_SET_ARG1(call->data, irq);
-		IPC_SET_ARG3(call->data, atomic_preinc(&irq_conns[irq].counter));
+		IPC_SET_ARG2(call->data, a2);
+		IPC_SET_ARG3(call->data, a3);
+		
+		send_call(mq, call);
+	}
+	spinlock_unlock(&irq_conns[mq].lock);
+}
+
+/** Notify process that an irq had happend
+ *
+ * We expect interrupts to be disabled
+ */
+void ipc_irq_send_notif(int irq)
+{
+	call_t *call;
+	int mq = irq + IPC_IRQ_RESERVED_VIRTUAL;
+
+	ASSERT(irq_conns);
+	spinlock_lock(&irq_conns[mq].lock);
+
+	if (irq_conns[mq].box) {
+		call = ipc_call_alloc(FRAME_ATOMIC);
+		if (!call) {
+			spinlock_unlock(&irq_conns[mq].lock);
+			return;
+		}
+		call->flags |= IPC_CALL_NOTIF;
+		IPC_SET_METHOD(call->data, IPC_M_INTERRUPT);
+		IPC_SET_ARG1(call->data, irq);
+		IPC_SET_ARG3(call->data, atomic_preinc(&irq_conns[mq].counter));
 
 		/* Execute code to handle irq */
-		code_execute(call, irq_conns[irq].code);
-
-		spinlock_lock(&irq_conns[irq].box->irq_lock);
-		list_append(&call->link, &irq_conns[irq].box->irq_notifs);
-		spinlock_unlock(&irq_conns[irq].box->irq_lock);
-
-		waitq_wakeup(&irq_conns[irq].box->wq, 0);
-	}
+		code_execute(call, irq_conns[mq].code);
 		
-	spinlock_unlock(&irq_conns[irq].lock);
-}
-
-
-/** Initialize table of interrupt handlers */
+		send_call(mq, call);
+	}
+		
+	spinlock_unlock(&irq_conns[mq].lock);
+}
+
+
+/** Initialize table of interrupt handlers
+ *
+ * @param irqcount Count of required hardware IRQs to be supported
+ */
 void ipc_irq_make_table(int irqcount)
 {
 	int i;
+
+	irqcount +=  IPC_IRQ_RESERVED_VIRTUAL;
 
 	irq_conns_size = irqcount;
Index: generic/src/ipc/sysipc.c
===================================================================
--- generic/src/ipc/sysipc.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/src/ipc/sysipc.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -554,12 +554,12 @@
 
 /** Connect irq handler to task */
-__native sys_ipc_register_irq(__native irq, irq_code_t *ucode)
+__native sys_ipc_register_irq(int irq, irq_code_t *ucode)
 {
 	if (!(cap_get(TASK) & CAP_IRQ_REG))
 		return EPERM;
 
-	if (irq >= IRQ_COUNT)
+	if (irq >= IRQ_COUNT || irq <= -IPC_IRQ_RESERVED_VIRTUAL)
 		return (__native) ELIMIT;
-
+	
 	irq_ipc_bind_arch(irq);
 
@@ -568,10 +568,10 @@
 
 /* Disconnect irq handler from task */
-__native sys_ipc_unregister_irq(__native irq)
+__native sys_ipc_unregister_irq(int irq)
 {
 	if (!(cap_get(TASK) & CAP_IRQ_REG))
 		return EPERM;
 
-	if (irq >= IRQ_COUNT)
+	if (irq >= IRQ_COUNT || irq <= -IPC_IRQ_RESERVED_VIRTUAL)
 		return (__native) ELIMIT;
 
Index: generic/src/main/main.c
===================================================================
--- generic/src/main/main.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/src/main/main.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -75,4 +75,5 @@
 #include <macros.h>
 #include <adt/btree.h>
+#include <console/klog.h>
 
 #ifdef CONFIG_SMP
@@ -219,4 +220,5 @@
 	thread_init();
 	futex_init();
+	klog_init();
 	
 	for (i = 0; i < init.cnt; i++)
Index: generic/src/proc/thread.c
===================================================================
--- generic/src/proc/thread.c	(revision 6f9a9bca0eb57eab9af41bd5a627f7f7fdcdc276)
+++ generic/src/proc/thread.c	(revision 874621f88e11575154ad0c2e08fc906a8d92e4c0)
@@ -389,4 +389,8 @@
 	spinlock_unlock(&THREAD->lock);
 	scheduler();
+
+	/* Not reached */
+	while (1)
+		;
 }
 
