Index: Makefile
===================================================================
--- Makefile	(revision e9073f240239cbd48fb09793c7ed5cc32ff493fb)
+++ Makefile	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -40,5 +40,7 @@
 	fb \
 	console \
-	tetris
+	tetris \
+	ipcc \
+	klog
 
 ifeq ($(ARCH), amd64)
Index: ipcc/Makefile
===================================================================
--- ipcc/Makefile	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
+++ ipcc/Makefile	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -0,0 +1,73 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+LIBC_PREFIX = ../libc
+SOFTINT_PREFIX = ../softint
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -I../kbd/include
+
+LIBS = $(LIBC_PREFIX)/libc.a
+
+## Sources
+#
+
+OUTPUT = ipcc
+SOURCES = ipcc.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all clean depend disasm
+
+all: $(OUTPUT) disasm
+
+-include Makefile.depend
+
+clean:
+	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend
+
+depend:
+	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+disasm:
+	$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm
+
+%.o: %.S
+	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
+
+%.o: %.s
+	$(AS) $(AFLAGS) $< -o $@
+
+%.o: %.c
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
Index: ipcc/ipcc.c
===================================================================
--- ipcc/ipcc.c	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
+++ ipcc/ipcc.c	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <async.h>
+#include <ipc/ipc.h>
+#include <ipc/services.h>
+#include <errno.h>
+
+#define TEST_START       10000
+#define MAXLIST          4
+
+#define MSG_HANG_ME_UP   2000
+
+static int connections[50];
+static ipc_callid_t callids[50];
+static int phones[20];
+static int myservice = 0;
+
+static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	ipcarg_t phonehash = icall->in_phone_hash;
+	int retval;
+	int i;
+
+	printf("Connected phone: %P, accepting\n", icall->in_phone_hash);
+	ipc_answer_fast(iid, 0, 0, 0);
+	for (i=0;i < 1024;i++)
+		if (!connections[i]) {
+			connections[i] = phonehash;
+			break;
+		}
+	
+	while (1) {
+		callid = async_get_call(&call);
+		switch (IPC_GET_METHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			printf("Phone (%P) hung up.\n", phonehash);
+			retval = 0;
+			break;
+		default:
+			printf("Received message from %P: %X\n", phonehash,callid);
+			for (i=0; i < 1024; i++)
+				if (!callids[i]) {
+					callids[i] = callid;
+					break;
+				}
+			continue;
+		}
+		ipc_answer_fast(callid, retval, 0, 0);
+	}
+}
+
+static void printhelp(void)
+{
+	printf("? - help\n");
+	printf("c - connect to other service\n");
+	printf("h - hangup connection\n");
+	printf("a - send async message to other service\n");
+	printf("s - send sync message to other service\n");
+	printf("d - answer message that we have received\n");
+	printf("j - jump to endless loop\n");
+	printf("p - page fault\n");
+}
+
+static void callback(void *private, int retval, ipc_call_t *data)
+{
+	printf("Received response to msg %d - retval: %d.\n", private,
+	       retval);
+}
+
+static void do_answer_msg(void)
+{
+	int i,cnt, errn;
+	char c;
+	ipc_callid_t callid;
+
+	cnt = 0;
+	for (i=0;i < 50;i++) {
+		if (callids[i]) {
+			printf("%d: %P\n", cnt, callids[i]);
+			cnt++;
+		}
+		if (cnt >= 10)
+			break;
+	}
+	if (!cnt)
+		return;
+	printf("Choose message:\n");
+	do {
+		c = getchar();
+	} while (c < '0' || (c-'0') >= cnt);
+	cnt = c - '0' + 1;
+	
+	for (i=0;cnt;i++)
+		if (callids[i])
+			cnt--;
+	i -= 1;
+
+	printf("Normal (n) or hangup (h) or error(e) message?\n");
+	do {
+		c = getchar();
+	} while (c != 'n' && c != 'h' && c != 'e');
+	if (c == 'n')
+		errn = 0;
+	else if (c == 'h')
+		errn = EHANGUP;
+	else if (c == 'e')
+		errn = ENOENT;
+	printf("Answering %P\n", callids[i]);
+	ipc_answer_fast(callids[i], errn, 0, 0);
+	callids[i] = 0;
+}
+
+static void do_send_msg(int async)
+{
+	int phoneid;
+	int res;
+	static int msgid = 1;
+	char c;
+
+	printf("Select phoneid to send msg: 2-9\n");
+	do {
+		c = getchar();
+	} while (c < '2' || c > '9');
+	phoneid = c - '0';
+
+	if (async) {
+		ipc_call_async(phoneid, 2000, 0, (void *)msgid, callback, 1);
+		printf("Async sent - msg %d\n", msgid);
+		msgid++;
+	} else {
+		printf("Sending msg...");
+		res = ipc_call_sync_2(phoneid, 2000, 0, 0, NULL, NULL);
+		printf("done: %d\n", res);
+	}
+}
+
+static void do_hangup(void)
+{
+	char c;
+	int res;
+	int phoneid;
+
+	printf("Select phoneid to hangup: 2-9\n");
+	do {
+		c = getchar();
+	} while (c < '2' || c > '9');
+	phoneid = c - '0';
+	
+	printf("Hanging up...");
+	res = ipc_hangup(phoneid);
+	printf("done: %d\n", phoneid);
+}
+
+static void do_connect(void)
+{
+	char c;
+	int svc;
+	int phid;
+
+	printf("Choose one service: 0:10000....9:10009\n");
+	do {
+		c = getchar();
+	} while (c < '0' || c > '9');
+	svc = TEST_START + c - '0';
+	if (svc == myservice) {
+		printf("Currently cannot connect to myself, update test\n");
+		return;
+	}
+	printf("Connecting to %d..", svc);
+	phid = ipc_connect_me_to(PHONE_NS, svc, 0);
+	if (phid > 0) {
+		printf("phoneid: %d\n", phid);
+		phones[phid] = 1;
+	} else
+		printf("error: %d\n", phid);
+}
+
+int main(void)
+{
+	ipcarg_t phonead;
+	int i;
+	char c;
+	int res;
+
+	printf("********************************\n");
+	printf("***********IPC Tester***********\n");
+	printf("********************************\n");
+
+	
+	async_set_client_connection(client_connection);
+
+	for (i=TEST_START;i < TEST_START+10;i++) {
+		res = ipc_connect_to_me(PHONE_NS, i, 0, &phonead);
+		if (!res)
+			break;
+		printf("Failed registering as %d..:%d\n", i, res);
+	}
+	printf("Registered as service: %d\n", i);
+	myservice = i;
+
+	printhelp();
+	while (1) {
+		c = getchar();
+		switch (c) {
+		case '?':
+			printhelp();
+			break;
+		case 'h':
+			do_hangup();
+			break;
+		case 'c':
+			do_connect();
+			break;
+		case 'a':
+			do_send_msg(1);
+			break;
+		case 's':
+			do_send_msg(0);
+			break;
+		case 'd':
+			do_answer_msg();
+			break;
+		case 'j':
+			while (1)
+				;
+		case 'p':
+			printf("Doing page fault\n");
+			*((char *)0) = 1;
+			printf("done\n");
+		}
+	}
+}
Index: klog/Makefile
===================================================================
--- klog/Makefile	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
+++ klog/Makefile	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -0,0 +1,73 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+LIBC_PREFIX = ../libc
+SOFTINT_PREFIX = ../softint
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+LIBS = $(LIBC_PREFIX)/libc.a
+
+## Sources
+#
+
+OUTPUT = klog
+SOURCES = \
+	klog.c
+
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all clean depend disasm
+
+all: $(OUTPUT) disasm
+
+-include Makefile.depend
+
+clean:
+	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend
+
+depend:
+	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+disasm:
+	$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm
+
+%.o: %.S
+	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
+
+%.o: %.s
+	$(AS) $(AFLAGS) $< -o $@
+
+%.o: %.c
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
Index: klog/klog.c
===================================================================
--- klog/klog.c	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
+++ klog/klog.c	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -0,0 +1,78 @@
+/*
+ * 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 <stdio.h>
+#include <ipc/ipc.h>
+#include <async.h>
+#include <ipc/services.h>
+#include <as.h>
+#include <kernel/ipc/irq.h>
+
+/* Pointer to klog area */
+static char *klog;
+
+void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
+{
+	int i;
+	
+//	psthread_serialize_start();
+	/* TODO: remove workaround around non-functional vsnprintf */
+	for (i=0; klog[i + IPC_GET_ARG2(*call)] && i < IPC_GET_ARG3(*call); i++)
+		putchar(klog[i + IPC_GET_ARG2(*call)]);
+	putchar('\n');
+//	psthread_serialize_done();
+}
+
+int main(int argc, char *argv[])
+{
+	int res;
+	void *mapping;
+
+	printf("Kernel console output.\n");
+	
+	mapping = as_get_mappable_page(PAGE_SIZE);
+	res = ipc_call_sync_3(PHONE_NS, IPC_M_AS_AREA_RECV, 
+			      (sysarg_t)mapping, PAGE_SIZE, SERVICE_MEM_KLOG,
+			      NULL,NULL,NULL);
+	if (res) {
+		printf("Failed to initialize klog memarea\n");
+		_exit(1);
+	}
+	klog = mapping;
+
+	if (ipc_register_irq(IPC_IRQ_KLOG, NULL)) {
+		printf("Error registering for klog service.\n");
+		return 0;
+	}
+
+	async_set_interrupt_received(interrupt_received);
+
+	async_manager();
+
+	return 0;
+}
Index: libc/generic/async.c
===================================================================
--- libc/generic/async.c	(revision e9073f240239cbd48fb09793c7ed5cc32ff493fb)
+++ libc/generic/async.c	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -139,5 +139,7 @@
 
 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
+static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
 static async_client_conn_t client_connection = default_client_connection;
+static async_client_conn_t interrupt_received = default_interrupt_received;
 
 /** Add microseconds to give timeval */
@@ -342,14 +344,7 @@
 	ipc_answer_fast(callid, ENOENT, 0, 0);
 }
-
-/** Function that gets called on interrupt receival
- *
- * This function is defined as a weak symbol - to be redefined in
- * user code.
- */
-void interrupt_received(ipc_call_t *call)
-{
-}
-
+static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
+{
+}
 
 /** Wrapper for client connection thread
@@ -441,5 +436,5 @@
 	switch (IPC_GET_METHOD(*call)) {
 	case IPC_M_INTERRUPT:
-		interrupt_received(call);
+		(*interrupt_received)(callid,call);
 		return;
 	case IPC_M_CONNECT_ME_TO:
@@ -758,2 +753,6 @@
 	client_connection = conn;
 }
+void async_set_interrupt_received(async_client_conn_t conn)
+{
+	interrupt_received = conn;
+}
Index: libc/generic/time.c
===================================================================
--- libc/generic/time.c	(revision e9073f240239cbd48fb09793c7ed5cc32ff493fb)
+++ libc/generic/time.c	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -35,4 +35,5 @@
 #include <atomic.h>
 #include <futex.h>
+#include <ipc/services.h>
 
 #include <sysinfo.h>
@@ -68,5 +69,5 @@
 		/* Get the mapping of kernel clock */
 		res = ipc_call_sync_3(PHONE_NS, IPC_M_AS_AREA_RECV, 
-				      mapping, PAGE_SIZE, 0,
+				      mapping, PAGE_SIZE, SERVICE_MEM_REALTIME,
 				      NULL,&rights,NULL);
 		if (res) {
Index: libc/include/async.h
===================================================================
--- libc/include/async.h	(revision e9073f240239cbd48fb09793c7ed5cc32ff493fb)
+++ libc/include/async.h	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -99,8 +99,6 @@
 void async_destroy_manager(void);
 void async_set_client_connection(async_client_conn_t conn);
+void async_set_interrupt_received(async_client_conn_t conn);
 int _async_init(void);
-
-/* Should be defined by application */
-void interrupt_received(ipc_call_t *call)  __attribute__((weak));
 
 
Index: libc/include/ipc/services.h
===================================================================
--- libc/include/ipc/services.h	(revision e9073f240239cbd48fb09793c7ed5cc32ff493fb)
+++ libc/include/ipc/services.h	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -42,4 +42,5 @@
 /* Memory area to be received from NS */
 #define SERVICE_MEM_REALTIME    1
+#define SERVICE_MEM_KLOG        2
 
 #endif
Index: ns/ns.c
===================================================================
--- ns/ns.c	(revision e9073f240239cbd48fb09793c7ed5cc32ff493fb)
+++ ns/ns.c	(revision 51dbadf3d0373e65b18fe92a7f6eb61e7bde59f6)
@@ -34,4 +34,5 @@
 #include <ipc/ipc.h>
 #include <ipc/ns.h>
+#include <ipc/services.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -77,19 +78,21 @@
 int static ping_phone;
 
-static void get_realtime_as(ipc_callid_t callid, ipc_call_t *call)
-{
-	static void *addr = NULL;
+static void *clockaddr = NULL;
+static void *klogaddr = NULL;
+
+static void get_as(ipc_callid_t callid, ipc_call_t *call, char *name, void **addr)
+{
 	void *ph_addr;
 
-	if (!addr) {
-		ph_addr = (void *)sysinfo_value("clock.faddr");
+	if (!*addr) {
+		ph_addr = (void *)sysinfo_value(name);
 		if (!ph_addr) {
 			ipc_answer_fast(callid, ENOENT, 0, 0);
 			return;
 		}
-		addr = as_get_mappable_page(PAGE_SIZE);
-		map_physmem(ph_addr, addr, 1, AS_AREA_READ | AS_AREA_CACHEABLE);
-	}
-	ipc_answer_fast(callid, 0, (ipcarg_t)addr, AS_AREA_READ);
+		*addr = as_get_mappable_page(PAGE_SIZE);
+		map_physmem(ph_addr, *addr, 1, AS_AREA_READ | AS_AREA_CACHEABLE);
+	}
+	ipc_answer_fast(callid, 0, (ipcarg_t)*addr, AS_AREA_READ);
 }
 
@@ -110,5 +113,14 @@
 		switch (IPC_GET_METHOD(call)) {
 		case IPC_M_AS_AREA_RECV:
-			get_realtime_as(callid, &call);
+			switch (IPC_GET_ARG3(call)) {
+			case SERVICE_MEM_REALTIME:
+				get_as(callid, &call, "clock.faddr", &clockaddr);
+				break;
+			case SERVICE_MEM_KLOG:
+				get_as(callid, &call, "klog.faddr", &klogaddr);
+				break;
+			default:
+				ipc_answer_fast(callid, ENOENT, 0, 0);
+			}
 			continue;
 		case IPC_M_PHONE_HUNGUP:
