Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ HelenOS.config	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -457,4 +457,7 @@
 ! [(CONFIG_HID_IN=generic|CONFIG_HID_IN=serial)&PLATFORM=ia64&MACHINE=i460GX] CONFIG_NS16550 (y/n)
 
+% Support for ARM926 on-chip UART
+! [(CONFIG_HID_OUT=generic|CONFIG_HID_OUT=serial)&PLATFORM=arm32&MACHINE=integratorcp] CONFIG_ARM926_UART (y/n)
+
 % Support for Samsung S3C24XX on-chip UART
 ! [(CONFIG_HID_OUT=generic|CONFIG_HID_OUT=serial)&PLATFORM=arm32&MACHINE=gta02] CONFIG_S3C24XX_UART (y/n)
@@ -482,5 +485,5 @@
 
 % Serial line input module
-! [CONFIG_DSRLNIN=y|(PLATFORM=arm32&MACHINE=gta02)|(PLATFORM=ia64&MACHINE=i460GX&CONFIG_NS16550=y)|(PLATFORM=ia64&MACHINE=ski)|(PLATFORM=sparc64&PROCESSOR=sun4v)] CONFIG_SRLN (y)
+! [CONFIG_DSRLNIN=y|(PLATFORM=arm32&MACHINE=gta02)|(PLATFORM=arm32&MACHINE=integratorcp&CONFIG_ARM926_UART=y)|(PLATFORM=ia64&MACHINE=i460GX&CONFIG_NS16550=y)|(PLATFORM=ia64&MACHINE=ski)|(PLATFORM=sparc64&PROCESSOR=sun4v)] CONFIG_SRLN (y)
 
 % EGA support
@@ -579,7 +582,4 @@
 # USB settings
 
-% USB verbose messages
-! CONFIG_USB_VERBOSE (n/y)
-
 % Start virtual USB host controller
 ! CONFIG_RUN_VIRTUAL_USB_HC (n/y)
Index: abi/include/ipc/ipc.h
===================================================================
--- abi/include/ipc/ipc.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ abi/include/ipc/ipc.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -57,9 +57,6 @@
 #define IPC_CALL_FORWARDED  (1 << 2)
 
-/** Identify connect_me_to answer */
-#define IPC_CALL_CONN_ME_TO  (1 << 3)
-
 /** Interrupt notification */
-#define IPC_CALL_NOTIF  (1 << 4)
+#define IPC_CALL_NOTIF  (1 << 3)
 
 
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ boot/Makefile.common	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -74,5 +74,6 @@
 	$(USPACE_PATH)/srv/locsrv/locsrv \
 	$(USPACE_PATH)/srv/bd/rd/rd \
-	$(USPACE_PATH)/srv/vfs/vfs
+	$(USPACE_PATH)/srv/vfs/vfs \
+	$(USPACE_PATH)/srv/logger/logger
 
 ifeq ($(RDFMT),tmpfs)
@@ -107,4 +108,5 @@
 	$(USPACE_PATH)/srv/fs/cdfs/cdfs \
 	$(USPACE_PATH)/srv/fs/exfat/exfat \
+	$(USPACE_PATH)/srv/fs/udf/udf \
 	$(USPACE_PATH)/srv/fs/ext2fs/ext2fs \
 	$(USPACE_PATH)/srv/fs/ext4fs/ext4fs \
@@ -170,8 +172,8 @@
 	$(USPACE_PATH)/app/killall/killall \
 	$(USPACE_PATH)/app/loc/loc \
+	$(USPACE_PATH)/app/logset/logset \
 	$(USPACE_PATH)/app/mkfat/mkfat \
 	$(USPACE_PATH)/app/mkexfat/mkexfat \
 	$(USPACE_PATH)/app/mkmfs/mkmfs \
-	$(USPACE_PATH)/app/lsusb/lsusb \
 	$(USPACE_PATH)/app/sbi/sbi \
 	$(USPACE_PATH)/app/sportdmp/sportdmp \
@@ -196,4 +198,5 @@
 	$(USPACE_PATH)/app/mkbd/mkbd \
 	$(USPACE_PATH)/app/websrv/websrv \
+	$(USPACE_PATH)/app/date/date \
 	$(USPACE_PATH)/app/vdemo/vdemo
 
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ boot/arch/amd64/Makefile.inc	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -42,4 +42,5 @@
 	char/ps2mouse \
 	char/xtkbd \
+	time/cmos-rtc \
 	bus/usb/ehci\
 	bus/usb/ohci \
Index: boot/arch/arm32/include/main.h
===================================================================
--- boot/arch/arm32/include/main.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ boot/arch/arm32/include/main.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -52,8 +52,8 @@
 
 /** GXemul testarm serial console output register */
-#define TESTARM_SCONS_ADDR 	0x10000000
+#define TESTARM_SCONS_ADDR	0x10000000
 
 /** IntegratorCP serial console output register */
-#define ICP_SCONS_ADDR 		0x16000000
+#define ICP_SCONS_ADDR		0x16000000
 
 extern void bootstrap(void);
Index: boot/arch/ppc32/_link.ld.in
===================================================================
--- boot/arch/ppc32/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ boot/arch/ppc32/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -2,5 +2,5 @@
 
 SECTIONS {
-	. = 0x01000000;
+	. = 0x02000000;
 	.text : {
 		*(BOOTSTRAP);
Index: boot/arch/ppc32/include/arch.h
===================================================================
--- boot/arch/ppc32/include/arch.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ boot/arch/ppc32/include/arch.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -35,5 +35,5 @@
 #define BOOT_OFFSET  0x8000
 
-#define LOADER_ADDRESS  0x01000000
+#define LOADER_ADDRESS  0x02000000
 
 #ifndef __ASM__
Index: boot/arch/ppc32/src/main.c
===================================================================
--- boot/arch/ppc32/src/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ boot/arch/ppc32/src/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -103,4 +103,10 @@
 	}
 	
+	if (top >= (size_t) loader_address_pa) {
+		printf("Inflated components overlap loader area.\n");
+		printf("The boot image is too large. Halting.\n");
+		halt();
+	}
+	
 	void *balloc_base;
 	void *balloc_base_pa;
Index: boot/generic/include/printf.h
===================================================================
--- boot/generic/include/printf.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ boot/generic/include/printf.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -35,15 +35,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: boot/generic/include/printf_verify.h
===================================================================
--- boot/generic/include/printf_verify.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ boot/generic/include/printf_verify.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/** @file
+ */
+
+#ifndef BOOT_PRINTF_VERIFY_H_
+#define BOOT_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: contrib/conf/sparc64-qe
===================================================================
--- contrib/conf/sparc64-qe	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ contrib/conf/sparc64-qe	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+qemu-system-sparc64 $@ -M sun4u -boot d -cdrom image.iso
Index: defaults/amd64/Makefile.config
===================================================================
--- defaults/amd64/Makefile.config	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ defaults/amd64/Makefile.config	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -54,5 +54,5 @@
 
 # Default framebuffer mode
-CONFIG_BFB_MODE = 800x600
+CONFIG_BFB_MODE = 1024x768
 
 # Default framebuffer depth
Index: defaults/ia32/Makefile.config
===================================================================
--- defaults/ia32/Makefile.config	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ defaults/ia32/Makefile.config	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -60,5 +60,5 @@
 
 # Default framebuffer mode
-CONFIG_BFB_MODE = 800x600
+CONFIG_BFB_MODE = 1024x768
 
 # Default framebuffer depth
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -257,4 +257,15 @@
 	generic/src/ipc/ipc.c \
 	generic/src/ipc/sysipc.c \
+	generic/src/ipc/sysipc_ops.c \
+	generic/src/ipc/ops/clnestab.c \
+	generic/src/ipc/ops/conctmeto.c \
+	generic/src/ipc/ops/concttome.c \
+	generic/src/ipc/ops/connclone.c \
+	generic/src/ipc/ops/dataread.c \
+	generic/src/ipc/ops/datawrite.c \
+	generic/src/ipc/ops/debug.c \
+	generic/src/ipc/ops/sharein.c \
+	generic/src/ipc/ops/shareout.c \
+	generic/src/ipc/ops/stchngath.c \
 	generic/src/ipc/ipcrsc.c \
 	generic/src/ipc/irq.c \
Index: kernel/arch/arm32/Makefile.inc
===================================================================
--- kernel/arch/arm32/Makefile.inc	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/arch/arm32/Makefile.inc	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -33,5 +33,5 @@
 ATSIGN = %
 
-GCC_CFLAGS += -march=armv4
+GCC_CFLAGS += -march=armv4 -fno-omit-frame-pointer -mapcs-frame
 
 BITS = 32
Index: kernel/arch/arm32/include/istate.h
===================================================================
--- kernel/arch/arm32/include/istate.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/arch/arm32/include/istate.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -49,4 +49,5 @@
 /** Struct representing CPU state saved when an exception occurs. */
 typedef struct istate {
+	uint32_t dummy;
 	uint32_t spsr;
 	uint32_t sp;
Index: kernel/arch/arm32/src/exc_handler.S
===================================================================
--- kernel/arch/arm32/src/exc_handler.S	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/arch/arm32/src/exc_handler.S	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -130,7 +130,9 @@
 	stmfd r13!, {r2}
 2:
+	sub sp, sp, #4
 .endm
 
 .macro LOAD_REGS_FROM_STACK
+	add sp, sp, #4
 	ldmfd r13!, {r0}
 	msr spsr, r0
Index: kernel/arch/arm32/src/exception.c
===================================================================
--- kernel/arch/arm32/src/exception.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/arch/arm32/src/exception.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -123,5 +123,5 @@
 	
 	asm volatile (
-		"mrc p15, 0, %[control_reg], c1, c1"
+		"mrc p15, 0, %[control_reg], c1, c0"
 		: [control_reg] "=r" (control_reg)
 	);
@@ -131,5 +131,5 @@
 	
 	asm volatile (
-		"mcr p15, 0, %[control_reg], c1, c1"
+		"mcr p15, 0, %[control_reg], c1, c0"
 		:: [control_reg] "r" (control_reg)
 	);
Index: kernel/arch/arm32/src/mach/integratorcp/integratorcp.c
===================================================================
--- kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -38,5 +38,7 @@
 #include <console/chardev.h>
 #include <genarch/drivers/pl050/pl050.h>
+#include <genarch/drivers/arm926_uart/arm926_uart.h>
 #include <genarch/kbrd/kbrd.h>
+#include <genarch/srln/srln.h>
 #include <console/console.h>
 #include <sysinfo/sysinfo.h>
@@ -53,7 +55,15 @@
 #include <print.h>
 
+
 #define SDRAM_SIZE	(sdram[((*(uint32_t *)(ICP_CMCR+ICP_SDRAMCR_OFFSET) & ICP_SDRAM_MASK) >> 2)])
-static icp_hw_map_t icp_hw_map;
-static irq_t icp_timer_irq;
+
+static struct {
+	icp_hw_map_t hw_map;
+	irq_t timer_irq;
+	arm926_uart_t uart;
+} icp;
+
+
+
 struct arm_machine_ops icp_machine_ops = {
 	icp_init,
@@ -70,5 +80,4 @@
 
 static bool hw_map_init_called = false;
-static bool vga_init = false;
 uint32_t sdram[8] = {
 	16777216,	/* 16mb */
@@ -89,12 +98,12 @@
 void icp_vga_init(void)
 {
-	*(uint32_t*)((char *)(icp_hw_map.cmcr)+0x14) = 0xA05F0000;
-	*(uint32_t*)((char *)(icp_hw_map.cmcr)+0x1C) = 0x12C11000;
-	*(uint32_t*)icp_hw_map.vga = 0x3F1F3F9C;
-	*(uint32_t*)((char *)(icp_hw_map.vga) + 0x4) = 0x080B61DF;
-	*(uint32_t*)((char *)(icp_hw_map.vga) + 0x8) = 0x067F3800;
-	*(uint32_t*)((char *)(icp_hw_map.vga) + 0x10) = ICP_FB;
-	*(uint32_t *)((char *)(icp_hw_map.vga) + 0x1C) = 0x182B;
-	*(uint32_t*)((char *)(icp_hw_map.cmcr)+0xC) = 0x33805000;
+	*(uint32_t*)((char *)(icp.hw_map.cmcr)+0x14) = 0xA05F0000;
+	*(uint32_t*)((char *)(icp.hw_map.cmcr)+0x1C) = 0x12C11000;
+	*(uint32_t*)icp.hw_map.vga = 0x3F1F3F9C;
+	*(uint32_t*)((char *)(icp.hw_map.vga) + 0x4) = 0x080B61DF;
+	*(uint32_t*)((char *)(icp.hw_map.vga) + 0x8) = 0x067F3800;
+	*(uint32_t*)((char *)(icp.hw_map.vga) + 0x10) = ICP_FB;
+	*(uint32_t *)((char *)(icp.hw_map.vga) + 0x1C) = 0x182B;
+	*(uint32_t*)((char *)(icp.hw_map.cmcr)+0xC) = 0x33805000;
 	
 }
@@ -103,5 +112,5 @@
 static inline uint32_t icp_irqc_get_sources(void)
 {
-	return *((uint32_t *) icp_hw_map.irqc);
+	return *((uint32_t *) icp.hw_map.irqc);
 }
 
@@ -113,5 +122,5 @@
 static inline void icp_irqc_mask(uint32_t irq)
 {
-	*((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq);
+	*((uint32_t *) icp.hw_map.irqc_mask) = (1 << irq);
 }
 
@@ -123,33 +132,33 @@
 static inline void icp_irqc_unmask(uint32_t irq)
 {
-	*((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq);
-}
-
-/** Initializes icp_hw_map. */
+	*((uint32_t *) icp.hw_map.irqc_unmask) |= (1 << irq);
+}
+
+/** Initializes icp.hw_map. */
 void icp_init(void)
 {
-	icp_hw_map.uart = km_map(ICP_UART, PAGE_SIZE,
-	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
-	icp_hw_map.kbd_ctrl = km_map(ICP_KBD, PAGE_SIZE, PAGE_NOT_CACHEABLE);
-	icp_hw_map.kbd_stat = icp_hw_map.kbd_ctrl + ICP_KBD_STAT;
-	icp_hw_map.kbd_data = icp_hw_map.kbd_ctrl + ICP_KBD_DATA;
-	icp_hw_map.kbd_intstat = icp_hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
-	icp_hw_map.rtc = km_map(ICP_RTC, PAGE_SIZE,
-	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
-	icp_hw_map.rtc1_load = icp_hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
-	icp_hw_map.rtc1_read = icp_hw_map.rtc + ICP_RTC1_READ_OFFSET;
-	icp_hw_map.rtc1_ctl = icp_hw_map.rtc + ICP_RTC1_CTL_OFFSET;
-	icp_hw_map.rtc1_intrclr = icp_hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
-	icp_hw_map.rtc1_bgload = icp_hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
-	icp_hw_map.rtc1_intrstat = icp_hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
-
-	icp_hw_map.irqc = km_map(ICP_IRQC, PAGE_SIZE,
-	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
-	icp_hw_map.irqc_mask = icp_hw_map.irqc + ICP_IRQC_MASK_OFFSET;
-	icp_hw_map.irqc_unmask = icp_hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
-	icp_hw_map.cmcr = km_map(ICP_CMCR, PAGE_SIZE,
-	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
-	icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET;
-	icp_hw_map.vga = km_map(ICP_VGA, PAGE_SIZE,
+	icp.hw_map.uart = km_map(ICP_UART, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp.hw_map.kbd_ctrl = km_map(ICP_KBD, PAGE_SIZE, PAGE_NOT_CACHEABLE);
+	icp.hw_map.kbd_stat = icp.hw_map.kbd_ctrl + ICP_KBD_STAT;
+	icp.hw_map.kbd_data = icp.hw_map.kbd_ctrl + ICP_KBD_DATA;
+	icp.hw_map.kbd_intstat = icp.hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
+	icp.hw_map.rtc = km_map(ICP_RTC, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp.hw_map.rtc1_load = icp.hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
+	icp.hw_map.rtc1_read = icp.hw_map.rtc + ICP_RTC1_READ_OFFSET;
+	icp.hw_map.rtc1_ctl = icp.hw_map.rtc + ICP_RTC1_CTL_OFFSET;
+	icp.hw_map.rtc1_intrclr = icp.hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
+	icp.hw_map.rtc1_bgload = icp.hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
+	icp.hw_map.rtc1_intrstat = icp.hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
+
+	icp.hw_map.irqc = km_map(ICP_IRQC, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp.hw_map.irqc_mask = icp.hw_map.irqc + ICP_IRQC_MASK_OFFSET;
+	icp.hw_map.irqc_unmask = icp.hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
+	icp.hw_map.cmcr = km_map(ICP_CMCR, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp.hw_map.sdramcr = icp.hw_map.cmcr + ICP_SDRAMCR_OFFSET;
+	icp.hw_map.vga = km_map(ICP_VGA, PAGE_SIZE,
 	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 
@@ -164,7 +173,7 @@
 {
 	icp_irqc_mask(ICP_TIMER_IRQ);
-	*((uint32_t*) icp_hw_map.rtc1_load) = frequency;
-	*((uint32_t*) icp_hw_map.rtc1_bgload) = frequency;
-	*((uint32_t*) icp_hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
+	*((uint32_t*) icp.hw_map.rtc1_load) = frequency;
+	*((uint32_t*) icp.hw_map.rtc1_bgload) = frequency;
+	*((uint32_t*) icp.hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
 	icp_irqc_unmask(ICP_TIMER_IRQ);
 }
@@ -172,6 +181,6 @@
 static irq_ownership_t icp_timer_claim(irq_t *irq)
 {
-	if (icp_hw_map.rtc1_intrstat) {
-		*((uint32_t*) icp_hw_map.rtc1_intrclr) = 1;
+	if (icp.hw_map.rtc1_intrstat) {
+		*((uint32_t*) icp.hw_map.rtc1_intrclr) = 1;
 		return IRQ_ACCEPT;
 	} else
@@ -200,11 +209,11 @@
 static void icp_timer_irq_init(void)
 {
-	irq_initialize(&icp_timer_irq);
-	icp_timer_irq.devno = device_assign_devno();
-	icp_timer_irq.inr = ICP_TIMER_IRQ;
-	icp_timer_irq.claim = icp_timer_claim;
-	icp_timer_irq.handler = icp_timer_irq_handler;
-
-	irq_register(&icp_timer_irq);
+	irq_initialize(&icp.timer_irq);
+	icp.timer_irq.devno = device_assign_devno();
+	icp.timer_irq.inr = ICP_TIMER_IRQ;
+	icp.timer_irq.claim = icp_timer_claim;
+	icp.timer_irq.handler = icp_timer_irq_handler;
+
+	irq_register(&icp.timer_irq);
 }
 
@@ -231,5 +240,5 @@
 
 	if (hw_map_init_called) {
-		*size = (sdram[((*(uint32_t *)icp_hw_map.sdramcr &
+		*size = (sdram[((*(uint32_t *)icp.hw_map.sdramcr &
 		    ICP_SDRAM_MASK) >> 2)]);
 	} else {
@@ -286,4 +295,5 @@
 {
 #ifdef CONFIG_FB
+	static bool vga_init = false;
 	if (!vga_init) {
 		icp_vga_init();
@@ -304,4 +314,9 @@
 		stdout_wire(fbdev);
 #endif
+#ifdef CONFIG_ARM926_UART
+	if (arm926_uart_init(&icp.uart, ARM926_UART0_IRQ,
+	    ARM926_UART0_BASE_ADDRESS, sizeof(arm926_uart_regs_t)))
+		stdout_wire(&icp.uart.outdev);
+#endif
 }
 
@@ -310,7 +325,7 @@
 
 	pl050_t *pl050 = malloc(sizeof(pl050_t), FRAME_ATOMIC);
-	pl050->status = (ioport8_t *)icp_hw_map.kbd_stat;
-	pl050->data = (ioport8_t *)icp_hw_map.kbd_data;
-	pl050->ctrl = (ioport8_t *)icp_hw_map.kbd_ctrl;
+	pl050->status = (ioport8_t *)icp.hw_map.kbd_stat;
+	pl050->data = (ioport8_t *)icp.hw_map.kbd_data;
+	pl050->ctrl = (ioport8_t *)icp.hw_map.kbd_ctrl;
 		
 	pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ);
@@ -335,4 +350,13 @@
 	    ICP_KBD);
 
+#ifdef CONFIG_ARM926_UART
+        srln_instance_t *srln_instance = srln_init();
+        if (srln_instance) {
+                indev_t *sink = stdin_wire();
+                indev_t *srln = srln_wire(srln_instance, sink);
+                arm926_uart_input_wire(&icp.uart, srln);
+		icp_irqc_unmask(ARM926_UART0_IRQ);
+        }
+#endif
 }
 
Index: kernel/arch/arm32/src/mm/page_fault.c
===================================================================
--- kernel/arch/arm32/src/mm/page_fault.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/arch/arm32/src/mm/page_fault.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -77,49 +77,4 @@
 }
 
-/** Decides whether the instruction is load/store or not.
- *
- * @param instr Instruction
- *
- * @return true when instruction is load/store, false otherwise
- *
- */
-static inline bool is_load_store_instruction(instruction_t instr)
-{
-	/* load store immediate offset */
-	if (instr.type == 0x2)
-		return true;
-	
-	/* load store register offset */
-	if ((instr.type == 0x3) && (instr.bit4 == 0))
-		return true;
-	
-	/* load store multiple */
-	if (instr.type == 0x4)
-		return true;
-	
-	/* oprocessor load/store */
-	if (instr.type == 0x6)
-		return true;
-	
-	return false;
-}
-
-/** Decides whether the instruction is swap or not.
- *
- * @param instr Instruction
- *
- * @return true when instruction is swap, false otherwise
- */
-static inline bool is_swap_instruction(instruction_t instr)
-{
-	/* swap, swapb instruction */
-	if ((instr.type == 0x0) &&
-	    ((instr.opcode == 0x8) || (instr.opcode == 0xa)) &&
-	    (instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1))
-		return true;
-	
-	return false;
-}
-
 /** Decides whether read or write into memory is requested.
  *
@@ -128,5 +83,5 @@
  *
  * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is
- * 	   requested.
+ *	   requested.
  */
 static pf_access_t get_memory_access_type(uint32_t instr_addr,
@@ -146,23 +101,38 @@
 	}
 
-	/* load store instructions */
-	if (is_load_store_instruction(instr)) {
-		if (instr.access == 1) {
-			return PF_ACCESS_READ;
-		} else {
-			return PF_ACCESS_WRITE;
+	/* See ARM Architecture reference manual ARMv7-A and ARMV7-R edition
+	 * A5.3 (PDF p. 206) */
+	static const struct {
+		uint32_t mask;
+		uint32_t value;
+		pf_access_t access;
+	} ls_inst[] = {
+		/* Store word/byte */
+		{ 0x0e100000, 0x04000000, PF_ACCESS_WRITE }, /*STR(B) imm*/
+		{ 0x0e100010, 0x06000000, PF_ACCESS_WRITE }, /*STR(B) reg*/
+		/* Load word/byte */
+		{ 0x0e100000, 0x04100000, PF_ACCESS_READ }, /*LDR(B) imm*/
+		{ 0x0e100010, 0x06100000, PF_ACCESS_READ }, /*LDR(B) reg*/
+		/* Store half-word/dual  A5.2.8 */
+		{ 0x0e1000b0, 0x000000b0, PF_ACCESS_WRITE }, /*STRH imm reg*/
+		/* Load half-word/dual A5.2.8 */
+		{ 0x0e0000f0, 0x000000d0, PF_ACCESS_READ }, /*LDRH imm reg*/
+		{ 0x0e1000b0, 0x001000b0, PF_ACCESS_READ }, /*LDRH imm reg*/
+		/* Block data transfer, Store */
+		{ 0x0e100000, 0x08000000, PF_ACCESS_WRITE }, /* STM variants */
+		{ 0x0e100000, 0x08100000, PF_ACCESS_READ },  /* LDM variants */
+		/* Swap */
+		{ 0x0fb00000, 0x01000000, PF_ACCESS_WRITE },
+	};
+	const uint32_t inst = *(uint32_t*)instr_addr;
+	for (unsigned i = 0; i < sizeof(ls_inst) / sizeof(ls_inst[0]); ++i) {
+		if ((inst & ls_inst[i].mask) == ls_inst[i].value) {
+			return ls_inst[i].access;
 		}
-	}
-
-	/* swap, swpb instruction */
-	if (is_swap_instruction(instr)) {
-		return PF_ACCESS_WRITE;
 	}
 
 	panic("page_fault - instruction doesn't access memory "
 	    "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
-	    instr_union.pc, (void *) badvaddr);
-
-	return PF_ACCESS_EXEC;
+	    inst, (void *) badvaddr);
 }
 
Index: kernel/genarch/Makefile.inc
===================================================================
--- kernel/genarch/Makefile.inc	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/genarch/Makefile.inc	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -91,4 +91,9 @@
 endif
 
+ifeq ($(CONFIG_ARM926_UART),y)
+	GENARCH_SOURCES += \
+		genarch/src/drivers/arm926_uart/arm926_uart.c
+endif
+
 ifeq ($(CONFIG_S3C24XX_IRQC),y)
 	GENARCH_SOURCES += \
Index: kernel/genarch/include/drivers/arm926_uart/arm926_uart.h
===================================================================
--- kernel/genarch/include/drivers/arm926_uart/arm926_uart.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/genarch/include/drivers/arm926_uart/arm926_uart.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * 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 genarch
+ * @{
+ */
+/**
+ * @file
+ * @brief ARM926 on-chip UART (PrimeCell UART, PL011) driver.
+ */
+
+#ifndef KERN_ARM926_UART_H_
+#define KERN_ARM926_UART_H_
+
+#include <ddi/irq.h>
+#include <console/chardev.h>
+#include <typedefs.h>
+
+
+/** ARM926 User Guide ch. 4.8.5 (p. 106 in the pdf) */
+#define ARM926_UART0_BASE_ADDRESS   0x16000000
+#define ARM926_UART1_BASE_ADDRESS   0x16000000
+
+/** ARM926 User Guide ch. A.1 (p. 124 in the pdf) */
+#define ARM926_UART0_IRQ   1
+#define ARM926_UART1_IRQ   2
+
+/** PrimeCell UART TRM ch. 3.3 (p. 49 in the pdf) */
+typedef struct {
+	/** UART data register */
+	ioport32_t data;
+#define ARM926_UART_DATA_DATA_MASK   0xff
+#define ARM926_UART_DATA_FE_FLAG   (1 <<  7)
+#define ARM926_UART_DATA_PE_FLAG   (1 <<  9)
+#define ARM926_UART_DATA_BE_FLAG   (1 << 10)
+#define ARM926_UART_DATA_OE_FLAG   (1 << 11)
+
+	union {
+		/* Same values that are in upper bits of data register*/
+		const ioport32_t status;
+#define ARM926_UART_STATUS_FE_FLAG   (1 << 0)
+#define ARM926_UART_STATUS_PE_FLAG   (1 << 1)
+#define ARM926_UART_STATUS_BE_FLAG   (1 << 2)
+#define ARM926_UART_STATUS_OE_FLAG   (1 << 3)
+		/* Writing anything clears all errors */
+		ioport32_t error_clear;
+	};
+	uint32_t padd0_[4];
+
+	const ioport32_t flag;
+#define ARM926_UART_FLAG_CTS_FLAG    (1 << 0)
+#define ARM926_UART_FLAG_DSR_FLAG    (1 << 1)
+#define ARM926_UART_FLAG_DCD_FLAG    (1 << 2)
+#define ARM926_UART_FLAG_BUSY_FLAG   (1 << 3)
+#define ARM926_UART_FLAG_RXFE_FLAG   (1 << 4)
+#define ARM926_UART_FLAG_TXFF_FLAG   (1 << 5)
+#define ARM926_UART_FLAG_RXFF_FLAG   (1 << 6)
+#define ARM926_UART_FLAG_TXFE_FLAG   (1 << 7)
+#define ARM926_UART_FLAG_RI_FLAG     (1 << 8)
+	uint32_t padd1_;
+
+	ioport32_t irda_low_power;
+#define ARM926_UART_IRDA_LOW_POWER_MASK   0xff
+
+	ioport32_t int_baud_divisor;
+#define ARM926_UART_INT_BAUD_DIVISOR_MASK   0xffff
+
+	ioport32_t fract_baud_divisor;
+#define ARM926_UART_FRACT_BAUD_DIVISOR_MASK   0x1f
+
+	ioport32_t line_control_high;
+#define ARM926_UART_CONTROLHI_BRK_FLAG    (1 << 0)
+#define ARM926_UART_CONTROLHI_PEN_FLAG    (1 << 1)
+#define ARM926_UART_CONTROLHI_EPS_FLAG    (1 << 2)
+#define ARM926_UART_CONTROLHI_STP2_FLAG   (1 << 3)
+#define ARM926_UART_CONTROLHI_FEN_FLAG    (1 << 4)
+#define ARM926_UART_CONTROLHI_WLEN_MASK   0x3
+#define ARM926_UART_CONTROLHI_WLEN_SHIFT    5
+#define ARM926_UART_CONTROLHI_SPS_FLAG    (1 << 5)
+
+	ioport32_t control;
+#define ARM926_UART_CONTROL_UARTEN_FLAG   (1 << 0)
+#define ARM926_UART_CONTROL_SIREN_FLAG    (1 << 1)
+#define ARM926_UART_CONTROL_SIRLP_FLAG    (1 << 2)
+#define ARM926_UART_CONTROL_LBE_FLAG      (1 << 7)
+#define ARM926_UART_CONTROL_TXE_FLAG      (1 << 8)
+#define ARM926_UART_CONTROL_RXE_FLAG      (1 << 9)
+#define ARM926_UART_CONTROL_DTR_FLAG     (1 << 10)
+#define ARM926_UART_CONTROL_RTS_FLAG     (1 << 11)
+#define ARM926_UART_CONTROL_OUT1_FLAG    (1 << 12)
+#define ARM926_UART_CONTROL_OUT2_FLAG    (1 << 13)
+#define ARM926_UART_CONTROL_RTSE_FLAG    (1 << 14)
+#define ARM926_UART_CONTROL_CTSE_FLAG    (1 << 15)
+
+	ioport32_t interrupt_fifo;
+#define ARM926_UART_INTERRUPTFIFO_TX_MASK   0x7
+#define ARM926_UART_INTERRUPTFIFO_TX_SHIFT    0
+#define ARM926_UART_INTERRUPTFIFO_RX_MASK   0x7
+#define ARM926_UART_INTERRUPTFIFO_RX_SHIFT    3
+
+	/** Interrupt mask register */
+	ioport32_t interrupt_mask;
+	/** Pending interrupts before applying the mask */
+	const ioport32_t raw_interrupt_status;
+	/** Pending interrupts after applying the mask */
+	const ioport32_t masked_interrupt_status;
+	/** Write 1s to clear pending interrupts */
+	ioport32_t interrupt_clear;
+#define ARM926_UART_INTERRUPT_RIM_FLAG    (1 << 0)
+#define ARM926_UART_INTERRUPT_CTSM_FLAG   (1 << 1)
+#define ARM926_UART_INTERRUPT_DCDM_FLAG   (1 << 2)
+#define ARM926_UART_INTERRUPT_DSRM_FLAG   (1 << 3)
+#define ARM926_UART_INTERRUPT_RX_FLAG     (1 << 4)
+#define ARM926_UART_INTERRUPT_TX_FLAG     (1 << 5)
+#define ARM926_UART_INTERRUPT_RT_FLAG     (1 << 6)
+#define ARM926_UART_INTERRUPT_FE_FLAG     (1 << 7)
+#define ARM926_UART_INTERRUPT_PE_FLAG     (1 << 8)
+#define ARM926_UART_INTERRUPT_BE_FLAG     (1 << 9)
+#define ARM926_UART_INTERRUPT_OE_FLAG    (1 << 10)
+#define ARM926_UART_INTERRUPT_ALL           0x3ff
+
+	ioport32_t dma_control;
+#define ARM926_UART_DMACONTROL_RXDMAEN_FLAG    (1 << 0)
+#define ARM926_UART_DMACONTROL_TXDMAEN_FLAG    (1 << 1)
+#define ARM926_UART_DMACONTROL_DMAONERR_FLAG   (1 << 2)
+
+	// TODO There is some reserved space here followed by
+	// peripheral identification registers.
+} arm926_uart_regs_t;
+
+typedef struct {
+	arm926_uart_regs_t *regs;
+	indev_t *indev;
+	outdev_t outdev;
+	irq_t irq;
+} arm926_uart_t;
+
+bool arm926_uart_init(arm926_uart_t *, inr_t, uintptr_t, size_t);
+void arm926_uart_input_wire(arm926_uart_t *, indev_t *);
+
+#endif
+/**
+ * @}
+ */
Index: kernel/genarch/include/multiboot/multiboot.h
===================================================================
--- kernel/genarch/include/multiboot/multiboot.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/genarch/include/multiboot/multiboot.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -99,4 +99,5 @@
 
 extern void multiboot_extract_command(char *, size_t, const char *);
+extern void multiboot_extract_argument(char *, size_t, const char *);
 extern void multiboot_info_parse(uint32_t, const multiboot_info_t *);
 
Index: kernel/genarch/src/drivers/arm926_uart/arm926_uart.c
===================================================================
--- kernel/genarch/src/drivers/arm926_uart/arm926_uart.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/genarch/src/drivers/arm926_uart/arm926_uart.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * 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 genarch
+ * @{
+ */
+/**
+ * @file
+ * @brief ARM926 on-chip UART (PrimeCell UART, PL011) driver.
+ */
+
+#include <genarch/drivers/arm926_uart/arm926_uart.h>
+#include <console/chardev.h>
+#include <console/console.h>
+#include <ddi/device.h>
+#include <arch/asm.h>
+#include <mm/slab.h>
+#include <mm/page.h>
+#include <mm/km.h>
+#include <sysinfo/sysinfo.h>
+#include <str.h>
+
+static void arm926_uart_sendb(arm926_uart_t *uart, uint8_t byte)
+{
+	/* Wait for space becoming available in Tx FIFO. */
+	// TODO make pio_read accept consts pointers and remove the cast
+	while ((pio_read_32((ioport32_t*)&uart->regs->flag) & ARM926_UART_FLAG_TXFF_FLAG) != 0)
+		;
+
+	pio_write_32(&uart->regs->data, byte);
+}
+
+static void arm926_uart_putchar(outdev_t *dev, wchar_t ch)
+{
+	arm926_uart_t *uart = dev->data;
+
+	if (!ascii_check(ch)) {
+		arm926_uart_sendb(uart, U_SPECIAL);
+	} else {
+		if (ch == '\n')
+			arm926_uart_sendb(uart, (uint8_t) '\r');
+		arm926_uart_sendb(uart, (uint8_t) ch);
+	}
+}
+
+static outdev_operations_t arm926_uart_ops = {
+	.write = arm926_uart_putchar,
+	.redraw = NULL,
+};
+
+static irq_ownership_t arm926_uart_claim(irq_t *irq)
+{
+	return IRQ_ACCEPT;
+}
+
+static void arm926_uart_irq_handler(irq_t *irq)
+{
+	arm926_uart_t *uart = irq->instance;
+
+	// TODO make pio_read accept const pointers and remove the cast
+	while ((pio_read_32((ioport32_t*)&uart->regs->flag) & ARM926_UART_FLAG_RXFE_FLAG) == 0) {
+		/* We ignore all error flags here */
+		const uint8_t data = pio_read_32(&uart->regs->data);
+		if (uart->indev)
+			indev_push_character(uart->indev, data);
+	}
+	/* Ack interrupts */
+	pio_write_32(&uart->regs->interrupt_clear, ARM926_UART_INTERRUPT_ALL);
+}
+
+bool arm926_uart_init(
+    arm926_uart_t *uart, inr_t interrupt, uintptr_t addr, size_t size)
+{
+	ASSERT(uart);
+	uart->regs = (void*)km_map(addr, size, PAGE_NOT_CACHEABLE);
+
+	ASSERT(uart->regs);
+
+	/* Enable hw flow control */
+	uart->regs->control = 0 |
+	    ARM926_UART_CONTROL_UARTEN_FLAG |
+	    ARM926_UART_CONTROL_RTSE_FLAG |
+	    ARM926_UART_CONTROL_CTSE_FLAG;
+
+	/* Mask all interrupts */
+	uart->regs->interrupt_mask = 0;
+
+	outdev_initialize("arm926_uart_dev", &uart->outdev, &arm926_uart_ops);
+	uart->outdev.data = uart;
+
+	/* Initialize IRQ */
+	irq_initialize(&uart->irq);
+        uart->irq.devno = device_assign_devno();
+        uart->irq.inr = interrupt;
+        uart->irq.claim = arm926_uart_claim;
+        uart->irq.handler = arm926_uart_irq_handler;
+        uart->irq.instance = uart;
+
+	return true;
+}
+
+void arm926_uart_input_wire(arm926_uart_t *uart, indev_t *indev)
+{
+	ASSERT(uart);
+	ASSERT(indev);
+
+	uart->indev = indev;
+	irq_register(&uart->irq);
+	/* Enable receive interrupt */
+	uart->regs->interrupt_mask |= ARM926_UART_INTERRUPT_RX_FLAG;
+}
+
+/** @}
+ */
+
Index: kernel/genarch/src/multiboot/multiboot.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/genarch/src/multiboot/multiboot.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -71,4 +71,33 @@
 }
 
+/** Extract arguments from the multiboot module command line.
+ *
+ * @param buf      Destination buffer (will be always NULL-terminated).
+ * @param size     Size of destination buffer (in bytes).
+ * @param cmd_line Input string (the command line).
+ *
+ */
+void multiboot_extract_argument(char *buf, size_t size, const char *cmd_line)
+{
+	/* Start after first space. */
+	const char *start = str_chr(cmd_line, ' ');
+	if (start == NULL) {
+		str_cpy(buf, size, "");
+		return;
+	}
+
+	const char *end = cmd_line + str_size(cmd_line);
+
+	/* Skip the space(s). */
+	while (start != end) {
+		if (start[0] == ' ')
+			start++;
+		else
+			break;
+	}
+
+	str_ncpy(buf, size, start, (size_t) (end - start));
+}
+
 static void multiboot_modules(uint32_t count, multiboot_module_t *mods)
 {
@@ -84,6 +113,10 @@
 			multiboot_extract_command(init.tasks[init.cnt].name,
 			    CONFIG_TASK_NAME_BUFLEN, MULTIBOOT_PTR(mods[i].string));
-		} else
+			multiboot_extract_argument(init.tasks[init.cnt].arguments,
+			    CONFIG_TASK_ARGUMENTS_BUFLEN, MULTIBOOT_PTR(mods[i].string));
+		} else {
 			init.tasks[init.cnt].name[0] = 0;
+			init.tasks[init.cnt].arguments[0] = 0;
+		}
 		
 		init.cnt++;
Index: kernel/genarch/src/multiboot/multiboot2.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot2.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/genarch/src/multiboot/multiboot2.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -49,4 +49,6 @@
 		multiboot_extract_command(init.tasks[init.cnt].name,
 		    CONFIG_TASK_NAME_BUFLEN, module->string);
+		multiboot_extract_argument(init.tasks[init.cnt].arguments,
+		    CONFIG_TASK_ARGUMENTS_BUFLEN, module->string);
 		
 		init.cnt++;
Index: kernel/generic/include/config.h
===================================================================
--- kernel/generic/include/config.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/include/config.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/include/interrupt.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/include/ipc/ipc.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/include/ipc/ipcrsc.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/include/ipc/sysipc_ops.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/include/ipc/sysipc_priv.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/include/lib/elf_load.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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/print.h
===================================================================
--- kernel/generic/include/print.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/include/print.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/include/printf/verify.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/include/proc/task.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -91,8 +91,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
Index: kernel/generic/src/ipc/event.c
===================================================================
--- kernel/generic/src/ipc/event.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/src/ipc/event.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -163,9 +163,13 @@
 				call->data.task_id = TASK ? TASK->taskid : 0;
 				
-				irq_spinlock_lock(&event->answerbox->irq_lock, true);
-				list_append(&call->link, &event->answerbox->irq_notifs);
-				irq_spinlock_unlock(&event->answerbox->irq_lock, true);
-				
-				waitq_wakeup(&event->answerbox->wq, WAKEUP_FIRST);
+				irq_spinlock_lock(&event->answerbox->irq_lock,
+				    true);
+				list_append(&call->ab_link,
+				    &event->answerbox->irq_notifs);
+				irq_spinlock_unlock(&event->answerbox->irq_lock,
+				    true);
+				
+				waitq_wakeup(&event->answerbox->wq,
+				    WAKEUP_FIRST);
 				
 				if (mask)
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/src/ipc/ipc.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -45,4 +45,6 @@
 #include <ipc/kbox.h>
 #include <ipc/event.h>
+#include <ipc/sysipc_ops.h>
+#include <ipc/sysipc_priv.h>
 #include <errno.h>
 #include <mm/slab.h>
@@ -71,6 +73,23 @@
 {
 	memsetb(call, sizeof(*call), 0);
-	call->sender = TASK;
+	spinlock_initialize(&call->forget_lock, "forget_lock");
+	call->active = false;
+	call->forget = false;
+	call->sender = NULL;
 	call->buffer = NULL;
+}
+
+void ipc_call_hold(call_t *call)
+{
+	atomic_inc(&call->refcnt);
+}
+
+void ipc_call_release(call_t *call)
+{
+	if (atomic_predec(&call->refcnt) == 0) {
+		if (call->buffer)
+			free(call->buffer);
+		slab_free(ipc_call_slab, call);
+	}
 }
 
@@ -83,5 +102,5 @@
  *
  * @return If flags permit it, return NULL, or initialized kernel
- *         call structure.
+ *         call structure with one reference.
  *
  */
@@ -89,6 +108,8 @@
 {
 	call_t *call = slab_alloc(ipc_call_slab, flags);
-	if (call)
+	if (call) {
 		_ipc_call_init(call);
+		ipc_call_hold(call);
+	}
 	
 	return call;
@@ -102,8 +123,5 @@
 void ipc_call_free(call_t *call)
 {
-	/* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
-	if (call->buffer)
-		free(call->buffer);
-	slab_free(ipc_call_slab, call);
+	ipc_call_release(call);
 }
 
@@ -132,18 +150,24 @@
  * @param phone Initialized phone structure.
  * @param box   Initialized answerbox structure.
- *
- */
-void ipc_phone_connect(phone_t *phone, answerbox_t *box)
-{
+ * @return      True if the phone was connected, false otherwise.
+ */
+bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
+{
+	bool active;
+
 	mutex_lock(&phone->lock);
-	
-	phone->state = IPC_PHONE_CONNECTED;
-	phone->callee = box;
-	
 	irq_spinlock_lock(&box->lock, true);
-	list_append(&phone->link, &box->connected_phones);
+
+	active = box->active;
+	if (active) {
+		phone->state = IPC_PHONE_CONNECTED;
+		phone->callee = box;
+		list_append(&phone->link, &box->connected_phones);
+	}
+
 	irq_spinlock_unlock(&box->lock, true);
-	
 	mutex_unlock(&phone->lock);
+
+	return active;
 }
 
@@ -151,9 +175,11 @@
  *
  * @param phone Phone structure to be initialized.
- *
- */
-void ipc_phone_init(phone_t *phone)
+ * @param caller Owning task.
+ *
+ */
+void ipc_phone_init(phone_t *phone, task_t *caller)
 {
 	mutex_initialize(&phone->lock, MUTEX_PASSIVE);
+	phone->caller = caller;
 	phone->callee = NULL;
 	phone->state = IPC_PHONE_FREE;
@@ -167,23 +193,36 @@
  *
  */
-static void _ipc_answer_free_call(call_t *call, bool selflocked)
-{
-	answerbox_t *callerbox = &call->sender->answerbox;
-	bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
-	
+void _ipc_answer_free_call(call_t *call, bool selflocked)
+{
 	/* Count sent answer */
 	irq_spinlock_lock(&TASK->lock, true);
 	TASK->ipc_info.answer_sent++;
 	irq_spinlock_unlock(&TASK->lock, true);
+
+	spinlock_lock(&call->forget_lock);
+	if (call->forget) {
+		/* This is a forgotten call and call->sender is not valid. */
+		spinlock_unlock(&call->forget_lock);
+		ipc_call_free(call);
+		return;
+	} else {
+		/*
+		 * If the call is still active, i.e. it was answered
+		 * in a non-standard way, remove the call from the
+		 * sender's active call list.
+		 */
+		if (call->active) {
+			spinlock_lock(&call->sender->active_calls_lock);
+			list_remove(&call->ta_link);
+			spinlock_unlock(&call->sender->active_calls_lock);
+		}
+	}
+	spinlock_unlock(&call->forget_lock);
+
+	answerbox_t *callerbox = &call->sender->answerbox;
+	bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
 	
 	call->flags |= IPC_CALL_ANSWERED;
 	
-	if (call->flags & IPC_CALL_FORWARDED) {
-		if (call->caller_phone) {
-			/* Demasquerade the caller phone. */
-			call->data.phone = call->caller_phone;
-		}
-	}
-
 	call->data.task_id = TASK->taskid;
 	
@@ -191,5 +230,5 @@
 		irq_spinlock_lock(&callerbox->lock, true);
 	
-	list_append(&call->link, &callerbox->answers);
+	list_append(&call->ab_link, &callerbox->answers);
 	
 	if (do_lock)
@@ -209,9 +248,26 @@
 	/* Remove from active box */
 	irq_spinlock_lock(&box->lock, true);
-	list_remove(&call->link);
+	list_remove(&call->ab_link);
 	irq_spinlock_unlock(&box->lock, true);
 	
 	/* Send back answer */
 	_ipc_answer_free_call(call, false);
+}
+
+static void _ipc_call_actions_internal(phone_t *phone, call_t *call)
+{
+	task_t *caller = phone->caller;
+
+	atomic_inc(&phone->active_calls);
+	call->caller_phone = phone;
+	call->sender = caller;
+
+	call->active = true;
+	spinlock_lock(&caller->active_calls_lock);
+	list_append(&call->ta_link, &caller->active_calls);
+	spinlock_unlock(&caller->active_calls_lock);
+
+	call->data.phone = phone;
+	call->data.task_id = caller->taskid;
 }
 
@@ -228,6 +284,5 @@
 void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
 {
-	call->data.phone = phone;
-	atomic_inc(&phone->active_calls);
+	_ipc_call_actions_internal(phone, call);
 	IPC_SET_RETVAL(call->data, err);
 	_ipc_answer_free_call(call, false);
@@ -243,17 +298,16 @@
 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
 {
+	task_t *caller = phone->caller;
+
 	/* Count sent ipc call */
-	irq_spinlock_lock(&TASK->lock, true);
-	TASK->ipc_info.call_sent++;
-	irq_spinlock_unlock(&TASK->lock, true);
-	
-	if (!(call->flags & IPC_CALL_FORWARDED)) {
-		atomic_inc(&phone->active_calls);
-		call->data.phone = phone;
-		call->data.task_id = TASK->taskid;
-	}
+	irq_spinlock_lock(&caller->lock, true);
+	caller->ipc_info.call_sent++;
+	irq_spinlock_unlock(&caller->lock, true);
+	
+	if (!(call->flags & IPC_CALL_FORWARDED))
+		_ipc_call_actions_internal(phone, call);
 	
 	irq_spinlock_lock(&box->lock, true);
-	list_append(&call->link, &box->calls);
+	list_append(&call->ab_link, &box->calls);
 	irq_spinlock_unlock(&box->lock, true);
 	
@@ -275,8 +329,5 @@
 	if (phone->state != IPC_PHONE_CONNECTED) {
 		mutex_unlock(&phone->lock);
-		if (call->flags & IPC_CALL_FORWARDED) {
-			IPC_SET_RETVAL(call->data, EFORWARD);
-			_ipc_answer_free_call(call, false);
-		} else {
+		if (!(call->flags & IPC_CALL_FORWARDED)) {
 			if (phone->state == IPC_PHONE_HUNGUP)
 				ipc_backsend_err(phone, call, EHANGUP);
@@ -325,4 +376,5 @@
 		call_t *call = ipc_call_alloc(0);
 		IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
+		call->request_method = IPC_M_PHONE_HUNGUP;
 		call->flags |= IPC_CALL_DISCARD_ANSWER;
 		_ipc_call(phone, box, call);
@@ -356,10 +408,8 @@
 	TASK->ipc_info.forwarded++;
 	irq_spinlock_pass(&TASK->lock, &oldbox->lock);
-	list_remove(&call->link);
+	list_remove(&call->ab_link);
 	irq_spinlock_unlock(&oldbox->lock, true);
 	
 	if (mode & IPC_FF_ROUTE_FROM_ME) {
-		if (!call->caller_phone)
-			call->caller_phone = call->data.phone;
 		call->data.phone = newphone;
 		call->data.task_id = TASK->taskid;
@@ -406,6 +456,6 @@
 		
 		request = list_get_instance(list_first(&box->irq_notifs),
-		    call_t, link);
-		list_remove(&request->link);
+		    call_t, ab_link);
+		list_remove(&request->ab_link);
 		
 		irq_spinlock_unlock(&box->irq_lock, false);
@@ -416,7 +466,7 @@
 		/* Handle asynchronous answers */
 		request = list_get_instance(list_first(&box->answers),
-		    call_t, link);
-		list_remove(&request->link);
-		atomic_dec(&request->data.phone->active_calls);
+		    call_t, ab_link);
+		list_remove(&request->ab_link);
+		atomic_dec(&request->caller_phone->active_calls);
 	} else if (!list_empty(&box->calls)) {
 		/* Count received call */
@@ -425,9 +475,9 @@
 		/* Handle requests */
 		request = list_get_instance(list_first(&box->calls),
-		    call_t, link);
-		list_remove(&request->link);
+		    call_t, ab_link);
+		list_remove(&request->ab_link);
 		
 		/* Append request to dispatch queue */
-		list_append(&request->link, &box->dispatched_calls);
+		list_append(&request->ab_link, &box->dispatched_calls);
 	} else {
 		/* This can happen regularly after ipc_cleanup */
@@ -449,19 +499,29 @@
 /** Answer all calls from list with EHANGUP answer.
  *
+ * @param box Answerbox with the list.
  * @param lst Head of the list to be cleaned up.
- *
- */
-void ipc_cleanup_call_list(list_t *lst)
-{
+ */
+void ipc_cleanup_call_list(answerbox_t *box, list_t *lst)
+{
+	irq_spinlock_lock(&box->lock, true);
 	while (!list_empty(lst)) {
-		call_t *call = list_get_instance(list_first(lst), call_t, link);
-		if (call->buffer)
-			free(call->buffer);
-		
-		list_remove(&call->link);
-		
+		call_t *call = list_get_instance(list_first(lst), call_t,
+		    ab_link);
+		
+		list_remove(&call->ab_link);
+
+		irq_spinlock_unlock(&box->lock, true);
+
+		if (lst == &box->calls)
+			SYSIPC_OP(request_process, call, box);
+
+		ipc_data_t old = call->data;
 		IPC_SET_RETVAL(call->data, EHANGUP);
+		answer_preprocess(call, &old);
 		_ipc_answer_free_call(call, true);
-	}
+
+		irq_spinlock_lock(&box->lock, true);
+	}
+	irq_spinlock_unlock(&box->lock, true);
 }
 
@@ -501,5 +561,7 @@
 			mutex_unlock(&phone->lock);
 			irq_spinlock_unlock(&box->lock, true);
-			
+
+			// FIXME: phone can become deallocated at any time now
+
 			/*
 			 * Send one message to the answerbox for each
@@ -509,4 +571,5 @@
 			 */
 			IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
+			call->request_method = IPC_M_PHONE_HUNGUP;
 			call->flags |= IPC_CALL_DISCARD_ANSWER;
 			_ipc_call(phone, box, call);
@@ -529,4 +592,127 @@
 }
 
+static void ipc_forget_all_active_calls(void)
+{
+	call_t *call;
+
+restart:
+	spinlock_lock(&TASK->active_calls_lock);
+	if (list_empty(&TASK->active_calls)) {
+		/*
+		 * We are done, there are no more active calls.
+		 * Nota bene: there may still be answers waiting for pick up.
+		 */
+		spinlock_unlock(&TASK->active_calls_lock);	
+		return;	
+	}
+	
+	call = list_get_instance(list_first(&TASK->active_calls), call_t,
+	    ta_link);
+
+	if (!spinlock_trylock(&call->forget_lock)) {
+		/*
+		 * Avoid deadlock and let async_answer() or
+		 *  _ipc_answer_free_call() win the race to dequeue the first
+		 * call on the list.
+		 */
+		spinlock_unlock(&TASK->active_calls_lock);	
+		goto restart;
+	}
+
+	/*
+	 * Forget the call and donate it to the task which holds up the answer.
+	 */
+
+	call->forget = true;
+	call->sender = NULL;
+	list_remove(&call->ta_link);
+
+	/*
+	 * The call may be freed by _ipc_answer_free_call() before we are done
+	 * with it; to avoid working with a destroyed call_t structure, we
+	 * must hold a reference to it.
+	 */
+	ipc_call_hold(call);
+
+	spinlock_unlock(&call->forget_lock);
+	spinlock_unlock(&TASK->active_calls_lock);
+
+	atomic_dec(&call->caller_phone->active_calls);
+
+	SYSIPC_OP(request_forget, call);
+
+	ipc_call_release(call);
+
+	goto restart;
+}
+
+/** Wait for all answers to asynchronous calls to arrive. */
+static void ipc_wait_for_all_answered_calls(void)
+{
+	call_t *call;
+	size_t i;
+
+restart:
+	/*
+	 * Go through all phones, until they are all free.
+	 * Locking is needed as there may be connection handshakes in progress.
+	 */
+	for (i = 0; i < IPC_MAX_PHONES; i++) {
+		phone_t *phone = &TASK->phones[i];
+
+		mutex_lock(&phone->lock);	
+		if ((phone->state == IPC_PHONE_HUNGUP) &&
+		    (atomic_get(&phone->active_calls) == 0)) {
+			phone->state = IPC_PHONE_FREE;
+			phone->callee = NULL;
+		}
+
+		/*
+		 * We might have had some IPC_PHONE_CONNECTING phones at the
+		 * beginning of ipc_cleanup(). Depending on whether these were
+		 * forgotten or answered, they will eventually enter the
+		 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.
+		 * In the latter case, the other side may slam the open phones
+		 * at any time, in which case we will get an IPC_PHONE_SLAMMED
+		 * phone.
+		 */
+		if ((phone->state == IPC_PHONE_CONNECTED) ||
+		    (phone->state == IPC_PHONE_SLAMMED)) {
+			mutex_unlock(&phone->lock);
+			ipc_phone_hangup(phone);
+			/*
+			 * Now there may be one extra active call, which needs
+			 * to be forgotten.
+			 */
+			ipc_forget_all_active_calls();
+			goto restart;
+		}
+
+		/*
+		 * If the hangup succeeded, it has sent a HANGUP message, the
+		 * IPC is now in HUNGUP state, we wait for the reply to come
+		 */
+		if (phone->state != IPC_PHONE_FREE) {
+			mutex_unlock(&phone->lock);
+			break;
+		}
+
+		mutex_unlock(&phone->lock);
+	}
+		
+	/* Got into cleanup */
+	if (i == IPC_MAX_PHONES)
+		return;
+		
+	call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
+	    SYNCH_FLAGS_NONE);
+	ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
+
+	SYSIPC_OP(answer_process, call);
+
+	ipc_call_free(call);
+	goto restart;
+}
+
 /** Clean up all IPC communication of the current task.
  *
@@ -537,7 +723,16 @@
 void ipc_cleanup(void)
 {
+	/*
+	 * Mark the answerbox as inactive.
+	 *
+	 * The main purpose for doing this is to prevent any pending callback
+	 * connections from getting established beyond this point.
+	 */
+	irq_spinlock_lock(&TASK->answerbox.lock, true);
+	TASK->answerbox.active = false;
+	irq_spinlock_unlock(&TASK->answerbox.lock, true);
+
 	/* Disconnect all our phones ('ipc_phone_hangup') */
-	size_t i;
-	for (i = 0; i < IPC_MAX_PHONES; i++)
+	for (size_t i = 0; i < IPC_MAX_PHONES; i++)
 		ipc_phone_hangup(&TASK->phones[i]);
 	
@@ -557,51 +752,10 @@
 	
 	/* Answer all messages in 'calls' and 'dispatched_calls' queues */
-	irq_spinlock_lock(&TASK->answerbox.lock, true);
-	ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
-	ipc_cleanup_call_list(&TASK->answerbox.calls);
-	irq_spinlock_unlock(&TASK->answerbox.lock, true);
-	
-	/* Wait for all answers to asynchronous calls to arrive */
-	while (true) {
-		/*
-		 * Go through all phones, until they are all FREE
-		 * Locking is not needed, no one else should modify
-		 * it when we are in cleanup
-		 */
-		for (i = 0; i < IPC_MAX_PHONES; i++) {
-			if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
-			    atomic_get(&TASK->phones[i].active_calls) == 0) {
-				TASK->phones[i].state = IPC_PHONE_FREE;
-				TASK->phones[i].callee = NULL;
-			}
-			
-			/*
-			 * Just for sure, we might have had some
-			 * IPC_PHONE_CONNECTING phones
-			 */
-			if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
-				ipc_phone_hangup(&TASK->phones[i]);
-			
-			/*
-			 * If the hangup succeeded, it has sent a HANGUP
-			 * message, the IPC is now in HUNGUP state, we
-			 * wait for the reply to come
-			 */
-			
-			if (TASK->phones[i].state != IPC_PHONE_FREE)
-				break;
-		}
-		
-		/* Got into cleanup */
-		if (i == IPC_MAX_PHONES)
-			break;
-		
-		call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
-		    SYNCH_FLAGS_NONE);
-		ASSERT((call->flags & IPC_CALL_ANSWERED) ||
-		    (call->flags & IPC_CALL_NOTIF));
-		
-		ipc_call_free(call);
-	}
+	ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls);
+	ipc_cleanup_call_list(&TASK->answerbox,
+	    &TASK->answerbox.dispatched_calls);
+
+	ipc_forget_all_active_calls();
+	ipc_wait_for_all_answered_calls();
 }
 
@@ -615,4 +769,38 @@
 	ipc_answerbox_slab = slab_cache_create("answerbox_t",
 	    sizeof(answerbox_t), 0, NULL, NULL, 0);
+}
+
+
+static void ipc_print_call_list(list_t *list)
+{
+	list_foreach(*list, cur) {
+		call_t *call = list_get_instance(cur, call_t, ab_link);
+		
+#ifdef __32_BITS__
+		printf("%10p ", call);
+#endif
+		
+#ifdef __64_BITS__
+		printf("%18p ", call);
+#endif
+		
+		spinlock_lock(&call->forget_lock);
+
+		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
+		    " %-6" PRIun " %-6" PRIun " %-7x",
+		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
+		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
+		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
+		    call->flags);
+
+		if (call->forget) {
+			printf(" ? (call forgotten)\n");
+		} else {
+			printf(" %" PRIu64 " (%s)\n",
+			    call->sender->taskid, call->sender->name);
+		}
+
+		spinlock_unlock(&call->forget_lock);
+	}
 }
 
@@ -688,62 +876,9 @@
 	
 	printf(" --- incomming calls ---\n");
-	list_foreach(task->answerbox.calls, cur) {
-		call_t *call = list_get_instance(cur, call_t, link);
-		
-#ifdef __32_BITS__
-		printf("%10p ", call);
-#endif
-		
-#ifdef __64_BITS__
-		printf("%18p ", call);
-#endif
-		
-		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
-		    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
-		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
-		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
-		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
-		    call->flags, call->sender->taskid, call->sender->name);
-	}
-	
+	ipc_print_call_list(&task->answerbox.calls);
 	printf(" --- dispatched calls ---\n");
-	list_foreach(task->answerbox.dispatched_calls, cur) {
-		call_t *call = list_get_instance(cur, call_t, link);
-		
-#ifdef __32_BITS__
-		printf("%10p ", call);
-#endif
-		
-#ifdef __64_BITS__
-		printf("%18p ", call);
-#endif
-		
-		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
-		    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
-		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
-		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
-		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
-		    call->flags, call->sender->taskid, call->sender->name);
-	}
-	
+	ipc_print_call_list(&task->answerbox.dispatched_calls);
 	printf(" --- incoming answers ---\n");
-	list_foreach(task->answerbox.answers, cur) {
-		call_t *call = list_get_instance(cur, call_t, link);
-		
-#ifdef __32_BITS__
-		printf("%10p ", call);
-#endif
-		
-#ifdef __64_BITS__
-		printf("%18p ", call);
-#endif
-		
-		printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
-		    " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
-		    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
-		    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
-		    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
-		    call->flags, call->sender->taskid, call->sender->name);
-	}
+	ipc_print_call_list(&task->answerbox.answers);
 	
 	irq_spinlock_unlock(&task->answerbox.lock, false);
Index: kernel/generic/src/ipc/ipcrsc.c
===================================================================
--- kernel/generic/src/ipc/ipcrsc.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/src/ipc/ipcrsc.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -132,4 +132,5 @@
 #include <ipc/ipcrsc.h>
 #include <debug.h>
+#include <abi/errno.h>
 
 /** Find call_t * in call table according to callid.
@@ -151,5 +152,5 @@
 	
 	list_foreach(TASK->answerbox.dispatched_calls, lst) {
-		call_t *call = list_get_instance(lst, call_t, link);
+		call_t *call = list_get_instance(lst, call_t, ab_link);
 		if ((sysarg_t) call == callid) {
 			result = call;
@@ -162,4 +163,21 @@
 }
 
+/** Get phone from the current task by ID.
+ *
+ * @param phoneid Phone ID.
+ * @param phone   Place to store pointer to phone.
+ *
+ * @return EOK on success, EINVAL if ID is invalid.
+ *
+ */
+int phone_get(sysarg_t phoneid, phone_t **phone)
+{
+	if (phoneid >= IPC_MAX_PHONES)
+		return EINVAL;
+	
+	*phone = &TASK->phones[phoneid];
+	return EOK;
+}
+
 /** Allocate new phone slot in the specified task.
  *
@@ -176,10 +194,12 @@
 	size_t i;
 	for (i = 0; i < IPC_MAX_PHONES; i++) {
-		if ((task->phones[i].state == IPC_PHONE_HUNGUP) &&
-		    (atomic_get(&task->phones[i].active_calls) == 0))
-			task->phones[i].state = IPC_PHONE_FREE;
+		phone_t *phone = &task->phones[i];
+
+		if ((phone->state == IPC_PHONE_HUNGUP) &&
+		    (atomic_get(&phone->active_calls) == 0))
+			phone->state = IPC_PHONE_FREE;
 		
-		if (task->phones[i].state == IPC_PHONE_FREE) {
-			task->phones[i].state = IPC_PHONE_CONNECTING;
+		if (phone->state == IPC_PHONE_FREE) {
+			phone->state = IPC_PHONE_CONNECTING;
 			break;
 		}
@@ -223,4 +243,5 @@
  * @param phoneid Phone handle to be connected.
  * @param box     Answerbox to which to connect the phone handle.
+ * @return        True if the phone was connected, false otherwise.
  *
  * The procedure _enforces_ that the user first marks the phone
@@ -229,10 +250,10 @@
  *
  */
-void phone_connect(int phoneid, answerbox_t *box)
+bool phone_connect(int phoneid, answerbox_t *box)
 {
 	phone_t *phone = &TASK->phones[phoneid];
 	
 	ASSERT(phone->state == IPC_PHONE_CONNECTING);
-	ipc_phone_connect(phone, box);
+	return ipc_phone_connect(phone, box);
 }
 
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/src/ipc/irq.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -510,5 +510,5 @@
 {
 	irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
-	list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
+	list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs);
 	irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false);
 	
Index: kernel/generic/src/ipc/kbox.c
===================================================================
--- kernel/generic/src/ipc/kbox.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/src/ipc/kbox.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -48,4 +48,12 @@
 {
 	/*
+	 * Not really needed, just to be consistent with the meaning of
+	 * answerbox_t.active.
+	 */
+	irq_spinlock_lock(&TASK->kb.box.lock, true);
+	TASK->kb.box.active = false;
+	irq_spinlock_unlock(&TASK->kb.box.lock, true);
+
+	/*
 	 * Only hold kb.cleanup_lock while setting kb.finished -
 	 * this is enough.
@@ -88,8 +96,6 @@
 	
 	/* Answer all messages in 'calls' and 'dispatched_calls' queues. */
-	irq_spinlock_lock(&TASK->kb.box.lock, true);
-	ipc_cleanup_call_list(&TASK->kb.box.dispatched_calls);
-	ipc_cleanup_call_list(&TASK->kb.box.calls);
-	irq_spinlock_unlock(&TASK->kb.box.lock, true);
+	ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
+	ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
 }
 
@@ -162,5 +168,5 @@
 	while (!done) {
 		call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,
-			SYNCH_FLAGS_NONE);
+		    SYNCH_FLAGS_NONE);
 		
 		if (call == NULL)
@@ -236,5 +242,5 @@
 	
 	/* Connect the newly allocated phone to the kbox */
-	ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
+	(void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
 	
 	if (task->kb.thread != NULL) {
Index: kernel/generic/src/ipc/ops/clnestab.c
===================================================================
--- kernel/generic/src/ipc/ops/clnestab.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/clnestab.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,88 @@
+/*
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <synch/mutex.h>
+#include <abi/errno.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	IPC_SET_ARG5(call->data, (sysarg_t) phone);
+
+	return EOK;	
+}
+
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
+{
+	phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
+
+	mutex_lock(&phone->lock);
+	if (phone->state == IPC_PHONE_CONNECTED) {
+		irq_spinlock_lock(&phone->callee->lock, true);
+		list_remove(&phone->link);
+		phone->state = IPC_PHONE_SLAMMED;
+		irq_spinlock_unlock(&phone->callee->lock, true);
+	}
+	mutex_unlock(&phone->lock);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+
+	if (IPC_GET_RETVAL(answer->data) != EOK) {
+		/*
+		 * The other party on the cloned phone rejected our request
+		 * for connection on the protocol level.  We need to break the
+		 * connection without sending IPC_M_HUNGUP back.
+		 */
+		answer_cleanup(answer, olddata);
+	}
+	
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_clone_establish_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/conctmeto.c
===================================================================
--- kernel/generic/src/ipc/ops/conctmeto.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/conctmeto.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	int newphid = phone_alloc(TASK);
+
+	if (newphid < 0)
+		return ELIMIT;
+		
+	/* Set arg5 for server */
+	IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
+	call->priv = newphid;
+
+	return EOK;
+}
+
+static int request_forget(call_t *call)
+{
+	phone_dealloc(call->priv);
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
+
+	/* If the user accepted call, connect */
+	if (IPC_GET_RETVAL(answer->data) == EOK)
+		(void) ipc_phone_connect(phone, &TASK->answerbox);
+
+	return EOK;
+}
+
+static int answer_process(call_t *answer)
+{
+	if (IPC_GET_RETVAL(answer->data))
+		phone_dealloc(answer->priv);
+	else
+		IPC_SET_ARG5(answer->data, answer->priv);
+	
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_connect_me_to_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/concttome.c
===================================================================
--- kernel/generic/src/ipc/ops/concttome.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/concttome.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static int request_process(call_t *call, answerbox_t *box)
+{
+	int phoneid = phone_alloc(TASK);
+
+	IPC_SET_ARG5(call->data, phoneid);
+	
+	return EOK;
+}
+
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
+{
+	int phoneid = (int) IPC_GET_ARG5(*olddata);
+
+	if (phoneid >= 0)
+		phone_dealloc(phoneid);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	int phoneid = (int) IPC_GET_ARG5(*olddata);
+
+	if (IPC_GET_RETVAL(answer->data) != EOK) {
+		/* The connection was not accepted */
+		answer_cleanup(answer, olddata);
+	} else if (phoneid >= 0) {
+		/* The connection was accepted */
+		if (phone_connect(phoneid, &answer->sender->answerbox)) {
+			/* Set 'phone hash' as arg5 of response */
+			IPC_SET_ARG5(answer->data,
+			    (sysarg_t) &TASK->phones[phoneid]);
+		} else {
+			/* The answerbox is shutting down. */
+			IPC_SET_RETVAL(answer->data, ENOENT);
+			answer_cleanup(answer, olddata);
+		}
+	} else {
+		IPC_SET_RETVAL(answer->data, ELIMIT);
+	}
+
+	return EOK;
+}
+
+
+sysipc_ops_t ipc_m_connect_to_me_ops = {
+	.request_preprocess = null_request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = request_process,
+	.answer_cleanup = answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/connclone.c
===================================================================
--- kernel/generic/src/ipc/ops/connclone.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/connclone.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,144 @@
+/*
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <synch/mutex.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static void phones_lock(phone_t *p1, phone_t *p2)
+{
+	if (p1 < p2) {
+		mutex_lock(&p1->lock);
+		mutex_lock(&p2->lock);
+	} else if (p1 > p2) {
+		mutex_lock(&p2->lock);
+		mutex_lock(&p1->lock);
+	} else
+		mutex_lock(&p1->lock);
+}
+
+static void phones_unlock(phone_t *p1, phone_t *p2)
+{
+	mutex_unlock(&p1->lock);
+	if (p1 != p2)
+		mutex_unlock(&p2->lock);
+}
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	phone_t *cloned_phone;
+
+	if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
+		return ENOENT;
+		
+	phones_lock(cloned_phone, phone);
+		
+	if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
+	    phone->state != IPC_PHONE_CONNECTED) {
+		phones_unlock(cloned_phone, phone);
+		return EINVAL;
+	}
+		
+	/*
+	 * We can be pretty sure now that both tasks exist and we are
+	 * connected to them. As we continue to hold the phone locks,
+	 * we are effectively preventing them from finishing their
+	 * potential cleanup.
+	 *
+	 */
+	int newphid = phone_alloc(phone->callee->task);
+	if (newphid < 0) {
+		phones_unlock(cloned_phone, phone);
+		return ELIMIT;
+	}
+		
+	(void) ipc_phone_connect(&phone->callee->task->phones[newphid],
+	    cloned_phone->callee);
+	phones_unlock(cloned_phone, phone);
+		
+	/* Set the new phone for the callee. */
+	IPC_SET_ARG1(call->data, newphid);
+
+	return EOK;
+}
+
+static int answer_cleanup(call_t *answer, ipc_data_t *olddata)
+{
+	int phoneid = (int) IPC_GET_ARG1(*olddata);
+	phone_t *phone = &TASK->phones[phoneid];
+
+	/*
+	 * In this case, the connection was established at the request
+	 * time and therefore we need to slam the phone.  We don't
+	 * merely hangup as that would result in sending IPC_M_HUNGUP
+	 * to the third party on the other side of the cloned phone.
+	 */
+	mutex_lock(&phone->lock);
+	if (phone->state == IPC_PHONE_CONNECTED) {
+		irq_spinlock_lock(&phone->callee->lock, true);
+		list_remove(&phone->link);
+		phone->state = IPC_PHONE_SLAMMED;
+		irq_spinlock_unlock(&phone->callee->lock, true);
+	}
+	mutex_unlock(&phone->lock);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	if (IPC_GET_RETVAL(answer->data) != EOK) {
+		/*
+		 * The recipient of the cloned phone rejected the offer.
+		 */
+		answer_cleanup(answer, olddata);
+	}
+
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_connection_clone_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/dataread.c
===================================================================
--- kernel/generic/src/ipc/ops/dataread.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/dataread.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,121 @@
+/*
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <mm/slab.h>
+#include <abi/errno.h>
+#include <syscall/copy.h>
+#include <config.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	size_t size = IPC_GET_ARG2(call->data);
+
+	if (size > DATA_XFER_LIMIT) {
+		int flags = IPC_GET_ARG3(call->data);
+
+		if (flags & IPC_XF_RESTRICT)
+			IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
+		else
+			return ELIMIT;
+	}
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	ASSERT(!answer->buffer);
+
+	if (!IPC_GET_RETVAL(answer->data)) {
+		/* The recipient agreed to send data. */
+		uintptr_t src = IPC_GET_ARG1(answer->data);
+		uintptr_t dst = IPC_GET_ARG1(*olddata);
+		size_t max_size = IPC_GET_ARG2(*olddata);
+		size_t size = IPC_GET_ARG2(answer->data);
+
+		if (size && size <= max_size) {
+			/*
+			 * Copy the destination VA so that this piece of
+			 * information is not lost.
+			 */
+			IPC_SET_ARG1(answer->data, dst);
+				
+			answer->buffer = malloc(size, 0);
+			int rc = copy_from_uspace(answer->buffer,
+			    (void *) src, size);
+			if (rc) {
+				IPC_SET_RETVAL(answer->data, rc);
+				/*
+				 * answer->buffer will be cleaned up in
+				 * ipc_call_free().
+				 */
+			}
+		} else if (!size) {
+			IPC_SET_RETVAL(answer->data, EOK);
+		} else {
+			IPC_SET_RETVAL(answer->data, ELIMIT);
+		}
+	}
+
+	return EOK;
+}
+
+static int answer_process(call_t *answer)
+{
+	if (answer->buffer) {
+		uintptr_t dst = IPC_GET_ARG1(answer->data);
+		size_t size = IPC_GET_ARG2(answer->data);
+		int rc;
+
+		rc = copy_to_uspace((void *) dst, answer->buffer, size);
+		if (rc)
+			IPC_SET_RETVAL(answer->data, rc);
+	}
+
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_data_read_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/datawrite.c
===================================================================
--- kernel/generic/src/ipc/ops/datawrite.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/datawrite.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,104 @@
+/*
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <mm/slab.h>
+#include <abi/errno.h>
+#include <syscall/copy.h>
+#include <config.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	uintptr_t src = IPC_GET_ARG1(call->data);
+	size_t size = IPC_GET_ARG2(call->data);
+
+	if (size > DATA_XFER_LIMIT) {
+		int flags = IPC_GET_ARG3(call->data);
+
+		if (flags & IPC_XF_RESTRICT) {
+			size = DATA_XFER_LIMIT;
+			IPC_SET_ARG2(call->data, size);
+		} else
+			return ELIMIT;
+	}
+
+	call->buffer = (uint8_t *) malloc(size, 0);
+	int rc = copy_from_uspace(call->buffer, (void *) src, size);
+	if (rc != 0) {
+		/*
+		 * call->buffer will be cleaned up in ipc_call_free() at the
+		 * latest.
+		 */
+		return rc;
+	}
+		
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	ASSERT(answer->buffer);
+
+	if (!IPC_GET_RETVAL(answer->data)) {
+		/* The recipient agreed to receive data. */
+		uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
+		size_t size = (size_t)IPC_GET_ARG2(answer->data);
+		size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
+			
+		if (size <= max_size) {
+			int rc = copy_to_uspace((void *) dst,
+			    answer->buffer, size);
+			if (rc)
+				IPC_SET_RETVAL(answer->data, rc);
+		} else {
+			IPC_SET_RETVAL(answer->data, ELIMIT);
+		}
+	}
+
+	return EOK;
+}
+
+
+sysipc_ops_t ipc_m_data_write_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/debug.c
===================================================================
--- kernel/generic/src/ipc/ops/debug.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/debug.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008 Jiri Svoboda 
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <udebug/udebug_ipc.h>
+#include <syscall/copy.h>
+#include <abi/errno.h>
+
+static int request_process(call_t *call, answerbox_t *box)
+{
+	return -1;
+}
+
+static int answer_process(call_t *answer)
+{
+	if (answer->buffer) {
+		uintptr_t dst = IPC_GET_ARG1(answer->data);
+		size_t size = IPC_GET_ARG2(answer->data);
+		int rc;
+
+		rc = copy_to_uspace((void *) dst, answer->buffer, size);
+		if (rc)
+			IPC_SET_RETVAL(answer->data, rc);
+	}
+
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_debug_ops = {
+#ifdef CONFIG_UDEBUG
+	.request_preprocess = udebug_request_preprocess,
+#else
+	.request_preprocess = null_request_preprocess,
+#endif
+	.request_forget = null_request_forget,
+	.request_process = request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = null_answer_preprocess,
+	.answer_process = answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/sharein.c
===================================================================
--- kernel/generic/src/ipc/ops/sharein.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/sharein.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,71 @@
+/*
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <mm/as.h>
+#include <synch/spinlock.h>
+#include <proc/task.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	if (!IPC_GET_RETVAL(answer->data)) {
+		irq_spinlock_lock(&answer->sender->lock, true);
+		as_t *as = answer->sender->as;
+		irq_spinlock_unlock(&answer->sender->lock, true);
+			
+		uintptr_t dst_base = (uintptr_t) -1;
+		int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
+		    IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
+		    &dst_base, IPC_GET_ARG3(answer->data));
+		IPC_SET_ARG4(answer->data, dst_base);
+		IPC_SET_RETVAL(answer->data, rc);
+	}
+	
+	return EOK;
+}
+
+sysipc_ops_t ipc_m_share_in_ops = {
+	.request_preprocess = null_request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/shareout.c
===================================================================
--- kernel/generic/src/ipc/ops/shareout.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/shareout.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,92 @@
+/*
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <mm/as.h>
+#include <synch/spinlock.h>
+#include <proc/task.h>
+#include <syscall/copy.h>
+#include <abi/errno.h>
+#include <arch.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
+
+	if (!size)
+		return EPERM;
+	IPC_SET_ARG2(call->data, size);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	int rc = EOK;
+
+	if (!IPC_GET_RETVAL(answer->data)) {
+		/* Accepted, handle as_area receipt */
+
+		irq_spinlock_lock(&answer->sender->lock, true);
+		as_t *as = answer->sender->as;
+		irq_spinlock_unlock(&answer->sender->lock, true);
+
+		uintptr_t dst_base = (uintptr_t) -1;
+		rc = as_area_share(as, IPC_GET_ARG1(*olddata),
+		    IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
+		    &dst_base, IPC_GET_ARG1(answer->data));
+			
+		if (rc == EOK) {
+			rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
+			    &dst_base, sizeof(dst_base));
+		}
+			
+		IPC_SET_RETVAL(answer->data, rc);
+	}
+
+	return rc;
+}
+
+sysipc_ops_t ipc_m_share_out_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/ops/stchngath.c
===================================================================
--- kernel/generic/src/ipc/ops/stchngath.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/ops/stchngath.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,128 @@
+/*
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <synch/mutex.h>
+#include <proc/task.h>
+#include <abi/errno.h>
+#include <macros.h>
+
+static int request_preprocess(call_t *call, phone_t *phone)
+{
+	phone_t *sender_phone;
+	task_t *other_task_s;
+
+	if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
+		return ENOENT;
+
+	mutex_lock(&sender_phone->lock);
+	if (sender_phone->state != IPC_PHONE_CONNECTED) {
+		mutex_unlock(&sender_phone->lock);
+		return EINVAL;
+	}
+
+	other_task_s = sender_phone->callee->task;
+
+	mutex_unlock(&sender_phone->lock);
+
+	/* Remember the third party task hash. */
+	IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
+
+	return EOK;
+}
+
+static int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	int rc = EOK;
+
+	if (!IPC_GET_RETVAL(answer->data)) {
+		/* The recipient authorized the change of state. */
+		phone_t *recipient_phone;
+		task_t *other_task_s;
+		task_t *other_task_r;
+
+		rc = phone_get(IPC_GET_ARG1(answer->data),
+		    &recipient_phone);
+		if (rc != EOK) {
+			IPC_SET_RETVAL(answer->data, ENOENT);
+			return ENOENT;
+		}
+
+		mutex_lock(&recipient_phone->lock);
+		if (recipient_phone->state != IPC_PHONE_CONNECTED) {
+			mutex_unlock(&recipient_phone->lock);
+			IPC_SET_RETVAL(answer->data, EINVAL);
+			return EINVAL;
+		}
+
+		other_task_r = recipient_phone->callee->task;
+		other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
+
+		/*
+		 * See if both the sender and the recipient meant the
+		 * same third party task.
+		 */
+		if (other_task_r != other_task_s) {
+			IPC_SET_RETVAL(answer->data, EINVAL);
+			rc = EINVAL;
+		} else {
+			rc = event_task_notify_5(other_task_r,
+			    EVENT_TASK_STATE_CHANGE, false,
+			    IPC_GET_ARG1(*olddata),
+			    IPC_GET_ARG2(*olddata),
+			    IPC_GET_ARG3(*olddata),
+			    LOWER32(olddata->task_id),
+			    UPPER32(olddata->task_id));
+			IPC_SET_RETVAL(answer->data, rc);
+		}
+
+		mutex_unlock(&recipient_phone->lock);
+	}
+
+	return rc;
+}
+
+sysipc_ops_t ipc_m_state_change_authorize_ops = {
+	.request_preprocess = request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+/** @}
+ */
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/src/ipc/sysipc.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -34,12 +34,11 @@
 
 #include <arch.h>
-#include <proc/task.h>
-#include <proc/thread.h>
 #include <errno.h>
 #include <memstr.h>
-#include <debug.h>
 #include <ipc/ipc.h>
 #include <abi/ipc/methods.h>
 #include <ipc/sysipc.h>
+#include <ipc/sysipc_ops.h>
+#include <ipc/sysipc_priv.h>
 #include <ipc/irq.h>
 #include <ipc/ipcrsc.h>
@@ -47,37 +46,12 @@
 #include <ipc/kbox.h>
 #include <synch/waitq.h>
-#include <udebug/udebug_ipc.h>
 #include <arch/interrupt.h>
 #include <syscall/copy.h>
 #include <security/cap.h>
 #include <console/console.h>
-#include <mm/as.h>
 #include <print.h>
 #include <macros.h>
 
-/**
- * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
- * requests.
- */
-#define DATA_XFER_LIMIT  (64 * 1024)
-
 #define STRUCT_TO_USPACE(dst, src)  copy_to_uspace((dst), (src), sizeof(*(src)))
-
-/** Get phone from the current task by ID.
- *
- * @param phoneid Phone ID.
- * @param phone   Place to store pointer to phone.
- *
- * @return EOK on success, EINVAL if ID is invalid.
- *
- */
-static int phone_get(sysarg_t phoneid, phone_t **phone)
-{
-	if (phoneid >= IPC_MAX_PHONES)
-		return EINVAL;
-	
-	*phone = &TASK->phones[phoneid];
-	return EOK;
-}
 
 /** Decide if the interface and method is a system method.
@@ -181,235 +155,59 @@
  * @param olddata Saved data of the request.
  *
- * @return Return 0 on success or an error code.
- *
- */
-static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
-{
+ * @return Return EOK on success or a negative error code.
+ *
+ */
+int answer_preprocess(call_t *answer, ipc_data_t *olddata)
+{
+	int rc = EOK;
+
+	spinlock_lock(&answer->forget_lock);
+	if (answer->forget) {
+		/*
+		 * This is a forgotten call and answer->sender is not valid.
+		 */
+		spinlock_unlock(&answer->forget_lock);
+
+		SYSIPC_OP(answer_cleanup, answer, olddata);
+		return rc;
+	} else {
+		ASSERT(answer->active);
+
+		/*
+		 * Mark the call as inactive to prevent _ipc_answer_free_call()
+		 * from attempting to remove the call from the active list
+		 * itself.
+		 */
+		answer->active = false;
+
+		/*
+		 * Remove the call from the sender's active call list.
+		 * We enforce this locking order so that any potential
+		 * concurrently executing forget operation is forced to
+		 * release its active_calls_lock and lose the race to
+		 * forget this soon to be answered call. 
+		 */
+		spinlock_lock(&answer->sender->active_calls_lock);
+		list_remove(&answer->ta_link);
+		spinlock_unlock(&answer->sender->active_calls_lock);
+	}
+	spinlock_unlock(&answer->forget_lock);
+
 	if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
-		/* In case of forward, hangup the forwared phone,
-		 * not the originator
-		 */
-		mutex_lock(&answer->data.phone->lock);
-		irq_spinlock_lock(&TASK->answerbox.lock, true);
-		if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
-			list_remove(&answer->data.phone->link);
-			answer->data.phone->state = IPC_PHONE_SLAMMED;
+		phone_t *phone = answer->caller_phone;
+		mutex_lock(&phone->lock);
+		if (phone->state == IPC_PHONE_CONNECTED) {
+			irq_spinlock_lock(&phone->callee->lock, true);
+			list_remove(&phone->link);
+			phone->state = IPC_PHONE_SLAMMED;
+			irq_spinlock_unlock(&phone->callee->lock, true);
 		}
-		irq_spinlock_unlock(&TASK->answerbox.lock, true);
-		mutex_unlock(&answer->data.phone->lock);
+		mutex_unlock(&phone->lock);
 	}
 	
 	if (!olddata)
-		return 0;
-	
-	if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
-		int phoneid = IPC_GET_ARG1(*olddata);
-		phone_t *phone = &TASK->phones[phoneid];
-		
-		if (IPC_GET_RETVAL(answer->data) != EOK) {
-			/*
-			 * The recipient of the cloned phone rejected the offer.
-			 * In this case, the connection was established at the
-			 * request time and therefore we need to slam the phone.
-			 * We don't merely hangup as that would result in
-			 * sending IPC_M_HUNGUP to the third party on the
-			 * other side of the cloned phone.
-			 */
-			mutex_lock(&phone->lock);
-			if (phone->state == IPC_PHONE_CONNECTED) {
-				irq_spinlock_lock(&phone->callee->lock, true);
-				list_remove(&phone->link);
-				phone->state = IPC_PHONE_SLAMMED;
-				irq_spinlock_unlock(&phone->callee->lock, true);
-			}
-			mutex_unlock(&phone->lock);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CLONE_ESTABLISH) {
-		phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
-		
-		if (IPC_GET_RETVAL(answer->data) != EOK) {
-			/*
-			 * The other party on the cloned phoned rejected our
-			 * request for connection on the protocol level.
-			 * We need to break the connection without sending
-			 * IPC_M_HUNGUP back.
-			 */
-			mutex_lock(&phone->lock);
-			if (phone->state == IPC_PHONE_CONNECTED) {
-				irq_spinlock_lock(&phone->callee->lock, true);
-				list_remove(&phone->link);
-				phone->state = IPC_PHONE_SLAMMED;
-				irq_spinlock_unlock(&phone->callee->lock, true);
-			}
-			mutex_unlock(&phone->lock);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
-		int phoneid = IPC_GET_ARG5(*olddata);
-		
-		if (IPC_GET_RETVAL(answer->data) != EOK) {
-			/* The connection was not accepted */
-			phone_dealloc(phoneid);
-		} else {
-			/* The connection was accepted */
-			phone_connect(phoneid, &answer->sender->answerbox);
-			/* Set 'phone hash' as arg5 of response */
-			IPC_SET_ARG5(answer->data,
-			    (sysarg_t) &TASK->phones[phoneid]);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
-		/* If the users accepted call, connect */
-		if (IPC_GET_RETVAL(answer->data) == EOK) {
-			ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
-			    &TASK->answerbox);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_OUT) {
-		if (!IPC_GET_RETVAL(answer->data)) {
-			/* Accepted, handle as_area receipt */
-			
-			irq_spinlock_lock(&answer->sender->lock, true);
-			as_t *as = answer->sender->as;
-			irq_spinlock_unlock(&answer->sender->lock, true);
-			
-			uintptr_t dst_base = (uintptr_t) -1;
-			int rc = as_area_share(as, IPC_GET_ARG1(*olddata),
-			    IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
-			    &dst_base, IPC_GET_ARG1(answer->data));
-			
-			if (rc == EOK)
-				rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
-				    &dst_base, sizeof(dst_base));
-			
-			IPC_SET_RETVAL(answer->data, rc);
-			return rc;
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
-		if (!IPC_GET_RETVAL(answer->data)) {
-			irq_spinlock_lock(&answer->sender->lock, true);
-			as_t *as = answer->sender->as;
-			irq_spinlock_unlock(&answer->sender->lock, true);
-			
-			uintptr_t dst_base = (uintptr_t) -1;
-			int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
-			    IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
-			    &dst_base, IPC_GET_ARG3(answer->data));
-			IPC_SET_ARG4(answer->data, dst_base);
-			IPC_SET_RETVAL(answer->data, rc);
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_READ) {
-		ASSERT(!answer->buffer);
-		if (!IPC_GET_RETVAL(answer->data)) {
-			/* The recipient agreed to send data. */
-			uintptr_t src = IPC_GET_ARG1(answer->data);
-			uintptr_t dst = IPC_GET_ARG1(*olddata);
-			size_t max_size = IPC_GET_ARG2(*olddata);
-			size_t size = IPC_GET_ARG2(answer->data);
-			if (size && size <= max_size) {
-				/*
-				 * Copy the destination VA so that this piece of
-				 * information is not lost.
-				 */
-				IPC_SET_ARG1(answer->data, dst);
-				
-				answer->buffer = malloc(size, 0);
-				int rc = copy_from_uspace(answer->buffer,
-				    (void *) src, size);
-				if (rc) {
-					IPC_SET_RETVAL(answer->data, rc);
-					free(answer->buffer);
-					answer->buffer = NULL;
-				}
-			} else if (!size) {
-				IPC_SET_RETVAL(answer->data, EOK);
-			} else {
-				IPC_SET_RETVAL(answer->data, ELIMIT);
-			}
-		}
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_WRITE) {
-		ASSERT(answer->buffer);
-		if (!IPC_GET_RETVAL(answer->data)) {
-			/* The recipient agreed to receive data. */
-			uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
-			size_t size = (size_t)IPC_GET_ARG2(answer->data);
-			size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
-			
-			if (size <= max_size) {
-				int rc = copy_to_uspace((void *) dst,
-				    answer->buffer, size);
-				if (rc)
-					IPC_SET_RETVAL(answer->data, rc);
-			} else {
-				IPC_SET_RETVAL(answer->data, ELIMIT);
-			}
-		}
-		free(answer->buffer);
-		answer->buffer = NULL;
-	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_STATE_CHANGE_AUTHORIZE) {
-		if (!IPC_GET_RETVAL(answer->data)) {
-			/* The recipient authorized the change of state. */
-			phone_t *recipient_phone;
-			task_t *other_task_s;
-			task_t *other_task_r;
-			int rc;
-
-			rc = phone_get(IPC_GET_ARG1(answer->data),
-			    &recipient_phone);
-			if (rc != EOK) {
-				IPC_SET_RETVAL(answer->data, ENOENT);
-				return ENOENT;
-			}
-
-			mutex_lock(&recipient_phone->lock);
-			if (recipient_phone->state != IPC_PHONE_CONNECTED) {
-				mutex_unlock(&recipient_phone->lock);
-				IPC_SET_RETVAL(answer->data, EINVAL);
-				return EINVAL;
-			}
-
-			other_task_r = recipient_phone->callee->task;
-			other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
-
-			/*
-			 * See if both the sender and the recipient meant the
-			 * same third party task.
-			 */
-			if (other_task_r != other_task_s) {
-				IPC_SET_RETVAL(answer->data, EINVAL);
-				rc = EINVAL;
-			} else {
-				rc = event_task_notify_5(other_task_r,
-				    EVENT_TASK_STATE_CHANGE, false,
-				    IPC_GET_ARG1(*olddata),
-				    IPC_GET_ARG2(*olddata),
-				    IPC_GET_ARG3(*olddata),
-				    LOWER32(olddata->task_id),
-				    UPPER32(olddata->task_id));
-				IPC_SET_RETVAL(answer->data, rc);
-			}
-
-			mutex_unlock(&recipient_phone->lock);
-			return rc;
-		}
-	}
-	
-	return 0;
-}
-
-static void phones_lock(phone_t *p1, phone_t *p2)
-{
-	if (p1 < p2) {
-		mutex_lock(&p1->lock);
-		mutex_lock(&p2->lock);
-	} else if (p1 > p2) {
-		mutex_lock(&p2->lock);
-		mutex_lock(&p1->lock);
-	} else
-		mutex_lock(&p1->lock);
-}
-
-static void phones_unlock(phone_t *p1, phone_t *p2)
-{
-	mutex_unlock(&p1->lock);
-	if (p1 != p2)
-		mutex_unlock(&p2->lock);
+		return rc;
+
+	return SYSIPC_OP(answer_preprocess, answer, olddata);
 }
 
@@ -424,124 +222,6 @@
 static int request_preprocess(call_t *call, phone_t *phone)
 {
-	switch (IPC_GET_IMETHOD(call->data)) {
-	case IPC_M_CONNECTION_CLONE: {
-		phone_t *cloned_phone;
-		if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
-			return ENOENT;
-		
-		phones_lock(cloned_phone, phone);
-		
-		if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
-		    phone->state != IPC_PHONE_CONNECTED) {
-			phones_unlock(cloned_phone, phone);
-			return EINVAL;
-		}
-		
-		/*
-		 * We can be pretty sure now that both tasks exist and we are
-		 * connected to them. As we continue to hold the phone locks,
-		 * we are effectively preventing them from finishing their
-		 * potential cleanup.
-		 *
-		 */
-		int newphid = phone_alloc(phone->callee->task);
-		if (newphid < 0) {
-			phones_unlock(cloned_phone, phone);
-			return ELIMIT;
-		}
-		
-		ipc_phone_connect(&phone->callee->task->phones[newphid],
-		    cloned_phone->callee);
-		phones_unlock(cloned_phone, phone);
-		
-		/* Set the new phone for the callee. */
-		IPC_SET_ARG1(call->data, newphid);
-		break;
-	}
-	case IPC_M_CLONE_ESTABLISH:
-		IPC_SET_ARG5(call->data, (sysarg_t) phone);
-		break;
-	case IPC_M_CONNECT_ME_TO: {
-		int newphid = phone_alloc(TASK);
-		if (newphid < 0)
-			return ELIMIT;
-		
-		/* Set arg5 for server */
-		IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
-		call->flags |= IPC_CALL_CONN_ME_TO;
-		call->priv = newphid;
-		break;
-	}
-	case IPC_M_SHARE_OUT: {
-		size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
-		if (!size)
-			return EPERM;
-		
-		IPC_SET_ARG2(call->data, size);
-		break;
-	}
-	case IPC_M_DATA_READ: {
-		size_t size = IPC_GET_ARG2(call->data);
-		if (size > DATA_XFER_LIMIT) {
-			int flags = IPC_GET_ARG3(call->data);
-			if (flags & IPC_XF_RESTRICT)
-				IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
-			else
-				return ELIMIT;
-		}
-		break;
-	}
-	case IPC_M_DATA_WRITE: {
-		uintptr_t src = IPC_GET_ARG1(call->data);
-		size_t size = IPC_GET_ARG2(call->data);
-		
-		if (size > DATA_XFER_LIMIT) {
-			int flags = IPC_GET_ARG3(call->data);
-			if (flags & IPC_XF_RESTRICT) {
-				size = DATA_XFER_LIMIT;
-				IPC_SET_ARG2(call->data, size);
-			} else
-				return ELIMIT;
-		}
-		
-		call->buffer = (uint8_t *) malloc(size, 0);
-		int rc = copy_from_uspace(call->buffer, (void *) src, size);
-		if (rc != 0) {
-			free(call->buffer);
-			return rc;
-		}
-		
-		break;
-	}
-	case IPC_M_STATE_CHANGE_AUTHORIZE: {
-		phone_t *sender_phone;
-		task_t *other_task_s;
-
-		if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
-			return ENOENT;
-
-		mutex_lock(&sender_phone->lock);
-		if (sender_phone->state != IPC_PHONE_CONNECTED) {
-			mutex_unlock(&sender_phone->lock);
-			return EINVAL;
-		}
-
-		other_task_s = sender_phone->callee->task;
-
-		mutex_unlock(&sender_phone->lock);
-
-		/* Remember the third party task hash. */
-		IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
-		break;
-	}
-#ifdef CONFIG_UDEBUG
-	case IPC_M_DEBUG:
-		return udebug_request_preprocess(call, phone);
-#endif
-	default:
-		break;
-	}
-	
-	return 0;
+	call->request_method = IPC_GET_IMETHOD(call->data);
+	return SYSIPC_OP(request_preprocess, call, phone);
 }
 
@@ -561,26 +241,7 @@
 		IPC_SET_RETVAL(call->data, EFORWARD);
 	
-	if (call->flags & IPC_CALL_CONN_ME_TO) {
-		if (IPC_GET_RETVAL(call->data))
-			phone_dealloc(call->priv);
-		else
-			IPC_SET_ARG5(call->data, call->priv);
-	}
-	
-	if (call->buffer) {
-		/*
-		 * This must be an affirmative answer to IPC_M_DATA_READ
-		 * or IPC_M_DEBUG/UDEBUG_M_MEM_READ...
-		 *
-		 */
-		uintptr_t dst = IPC_GET_ARG1(call->data);
-		size_t size = IPC_GET_ARG2(call->data);
-		int rc = copy_to_uspace((void *) dst, call->buffer, size);
-		if (rc)
-			IPC_SET_RETVAL(call->data, rc);
-		free(call->buffer);
-		call->buffer = NULL;
-	}
-}
+	SYSIPC_OP(answer_process, call);
+}
+
 
 /** Do basic kernel processing of received call request.
@@ -595,23 +256,5 @@
 static int process_request(answerbox_t *box, call_t *call)
 {
-	if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME) {
-		int phoneid = phone_alloc(TASK);
-		if (phoneid < 0) {  /* Failed to allocate phone */
-			IPC_SET_RETVAL(call->data, ELIMIT);
-			ipc_answer(box, call);
-			return -1;
-		}
-		
-		IPC_SET_ARG5(call->data, phoneid);
-	}
-	
-	switch (IPC_GET_IMETHOD(call->data)) {
-	case IPC_M_DEBUG:
-		return -1;
-	default:
-		break;
-	}
-	
-	return 0;
+	return SYSIPC_OP(request_process, call, box);
 }
 
@@ -745,21 +388,27 @@
 {
 	call_t *call = get_call(callid);
+	phone_t *phone;
+	bool need_old = answer_need_old(call);
+	bool after_forward = false;
+	ipc_data_t old;
+	int rc;
+
 	if (!call)
 		return ENOENT;
-	
+
+	if (need_old)
+		old = call->data;
+	
+	if (phone_get(phoneid, &phone) != EOK) {
+		rc = ENOENT;
+		goto error;
+	}
+	
+	if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
+		rc = EPERM;
+		goto error;
+	}
+
 	call->flags |= IPC_CALL_FORWARDED;
-	
-	phone_t *phone;
-	if (phone_get(phoneid, &phone) != EOK) {
-		IPC_SET_RETVAL(call->data, EFORWARD);
-		ipc_answer(&TASK->answerbox, call);
-		return ENOENT;
-	}
-	
-	if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
-		IPC_SET_RETVAL(call->data, EFORWARD);
-		ipc_answer(&TASK->answerbox, call);
-		return EPERM;
-	}
 	
 	/*
@@ -797,5 +446,21 @@
 	}
 	
-	return ipc_forward(call, phone, &TASK->answerbox, mode);
+	rc = ipc_forward(call, phone, &TASK->answerbox, mode);
+	if (rc != EOK) {
+		after_forward = true;
+		goto error;
+	}
+
+	return EOK;
+
+error:
+	IPC_SET_RETVAL(call->data, EFORWARD);
+	(void) answer_preprocess(call, need_old ? &old : NULL);
+	if (after_forward)
+		_ipc_answer_free_call(call, false);
+	else
+		ipc_answer(&TASK->answerbox, call);
+
+	return rc;
 }
 
Index: kernel/generic/src/ipc/sysipc_ops.c
===================================================================
--- kernel/generic/src/ipc/sysipc_ops.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ kernel/generic/src/ipc/sysipc_ops.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,112 @@
+/*
+ * 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
+ */
+
+#include <ipc/sysipc_ops.h>
+#include <abi/ipc/methods.h>
+#include <abi/errno.h>
+
+/* Forward declarations. */
+sysipc_ops_t ipc_m_connection_clone_ops;
+sysipc_ops_t ipc_m_clone_establish_ops;
+sysipc_ops_t ipc_m_connect_to_me_ops;
+sysipc_ops_t ipc_m_connect_me_to_ops;
+sysipc_ops_t ipc_m_share_out_ops;
+sysipc_ops_t ipc_m_share_in_ops;
+sysipc_ops_t ipc_m_data_write_ops;
+sysipc_ops_t ipc_m_data_read_ops;
+sysipc_ops_t ipc_m_state_change_authorize_ops;
+sysipc_ops_t ipc_m_debug_ops;
+
+static sysipc_ops_t *sysipc_ops[] = {
+	[IPC_M_CONNECTION_CLONE] = &ipc_m_connection_clone_ops,
+	[IPC_M_CLONE_ESTABLISH] = &ipc_m_clone_establish_ops,
+	[IPC_M_CONNECT_TO_ME] = &ipc_m_connect_to_me_ops,
+	[IPC_M_CONNECT_ME_TO] = &ipc_m_connect_me_to_ops,
+	[IPC_M_SHARE_OUT] = &ipc_m_share_out_ops,
+	[IPC_M_SHARE_IN] = &ipc_m_share_in_ops,
+	[IPC_M_DATA_WRITE] = &ipc_m_data_write_ops,
+	[IPC_M_DATA_READ] = &ipc_m_data_read_ops,
+	[IPC_M_STATE_CHANGE_AUTHORIZE] = &ipc_m_state_change_authorize_ops,
+	[IPC_M_DEBUG] = &ipc_m_debug_ops
+};
+
+static sysipc_ops_t null_ops = {
+	.request_preprocess = null_request_preprocess,
+	.request_forget = null_request_forget,
+	.request_process = null_request_process,
+	.answer_cleanup = null_answer_cleanup,
+	.answer_preprocess = null_answer_preprocess,
+	.answer_process = null_answer_process,
+};
+
+int null_request_preprocess(call_t *call, phone_t *phone)
+{
+	return EOK;
+}
+
+int null_request_forget(call_t *call)
+{
+	return EOK;
+}
+
+int null_request_process(call_t *call, answerbox_t *box)
+{
+	return EOK;
+}
+
+int null_answer_cleanup(call_t *call, ipc_data_t *data)
+{
+	return EOK;
+}
+
+int null_answer_preprocess(call_t *call, ipc_data_t *data)
+{
+	return EOK;
+}
+
+int null_answer_process(call_t *call)
+{
+	return EOK;
+}
+
+sysipc_ops_t *sysipc_ops_get(sysarg_t imethod)
+{
+	if (imethod < sizeof(sysipc_ops) / (sizeof(sysipc_ops_t *)))
+		return sysipc_ops[imethod] ? sysipc_ops[imethod] : &null_ops;
+
+	return &null_ops;
+}
+
+/** @}
+ */
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/src/main/kinit.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -69,4 +69,5 @@
 #include <str.h>
 #include <sysinfo/stats.h>
+#include <sysinfo/sysinfo.h>
 #include <align.h>
 
@@ -179,4 +180,26 @@
 	program_t programs[CONFIG_INIT_TASKS];
 	
+	// FIXME: do not propagate arguments through sysinfo
+	// but pass them directly to the tasks
+	for (i = 0; i < init.cnt; i++) {
+		const char *arguments = init.tasks[i].arguments;
+		if (str_length(arguments) == 0)
+			continue;
+		if (str_length(init.tasks[i].name) == 0)
+			continue;
+		size_t arguments_size = str_size(arguments);
+
+		void *arguments_copy = malloc(arguments_size, 0);
+		if (arguments_copy == NULL)
+			continue;
+		memcpy(arguments_copy, arguments, arguments_size);
+
+		char item_name[CONFIG_TASK_NAME_BUFLEN + 15];
+		snprintf(item_name, CONFIG_TASK_NAME_BUFLEN + 15,
+		    "init_args.%s", init.tasks[i].name);
+
+		sysinfo_set_item_data(item_name, NULL, arguments_copy, arguments_size);
+	}
+
 	for (i = 0; i < init.cnt; i++) {
 		if (init.tasks[i].paddr % FRAME_SIZE) {
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ kernel/generic/src/proc/task.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -161,5 +161,8 @@
 	size_t i;
 	for (i = 0; i < IPC_MAX_PHONES; i++)
-		ipc_phone_init(&task->phones[i]);
+		ipc_phone_init(&task->phones[i], task);
+
+	spinlock_initialize(&task->active_calls_lock, "active_calls_lock");
+	list_initialize(&task->active_calls);
 	
 #ifdef CONFIG_UDEBUG
@@ -203,4 +206,6 @@
 	event_task_init(task);
 	
+	task->answerbox.active = true;
+
 #ifdef CONFIG_UDEBUG
 	/* Init debugging stuff */
@@ -208,4 +213,5 @@
 	
 	/* Init kbox stuff */
+	task->kb.box.active = true;
 	task->kb.finished = false;
 #endif
@@ -213,5 +219,5 @@
 	if ((ipc_phone_0) &&
 	    (container_check(ipc_phone_0->task->container, task->container)))
-		ipc_phone_connect(&task->phones[0], ipc_phone_0);
+		(void) ipc_phone_connect(&task->phones[0], ipc_phone_0);
 	
 	btree_create(&task->futexes);
Index: tools/toolchain.sh
===================================================================
--- tools/toolchain.sh	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ tools/toolchain.sh	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -55,6 +55,6 @@
 BINUTILS_VERSION="2.22"
 BINUTILS_RELEASE=""
-GCC_VERSION="4.7.1"
-GDB_VERSION="7.4"
+GCC_VERSION="4.7.2"
+GDB_VERSION="7.5"
 
 BASEDIR="`pwd`"
@@ -192,4 +192,5 @@
 	echo " - SED, AWK, Flex, Bison, gzip, bzip2, Bourne Shell"
 	echo " - gettext, zlib, Texinfo, libelf, libgomp"
+	echo " - terminfo"
 	echo " - GNU Multiple Precision Library (GMP)"
 	echo " - GNU Make"
@@ -274,6 +275,6 @@
 	
 	download_fetch "${BINUTILS_SOURCE}" "${BINUTILS}" "ee0f10756c84979622b992a4a61ea3f5"
-	download_fetch "${GCC_SOURCE}" "${GCC}" "933e6f15f51c031060af64a9e14149ff"
-	download_fetch "${GDB_SOURCE}" "${GDB}" "95a9a8305fed4d30a30a6dc28ff9d060"
+	download_fetch "${GCC_SOURCE}" "${GCC}" "cc308a0891e778cfda7a151ab8a6e762"
+	download_fetch "${GDB_SOURCE}" "${GDB}" "24a6779a9fe0260667710de1b082ef61"
 }
 
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -48,4 +48,5 @@
 	app/klog \
 	app/loc \
+	app/logset \
 	app/mkfat \
 	app/mkexfat \
@@ -72,4 +73,5 @@
 	app/sysinfo \
 	app/mkbd \
+	app/date \
 	app/websrv \
 	app/vdemo \
@@ -78,4 +80,5 @@
 	srv/clipboard \
 	srv/locsrv \
+	srv/logger \
 	srv/devman \
 	srv/loader \
@@ -96,4 +99,5 @@
 	srv/bd/part/mbr_part \
 	srv/fs/exfat \
+	srv/fs/udf \
 	srv/fs/fat \
 	srv/fs/cdfs \
@@ -133,5 +137,5 @@
 	drv/nic/ne2k \
 	drv/nic/e1k \
-	drv/nic/rtl8139
+	drv/nic/rtl8139 \
 
 ifeq ($(CONFIG_PCC),y)
@@ -162,4 +166,5 @@
 		drv/bus/isa \
 		drv/char/ns8250 \
+		drv/time/cmos-rtc \
 		srv/hw/irc/apic \
 		srv/hw/irc/i8259
@@ -172,4 +177,5 @@
 		drv/bus/isa \
 		drv/char/ns8250 \
+		drv/time/cmos-rtc \
 		srv/hw/irc/apic \
 		srv/hw/irc/i8259
Index: uspace/app/bdsh/errors.h
===================================================================
--- uspace/app/bdsh/errors.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/app/bdsh/errors.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -30,4 +30,6 @@
 #define ERRORS_H
 
+#include <io/verify.h>
+
 /* Various error levels */
 #define CL_EFATAL  -1
@@ -46,5 +48,6 @@
 extern volatile int cli_errno;
 
-extern void cli_error(int, const char *, ...);
+extern void cli_error(int, const char *, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 
 #endif
Index: uspace/app/date/Makefile
===================================================================
--- uspace/app/date/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/date/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2012 Maurizio Lombardi
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = date
+
+SOURCES = \
+	date.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/date/date.c
===================================================================
--- uspace/app/date/date.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/date/date.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 <device/clock_dev.h>
+#include <errno.h>
+#include <loc.h>
+#include <time.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <ctype.h>
+
+#define NAME   "date"
+
+static int read_date_from_arg(char *wdate, struct tm *t);
+static int read_time_from_arg(char *wdate, struct tm *t);
+static int tm_sanity_check(struct tm *t);
+static bool is_leap_year(int year);
+
+static void usage(void);
+
+static int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+int
+main(int argc, char **argv)
+{
+	int rc, c;
+	category_id_t cat_id;
+	size_t        svc_cnt;
+	service_id_t  *svc_ids = NULL;
+	service_id_t  svc_id;
+	char          *svc_name = NULL;
+	bool          read_only = true;
+	char          *wdate = NULL;
+	char          *wtime = NULL;
+	struct tm     t;
+	int           n_args = argc;
+
+	while ((c = getopt(argc, argv, "hd:t:")) != -1) {
+		switch (c) {
+		case 'h':
+			usage();
+			return 0;
+		case 'd':
+			if (wdate) {
+				usage();
+				return 1;
+			}
+			wdate = (char *)optarg;
+			read_only = false;
+			n_args -= 2;
+			break;
+		case 't':
+			if (wtime) {
+				usage();
+				return 1;
+			}
+			wtime = (char *)optarg;
+			read_only = false;
+			n_args -= 2;
+			break;
+		case '?':
+			usage();
+			return 1;
+		}
+	}
+
+	if (n_args != 1) {
+		printf(NAME ": Unrecognized parameter\n");
+		usage();
+		return 1;
+	}
+
+	/* Get the id of the clock category */
+	rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf(NAME ": Cannot get clock category id\n");
+		goto exit;
+	}
+
+	/* Get the list of available services in the clock category */
+	rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
+	if (rc != EOK) {
+		printf(NAME ": Cannot get the list of services in the clock "
+		    "category\n");
+		goto exit;
+	}
+
+	/* Check if there are available services in the clock category */
+	if (svc_cnt == 0) {
+		printf(NAME ": No available service found in "
+		    "the clock category\n");
+		goto exit;
+	}
+
+	/* Get the name of the clock service */
+	rc = loc_service_get_name(svc_ids[0], &svc_name);
+	if (rc != EOK) {
+		printf(NAME ": Cannot get the name of the service\n");
+		goto exit;
+	}
+
+	/* Get the service id for the device */
+	rc = loc_service_get_id(svc_name, &svc_id, 0);
+	if (rc != EOK) {
+		printf(NAME ": Cannot get the service id for device %s",
+		    svc_name);
+		goto exit;
+	}
+
+	/* Connect to the device */
+	async_sess_t *sess = loc_service_connect(EXCHANGE_SERIALIZE,
+	    svc_id, 0);
+	if (!sess) {
+		printf(NAME ": Cannot connect to the device\n");
+		goto exit;
+	}
+
+	/* Read the current date/time */
+	rc = clock_dev_time_get(sess, &t);
+	if (rc != EOK) {
+		printf(NAME ": Cannot read the current time\n");
+		goto exit;
+	}
+
+	if (read_only) {
+		/* Print the current time and exit */
+		printf("%02d/%02d/%d ", t.tm_mday,
+		    t.tm_mon + 1, 1900 + t.tm_year);
+		printf("%02d:%02d:%02d\n", t.tm_hour, t.tm_min, t.tm_sec);
+	} else {
+		if (wdate) {
+			rc = read_date_from_arg(wdate, &t);
+			if (rc != EOK) {
+				printf(NAME ": error, date format not "
+				    "recognized\n");
+				usage();
+				goto exit;
+			}
+		}
+		if (wtime) {
+			rc = read_time_from_arg(wtime, &t);
+			if (rc != EOK) {
+				printf(NAME ": error, time format not "
+				    "recognized\n");
+				usage();
+				goto exit;
+			}
+		}
+
+		rc = tm_sanity_check(&t);
+		if (rc != EOK) {
+			printf(NAME ": error, invalid date/time\n");
+			goto exit;
+		}
+
+		rc = clock_dev_time_set(sess, &t);
+		if (rc != EOK) {
+			printf(NAME ": error, Unable to set date/time\n");
+			goto exit;
+		}
+	}
+
+exit:
+	free(svc_name);
+	free(svc_ids);
+	return rc;
+}
+
+/** Read the day, month and year from a string
+ *  with the following format: DD/MM/YYYY
+ */
+static int
+read_date_from_arg(char *wdate, struct tm *t)
+{
+	int rc;
+	uint32_t tmp;
+
+	if (str_size(wdate) != 10) /* str_size("DD/MM/YYYY") == 10 */
+		return EINVAL;
+
+	if (wdate[2] != '/' ||
+	    wdate[5] != '/') {
+		return EINVAL;
+	}
+
+	rc = str_uint32_t(&wdate[0], NULL, 10, false, &tmp);
+	if (rc != EOK)
+		return rc;
+
+	t->tm_mday = tmp;
+
+	rc = str_uint32_t(&wdate[3], NULL, 10, false, &tmp);
+	if (rc != EOK)
+		return rc;
+
+	t->tm_mon = tmp - 1;
+
+	rc = str_uint32_t(&wdate[6], NULL, 10, false, &tmp);
+	t->tm_year = tmp - 1900;
+
+	return rc;
+}
+
+/** Read the hours, minutes and seconds from a string
+ *  with the following format: HH:MM:SS or HH:MM
+ */
+static int
+read_time_from_arg(char *wtime, struct tm *t)
+{
+	int rc;
+	size_t len = str_size(wtime);
+	bool sec_present = len == 8;
+	uint32_t tmp;
+
+	/* str_size("HH:MM") == 5 */
+	/* str_size("HH:MM:SS") == 8 */
+	if (len != 8 && len != 5)
+		return EINVAL;
+
+	if (sec_present && wtime[5] != ':')
+		return EINVAL;
+
+	if (wtime[2] != ':')
+		return EINVAL;
+
+	rc = str_uint32_t(&wtime[0], NULL, 10, false, &tmp);
+	if (rc != EOK)
+		return rc;
+
+	t->tm_hour = tmp;
+
+	rc = str_uint32_t(&wtime[3], NULL, 10, false, &tmp);
+	if (rc != EOK)
+		return rc;
+
+	t->tm_min = tmp;
+
+	if (sec_present) {
+		rc = str_uint32_t(&wtime[6], NULL, 10, false, &tmp);
+		t->tm_sec = tmp;
+	} else
+		t->tm_sec = 0;
+
+	return rc;
+}
+
+/** Check if the tm structure contains valid values
+ *
+ * @param t     The tm structure to check
+ *
+ * @return      EOK on success or EINVAL
+ */
+static int
+tm_sanity_check(struct tm *t)
+{
+	int ndays;
+
+	if (t->tm_sec < 0 || t->tm_sec > 59)
+		return EINVAL;
+	else if (t->tm_min < 0 || t->tm_min > 59)
+		return EINVAL;
+	else if (t->tm_hour < 0 || t->tm_hour > 23)
+		return EINVAL;
+	else if (t->tm_mday < 1 || t->tm_mday > 31)
+		return EINVAL;
+	else if (t->tm_mon < 0 || t->tm_mon > 11)
+		return EINVAL;
+	else if (t->tm_year < 0 || t->tm_year > 199)
+		return EINVAL;
+
+	if (t->tm_mon == 1/* FEB */ && is_leap_year(t->tm_year))
+		ndays = 29;
+	else
+		ndays = days_month[t->tm_mon];
+
+	if (t->tm_mday > ndays)
+		return EINVAL;
+
+	return EOK;
+}
+
+/** Check if a year is a leap year
+ *
+ * @param year   The year to check
+ *
+ * @return       true if it is a leap year, false otherwise
+ */
+static bool
+is_leap_year(int year)
+{
+	bool r = false;
+
+	if (year % 4 == 0) {
+		if (year % 100 == 0)
+			r = year % 400 == 0;
+		else
+			r = true;
+	}
+
+	return r;
+}
+
+static void
+usage(void)
+{
+	printf("Usage: date [-d DD/MM/YYYY] [-t HH:MM[:SS]]\n");
+	printf("       -d   Change the current date\n");
+	printf("       -t   Change the current time\n");
+	printf("       -h   Display this information\n");
+}
+
Index: uspace/app/devctl/devctl.c
===================================================================
--- uspace/app/devctl/devctl.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/app/devctl/devctl.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -151,5 +151,6 @@
 	rc = devman_fun_offline(funh);
 	if (rc != EOK) {
-		printf(NAME ": Failed to offline function '%s'.\n", path);
+		printf(NAME ": Failed to offline function '%s' (%s)\n", path,
+		    str_error(rc));
 		return rc;
 	}
Index: uspace/app/logset/Makefile
===================================================================
--- uspace/app/logset/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/logset/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2012 Vojtech Horky
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = logset
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/logset/main.c
===================================================================
--- uspace/app/logset/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/logset/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logset
+ * @{
+ */
+/** @file Change logger behavior.
+ */
+#include <stdio.h>
+#include <async.h>
+#include <errno.h>
+#include <str_error.h>
+#include <io/logctl.h>
+
+static log_level_t parse_log_level_or_die(const char *log_level)
+{
+	log_level_t result;
+	int rc = log_level_from_str(log_level, &result);
+	if (rc != EOK) {
+		fprintf(stderr, "Unrecognised log level '%s': %s.\n",
+		    log_level, str_error(rc));
+		exit(2);
+	}
+	return result;
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr, "Usage:\n");
+	fprintf(stderr, "  %s <default-logging-level>\n", progname);
+	fprintf(stderr, "  %s <log-name> <logging-level>\n", progname);
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc == 2) {
+		log_level_t new_default_level = parse_log_level_or_die(argv[1]);
+		int rc = logctl_set_default_level(new_default_level);
+
+		if (rc != EOK) {
+			fprintf(stderr, "Failed to change default logging level: %s.\n",
+			    str_error(rc));
+			return 2;
+		}
+	} else if (argc == 3) {
+		log_level_t new_level = parse_log_level_or_die(argv[2]);
+		const char *logname = argv[1];
+		int rc = logctl_set_log_level(logname, new_level);
+
+		if (rc != EOK) {
+			fprintf(stderr, "Failed to change logging level: %s.\n",
+			    str_error(rc));
+			return 2;
+		}
+	} else {
+		usage(argv[0]);
+		return 1;
+	}
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/app/tester/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -29,6 +29,6 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBEXT2_PREFIX)/libext2.a $(LIBBLOCK_PREFIX)/libblock.a
-EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX)
+LIBS = $(LIBEXT2_PREFIX)/libext2.a $(LIBBLOCK_PREFIX)/libblock.a $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX) -I$(LIBSOFTFLOAT_PREFIX)
 BINARY = tester
 
@@ -45,7 +45,11 @@
 	stdio/stdio1.c \
 	stdio/stdio2.c \
+	stdio/logger1.c \
+	stdio/logger2.c \
 	fault/fault1.c \
 	fault/fault2.c \
 	fault/fault3.c \
+	float/float1.c \
+	float/softfloat1.c \
 	vfs/vfs1.c \
 	ipc/ping_pong.c \
@@ -59,5 +63,5 @@
 	hw/misc/virtchar1.c \
 	hw/serial/serial1.c \
-	libext2/libext2_1.c
+	ext2/ext2_1.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tester/ext2/ext2_1.c
===================================================================
--- uspace/app/tester/ext2/ext2_1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/ext2/ext2_1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 <unistd.h>
+#include "../tester.h"
+#include "../util.h"
+#include <libext2.h>
+#include <malloc.h>
+
+static ext2_superblock_t *fake_superblock1()
+{
+	uint8_t *buf;
+	int i;
+	
+	buf = malloc(EXT2_SUPERBLOCK_SIZE);
+	if (buf == NULL) {
+		return NULL;
+	}
+	
+	for (i = 0; i < EXT2_SUPERBLOCK_SIZE; i++) {
+		buf[i] = i % 256;
+	}
+	
+	return (ext2_superblock_t *) buf;
+}
+
+const char *test_ext2_1(void)
+{
+	ext2_superblock_t *fake1;
+	
+	TPRINTF("Testing ext2 superblock getters...\n");
+	TPRINTF("Simple test for correct position and byte order\n");
+	
+	fake1 = fake_superblock1();
+	if (fake1 == NULL) {
+		return "Failed allocating memory for test superblock 1";
+	}
+	
+	ASSERT_EQ_32(0x03020100, ext2_superblock_get_total_inode_count(fake1),
+	    "Failed getting total inode count");
+	ASSERT_EQ_32(0x07060504, ext2_superblock_get_total_block_count(fake1),
+	    "Failed getting total block count");
+	ASSERT_EQ_32(0x0B0A0908, ext2_superblock_get_reserved_block_count(fake1),
+	    "Failed getting reserved block count");
+	ASSERT_EQ_32(0x0F0E0D0C, ext2_superblock_get_free_block_count(fake1),
+	    "Failed getting free block count");
+	ASSERT_EQ_32(0x13121110, ext2_superblock_get_free_inode_count(fake1),
+	    "Failed getting free inode count");
+	ASSERT_EQ_32(0x17161514, ext2_superblock_get_first_block(fake1),
+	    "Failed getting first block number");
+	ASSERT_EQ_32(0x1B1A1918, ext2_superblock_get_block_size_log2(fake1),
+	    "Failed getting log block size");
+	ASSERT_EQ_32(0x1F1E1D1C, ext2_superblock_get_fragment_size_log2(fake1),
+	    "Failed getting log fragment size");
+	ASSERT_EQ_32(0x23222120, ext2_superblock_get_blocks_per_group(fake1),
+	    "Failed getting blocks per group");
+	ASSERT_EQ_32(0x27262524, ext2_superblock_get_fragments_per_group(fake1),
+	    "Failed getting fragments per group");
+	ASSERT_EQ_32(0x2B2A2928, ext2_superblock_get_inodes_per_group(fake1),
+	    "Failed getting inodes per group");
+	ASSERT_EQ_16(0x3938, ext2_superblock_get_magic(fake1),
+	    "Failed getting magic number");
+	ASSERT_EQ_16(0x3B3A, ext2_superblock_get_state(fake1),
+	    "Failed getting state");
+	ASSERT_EQ_16(0x3F3E, ext2_superblock_get_rev_minor(fake1),
+	    "Failed getting minor revision number");
+	ASSERT_EQ_32(0x4B4A4948, ext2_superblock_get_os(fake1),
+	    "Failed getting OS");
+	ASSERT_EQ_32(0x4F4E4D4C, ext2_superblock_get_rev_major(fake1),
+	    "Failed getting major revision number");
+	ASSERT_EQ_32(0x57565554, ext2_superblock_get_first_inode(fake1),
+	    "Failed getting first inode number");
+	ASSERT_EQ_16(0x5958, ext2_superblock_get_inode_size(fake1),
+	    "Failed getting size");
+	ASSERT_EQ_8(0x68, fake1->uuid[0], "UUID position is incorrect");
+	ASSERT_EQ_8(0x78, fake1->volume_name[0],
+	    "Volume name position is incorrect");
+	
+	return NULL;
+}
Index: uspace/app/tester/ext2/ext2_1.def
===================================================================
--- uspace/app/tester/ext2/ext2_1.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/ext2/ext2_1.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,6 @@
+{
+	"ext2_1",
+	"Superblock getters test",
+	&test_ext2_1,
+	true
+},
Index: uspace/app/tester/float/float1.c
===================================================================
--- uspace/app/tester/float/float1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/float/float1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2005 Jakub Vana
+ * Copyright (c) 2005 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <atomic.h>
+#include <thread.h>
+#include <inttypes.h>
+#include "../tester.h"
+
+#define THREADS   150
+#define ATTEMPTS  100
+
+#define E_10E8     UINT32_C(271828182)
+#define PRECISION  100000000
+
+static atomic_t threads_finished;
+static atomic_t threads_fault;
+
+static void e(void *data)
+{
+	for (unsigned int i = 0; i < ATTEMPTS; i++) {
+		double le = -1;
+		double e = 0;
+		double f = 1;
+		
+		for (double d = 1; e != le; d *= f, f += 1) {
+			le = e;
+			e = e + 1 / d;
+		}
+		
+		if ((uint32_t) (e * PRECISION) != E_10E8) {
+			atomic_inc(&threads_fault);
+			break;
+		}
+	}
+	
+	atomic_inc(&threads_finished);
+}
+
+const char *test_float1(void)
+{
+	atomic_count_t total = 0;
+	
+	atomic_set(&threads_finished, 0);
+	atomic_set(&threads_fault, 0);
+	
+	TPRINTF("Creating threads");
+	for (unsigned int i = 0; i < THREADS; i++) {
+		if (thread_create(e, NULL, "e", NULL) < 0) {
+			TPRINTF("\nCould not create thread %u\n", i);
+			break;
+		}
+		
+		TPRINTF(".");
+		total++;
+	}
+	
+	TPRINTF("\n");
+	
+	while (atomic_get(&threads_finished) < total) {
+		TPRINTF("Threads left: %" PRIua "\n",
+		    total - atomic_get(&threads_finished));
+		sleep(1);
+	}
+	
+	if (atomic_get(&threads_fault) == 0)
+		return NULL;
+	
+	return "Test failed";
+}
Index: uspace/app/tester/float/float1.def
===================================================================
--- uspace/app/tester/float/float1.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/float/float1.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,6 @@
+{
+	"float1",
+	"Floating point computation",
+	&test_float1,
+	true
+},
Index: uspace/app/tester/float/softfloat1.c
===================================================================
--- uspace/app/tester/float/softfloat1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/float/softfloat1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sftypes.h>
+#include <add.h>
+#include <bool.h>
+#include "../tester.h"
+
+#define OPERANDS   5
+#define PRECISION  10000
+
+#define PRIdCMPTYPE  PRId32
+
+typedef int32_t cmptype_t;
+
+static float float_op_a[OPERANDS] =
+	{3.5, -2.1, 100.0, 50.0, -1024.0};
+
+static float float_op_b[OPERANDS] =
+	{-2.1, 100.0, 50.0, -1024.0, 3.5};
+
+static cmptype_t cmpabs(cmptype_t a)
+{
+	if (a >= 0)
+		return a;
+	
+	return -a;
+}
+
+static bool test_float_add(void)
+{
+	bool correct = true;
+	
+	for (unsigned int i = 0; i < OPERANDS; i++) {
+		for (unsigned int j = 0; j < OPERANDS; j++) {
+			float a = float_op_a[i];
+			float b = float_op_b[j];
+			float c = a + b;
+			
+			float_t sa;
+			float_t sb;
+			float_t sc;
+			
+			sa.val = float_op_a[i];
+			sb.val = float_op_b[j];
+			sc.data = add_float(sa.data, sb.data);
+			
+			cmptype_t ic = (cmptype_t) (c * PRECISION);
+			cmptype_t isc = (cmptype_t) (sc.val * PRECISION);
+			cmptype_t diff = cmpabs(ic - isc);
+			
+			if (diff != 0) {
+				TPRINTF("i=%u, j=%u diff=%" PRIdCMPTYPE "\n", i, j, diff);
+				correct = false;
+			}
+		}
+	}
+	
+	return correct;
+}
+
+const char *test_softfloat1(void)
+{
+	if (!test_float_add())
+		return "Float addition failed";
+	
+	return NULL;
+}
Index: uspace/app/tester/float/softfloat1.def
===================================================================
--- uspace/app/tester/float/softfloat1.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/float/softfloat1.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,6 @@
+{
+	"softfloat1",
+	"Software floating point computation",
+	&test_softfloat1,
+	true
+},
Index: pace/app/tester/libext2/libext2_1.c
===================================================================
--- uspace/app/tester/libext2/libext2_1.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,106 +1,0 @@
-/*
- * Copyright (c) 2011 Martin Sucha
- * 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 <unistd.h>
-#include "../tester.h"
-#include "../util.h"
-#include <libext2.h>
-#include <malloc.h>
-
-static ext2_superblock_t *fake_superblock1()
-{
-	uint8_t *buf;
-	int i;
-	
-	buf = malloc(EXT2_SUPERBLOCK_SIZE);
-	if (buf == NULL) {
-		return NULL;
-	}
-	
-	for (i = 0; i < EXT2_SUPERBLOCK_SIZE; i++) {
-		buf[i] = i % 256;
-	}
-	
-	return (ext2_superblock_t *) buf;
-}
-
-const char *test_libext2_1(void)
-{
-	ext2_superblock_t *fake1;
-	
-	TPRINTF("Testing libext2 superblock getters...\n");
-	TPRINTF("Simple test for correct position and byte order\n");
-	
-	fake1 = fake_superblock1();
-	if (fake1 == NULL) {
-		return "Failed allocating memory for test superblock 1";
-	}
-	
-	ASSERT_EQ_32(0x03020100, ext2_superblock_get_total_inode_count(fake1),
-	    "Failed getting total inode count");
-	ASSERT_EQ_32(0x07060504, ext2_superblock_get_total_block_count(fake1),
-	    "Failed getting total block count");
-	ASSERT_EQ_32(0x0B0A0908, ext2_superblock_get_reserved_block_count(fake1),
-	    "Failed getting reserved block count");
-	ASSERT_EQ_32(0x0F0E0D0C, ext2_superblock_get_free_block_count(fake1),
-	    "Failed getting free block count");
-	ASSERT_EQ_32(0x13121110, ext2_superblock_get_free_inode_count(fake1),
-	    "Failed getting free inode count");
-	ASSERT_EQ_32(0x17161514, ext2_superblock_get_first_block(fake1),
-	    "Failed getting first block number");
-	ASSERT_EQ_32(0x1B1A1918, ext2_superblock_get_block_size_log2(fake1),
-	    "Failed getting log block size");
-	ASSERT_EQ_32(0x1F1E1D1C, ext2_superblock_get_fragment_size_log2(fake1),
-	    "Failed getting log fragment size");
-	ASSERT_EQ_32(0x23222120, ext2_superblock_get_blocks_per_group(fake1),
-	    "Failed getting blocks per group");
-	ASSERT_EQ_32(0x27262524, ext2_superblock_get_fragments_per_group(fake1),
-	    "Failed getting fragments per group");
-	ASSERT_EQ_32(0x2B2A2928, ext2_superblock_get_inodes_per_group(fake1),
-	    "Failed getting inodes per group");
-	ASSERT_EQ_16(0x3938, ext2_superblock_get_magic(fake1),
-	    "Failed getting magic number");
-	ASSERT_EQ_16(0x3B3A, ext2_superblock_get_state(fake1),
-	    "Failed getting state");
-	ASSERT_EQ_16(0x3F3E, ext2_superblock_get_rev_minor(fake1),
-	    "Failed getting minor revision number");
-	ASSERT_EQ_32(0x4B4A4948, ext2_superblock_get_os(fake1),
-	    "Failed getting OS");
-	ASSERT_EQ_32(0x4F4E4D4C, ext2_superblock_get_rev_major(fake1),
-	    "Failed getting major revision number");
-	ASSERT_EQ_32(0x57565554, ext2_superblock_get_first_inode(fake1),
-	    "Failed getting first inode number");
-	ASSERT_EQ_16(0x5958, ext2_superblock_get_inode_size(fake1),
-	    "Failed getting size");
-	ASSERT_EQ_8(0x68, fake1->uuid[0], "UUID position is incorrect");
-	ASSERT_EQ_8(0x78, fake1->volume_name[0],
-	    "Volume name position is incorrect");
-	
-	return NULL;
-}
Index: pace/app/tester/libext2/libext2_1.def
===================================================================
--- uspace/app/tester/libext2/libext2_1.def	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"libext2_1",
-	"Superblock getters test",
-	&test_libext2_1,
-	true
-},
Index: uspace/app/tester/stdio/logger1.c
===================================================================
--- uspace/app/tester/stdio/logger1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/stdio/logger1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 <stdlib.h>
+#include <errno.h>
+#include <io/log.h>
+#include "../tester.h"
+
+const char *test_logger1(void)
+{
+	for (log_level_t level = 0; level < LVL_LIMIT; level++) {
+		log_msg(LOG_DEFAULT, level, "Testing logger, level %d.", (int) level);
+	}
+
+	return NULL;
+}
Index: uspace/app/tester/stdio/logger1.def
===================================================================
--- uspace/app/tester/stdio/logger1.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/stdio/logger1.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,6 @@
+{
+	"logger1",
+	"Logger printing test",
+	&test_logger1,
+	true
+},
Index: uspace/app/tester/stdio/logger2.c
===================================================================
--- uspace/app/tester/stdio/logger2.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/stdio/logger2.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 <stdlib.h>
+#include <errno.h>
+#include <io/log.h>
+#include <async.h>
+#include "../tester.h"
+
+const char *test_logger2(void)
+{
+	log_t log_alpha = log_create("alpha", LOG_DEFAULT);
+	log_t log_bravo = log_create("bravo", log_alpha);
+
+	TPRINTF("Alpha is %" PRIlogctx ".\n", log_alpha);
+	TPRINTF("Bravo is %" PRIlogctx ".\n", log_bravo);
+
+	while (true) {
+		/*
+		 * Intentionally skipping FATAL to allow muting
+		 * the output completely by setting visible level to FATAL.
+		 */
+		for (log_level_t level = LVL_ERROR; level < LVL_LIMIT; level++) {
+			log_msg(LOG_DEFAULT, level, "Printing level %d (%s).",
+			    (int) level, log_level_str(level));
+			log_msg(log_alpha, level,
+			    "Printing level %d (%s) into alpha log.",
+			    (int) level, log_level_str(level));
+			log_msg(log_bravo, level,
+			    "Printing level %d (%s) into bravo sub-log.",
+			    (int) level, log_level_str(level));
+			async_usleep(1000 * 100);
+		}
+	}
+
+	return NULL;
+}
Index: uspace/app/tester/stdio/logger2.def
===================================================================
--- uspace/app/tester/stdio/logger2.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/app/tester/stdio/logger2.def	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,6 @@
+{
+	"logger2",
+	"Logger endless test",
+	&test_logger2,
+	false
+},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/app/tester/tester.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -39,4 +39,5 @@
 #include <stdio.h>
 #include <str.h>
+#include <io/log.h>
 #include "tester.h"
 
@@ -55,7 +56,11 @@
 #include "stdio/stdio1.def"
 #include "stdio/stdio2.def"
+#include "stdio/logger1.def"
+#include "stdio/logger2.def"
 #include "fault/fault1.def"
 #include "fault/fault2.def"
 #include "fault/fault3.def"
+#include "float/float1.def"
+#include "float/softfloat1.def"
 #include "vfs/vfs1.def"
 #include "ipc/ping_pong.def"
@@ -68,5 +73,5 @@
 #include "hw/serial/serial1.def"
 #include "hw/misc/virtchar1.def"
-#include "libext2/libext2_1.def"
+#include "ext2/ext2_1.def"
 	{NULL, NULL, NULL, false}
 };
@@ -138,4 +143,6 @@
 	}
 	
+	log_init("tester");
+
 	test_quiet = false;
 	test_argc = argc - 2;
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/app/tester/tester.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -88,7 +88,11 @@
 extern const char *test_stdio1(void);
 extern const char *test_stdio2(void);
+extern const char *test_logger1(void);
+extern const char *test_logger2(void);
 extern const char *test_fault1(void);
 extern const char *test_fault2(void);
 extern const char *test_fault3(void);
+extern const char *test_float1(void);
+extern const char *test_softfloat1(void);
 extern const char *test_vfs1(void);
 extern const char *test_ping_pong(void);
@@ -101,5 +105,5 @@
 extern const char *test_serial1(void);
 extern const char *test_virtchar1(void);
-extern const char *test_libext2_1(void);
+extern const char *test_ext2_1(void);
 extern const char *test_devman1(void);
 extern const char *test_devman2(void);
Index: uspace/app/top/screen.h
===================================================================
--- uspace/app/top/screen.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/app/top/screen.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -36,4 +36,5 @@
 
 #include <io/console.h>
+#include <io/verify.h>
 #include "top.h"
 
@@ -43,5 +44,6 @@
 extern void screen_done(void);
 extern void print_data(data_t *);
-extern void show_warning(const char *, ...);
+extern void show_warning(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 
 extern int tgetchar(unsigned int);
Index: uspace/app/vuhid/main.c
===================================================================
--- uspace/app/vuhid/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/app/vuhid/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -155,5 +155,5 @@
 	int rc;
 
-	usb_log_enable(USB_LOG_LEVEL_DEBUG2, "vusbhid");
+	log_init("vuhid");
 
 	fibril_mutex_initialize(&vuhid_data.iface_count_mutex);
Index: uspace/dist/src/c/demos/top/screen.h
===================================================================
--- uspace/dist/src/c/demos/top/screen.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/dist/src/c/demos/top/screen.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -36,4 +36,5 @@
 
 #include <io/console.h>
+#include <io/verify.h>
 #include "top.h"
 
@@ -43,5 +44,6 @@
 extern void screen_done(void);
 extern void print_data(data_t *);
-extern void print_warning(const char *, ...);
+extern void print_warning(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 
 extern int tgetchar(unsigned int);
Index: uspace/drv/block/ahci/ahci.c
===================================================================
--- uspace/drv/block/ahci/ahci.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/block/ahci/ahci.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -1340,5 +1340,5 @@
 {
 	printf("%s: HelenOS AHCI device driver\n", NAME);
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	fibril_mutex_initialize(&sata_devices_count_lock);
 	return ddf_driver_main(&ahci_driver);
Index: uspace/drv/bus/isa/i8237.c
===================================================================
--- uspace/drv/bus/isa/i8237.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/isa/i8237.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -351,5 +351,6 @@
 	
 	/* 16 bit transfers are a bit special */
-	ddf_msg(LVL_DEBUG, "Unspoiled address: %p and size: %zu.", pa, size);
+	ddf_msg(LVL_DEBUG, "Unspoiled address %#" PRIx32 " (size %" PRIu16 ")",
+	    pa, size);
 	if (channel > 4) {
 		/* Size must be aligned to 16 bits */
@@ -367,6 +368,6 @@
 	const dma_channel_t dma_channel = controller_8237.channels[channel];
 	
-	ddf_msg(LVL_DEBUG, "Setting channel %u, to address %p(%zu), mode %hhx.",
-	    channel, pa, size, mode);
+	ddf_msg(LVL_DEBUG, "Setting channel %u to address %#" PRIx32 " "
+	    "(size %" PRIu16 "), mode %hhx.", channel, pa, size, mode);
 	
 	/* Mask DMA request */
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/isa/isa.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -712,5 +712,5 @@
 static void isa_init()
 {
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	isa_fun_ops.interfaces[HW_RES_DEV_IFACE] = &isa_fun_hw_res_ops;
 }
Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/isa/isa.dev	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -27,2 +27,6 @@
 	dma 1
 	dma 5
+
+cmos-rtc:
+	match 100 isa/cmos-rtc
+	io_range 70 2
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -729,5 +729,5 @@
 static void pciintel_init(void)
 {
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops;
 	pci_fun_ops.interfaces[PCI_DEV_IFACE] = &pci_dev_ops;
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/ehci/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -132,5 +132,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 	return ddf_driver_main(&ehci_driver);
 }
Index: uspace/drv/bus/usb/ohci/main.c
===================================================================
--- uspace/drv/bus/usb/ohci/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/ohci/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -83,5 +83,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 	return ddf_driver_main(&ohci_driver);
 }
Index: uspace/drv/bus/usb/uhci/main.c
===================================================================
--- uspace/drv/bus/usb/uhci/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/uhci/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -87,5 +87,5 @@
 {
 	printf(NAME ": HelenOS UHCI driver.\n");
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return ddf_driver_main(&uhci_driver);
Index: uspace/drv/bus/usb/uhcirh/main.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/uhcirh/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -73,5 +73,5 @@
 {
 	printf(NAME ": HelenOS UHCI root hub driver.\n");
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 	return ddf_driver_main(&uhci_rh_driver);
 }
Index: uspace/drv/bus/usb/usbflbk/main.c
===================================================================
--- uspace/drv/bus/usb/usbflbk/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/usbflbk/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -110,5 +110,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&usbfallback_driver);
Index: uspace/drv/bus/usb/usbhid/main.c
===================================================================
--- uspace/drv/bus/usb/usbhid/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/usbhid/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -172,5 +172,5 @@
 	printf(NAME ": HelenOS USB HID driver.\n");
 
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&usb_hid_driver);
Index: uspace/drv/bus/usb/usbhub/main.c
===================================================================
--- uspace/drv/bus/usb/usbhub/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/usbhub/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -79,5 +79,5 @@
 {
 	printf(NAME ": HelenOS USB hub driver.\n");
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&usb_hub_driver);
Index: uspace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -383,5 +383,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&usbmast_driver);
Index: uspace/drv/bus/usb/usbmid/main.c
===================================================================
--- uspace/drv/bus/usb/usbmid/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/usbmid/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -180,5 +180,5 @@
 	printf(NAME ": USB multi interface device driver.\n");
 
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	return usb_driver_main(&mid_driver);
Index: uspace/drv/bus/usb/vhc/Makefile
===================================================================
--- uspace/drv/bus/usb/vhc/Makefile	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/vhc/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -32,6 +32,6 @@
 	$(LIBUSBDEV_PREFIX)/libusbdev.a \
 	$(LIBUSBHOST_PREFIX)/libusbhost.a \
+	$(LIBUSBVIRT_PREFIX)/libusbvirt.a \
 	$(LIBUSB_PREFIX)/libusb.a \
-	$(LIBUSBVIRT_PREFIX)/libusbvirt.a \
 	$(LIBDRV_PREFIX)/libdrv.a
 
Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/bus/usb/vhc/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -138,5 +138,5 @@
 int main(int argc, char * argv[])
 {	
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	log_init(NAME);
 
 	printf(NAME ": virtual USB host controller driver.\n");
Index: uspace/drv/char/i8042/i8042.c
===================================================================
--- uspace/drv/char/i8042/i8042.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/char/i8042/i8042.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -302,5 +302,5 @@
 	const bool enabled = hw_res_enable_interrupt(parent_sess);
 	if (!enabled) {
-		log_msg(LVL_ERROR, "Failed to enable interrupts: %s.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to enable interrupts: %s.",
 		    ddf_dev_get_name(ddf_dev));
 		rc = EIO;
Index: uspace/drv/char/i8042/main.c
===================================================================
--- uspace/drv/char/i8042/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/char/i8042/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -151,5 +151,5 @@
 {
 	printf("%s: HelenOS PS/2 driver.\n", NAME);
-	ddf_log_init(NAME, LVL_NOTE);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&i8042_driver);
 }
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/char/ns8250/ns8250.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -1084,5 +1084,5 @@
 static void ns8250_init(void)
 {
-	ddf_log_init(NAME, LVL_WARN);
+	ddf_log_init(NAME);
 	
 	ns8250_dev_ops.open = &ns8250_open;
Index: uspace/drv/char/ps2mouse/main.c
===================================================================
--- uspace/drv/char/ps2mouse/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/char/ps2mouse/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -69,5 +69,5 @@
 {
 	printf(NAME ": HelenOS ps/2 mouse driver.\n");
-	ddf_log_init(NAME, LVL_NOTE);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&mouse_driver);
 }
Index: uspace/drv/char/ps2mouse/ps2mouse.c
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/char/ps2mouse/ps2mouse.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -75,5 +75,5 @@
 	const ssize_t size = chardev_read(sess, &data, 1); \
 	if (size != 1) { \
-		ddf_msg(LVL_ERROR, "Failed reading byte: %d)", size);\
+		ddf_msg(LVL_ERROR, "Failed reading byte: %zd)", size);\
 		return size < 0 ? size : EIO; \
 	} \
Index: uspace/drv/char/xtkbd/main.c
===================================================================
--- uspace/drv/char/xtkbd/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/char/xtkbd/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -69,5 +69,5 @@
 {
 	printf(NAME ": HelenOS XT keyboard driver.\n");
-	ddf_log_init(NAME, LVL_NOTE);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&kbd_driver);
 }
Index: uspace/drv/infrastructure/root/root.c
===================================================================
--- uspace/drv/infrastructure/root/root.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/infrastructure/root/root.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -237,5 +237,5 @@
 	printf(NAME ": HelenOS root device driver\n");
 
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&root_driver);
 }
Index: uspace/drv/infrastructure/rootmac/rootmac.c
===================================================================
--- uspace/drv/infrastructure/rootmac/rootmac.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/infrastructure/rootmac/rootmac.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -179,5 +179,5 @@
 {
 	printf("%s: HelenOS Mac platform driver\n", NAME);
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	rootmac_fun_ops.interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops;
 	return ddf_driver_main(&rootmac_driver);
Index: uspace/drv/infrastructure/rootpc/rootpc.c
===================================================================
--- uspace/drv/infrastructure/rootpc/rootpc.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/infrastructure/rootpc/rootpc.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -195,5 +195,5 @@
 static void root_pc_init(void)
 {
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	rootpc_fun_ops.interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops;
 }
Index: uspace/drv/infrastructure/rootvirt/rootvirt.c
===================================================================
--- uspace/drv/infrastructure/rootvirt/rootvirt.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/infrastructure/rootvirt/rootvirt.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -240,5 +240,5 @@
 	printf(NAME ": HelenOS virtual devices root driver\n");
 
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&rootvirt_driver);
 }
Index: uspace/drv/nic/e1k/e1k.c
===================================================================
--- uspace/drv/nic/e1k/e1k.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/nic/e1k/e1k.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -2381,5 +2381,5 @@
 	    &e1000_nic_iface);
 	
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	ddf_msg(LVL_NOTE, "HelenOS E1000 driver started");
 	return ddf_driver_main(&e1000_driver);
Index: uspace/drv/nic/rtl8139/driver.c
===================================================================
--- uspace/drv/nic/rtl8139/driver.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/nic/rtl8139/driver.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -620,6 +620,6 @@
 		/* Check if the header is valid, otherwise we are lost in the buffer */
 		if (size == 0 || size > RTL8139_FRAME_MAX_LENGTH) {
-			ddf_msg(LVL_ERROR, "Receiver error -> receiver reset (size: %4"PRIu16", "
-			    "header 0x%4"PRIx16". Offset: %zu)", size, frame_header, 
+			ddf_msg(LVL_ERROR, "Receiver error -> receiver reset (size: %4" PRIu16 ", "
+			    "header 0x%4" PRIx16 ". Offset: %d)", size, frame_header,
 			    rx_offset);
 			goto rx_err;
@@ -1162,5 +1162,5 @@
 
 	/* Allocate buffer for receiver */
-	ddf_msg(LVL_DEBUG, "Allocating receiver buffer of the size %zu bytes",
+	ddf_msg(LVL_DEBUG, "Allocating receiver buffer of the size %d bytes",
 	    RxBUF_TOT_LENGTH);
 
@@ -1249,5 +1249,5 @@
 	/* Gain control over port's registers. */
 	if (pio_enable(rtl8139->io_addr, RTL8139_IO_SIZE, &rtl8139->io_port)) {
-		ddf_msg(LVL_ERROR, "Cannot gain the port %lx for device %s.", rtl8139->io_addr,
+		ddf_msg(LVL_ERROR, "Cannot gain the port %p for device %s.", rtl8139->io_addr,
 		    ddf_dev_get_name(dev));
 		return EADDRNOTAVAIL;
@@ -1296,5 +1296,5 @@
 
 	assert(dev);
-	ddf_msg(LVL_NOTE, "RTL8139_dev_add %s (handle = %d)",
+	ddf_msg(LVL_NOTE, "RTL8139_dev_add %s (handle = %zu)",
 	    ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
 
@@ -1328,5 +1328,5 @@
 	rc = nic_connect_to_services(nic_data);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed to connect to services", rc);
+		ddf_msg(LVL_ERROR, "Failed to connect to services (%d)", rc);
 		goto err_irq;
 	}
@@ -2139,7 +2139,8 @@
 		pio_write_32(rtl8139->io_port + TCTR, 0);
 
-		ddf_msg(LVL_DEBUG, "Periodic mode. Interrupt mask %"PRIx16", poll.full_skips %"
-		    PRIu32", last timer %"PRIu32".", rtl8139->int_mask, 
-		    rtl8139->poll_timer.full_skips, rtl8139->poll_timer.last_val);
+		ddf_msg(LVL_DEBUG, "Periodic mode. Interrupt mask %" PRIx16 ", "
+		    "poll.full_skips %zu, last timer %" PRIu32,
+		    rtl8139->int_mask, rtl8139->poll_timer.full_skips,
+		    rtl8139->poll_timer.last_val);
 		break;
 	default:
@@ -2186,5 +2187,5 @@
 		&rtl8139_driver_ops, &rtl8139_dev_ops, &rtl8139_nic_iface);
 
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	ddf_msg(LVL_NOTE, "HelenOS RTL8139 driver started");
 	return ddf_driver_main(&rtl8139_driver);
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/test/test1/test1.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -306,5 +306,5 @@
 {
 	printf(NAME ": HelenOS test1 virtual device driver\n");
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&test1_driver);
 }
Index: uspace/drv/test/test2/test2.c
===================================================================
--- uspace/drv/test/test2/test2.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/test/test2/test2.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -308,5 +308,5 @@
 {
 	printf(NAME ": HelenOS test2 virtual device driver\n");
-	ddf_log_init(NAME, LVL_NOTE);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&test2_driver);
 }
Index: uspace/drv/test/test3/test3.c
===================================================================
--- uspace/drv/test/test3/test3.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/drv/test/test3/test3.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -193,5 +193,5 @@
 {
 	printf(NAME ": HelenOS test3 virtual device driver\n");
-	ddf_log_init(NAME, LVL_ERROR);
+	ddf_log_init(NAME);
 	return ddf_driver_main(&test3_driver);
 }
Index: uspace/drv/time/cmos-rtc/Makefile
===================================================================
--- uspace/drv/time/cmos-rtc/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/drv/time/cmos-rtc/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2012 Maurizio Lombardi
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = cmos-rtc
+
+SOURCES = \
+	cmos-rtc.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/time/cmos-rtc/cmos-regs.h
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-regs.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/drv/time/cmos-rtc/cmos-regs.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 _CMOS_RTC_H_
+#define _CMOS_RTC_H_
+
+#define RTC_SEC           0x00
+#define RTC_MIN           0x02
+#define RTC_HOUR          0x04
+#define RTC_DAY           0x07
+#define RTC_MON           0x08
+#define RTC_YEAR          0x09
+
+#define RTC_STATUS_B      0x0B
+#define RTC_B_24H         0x02 /* 24h mode */
+#define RTC_B_BCD         0x04 /* BCD mode */
+#define RTC_B_INH         0x80 /* Inhibit updates */
+
+#define RTC_STATUS_D      0x0D
+#define RTC_D_BATTERY_OK  0x80 /* Battery status */
+
+#define RTC_STATUS_A      0x0A
+#define RTC_A_UPDATE      0x80 /* Update in progress */
+#define RTC_A_CLK_STOP    0x70 /* Stop the clock */
+
+#endif
+
Index: uspace/drv/time/cmos-rtc/cmos-rtc.c
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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.
+ */
+
+/**
+ * @defgroup CMOS RTC driver.
+ * @brief HelenOS RTC driver.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <errno.h>
+#include <ddi.h>
+#include <as.h>
+#include <sysinfo.h>
+#include <libarch/ddi.h>
+#include <libarch/barrier.h>
+#include <stdio.h>
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <ops/clock_dev.h>
+#include <ops/battery_dev.h>
+#include <fibril_synch.h>
+#include <device/hw_res.h>
+#include <macros.h>
+#include <time.h>
+
+#include "cmos-regs.h"
+
+#define NAME "cmos-rtc"
+
+#define REG_COUNT 2
+
+#define REG_SEL_PORT(port)  (port)
+#define REG_RW_PORT(port)   ((port) + 1)
+
+typedef struct rtc {
+	/** DDF device node */
+	ddf_dev_t *dev;
+	/** DDF function node */
+	ddf_fun_t *fun;
+	/** The fibril mutex for synchronizing the access to the device */
+	fibril_mutex_t mutex;
+	/** The base I/O address of the device registers */
+	ioport8_t *io_addr;
+	/** The I/O port used to access the CMOS registers */
+	ioport8_t *port;
+	/** true if device is removed */
+	bool removed;
+	/** number of connected clients */
+	int clients_connected;
+	/** time at which the system booted */
+	time_t boottime;
+} rtc_t;
+
+static rtc_t *dev_rtc(ddf_dev_t *dev);
+static rtc_t *fun_rtc(ddf_fun_t *fun);
+static int
+rtc_battery_status_get(ddf_fun_t *fun, battery_status_t *status);
+static int  rtc_time_get(ddf_fun_t *fun, struct tm *t);
+static int  rtc_time_set(ddf_fun_t *fun, struct tm *t);
+static int  rtc_dev_add(ddf_dev_t *dev);
+static int  rtc_dev_initialize(rtc_t *rtc);
+static bool rtc_pio_enable(rtc_t *rtc);
+static void rtc_dev_cleanup(rtc_t *rtc);
+static int  rtc_open(ddf_fun_t *fun);
+static void rtc_close(ddf_fun_t *fun);
+static bool rtc_update_in_progress(rtc_t *rtc);
+static int  rtc_register_read(rtc_t *rtc, int reg);
+static unsigned bcd2bin(unsigned bcd);
+static unsigned bin2bcd(unsigned binary);
+static int rtc_dev_remove(ddf_dev_t *dev);
+static void rtc_register_write(rtc_t *rtc, int reg, int data);
+static time_t uptime_get(void);
+static bool is_battery_ok(rtc_t *rtc);
+
+static ddf_dev_ops_t rtc_dev_ops;
+
+/** The RTC device driver's standard operations */
+static driver_ops_t rtc_ops = {
+	.dev_add = rtc_dev_add,
+	.dev_remove = rtc_dev_remove,
+};
+
+/** The RTC device driver structure */
+static driver_t rtc_driver = {
+	.name = NAME,
+	.driver_ops = &rtc_ops,
+};
+
+/** Clock interface */
+static clock_dev_ops_t rtc_clock_dev_ops = {
+	.time_get = rtc_time_get,
+	.time_set = rtc_time_set,
+};
+
+/** Battery powered device interface */
+static battery_dev_ops_t rtc_battery_dev_ops = {
+	.battery_status_get = rtc_battery_status_get,
+	.battery_charge_level_get = NULL,
+};
+
+/** Obtain soft state structure from device node */
+static rtc_t *
+dev_rtc(ddf_dev_t *dev)
+{
+	return ddf_dev_data_get(dev);
+}
+
+/** Obtain soft state structure from function node */
+static rtc_t *
+fun_rtc(ddf_fun_t *fun)
+{
+	return dev_rtc(ddf_fun_get_dev(fun));
+}
+
+/** Initialize the RTC driver */
+static void
+rtc_init(void)
+{
+	ddf_log_init(NAME);
+
+	rtc_dev_ops.open = rtc_open;
+	rtc_dev_ops.close = rtc_close;
+
+	rtc_dev_ops.interfaces[CLOCK_DEV_IFACE] = &rtc_clock_dev_ops;
+	rtc_dev_ops.interfaces[BATTERY_DEV_IFACE] = &rtc_battery_dev_ops;
+	rtc_dev_ops.default_handler = NULL;
+}
+
+/** Clean up the RTC soft state
+ *
+ * @param rtc  The RTC device
+ */
+static void
+rtc_dev_cleanup(rtc_t *rtc)
+{
+}
+
+/** Enable the I/O ports of the device
+ *
+ * @param rtc  The real time clock device
+ *
+ * @return  true in case of success, false otherwise
+ */
+static bool
+rtc_pio_enable(rtc_t *rtc)
+{
+	if (pio_enable((void *) rtc->io_addr, REG_COUNT,
+	    (void **) &rtc->port)) {
+
+		ddf_msg(LVL_ERROR, "Cannot map the port %lx"
+		    " for device %s", (long unsigned int)rtc->io_addr,
+		    ddf_dev_get_name(rtc->dev));
+		return false;
+	}
+
+	return true;
+}
+
+/** Initialize the RTC device
+ *
+ * @param rtc  Pointer to the RTC device
+ *
+ * @return  EOK on success or a negative error code
+ */ 
+static int
+rtc_dev_initialize(rtc_t *rtc)
+{
+	int rc;
+	size_t i;
+	hw_resource_t *res;
+	bool ioport = false;
+	async_sess_t *parent_sess;
+
+	ddf_msg(LVL_DEBUG, "rtc_dev_initialize %s", ddf_dev_get_name(rtc->dev));
+
+	rtc->boottime = 0;
+	rtc->clients_connected = 0;
+
+	hw_resource_list_t hw_resources;
+	memset(&hw_resources, 0, sizeof(hw_resource_list_t));
+
+	/* Connect to the parent's driver */
+
+	parent_sess = ddf_dev_parent_sess_create(rtc->dev, EXCHANGE_SERIALIZE);
+	if (!parent_sess) {
+		ddf_msg(LVL_ERROR, "Failed to connect to parent driver\
+		    of device %s.", ddf_dev_get_name(rtc->dev));
+		rc = ENOENT;
+		goto error;
+	}
+
+	/* Get the HW resources */
+	rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to get HW resources\
+		    for device %s", ddf_dev_get_name(rtc->dev));
+		goto error;
+	}
+
+	for (i = 0; i < hw_resources.count; ++i) {
+		res = &hw_resources.resources[i];
+
+		if (res->res.io_range.size < REG_COUNT) {
+			ddf_msg(LVL_ERROR, "I/O range assigned to \
+			    device %s is too small",
+			    ddf_dev_get_name(rtc->dev));
+			rc = ELIMIT;
+			continue;
+		}
+
+		rtc->io_addr = (ioport8_t *) (long) res->res.io_range.address;
+		ioport = true;
+		ddf_msg(LVL_NOTE, "Device %s was assigned I/O address "
+		    "0x%lx", ddf_dev_get_name(rtc->dev),
+		    (unsigned long int) rtc->io_addr);
+		rc = EOK;
+		break;
+	}
+
+	if (rc != EOK)
+		goto error;
+
+	if (!ioport) {
+		/* No I/O address assigned to this device */
+		ddf_msg(LVL_ERROR, "Missing HW resource for device %s",
+		    ddf_dev_get_name(rtc->dev));
+		rc = ENOENT;
+		goto error;
+	}
+
+	hw_res_clean_resource_list(&hw_resources);
+
+	return EOK;
+
+error:
+	rtc_dev_cleanup(rtc);
+	hw_res_clean_resource_list(&hw_resources);
+
+	return rc;
+}
+
+/** Read a register from the CMOS memory
+ *
+ * @param rtc    The rtc device
+ * @param reg    The index of the register to read
+ *
+ * @return       The value of the register
+ */
+static int
+rtc_register_read(rtc_t *rtc, int reg)
+{
+	pio_write_8(REG_SEL_PORT(rtc->port), reg);
+	return pio_read_8(REG_RW_PORT(rtc->port));
+}
+
+/** Write a register to the CMOS memory
+ *
+ * @param rtc    The rtc device
+ * @param reg    The index of the register to write
+ * @param data   The data to write
+ */
+static void
+rtc_register_write(rtc_t *rtc, int reg, int data)
+{
+	pio_write_8(REG_SEL_PORT(rtc->port), reg);
+	pio_write_8(REG_RW_PORT(rtc->port), data);
+}
+
+/** Check if an update is in progress
+ *
+ * @param rtc  The rtc device
+ *
+ * @return  true if an update is in progress, false otherwise
+ */
+static bool
+rtc_update_in_progress(rtc_t *rtc)
+{
+	return rtc_register_read(rtc, RTC_STATUS_A) & RTC_A_UPDATE;
+}
+
+/** Read the current time from the CMOS
+ *
+ * @param fun  The RTC function
+ * @param t    Pointer to the time variable
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_time_get(ddf_fun_t *fun, struct tm *t)
+{
+	bool bcd_mode;
+	bool pm_mode = false;
+	rtc_t *rtc = fun_rtc(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	if (rtc->boottime != 0) {
+		/* There is no need to read the current time from the
+		 * device because it has already been cached.
+		 */
+
+		time_t cur_time = rtc->boottime + uptime_get();
+
+		fibril_mutex_unlock(&rtc->mutex);
+
+		return time_local2tm(cur_time, t);
+	}
+
+	/* Check if the RTC battery is OK */
+	if (!is_battery_ok(rtc)) {
+		fibril_mutex_unlock(&rtc->mutex);
+		return EIO;
+	}
+
+	/* now read the registers */
+	do {
+		/* Suspend until the update process has finished */
+		while (rtc_update_in_progress(rtc));
+
+		t->tm_sec  = rtc_register_read(rtc, RTC_SEC);
+		t->tm_min  = rtc_register_read(rtc, RTC_MIN);
+		t->tm_hour = rtc_register_read(rtc, RTC_HOUR);
+		t->tm_mday = rtc_register_read(rtc, RTC_DAY);
+		t->tm_mon  = rtc_register_read(rtc, RTC_MON);
+		t->tm_year = rtc_register_read(rtc, RTC_YEAR);
+
+		/* Now check if it is stable */
+	} while(t->tm_sec  != rtc_register_read(rtc, RTC_SEC) ||
+	    t->tm_min  != rtc_register_read(rtc, RTC_MIN) ||
+	    t->tm_mday != rtc_register_read(rtc, RTC_DAY) ||
+	    t->tm_mon  != rtc_register_read(rtc, RTC_MON) ||
+	    t->tm_year != rtc_register_read(rtc, RTC_YEAR));
+
+	/* Check if the RTC is working in 12h mode */
+	bool _12h_mode = !(rtc_register_read(rtc, RTC_STATUS_B) &
+	    RTC_B_24H);
+
+	if (_12h_mode) {
+		/* The RTC is working in 12h mode, check if it is AM or PM */
+		if (t->tm_hour & 0x80) {
+			/* PM flag is active, it must be cleared */
+			t->tm_hour &= ~0x80;
+			pm_mode = true;
+		}
+	}
+
+	/* Check if the RTC is working in BCD mode */
+	bcd_mode = !(rtc_register_read(rtc, RTC_STATUS_B) & RTC_B_BCD);
+
+	if (bcd_mode) {
+		t->tm_sec  = bcd2bin(t->tm_sec);
+		t->tm_min  = bcd2bin(t->tm_min);
+		t->tm_hour = bcd2bin(t->tm_hour);
+		t->tm_mday = bcd2bin(t->tm_mday);
+		t->tm_mon  = bcd2bin(t->tm_mon);
+		t->tm_year = bcd2bin(t->tm_year);
+	}
+
+	if (_12h_mode) {
+		/* Convert to 24h mode */
+		if (pm_mode) {
+			if (t->tm_hour < 12)
+				t->tm_hour += 12;
+		} else if (t->tm_hour == 12)
+			t->tm_hour = 0;
+	}
+
+	/* Count the months starting from 0, not from 1 */
+	t->tm_mon--;
+
+	if (t->tm_year < 100) {
+		/* tm_year is the number of years since 1900 but the
+		 * RTC epoch is 2000.
+		 */
+		t->tm_year += 100;
+	}
+
+	/* Try to normalize the content of the tm structure */
+	time_t r = mktime(t);
+
+	rtc->boottime = r - uptime_get();
+
+	fibril_mutex_unlock(&rtc->mutex);
+
+	return r < 0 ? EINVAL : EOK;
+}
+
+/** Set the time in the RTC
+ *
+ * @param fun  The RTC function
+ * @param t    The time value to set
+ *
+ * @return  EOK or a negative error code
+ */
+static int
+rtc_time_set(ddf_fun_t *fun, struct tm *t)
+{
+	bool bcd_mode;
+	time_t norm_time;
+	time_t uptime;
+	int  reg_b;
+	int  reg_a;
+	int  epoch;
+	rtc_t *rtc = fun_rtc(fun);
+
+	/* Try to normalize the content of the tm structure */
+	if ((norm_time = mktime(t)) < 0)
+		return EINVAL;
+
+	uptime = uptime_get();
+	if (norm_time <= uptime) {
+		/* This is not acceptable */
+		return EINVAL;
+	}
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	if (!is_battery_ok(rtc)) {
+		fibril_mutex_unlock(&rtc->mutex);
+		return EIO;
+	}
+
+	/* boottime must be recomputed */
+	rtc->boottime = 0;
+
+	/* Detect the RTC epoch */
+	if (rtc_register_read(rtc, RTC_YEAR) < 100)
+		epoch = 2000;
+	else
+		epoch = 1900;
+
+	if (epoch == 2000 && t->tm_year < 100) {
+		/* Can't set a year before the epoch */
+		fibril_mutex_unlock(&rtc->mutex);
+		return EINVAL;
+	}
+
+	t->tm_mon++; /* counts from 1, not from 0 */
+
+	reg_b = rtc_register_read(rtc, RTC_STATUS_B);
+
+	if (!(reg_b & RTC_B_24H)) {
+		/* Force 24h mode of operation */
+		reg_b |= RTC_B_24H;
+		rtc_register_write(rtc, RTC_STATUS_B, reg_b);
+	}
+
+	if (epoch == 2000) {
+		/* The RTC epoch is year 2000  but the tm_year
+		 * field counts years since 1900.
+		 */
+		t->tm_year -= 100;
+	}
+
+	/* Check if the rtc is working in bcd mode */
+	bcd_mode = !(reg_b & RTC_B_BCD);
+	if (bcd_mode) {
+		/* Convert the tm struct fields in BCD mode */
+		t->tm_sec  = bin2bcd(t->tm_sec);
+		t->tm_min  = bin2bcd(t->tm_min);
+		t->tm_hour = bin2bcd(t->tm_hour);
+		t->tm_mday = bin2bcd(t->tm_mday);
+		t->tm_mon  = bin2bcd(t->tm_mon);
+		t->tm_year = bin2bcd(t->tm_year);
+	}
+
+	/* Inhibit updates */
+	rtc_register_write(rtc, RTC_STATUS_B, reg_b | RTC_B_INH);
+
+	/* Write current time to RTC */
+	rtc_register_write(rtc, RTC_SEC, t->tm_sec);
+	rtc_register_write(rtc, RTC_MIN, t->tm_min);
+	rtc_register_write(rtc, RTC_HOUR, t->tm_hour);
+	rtc_register_write(rtc, RTC_DAY, t->tm_mday);
+	rtc_register_write(rtc, RTC_MON, t->tm_mon);
+	rtc_register_write(rtc, RTC_YEAR, t->tm_year);
+
+	/* Stop the clock */
+	reg_a = rtc_register_read(rtc, RTC_STATUS_A);
+	rtc_register_write(rtc, RTC_STATUS_A, RTC_A_CLK_STOP | reg_a);
+	
+	/* Enable updates */
+	rtc_register_write(rtc, RTC_STATUS_B, reg_b);
+	rtc_register_write(rtc, RTC_STATUS_A, reg_a);
+
+	fibril_mutex_unlock(&rtc->mutex);
+
+	return EOK;
+}
+
+/** Get the status of the real time clock battery
+ *
+ * @param fun    The RTC function
+ * @param status The status of the battery
+ *
+ * @return       EOK on success or a negative error code
+ */
+static int
+rtc_battery_status_get(ddf_fun_t *fun, battery_status_t *status)
+{
+	rtc_t *rtc = fun_rtc(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+	const bool batt_ok = is_battery_ok(rtc);
+	fibril_mutex_unlock(&rtc->mutex);
+
+	*status = batt_ok ? BATTERY_OK : BATTERY_LOW;
+
+	return EOK;
+}
+
+/** Check if the battery is working properly or not.
+ *  The caller already holds the rtc->mutex lock.
+ *
+ *  @param rtc   The RTC instance.
+ *
+ *  @return      true if the battery is ok, false otherwise.
+ */
+static bool
+is_battery_ok(rtc_t *rtc)
+{
+	return rtc_register_read(rtc, RTC_STATUS_D) & RTC_D_BATTERY_OK;
+}
+
+/** The dev_add callback of the rtc driver
+ *
+ * @param dev  The RTC device
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_dev_add(ddf_dev_t *dev)
+{
+	rtc_t *rtc;
+	ddf_fun_t *fun = NULL;
+	int rc;
+	bool need_cleanup = false;
+
+	ddf_msg(LVL_DEBUG, "rtc_dev_add %s (handle = %d)",
+	    ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
+
+	rtc = ddf_dev_data_alloc(dev, sizeof(rtc_t));
+	if (!rtc)
+		return ENOMEM;
+
+	rtc->dev = dev;
+	fibril_mutex_initialize(&rtc->mutex);
+
+	rc = rtc_dev_initialize(rtc);
+	if (rc != EOK)
+		goto error;
+
+	need_cleanup = true;
+
+	if (!rtc_pio_enable(rtc)) {
+		rc = EADDRNOTAVAIL;
+		goto error;
+	}
+
+	fun = ddf_fun_create(dev, fun_exposed, "a");
+	if (!fun) {
+		ddf_msg(LVL_ERROR, "Failed creating function");
+		rc = ENOENT;
+		goto error;
+	}
+
+	ddf_fun_set_ops(fun, &rtc_dev_ops);
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function");
+		goto error;
+	}
+
+	rtc->fun = fun;
+
+	ddf_fun_add_to_category(fun, "clock");
+
+	ddf_msg(LVL_NOTE, "Device %s successfully initialized",
+	    ddf_dev_get_name(dev));
+
+	return rc;
+
+error:
+	if (fun)
+		ddf_fun_destroy(fun);
+	if (need_cleanup)
+		rtc_dev_cleanup(rtc);
+	return rc;
+}
+
+/** The dev_remove callback for the rtc driver
+ *
+ * @param dev   The RTC device
+ *
+ * @return      EOK on success or a negative error code
+ */
+static int
+rtc_dev_remove(ddf_dev_t *dev)
+{
+	rtc_t *rtc = dev_rtc(dev);
+	int rc;
+
+	fibril_mutex_lock(&rtc->mutex);
+	if (rtc->clients_connected > 0) {
+		fibril_mutex_unlock(&rtc->mutex);
+		return EBUSY;
+	}
+
+	rtc->removed = true;
+	fibril_mutex_unlock(&rtc->mutex);
+
+	rc = ddf_fun_unbind(rtc->fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to unbind function");
+		return rc;
+	}
+
+	ddf_fun_destroy(rtc->fun);
+	rtc_dev_cleanup(rtc);
+
+	return rc;
+}
+
+/** Open the device
+ *
+ * @param fun   The function node
+ *
+ * @return  EOK on success or a negative error code
+ */
+static int
+rtc_open(ddf_fun_t *fun)
+{
+	int rc;
+	rtc_t *rtc = fun_rtc(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	if (rtc->removed)
+		rc = ENXIO;
+	else {
+		rc = EOK;
+		rtc->clients_connected++;
+	}
+
+	fibril_mutex_unlock(&rtc->mutex);
+	return rc;
+}
+
+/** Close the device
+ *
+ * @param fun  The function node
+ */
+static void
+rtc_close(ddf_fun_t *fun)
+{
+	rtc_t *rtc = fun_rtc(fun);
+
+	fibril_mutex_lock(&rtc->mutex);
+
+	rtc->clients_connected--;
+	assert(rtc->clients_connected >= 0);
+
+	fibril_mutex_unlock(&rtc->mutex);
+}
+
+/** Convert from BCD mode to binary mode
+ *
+ * @param bcd   The number in BCD format to convert
+ *
+ * @return      The converted value
+ */
+static unsigned 
+bcd2bin(unsigned bcd)
+{
+	return ((bcd & 0xF0) >> 1) + ((bcd & 0xF0) >> 3) + (bcd & 0xf);
+}
+
+/** Convert from binary mode to BCD mode
+ *
+ * @param bcd   The number in binary mode to convert
+ *
+ * @return      The converted value
+ */
+static unsigned
+bin2bcd(unsigned binary)
+{
+	return ((binary / 10) << 4) + (binary % 10);
+}
+
+static time_t
+uptime_get(void)
+{
+	struct timeval tv;
+
+	getuptime(&tv);
+
+	return tv.tv_sec;
+}
+
+int
+main(int argc, char **argv)
+{
+	printf(NAME ": HelenOS RTC driver\n");
+	rtc_init();
+	return ddf_driver_main(&rtc_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/time/cmos-rtc/cmos-rtc.ma
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.ma	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.ma	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,1 @@
+100 isa/cmos-rtc
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -71,4 +71,6 @@
 	generic/device/hw_res_parsed.c \
 	generic/device/char_dev.c \
+	generic/device/clock_dev.c \
+	generic/device/battery_dev.c \
 	generic/device/graph_dev.c \
 	generic/device/nic.c \
@@ -101,4 +103,5 @@
 	generic/io/printf.c \
 	generic/io/log.c \
+	generic/io/logctl.c \
 	generic/io/klog.c \
 	generic/io/snprintf.c \
@@ -106,4 +109,5 @@
 	generic/io/vsnprintf.c \
 	generic/io/printf_core.c \
+	generic/io/con_srv.c \
 	generic/io/console.c \
 	generic/io/visualizer.c \
Index: uspace/lib/c/arch/abs32le/_link.ld.in
===================================================================
--- uspace/lib/c/arch/abs32le/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/abs32le/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.text : {
@@ -30,4 +23,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/arm32/Makefile.common
===================================================================
--- uspace/lib/c/arch/arm32/Makefile.common	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/arm32/Makefile.common	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -28,5 +28,6 @@
 #
 
-GCC_CFLAGS += -ffixed-r9 -mtp=soft -fno-omit-frame-pointer -march=armv4
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
+GCC_CFLAGS += -ffixed-r9 -mtp=soft -fno-omit-frame-pointer -march=armv4 -mapcs-frame
 
 ENDIANESS = LE
Index: uspace/lib/c/arch/arm32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/arm32/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/arm32/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 8);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -24,13 +24,4 @@
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-#if defined(LOADER) || defined(DLEXE)
-	.interp : {
-		*(.interp);
-	} :interp :text
-#endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -71,4 +62,11 @@
 	} :text
 #endif
+	
+#if defined(LOADER) || defined(DLEXE)
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
+	
 	. = . + 0x1000;
 	
Index: uspace/lib/c/arch/ia64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia64/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/ia64/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -15,13 +15,9 @@
 #ifdef LOADER
 	. = 0x800000000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
 	
-	/* Make sure the code is aligned reasonably */
+	/* Workaround proper alignment of the .init section */
 	. = ALIGN(., 16);
 	
@@ -34,4 +30,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/mips32/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips32/Makefile.common	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/mips32/Makefile.common	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 
 ENDIANESS = LE
Index: uspace/lib/c/arch/mips32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/mips32/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/mips32eb/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips32eb/Makefile.common	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/mips32eb/Makefile.common	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 
 ENDIANESS = BE
Index: uspace/lib/c/arch/mips64/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips64/Makefile.common	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/mips64/Makefile.common	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -msoft-float -mips3 -mabi=64
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 AFLAGS = -64
 
Index: uspace/lib/c/arch/mips64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips64/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/mips64/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/ppc32/Makefile.common
===================================================================
--- uspace/lib/c/arch/ppc32/Makefile.common	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/ppc32/Makefile.common	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -28,4 +28,5 @@
 
 GCC_CFLAGS += -mcpu=powerpc -msoft-float -m32
+BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
 AFLAGS = -a32
 
Index: uspace/lib/c/arch/ppc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ppc32/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/ppc32/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 4);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/sparc64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc64/_link.ld.in	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/arch/sparc64/_link.ld.in	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/generic/async.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -638,5 +638,5 @@
 	
 	if (usecs) {
-		gettimeofday(&conn->wdata.to_event.expires, NULL);
+		getuptime(&conn->wdata.to_event.expires);
 		tv_add(&conn->wdata.to_event.expires, usecs);
 	} else
@@ -967,5 +967,5 @@
 {
 	struct timeval tv;
-	gettimeofday(&tv, NULL);
+	getuptime(&tv);
 	
 	futex_down(&async_futex);
@@ -1024,5 +1024,5 @@
 			
 			struct timeval tv;
-			gettimeofday(&tv, NULL);
+			getuptime(&tv);
 			
 			if (tv_gteq(&tv, &waiter->to_event.expires)) {
@@ -1331,5 +1331,5 @@
 		timeout = 0;
 
-	gettimeofday(&msg->wdata.to_event.expires, NULL);
+	getuptime(&msg->wdata.to_event.expires);
 	tv_add(&msg->wdata.to_event.expires, timeout);
 	
@@ -1413,5 +1413,5 @@
 	msg->wdata.fid = fibril_get_id();
 	
-	gettimeofday(&msg->wdata.to_event.expires, NULL);
+	getuptime(&msg->wdata.to_event.expires);
 	tv_add(&msg->wdata.to_event.expires, timeout);
 	
Index: uspace/lib/c/generic/device/battery_dev.c
===================================================================
--- uspace/lib/c/generic/device/battery_dev.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/generic/device/battery_dev.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/dev_iface.h>
+#include <device/battery_dev.h>
+#include <errno.h>
+#include <async.h>
+#include <time.h>
+
+/** Read the current battery status from the device
+ *
+ * @param sess     Session of the device
+ * @param status   Current status of the battery
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+battery_status_get(async_sess_t *sess, battery_status_t *batt_status)
+{
+	sysarg_t status;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	int const rc = async_req_1_1(exch, DEV_IFACE_ID(BATTERY_DEV_IFACE),
+	    BATTERY_STATUS_GET, &status);
+
+	async_exchange_end(exch);
+
+	if (rc == EOK)
+		*batt_status = (battery_status_t) status;
+
+	return rc;
+}
+
+/** Read the current battery charge level from the device
+ *
+ * @param sess     Session of the device
+ * @param level    Battery charge level (0 - 100)
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+battery_charge_level_get(async_sess_t *sess, int *level)
+{
+	sysarg_t charge_level;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	int const rc = async_req_1_1(exch, DEV_IFACE_ID(BATTERY_DEV_IFACE),
+	    BATTERY_CHARGE_LEVEL_GET, &charge_level);
+
+	async_exchange_end(exch);
+
+	if (rc == EOK)
+		*level = (int) charge_level;
+
+	return rc;
+}
+
+/** @}
+ */
+
Index: uspace/lib/c/generic/device/clock_dev.c
===================================================================
--- uspace/lib/c/generic/device/clock_dev.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/generic/device/clock_dev.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/dev_iface.h>
+#include <device/clock_dev.h>
+#include <errno.h>
+#include <async.h>
+#include <time.h>
+
+/** Read the current time from the device
+ *
+ * @param sess     Session of the device
+ * @param t        The current time that will be read from the device
+ *
+ * @return         EOK on success or a negative error code
+ */
+int
+clock_dev_time_get(async_sess_t *sess, struct tm *t)
+{
+	aid_t req;
+	int ret;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	req = async_send_1(exch, DEV_IFACE_ID(CLOCK_DEV_IFACE),
+	    CLOCK_DEV_TIME_GET, NULL);
+	ret = async_data_read_start(exch, t, sizeof(*t));
+
+	async_exchange_end(exch);
+
+	sysarg_t rc;
+	if (ret != EOK) {
+		async_forget(req);
+		return ret;
+	}
+
+	async_wait_for(req, &rc);
+	return (int)rc;
+}
+
+/** Set the current time
+ *
+ * @param sess   Session of the device
+ * @param t      The current time that will be written to the device
+ *
+ * @return       EOK on success or a negative error code
+ */
+int
+clock_dev_time_set(async_sess_t *sess, struct tm *t)
+{
+	aid_t req;
+	int ret;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	req = async_send_1(exch, DEV_IFACE_ID(CLOCK_DEV_IFACE),
+	    CLOCK_DEV_TIME_SET, NULL);
+	ret = async_data_write_start(exch, t, sizeof(*t));
+
+	async_exchange_end(exch);
+
+	sysarg_t rc;
+	if (ret != EOK) {
+		async_forget(req);
+		return ret;
+	}
+
+	async_wait_for(req, &rc);
+	return (int)rc;
+}
+
+/** @}
+ */
+
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/generic/fibril_synch.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -379,5 +379,5 @@
 	futex_down(&async_futex);
 	if (timeout) {
-		gettimeofday(&wdata.to_event.expires, NULL);
+		getuptime(&wdata.to_event.expires);
 		tv_add(&wdata.to_event.expires, timeout);
 		async_insert_timeout(&wdata);
Index: uspace/lib/c/generic/io/con_srv.c
===================================================================
--- uspace/lib/c/generic/io/con_srv.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/generic/io/con_srv.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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 libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Console protocol server stub
+ */
+#include <errno.h>
+#include <ipc/console.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <io/con_srv.h>
+
+static void con_read_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	void *buf;
+	size_t size;
+	int rc;
+	ipc_callid_t rcallid;
+
+	if (!async_data_read_receive(&rcallid, &size)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	buf = malloc(size);
+	if (buf == NULL) {
+		async_answer_0(rcallid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	if (srv->srvs->ops->read == NULL) {
+		async_answer_0(rcallid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->read(srv, buf, size);
+	if (rc < 0) {
+		async_answer_0(rcallid, rc);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	async_data_read_finalize(rcallid, buf, size);
+	free(buf);
+
+	if (rc >= 0)
+		async_answer_1(callid, EOK, rc);
+	else
+		async_answer_0(callid, rc);
+}
+
+static void con_write_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	void *data;
+	size_t size;
+	int rc;
+
+	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	if (srv->srvs->ops->write == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->write(srv, data, size);
+	free(data);
+
+	if (rc >= 0)
+		async_answer_1(callid, EOK, rc);
+	else
+		async_answer_0(callid, rc);
+}
+
+static void con_sync_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	if (srv->srvs->ops->sync == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->sync(srv);
+	async_answer_0(callid, EOK);
+}
+
+static void con_clear_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	if (srv->srvs->ops->clear == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->clear(srv);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_pos_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	sysarg_t col;
+	sysarg_t row;
+
+	col = IPC_GET_ARG1(*call);
+	row = IPC_GET_ARG2(*call);
+
+	if (srv->srvs->ops->set_pos == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_pos(srv, col, row);
+	async_answer_0(callid, EOK);
+}
+
+static void con_get_pos_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	sysarg_t col;
+	sysarg_t row;
+
+	if (srv->srvs->ops->get_pos == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_pos(srv, &col, &row);
+	async_answer_2(callid, rc, col, row);
+}
+
+static void con_get_size_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	sysarg_t cols;
+	sysarg_t rows;
+
+	if (srv->srvs->ops->get_size == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_size(srv, &cols, &rows);
+	async_answer_2(callid, rc, cols, rows);
+}
+
+static void con_get_color_cap_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	console_caps_t ccap;
+
+	if (srv->srvs->ops->get_color_cap == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_color_cap(srv, &ccap);
+	async_answer_1(callid, rc, (sysarg_t)ccap);
+}
+
+static void con_set_style_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	console_style_t style;
+
+	style = IPC_GET_ARG1(*call);
+
+	if (srv->srvs->ops->set_style == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_style(srv, style);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_color_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	console_color_t bgcolor;
+	console_color_t fgcolor;
+	console_color_attr_t flags;
+
+	bgcolor = IPC_GET_ARG1(*call);
+	fgcolor = IPC_GET_ARG2(*call);
+	flags = IPC_GET_ARG3(*call);
+
+	if (srv->srvs->ops->set_color == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_color(srv, bgcolor, fgcolor, flags);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_rgb_color_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	pixel_t bgcolor;
+	pixel_t fgcolor;
+
+	bgcolor = IPC_GET_ARG1(*call);
+	fgcolor = IPC_GET_ARG2(*call);
+
+	if (srv->srvs->ops->set_rgb_color == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_rgb_color(srv, bgcolor, fgcolor);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_cursor_visibility_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	bool show;
+
+	show = IPC_GET_ARG1(*call);
+
+	if (srv->srvs->ops->set_cursor_visibility == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_cursor_visibility(srv, show);
+	async_answer_0(callid, EOK);
+}
+
+static void con_get_event_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	kbd_event_t event;
+
+	if (srv->srvs->ops->get_event == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_event(srv, &event);
+	async_answer_4(callid, rc, event.type, event.key, event.mods, event.c);
+}
+
+static con_srv_t *con_srv_create(con_srvs_t *srvs)
+{
+	con_srv_t *srv;
+
+	srv = calloc(1, sizeof(*srv));
+	if (srv == NULL)
+		return NULL;
+
+	srv->srvs = srvs;
+	return srv;
+}
+
+void con_srvs_init(con_srvs_t *srvs)
+{
+	srvs->ops = NULL;
+	srvs->sarg = NULL;
+	srvs->abort_timeout = 0;
+	srvs->aborted = false;
+}
+
+int con_conn(ipc_callid_t iid, ipc_call_t *icall, con_srvs_t *srvs)
+{
+	con_srv_t *srv;
+	int rc;
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	srv = con_srv_create(srvs);
+	if (srv == NULL)
+		return ENOMEM;
+
+/*	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (sess == NULL)
+		return ENOMEM;
+
+	srv->client_sess = sess;
+*/
+	srv->client_sess = NULL;
+
+	rc = srvs->ops->open(srvs, srv);
+	if (rc != EOK)
+		return rc;
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = 0;
+
+		while (callid == 0) {
+			/* XXX Need to be able to abort immediately */
+			callid = async_get_call_timeout(&call,
+			    srvs->abort_timeout);
+
+			if (srv->srvs->aborted) {
+				if (callid != 0)
+					async_answer_0(callid, EINTR);
+				break;
+			}
+		}
+
+		if (callid == 0)
+			break;
+
+		sysarg_t method = IPC_GET_IMETHOD(call);
+
+		if (!method) {
+			/* The other side has hung up */
+			async_answer_0(callid, EOK);
+			break;
+		}
+
+		switch (method) {
+		case VFS_OUT_READ:
+			con_read_srv(srv, callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			con_write_srv(srv, callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			con_sync_srv(srv, callid, &call);
+			break;
+		case CONSOLE_CLEAR:
+			con_clear_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_POS:
+			con_set_pos_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_POS:
+			con_get_pos_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_SIZE:
+			con_get_size_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_COLOR_CAP:
+			con_get_color_cap_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_STYLE:
+			con_set_style_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_COLOR:
+			con_set_color_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_RGB_COLOR:
+			con_set_rgb_color_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_CURSOR_VISIBILITY:
+			con_set_cursor_visibility_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_EVENT:
+			con_get_event_srv(srv, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+
+	rc = srvs->ops->close(srv);
+	free(srv);
+
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/console.c
===================================================================
--- uspace/lib/c/generic/io/console.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/generic/io/console.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -38,5 +38,4 @@
 #include <async.h>
 #include <errno.h>
-#include <stdio.h>
 #include <malloc.h>
 #include <vfs/vfs_sess.h>
@@ -126,5 +125,5 @@
 {
 	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
-	async_req_1_0(exch, CONSOLE_CURSOR_VISIBILITY, (show != false));
+	async_req_1_0(exch, CONSOLE_SET_CURSOR_VISIBILITY, (show != false));
 	async_exchange_end(exch);
 }
@@ -151,5 +150,5 @@
 {
 	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
-	async_req_2_0(exch, CONSOLE_GOTO, col, row);
+	async_req_2_0(exch, CONSOLE_SET_POS, col, row);
 	async_exchange_end(exch);
 }
Index: uspace/lib/c/generic/io/log.c
===================================================================
--- uspace/lib/c/generic/io/log.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/generic/io/log.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -38,58 +38,190 @@
 #include <stdlib.h>
 #include <stdio.h>
-
+#include <async.h>
 #include <io/log.h>
-
-/** Serialization mutex for logging functions. */
-static FIBRIL_MUTEX_INITIALIZE(log_serializer);
-
-/** Current log level. */
-static log_level_t log_level;
-
-static FILE *log_stream;
-
+#include <ipc/logger.h>
+#include <ns.h>
+
+/** Id of the first log we create at logger. */
+static sysarg_t default_log_id;
+
+/** Log messages are printed under this name. */
 static const char *log_prog_name;
 
-/** Prefixes for individual logging levels. */
+/** Names of individual log levels. */
 static const char *log_level_names[] = {
-	[LVL_FATAL] = "Fatal error",
-	[LVL_ERROR] = "Error",
-	[LVL_WARN] = "Warning",
-	[LVL_NOTE] = "Note",
-	[LVL_DEBUG] = "Debug",
-	[LVL_DEBUG2] = "Debug2"
+	"fatal",
+	"error",
+	"warn",
+	"note",
+	"debug",
+	"debug2",
+	NULL
 };
 
+/** IPC session with the logger service. */
+static async_sess_t *logger_session;
+
+/** Maximum length of a single log message (in bytes). */
+#define MESSAGE_BUFFER_SIZE 4096
+
+/** Send formatted message to the logger service.
+ *
+ * @param session Initialized IPC session with the logger.
+ * @param log Log to use.
+ * @param level Verbosity level of the message.
+ * @param message The actual message.
+ * @return Error code of the conversion or EOK on success.
+ */
+static int logger_message(async_sess_t *session, log_t log, log_level_t level, char *message)
+{
+	async_exch_t *exchange = async_exchange_begin(session);
+	if (exchange == NULL) {
+		return ENOMEM;
+	}
+	if (log == LOG_DEFAULT)
+		log = default_log_id;
+
+	// FIXME: remove when all USB drivers use libc logging explicitly
+	str_rtrim(message, '\n');
+
+	aid_t reg_msg = async_send_2(exchange, LOGGER_WRITER_MESSAGE,
+	    log, level, NULL);
+	int rc = async_data_write_start(exchange, message, str_size(message));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	/*
+	 * Getting ENAK means no-one wants our message. That is not an
+	 * error at all.
+	 */
+	if (rc == ENAK)
+		rc = EOK;
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return reg_msg_rc;
+}
+
+/** Get name of the log level.
+ *
+ * @param level The log level.
+ * @return String name or "unknown".
+ */
+const char *log_level_str(log_level_t level)
+{
+	if (level >= LVL_LIMIT)
+		return "unknown";
+	else
+		return log_level_names[level];
+}
+
+/** Convert log level name to the enum.
+ *
+ * @param[in] name Log level name or log level number.
+ * @param[out] level_out Where to store the result (set to NULL to ignore).
+ * @return Error code of the conversion or EOK on success.
+ */
+int log_level_from_str(const char *name, log_level_t *level_out)
+{
+	log_level_t level = LVL_FATAL;
+
+	while (log_level_names[level] != NULL) {
+		if (str_cmp(name, log_level_names[level]) == 0) {
+			if (level_out != NULL)
+				*level_out = level;
+			return EOK;
+		}
+		level++;
+	}
+
+	/* Maybe user specified number directly. */
+	char *end_ptr;
+	int level_int = strtol(name, &end_ptr, 0);
+	if ((end_ptr == name) || (str_length(end_ptr) != 0))
+		return EINVAL;
+	if (level_int < 0)
+		return ERANGE;
+	if (level_int >= (int) LVL_LIMIT)
+		return ERANGE;
+
+	if (level_out != NULL)
+		*level_out = (log_level_t) level_int;
+
+	return EOK;
+}
+
 /** Initialize the logging system.
  *
- * @param prog_name	Program name, will be printed as part of message
- * @param level		Minimum message level to print
- */
-int log_init(const char *prog_name, log_level_t level)
-{
-	assert(level < LVL_LIMIT);
-	log_level = level;
-
-	log_stream = stdout;
+ * @param prog_name Program name, will be printed as part of message
+ */
+int log_init(const char *prog_name)
+{
 	log_prog_name = str_dup(prog_name);
 	if (log_prog_name == NULL)
 		return ENOMEM;
 
+	logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0);
+	if (logger_session == NULL) {
+		return ENOMEM;
+	}
+
+	default_log_id = log_create(prog_name, LOG_NO_PARENT);
+
 	return EOK;
 }
 
+/** Create a new (sub-) log.
+ *
+ * This function always returns a valid log_t. In case of errors,
+ * @c parent is returned and errors are silently ignored.
+ *
+ * @param name Log name under which message will be reported (appended to parents name).
+ * @param parent Parent log.
+ * @return Opaque identifier of the newly created log.
+ */
+log_t log_create(const char *name, log_t parent)
+{
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		return parent;
+
+	if (parent == LOG_DEFAULT)
+		parent = default_log_id;
+
+	ipc_call_t answer;
+	aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG,
+	    parent, &answer);
+	int rc = async_data_write_start(exchange, name, str_size(name));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	if ((rc != EOK) || (reg_msg_rc != EOK))
+		return parent;
+
+	return IPC_GET_ARG1(answer);
+}
+
 /** Write an entry to the log.
  *
- * @param level		Message verbosity level. Message is only printed
- *			if verbosity is less than or equal to current
- *			reporting level.
- * @param fmt		Format string (no traling newline).
- */
-void log_msg(log_level_t level, const char *fmt, ...)
+ * The message is printed only if the verbosity level is less than or
+ * equal to currently set reporting level of the log.
+ *
+ * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
+ * @param level Severity level of the message.
+ * @param fmt Format string in printf-like format (without trailing newline).
+ */
+void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
 {
 	va_list args;
 
 	va_start(args, fmt);
-	log_msgv(level, fmt, args);
+	log_msgv(ctx, level, fmt, args);
 	va_end(args);
 }
@@ -97,25 +229,20 @@
 /** Write an entry to the log (va_list variant).
  *
- * @param level		Message verbosity level. Message is only printed
- *			if verbosity is less than or equal to current
- *			reporting level.
- * @param fmt		Format string (no trailing newline)
- */
-void log_msgv(log_level_t level, const char *fmt, va_list args)
+ * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
+ * @param level Severity level of the message.
+ * @param fmt Format string in printf-like format (without trailing newline).
+ * @param args Arguments.
+ */
+void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
 {
 	assert(level < LVL_LIMIT);
 
-	/* Higher number means higher verbosity. */
-	if (level <= log_level) {
-		fibril_mutex_lock(&log_serializer);
-
-		fprintf(log_stream, "%s: %s: ", log_prog_name,
-		    log_level_names[level]);
-		vfprintf(log_stream, fmt, args);
-		fputc('\n', log_stream);
-		fflush(log_stream);
-
-		fibril_mutex_unlock(&log_serializer);
-	}
+	char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
+	if (message_buffer == NULL) {
+		return;
+	}
+
+	vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
+	logger_message(logger_session, ctx, level, message_buffer);
 }
 
Index: uspace/lib/c/generic/io/logctl.c
===================================================================
--- uspace/lib/c/generic/io/logctl.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/generic/io/logctl.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 libc
+ * @{
+ */
+
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <io/logctl.h>
+#include <ipc/logger.h>
+#include <sysinfo.h>
+#include <ns.h>
+#include <str.h>
+
+/** IPC session with the logger service. */
+static async_sess_t *logger_session = NULL;
+
+static int start_logger_exchange(async_exch_t **exchange_out)
+{
+	assert(exchange_out != NULL);
+
+	if (logger_session == NULL) {
+		logger_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+		    SERVICE_LOGGER, LOGGER_INTERFACE_CONTROL, 0);
+		if (logger_session == NULL)
+			return ENOMEM;
+	}
+
+	assert(logger_session != NULL);
+
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		return ENOMEM;
+
+	*exchange_out = exchange;
+
+	return EOK;
+}
+
+/** Set default reported log level (global setting).
+ *
+ * This setting affects all logger clients whose reporting level was
+ * not yet changed.
+ *
+ * If logging level of client A is changed with logctl_set_log_level()
+ * to some level, this call will have no effect at that client's reporting
+ * level. Even if the actual value of the reporting level of client A is
+ * the same as current (previous) default log level.
+ *
+ * @param new_level New reported logging level.
+ * @return Error code of the conversion or EOK on success.
+ */
+int logctl_set_default_level(log_level_t new_level)
+{
+	async_exch_t *exchange = NULL;
+	int rc = start_logger_exchange(&exchange);
+	if (rc != EOK)
+		return rc;
+
+	rc = (int) async_req_1_0(exchange,
+	    LOGGER_CONTROL_SET_DEFAULT_LEVEL, new_level);
+
+	async_exchange_end(exchange);
+
+	return rc;
+}
+
+/** Set reported log level of a single log.
+ *
+ * @see logctl_set_default_level
+ *
+ * @param logname Log name.
+ * @param new_level New reported logging level.
+ * @return Error code of the conversion or EOK on success.
+ */
+int logctl_set_log_level(const char *logname, log_level_t new_level)
+{
+	async_exch_t *exchange = NULL;
+	int rc = start_logger_exchange(&exchange);
+	if (rc != EOK)
+		return rc;
+
+	aid_t reg_msg = async_send_1(exchange, LOGGER_CONTROL_SET_LOG_LEVEL,
+	    new_level, NULL);
+	rc = async_data_write_start(exchange, logname, str_size(logname));
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	if (rc != EOK)
+		return rc;
+
+	return (int) reg_msg_rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/output.c
===================================================================
--- uspace/lib/c/generic/io/output.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/generic/io/output.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -37,4 +37,5 @@
 #include <as.h>
 #include <ipc/output.h>
+#include <io/concaps.h>
 #include <io/output.h>
 
Index: uspace/lib/c/generic/time.c
===================================================================
--- uspace/lib/c/generic/time.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/generic/time.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -1,4 +1,6 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
  * All rights reserved.
  *
@@ -43,5 +45,14 @@
 #include <ddi.h>
 #include <libc.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
 #include <unistd.h>
+#include <loc.h>
+#include <device/clock_dev.h>
+#include <malloc.h>
+
+#define ASCTIME_BUF_LEN 26
 
 /** Pointer to kernel shared variables with time */
@@ -52,4 +63,337 @@
 } *ktime = NULL;
 
+/* Helper functions ***********************************************************/
+
+#define HOURS_PER_DAY (24)
+#define MINS_PER_HOUR (60)
+#define SECS_PER_MIN (60)
+#define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
+#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
+#define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
+
+/**
+ * Checks whether the year is a leap year.
+ *
+ * @param year Year since 1900 (e.g. for 1970, the value is 70).
+ * @return true if year is a leap year, false otherwise
+ */
+static bool _is_leap_year(time_t year)
+{
+	year += 1900;
+
+	if (year % 400 == 0)
+		return true;
+	if (year % 100 == 0)
+		return false;
+	if (year % 4 == 0)
+		return true;
+	return false;
+}
+
+/**
+ * Returns how many days there are in the given month of the given year.
+ * Note that year is only taken into account if month is February.
+ *
+ * @param year Year since 1900 (can be negative).
+ * @param mon Month of the year. 0 for January, 11 for December.
+ * @return Number of days in the specified month.
+ */
+static int _days_in_month(time_t year, time_t mon)
+{
+	assert(mon >= 0 && mon <= 11);
+
+	static int month_days[] =
+		{ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+	if (mon == 1) {
+		year += 1900;
+		/* february */
+		return _is_leap_year(year) ? 29 : 28;
+	} else {
+		return month_days[mon];
+	}
+}
+
+/**
+ * For specified year, month and day of month, returns which day of that year
+ * it is.
+ *
+ * For example, given date 2011-01-03, the corresponding expression is:
+ *     _day_of_year(111, 0, 3) == 2
+ *
+ * @param year Year (year 1900 = 0, can be negative).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (First day is 1).
+ * @return Day of year (First day is 0).
+ */
+static int _day_of_year(time_t year, time_t mon, time_t mday)
+{
+	static int mdays[] =
+	    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+	static int leap_mdays[] =
+	    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
+
+	return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
+}
+
+/**
+ * Integer division that rounds to negative infinity.
+ * Used by some functions in this file.
+ *
+ * @param op1 Dividend.
+ * @param op2 Divisor.
+ * @return Rounded quotient.
+ */
+static time_t _floor_div(time_t op1, time_t op2)
+{
+	if (op1 >= 0 || op1 % op2 == 0) {
+		return op1 / op2;
+	} else {
+		return op1 / op2 - 1;
+	}
+}
+
+/**
+ * Modulo that rounds to negative infinity.
+ * Used by some functions in this file.
+ *
+ * @param op1 Dividend.
+ * @param op2 Divisor.
+ * @return Remainder.
+ */
+static time_t _floor_mod(time_t op1, time_t op2)
+{
+	int div = _floor_div(op1, op2);
+
+	/* (a / b) * b + a % b == a */
+	/* thus, a % b == a - (a / b) * b */
+
+	int result = op1 - div * op2;
+	
+	/* Some paranoid checking to ensure I didn't make a mistake here. */
+	assert(result >= 0);
+	assert(result < op2);
+	assert(div * op2 + result == op1);
+	
+	return result;
+}
+
+/**
+ * Number of days since the Epoch.
+ * Epoch is 1970-01-01, which is also equal to day 0.
+ *
+ * @param year Year (year 1900 = 0, may be negative).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (first day = 1).
+ * @return Number of days since the Epoch.
+ */
+static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
+{
+	return (year - 70) * 365 + _floor_div(year - 69, 4) -
+	    _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
+	    _day_of_year(year, mon, mday);
+}
+
+/**
+ * Seconds since the Epoch. see also _days_since_epoch().
+ * 
+ * @param tm Normalized broken-down time.
+ * @return Number of seconds since the epoch, not counting leap seconds.
+ */
+static time_t _secs_since_epoch(const struct tm *tm)
+{
+	return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
+	    SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
+	    tm->tm_min * SECS_PER_MIN + tm->tm_sec;
+}
+
+/**
+ * Which day of week the specified date is.
+ * 
+ * @param year Year (year 1900 = 0).
+ * @param mon Month (January = 0).
+ * @param mday Day of month (first = 1).
+ * @return Day of week (Sunday = 0).
+ */
+static int _day_of_week(time_t year, time_t mon, time_t mday)
+{
+	/* 1970-01-01 is Thursday */
+	return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);
+}
+
+/**
+ * Normalizes the broken-down time and optionally adds specified amount of
+ * seconds.
+ * 
+ * @param tm Broken-down time to normalize.
+ * @param sec_add Seconds to add.
+ * @return 0 on success, -1 on overflow
+ */
+static int _normalize_time(struct tm *tm, time_t sec_add)
+{
+	// TODO: DST correction
+
+	/* Set initial values. */
+	time_t sec = tm->tm_sec + sec_add;
+	time_t min = tm->tm_min;
+	time_t hour = tm->tm_hour;
+	time_t day = tm->tm_mday - 1;
+	time_t mon = tm->tm_mon;
+	time_t year = tm->tm_year;
+
+	/* Adjust time. */
+	min += _floor_div(sec, SECS_PER_MIN);
+	sec = _floor_mod(sec, SECS_PER_MIN);
+	hour += _floor_div(min, MINS_PER_HOUR);
+	min = _floor_mod(min, MINS_PER_HOUR);
+	day += _floor_div(hour, HOURS_PER_DAY);
+	hour = _floor_mod(hour, HOURS_PER_DAY);
+
+	/* Adjust month. */
+	year += _floor_div(mon, 12);
+	mon = _floor_mod(mon, 12);
+
+	/* Now the difficult part - days of month. */
+	
+	/* First, deal with whole cycles of 400 years = 146097 days. */
+	year += _floor_div(day, 146097) * 400;
+	day = _floor_mod(day, 146097);
+	
+	/* Then, go in one year steps. */
+	if (mon <= 1) {
+		/* January and February. */
+		while (day > 365) {
+			day -= _is_leap_year(year) ? 366 : 365;
+			year++;
+		}
+	} else {
+		/* Rest of the year. */
+		while (day > 365) {
+			day -= _is_leap_year(year + 1) ? 366 : 365;
+			year++;
+		}
+	}
+	
+	/* Finally, finish it off month per month. */
+	while (day >= _days_in_month(year, mon)) {
+		day -= _days_in_month(year, mon);
+		mon++;
+		if (mon >= 12) {
+			mon -= 12;
+			year++;
+		}
+	}
+	
+	/* Calculate the remaining two fields. */
+	tm->tm_yday = _day_of_year(year, mon, day + 1);
+	tm->tm_wday = _day_of_week(year, mon, day + 1);
+	
+	/* And put the values back to the struct. */
+	tm->tm_sec = (int) sec;
+	tm->tm_min = (int) min;
+	tm->tm_hour = (int) hour;
+	tm->tm_mday = (int) day + 1;
+	tm->tm_mon = (int) mon;
+	
+	/* Casts to work around libc brain-damage. */
+	if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {
+		tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);
+		return -1;
+	}
+	
+	tm->tm_year = (int) year;
+	return 0;
+}
+
+/**
+ * Which day the week-based year starts on, relative to the first calendar day.
+ * E.g. if the year starts on December 31st, the return value is -1.
+ *
+ * @param Year since 1900.
+ * @return Offset of week-based year relative to calendar year.
+ */
+static int _wbyear_offset(int year)
+{
+	int start_wday = _day_of_week(year, 0, 1);
+	return _floor_mod(4 - start_wday, 7) - 3;
+}
+
+/**
+ * Returns week-based year of the specified time.
+ *
+ * @param tm Normalized broken-down time.
+ * @return Week-based year.
+ */
+static int _wbyear(const struct tm *tm)
+{
+	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
+	if (day < 0) {
+		/* Last week of previous year. */
+		return tm->tm_year - 1;
+	}
+	if (day > 364 + _is_leap_year(tm->tm_year)) {
+		/* First week of next year. */
+		return tm->tm_year + 1;
+	}
+	/* All the other days are in the calendar year. */
+	return tm->tm_year;
+}
+
+/**
+ * Week number of the year, assuming weeks start on sunday.
+ * The first Sunday of January is the first day of week 1;
+ * days in the new year before this are in week 0.
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (0 - 53).
+ */
+static int _sun_week_number(const struct tm *tm)
+{
+	int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
+	return (tm->tm_yday - first_day + 7) / 7;
+}
+
+/**
+ * Week number of the year, assuming weeks start on monday.
+ * If the week containing January 1st has four or more days in the new year,
+ * then it is considered week 1. Otherwise, it is the last week of the previous
+ * year, and the next week is week 1. Both January 4th and the first Thursday
+ * of January are always in week 1.
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (1 - 53).
+ */
+static int _iso_week_number(const struct tm *tm)
+{
+	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
+	if (day < 0) {
+		/* Last week of previous year. */
+		return 53;
+	}
+	if (day > 364 + _is_leap_year(tm->tm_year)) {
+		/* First week of next year. */
+		return 1;
+	}
+	/* All the other days give correct answer. */
+	return (day / 7 + 1);
+}
+
+/**
+ * Week number of the year, assuming weeks start on monday.
+ * The first Monday of January is the first day of week 1;
+ * days in the new year before this are in week 0. 
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (0 - 53).
+ */
+static int _mon_week_number(const struct tm *tm)
+{
+	int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
+	return (tm->tm_yday - first_day + 7) / 7;
+}
+
+/******************************************************************************/
+
+
 /** Add microseconds to given timeval.
  *
@@ -139,4 +483,67 @@
  */
 int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	int rc;
+	struct tm t;
+	category_id_t cat_id;
+	size_t svc_cnt;
+	service_id_t *svc_ids = NULL;
+	service_id_t svc_id;
+	char *svc_name = NULL;
+
+	static async_sess_t *clock_conn = NULL;
+
+	if (tz) {
+		tz->tz_minuteswest = 0;
+		tz->tz_dsttime = DST_NONE;
+	}
+
+	if (clock_conn == NULL) {
+		rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		if (svc_cnt == 0)
+			goto ret_uptime;
+
+		rc = loc_service_get_name(svc_ids[0], &svc_name);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		rc = loc_service_get_id(svc_name, &svc_id, 0);
+		if (rc != EOK)
+			goto ret_uptime;
+
+		clock_conn = loc_service_connect(EXCHANGE_SERIALIZE,
+		    svc_id, IPC_FLAG_BLOCKING);
+		if (!clock_conn)
+			goto ret_uptime;
+	}
+
+	rc = clock_dev_time_get(clock_conn, &t);
+	if (rc != EOK)
+		goto ret_uptime;
+
+	tv->tv_usec = 0;
+	tv->tv_sec = mktime(&t);
+
+	free(svc_name);
+	free(svc_ids);
+
+	return EOK;
+
+ret_uptime:
+
+	free(svc_name);
+	free(svc_ids);
+
+	return getuptime(tv);
+}
+
+int getuptime(struct timeval *tv)
 {
 	if (ktime == NULL) {
@@ -160,9 +567,4 @@
 	}
 	
-	if (tz) {
-		tz->tz_minuteswest = 0;
-		tz->tz_dsttime = DST_NONE;
-	}
-	
 	sysarg_t s2 = ktime->seconds2;
 	
@@ -178,5 +580,5 @@
 	} else
 		tv->tv_sec = s1;
-	
+
 	return 0;
 }
@@ -229,4 +631,355 @@
 }
 
+/**
+ * This function first normalizes the provided broken-down time
+ * (moves all values to their proper bounds) and then tries to
+ * calculate the appropriate time_t representation.
+ *
+ * @param tm Broken-down time.
+ * @return time_t representation of the time, undefined value on overflow.
+ */
+time_t mktime(struct tm *tm)
+{
+	// TODO: take DST flag into account
+	// TODO: detect overflow
+
+	_normalize_time(tm, 0);
+	return _secs_since_epoch(tm);
+}
+
+/**
+ * Convert time and date to a string, based on a specified format and
+ * current locale.
+ * 
+ * @param s Buffer to write string to.
+ * @param maxsize Size of the buffer.
+ * @param format Format of the output.
+ * @param tm Broken-down time to format.
+ * @return Number of bytes written.
+ */
+size_t strftime(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct tm *restrict tm)
+{
+	assert(s != NULL);
+	assert(format != NULL);
+	assert(tm != NULL);
+
+	// TODO: use locale
+	static const char *wday_abbr[] = {
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+	};
+	static const char *wday[] = {
+		"Sunday", "Monday", "Tuesday", "Wednesday",
+		"Thursday", "Friday", "Saturday"
+	};
+	static const char *mon_abbr[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+	static const char *mon[] = {
+		"January", "February", "March", "April", "May", "June", "July",
+		"August", "September", "October", "November", "December"
+	};
+	
+	if (maxsize < 1) {
+		return 0;
+	}
+	
+	char *ptr = s;
+	size_t consumed;
+	size_t remaining = maxsize;
+	
+	#define append(...) { \
+		/* FIXME: this requires POSIX-correct snprintf */ \
+		/*        otherwise it won't work with non-ascii chars */ \
+		consumed = snprintf(ptr, remaining, __VA_ARGS__); \
+		if (consumed >= remaining) { \
+			return 0; \
+		} \
+		ptr += consumed; \
+		remaining -= consumed; \
+	}
+	
+	#define recurse(fmt) { \
+		consumed = strftime(ptr, remaining, fmt, tm); \
+		if (consumed == 0) { \
+			return 0; \
+		} \
+		ptr += consumed; \
+		remaining -= consumed; \
+	}
+	
+	#define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
+	    (((hour) == 0) ? 12 : (hour)))
+	
+	while (*format != '\0') {
+		if (*format != '%') {
+			append("%c", *format);
+			format++;
+			continue;
+		}
+		
+		format++;
+		if (*format == '0' || *format == '+') {
+			// TODO: padding
+			format++;
+		}
+		while (isdigit(*format)) {
+			// TODO: padding
+			format++;
+		}
+		if (*format == 'O' || *format == 'E') {
+			// TODO: locale's alternative format
+			format++;
+		}
+		
+		switch (*format) {
+		case 'a':
+			append("%s", wday_abbr[tm->tm_wday]); break;
+		case 'A':
+			append("%s", wday[tm->tm_wday]); break;
+		case 'b':
+			append("%s", mon_abbr[tm->tm_mon]); break;
+		case 'B':
+			append("%s", mon[tm->tm_mon]); break;
+		case 'c':
+			// TODO: locale-specific datetime format
+			recurse("%Y-%m-%d %H:%M:%S"); break;
+		case 'C':
+			append("%02d", (1900 + tm->tm_year) / 100); break;
+		case 'd':
+			append("%02d", tm->tm_mday); break;
+		case 'D':
+			recurse("%m/%d/%y"); break;
+		case 'e':
+			append("%2d", tm->tm_mday); break;
+		case 'F':
+			recurse("%+4Y-%m-%d"); break;
+		case 'g':
+			append("%02d", _wbyear(tm) % 100); break;
+		case 'G':
+			append("%d", _wbyear(tm)); break;
+		case 'h':
+			recurse("%b"); break;
+		case 'H':
+			append("%02d", tm->tm_hour); break;
+		case 'I':
+			append("%02d", TO_12H(tm->tm_hour)); break;
+		case 'j':
+			append("%03d", tm->tm_yday); break;
+		case 'k':
+			append("%2d", tm->tm_hour); break;
+		case 'l':
+			append("%2d", TO_12H(tm->tm_hour)); break;
+		case 'm':
+			append("%02d", tm->tm_mon); break;
+		case 'M':
+			append("%02d", tm->tm_min); break;
+		case 'n':
+			append("\n"); break;
+		case 'p':
+			append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
+		case 'P':
+			append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
+		case 'r':
+			recurse("%I:%M:%S %p"); break;
+		case 'R':
+			recurse("%H:%M"); break;
+		case 's':
+			append("%ld", _secs_since_epoch(tm)); break;
+		case 'S':
+			append("%02d", tm->tm_sec); break;
+		case 't':
+			append("\t"); break;
+		case 'T':
+			recurse("%H:%M:%S"); break;
+		case 'u':
+			append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
+			break;
+		case 'U':
+			append("%02d", _sun_week_number(tm)); break;
+		case 'V':
+			append("%02d", _iso_week_number(tm)); break;
+		case 'w':
+			append("%d", tm->tm_wday); break;
+		case 'W':
+			append("%02d", _mon_week_number(tm)); break;
+		case 'x':
+			// TODO: locale-specific date format
+			recurse("%Y-%m-%d"); break;
+		case 'X':
+			// TODO: locale-specific time format
+			recurse("%H:%M:%S"); break;
+		case 'y':
+			append("%02d", tm->tm_year % 100); break;
+		case 'Y':
+			append("%d", 1900 + tm->tm_year); break;
+		case 'z':
+			// TODO: timezone
+			break;
+		case 'Z':
+			// TODO: timezone
+			break;
+		case '%':
+			append("%%");
+			break;
+		default:
+			/* Invalid specifier, print verbatim. */
+			while (*format != '%') {
+				format--;
+			}
+			append("%%");
+			break;
+		}
+		format++;
+	}
+	
+	#undef append
+	#undef recurse
+	
+	return maxsize - remaining;
+}
+
+
+/** Converts a time value to a broken-down UTC time
+ *
+ * @param time    Time to convert
+ * @param result  Structure to store the result to
+ *
+ * @return        EOK or a negative error code
+ */
+int time_utc2tm(const time_t time, struct tm *restrict result)
+{
+	assert(result != NULL);
+
+	/* Set result to epoch. */
+	result->tm_sec = 0;
+	result->tm_min = 0;
+	result->tm_hour = 0;
+	result->tm_mday = 1;
+	result->tm_mon = 0;
+	result->tm_year = 70; /* 1970 */
+
+	if (_normalize_time(result, time) == -1)
+		return EOVERFLOW;
+
+	return EOK;
+}
+
+/** Converts a time value to a null terminated string of the form
+ *  "Wed Jun 30 21:49:08 1993\n" expressed in UTC.
+ *
+ * @param time   Time to convert.
+ * @param buf    Buffer to store the string to, must be at least
+ *               ASCTIME_BUF_LEN bytes long.
+ *
+ * @return       EOK or a negative error code.
+ */
+int time_utc2str(const time_t time, char *restrict buf)
+{
+	struct tm t;
+	int r;
+
+	if ((r = time_utc2tm(time, &t)) != EOK)
+		return r;
+
+	time_tm2str(&t, buf);
+	return EOK;
+}
+
+
+/**
+ * Converts broken-down time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
+ *
+ * @param timeptr Broken-down time structure.
+ * @param buf     Buffer to store string to, must be at least ASCTIME_BUF_LEN
+ *                bytes long.
+ */
+void time_tm2str(const struct tm *restrict timeptr, char *restrict buf)
+{
+	assert(timeptr != NULL);
+	assert(buf != NULL);
+
+	static const char *wday[] = {
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+	};
+	static const char *mon[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+
+	snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
+	    wday[timeptr->tm_wday],
+	    mon[timeptr->tm_mon],
+	    timeptr->tm_mday, timeptr->tm_hour,
+	    timeptr->tm_min, timeptr->tm_sec,
+	    1900 + timeptr->tm_year);
+}
+
+/**
+ * Converts a time value to a broken-down local time, expressed relative
+ * to the user's specified timezone.
+ *
+ * @param timer     Time to convert.
+ * @param result    Structure to store the result to.
+ *
+ * @return          EOK on success or a negative error code.
+ */
+int time_local2tm(const time_t time, struct tm *restrict result)
+{
+	// TODO: deal with timezone
+	// currently assumes system and all times are in GMT
+
+	/* Set result to epoch. */
+	result->tm_sec = 0;
+	result->tm_min = 0;
+	result->tm_hour = 0;
+	result->tm_mday = 1;
+	result->tm_mon = 0;
+	result->tm_year = 70; /* 1970 */
+
+	if (_normalize_time(result, time) == -1)
+		return EOVERFLOW;
+
+	return EOK;
+}
+
+/**
+ * Converts the calendar time to a null terminated string
+ * of the form "Wed Jun 30 21:49:08 1993\n" expressed relative to the
+ * user's specified timezone.
+ * 
+ * @param timer  Time to convert.
+ * @param buf    Buffer to store the string to. Must be at least
+ *               ASCTIME_BUF_LEN bytes long.
+ *
+ * @return       EOK on success or a negative error code.
+ */
+int time_local2str(const time_t time, char *buf)
+{
+	struct tm loctime;
+	int r;
+
+	if ((r = time_local2tm(time, &loctime)) != EOK)
+		return r;
+
+	time_tm2str(&loctime, buf);
+
+	return EOK;
+}
+
+/**
+ * Calculate the difference between two times, in seconds.
+ * 
+ * @param time1 First time.
+ * @param time0 Second time.
+ * @return Time in seconds.
+ */
+double difftime(time_t time1, time_t time0)
+{
+	return (double) (time1 - time0);
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/tls.c
===================================================================
--- uspace/lib/c/generic/tls.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/generic/tls.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -42,4 +42,5 @@
 #include <str.h>
 #include <align.h>
+#include <unistd.h>
 
 /** Create TLS (Thread Local Storage) data structures.
@@ -57,4 +58,6 @@
 	
 	tcb = __alloc_tls(&data, tls_size);
+	if (!tcb)
+		return NULL;
 	
 	/*
@@ -89,5 +92,8 @@
 
 	result = malloc(sizeof(tcb_t) + size);
+	if (!result)
+		return NULL;
 	*data = ((void *)result) + sizeof(tcb_t);
+
 	return result;
 }
@@ -118,5 +124,6 @@
 	size = ALIGN_UP(size, &_tls_alignment);
 	*data = memalign((uintptr_t) &_tls_alignment, sizeof(tcb_t) + size);
-
+	if (!*data)
+		return NULL;
 	tcb = (tcb_t *) (*data + size);
 	tcb->self = tcb;
Index: uspace/lib/c/include/device/battery_dev.h
===================================================================
--- uspace/lib/c/include/device/battery_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/include/device/battery_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVICE_BATTERY_DEV_H_
+#define LIBC_DEVICE_BATTERY_DEV_H_
+
+#include <async.h>
+
+typedef enum {
+	BATTERY_OK,
+	BATTERY_LOW,
+	BATTERY_NOT_PRESENT,
+} battery_status_t;
+
+typedef enum {
+	BATTERY_STATUS_GET = 0,
+	BATTERY_CHARGE_LEVEL_GET,
+} battery_dev_method_t;
+
+extern int battery_status_get(async_sess_t *, battery_status_t *);
+extern int battery_charge_level_get(async_sess_t *, int *);
+
+#endif
+
Index: uspace/lib/c/include/device/clock_dev.h
===================================================================
--- uspace/lib/c/include/device/clock_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/include/device/clock_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVICE_CLOCK_DEV_H_
+#define LIBC_DEVICE_CLOCK_DEV_H_
+
+#include <async.h>
+#include <time.h>
+
+typedef enum {
+	CLOCK_DEV_TIME_GET = 0,
+	CLOCK_DEV_TIME_SET,
+} clock_dev_method_t;
+
+extern int clock_dev_time_get(async_sess_t *, struct tm *);
+extern int clock_dev_time_set(async_sess_t *, struct tm *);
+
+#endif
+
Index: uspace/lib/c/include/io/con_srv.h
===================================================================
--- uspace/lib/c/include/io/con_srv.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/include/io/con_srv.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_CON_SRV_H_
+#define LIBC_CON_SRV_H_
+
+#include <adt/list.h>
+#include <async.h>
+#include <fibril_synch.h>
+#include <io/color.h>
+#include <io/concaps.h>
+#include <io/kbd_event.h>
+#include <io/pixel.h>
+#include <io/style.h>
+#include <bool.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+typedef struct con_ops con_ops_t;
+
+/** Service setup (per sevice) */
+typedef struct {
+	con_ops_t *ops;
+	void *sarg;
+	/** Period to check for abort */
+	suseconds_t abort_timeout;
+	bool aborted;
+} con_srvs_t;
+
+/** Server structure (per client session) */
+typedef struct {
+	con_srvs_t *srvs;
+	async_sess_t *client_sess;
+	void *carg;
+} con_srv_t;
+
+typedef struct con_ops {
+	int (*open)(con_srvs_t *, con_srv_t *);
+	int (*close)(con_srv_t *);
+	int (*read)(con_srv_t *, void *, size_t);
+	int (*write)(con_srv_t *, void *, size_t);
+	void (*sync)(con_srv_t *);
+	void (*clear)(con_srv_t *);
+	void (*set_pos)(con_srv_t *, sysarg_t col, sysarg_t row);
+	int (*get_pos)(con_srv_t *, sysarg_t *, sysarg_t *);
+	int (*get_size)(con_srv_t *, sysarg_t *, sysarg_t *);
+	int (*get_color_cap)(con_srv_t *, console_caps_t *);
+	void (*set_style)(con_srv_t *, console_style_t);
+	void (*set_color)(con_srv_t *, console_color_t, console_color_t,
+	    console_color_attr_t);
+	void (*set_rgb_color)(con_srv_t *, pixel_t, pixel_t);
+	void (*set_cursor_visibility)(con_srv_t *, bool);
+	int (*get_event)(con_srv_t *, kbd_event_t *);
+} con_ops_t;
+
+extern void con_srvs_init(con_srvs_t *);
+
+extern int con_conn(ipc_callid_t, ipc_call_t *, con_srvs_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/concaps.h
===================================================================
--- uspace/lib/c/include/io/concaps.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/include/io/concaps.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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 libcipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_CONCAPS_H_
+#define LIBC_IO_CONCAPS_H_
+
+typedef enum {
+	CONSOLE_CAP_NONE = 0,
+	CONSOLE_CAP_STYLE = 1,
+	CONSOLE_CAP_INDEXED = 2,
+	CONSOLE_CAP_RGB = 4
+} console_caps_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/console.h
===================================================================
--- uspace/lib/c/include/io/console.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/include/io/console.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -37,4 +37,5 @@
 
 #include <sys/time.h>
+#include <io/concaps.h>
 #include <io/kbd_event.h>
 #include <io/keycode.h>
@@ -42,11 +43,4 @@
 #include <bool.h>
 #include <stdio.h>
-
-typedef enum {
-	CONSOLE_CAP_NONE = 0,
-	CONSOLE_CAP_STYLE = 1,
-	CONSOLE_CAP_INDEXED = 2,
-	CONSOLE_CAP_RGB = 4
-} console_caps_t;
 
 /** Console control structure. */
Index: uspace/lib/c/include/io/klog.h
===================================================================
--- uspace/lib/c/include/io/klog.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/include/io/klog.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -38,8 +38,10 @@
 #include <sys/types.h>
 #include <stdarg.h>
+#include <io/verify.h>
 
 extern size_t klog_write(const void *, size_t);
 extern void klog_update(void);
-extern int klog_printf(const char *, ...);
+extern int klog_printf(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 extern int klog_vprintf(const char *, va_list);
 
Index: uspace/lib/c/include/io/log.h
===================================================================
--- uspace/lib/c/include/io/log.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/include/io/log.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -36,20 +36,46 @@
 
 #include <stdarg.h>
+#include <inttypes.h>
+#include <io/verify.h>
 
+/** Log message level. */
 typedef enum {
+	/** Fatal error, program is not able to recover at all. */
 	LVL_FATAL,
+	/** Serious error but the program can recover from it. */
 	LVL_ERROR,
+	/** Easily recoverable problem. */
 	LVL_WARN,
+	/** Information message that ought to be printed by default. */
 	LVL_NOTE,
+	/** Debugging purpose message. */
 	LVL_DEBUG,
+	/** More detailed debugging message. */
 	LVL_DEBUG2,
-
+	
 	/** For checking range of values */
 	LVL_LIMIT
 } log_level_t;
 
-extern int log_init(const char *, log_level_t);
-extern void log_msg(log_level_t, const char *, ...);
-extern void log_msgv(log_level_t, const char *, va_list);
+/** Log itself (logging target). */
+typedef sysarg_t log_t;
+/** Formatting directive for printing log_t. */
+#define PRIlogctx PRIxn
+
+/** Default log (target). */
+#define LOG_DEFAULT ((log_t) -1)
+
+/** Use when creating new top-level log. */
+#define LOG_NO_PARENT ((log_t) 0)
+
+extern const char *log_level_str(log_level_t);
+extern int log_level_from_str(const char *, log_level_t *);
+
+extern int log_init(const char *);
+extern log_t log_create(const char *, log_t);
+
+extern void log_msg(log_t, log_level_t, const char *, ...)
+    PRINTF_ATTRIBUTE(3, 4);
+extern void log_msgv(log_t, log_level_t, const char *, va_list);
 
 #endif
Index: uspace/lib/c/include/io/logctl.h
===================================================================
--- uspace/lib/c/include/io/logctl.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/include/io/logctl.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011-2012 Vojtech Horky
+ * 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 libc
+ * @{
+ */
+
+#ifndef LIBC_IO_LOGCTL_H_
+#define LIBC_IO_LOGCTL_H_
+
+#include <io/log.h>
+
+extern int logctl_set_default_level(log_level_t);
+extern int logctl_set_log_level(const char *, log_level_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/verify.h
===================================================================
--- uspace/lib/c/include/io/verify.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/include/io/verify.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_VERIFY_H_
+#define LIBC_IO_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: uspace/lib/c/include/ipc/console.h
===================================================================
--- uspace/lib/c/include/ipc/console.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/include/ipc/console.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -43,10 +43,10 @@
 	CONSOLE_GET_EVENT,
 	CONSOLE_GET_POS,
-	CONSOLE_GOTO,
+	CONSOLE_SET_POS,
 	CONSOLE_CLEAR,
 	CONSOLE_SET_STYLE,
 	CONSOLE_SET_COLOR,
 	CONSOLE_SET_RGB_COLOR,
-	CONSOLE_CURSOR_VISIBILITY
+	CONSOLE_SET_CURSOR_VISIBILITY
 } console_request_t;
 
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -54,4 +54,8 @@
 	/** Interface provided by USB HID devices. */
 	USBHID_DEV_IFACE,
+	/** Interface provided by Real Time Clock devices */
+	CLOCK_DEV_IFACE,
+	/** Interface provided by battery powered devices */
+	BATTERY_DEV_IFACE,
 	/** Interface provided by AHCI devices. */
 	AHCI_DEV_IFACE,
Index: uspace/lib/c/include/ipc/logger.h
===================================================================
--- uspace/lib/c/include/ipc/logger.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/c/include/ipc/logger.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 libc
+ * @{
+ */
+
+#ifndef LIBC_IPC_LOGGER_H_
+#define LIBC_IPC_LOGGER_H_
+
+#include <ipc/common.h>
+
+typedef enum {
+	/** Set (global) default displayed logging level.
+	 *
+	 * Arguments: new log level.
+	 * Returns: error code
+	 */
+	LOGGER_CONTROL_SET_DEFAULT_LEVEL = IPC_FIRST_USER_METHOD,
+	/** Set displayed level for given log.
+	 *
+	 * Arguments: new log level.
+	 * Returns: error code
+	 * Followed by: string with full log name.
+	 */
+	LOGGER_CONTROL_SET_LOG_LEVEL
+} logger_control_request_t;
+
+typedef enum {
+	/** Create new log.
+	 *
+	 * Arguments: parent log id (0 for top-level log).
+	 * Returns: error code, log id
+	 * Followed by: string with log name.
+	 */
+	LOGGER_WRITER_CREATE_LOG = IPC_FIRST_USER_METHOD,
+	/** Write a message to a given log.
+	 *
+	 * Arguments: log id, message severity level (log_level_t)
+	 * Returns: error code
+	 * Followed by: string with the message.
+	 */
+	LOGGER_WRITER_MESSAGE
+} logger_writer_request_t;
+
+typedef enum {
+	/** Interface for controlling logger behavior. */
+	LOGGER_INTERFACE_CONTROL,
+	/** Interface for servers writing to the log. */
+	LOGGER_INTERFACE_WRITER
+} logger_interface_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/include/ipc/services.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -45,4 +45,5 @@
 	SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
 	SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
+	SERVICE_LOGGER     = FOURCC('l', 'o', 'g', 'g'),
 	SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
 	SERVICE_IRC        = FOURCC('i', 'r', 'c', ' '),
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/include/stdio.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -39,15 +39,5 @@
 #include <stdarg.h>
 #include <str.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 <io/verify.h>
 
 #define EOF  (-1)
Index: uspace/lib/c/include/sys/time.h
===================================================================
--- uspace/lib/c/include/sys/time.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/c/include/sys/time.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -1,4 +1,6 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2011 Jiri Zarevucky
  * All rights reserved.
  *
@@ -39,4 +41,5 @@
 
 #define DST_NONE 0
+#define ASCTIME_BUF_LEN 26
 
 typedef long time_t;
@@ -45,4 +48,16 @@
 typedef uint32_t useconds_t;
 typedef uint32_t mseconds_t;
+
+struct tm {
+	int tm_sec;         /* Seconds [0,60]. */
+	int tm_min;         /* Minutes [0,59]. */
+	int tm_hour;        /* Hour [0,23]. */
+	int tm_mday;        /* Day of month [1,31]. */
+	int tm_mon;         /* Month of year [0,11]. */
+	int tm_year;        /* Years since 1900. */
+	int tm_wday;        /* Day of week [0,6] (Sunday = 0). */
+	int tm_yday;        /* Day of year [0,365]. */
+	int tm_isdst;       /* Daylight Savings flag. */
+};
 
 struct timeval {
@@ -61,6 +76,17 @@
 extern int tv_gteq(struct timeval *tv1, struct timeval *tv2);
 extern int gettimeofday(struct timeval *tv, struct timezone *tz);
+extern int getuptime(struct timeval *tv);
 
 extern void udelay(useconds_t);
+
+extern time_t mktime(struct tm *tm);
+extern int time_utc2tm(const time_t time, struct tm *result);
+extern int time_utc2str(const time_t time, char *buf);
+extern void time_tm2str(const struct tm *timeptr, char *buf);
+extern int time_local2tm(const time_t time, struct tm *result);
+extern int time_local2str(const time_t time, char *buf);
+extern double difftime(time_t time1, time_t time0);
+extern size_t strftime(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct tm *restrict tm);
 
 #endif
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/drv/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -46,4 +46,6 @@
 	generic/remote_usbhc.c \
 	generic/remote_usbhid.c \
+	generic/remote_clock_dev.c \
+	generic/remote_battery_dev.c \
 	generic/remote_ahci.c
 
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/drv/generic/dev_iface.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -41,4 +41,6 @@
 #include "remote_hw_res.h"
 #include "remote_char_dev.h"
+#include "remote_clock_dev.h"
+#include "remote_battery_dev.h"
 #include "remote_graph_dev.h"
 #include "remote_nic.h"
@@ -59,4 +61,6 @@
 		&remote_usbhc_iface,
 		&remote_usbhid_iface,
+		&remote_clock_dev_iface,
+		&remote_battery_dev_iface,
 		&remote_ahci_iface
 	}
Index: uspace/lib/drv/generic/log.c
===================================================================
--- uspace/lib/drv/generic/log.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/drv/generic/log.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -38,10 +38,9 @@
  *
  * @param drv_name Driver name, will be printed as part of message
- * @param level    Minimum message level to print
  *
  */
-int ddf_log_init(const char *drv_name, log_level_t level)
+int ddf_log_init(const char *drv_name)
 {
-	return log_init(drv_name, level);
+	return log_init(drv_name);
 }
 
@@ -59,5 +58,5 @@
 	
 	va_start(args, fmt);
-	log_msgv(level, fmt, args);
+	log_msgv(LOG_DEFAULT, level, fmt, args);
 	va_end(args);
 }
Index: uspace/lib/drv/generic/remote_battery_dev.c
===================================================================
--- uspace/lib/drv/generic/remote_battery_dev.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/drv/generic/remote_battery_dev.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <ops/battery_dev.h>
+#include <device/battery_dev.h>
+#include <ddf/driver.h>
+
+static void remote_battery_status_get(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+static void remote_battery_charge_level_get(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+
+/** Remote battery interface operations */
+static remote_iface_func_ptr_t remote_battery_dev_iface_ops[] = {
+	&remote_battery_status_get,
+	&remote_battery_charge_level_get,
+};
+
+/** Remote battery interface structure
+ *
+ * Interface for processing request from remote clients
+ * addressed by the battery interface.
+ *
+ */
+remote_iface_t remote_battery_dev_iface = {
+	.method_count = sizeof(remote_battery_dev_iface_ops) /
+	    sizeof(remote_iface_func_ptr_t),
+	.methods = remote_battery_dev_iface_ops,
+};
+
+/** Process the status_get() request from the remote client
+ *
+ * @param fun    The function from which the battery status is read
+ * @param ops    The local ops structure
+ */
+static void
+remote_battery_status_get(ddf_fun_t *fun, void *ops, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	const battery_dev_ops_t *bops = (battery_dev_ops_t *) ops;
+
+	if (bops->battery_status_get == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	battery_status_t batt_status;
+	const int rc = bops->battery_status_get(fun, &batt_status);
+
+	if (rc != EOK)
+		async_answer_0(callid, rc);
+	else
+		async_answer_1(callid, rc, batt_status);
+}
+
+/** Process the battery_charge_level_get() request from the remote client
+ *
+ * @param fun    The function from which the battery charge level is read
+ * @param ops    The local ops structure
+ *
+ */
+static void
+remote_battery_charge_level_get(ddf_fun_t *fun, void *ops, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	const battery_dev_ops_t *bops = (battery_dev_ops_t *) ops;
+
+	if (bops->battery_charge_level_get == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	int battery_level;
+	const int rc = bops->battery_charge_level_get(fun, &battery_level);
+
+	if (rc != EOK)
+		async_answer_0(callid, rc);
+	else
+		async_answer_1(callid, rc, battery_level);
+}
+
Index: uspace/lib/drv/generic/remote_clock_dev.c
===================================================================
--- uspace/lib/drv/generic/remote_clock_dev.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/drv/generic/remote_clock_dev.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <time.h>
+
+#include <ops/clock_dev.h>
+#include <ddf/driver.h>
+
+static void remote_clock_time_get(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+static void remote_clock_time_set(ddf_fun_t *, void *, ipc_callid_t,
+    ipc_call_t *);
+
+/** Remote clock interface operations */
+static remote_iface_func_ptr_t remote_clock_dev_iface_ops[] = {
+	&remote_clock_time_get,
+	&remote_clock_time_set,
+};
+
+/** Remote clock interface structure
+ *
+ * Interface for processing requests from remote clients
+ * addressed by the clock interface.
+ */
+remote_iface_t remote_clock_dev_iface = {
+	.method_count = sizeof(remote_clock_dev_iface_ops) /
+	    sizeof(remote_iface_func_ptr_t),
+	.methods = remote_clock_dev_iface_ops,
+};
+
+/** Process the time_get() request from the remote client
+ *
+ * @param fun   The function from which the time is read
+ * @param ops   The local ops structure
+ */
+static void
+remote_clock_time_get(ddf_fun_t *fun, void *ops, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	clock_dev_ops_t *clock_dev_ops = (clock_dev_ops_t *) ops;
+	ipc_callid_t cid;
+	struct tm t;
+	int rc;
+	size_t len;
+
+	if (!async_data_read_receive(&cid, &len)) {
+		/* TODO: Handle protocol error */
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (!clock_dev_ops->time_get) {
+		/* The driver does not provide the time_get() functionality */
+		async_answer_0(cid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = (*clock_dev_ops->time_get)(fun, &t);
+
+	if (rc != EOK) {
+		/* Some error occurred */
+		async_answer_0(cid, rc);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	/* The operation was successful */
+	async_data_read_finalize(cid, &t, sizeof(struct tm));
+	async_answer_0(callid, rc);
+}
+
+/** Process the time_set() request from the remote client
+ *
+ * @param fun   The function to which the data are written
+ * @param ops   The local ops structure
+ */
+static void remote_clock_time_set(ddf_fun_t *fun, void *ops,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	clock_dev_ops_t *clock_dev_ops = (clock_dev_ops_t *) ops;
+	int          rc;
+	struct tm    t;
+	ipc_callid_t cid;
+	size_t       len;
+
+	if (!async_data_write_receive(&cid, &len)) {
+		/* TODO: Handle protocol error */
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (!clock_dev_ops->time_set) {
+		/* The driver does not support the time_set() functionality */
+		async_answer_0(cid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	async_data_write_finalize(cid, &t, sizeof(struct tm));
+
+	rc = (*clock_dev_ops->time_set)(fun, &t);
+
+	async_answer_0(callid, rc);
+}
+
+/**
+ * @}
+ */
+
Index: uspace/lib/drv/include/ddf/log.h
===================================================================
--- uspace/lib/drv/include/ddf/log.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/drv/include/ddf/log.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -35,7 +35,9 @@
 
 #include <io/log.h>
+#include <io/verify.h>
 
-extern int ddf_log_init(const char *, log_level_t);
-extern void ddf_msg(log_level_t, const char *, ...);
+extern int ddf_log_init(const char *);
+extern void ddf_msg(log_level_t, const char *, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 
 extern void ddf_dump_buffer(char *, size_t, const void *, size_t, size_t,
Index: uspace/lib/drv/include/ops/battery_dev.h
===================================================================
--- uspace/lib/drv/include/ops/battery_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/drv/include/ops/battery_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_OPS_BATTERY_DEV_H_
+#define LIBDRV_OPS_BATTERY_DEV_H_
+
+#include "../ddf/driver.h"
+#include "device/battery_dev.h"
+
+typedef struct {
+	int (*battery_status_get)(ddf_fun_t *, battery_status_t *);
+	int (*battery_charge_level_get)(ddf_fun_t *, int *);
+} battery_dev_ops_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/ops/clock_dev.h
===================================================================
--- uspace/lib/drv/include/ops/clock_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/drv/include/ops/clock_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_OPS_CLOCK_DEV_H_
+#define LIBDRV_OPS_CLOCK_DEV_H_
+
+#include <time.h>
+#include "../ddf/driver.h"
+
+typedef struct {
+	int (*time_get)(ddf_fun_t *, struct tm *);
+	int (*time_set)(ddf_fun_t *, struct tm *);
+} clock_dev_ops_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/remote_battery_dev.h
===================================================================
--- uspace/lib/drv/include/remote_battery_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/drv/include/remote_battery_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_BATTERY_DEV_H_
+#define LIBDRV_REMOTE_BATTERY_DEV_H_
+
+extern remote_iface_t remote_battery_dev_iface;
+
+#endif
+
+/**
+ * @}
+ */
+
Index: uspace/lib/drv/include/remote_clock_dev.h
===================================================================
--- uspace/lib/drv/include/remote_clock_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/drv/include/remote_clock_dev.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 Maurizio Lombardi
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_CLOCK_DEV_H_
+#define LIBDRV_REMOTE_CLOCK_DEV_H_
+
+extern remote_iface_t remote_clock_dev_iface;
+
+#endif
+
+/**
+ * @}
+ */
+
Index: uspace/lib/ext4/libext4_crc.c
===================================================================
--- uspace/lib/ext4/libext4_crc.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/ext4/libext4_crc.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -33,78 +33,12 @@
 /**
  * @file  libext4_crc.c
- * @brief CRC checksumming implementation from Linux.
  */
 
-#include <byteorder.h>
 #include "libext4.h"
 
-/** CRC table for the CRC-16.
- *
- * The poly is 0x8005 (x^16 + x^15 + x^2 + 1).
- *
- */
-uint16_t const crc16_table[256] = {
-	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
-	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
-	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
-	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
-	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
-	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
-	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
-	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
-	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
-	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
-	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
-	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
-	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
-	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
-	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
-	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
-	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
-	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
-	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
-	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
-	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
-	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
-	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
-	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
-	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
-	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
-	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
-	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
-	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
-	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
-	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
-	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
-};
-
-/** Modify CRC value.
- *
- * @param crc   Current CRC value
- * @param data  New byte of data to be "added" to CRC
- *
- * @return Updated CRC value
- *
- */
-static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data)
-{
-	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
-}
-
-/** Compute the CRC-16 for the data buffer.
- *
- * @param crc    Previous CRC value
- * @param buffer Data pointer
- * @param len    Number of bytes in the buffer
- *
- * @return Updated CRC value
- *
- */
 uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len)
 {
-	while (len--)
-		crc = crc16_byte(crc, *buffer++);
-	
-	return crc;
+	// TODO
+	return 0;
 }
 
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -471,6 +471,4 @@
 
 /** Compute checksum of block group descriptor.
- *
- * It uses crc functions from Linux kernel implementation.
  *
  * @param sb   Superblock
@@ -1284,4 +1282,9 @@
 	block_t *block;
 	while (level > 0) {
+		
+		/* Sparse check */
+		if (current_block == 0)
+			return EOK;
+		
 		int rc = block_get(&block, fs->device, current_block, 0);
 		if (rc != EOK)
Index: uspace/lib/ext4/libext4_hash.c
===================================================================
--- uspace/lib/ext4/libext4_hash.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/ext4/libext4_hash.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -35,285 +35,12 @@
  */
 
+#include "libext4.h"
 #include <errno.h>
-#include <mem.h>
-#include "libext4.h"
 
-#define TEA_DELTA  0x9E3779B9
-
-/* F, G and H are basic MD4 functions: selection, majority, parity */
-#define F(x, y, z)  ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z)  (((x) & (y)) + (((x) ^ (y)) & (z)))
-#define H(x, y, z)  ((x) ^ (y) ^ (z))
-
-/*
- * The generic round function.  The application is so specific that
- * we don't bother protecting all the arguments with parens, as is generally
- * good macro practice, in favor of extra legibility.
- * Rotation is separate from addition to prevent recomputation
- */
-#define ROUND(f, a, b, c, d, x, s) \
-	(a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))
-
-#define K1  0
-#define K2  013240474631UL
-#define K3  015666365641UL
-
-static void tea_transform(uint32_t buf[4], uint32_t const in[])
-{
-	uint32_t sum = 0;
-	uint32_t b0 = buf[0];
-	uint32_t b1 = buf[1];
-	uint32_t a = in[0];
-	uint32_t b = in[1];
-	uint32_t c = in[2];
-	uint32_t d = in[3];
-	
-	int n = 16;
-	
-	do {
-		sum += TEA_DELTA;
-		b0 += ((b1 << 4) + a) ^ (b1 + sum) ^ ((b1 >> 5) + b);
-		b1 += ((b0 << 4) + c) ^ (b0 + sum) ^ ((b0 >> 5) + d);
-	} while (--n);
-	
-	buf[0] += b0;
-	buf[1] += b1;
-}
-
-
-static void half_md4_transform(uint32_t buf[4], const uint32_t in[8])
-{
-	uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-	
-	/* Round 1 */
-	ROUND(F, a, b, c, d, in[0] + K1,  3);
-	ROUND(F, d, a, b, c, in[1] + K1,  7);
-	ROUND(F, c, d, a, b, in[2] + K1, 11);
-	ROUND(F, b, c, d, a, in[3] + K1, 19);
-	ROUND(F, a, b, c, d, in[4] + K1,  3);
-	ROUND(F, d, a, b, c, in[5] + K1,  7);
-	ROUND(F, c, d, a, b, in[6] + K1, 11);
-	ROUND(F, b, c, d, a, in[7] + K1, 19);
-	
-	/* Round 2 */
-	ROUND(G, a, b, c, d, in[1] + K2,  3);
-	ROUND(G, d, a, b, c, in[3] + K2,  5);
-	ROUND(G, c, d, a, b, in[5] + K2,  9);
-	ROUND(G, b, c, d, a, in[7] + K2, 13);
-	ROUND(G, a, b, c, d, in[0] + K2,  3);
-	ROUND(G, d, a, b, c, in[2] + K2,  5);
-	ROUND(G, c, d, a, b, in[4] + K2,  9);
-	ROUND(G, b, c, d, a, in[6] + K2, 13);
-	
-	/* Round 3 */
-	ROUND(H, a, b, c, d, in[3] + K3,  3);
-	ROUND(H, d, a, b, c, in[7] + K3,  9);
-	ROUND(H, c, d, a, b, in[2] + K3, 11);
-	ROUND(H, b, c, d, a, in[6] + K3, 15);
-	ROUND(H, a, b, c, d, in[1] + K3,  3);
-	ROUND(H, d, a, b, c, in[5] + K3,  9);
-	ROUND(H, c, d, a, b, in[0] + K3, 11);
-	ROUND(H, b, c, d, a, in[4] + K3, 15);
-	
-	buf[0] += a;
-	buf[1] += b;
-	buf[2] += c;
-	buf[3] += d;
-}
-
-static uint32_t hash_unsigned(const char *name, int len)
-{
-	uint32_t hash;
-	uint32_t hash0 = 0x12a3fe2d;
-	uint32_t hash1 = 0x37abe8f9;
-	const unsigned char *ucp = (const unsigned char *) name;
-	
-	while (len--) {
-		hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373));
-		
-		if (hash & 0x80000000)
-			hash -= 0x7fffffff;
-		
-		hash1 = hash0;
-		hash0 = hash;
-	}
-	
-	return hash0 << 1;
-}
-
-static uint32_t hash_signed(const char *name, int len)
-{
-	uint32_t hash;
-	uint32_t hash0 = 0x12a3fe2d;
-	uint32_t hash1 = 0x37abe8f9;
-	const signed char *scp = (const signed char *) name;
-	
-	while (len--) {
-		hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373));
-		
-		if (hash & 0x80000000)
-			hash -= 0x7fffffff;
-		
-		hash1 = hash0;
-		hash0 = hash;
-	}
-	
-	return hash0 << 1;
-}
-
-static void str2hashbuf_signed(const char *msg, int len, uint32_t *buf, int num)
-{
-	uint32_t pad, val;
-	int i;
-	const signed char *scp = (const signed char *) msg;
-	
-	pad = (uint32_t) len | ((uint32_t) len << 8);
-	pad |= pad << 16;
-	
-	val = pad;
-	if (len > num * 4)
-		len = num * 4;
-	
-	for (i = 0; i < len; i++) {
-		if ((i % 4) == 0)
-			val = pad;
-		
-		val = ((int) scp[i]) + (val << 8);
-		if ((i % 4) == 3) {
-			*buf++ = val;
-			val = pad;
-			num--;
-		}
-	}
-	
-	if (--num >= 0)
-		*buf++ = val;
-	
-	while (--num >= 0)
-		*buf++ = pad;
-}
-
-static void str2hashbuf_unsigned(const char *msg, int len, uint32_t *buf,
-    int num)
-{
-	uint32_t pad, val;
-	int i;
-	const unsigned char *ucp = (const unsigned char *) msg;
-	
-	pad = (uint32_t) len | ((uint32_t) len << 8);
-	pad |= pad << 16;
-	
-	val = pad;
-	if (len > num * 4)
-		len = num * 4;
-	
-	for (i = 0; i < len; i++) {
-		if ((i % 4) == 0)
-			val = pad;
-		
-		val = ((int) ucp[i]) + (val << 8);
-		if ((i % 4) == 3) {
-			*buf++ = val;
-			val = pad;
-			num--;
-		}
-	}
-	
-	if (--num >= 0)
-		*buf++ = val;
-	
-	while (--num >= 0)
-		*buf++ = pad;
-}
-
-/** Compute hash value of the string.
- *
- * @param hinfo Hash info structure with information about
- *              the algorithm, hash seed and with the place
- *              for the output hash value
- * @param len  Length of the name
- * @param name Name to be hashed
- *
- * @return Error code
- *
- */
 int ext4_hash_string(ext4_hash_info_t *hinfo, int len, const char *name)
 {
-	uint32_t hash = 0;
-	uint32_t minor_hash = 0;
-	const char *p;
-	int i;
-	uint32_t in[8], buf[4];
-	void (*str2hashbuf)(const char *, int, uint32_t *, int) =
-	    str2hashbuf_signed;
-	
-	/* Initialize the default seed for the hash checksum functions */
-	buf[0] = 0x67452301;
-	buf[1] = 0xefcdab89;
-	buf[2] = 0x98badcfe;
-	buf[3] = 0x10325476;
-	
-	/* Check if the seed is all zero's */
-	if (hinfo->seed) {
-		for (i = 0; i < 4; i++) {
-			if (hinfo->seed[i] != 0)
-				break;
-			
-		}
-		
-		if (i < 4)
-			memcpy(buf, hinfo->seed, sizeof(buf));
-	}
-	
-	switch (hinfo->hash_version) {
-	case EXT4_HASH_VERSION_LEGACY_UNSIGNED:
-		hash = hash_unsigned(name, len);
-		break;
-	case EXT4_HASH_VERSION_LEGACY:
-		hash = hash_signed(name, len);
-		break;
-	case EXT4_HASH_VERSION_HALF_MD4_UNSIGNED:
-		str2hashbuf = str2hashbuf_unsigned;
-	case EXT4_HASH_VERSION_HALF_MD4:
-		p = name;
-		
-		while (len > 0) {
-			(*str2hashbuf)(p, len, in, 8);
-			half_md4_transform(buf, in);
-			len -= 32;
-			p += 32;
-		}
-		
-		minor_hash = buf[2];
-		hash = buf[1];
-		break;
-	case EXT4_HASH_VERSION_TEA_UNSIGNED:
-		str2hashbuf = str2hashbuf_unsigned;
-	case EXT4_HASH_VERSION_TEA:
-		p = name;
-		
-		while (len > 0) {
-			(*str2hashbuf)(p, len, in, 4);
-			tea_transform(buf, in);
-			len -= 16;
-			p += 16;
-		}
-		
-		hash = buf[0];
-		minor_hash = buf[1];
-		break;
-	default:
-		hinfo->hash = 0;
-		return EINVAL;
-	}
-	
-	hash = hash & ~1;
-	if (hash == (EXT4_DIRECTORY_HTREE_EOF << 1))
-		hash = (EXT4_DIRECTORY_HTREE_EOF - 1) << 1;
-	
-	hinfo->hash = hash;
-	hinfo->minor_hash = minor_hash;
-	
-	return EOK;
+	// TODO
+	hinfo->hash = 0;
+	return ENOTSUP;
 }
 
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/fs/libfs.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -631,12 +631,7 @@
 						async_answer_0(rid, rc);
 					} else {
-						aoff64_t size = ops->size_get(fn);
-						async_answer_5(rid, fs_handle,
-						    service_id,
-						    ops->index_get(fn),
-						    LOWER32(size),
-						    UPPER32(size),
-						    ops->lnkcnt_get(fn));
-						(void) ops->node_put(fn);
+						(void) ops->node_put(cur);
+						cur = fn;
+						goto out_with_answer;
 					}
 				} else
@@ -715,12 +710,7 @@
 					async_answer_0(rid, rc);
 				} else {
-					aoff64_t size = ops->size_get(fn);
-					async_answer_5(rid, fs_handle,
-					    service_id,
-					    ops->index_get(fn),
-					    LOWER32(size),
-					    UPPER32(size),
-					    ops->lnkcnt_get(fn));
-					(void) ops->node_put(fn);
+					(void) ops->node_put(cur);
+					cur = fn;
+					goto out_with_answer;
 				}
 			} else
Index: uspace/lib/gui/terminal.c
===================================================================
--- uspace/lib/gui/terminal.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/gui/terminal.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -39,6 +39,7 @@
 #include <surface.h>
 #include <gfx/font-8x16.h>
+#include <io/con_srv.h>
+#include <io/concaps.h>
 #include <io/console.h>
-#include <ipc/console.h>
 #include <task.h>
 #include <adt/list.h>
@@ -60,4 +61,44 @@
 
 static LIST_INITIALIZE(terms);
+
+static int term_open(con_srvs_t *, con_srv_t *);
+static int term_close(con_srv_t *);
+static int term_read(con_srv_t *, void *, size_t);
+static int term_write(con_srv_t *, void *, size_t);
+static void term_sync(con_srv_t *);
+static void term_clear(con_srv_t *);
+static void term_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int term_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int term_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int term_get_color_cap(con_srv_t *, console_caps_t *);
+static void term_set_style(con_srv_t *, console_style_t);
+static void term_set_color(con_srv_t *, console_color_t, console_color_t,
+    console_color_attr_t);
+static void term_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
+static void term_set_cursor_visibility(con_srv_t *, bool);
+static int term_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = term_open,
+	.close = term_close,
+	.read = term_read,
+	.write = term_write,
+	.sync = term_sync,
+	.clear = term_clear,
+	.set_pos = term_set_pos,
+	.get_pos = term_get_pos,
+	.get_size = term_get_size,
+	.get_color_cap = term_get_color_cap,
+	.set_style = term_set_style,
+	.set_color = term_set_color,
+	.set_rgb_color = term_set_rgb_color,
+	.set_cursor_visibility = term_set_cursor_visibility,
+	.get_event = term_get_event
+};
+
+static terminal_t *srv_to_terminal(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
 
 static void getterm(const char *svc, const char *app)
@@ -341,39 +382,18 @@
 }
 
-static void term_set_cursor(terminal_t *term, sysarg_t col, sysarg_t row)
-{
-	fibril_mutex_lock(&term->mtx);
-	chargrid_set_cursor(term->frontbuf, col, row);
-	fibril_mutex_unlock(&term->mtx);
-	
-	term_update(term);
-}
-
-static void term_set_cursor_visibility(terminal_t *term, bool visible)
-{
-	fibril_mutex_lock(&term->mtx);
-	chargrid_set_cursor_visibility(term->frontbuf, visible);
-	fibril_mutex_unlock(&term->mtx);
-	
-	term_update(term);
-}
-
-static void term_read(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	char *buf = (char *) malloc(size);
-	if (buf == NULL) {
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
+static int term_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int term_close(con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int term_read(con_srv_t *srv, void *buf, size_t size)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	uint8_t *bbuf = buf;
 	size_t pos = 0;
 	
@@ -386,5 +406,5 @@
 		/* Copy to the buffer remaining characters. */
 		while ((pos < size) && (term->char_remains_len > 0)) {
-			buf[pos] = term->char_remains[0];
+			bbuf[pos] = term->char_remains[0];
 			pos++;
 			
@@ -416,7 +436,5 @@
 	}
 	
-	(void) async_data_read_finalize(callid, buf, size);
-	async_answer_1(iid, EOK, size);
-	free(buf);
+	return size;
 }
 
@@ -449,25 +467,26 @@
 }
 
-static void term_write(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	void *buf;
-	size_t size;
-	int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
-	
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
+static int term_write(con_srv_t *srv, void *data, size_t size)
+{
+	terminal_t *term = srv_to_terminal(srv);
 	
 	size_t off = 0;
 	while (off < size)
-		term_write_char(term, str_decode(buf, &off, size));
-	
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void term_clear(terminal_t *term)
-{
+		term_write_char(term, str_decode(data, &off, size));
+	
+	return size;
+}
+
+static void term_sync(con_srv_t *srv)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	term_update(term);
+}
+
+static void term_clear(con_srv_t *srv)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_clear(term->frontbuf);
@@ -477,18 +496,50 @@
 }
 
-static void term_get_cursor(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	sysarg_t col;
-	sysarg_t row;
-	
-	fibril_mutex_lock(&term->mtx);
-	chargrid_get_cursor(term->frontbuf, &col, &row);
-	fibril_mutex_unlock(&term->mtx);
-	
-	async_answer_2(iid, EOK, col, row);
-}
-
-static void term_set_style(terminal_t *term, console_style_t style)
-{
+static void term_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_set_cursor(term->frontbuf, col, row);
+	fibril_mutex_unlock(&term->mtx);
+	
+	term_update(term);
+}
+
+static int term_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_get_cursor(term->frontbuf, col, row);
+	fibril_mutex_unlock(&term->mtx);
+	
+	return EOK;
+}
+
+static int term_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	*cols = term->cols;
+	*rows = term->rows;
+	fibril_mutex_unlock(&term->mtx);
+	
+	return EOK;
+}
+
+static int term_get_color_cap(con_srv_t *srv, console_caps_t *caps)
+{
+	(void) srv;
+	*caps = TERM_CAPS;
+	
+	return EOK;
+}
+
+static void term_set_style(con_srv_t *srv, console_style_t style)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_style(term->frontbuf, style);
@@ -496,7 +547,9 @@
 }
 
-static void term_set_color(terminal_t *term, console_color_t bgcolor,
+static void term_set_color(con_srv_t *srv, console_color_t bgcolor,
     console_color_t fgcolor, console_color_attr_t attr)
 {
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr);
@@ -504,7 +557,9 @@
 }
 
-static void term_set_rgb_color(terminal_t *term, pixel_t bgcolor,
+static void term_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
     pixel_t fgcolor)
 {
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor);
@@ -512,11 +567,24 @@
 }
 
-static void term_get_event(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
+static void term_set_cursor_visibility(con_srv_t *srv, bool visible)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_set_cursor_visibility(term->frontbuf, visible);
+	fibril_mutex_unlock(&term->mtx);
+	
+	term_update(term);
+}
+
+static int term_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	terminal_t *term = srv_to_terminal(srv);
 	link_t *link = prodcons_consume(&term->input_pc);
-	kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-	
-	async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
-	free(event);
+	kbd_event_t *kevent = list_get_instance(link, kbd_event_t, link);
+	
+	*event = *kevent;
+	free(kevent);
+	return EOK;
 }
 
@@ -612,68 +680,7 @@
 	
 	if (atomic_postinc(&term->refcnt) == 0)
-		term_set_cursor_visibility(term, true);
-	
-	/* Accept the connection */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_READ:
-			term_read(term, callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			term_write(term, callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			term_update(term);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			term_clear(term);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GOTO:
-			term_set_cursor(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_POS:
-			term_get_cursor(term, callid, &call);
-			break;
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, term->cols, term->rows);
-			break;
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, TERM_CAPS);
-			break;
-		case CONSOLE_SET_STYLE:
-			term_set_style(term, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_COLOR:
-			term_set_color(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
-			    IPC_GET_ARG3(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			term_set_rgb_color(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CURSOR_VISIBILITY:
-			term_set_cursor_visibility(term, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_EVENT:
-			term_get_event(term, callid, &call);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
+		chargrid_set_cursor_visibility(term->frontbuf, true);
+	
+	con_conn(iid, icall, &term->srvs);
 }
 
@@ -727,4 +734,8 @@
 	
 	async_set_client_connection(term_connection);
+	con_srvs_init(&term->srvs);
+	term->srvs.ops = &con_ops;
+	term->srvs.sarg = term;
+	
 	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
Index: uspace/lib/gui/terminal.h
===================================================================
--- uspace/lib/gui/terminal.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/gui/terminal.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -41,4 +41,5 @@
 #include <font.h>
 #include <io/chargrid.h>
+#include <io/con_srv.h>
 #include <adt/list.h>
 #include <adt/prodcons.h>
@@ -66,4 +67,5 @@
 	
 	service_id_t dsid;
+	con_srvs_t srvs;
 } terminal_t;
 
Index: uspace/lib/posix/time.c
===================================================================
--- uspace/lib/posix/time.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/posix/time.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -61,338 +61,4 @@
  */
 
-
-
-/* Helper functions ***********************************************************/
-
-#define HOURS_PER_DAY (24)
-#define MINS_PER_HOUR (60)
-#define SECS_PER_MIN (60)
-#define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
-#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
-#define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
-
-/**
- * Checks whether the year is a leap year.
- *
- * @param year Year since 1900 (e.g. for 1970, the value is 70).
- * @return true if year is a leap year, false otherwise
- */
-static bool _is_leap_year(time_t year)
-{
-	year += 1900;
-
-	if (year % 400 == 0)
-		return true;
-	if (year % 100 == 0)
-		return false;
-	if (year % 4 == 0)
-		return true;
-	return false;
-}
-
-/**
- * Returns how many days there are in the given month of the given year.
- * Note that year is only taken into account if month is February.
- *
- * @param year Year since 1900 (can be negative).
- * @param mon Month of the year. 0 for January, 11 for December.
- * @return Number of days in the specified month.
- */
-static int _days_in_month(time_t year, time_t mon)
-{
-	assert(mon >= 0 && mon <= 11);
-
-	static int month_days[] =
-		{ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-	if (mon == 1) {
-		year += 1900;
-		/* february */
-		return _is_leap_year(year) ? 29 : 28;
-	} else {
-		return month_days[mon];
-	}
-}
-
-/**
- * For specified year, month and day of month, returns which day of that year
- * it is.
- *
- * For example, given date 2011-01-03, the corresponding expression is:
- *     _day_of_year(111, 0, 3) == 2
- *
- * @param year Year (year 1900 = 0, can be negative).
- * @param mon Month (January = 0).
- * @param mday Day of month (First day is 1).
- * @return Day of year (First day is 0).
- */
-static int _day_of_year(time_t year, time_t mon, time_t mday)
-{
-	static int mdays[] =
-	    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-	static int leap_mdays[] =
-	    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
-
-	return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
-}
-
-/**
- * Integer division that rounds to negative infinity.
- * Used by some functions in this file.
- *
- * @param op1 Divident.
- * @param op2 Divisor.
- * @return Rounded quotient.
- */
-static time_t _floor_div(time_t op1, time_t op2)
-{
-	if (op1 >= 0 || op1 % op2 == 0) {
-		return op1 / op2;
-	} else {
-		return op1 / op2 - 1;
-	}
-}
-
-/**
- * Modulo that rounds to negative infinity.
- * Used by some functions in this file.
- *
- * @param op1 Divident.
- * @param op2 Divisor.
- * @return Remainder.
- */
-static time_t _floor_mod(time_t op1, time_t op2)
-{
-	int div = _floor_div(op1, op2);
-
-	/* (a / b) * b + a % b == a */
-	/* thus, a % b == a - (a / b) * b */
-
-	int result = op1 - div * op2;
-	
-	/* Some paranoid checking to ensure I didn't make a mistake here. */
-	assert(result >= 0);
-	assert(result < op2);
-	assert(div * op2 + result == op1);
-	
-	return result;
-}
-
-/**
- * Number of days since the Epoch.
- * Epoch is 1970-01-01, which is also equal to day 0.
- *
- * @param year Year (year 1900 = 0, may be negative).
- * @param mon Month (January = 0).
- * @param mday Day of month (first day = 1).
- * @return Number of days since the Epoch.
- */
-static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
-{
-	return (year - 70) * 365 + _floor_div(year - 69, 4) -
-	    _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
-	    _day_of_year(year, mon, mday);
-}
-
-/**
- * Seconds since the Epoch. see also _days_since_epoch().
- * 
- * @param tm Normalized broken-down time.
- * @return Number of seconds since the epoch, not counting leap seconds.
- */
-static time_t _secs_since_epoch(const struct posix_tm *tm)
-{
-	return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
-	    SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
-	    tm->tm_min * SECS_PER_MIN + tm->tm_sec;
-}
-
-/**
- * Which day of week the specified date is.
- * 
- * @param year Year (year 1900 = 0).
- * @param mon Month (January = 0).
- * @param mday Day of month (first = 1).
- * @return Day of week (Sunday = 0).
- */
-static int _day_of_week(time_t year, time_t mon, time_t mday)
-{
-	/* 1970-01-01 is Thursday */
-	return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);
-}
-
-/**
- * Normalizes the broken-down time and optionally adds specified amount of
- * seconds.
- * 
- * @param tm Broken-down time to normalize.
- * @param sec_add Seconds to add.
- * @return 0 on success, -1 on overflow
- */
-static int _normalize_time(struct posix_tm *tm, time_t sec_add)
-{
-	// TODO: DST correction
-
-	/* Set initial values. */
-	time_t sec = tm->tm_sec + sec_add;
-	time_t min = tm->tm_min;
-	time_t hour = tm->tm_hour;
-	time_t day = tm->tm_mday - 1;
-	time_t mon = tm->tm_mon;
-	time_t year = tm->tm_year;
-
-	/* Adjust time. */
-	min += _floor_div(sec, SECS_PER_MIN);
-	sec = _floor_mod(sec, SECS_PER_MIN);
-	hour += _floor_div(min, MINS_PER_HOUR);
-	min = _floor_mod(min, MINS_PER_HOUR);
-	day += _floor_div(hour, HOURS_PER_DAY);
-	hour = _floor_mod(hour, HOURS_PER_DAY);
-
-	/* Adjust month. */
-	year += _floor_div(mon, 12);
-	mon = _floor_mod(mon, 12);
-
-	/* Now the difficult part - days of month. */
-	
-	/* First, deal with whole cycles of 400 years = 146097 days. */
-	year += _floor_div(day, 146097) * 400;
-	day = _floor_mod(day, 146097);
-	
-	/* Then, go in one year steps. */
-	if (mon <= 1) {
-		/* January and February. */
-		while (day > 365) {
-			day -= _is_leap_year(year) ? 366 : 365;
-			year++;
-		}
-	} else {
-		/* Rest of the year. */
-		while (day > 365) {
-			day -= _is_leap_year(year + 1) ? 366 : 365;
-			year++;
-		}
-	}
-	
-	/* Finally, finish it off month per month. */
-	while (day >= _days_in_month(year, mon)) {
-		day -= _days_in_month(year, mon);
-		mon++;
-		if (mon >= 12) {
-			mon -= 12;
-			year++;
-		}
-	}
-	
-	/* Calculate the remaining two fields. */
-	tm->tm_yday = _day_of_year(year, mon, day + 1);
-	tm->tm_wday = _day_of_week(year, mon, day + 1);
-	
-	/* And put the values back to the struct. */
-	tm->tm_sec = (int) sec;
-	tm->tm_min = (int) min;
-	tm->tm_hour = (int) hour;
-	tm->tm_mday = (int) day + 1;
-	tm->tm_mon = (int) mon;
-	
-	/* Casts to work around libc brain-damage. */
-	if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {
-		tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);
-		return -1;
-	}
-	
-	tm->tm_year = (int) year;
-	return 0;
-}
-
-/**
- * Which day the week-based year starts on, relative to the first calendar day.
- * E.g. if the year starts on December 31st, the return value is -1.
- *
- * @param Year since 1900.
- * @return Offset of week-based year relative to calendar year.
- */
-static int _wbyear_offset(int year)
-{
-	int start_wday = _day_of_week(year, 0, 1);
-	return _floor_mod(4 - start_wday, 7) - 3;
-}
-
-/**
- * Returns week-based year of the specified time.
- *
- * @param tm Normalized broken-down time.
- * @return Week-based year.
- */
-static int _wbyear(const struct posix_tm *tm)
-{
-	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
-	if (day < 0) {
-		/* Last week of previous year. */
-		return tm->tm_year - 1;
-	}
-	if (day > 364 + _is_leap_year(tm->tm_year)) {
-		/* First week of next year. */
-		return tm->tm_year + 1;
-	}
-	/* All the other days are in the calendar year. */
-	return tm->tm_year;
-}
-
-/**
- * Week number of the year, assuming weeks start on sunday.
- * The first Sunday of January is the first day of week 1;
- * days in the new year before this are in week 0.
- *
- * @param tm Normalized broken-down time.
- * @return The week number (0 - 53).
- */
-static int _sun_week_number(const struct posix_tm *tm)
-{
-	int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
-	return (tm->tm_yday - first_day + 7) / 7;
-}
-
-/**
- * Week number of the year, assuming weeks start on monday.
- * If the week containing January 1st has four or more days in the new year,
- * then it is considered week 1. Otherwise, it is the last week of the previous
- * year, and the next week is week 1. Both January 4th and the first Thursday
- * of January are always in week 1.
- *
- * @param tm Normalized broken-down time.
- * @return The week number (1 - 53).
- */
-static int _iso_week_number(const struct posix_tm *tm)
-{
-	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
-	if (day < 0) {
-		/* Last week of previous year. */
-		return 53;
-	}
-	if (day > 364 + _is_leap_year(tm->tm_year)) {
-		/* First week of next year. */
-		return 1;
-	}
-	/* All the other days give correct answer. */
-	return (day / 7 + 1);
-}
-
-/**
- * Week number of the year, assuming weeks start on monday.
- * The first Monday of January is the first day of week 1;
- * days in the new year before this are in week 0. 
- *
- * @param tm Normalized broken-down time.
- * @return The week number (0 - 53).
- */
-static int _mon_week_number(const struct posix_tm *tm)
-{
-	int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
-	return (tm->tm_yday - first_day + 7) / 7;
-}
-
-/******************************************************************************/
-
 int posix_daylight;
 long posix_timezone;
@@ -412,47 +78,4 @@
 
 /**
- * Calculate the difference between two times, in seconds.
- * 
- * @param time1 First time.
- * @param time0 Second time.
- * @return Time in seconds.
- */
-double posix_difftime(time_t time1, time_t time0)
-{
-	return (double) (time1 - time0);
-}
-
-/**
- * This function first normalizes the provided broken-down time
- * (moves all values to their proper bounds) and then tries to
- * calculate the appropriate time_t representation.
- *
- * @param tm Broken-down time.
- * @return time_t representation of the time, undefined value on overflow.
- */
-time_t posix_mktime(struct posix_tm *tm)
-{
-	// TODO: take DST flag into account
-	// TODO: detect overflow
-
-	_normalize_time(tm, 0);
-	return _secs_since_epoch(tm);
-}
-
-/**
- * Converts a time value to a broken-down UTC time.
- *
- * @param timer Time to convert.
- * @return Normalized broken-down time in UTC, NULL on overflow.
- */
-struct posix_tm *posix_gmtime(const time_t *timer)
-{
-	assert(timer != NULL);
-
-	static struct posix_tm result;
-	return posix_gmtime_r(timer, &result);
-}
-
-/**
  * Converts a time value to a broken-down UTC time.
  * 
@@ -461,20 +84,10 @@
  * @return Value of result on success, NULL on overflow.
  */
-struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
-    struct posix_tm *restrict result)
-{
-	assert(timer != NULL);
-	assert(result != NULL);
-
-	/* Set result to epoch. */
-	result->tm_sec = 0;
-	result->tm_min = 0;
-	result->tm_hour = 0;
-	result->tm_mday = 1;
-	result->tm_mon = 0;
-	result->tm_year = 70; /* 1970 */
-
-	if (_normalize_time(result, *timer) == -1) {
-		errno = EOVERFLOW;
+struct tm *posix_gmtime_r(const time_t *restrict timer,
+    struct tm *restrict result)
+{
+	int rc = time_utc2tm(*timer, result);
+	if (rc != EOK) {
+		errno = rc;
 		return NULL;
 	}
@@ -484,13 +97,16 @@
 
 /**
- * Converts a time value to a broken-down local time.
- *
- * @param timer Time to convert.
- * @return Normalized broken-down time in local timezone, NULL on overflow.
- */
-struct posix_tm *posix_localtime(const time_t *timer)
-{
-	static struct posix_tm result;
-	return posix_localtime_r(timer, &result);
+ * Converts a time value to a broken-down UTC time.
+ * (non reentrant version)
+ *
+ * @param timep  Time to convert
+ * @return       Pointer to a statically allocated structure that stores
+ *               the result, NULL in case of error.
+ */
+struct tm *posix_gmtime(const time_t *restrict timep)
+{
+	static struct tm result;
+
+	return posix_gmtime_r(timep, &result);
 }
 
@@ -502,6 +118,6 @@
  * @return Value of result on success, NULL on overflow.
  */
-struct posix_tm *posix_localtime_r(const time_t *restrict timer,
-    struct posix_tm *restrict result)
+struct tm *posix_localtime_r(const time_t *restrict timer,
+    struct tm *restrict result)
 {
 	// TODO: deal with timezone
@@ -511,14 +127,16 @@
 
 /**
- * Converts broken-down time to a string in format
- * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
- *
- * @param timeptr Broken-down time structure.
- * @return Pointer to a statically allocated string.
- */
-char *posix_asctime(const struct posix_tm *timeptr)
-{
-	static char buf[ASCTIME_BUF_LEN];
-	return posix_asctime_r(timeptr, buf);
+ * Converts a time value to a broken-down local time.
+ * (non reentrant version)
+ *
+ * @param timep    Time to convert.
+ * @return         Pointer to a statically allocated structure that stores
+ *                 the result, NULL in case of error.
+ */
+struct tm *posix_localtime(const time_t *restrict timep)
+{
+	static struct tm result;
+
+	return posix_localtime_r(timep, &result);
 }
 
@@ -532,250 +150,61 @@
  * @return Value of buf.
  */
-char *posix_asctime_r(const struct posix_tm *restrict timeptr,
+char *posix_asctime_r(const struct tm *restrict timeptr,
     char *restrict buf)
 {
-	assert(timeptr != NULL);
-	assert(buf != NULL);
-
-	static const char *wday[] = {
-		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-	};
-	static const char *mon[] = {
-		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-	};
-
-	snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
-	    wday[timeptr->tm_wday],
-	    mon[timeptr->tm_mon],
-	    timeptr->tm_mday, timeptr->tm_hour,
-	    timeptr->tm_min, timeptr->tm_sec,
-	    1900 + timeptr->tm_year);
-
+	time_tm2str(timeptr, buf);
 	return buf;
 }
 
 /**
- * Equivalent to asctime(localtime(clock)).
- * 
- * @param timer Time to convert.
- * @return Pointer to a statically allocated string holding the date.
- */
-char *posix_ctime(const time_t *timer)
-{
-	struct posix_tm *loctime = posix_localtime(timer);
-	if (loctime == NULL) {
-		return NULL;
-	}
-	return posix_asctime(loctime);
-}
-
-/**
- * Reentrant variant of ctime().
+ * Convers broken-down time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
+ * (non reentrant version)
+ *
+ * @param timeptr    Broken-down time structure.
+ * @return           Pointer to a statically allocated buffer that stores
+ *                   the result, NULL in case of error.
+ */
+char *posix_asctime(const struct tm *restrict timeptr)
+{
+	static char buf[ASCTIME_BUF_LEN];
+
+	return posix_asctime_r(timeptr, buf);
+}
+
+/**
+ * Converts the calendar time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n" (Obsolete)
  * 
  * @param timer Time to convert.
  * @param buf Buffer to store string to. Must be at least ASCTIME_BUF_LEN
  *     bytes long.
- * @return Pointer to buf on success, NULL on falure.
+ * @return Pointer to buf on success, NULL on failure.
  */
 char *posix_ctime_r(const time_t *timer, char *buf)
 {
-	struct posix_tm loctime;
-	if (posix_localtime_r(timer, &loctime) == NULL) {
+	int r = time_local2str(*timer, buf);
+	if (r != EOK) {
+		errno = r;
 		return NULL;
 	}
-	return posix_asctime_r(&loctime, buf);
-}
-
-/**
- * Convert time and date to a string, based on a specified format and
- * current locale.
- * 
- * @param s Buffer to write string to.
- * @param maxsize Size of the buffer.
- * @param format Format of the output.
- * @param tm Broken-down time to format.
- * @return Number of bytes written.
- */
-size_t posix_strftime(char *restrict s, size_t maxsize,
-    const char *restrict format, const struct posix_tm *restrict tm)
-{
-	assert(s != NULL);
-	assert(format != NULL);
-	assert(tm != NULL);
-
-	// TODO: use locale
-	static const char *wday_abbr[] = {
-		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-	};
-	static const char *wday[] = {
-		"Sunday", "Monday", "Tuesday", "Wednesday",
-		"Thursday", "Friday", "Saturday"
-	};
-	static const char *mon_abbr[] = {
-		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-	};
-	static const char *mon[] = {
-		"January", "February", "March", "April", "May", "June", "July",
-		"August", "September", "October", "November", "December"
-	};
-	
-	if (maxsize < 1) {
-		return 0;
-	}
-	
-	char *ptr = s;
-	size_t consumed;
-	size_t remaining = maxsize;
-	
-	#define append(...) { \
-		/* FIXME: this requires POSIX-correct snprintf */ \
-		/*        otherwise it won't work with non-ascii chars */ \
-		consumed = snprintf(ptr, remaining, __VA_ARGS__); \
-		if (consumed >= remaining) { \
-			return 0; \
-		} \
-		ptr += consumed; \
-		remaining -= consumed; \
-	}
-	
-	#define recurse(fmt) { \
-		consumed = posix_strftime(ptr, remaining, fmt, tm); \
-		if (consumed == 0) { \
-			return 0; \
-		} \
-		ptr += consumed; \
-		remaining -= consumed; \
-	}
-	
-	#define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
-	    (((hour) == 0) ? 12 : (hour)))
-	
-	while (*format != '\0') {
-		if (*format != '%') {
-			append("%c", *format);
-			format++;
-			continue;
-		}
-		
-		format++;
-		if (*format == '0' || *format == '+') {
-			// TODO: padding
-			format++;
-		}
-		while (isdigit(*format)) {
-			// TODO: padding
-			format++;
-		}
-		if (*format == 'O' || *format == 'E') {
-			// TODO: locale's alternative format
-			format++;
-		}
-		
-		switch (*format) {
-		case 'a':
-			append("%s", wday_abbr[tm->tm_wday]); break;
-		case 'A':
-			append("%s", wday[tm->tm_wday]); break;
-		case 'b':
-			append("%s", mon_abbr[tm->tm_mon]); break;
-		case 'B':
-			append("%s", mon[tm->tm_mon]); break;
-		case 'c':
-			// TODO: locale-specific datetime format
-			recurse("%Y-%m-%d %H:%M:%S"); break;
-		case 'C':
-			append("%02d", (1900 + tm->tm_year) / 100); break;
-		case 'd':
-			append("%02d", tm->tm_mday); break;
-		case 'D':
-			recurse("%m/%d/%y"); break;
-		case 'e':
-			append("%2d", tm->tm_mday); break;
-		case 'F':
-			recurse("%+4Y-%m-%d"); break;
-		case 'g':
-			append("%02d", _wbyear(tm) % 100); break;
-		case 'G':
-			append("%d", _wbyear(tm)); break;
-		case 'h':
-			recurse("%b"); break;
-		case 'H':
-			append("%02d", tm->tm_hour); break;
-		case 'I':
-			append("%02d", TO_12H(tm->tm_hour)); break;
-		case 'j':
-			append("%03d", tm->tm_yday); break;
-		case 'k':
-			append("%2d", tm->tm_hour); break;
-		case 'l':
-			append("%2d", TO_12H(tm->tm_hour)); break;
-		case 'm':
-			append("%02d", tm->tm_mon); break;
-		case 'M':
-			append("%02d", tm->tm_min); break;
-		case 'n':
-			append("\n"); break;
-		case 'p':
-			append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
-		case 'P':
-			append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
-		case 'r':
-			recurse("%I:%M:%S %p"); break;
-		case 'R':
-			recurse("%H:%M"); break;
-		case 's':
-			append("%ld", _secs_since_epoch(tm)); break;
-		case 'S':
-			append("%02d", tm->tm_sec); break;
-		case 't':
-			append("\t"); break;
-		case 'T':
-			recurse("%H:%M:%S"); break;
-		case 'u':
-			append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); break;
-		case 'U':
-			append("%02d", _sun_week_number(tm)); break;
-		case 'V':
-			append("%02d", _iso_week_number(tm)); break;
-		case 'w':
-			append("%d", tm->tm_wday); break;
-		case 'W':
-			append("%02d", _mon_week_number(tm)); break;
-		case 'x':
-			// TODO: locale-specific date format
-			recurse("%Y-%m-%d"); break;
-		case 'X':
-			// TODO: locale-specific time format
-			recurse("%H:%M:%S"); break;
-		case 'y':
-			append("%02d", tm->tm_year % 100); break;
-		case 'Y':
-			append("%d", 1900 + tm->tm_year); break;
-		case 'z':
-			// TODO: timezone
-			break;
-		case 'Z':
-			// TODO: timezone
-			break;
-		case '%':
-			append("%%");
-			break;
-		default:
-			/* Invalid specifier, print verbatim. */
-			while (*format != '%') {
-				format--;
-			}
-			append("%%");
-			break;
-		}
-		format++;
-	}
-	
-	#undef append
-	#undef recurse
-	
-	return maxsize - remaining;
+
+	return buf;
+}
+
+/**
+ * Converts the calendar time to a string in format
+ * "Sun Jan 1 00:00:00 1970\n" (Obsolete)
+ * (non reentrant version)
+ *
+ * @param timep    Time to convert.
+ * @return         Pointer to a statically allocated buffer that stores
+ *                 the result, NULL in case of error.
+ */
+char *posix_ctime(const time_t *timep)
+{
+	static char buf[ASCTIME_BUF_LEN];
+
+	return posix_ctime_r(timep, buf);
 }
 
@@ -894,5 +323,6 @@
 	stats_task_t *task_stats = stats_get_task(task_get_id());
 	if (task_stats) {
-		total_cycles = (posix_clock_t) (task_stats->kcycles + task_stats->ucycles);
+		total_cycles = (posix_clock_t) (task_stats->kcycles +
+		    task_stats->ucycles);
 		free(task_stats);
 		task_stats = 0;
Index: uspace/lib/posix/time.h
===================================================================
--- uspace/lib/posix/time.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/posix/time.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -63,21 +63,6 @@
 #endif
 
-#undef ASCTIME_BUF_LEN
-#define ASCTIME_BUF_LEN 26
-
 #undef CLOCK_REALTIME
 #define CLOCK_REALTIME ((posix_clockid_t) 0)
-
-struct posix_tm {
-	int tm_sec;         /* Seconds [0,60]. */
-	int tm_min;         /* Minutes [0,59]. */
-	int tm_hour;        /* Hour [0,23]. */
-	int tm_mday;        /* Day of month [1,31]. */
-	int tm_mon;         /* Month of year [0,11]. */
-	int tm_year;        /* Years since 1900. */
-	int tm_wday;        /* Day of week [0,6] (Sunday = 0). */
-	int tm_yday;        /* Day of year [0,365]. */
-	int tm_isdst;       /* Daylight Savings flag. */
-};
 
 struct posix_timespec {
@@ -99,24 +84,18 @@
 extern void posix_tzset(void);
 
-/* Elapsed Time */
-extern double posix_difftime(time_t time1, time_t time0);
-
 /* Broken-down Time */
-extern time_t posix_mktime(struct posix_tm *tm);
-extern struct posix_tm *posix_gmtime(const time_t *timer);
-extern struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
-    struct posix_tm *restrict result);
-extern struct posix_tm *posix_localtime(const time_t *timer);
-extern struct posix_tm *posix_localtime_r(const time_t *restrict timer,
-    struct posix_tm *restrict result);
+extern struct tm *posix_gmtime_r(const time_t *restrict timer,
+    struct tm *restrict result);
+extern struct tm *posix_gmtime(const time_t *restrict timep);
+extern struct tm *posix_localtime_r(const time_t *restrict timer,
+    struct tm *restrict result);
+extern struct tm *posix_localtime(const time_t *restrict timep);
 
 /* Formatting Calendar Time */
-extern char *posix_asctime(const struct posix_tm *timeptr);
-extern char *posix_asctime_r(const struct posix_tm *restrict timeptr,
+extern char *posix_asctime_r(const struct tm *restrict timeptr,
     char *restrict buf);
+extern char *posix_asctime(const struct tm *restrict timeptr);
+extern char *posix_ctime_r(const time_t *timer, char *buf);
 extern char *posix_ctime(const time_t *timer);
-extern char *posix_ctime_r(const time_t *timer, char *buf);
-extern size_t posix_strftime(char *restrict s, size_t maxsize,
-    const char *restrict format, const struct posix_tm *restrict tm);
 
 /* Clocks */
@@ -134,27 +113,22 @@
 
 #ifndef LIBPOSIX_INTERNAL
-	#define tm posix_tm
-	#define timespec posix_timespec
-	#define itimerspec posix_itimerspec
-	#define timer_t posix_timer_t
+	#define timespec    posix_timespec
+	#define itimerspec  posix_itimerspec
+	#define timer_t     posix_timer_t
 
-	#define daylight posix_daylight
-	#define timezone posix_timezone
-	#define tzname posix_tzname
-	#define tzset posix_tzset
+	#define daylight    posix_daylight
+	#define timezone    posix_timezone
+	#define tzname      posix_tzname
+	#define tzset       posix_tzset
 
-	#define difftime posix_difftime
+	#define gmtime_r    posix_gmtime_r
+	#define gmtime      posix_gmtime
+	#define localtime_r posix_localtime_r
+	#define localtime   posix_localtime
 
-	#define mktime posix_mktime
-	#define gmtime posix_gmtime
-	#define gmtime_r posix_gmtime_r
-	#define localtime posix_localtime
-	#define localtime_r posix_localtime_r
-
-	#define asctime posix_asctime
-	#define asctime_r posix_asctime_r
-	#define ctime posix_ctime
-	#define ctime_r posix_ctime_r
-	#define strftime posix_strftime
+	#define asctime_r   posix_asctime_r
+	#define asctime     posix_asctime
+	#define ctime_r     posix_ctime_r
+	#define ctime       posix_ctime
 
 	#define clock_getres posix_clock_getres
Index: uspace/lib/softfloat/Makefile
===================================================================
--- uspace/lib/softfloat/Makefile	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/softfloat/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -29,17 +29,16 @@
 
 USPACE_PREFIX = ../..
-EXTRA_CFLAGS = -Iinclude
 LIBRARY = libsoftfloat
 
 SOURCES = \
-	generic/add.c \
-	generic/common.c \
-	generic/comparison.c \
-	generic/conversion.c \
-	generic/div.c \
-	generic/mul.c \
-	generic/other.c \
-	generic/softfloat.c \
-	generic/sub.c
+	softfloat.c \
+	common.c \
+	add.c \
+	sub.c \
+	div.c \
+	mul.c \
+	comparison.c \
+	conversion.c \
+	other.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/softfloat/add.c
===================================================================
--- uspace/lib/softfloat/add.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/add.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Addition functions.
+ */
+
+#include "sftypes.h"
+#include "add.h"
+#include "comparison.h"
+#include "common.h"
+
+/** Add two single-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ * @return Result of addition.
+ */
+float32 add_float32(float32 a, float32 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2, frac1, frac2;
+	
+	expdiff = a.parts.exp - b.parts.exp;
+	if (expdiff < 0) {
+		if (is_float32_nan(b)) {
+			/* TODO: fix SigNaN */
+			if (is_float32_signan(b)) {
+			}
+
+			return b;
+		}
+		
+		if (b.parts.exp == FLOAT32_MAX_EXPONENT) { 
+			return b;
+		}
+		
+		frac1 = b.parts.fraction;
+		exp1 = b.parts.exp;
+		frac2 = a.parts.fraction;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if ((is_float32_nan(a)) || (is_float32_nan(b))) {
+			/* TODO: fix SigNaN */
+			if (is_float32_signan(a) || is_float32_signan(b)) {
+			}
+			return (is_float32_nan(a) ? a : b);
+		}
+		
+		if (a.parts.exp == FLOAT32_MAX_EXPONENT) { 
+			return a;
+		}
+		
+		frac1 = a.parts.fraction;
+		exp1 = a.parts.exp;
+		frac2 = b.parts.fraction;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		frac1 += frac2;
+		if (frac1 & FLOAT32_HIDDEN_BIT_MASK) {
+			/* result is not denormalized */
+			a.parts.exp = 1;
+		}
+		a.parts.fraction = frac1;
+		return a;
+	}
+	
+	frac1 |= FLOAT32_HIDDEN_BIT_MASK; /* add hidden bit */
+
+	if (exp2 == 0) {
+		/* second operand is denormalized */
+		--expdiff;
+	} else {
+		/* add hidden bit to second operand */
+		frac2 |= FLOAT32_HIDDEN_BIT_MASK; 
+	}
+	
+	/* create some space for rounding */
+	frac1 <<= 6;
+	frac2 <<= 6;
+	
+	if (expdiff < (FLOAT32_FRACTION_SIZE + 2)) {
+		frac2 >>= expdiff;
+		frac1 += frac2;
+	} else {
+		a.parts.exp = exp1;
+		a.parts.fraction = (frac1 >> 6) & (~(FLOAT32_HIDDEN_BIT_MASK));
+		return a;
+	}
+	
+	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	frac1 += (0x1 << 5);
+	
+	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) { 
+		/* rounding overflow */
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	if ((exp1 == FLOAT32_MAX_EXPONENT) || (exp2 > exp1)) {
+		/* overflow - set infinity as result */
+		a.parts.exp = FLOAT32_MAX_EXPONENT;
+		a.parts.fraction = 0;
+		return a;
+	}
+	
+	a.parts.exp = exp1;
+	
+	/* Clear hidden bit and shift */
+	a.parts.fraction = ((frac1 >> 6) & (~FLOAT32_HIDDEN_BIT_MASK)); 
+	return a;
+}
+
+/** Add two double-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ * @return Result of addition.
+ */
+float64 add_float64(float64 a, float64 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2;
+	uint64_t frac1, frac2;
+	
+	expdiff = ((int) a.parts.exp) - b.parts.exp;
+	if (expdiff < 0) {
+		if (is_float64_nan(b)) {
+			/* TODO: fix SigNaN */
+			if (is_float64_signan(b)) {
+			}
+
+			return b;
+		}
+		
+		/* b is infinity and a not */
+		if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
+			return b;
+		}
+		
+		frac1 = b.parts.fraction;
+		exp1 = b.parts.exp;
+		frac2 = a.parts.fraction;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float64_nan(a)) {
+			/* TODO: fix SigNaN */
+			if (is_float64_signan(a) || is_float64_signan(b)) {
+			}
+			return a;
+		}
+		
+		/* a is infinity and b not */
+		if (a.parts.exp == FLOAT64_MAX_EXPONENT) { 
+			return a;
+		}
+		
+		frac1 = a.parts.fraction;
+		exp1 = a.parts.exp;
+		frac2 = b.parts.fraction;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		frac1 += frac2;
+		if (frac1 & FLOAT64_HIDDEN_BIT_MASK) { 
+			/* result is not denormalized */
+			a.parts.exp = 1;
+		}
+		a.parts.fraction = frac1;
+		return a;
+	}
+	
+	/* add hidden bit - frac1 is sure not denormalized */
+	frac1 |= FLOAT64_HIDDEN_BIT_MASK;
+
+	/* second operand ... */
+	if (exp2 == 0) {
+		/* ... is denormalized */
+		--expdiff;	
+	} else {
+		/* is not denormalized */
+		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
+	}
+	
+	/* create some space for rounding */
+	frac1 <<= 6;
+	frac2 <<= 6;
+	
+	if (expdiff < (FLOAT64_FRACTION_SIZE + 2)) {
+		frac2 >>= expdiff;
+		frac1 += frac2;
+	} else {
+		a.parts.exp = exp1;
+		a.parts.fraction = (frac1 >> 6) & (~(FLOAT64_HIDDEN_BIT_MASK));
+		return a;
+	}
+	
+	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) {
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	frac1 += (0x1 << 5); 
+	
+	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) { 
+		/* rounding overflow */
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	if ((exp1 == FLOAT64_MAX_EXPONENT) || (exp2 > exp1)) {
+		/* overflow - set infinity as result */
+		a.parts.exp = FLOAT64_MAX_EXPONENT;
+		a.parts.fraction = 0;
+		return a;
+	}
+	
+	a.parts.exp = exp1;
+	/* Clear hidden bit and shift */
+	a.parts.fraction = ((frac1 >> 6) & (~FLOAT64_HIDDEN_BIT_MASK));
+	return a;
+}
+
+/** Add two quadruple-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ * @return Result of addition.
+ */
+float128 add_float128(float128 a, float128 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2;
+	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
+
+	expdiff = ((int) a.parts.exp) - b.parts.exp;
+	if (expdiff < 0) {
+		if (is_float128_nan(b)) {
+			/* TODO: fix SigNaN */
+			if (is_float128_signan(b)) {
+			}
+
+			return b;
+		}
+
+		/* b is infinity and a not */
+		if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
+			return b;
+		}
+
+		frac1_hi = b.parts.frac_hi;
+		frac1_lo = b.parts.frac_lo;
+		exp1 = b.parts.exp;
+		frac2_hi = a.parts.frac_hi;
+		frac2_lo = a.parts.frac_lo;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float128_nan(a)) {
+			/* TODO: fix SigNaN */
+			if (is_float128_signan(a) || is_float128_signan(b)) {
+			}
+			return a;
+		}
+
+		/* a is infinity and b not */
+		if (a.parts.exp == FLOAT128_MAX_EXPONENT) {
+			return a;
+		}
+
+		frac1_hi = a.parts.frac_hi;
+		frac1_lo = a.parts.frac_lo;
+		exp1 = a.parts.exp;
+		frac2_hi = b.parts.frac_hi;
+		frac2_lo = b.parts.frac_lo;
+		exp2 = b.parts.exp;
+	}
+
+	if (exp1 == 0) {
+		/* both are denormalized */
+		add128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &frac1_hi, &frac1_lo);
+
+		and128(frac1_hi, frac1_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hi, &tmp_lo);
+		if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+			/* result is not denormalized */
+			a.parts.exp = 1;
+		}
+
+		a.parts.frac_hi = frac1_hi;
+		a.parts.frac_lo = frac1_lo;
+		return a;
+	}
+
+	/* add hidden bit - frac1 is sure not denormalized */
+	or128(frac1_hi, frac1_lo,
+	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &frac1_hi, &frac1_lo);
+
+	/* second operand ... */
+	if (exp2 == 0) {
+		/* ... is denormalized */
+		--expdiff;
+	} else {
+		/* is not denormalized */
+		or128(frac2_hi, frac2_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &frac2_hi, &frac2_lo);
+	}
+
+	/* create some space for rounding */
+	lshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+	lshift128(frac2_hi, frac2_lo, 6, &frac2_hi, &frac2_lo);
+
+	if (expdiff < (FLOAT128_FRACTION_SIZE + 2)) {
+		rshift128(frac2_hi, frac2_lo, expdiff, &frac2_hi, &frac2_lo);
+		add128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &frac1_hi, &frac1_lo);
+	} else {
+		a.parts.exp = exp1;
+
+		rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+		not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hi, &tmp_lo);
+		and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+
+		a.parts.frac_hi = tmp_hi;
+		a.parts.frac_lo = tmp_lo;
+		return a;
+	}
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
+	    &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		++exp1;
+		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+	}
+
+	/* rounding - if first bit after fraction is set then round up */
+	add128(frac1_hi, frac1_lo, 0x0ll, 0x1ll << 5, &frac1_hi, &frac1_lo);
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
+	   &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		/* rounding overflow */
+		++exp1;
+		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+	}
+
+	if ((exp1 == FLOAT128_MAX_EXPONENT ) || (exp2 > exp1)) {
+		/* overflow - set infinity as result */
+		a.parts.exp = FLOAT64_MAX_EXPONENT;
+		a.parts.frac_hi = 0;
+		a.parts.frac_lo = 0;
+		return a;
+	}
+
+	a.parts.exp = exp1;
+	
+	/* Clear hidden bit and shift */
+	rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+
+	a.parts.frac_hi = tmp_hi;
+	a.parts.frac_lo = tmp_lo;
+
+	return a;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/add.h
===================================================================
--- uspace/lib/softfloat/add.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/add.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Addition functions.
+ */
+
+#ifndef __ADD_H__
+#define __ADD_H__
+
+extern float32 add_float32(float32, float32);
+extern float64 add_float64(float64, float64);
+extern float96 add_float96(float96, float96);
+extern float128 add_float128(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/common.c
===================================================================
--- uspace/lib/softfloat/common.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/common.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Common helper operations.
+ */
+
+#include "sftypes.h"
+#include "common.h"
+
+/* Table for fast leading zeroes counting. */
+char zeroTable[256] = {
+	8, 7, 7, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, \
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, \
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/**
+ * Take fraction shifted by 10 bits to the left, round it, normalize it
+ * and detect exceptions
+ * 
+ * @param cexp Exponent with bias.
+ * @param cfrac Fraction shifted 10 bits to the left with added hidden bit.
+ * @param sign Resulting sign.
+ * @return Finished double-precision float.
+ */
+float64 finish_float64(int32_t cexp, uint64_t cfrac, char sign)
+{
+	float64 result;
+
+	result.parts.sign = sign;
+
+	/* find first nonzero digit and shift result and detect possibly underflow */
+	while ((cexp > 0) && (cfrac) &&
+	    (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1))))) {
+		cexp--;
+		cfrac <<= 1;
+		/* TODO: fix underflow */
+	}
+	
+	if ((cexp < 0) || (cexp == 0 &&
+	    (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1)))))) {
+		/* FIXME: underflow */
+		result.parts.exp = 0;
+		if ((cexp + FLOAT64_FRACTION_SIZE + 1) < 0) { /* +1 is place for rounding */
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		while (cexp < 0) {
+			cexp++;
+			cfrac >>= 1;
+		}
+	
+		cfrac += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3)); 
+		
+		if (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1)))) {
+			result.parts.fraction =
+			    ((cfrac >> (64 - FLOAT64_FRACTION_SIZE - 2)) & (~FLOAT64_HIDDEN_BIT_MASK));
+			return result;
+		}	
+	} else {
+		cfrac += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3)); 
+	}
+	
+	++cexp;
+
+	if (cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1))) {
+		++cexp;
+		cfrac >>= 1;
+	}
+
+	/* check overflow */
+	if (cexp >= FLOAT64_MAX_EXPONENT) {
+		/* FIXME: overflow, return infinity */
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		result.parts.fraction = 0;
+		return result;
+	}
+
+	result.parts.exp = (uint32_t) cexp;
+	
+	result.parts.fraction = 
+	    ((cfrac >> (64 - FLOAT64_FRACTION_SIZE - 2)) & (~FLOAT64_HIDDEN_BIT_MASK));
+	
+	return result;	
+}
+
+/**
+ * Take fraction, round it, normalize it and detect exceptions
+ * 
+ * @param cexp Exponent with bias.
+ * @param cfrac_hi High part of the fraction shifted 14 bits to the left
+ *     with added hidden bit.
+ * @param cfrac_lo Low part of the fraction shifted 14 bits to the left
+ *     with added hidden bit.
+ * @param sign Resulting sign.
+ * @param shift_out Bits right-shifted out from fraction by the caller.
+ * @return Finished quadruple-precision float.
+ */
+float128 finish_float128(int32_t cexp, uint64_t cfrac_hi, uint64_t cfrac_lo, 
+    char sign, uint64_t shift_out)
+{
+	float128 result;
+	uint64_t tmp_hi, tmp_lo;
+
+	result.parts.sign = sign;
+
+	/* find first nonzero digit and shift result and detect possibly underflow */
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    1, &tmp_hi, &tmp_lo);
+	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	while ((cexp > 0) && (lt128(0x0ll, 0x0ll, cfrac_hi, cfrac_lo)) &&
+	    (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo))) {
+		cexp--;
+		lshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
+		/* TODO: fix underflow */
+
+		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    1, &tmp_hi, &tmp_lo);
+		and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	}
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    1, &tmp_hi, &tmp_lo);
+	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if ((cexp < 0) || (cexp == 0 &&
+	    (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)))) {
+		/* FIXME: underflow */
+		result.parts.exp = 0;
+		if ((cexp + FLOAT128_FRACTION_SIZE + 1) < 0) { /* +1 is place for rounding */
+			result.parts.frac_hi = 0x0ll;
+			result.parts.frac_lo = 0x0ll;
+			return result;
+		}
+
+		while (cexp < 0) {
+			cexp++;
+			rshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
+		}
+
+		if (shift_out & (0x1ull < 64)) {
+			add128(cfrac_hi, cfrac_lo, 0x0ll, 0x1ll, &cfrac_hi, &cfrac_lo);
+		}
+
+		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    1, &tmp_hi, &tmp_lo);
+		and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+		if (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+			not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+			    &tmp_hi, &tmp_lo);
+			and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+			result.parts.frac_hi = tmp_hi;
+			result.parts.frac_lo = tmp_lo;
+			return result;
+		}
+	} else {
+		if (shift_out & (0x1ull < 64)) {
+			add128(cfrac_hi, cfrac_lo, 0x0ll, 0x1ll, &cfrac_hi, &cfrac_lo);
+		}
+	}
+
+	++cexp;
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    1, &tmp_hi, &tmp_lo);
+	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		++cexp;
+		rshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
+	}
+
+	/* check overflow */
+	if (cexp >= FLOAT128_MAX_EXPONENT) {
+		/* FIXME: overflow, return infinity */
+		result.parts.exp = FLOAT128_MAX_EXPONENT;
+		result.parts.frac_hi = 0x0ll;
+		result.parts.frac_lo = 0x0ll;
+		return result;
+	}
+
+	result.parts.exp = (uint32_t) cexp;
+
+	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &tmp_hi, &tmp_lo);
+	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	result.parts.frac_hi = tmp_hi;
+	result.parts.frac_lo = tmp_lo;
+
+	return result;	
+}
+
+/**
+ * Counts leading zeroes in byte.
+ *
+ * @param i Byte for which to count leading zeroes.
+ * @return Number of detected leading zeroes.
+ */
+int count_zeroes8(uint8_t i)
+{
+	return zeroTable[i];
+}
+
+/** 
+ * Counts leading zeroes in 32bit unsigned integer.
+ *
+ * @param i Integer for which to count leading zeroes.
+ * @return Number of detected leading zeroes.
+ */
+int count_zeroes32(uint32_t i)
+{
+	int j;
+	for (j = 0; j < 32; j += 8) {
+		if (i & (0xFF << (24 - j))) {
+			return (j + count_zeroes8(i >> (24 - j)));
+		}
+	}
+
+	return 32;
+}
+
+/**
+ * Counts leading zeroes in 64bit unsigned integer.
+ *
+ * @param i Integer for which to count leading zeroes.
+ * @return Number of detected leading zeroes.
+ */
+int count_zeroes64(uint64_t i)
+{
+	int j;
+	for (j = 0; j < 64; j += 8) {
+		if (i & (0xFFll << (56 - j))) {
+			return (j + count_zeroes8(i >> (56 - j)));
+		}
+	}
+
+	return 64;
+}
+
+/**
+ * Round and normalize number expressed by exponent and fraction with
+ * first bit (equal to hidden bit) at 30th bit.
+ *
+ * @param exp Exponent part.
+ * @param fraction Fraction with hidden bit shifted to 30th bit.
+ */
+void round_float32(int32_t *exp, uint32_t *fraction)
+{
+	/* rounding - if first bit after fraction is set then round up */
+	(*fraction) += (0x1 << (32 - FLOAT32_FRACTION_SIZE - 3));
+	
+	if ((*fraction) & 
+	    (FLOAT32_HIDDEN_BIT_MASK << (32 - FLOAT32_FRACTION_SIZE - 1))) {
+		/* rounding overflow */
+		++(*exp);
+		(*fraction) >>= 1;
+	}
+	
+	if (((*exp) >= FLOAT32_MAX_EXPONENT) || ((*exp) < 0)) {
+		/* overflow - set infinity as result */
+		(*exp) = FLOAT32_MAX_EXPONENT;
+		(*fraction) = 0;
+	}
+}
+
+/**
+ * Round and normalize number expressed by exponent and fraction with
+ * first bit (equal to hidden bit) at 62nd bit.
+ *
+ * @param exp Exponent part.
+ * @param fraction Fraction with hidden bit shifted to 62nd bit.
+ */
+void round_float64(int32_t *exp, uint64_t *fraction)
+{
+	/* rounding - if first bit after fraction is set then round up */
+	(*fraction) += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3));
+	
+	if ((*fraction) & 
+	    (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 3))) {
+		/* rounding overflow */
+		++(*exp);
+		(*fraction) >>= 1;
+	}
+	
+	if (((*exp) >= FLOAT64_MAX_EXPONENT) || ((*exp) < 0)) {
+		/* overflow - set infinity as result */
+		(*exp) = FLOAT64_MAX_EXPONENT;
+		(*fraction) = 0;
+	}
+}
+
+/**
+ * Round and normalize number expressed by exponent and fraction with
+ * first bit (equal to hidden bit) at 126th bit.
+ *
+ * @param exp Exponent part.
+ * @param frac_hi High part of fraction part with hidden bit shifted to 126th bit.
+ * @param frac_lo Low part of fraction part with hidden bit shifted to 126th bit.
+ */
+void round_float128(int32_t *exp, uint64_t *frac_hi, uint64_t *frac_lo)
+{
+	uint64_t tmp_hi, tmp_lo;
+
+	/* rounding - if first bit after fraction is set then round up */
+	lshift128(0x0ll, 0x1ll, (128 - FLOAT128_FRACTION_SIZE - 3), &tmp_hi, &tmp_lo);
+	add128(*frac_hi, *frac_lo, tmp_hi, tmp_lo, frac_hi, frac_lo);
+
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    (128 - FLOAT128_FRACTION_SIZE - 3), &tmp_hi, &tmp_lo);
+	and128(*frac_hi, *frac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		/* rounding overflow */
+		++(*exp);
+		rshift128(*frac_hi, *frac_lo, 1, frac_hi, frac_lo);
+	}
+
+	if (((*exp) >= FLOAT128_MAX_EXPONENT) || ((*exp) < 0)) {
+		/* overflow - set infinity as result */
+		(*exp) = FLOAT128_MAX_EXPONENT;
+		(*frac_hi) = 0;
+		(*frac_lo) = 0;
+	}
+}
+
+/**
+ * Logical shift left on the 128-bit operand.
+ *
+ * @param a_hi High part of the input operand.
+ * @param a_lo Low part of the input operand.
+ * @param shift Number of bits by witch to shift.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void lshift128(
+    uint64_t a_hi, uint64_t a_lo, int shift,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	if (shift <= 0) {
+		/* do nothing */
+	} else if (shift >= 128) {
+		a_hi = 0;
+		a_lo = 0;
+	} else if (shift >= 64) {
+		a_hi = a_lo << (shift - 64);
+		a_lo = 0;
+	} else {
+		a_hi <<= shift;
+		a_hi |= a_lo >> (64 - shift);
+		a_lo <<= shift;
+	}
+
+	*r_hi = a_hi;
+	*r_lo = a_lo;
+}
+
+/**
+ * Logical shift right on the 128-bit operand.
+ *
+ * @param a_hi High part of the input operand.
+ * @param a_lo Low part of the input operand.
+ * @param shift Number of bits by witch to shift.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void rshift128(
+    uint64_t a_hi, uint64_t a_lo, int shift,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	if (shift <= 0) {
+		/* do nothing */
+	} else 	if (shift >= 128) {
+		a_hi = 0;
+		a_lo = 0;
+	} else if (shift >= 64) {
+		a_lo = a_hi >> (shift - 64);
+		a_hi = 0;
+	} else {
+		a_lo >>= shift;
+		a_lo |= a_hi << (64 - shift);
+		a_hi >>= shift;
+	}
+
+	*r_hi = a_hi;
+	*r_lo = a_lo;
+}
+
+/**
+ * Bitwise AND on 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void and128(
+    uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_hi = a_hi & b_hi;
+	*r_lo = a_lo & b_lo;
+}
+
+/**
+ * Bitwise inclusive OR on 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void or128(
+    uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_hi = a_hi | b_hi;
+	*r_lo = a_lo | b_lo;
+}
+
+/**
+ * Bitwise exclusive OR on 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void xor128(
+    uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_hi = a_hi ^ b_hi;
+	*r_lo = a_lo ^ b_lo;
+}
+
+/**
+ * Bitwise NOT on the 128-bit operand.
+ *
+ * @param a_hi High part of the input operand.
+ * @param a_lo Low part of the input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void not128(
+    uint64_t a_hi, uint64_t a_lo,
+	uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_hi = ~a_hi;
+	*r_lo = ~a_lo;
+}
+
+/**
+ * Equality comparison of 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @return 1 if operands are equal, 0 otherwise.
+ */
+int eq128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
+{
+	return (a_hi == b_hi) && (a_lo == b_lo);
+}
+
+/**
+ * Lower-or-equal comparison of 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @return 1 if a is lower or equal to b, 0 otherwise.
+ */
+int le128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
+{
+	return (a_hi < b_hi) || ((a_hi == b_hi) && (a_lo <= b_lo));
+}
+
+/**
+ * Lower-than comparison of 128-bit operands.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @return 1 if a is lower than b, 0 otherwise.
+ */
+int lt128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
+{
+	return (a_hi < b_hi) || ((a_hi == b_hi) && (a_lo < b_lo));
+}
+
+/**
+ * Addition of two 128-bit unsigned integers.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void add128(uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	uint64_t low = a_lo + b_lo;
+	*r_lo = low;
+	/* detect overflow to add a carry */
+	*r_hi = a_hi + b_hi + (low < a_lo);
+}
+
+/**
+ * Substraction of two 128-bit unsigned integers.
+ *
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void sub128(uint64_t a_hi, uint64_t a_lo,
+    uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hi, uint64_t *r_lo)
+{
+	*r_lo = a_lo - b_lo;
+	/* detect underflow to substract a carry */
+	*r_hi = a_hi - b_hi - (a_lo < b_lo);
+}
+
+/**
+ * Multiplication of two 64-bit unsigned integers.
+ * 
+ * @param a First input operand.
+ * @param b Second input operand.
+ * @param r_hi Address to store high part of the result.
+ * @param r_lo Address to store low part of the result.
+ */
+void mul64(uint64_t a, uint64_t b, uint64_t *r_hi, uint64_t *r_lo)
+{
+	uint64_t low, high, middle1, middle2;
+	uint32_t alow, blow;
+
+	alow = a & 0xFFFFFFFF;
+	blow = b & 0xFFFFFFFF;
+
+	a >>= 32;
+	b >>= 32;
+
+	low = ((uint64_t) alow) * blow;
+	middle1 = a * blow;
+	middle2 = alow * b;
+	high = a * b;
+
+	middle1 += middle2;
+	high += (((uint64_t) (middle1 < middle2)) << 32) + (middle1 >> 32);
+	middle1 <<= 32;
+	low += middle1;
+	high += (low < middle1);
+	*r_lo = low;
+	*r_hi = high;
+}
+
+/**
+ * Multiplication of two 128-bit unsigned integers.
+ * 
+ * @param a_hi High part of the first input operand.
+ * @param a_lo Low part of the first input operand.
+ * @param b_hi High part of the second input operand.
+ * @param b_lo Low part of the second input operand.
+ * @param r_hihi Address to store first (highest) quarter of the result.
+ * @param r_hilo Address to store second quarter of the result.
+ * @param r_lohi Address to store third quarter of the result.
+ * @param r_lolo Address to store fourth (lowest) quarter of the result.
+ */
+void mul128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo,
+    uint64_t *r_hihi, uint64_t *r_hilo, uint64_t *r_lohi, uint64_t *r_lolo)
+{
+	uint64_t hihi, hilo, lohi, lolo;
+	uint64_t tmp1, tmp2;
+
+	mul64(a_lo, b_lo, &lohi, &lolo);
+	mul64(a_lo, b_hi, &hilo, &tmp2);
+	add128(hilo, tmp2, 0x0ll, lohi, &hilo, &lohi);
+	mul64(a_hi, b_hi, &hihi, &tmp1);
+	add128(hihi, tmp1, 0x0ll, hilo, &hihi, &hilo);
+	mul64(a_hi, b_lo, &tmp1, &tmp2);
+	add128(tmp1, tmp2, 0x0ll, lohi, &tmp1, &lohi);
+	add128(hihi, hilo, 0x0ll, tmp1, &hihi, &hilo);
+
+	*r_hihi = hihi;
+	*r_hilo = hilo;
+	*r_lohi = lohi;
+	*r_lolo = lolo;
+}
+
+/**
+ * Estimate the quotient of 128-bit unsigned divident and 64-bit unsigned
+ * divisor.
+ * 
+ * @param a_hi High part of the divident.
+ * @param a_lo Low part of the divident.
+ * @param b Divisor.
+ * @return Quotient approximation.
+ */
+uint64_t div128est(uint64_t a_hi, uint64_t a_lo, uint64_t b)
+{
+	uint64_t b_hi, b_lo;
+	uint64_t rem_hi, rem_lo;
+	uint64_t tmp_hi, tmp_lo;
+	uint64_t result;
+
+	if (b <= a_hi) {
+		return 0xFFFFFFFFFFFFFFFFull;
+	}
+
+	b_hi = b >> 32;
+	result = ((b_hi << 32) <= a_hi) ? (0xFFFFFFFFull << 32) : (a_hi / b_hi) << 32;
+	mul64(b, result, &tmp_hi, &tmp_lo);
+	sub128(a_hi, a_lo, tmp_hi, tmp_lo, &rem_hi, &rem_lo);
+	
+	while ((int64_t) rem_hi < 0) {
+		result -= 0x1ll << 32;
+		b_lo = b << 32;
+		add128(rem_hi, rem_lo, b_hi, b_lo, &rem_hi, &rem_lo);
+	}
+
+	rem_hi = (rem_hi << 32) | (rem_lo >> 32);
+	if ((b_hi << 32) <= rem_hi) {
+		result |= 0xFFFFFFFF;
+	} else {
+		result |= rem_hi / b_hi;
+	}
+
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/common.h
===================================================================
--- uspace/lib/softfloat/common.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/common.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Common helper operations.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include "sftypes.h"
+
+extern float64 finish_float64(int32_t, uint64_t, char);
+extern float128 finish_float128(int32_t, uint64_t, uint64_t, char, uint64_t);
+
+extern int count_zeroes8(uint8_t);
+extern int count_zeroes32(uint32_t);
+extern int count_zeroes64(uint64_t);
+
+extern void round_float32(int32_t *, uint32_t *);
+extern void round_float64(int32_t *, uint64_t *);
+extern void round_float128(int32_t *, uint64_t *, uint64_t *);
+
+extern void lshift128(uint64_t, uint64_t, int, uint64_t *, uint64_t *);
+extern void rshift128(uint64_t, uint64_t, int, uint64_t *, uint64_t *);
+
+extern void and128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void or128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void xor128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void not128(uint64_t, uint64_t, uint64_t *, uint64_t *);
+
+extern int eq128(uint64_t, uint64_t, uint64_t, uint64_t);
+extern int le128(uint64_t, uint64_t, uint64_t, uint64_t);
+extern int lt128(uint64_t, uint64_t, uint64_t, uint64_t);
+
+extern void add128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void sub128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
+
+extern void mul64(uint64_t, uint64_t, uint64_t *, uint64_t *);
+extern void mul128(uint64_t, uint64_t, uint64_t, uint64_t,
+    uint64_t *, uint64_t *, uint64_t *, uint64_t *);
+
+extern uint64_t div128est(uint64_t, uint64_t, uint64_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/comparison.c
===================================================================
--- uspace/lib/softfloat/comparison.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/comparison.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Comparison functions.
+ */
+
+#include "sftypes.h"
+#include "comparison.h"
+#include "common.h"
+
+/**
+ * Determines whether the given float represents NaN (either signalling NaN or
+ * quiet NaN).
+ *
+ * @param f Single-precision float.
+ * @return 1 if float is NaN, 0 otherwise.
+ */
+int is_float32_nan(float32 f)
+{
+	/* NaN : exp = 0xff and nonzero fraction */
+	return ((f.parts.exp == 0xFF) && (f.parts.fraction));
+}
+
+/**
+ * Determines whether the given float represents NaN (either signalling NaN or
+ * quiet NaN).
+ *
+ * @param d Double-precision float.
+ * @return 1 if float is NaN, 0 otherwise.
+ */
+int is_float64_nan(float64 d)
+{
+	/* NaN : exp = 0x7ff and nonzero fraction */
+	return ((d.parts.exp == 0x7FF) && (d.parts.fraction));
+}
+
+/**
+ * Determines whether the given float represents NaN (either signalling NaN or
+ * quiet NaN).
+ *
+ * @param ld Quadruple-precision float.
+ * @return 1 if float is NaN, 0 otherwise.
+ */
+int is_float128_nan(float128 ld)
+{
+	/* NaN : exp = 0x7fff and nonzero fraction */
+	return ((ld.parts.exp == 0x7FF) &&
+	    !eq128(ld.parts.frac_hi, ld.parts.frac_lo, 0x0ll, 0x0ll));
+}
+
+/**
+ * Determines whether the given float represents signalling NaN.
+ *
+ * @param f Single-precision float.
+ * @return 1 if float is signalling NaN, 0 otherwise.
+ */
+int is_float32_signan(float32 f)
+{
+	/* SigNaN : exp = 0xff and fraction = 0xxxxx..x (binary),
+	 * where at least one x is nonzero */
+	return ((f.parts.exp == 0xFF) &&
+	    (f.parts.fraction < 0x400000) && (f.parts.fraction));
+}
+
+/**
+ * Determines whether the given float represents signalling NaN.
+ *
+ * @param d Double-precision float.
+ * @return 1 if float is signalling NaN, 0 otherwise.
+ */
+int is_float64_signan(float64 d)
+{
+	/* SigNaN : exp = 0x7ff and fraction = 0xxxxx..x (binary),
+	 * where at least one x is nonzero */
+	return ((d.parts.exp == 0x7FF) &&
+	    (d.parts.fraction) && (d.parts.fraction < 0x8000000000000ll));
+}
+
+/**
+ * Determines whether the given float represents signalling NaN.
+ *
+ * @param ld Quadruple-precision float.
+ * @return 1 if float is signalling NaN, 0 otherwise.
+ */
+int is_float128_signan(float128 ld)
+{
+	/* SigNaN : exp = 0x7fff and fraction = 0xxxxx..x (binary),
+	 * where at least one x is nonzero */
+	return ((ld.parts.exp == 0x7FFF) &&
+	    (ld.parts.frac_hi || ld.parts.frac_lo) &&
+	    lt128(ld.parts.frac_hi, ld.parts.frac_lo, 0x800000000000ll, 0x0ll));
+
+}
+
+/**
+ * Determines whether the given float represents positive or negative infinity.
+ *
+ * @param f Single-precision float.
+ * @return 1 if float is infinite, 0 otherwise.
+ */
+int is_float32_infinity(float32 f)
+{
+	/* NaN : exp = 0x7ff and zero fraction */
+	return ((f.parts.exp == 0xFF) && (f.parts.fraction == 0x0));
+}
+
+/**
+ * Determines whether the given float represents positive or negative infinity.
+ *
+ * @param d Double-precision float.
+ * @return 1 if float is infinite, 0 otherwise.
+ */
+int is_float64_infinity(float64 d)
+{
+	/* NaN : exp = 0x7ff and zero fraction */
+	return ((d.parts.exp == 0x7FF) && (d.parts.fraction == 0x0));
+}
+
+/**
+ * Determines whether the given float represents positive or negative infinity.
+ *
+ * @param ld Quadruple-precision float.
+ * @return 1 if float is infinite, 0 otherwise.
+ */
+int is_float128_infinity(float128 ld)
+{
+	/* NaN : exp = 0x7fff and zero fraction */
+	return ((ld.parts.exp == 0x7FFF) &&
+	    eq128(ld.parts.frac_hi, ld.parts.frac_lo, 0x0ll, 0x0ll));
+}
+
+/**
+ * Determines whether the given float represents positive or negative zero.
+ *
+ * @param f Single-precision float.
+ * @return 1 if float is zero, 0 otherwise.
+ */
+int is_float32_zero(float32 f)
+{
+	return (((f.bin) & 0x7FFFFFFF) == 0);
+}
+
+/**
+ * Determines whether the given float represents positive or negative zero.
+ *
+ * @param d Double-precision float.
+ * @return 1 if float is zero, 0 otherwise.
+ */
+int is_float64_zero(float64 d)
+{
+	return (((d.bin) & 0x7FFFFFFFFFFFFFFFll) == 0);
+}
+
+/**
+ * Determines whether the given float represents positive or negative zero.
+ *
+ * @param ld Quadruple-precision float.
+ * @return 1 if float is zero, 0 otherwise.
+ */
+int is_float128_zero(float128 ld)
+{
+	uint64_t tmp_hi;
+	uint64_t tmp_lo;
+	
+	and128(ld.bin.hi, ld.bin.lo,
+	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
+	
+	return eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll);
+}
+
+/**
+ * Determine whether two floats are equal. NaNs are not recognized.
+ *
+ * @a First single-precision operand.
+ * @b Second single-precision operand.
+ * @return 1 if both floats are equal, 0 otherwise.
+ */
+int is_float32_eq(float32 a, float32 b)
+{
+	/* a equals to b or both are zeros (with any sign) */
+	return ((a.bin == b.bin) ||
+	    (((a.bin | b.bin) & 0x7FFFFFFF) == 0));
+}
+
+/**
+ * Determine whether two floats are equal. NaNs are not recognized.
+ *
+ * @a First double-precision operand.
+ * @b Second double-precision operand.
+ * @return 1 if both floats are equal, 0 otherwise.
+ */
+int is_float64_eq(float64 a, float64 b)
+{
+	/* a equals to b or both are zeros (with any sign) */
+	return ((a.bin == b.bin) ||
+	    (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0));
+}
+
+/**
+ * Determine whether two floats are equal. NaNs are not recognized.
+ *
+ * @a First quadruple-precision operand.
+ * @b Second quadruple-precision operand.
+ * @return 1 if both floats are equal, 0 otherwise.
+ */
+int is_float128_eq(float128 a, float128 b)
+{
+	uint64_t tmp_hi;
+	uint64_t tmp_lo;
+	
+	/* both are zeros (with any sign) */
+	or128(a.bin.hi, a.bin.lo,
+	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
+	and128(tmp_hi, tmp_lo,
+	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
+	int both_zero = eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll);
+	
+	/* a equals to b */
+	int are_equal = eq128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
+	
+	return are_equal || both_zero;
+}
+
+/**
+ * Lower-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First single-precision operand.
+ * @b Second single-precision operand.
+ * @return 1 if a is lower than b, 0 otherwise.
+ */
+int is_float32_lt(float32 a, float32 b) 
+{
+	if (((a.bin | b.bin) & 0x7FFFFFFF) == 0) {
+		/* +- zeroes */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, smaller is that with greater binary value */
+		return (a.bin > b.bin);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return (a.bin < b.bin);
+}
+
+/**
+ * Lower-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First double-precision operand.
+ * @b Second double-precision operand.
+ * @return 1 if a is lower than b, 0 otherwise.
+ */
+int is_float64_lt(float64 a, float64 b)
+{
+	if (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0) {
+		/* +- zeroes */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, smaller is that with greater binary value */
+		return (a.bin > b.bin);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return (a.bin < b.bin);
+}
+
+/**
+ * Lower-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First quadruple-precision operand.
+ * @b Second quadruple-precision operand.
+ * @return 1 if a is lower than b, 0 otherwise.
+ */
+int is_float128_lt(float128 a, float128 b)
+{
+	uint64_t tmp_hi;
+	uint64_t tmp_lo;
+	
+	or128(a.bin.hi, a.bin.lo,
+	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
+	and128(tmp_hi, tmp_lo,
+	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
+	if (eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll)) {
+		/* +- zeroes */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, smaller is that with greater binary value */
+		return lt128(b.bin.hi, b.bin.lo, a.bin.hi, a.bin.lo);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return lt128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
+}
+
+/**
+ * Greater-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First single-precision operand.
+ * @b Second single-precision operand.
+ * @return 1 if a is greater than b, 0 otherwise.
+ */
+int is_float32_gt(float32 a, float32 b) 
+{
+	if (((a.bin | b.bin) & 0x7FFFFFFF) == 0) {
+		/* zeroes are equal with any sign */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, greater is that with smaller binary value */
+		return (a.bin < b.bin);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return (a.bin > b.bin);
+}
+
+/**
+ * Greater-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First double-precision operand.
+ * @b Second double-precision operand.
+ * @return 1 if a is greater than b, 0 otherwise.
+ */
+int is_float64_gt(float64 a, float64 b)
+{
+	if (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0) {
+		/* zeroes are equal with any sign */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, greater is that with smaller binary value */
+		return (a.bin < b.bin);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return (a.bin > b.bin);
+}
+
+/**
+ * Greater-than comparison between two floats. NaNs are not recognized.
+ *
+ * @a First quadruple-precision operand.
+ * @b Second quadruple-precision operand.
+ * @return 1 if a is greater than b, 0 otherwise.
+ */
+int is_float128_gt(float128 a, float128 b)
+{
+	uint64_t tmp_hi;
+	uint64_t tmp_lo;
+	
+	or128(a.bin.hi, a.bin.lo,
+	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
+	and128(tmp_hi, tmp_lo,
+	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
+	if (eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll)) {
+		/* zeroes are equal with any sign */
+		return 0;
+	}
+	
+	if ((a.parts.sign) && (b.parts.sign)) {
+		/* if both are negative, greater is that with smaller binary value */
+		return lt128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
+	}
+	
+	/*
+	 * lets negate signs - now will be positive numbers always
+	 * bigger than negative (first bit will be set for unsigned
+	 * integer comparison)
+	 */
+	a.parts.sign = !a.parts.sign;
+	b.parts.sign = !b.parts.sign;
+	return lt128(b.bin.hi, b.bin.lo, a.bin.hi, a.bin.lo);
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/comparison.h
===================================================================
--- uspace/lib/softfloat/comparison.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/comparison.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Comparison functions.
+ */
+
+#ifndef __COMPARISON_H__
+#define __COMPARISON_H__
+
+extern int is_float32_nan(float32);
+extern int is_float32_signan(float32);
+
+extern int is_float32_infinity(float32);
+extern int is_float32_zero(float32);
+
+extern int is_float32_eq(float32, float32);
+extern int is_float32_lt(float32, float32);
+extern int is_float32_gt(float32, float32);
+
+extern int is_float64_nan(float64);
+extern int is_float64_signan(float64);
+
+extern int is_float64_infinity(float64);
+extern int is_float64_zero(float64);
+
+extern int is_float64_eq(float64, float64);
+extern int is_float64_lt(float64, float64);
+extern int is_float64_gt(float64, float64);
+
+extern int is_float96_nan(float96);
+extern int is_float96_signan(float96);
+
+extern int is_float96_infinity(float96);
+extern int is_float96_zero(float96);
+
+extern int is_float96_eq(float96, float96);
+extern int is_float96_lt(float96, float96);
+extern int is_float96_gt(float96, float96);
+
+extern int is_float128_nan(float128);
+extern int is_float128_signan(float128);
+
+extern int is_float128_infinity(float128);
+extern int is_float128_zero(float128);
+
+extern int is_float128_eq(float128, float128);
+extern int is_float128_lt(float128, float128);
+extern int is_float128_gt(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/conversion.c
===================================================================
--- uspace/lib/softfloat/conversion.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/conversion.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,1041 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Conversion of precision and conversion between integers and floats.
+ */
+
+#include "sftypes.h"
+#include "conversion.h"
+#include "comparison.h"
+#include "common.h"
+
+float64 float32_to_float64(float32 a)
+{
+	float64 result;
+	uint64_t frac;
+	
+	result.parts.sign = a.parts.sign;
+	result.parts.fraction = a.parts.fraction;
+	result.parts.fraction <<= (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE);
+	
+	if ((is_float32_infinity(a)) || (is_float32_nan(a))) {
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		// TODO; check if its correct for SigNaNs
+		return result;
+	}
+	
+	result.parts.exp = a.parts.exp + ((int) FLOAT64_BIAS - FLOAT32_BIAS);
+	if (a.parts.exp == 0) {
+		/* normalize denormalized numbers */
+		
+		if (result.parts.fraction == 0) { /* fix zero */
+			result.parts.exp = 0;
+			return result;
+		}
+			
+		frac = result.parts.fraction;
+		
+		while (!(frac & FLOAT64_HIDDEN_BIT_MASK)) {
+			frac <<= 1;
+			--result.parts.exp;
+		}
+		
+		++result.parts.exp;
+		result.parts.fraction = frac;
+	}
+	
+	return result;
+}
+
+float128 float32_to_float128(float32 a)
+{
+	float128 result;
+	uint64_t frac_hi, frac_lo;
+	uint64_t tmp_hi, tmp_lo;
+	
+	result.parts.sign = a.parts.sign;
+	result.parts.frac_hi = 0;
+	result.parts.frac_lo = a.parts.fraction;
+	lshift128(result.parts.frac_hi, result.parts.frac_lo,
+	    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE),
+	    &frac_hi, &frac_lo);
+	result.parts.frac_hi = frac_hi;
+	result.parts.frac_lo = frac_lo;
+	
+	if ((is_float32_infinity(a)) || (is_float32_nan(a))) {
+		result.parts.exp = FLOAT128_MAX_EXPONENT;
+		// TODO; check if its correct for SigNaNs
+		return result;
+	}
+	
+	result.parts.exp = a.parts.exp + ((int) FLOAT128_BIAS - FLOAT32_BIAS);
+	if (a.parts.exp == 0) {
+		/* normalize denormalized numbers */
+		
+		if (eq128(result.parts.frac_hi,
+		    result.parts.frac_lo, 0x0ll, 0x0ll)) { /* fix zero */
+			result.parts.exp = 0;
+			return result;
+		}
+		
+		frac_hi = result.parts.frac_hi;
+		frac_lo = result.parts.frac_lo;
+		
+		and128(frac_hi, frac_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hi, &tmp_lo);
+		while (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+			lshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
+			--result.parts.exp;
+		}
+		
+		++result.parts.exp;
+		result.parts.frac_hi = frac_hi;
+		result.parts.frac_lo = frac_lo;
+	}
+	
+	return result;
+}
+
+float128 float64_to_float128(float64 a)
+{
+	float128 result;
+	uint64_t frac_hi, frac_lo;
+	uint64_t tmp_hi, tmp_lo;
+	
+	result.parts.sign = a.parts.sign;
+	result.parts.frac_hi = 0;
+	result.parts.frac_lo = a.parts.fraction;
+	lshift128(result.parts.frac_hi, result.parts.frac_lo,
+	    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE),
+	    &frac_hi, &frac_lo);
+	result.parts.frac_hi = frac_hi;
+	result.parts.frac_lo = frac_lo;
+	
+	if ((is_float64_infinity(a)) || (is_float64_nan(a))) {
+		result.parts.exp = FLOAT128_MAX_EXPONENT;
+		// TODO; check if its correct for SigNaNs
+		return result;
+	}
+	
+	result.parts.exp = a.parts.exp + ((int) FLOAT128_BIAS - FLOAT64_BIAS);
+	if (a.parts.exp == 0) {
+		/* normalize denormalized numbers */
+		
+		if (eq128(result.parts.frac_hi,
+		    result.parts.frac_lo, 0x0ll, 0x0ll)) { /* fix zero */
+			result.parts.exp = 0;
+			return result;
+		}
+		
+		frac_hi = result.parts.frac_hi;
+		frac_lo = result.parts.frac_lo;
+		
+		and128(frac_hi, frac_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hi, &tmp_lo);
+		while (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+			lshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
+			--result.parts.exp;
+		}
+		
+		++result.parts.exp;
+		result.parts.frac_hi = frac_hi;
+		result.parts.frac_lo = frac_lo;
+	}
+	
+	return result;
+}
+
+float32 float64_to_float32(float64 a)
+{
+	float32 result;
+	int32_t exp;
+	uint64_t frac;
+	
+	result.parts.sign = a.parts.sign;
+	
+	if (is_float64_nan(a)) {
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		
+		if (is_float64_signan(a)) {
+			/* set first bit of fraction nonzero */
+			result.parts.fraction = FLOAT32_HIDDEN_BIT_MASK >> 1;
+			return result;
+		}
+		
+		/* fraction nonzero but its first bit is zero */
+		result.parts.fraction = 0x1;
+		return result;
+	}
+	
+	if (is_float64_infinity(a)) {
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		return result;
+	}
+	
+	exp = (int) a.parts.exp - FLOAT64_BIAS + FLOAT32_BIAS;
+	
+	if (exp >= FLOAT32_MAX_EXPONENT) {
+		/* FIXME: overflow */
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		return result;
+	} else if (exp <= 0) {
+		/* underflow or denormalized */
+		
+		result.parts.exp = 0;
+		
+		exp *= -1;	
+		if (exp > FLOAT32_FRACTION_SIZE) {
+			/* FIXME: underflow */
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* denormalized */
+		
+		frac = a.parts.fraction; 
+		frac |= FLOAT64_HIDDEN_BIT_MASK; /* denormalize and set hidden bit */
+		
+		frac >>= (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1);
+		
+		while (exp > 0) {
+			--exp;
+			frac >>= 1;
+		}
+		result.parts.fraction = frac;
+		
+		return result;
+	}
+	
+	result.parts.exp = exp;
+	result.parts.fraction =
+	    a.parts.fraction >> (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE);
+	return result;
+}
+
+float32 float128_to_float32(float128 a)
+{
+	float32 result;
+	int32_t exp;
+	uint64_t frac_hi, frac_lo;
+	
+	result.parts.sign = a.parts.sign;
+	
+	if (is_float128_nan(a)) {
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		
+		if (is_float128_signan(a)) {
+			/* set first bit of fraction nonzero */
+			result.parts.fraction = FLOAT32_HIDDEN_BIT_MASK >> 1;
+			return result;
+		}
+		
+		/* fraction nonzero but its first bit is zero */
+		result.parts.fraction = 0x1;
+		return result;
+	}
+	
+	if (is_float128_infinity(a)) {
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		return result;
+	}
+	
+	exp = (int) a.parts.exp - FLOAT128_BIAS + FLOAT32_BIAS;
+	
+	if (exp >= FLOAT32_MAX_EXPONENT) {
+		/* FIXME: overflow */
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		return result;
+	} else if (exp <= 0) {
+		/* underflow or denormalized */
+		
+		result.parts.exp = 0;
+		
+		exp *= -1;
+		if (exp > FLOAT32_FRACTION_SIZE) {
+			/* FIXME: underflow */
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* denormalized */
+		
+		frac_hi = a.parts.frac_hi;
+		frac_lo = a.parts.frac_lo;
+		
+		/* denormalize and set hidden bit */
+		frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
+		
+		rshift128(frac_hi, frac_lo,
+		    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1),
+		    &frac_hi, &frac_lo);
+		
+		while (exp > 0) {
+			--exp;
+			rshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
+		}
+		result.parts.fraction = frac_lo;
+		
+		return result;
+	}
+	
+	result.parts.exp = exp;
+	frac_hi = a.parts.frac_hi;
+	frac_lo = a.parts.frac_lo;
+	rshift128(frac_hi, frac_lo,
+	    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1),
+	    &frac_hi, &frac_lo);
+	result.parts.fraction = frac_lo;
+	return result;
+}
+
+float64 float128_to_float64(float128 a)
+{
+	float64 result;
+	int32_t exp;
+	uint64_t frac_hi, frac_lo;
+	
+	result.parts.sign = a.parts.sign;
+	
+	if (is_float128_nan(a)) {
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		
+		if (is_float128_signan(a)) {
+			/* set first bit of fraction nonzero */
+			result.parts.fraction = FLOAT64_HIDDEN_BIT_MASK >> 1;
+			return result;
+		}
+		
+		/* fraction nonzero but its first bit is zero */
+		result.parts.fraction = 0x1;
+		return result;
+	}
+	
+	if (is_float128_infinity(a)) {
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		return result;
+	}
+	
+	exp = (int) a.parts.exp - FLOAT128_BIAS + FLOAT64_BIAS;
+	
+	if (exp >= FLOAT64_MAX_EXPONENT) {
+		/* FIXME: overflow */
+		result.parts.fraction = 0;
+		result.parts.exp = FLOAT64_MAX_EXPONENT;
+		return result;
+	} else if (exp <= 0) {
+		/* underflow or denormalized */
+		
+		result.parts.exp = 0;
+		
+		exp *= -1;
+		if (exp > FLOAT64_FRACTION_SIZE) {
+			/* FIXME: underflow */
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* denormalized */
+		
+		frac_hi = a.parts.frac_hi;
+		frac_lo = a.parts.frac_lo;
+		
+		/* denormalize and set hidden bit */
+		frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
+		
+		rshift128(frac_hi, frac_lo,
+		    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE + 1),
+		    &frac_hi, &frac_lo);
+		
+		while (exp > 0) {
+			--exp;
+			rshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
+		}
+		result.parts.fraction = frac_lo;
+		
+		return result;
+	}
+	
+	result.parts.exp = exp;
+	frac_hi = a.parts.frac_hi;
+	frac_lo = a.parts.frac_lo;
+	rshift128(frac_hi, frac_lo,
+	    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE + 1),
+	    &frac_hi, &frac_lo);
+	result.parts.fraction = frac_lo;
+	return result;
+}
+
+/** Helper procedure for converting float32 to uint32.
+ *
+ * @param a Floating point number in normalized form
+ *     (NaNs or Inf are not checked).
+ * @return Converted unsigned integer.
+ */
+static uint32_t _float32_to_uint32_helper(float32 a)
+{
+	uint32_t frac;
+	
+	if (a.parts.exp < FLOAT32_BIAS) {
+		/* TODO: rounding */
+		return 0;
+	}
+	
+	frac = a.parts.fraction;
+	
+	frac |= FLOAT32_HIDDEN_BIT_MASK;
+	/* shift fraction to left so hidden bit will be the most significant bit */
+	frac <<= 32 - FLOAT32_FRACTION_SIZE - 1; 
+	
+	frac >>= 32 - (a.parts.exp - FLOAT32_BIAS) - 1;
+	if ((a.parts.sign == 1) && (frac != 0)) {
+		frac = ~frac;
+		++frac;
+	}
+	
+	return frac;
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint32_t float32_to_uint32(float32 a)
+{
+	if (is_float32_nan(a))
+		return UINT32_MAX;
+	
+	if (is_float32_infinity(a) || (a.parts.exp >= (32 + FLOAT32_BIAS))) {
+		if (a.parts.sign)
+			return UINT32_MIN;
+		
+		return UINT32_MAX;
+	}
+	
+	return _float32_to_uint32_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int32_t float32_to_int32(float32 a)
+{
+	if (is_float32_nan(a))
+		return INT32_MAX;
+	
+	if (is_float32_infinity(a) || (a.parts.exp >= (32 + FLOAT32_BIAS))) {
+		if (a.parts.sign)
+			return INT32_MIN;
+		
+		return INT32_MAX;
+	}
+	
+	return _float32_to_uint32_helper(a);
+}
+
+/** Helper procedure for converting float32 to uint64.
+ *
+ * @param a Floating point number in normalized form
+ *     (NaNs or Inf are not checked).
+ * @return Converted unsigned integer.
+ */
+static uint64_t _float32_to_uint64_helper(float32 a)
+{
+	uint64_t frac;
+	
+	if (a.parts.exp < FLOAT32_BIAS) {
+		// TODO: rounding
+		return 0;
+	}
+	
+	frac = a.parts.fraction;
+	
+	frac |= FLOAT32_HIDDEN_BIT_MASK;
+	/* shift fraction to left so hidden bit will be the most significant bit */
+	frac <<= 64 - FLOAT32_FRACTION_SIZE - 1;
+	
+	frac >>= 64 - (a.parts.exp - FLOAT32_BIAS) - 1;
+	if ((a.parts.sign == 1) && (frac != 0)) {
+		frac = ~frac;
+		++frac;
+	}
+	
+	return frac;
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint64_t float32_to_uint64(float32 a)
+{
+	if (is_float32_nan(a))
+		return UINT64_MAX;
+	
+	if (is_float32_infinity(a) || (a.parts.exp >= (64 + FLOAT32_BIAS))) {
+		if (a.parts.sign)
+			return UINT64_MIN;
+		
+		return UINT64_MAX;
+	}
+	
+	return _float32_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int64_t float32_to_int64(float32 a)
+{
+	if (is_float32_nan(a))
+		return INT64_MAX;
+	
+	if (is_float32_infinity(a) || (a.parts.exp >= (64 + FLOAT32_BIAS))) {
+		if (a.parts.sign)
+			return INT64_MIN;
+		
+		return INT64_MAX;
+	}
+	
+	return _float32_to_uint64_helper(a);
+}
+
+/** Helper procedure for converting float64 to uint64.
+ *
+ * @param a Floating point number in normalized form
+ *     (NaNs or Inf are not checked).
+ * @return Converted unsigned integer.
+ */
+static uint64_t _float64_to_uint64_helper(float64 a)
+{
+	uint64_t frac;
+	
+	if (a.parts.exp < FLOAT64_BIAS) {
+		// TODO: rounding
+		return 0;
+	}
+	
+	frac = a.parts.fraction;
+	
+	frac |= FLOAT64_HIDDEN_BIT_MASK;
+	/* shift fraction to left so hidden bit will be the most significant bit */
+	frac <<= 64 - FLOAT64_FRACTION_SIZE - 1;
+	
+	frac >>= 64 - (a.parts.exp - FLOAT64_BIAS) - 1;
+	if ((a.parts.sign == 1) && (frac != 0)) {
+		frac = ~frac;
+		++frac;
+	}
+	
+	return frac;
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint32_t float64_to_uint32(float64 a)
+{
+	if (is_float64_nan(a))
+		return UINT32_MAX;
+	
+	if (is_float64_infinity(a) || (a.parts.exp >= (32 + FLOAT64_BIAS))) {
+		if (a.parts.sign)
+			return UINT32_MIN;
+		
+		return UINT32_MAX;
+	}
+	
+	return (uint32_t) _float64_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int32_t float64_to_int32(float64 a)
+{
+	if (is_float64_nan(a))
+		return INT32_MAX;
+	
+	if (is_float64_infinity(a) || (a.parts.exp >= (32 + FLOAT64_BIAS))) {
+		if (a.parts.sign)
+			return INT32_MIN;
+		
+		return INT32_MAX;
+	}
+	
+	return (int32_t) _float64_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens 
+ *  - now its the biggest or the smallest int
+ */
+uint64_t float64_to_uint64(float64 a)
+{
+	if (is_float64_nan(a))
+		return UINT64_MAX;
+	
+	if (is_float64_infinity(a) || (a.parts.exp >= (64 + FLOAT64_BIAS))) {
+		if (a.parts.sign)
+			return UINT64_MIN;
+		
+		return UINT64_MAX;
+	}
+	
+	return _float64_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens 
+ *  - now its the biggest or the smallest int
+ */
+int64_t float64_to_int64(float64 a)
+{
+	if (is_float64_nan(a))
+		return INT64_MAX;
+	
+	if (is_float64_infinity(a) || (a.parts.exp >= (64 + FLOAT64_BIAS))) {
+		if (a.parts.sign)
+			return INT64_MIN;
+		
+		return INT64_MAX;
+	}
+	
+	return _float64_to_uint64_helper(a);
+}
+
+/** Helper procedure for converting float128 to uint64.
+ *
+ * @param a Floating point number in normalized form
+ *     (NaNs or Inf are not checked).
+ * @return Converted unsigned integer.
+ */
+static uint64_t _float128_to_uint64_helper(float128 a)
+{
+	uint64_t frac_hi, frac_lo;
+	
+	if (a.parts.exp < FLOAT128_BIAS) {
+		// TODO: rounding
+		return 0;
+	}
+	
+	frac_hi = a.parts.frac_hi;
+	frac_lo = a.parts.frac_lo;
+	
+	frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
+	/* shift fraction to left so hidden bit will be the most significant bit */
+	lshift128(frac_hi, frac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 1), &frac_hi, &frac_lo);
+	
+	rshift128(frac_hi, frac_lo,
+	    (128 - (a.parts.exp - FLOAT128_BIAS) - 1), &frac_hi, &frac_lo);
+	if ((a.parts.sign == 1) && !eq128(frac_hi, frac_lo, 0x0ll, 0x0ll)) {
+		not128(frac_hi, frac_lo, &frac_hi, &frac_lo);
+		add128(frac_hi, frac_lo, 0x0ll, 0x1ll, &frac_hi, &frac_lo);
+	}
+	
+	return frac_lo;
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint32_t float128_to_uint32(float128 a)
+{
+	if (is_float128_nan(a))
+		return UINT32_MAX;
+	
+	if (is_float128_infinity(a) || (a.parts.exp >= (32 + FLOAT128_BIAS))) {
+		if (a.parts.sign)
+			return UINT32_MIN;
+		
+		return UINT32_MAX;
+	}
+	
+	return (uint32_t) _float128_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int32_t float128_to_int32(float128 a)
+{
+	if (is_float128_nan(a))
+		return INT32_MAX;
+	
+	if (is_float128_infinity(a) || (a.parts.exp >= (32 + FLOAT128_BIAS))) {
+		if (a.parts.sign)
+			return INT32_MIN;
+		
+		return INT32_MAX;
+	}
+	
+	return (int32_t) _float128_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+uint64_t float128_to_uint64(float128 a)
+{
+	if (is_float128_nan(a))
+		return UINT64_MAX;
+	
+	if (is_float128_infinity(a) || (a.parts.exp >= (64 + FLOAT128_BIAS))) {
+		if (a.parts.sign)
+			return UINT64_MIN;
+		
+		return UINT64_MAX;
+	}
+	
+	return _float128_to_uint64_helper(a);
+}
+
+/*
+ * FIXME: Im not sure what to return if overflow/underflow happens
+ *  - now its the biggest or the smallest int
+ */
+int64_t float128_to_int64(float128 a)
+{
+	if (is_float128_nan(a))
+		return INT64_MAX;
+	
+	if (is_float128_infinity(a) || (a.parts.exp >= (64 + FLOAT128_BIAS))) {
+		if (a.parts.sign)
+			return INT64_MIN;
+		
+		return INT64_MAX;
+	}
+	
+	return _float128_to_uint64_helper(a);
+}
+
+float32 uint32_to_float32(uint32_t i)
+{
+	int counter;
+	int32_t exp;
+	float32 result;
+	
+	result.parts.sign = 0;
+	result.parts.fraction = 0;
+	
+	counter = count_zeroes32(i);
+	
+	exp = FLOAT32_BIAS + 32 - counter - 1;
+	
+	if (counter == 32) {
+		result.bin = 0;
+		return result;
+	}
+	
+	if (counter > 0) {
+		i <<= counter - 1;
+	} else {
+		i >>= 1;
+	}
+	
+	round_float32(&exp, &i);
+	
+	result.parts.fraction = i >> (32 - FLOAT32_FRACTION_SIZE - 2);
+	result.parts.exp = exp;
+	
+	return result;
+}
+
+float32 int32_to_float32(int32_t i)
+{
+	float32 result;
+	
+	if (i < 0)
+		result = uint32_to_float32((uint32_t) (-i));
+	else
+		result = uint32_to_float32((uint32_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+float32 uint64_to_float32(uint64_t i)
+{
+	int counter;
+	int32_t exp;
+	uint32_t j;
+	float32 result;
+	
+	result.parts.sign = 0;
+	result.parts.fraction = 0;
+	
+	counter = count_zeroes64(i);
+	
+	exp = FLOAT32_BIAS + 64 - counter - 1;
+	
+	if (counter == 64) {
+		result.bin = 0;
+		return result;
+	}
+	
+	/* Shift all to the first 31 bits (31st will be hidden 1) */
+	if (counter > 33) {
+		i <<= counter - 1 - 32;
+	} else {
+		i >>= 1 + 32 - counter;
+	}
+	
+	j = (uint32_t) i;
+	round_float32(&exp, &j);
+	
+	result.parts.fraction = j >> (32 - FLOAT32_FRACTION_SIZE - 2);
+	result.parts.exp = exp;
+	return result;
+}
+
+float32 int64_to_float32(int64_t i)
+{
+	float32 result;
+	
+	if (i < 0)
+		result = uint64_to_float32((uint64_t) (-i));
+	else
+		result = uint64_to_float32((uint64_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+float64 uint32_to_float64(uint32_t i)
+{
+	int counter;
+	int32_t exp;
+	float64 result;
+	uint64_t frac;
+	
+	result.parts.sign = 0;
+	result.parts.fraction = 0;
+	
+	counter = count_zeroes32(i);
+	
+	exp = FLOAT64_BIAS + 32 - counter - 1;
+	
+	if (counter == 32) {
+		result.bin = 0;
+		return result;
+	}
+	
+	frac = i;
+	frac <<= counter + 32 - 1;
+	
+	round_float64(&exp, &frac);
+	
+	result.parts.fraction = frac >> (64 - FLOAT64_FRACTION_SIZE - 2);
+	result.parts.exp = exp;
+	
+	return result;
+}
+
+float64 int32_to_float64(int32_t i)
+{
+	float64 result;
+	
+	if (i < 0)
+		result = uint32_to_float64((uint32_t) (-i));
+	else
+		result = uint32_to_float64((uint32_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+
+float64 uint64_to_float64(uint64_t i)
+{
+	int counter;
+	int32_t exp;
+	float64 result;
+	
+	result.parts.sign = 0;
+	result.parts.fraction = 0;
+	
+	counter = count_zeroes64(i);
+	
+	exp = FLOAT64_BIAS + 64 - counter - 1;
+	
+	if (counter == 64) {
+		result.bin = 0;
+		return result;
+	}
+	
+	if (counter > 0) {
+		i <<= counter - 1;
+	} else {
+		i >>= 1;
+	}
+	
+	round_float64(&exp, &i);
+	
+	result.parts.fraction = i >> (64 - FLOAT64_FRACTION_SIZE - 2);
+	result.parts.exp = exp;
+	return result;
+}
+
+float64 int64_to_float64(int64_t i)
+{
+	float64 result;
+	
+	if (i < 0)
+		result = uint64_to_float64((uint64_t) (-i));
+	else
+		result = uint64_to_float64((uint64_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+float128 uint32_to_float128(uint32_t i)
+{
+	int counter;
+	int32_t exp;
+	float128 result;
+	uint64_t frac_hi, frac_lo;
+	
+	result.parts.sign = 0;
+	result.parts.frac_hi = 0;
+	result.parts.frac_lo = 0;
+	
+	counter = count_zeroes32(i);
+	
+	exp = FLOAT128_BIAS + 32 - counter - 1;
+	
+	if (counter == 32) {
+		result.bin.hi = 0;
+		result.bin.lo = 0;
+		return result;
+	}
+	
+	frac_hi = 0;
+	frac_lo = i;
+	lshift128(frac_hi, frac_lo, (counter + 96 - 1), &frac_hi, &frac_lo);
+	
+	round_float128(&exp, &frac_hi, &frac_lo);
+	
+	rshift128(frac_hi, frac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 2), &frac_hi, &frac_lo);
+	result.parts.frac_hi = frac_hi;
+	result.parts.frac_lo = frac_lo;
+	result.parts.exp = exp;
+	
+	return result;
+}
+
+float128 int32_to_float128(int32_t i)
+{
+	float128 result;
+	
+	if (i < 0)
+		result = uint32_to_float128((uint32_t) (-i));
+	else
+		result = uint32_to_float128((uint32_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+
+float128 uint64_to_float128(uint64_t i)
+{
+	int counter;
+	int32_t exp;
+	float128 result;
+	uint64_t frac_hi, frac_lo;
+	
+	result.parts.sign = 0;
+	result.parts.frac_hi = 0;
+	result.parts.frac_lo = 0;
+	
+	counter = count_zeroes64(i);
+	
+	exp = FLOAT128_BIAS + 64 - counter - 1;
+	
+	if (counter == 64) {
+		result.bin.hi = 0;
+		result.bin.lo = 0;
+		return result;
+	}
+	
+	frac_hi = 0;
+	frac_lo = i;
+	lshift128(frac_hi, frac_lo, (counter + 64 - 1), &frac_hi, &frac_lo);
+	
+	round_float128(&exp, &frac_hi, &frac_lo);
+	
+	rshift128(frac_hi, frac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 2), &frac_hi, &frac_lo);
+	result.parts.frac_hi = frac_hi;
+	result.parts.frac_lo = frac_lo;
+	result.parts.exp = exp;
+	
+	return result;
+}
+
+float128 int64_to_float128(int64_t i)
+{
+	float128 result;
+	
+	if (i < 0)
+		result = uint64_to_float128((uint64_t) (-i));
+	else
+		result = uint64_to_float128((uint64_t) i);
+	
+	result.parts.sign = i < 0;
+	
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/conversion.h
===================================================================
--- uspace/lib/softfloat/conversion.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/conversion.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Conversion of precision and conversion between integers and floats.
+ */
+
+#ifndef __CONVERSION_H__
+#define __CONVERSION_H__
+
+extern float64 float32_to_float64(float32);
+extern float96 float32_to_float96(float32);
+extern float128 float32_to_float128(float32);
+extern float96 float64_to_float96(float64);
+extern float128 float64_to_float128(float64);
+extern float128 float96_to_float128(float96);
+
+extern float32 float64_to_float32(float64);
+extern float32 float96_to_float32(float96);
+extern float64 float96_to_float64(float96);
+extern float32 float128_to_float32(float128);
+extern float64 float128_to_float64(float128);
+extern float96 float128_to_float96(float128);
+
+extern uint32_t float32_to_uint32(float32);
+extern int32_t float32_to_int32(float32);
+
+extern uint64_t float32_to_uint64(float32);
+extern int64_t float32_to_int64(float32);
+
+extern uint32_t float64_to_uint32(float64);
+extern int32_t float64_to_int32(float64);
+
+extern uint64_t float64_to_uint64(float64);
+extern int64_t float64_to_int64(float64);
+
+extern uint32_t float96_to_uint32(float96);
+extern int32_t float96_to_int32(float96);
+
+extern uint64_t float96_to_uint64(float96);
+extern int64_t float96_to_int64(float96);
+
+extern uint32_t float128_to_uint32(float128);
+extern int32_t float128_to_int32(float128);
+
+extern uint64_t float128_to_uint64(float128);
+extern int64_t float128_to_int64(float128);
+
+extern float32 uint32_to_float32(uint32_t);
+extern float32 int32_to_float32(int32_t);
+
+extern float32 uint64_to_float32(uint64_t);
+extern float32 int64_to_float32(int64_t);
+
+extern float64 uint32_to_float64(uint32_t);
+extern float64 int32_to_float64(int32_t);
+
+extern float64 uint64_to_float64(uint64_t);
+extern float64 int64_to_float64(int64_t);
+
+extern float96 uint32_to_float96(uint32_t);
+extern float96 int32_to_float96(int32_t);
+
+extern float96 uint64_to_float96(uint64_t);
+extern float96 int64_to_float96(int64_t);
+
+extern float128 uint32_to_float128(uint32_t);
+extern float128 int32_to_float128(int32_t);
+
+extern float128 uint64_to_float128(uint64_t);
+extern float128 int64_to_float128(int64_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/div.c
===================================================================
--- uspace/lib/softfloat/div.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/div.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Division functions.
+ */
+
+#include "sftypes.h"
+#include "add.h"
+#include "div.h"
+#include "comparison.h"
+#include "mul.h"
+#include "common.h"
+
+/** Divide two single-precision floats.
+ *
+ * @param a Nominator.
+ * @param b Denominator.
+ *
+ * @return Result of division.
+ *
+ */
+float32 div_float32(float32 a, float32 b)
+{
+	float32 result;
+	int32_t aexp, bexp, cexp;
+	uint64_t afrac, bfrac, cfrac;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float32_nan(a)) {
+		if (is_float32_signan(a)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return a;
+	}
+	
+	if (is_float32_nan(b)) {
+		if (is_float32_signan(b)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return b;
+	}
+	
+	if (is_float32_infinity(a)) {
+		if (is_float32_infinity(b)) {
+			/*FIXME: inf / inf */
+			result.bin = FLOAT32_NAN;
+			return result;
+		}
+		/* inf / num */
+		result.parts.exp = a.parts.exp;
+		result.parts.fraction = a.parts.fraction;
+		return result;
+	}
+	
+	if (is_float32_infinity(b)) {
+		if (is_float32_zero(a)) {
+			/* FIXME 0 / inf */
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+		/* FIXME: num / inf*/
+		result.parts.exp = 0;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	if (is_float32_zero(b)) {
+		if (is_float32_zero(a)) {
+			/*FIXME: 0 / 0*/
+			result.bin = FLOAT32_NAN;
+			return result;
+		}
+		/* FIXME: division by zero */
+		result.parts.exp = 0;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	afrac = a.parts.fraction;
+	aexp = a.parts.exp;
+	bfrac = b.parts.fraction;
+	bexp = b.parts.exp;
+	
+	/* denormalized numbers */
+	if (aexp == 0) {
+		if (afrac == 0) {
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* normalize it*/
+		afrac <<= 1;
+		/* afrac is nonzero => it must stop */
+		while (!(afrac & FLOAT32_HIDDEN_BIT_MASK)) {
+			afrac <<= 1;
+			aexp--;
+		}
+	}
+	
+	if (bexp == 0) {
+		bfrac <<= 1;
+		/* bfrac is nonzero => it must stop */
+		while (!(bfrac & FLOAT32_HIDDEN_BIT_MASK)) {
+			bfrac <<= 1;
+			bexp--;
+		}
+	}
+	
+	afrac = (afrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE - 1);
+	bfrac = (bfrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE);
+	
+	if (bfrac <= (afrac << 1)) {
+		afrac >>= 1;
+		aexp++;
+	}
+	
+	cexp = aexp - bexp + FLOAT32_BIAS - 2;
+	
+	cfrac = (afrac << 32) / bfrac;
+	if ((cfrac & 0x3F) == 0) { 
+		cfrac |= (bfrac * cfrac != afrac << 32);
+	}
+	
+	/* pack and round */
+	
+	/* find first nonzero digit and shift result and detect possibly underflow */
+	while ((cexp > 0) && (cfrac) && (!(cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)))) {
+		cexp--;
+		cfrac <<= 1;
+		/* TODO: fix underflow */
+	}
+	
+	cfrac += (0x1 << 6); /* FIXME: 7 is not sure*/
+	
+	if (cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
+		++cexp;
+		cfrac >>= 1;
+	}
+	
+	/* check overflow */
+	if (cexp >= FLOAT32_MAX_EXPONENT) {
+		/* FIXME: overflow, return infinity */
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	if (cexp < 0) {
+		/* FIXME: underflow */
+		result.parts.exp = 0;
+		if ((cexp + FLOAT32_FRACTION_SIZE) < 0) {
+			result.parts.fraction = 0;
+			return result;
+		}
+		cfrac >>= 1;
+		while (cexp < 0) {
+			cexp++;
+			cfrac >>= 1;
+		}
+	} else {
+		result.parts.exp = (uint32_t) cexp;
+	}
+	
+	result.parts.fraction = ((cfrac >> 6) & (~FLOAT32_HIDDEN_BIT_MASK)); 
+	
+	return result;
+}
+
+/** Divide two double-precision floats.
+ *
+ * @param a Nominator.
+ * @param b Denominator.
+ *
+ * @return Result of division.
+ *
+ */
+float64 div_float64(float64 a, float64 b) 
+{
+	float64 result;
+	int64_t aexp, bexp, cexp;
+	uint64_t afrac, bfrac, cfrac; 
+	uint64_t remlo, remhi;
+	uint64_t tmplo, tmphi;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float64_nan(a)) {
+		if (is_float64_signan(b)) {
+			// FIXME: SigNaN
+			return b;
+		}
+		
+		if (is_float64_signan(a)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return a;
+	}
+	
+	if (is_float64_nan(b)) {
+		if (is_float64_signan(b)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return b;
+	}
+	
+	if (is_float64_infinity(a)) {
+		if (is_float64_infinity(b) || is_float64_zero(b)) {
+			// FIXME: inf / inf
+			result.bin = FLOAT64_NAN;
+			return result;
+		}
+		/* inf / num */
+		result.parts.exp = a.parts.exp;
+		result.parts.fraction = a.parts.fraction;
+		return result;
+	}
+	
+	if (is_float64_infinity(b)) {
+		if (is_float64_zero(a)) {
+			/* FIXME 0 / inf */
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+		/* FIXME: num / inf*/
+		result.parts.exp = 0;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	if (is_float64_zero(b)) {
+		if (is_float64_zero(a)) {
+			/*FIXME: 0 / 0*/
+			result.bin = FLOAT64_NAN;
+			return result;
+		}
+		/* FIXME: division by zero */
+		result.parts.exp = 0;
+		result.parts.fraction = 0;
+		return result;
+	}
+	
+	afrac = a.parts.fraction;
+	aexp = a.parts.exp;
+	bfrac = b.parts.fraction;
+	bexp = b.parts.exp;
+	
+	/* denormalized numbers */
+	if (aexp == 0) {
+		if (afrac == 0) {
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+		
+		/* normalize it*/
+		aexp++;
+		/* afrac is nonzero => it must stop */	
+		while (!(afrac & FLOAT64_HIDDEN_BIT_MASK)) {
+			afrac <<= 1;
+			aexp--;
+		}
+	}
+	
+	if (bexp == 0) {
+		bexp++;
+		/* bfrac is nonzero => it must stop */	
+		while (!(bfrac & FLOAT64_HIDDEN_BIT_MASK)) {
+			bfrac <<= 1;
+			bexp--;
+		}
+	}
+	
+	afrac = (afrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 2);
+	bfrac = (bfrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 1);
+	
+	if (bfrac <= (afrac << 1)) {
+		afrac >>= 1;
+		aexp++;
+	}
+	
+	cexp = aexp - bexp + FLOAT64_BIAS - 2; 
+	
+	cfrac = div128est(afrac, 0x0ll, bfrac);
+	
+	if ((cfrac & 0x1FF) <= 2) {
+		mul64(bfrac, cfrac, &tmphi, &tmplo);
+		sub128(afrac, 0x0ll, tmphi, tmplo, &remhi, &remlo);
+		
+		while ((int64_t) remhi < 0) {
+			cfrac--;
+			add128(remhi, remlo, 0x0ll, bfrac, &remhi, &remlo);
+		}
+		cfrac |= (remlo != 0);
+	}
+	
+	/* round and shift */
+	result = finish_float64(cexp, cfrac, result.parts.sign);
+	return result;
+}
+
+/** Divide two quadruple-precision floats.
+ *
+ * @param a Nominator.
+ * @param b Denominator.
+ *
+ * @return Result of division.
+ *
+ */
+float128 div_float128(float128 a, float128 b)
+{
+	float128 result;
+	int64_t aexp, bexp, cexp;
+	uint64_t afrac_hi, afrac_lo, bfrac_hi, bfrac_lo, cfrac_hi, cfrac_lo;
+	uint64_t shift_out;
+	uint64_t rem_hihi, rem_hilo, rem_lohi, rem_lolo;
+	uint64_t tmp_hihi, tmp_hilo, tmp_lohi, tmp_lolo;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float128_nan(a)) {
+		if (is_float128_signan(b)) {
+			// FIXME: SigNaN
+			return b;
+		}
+		
+		if (is_float128_signan(a)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return a;
+	}
+	
+	if (is_float128_nan(b)) {
+		if (is_float128_signan(b)) {
+			// FIXME: SigNaN
+		}
+		/* NaN */
+		return b;
+	}
+	
+	if (is_float128_infinity(a)) {
+		if (is_float128_infinity(b) || is_float128_zero(b)) {
+			// FIXME: inf / inf
+			result.bin.hi = FLOAT128_NAN_HI;
+			result.bin.lo = FLOAT128_NAN_LO;
+			return result;
+		}
+		/* inf / num */
+		result.parts.exp = a.parts.exp;
+		result.parts.frac_hi = a.parts.frac_hi;
+		result.parts.frac_lo = a.parts.frac_lo;
+		return result;
+	}
+	
+	if (is_float128_infinity(b)) {
+		if (is_float128_zero(a)) {
+			// FIXME 0 / inf
+			result.parts.exp = 0;
+			result.parts.frac_hi = 0;
+			result.parts.frac_lo = 0;
+			return result;
+		}
+		// FIXME: num / inf
+		result.parts.exp = 0;
+		result.parts.frac_hi = 0;
+		result.parts.frac_lo = 0;
+		return result;
+	}
+	
+	if (is_float128_zero(b)) {
+		if (is_float128_zero(a)) {
+			// FIXME: 0 / 0
+			result.bin.hi = FLOAT128_NAN_HI;
+			result.bin.lo = FLOAT128_NAN_LO;
+			return result;
+		}
+		// FIXME: division by zero
+		result.parts.exp = 0;
+		result.parts.frac_hi = 0;
+		result.parts.frac_lo = 0;
+		return result;
+	}
+	
+	afrac_hi = a.parts.frac_hi;
+	afrac_lo = a.parts.frac_lo;
+	aexp = a.parts.exp;
+	bfrac_hi = b.parts.frac_hi;
+	bfrac_lo = b.parts.frac_lo;
+	bexp = b.parts.exp;
+	
+	/* denormalized numbers */
+	if (aexp == 0) {
+		if (eq128(afrac_hi, afrac_lo, 0x0ll, 0x0ll)) {
+			result.parts.exp = 0;
+			result.parts.frac_hi = 0;
+			result.parts.frac_lo = 0;
+			return result;
+		}
+		
+		/* normalize it*/
+		aexp++;
+		/* afrac is nonzero => it must stop */
+		and128(afrac_hi, afrac_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hihi, &tmp_lolo);
+		while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
+			lshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
+			aexp--;
+		}
+	}
+	
+	if (bexp == 0) {
+		bexp++;
+		/* bfrac is nonzero => it must stop */
+		and128(bfrac_hi, bfrac_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &tmp_hihi, &tmp_lolo);
+		while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
+			lshift128(bfrac_hi, bfrac_lo, 1, &bfrac_hi, &bfrac_lo);
+			bexp--;
+		}
+	}
+	
+	or128(afrac_hi, afrac_lo,
+	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &afrac_hi, &afrac_lo);
+	lshift128(afrac_hi, afrac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 1), &afrac_hi, &afrac_lo);
+	or128(bfrac_hi, bfrac_lo,
+	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &bfrac_hi, &bfrac_lo);
+	lshift128(bfrac_hi, bfrac_lo,
+	    (128 - FLOAT128_FRACTION_SIZE - 1), &bfrac_hi, &bfrac_lo);
+	
+	if (le128(bfrac_hi, bfrac_lo, afrac_hi, afrac_lo)) {
+		rshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
+		aexp++;
+	}
+	
+	cexp = aexp - bexp + FLOAT128_BIAS - 2;
+	
+	cfrac_hi = div128est(afrac_hi, afrac_lo, bfrac_hi);
+	
+	mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_hi,
+	    &tmp_lolo /* dummy */, &tmp_hihi, &tmp_hilo, &tmp_lohi);
+	
+	/* sub192(afrac_hi, afrac_lo, 0,
+	 *     tmp_hihi, tmp_hilo, tmp_lohi
+	 *     &rem_hihi, &rem_hilo, &rem_lohi); */
+	sub128(afrac_hi, afrac_lo, tmp_hihi, tmp_hilo, &rem_hihi, &rem_hilo);
+	if (tmp_lohi > 0) {
+		sub128(rem_hihi, rem_hilo, 0x0ll, 0x1ll, &rem_hihi, &rem_hilo);
+	}
+	rem_lohi = -tmp_lohi;
+	
+	while ((int64_t) rem_hihi < 0) {
+		--cfrac_hi;
+		/* add192(rem_hihi, rem_hilo, rem_lohi,
+		 *     0, bfrac_hi, bfrac_lo,
+		 *     &rem_hihi, &rem_hilo, &rem_lohi); */
+		add128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo, &rem_hilo, &rem_lohi);
+		if (lt128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo)) {
+			++rem_hihi;
+		}
+	}
+	
+	cfrac_lo = div128est(rem_hilo, rem_lohi, bfrac_lo);
+	
+	if ((cfrac_lo & 0x3FFF) <= 4) {
+		mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_lo,
+		    &tmp_hihi /* dummy */, &tmp_hilo, &tmp_lohi, &tmp_lolo);
+		
+		/* sub192(rem_hilo, rem_lohi, 0,
+		 *     tmp_hilo, tmp_lohi, tmp_lolo,
+		 *     &rem_hilo, &rem_lohi, &rem_lolo); */
+		sub128(rem_hilo, rem_lohi, tmp_hilo, tmp_lohi, &rem_hilo, &rem_lohi);
+		if (tmp_lolo > 0) {
+			sub128(rem_hilo, rem_lohi, 0x0ll, 0x1ll, &rem_hilo, &rem_lohi);
+		}
+		rem_lolo = -tmp_lolo;
+		
+		while ((int64_t) rem_hilo < 0) {
+			--cfrac_lo;
+			/* add192(rem_hilo, rem_lohi, rem_lolo,
+			 *     0, bfrac_hi, bfrac_lo,
+			 *     &rem_hilo, &rem_lohi, &rem_lolo); */
+			add128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo, &rem_lohi, &rem_lolo);
+			if (lt128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo)) {
+				++rem_hilo;
+			}
+		}
+		
+		cfrac_lo |= ((rem_hilo | rem_lohi | rem_lolo) != 0 );
+	}
+	
+	shift_out = cfrac_lo << (64 - (128 - FLOAT128_FRACTION_SIZE - 1));
+	rshift128(cfrac_hi, cfrac_lo, (128 - FLOAT128_FRACTION_SIZE - 1),
+	    &cfrac_hi, &cfrac_lo);
+	
+	result = finish_float128(cexp, cfrac_hi, cfrac_lo, result.parts.sign, shift_out);
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/div.h
===================================================================
--- uspace/lib/softfloat/div.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/div.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Division functions.
+ */
+
+#ifndef __DIV_H__
+#define __DIV_H__
+
+extern float32 div_float32(float32, float32);
+extern float64 div_float64(float64, float64);
+extern float96 div_float96(float96, float96);
+extern float128 div_float128(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: pace/lib/softfloat/generic/add.c
===================================================================
--- uspace/lib/softfloat/generic/add.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,416 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Addition functions.
- */
-
-#include <sftypes.h>
-#include <add.h>
-#include <comparison.h>
-#include <common.h>
-
-/** Add two single-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- * @return Result of addition.
- */
-float32 add_float32(float32 a, float32 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2, frac1, frac2;
-	
-	expdiff = a.parts.exp - b.parts.exp;
-	if (expdiff < 0) {
-		if (is_float32_nan(b)) {
-			/* TODO: fix SigNaN */
-			if (is_float32_signan(b)) {
-			}
-
-			return b;
-		}
-		
-		if (b.parts.exp == FLOAT32_MAX_EXPONENT) { 
-			return b;
-		}
-		
-		frac1 = b.parts.fraction;
-		exp1 = b.parts.exp;
-		frac2 = a.parts.fraction;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if ((is_float32_nan(a)) || (is_float32_nan(b))) {
-			/* TODO: fix SigNaN */
-			if (is_float32_signan(a) || is_float32_signan(b)) {
-			}
-			return (is_float32_nan(a) ? a : b);
-		}
-		
-		if (a.parts.exp == FLOAT32_MAX_EXPONENT) { 
-			return a;
-		}
-		
-		frac1 = a.parts.fraction;
-		exp1 = a.parts.exp;
-		frac2 = b.parts.fraction;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		frac1 += frac2;
-		if (frac1 & FLOAT32_HIDDEN_BIT_MASK ) {
-			/* result is not denormalized */
-			a.parts.exp = 1;
-		}
-		a.parts.fraction = frac1;
-		return a;
-	}
-	
-	frac1 |= FLOAT32_HIDDEN_BIT_MASK; /* add hidden bit */
-
-	if (exp2 == 0) {
-		/* second operand is denormalized */
-		--expdiff;
-	} else {
-		/* add hidden bit to second operand */
-		frac2 |= FLOAT32_HIDDEN_BIT_MASK; 
-	}
-	
-	/* create some space for rounding */
-	frac1 <<= 6;
-	frac2 <<= 6;
-	
-	if (expdiff < (FLOAT32_FRACTION_SIZE + 2) ) {
-		frac2 >>= expdiff;
-		frac1 += frac2;
-	} else {
-		a.parts.exp = exp1;
-		a.parts.fraction = (frac1 >> 6) & (~(FLOAT32_HIDDEN_BIT_MASK));
-		return a;
-	}
-	
-	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7) ) {
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	frac1 += (0x1 << 5);
-	
-	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) { 
-		/* rounding overflow */
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	if ((exp1 == FLOAT32_MAX_EXPONENT ) || (exp2 > exp1)) {
-		/* overflow - set infinity as result */
-		a.parts.exp = FLOAT32_MAX_EXPONENT;
-		a.parts.fraction = 0;
-		return a;
-	}
-	
-	a.parts.exp = exp1;
-	
-	/* Clear hidden bit and shift */
-	a.parts.fraction = ((frac1 >> 6) & (~FLOAT32_HIDDEN_BIT_MASK)); 
-	return a;
-}
-
-/** Add two double-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- * @return Result of addition.
- */
-float64 add_float64(float64 a, float64 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2;
-	uint64_t frac1, frac2;
-	
-	expdiff = ((int) a.parts.exp) - b.parts.exp;
-	if (expdiff < 0) {
-		if (is_float64_nan(b)) {
-			/* TODO: fix SigNaN */
-			if (is_float64_signan(b)) {
-			}
-
-			return b;
-		}
-		
-		/* b is infinity and a not */
-		if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
-			return b;
-		}
-		
-		frac1 = b.parts.fraction;
-		exp1 = b.parts.exp;
-		frac2 = a.parts.fraction;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float64_nan(a)) {
-			/* TODO: fix SigNaN */
-			if (is_float64_signan(a) || is_float64_signan(b)) {
-			}
-			return a;
-		}
-		
-		/* a is infinity and b not */
-		if (a.parts.exp == FLOAT64_MAX_EXPONENT) { 
-			return a;
-		}
-		
-		frac1 = a.parts.fraction;
-		exp1 = a.parts.exp;
-		frac2 = b.parts.fraction;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		frac1 += frac2;
-		if (frac1 & FLOAT64_HIDDEN_BIT_MASK) { 
-			/* result is not denormalized */
-			a.parts.exp = 1;
-		}
-		a.parts.fraction = frac1;
-		return a;
-	}
-	
-	/* add hidden bit - frac1 is sure not denormalized */
-	frac1 |= FLOAT64_HIDDEN_BIT_MASK;
-
-	/* second operand ... */
-	if (exp2 == 0) {
-		/* ... is denormalized */
-		--expdiff;	
-	} else {
-		/* is not denormalized */
-		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
-	}
-	
-	/* create some space for rounding */
-	frac1 <<= 6;
-	frac2 <<= 6;
-	
-	if (expdiff < (FLOAT64_FRACTION_SIZE + 2)) {
-		frac2 >>= expdiff;
-		frac1 += frac2;
-	} else {
-		a.parts.exp = exp1;
-		a.parts.fraction = (frac1 >> 6) & (~(FLOAT64_HIDDEN_BIT_MASK));
-		return a;
-	}
-	
-	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) {
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	frac1 += (0x1 << 5); 
-	
-	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) { 
-		/* rounding overflow */
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	if ((exp1 == FLOAT64_MAX_EXPONENT ) || (exp2 > exp1)) {
-		/* overflow - set infinity as result */
-		a.parts.exp = FLOAT64_MAX_EXPONENT;
-		a.parts.fraction = 0;
-		return a;
-	}
-	
-	a.parts.exp = exp1;
-	/* Clear hidden bit and shift */
-	a.parts.fraction = ((frac1 >> 6 ) & (~FLOAT64_HIDDEN_BIT_MASK));
-	return a;
-}
-
-/** Add two quadruple-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- * @return Result of addition.
- */
-float128 add_float128(float128 a, float128 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2;
-	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
-
-	expdiff = ((int) a.parts.exp) - b.parts.exp;
-	if (expdiff < 0) {
-		if (is_float128_nan(b)) {
-			/* TODO: fix SigNaN */
-			if (is_float128_signan(b)) {
-			}
-
-			return b;
-		}
-
-		/* b is infinity and a not */
-		if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
-			return b;
-		}
-
-		frac1_hi = b.parts.frac_hi;
-		frac1_lo = b.parts.frac_lo;
-		exp1 = b.parts.exp;
-		frac2_hi = a.parts.frac_hi;
-		frac2_lo = a.parts.frac_lo;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float128_nan(a)) {
-			/* TODO: fix SigNaN */
-			if (is_float128_signan(a) || is_float128_signan(b)) {
-			}
-			return a;
-		}
-
-		/* a is infinity and b not */
-		if (a.parts.exp == FLOAT128_MAX_EXPONENT) {
-			return a;
-		}
-
-		frac1_hi = a.parts.frac_hi;
-		frac1_lo = a.parts.frac_lo;
-		exp1 = a.parts.exp;
-		frac2_hi = b.parts.frac_hi;
-		frac2_lo = b.parts.frac_lo;
-		exp2 = b.parts.exp;
-	}
-
-	if (exp1 == 0) {
-		/* both are denormalized */
-		add128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &frac1_hi, &frac1_lo);
-
-		and128(frac1_hi, frac1_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hi, &tmp_lo);
-		if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-			/* result is not denormalized */
-			a.parts.exp = 1;
-		}
-
-		a.parts.frac_hi = frac1_hi;
-		a.parts.frac_lo = frac1_lo;
-		return a;
-	}
-
-	/* add hidden bit - frac1 is sure not denormalized */
-	or128(frac1_hi, frac1_lo,
-	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &frac1_hi, &frac1_lo);
-
-	/* second operand ... */
-	if (exp2 == 0) {
-		/* ... is denormalized */
-		--expdiff;
-	} else {
-		/* is not denormalized */
-		or128(frac2_hi, frac2_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &frac2_hi, &frac2_lo);
-	}
-
-	/* create some space for rounding */
-	lshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-	lshift128(frac2_hi, frac2_lo, 6, &frac2_hi, &frac2_lo);
-
-	if (expdiff < (FLOAT128_FRACTION_SIZE + 2)) {
-		rshift128(frac2_hi, frac2_lo, expdiff, &frac2_hi, &frac2_lo);
-		add128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &frac1_hi, &frac1_lo);
-	} else {
-		a.parts.exp = exp1;
-
-		rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-		not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hi, &tmp_lo);
-		and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-
-		a.parts.frac_hi = tmp_hi;
-		a.parts.frac_lo = tmp_lo;
-		return a;
-	}
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
-	    &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		++exp1;
-		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-	}
-
-	/* rounding - if first bit after fraction is set then round up */
-	add128(frac1_hi, frac1_lo, 0x0ll, 0x1ll << 5, &frac1_hi, &frac1_lo);
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
-	   &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		/* rounding overflow */
-		++exp1;
-		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-	}
-
-	if ((exp1 == FLOAT128_MAX_EXPONENT ) || (exp2 > exp1)) {
-		/* overflow - set infinity as result */
-		a.parts.exp = FLOAT64_MAX_EXPONENT;
-		a.parts.frac_hi = 0;
-		a.parts.frac_lo = 0;
-		return a;
-	}
-
-	a.parts.exp = exp1;
-	
-	/* Clear hidden bit and shift */
-	rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-
-	a.parts.frac_hi = tmp_hi;
-	a.parts.frac_lo = tmp_lo;
-
-	return a;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/common.c
===================================================================
--- uspace/lib/softfloat/generic/common.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,690 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Common helper operations.
- */
-
-#include <sftypes.h>
-#include <common.h>
-
-/* Table for fast leading zeroes counting. */
-char zeroTable[256] = {
-	8, 7, 7, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, \
-	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, \
-	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
-	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/** 
- * Take fraction shifted by 10 bits to the left, round it, normalize it
- * and detect exceptions
- * 
- * @param cexp Exponent with bias.
- * @param cfrac Fraction shifted 10 bits to the left with added hidden bit.
- * @param sign Resulting sign.
- * @return Finished double-precision float.
- */
-float64 finish_float64(int32_t cexp, uint64_t cfrac, char sign)
-{
-	float64 result;
-
-	result.parts.sign = sign;
-
-	/* find first nonzero digit and shift result and detect possibly underflow */
-	while ((cexp > 0) && (cfrac) &&
-	    (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1))))) {
-		cexp--; 
-		cfrac <<= 1;
-		/* TODO: fix underflow */
-	}
-	
-	if ((cexp < 0) || (cexp == 0 &&
-	    (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1)))))) {
-		/* FIXME: underflow */
-		result.parts.exp = 0;
-		if ((cexp + FLOAT64_FRACTION_SIZE + 1) < 0) { /* +1 is place for rounding */
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		while (cexp < 0) {
-			cexp++;
-			cfrac >>= 1;
-		}
-	
-		cfrac += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3)); 
-		
-		if (!(cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1)))) {
-			result.parts.fraction =
-			    ((cfrac >> (64 - FLOAT64_FRACTION_SIZE - 2)) & (~FLOAT64_HIDDEN_BIT_MASK));
-			return result;
-		}	
-	} else {
-		cfrac += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3)); 
-	}
-	
-	++cexp;
-
-	if (cfrac & (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 1))) {
-		++cexp;
-		cfrac >>= 1;
-	}	
-
-	/* check overflow */
-	if (cexp >= FLOAT64_MAX_EXPONENT) {
-		/* FIXME: overflow, return infinity */
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		result.parts.fraction = 0;
-		return result;
-	}
-
-	result.parts.exp = (uint32_t) cexp;
-	
-	result.parts.fraction = 
-	    ((cfrac >> (64 - FLOAT64_FRACTION_SIZE - 2)) & (~FLOAT64_HIDDEN_BIT_MASK));
-	
-	return result;	
-}
-
-/**
- * Take fraction, round it, normalize it and detect exceptions
- * 
- * @param cexp Exponent with bias.
- * @param cfrac_hi High part of the fraction shifted 14 bits to the left
- *     with added hidden bit.
- * @param cfrac_lo Low part of the fraction shifted 14 bits to the left
- *     with added hidden bit.
- * @param sign Resulting sign.
- * @param shift_out Bits right-shifted out from fraction by the caller.
- * @return Finished quadruple-precision float.
- */
-float128 finish_float128(int32_t cexp, uint64_t cfrac_hi, uint64_t cfrac_lo, 
-    char sign, uint64_t shift_out)
-{
-	float128 result;
-	uint64_t tmp_hi, tmp_lo;
-
-	result.parts.sign = sign;
-
-	/* find first nonzero digit and shift result and detect possibly underflow */
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    1, &tmp_hi, &tmp_lo);
-	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	while ((cexp > 0) && (lt128(0x0ll, 0x0ll, cfrac_hi, cfrac_lo)) &&
-	    (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo))) {
-		cexp--;
-		lshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
-		/* TODO: fix underflow */
-
-		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    1, &tmp_hi, &tmp_lo);
-		and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	}
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    1, &tmp_hi, &tmp_lo);
-	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if ((cexp < 0) || (cexp == 0 &&
-	    (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)))) {
-		/* FIXME: underflow */
-		result.parts.exp = 0;
-		if ((cexp + FLOAT128_FRACTION_SIZE + 1) < 0) { /* +1 is place for rounding */
-			result.parts.frac_hi = 0x0ll;
-			result.parts.frac_lo = 0x0ll;
-			return result;
-		}
-
-		while (cexp < 0) {
-			cexp++;
-			rshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
-		}
-
-		if (shift_out & (0x1ull < 64)) {
-			add128(cfrac_hi, cfrac_lo, 0x0ll, 0x1ll, &cfrac_hi, &cfrac_lo);
-		}
-
-		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    1, &tmp_hi, &tmp_lo);
-		and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-		if (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-			not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-			    &tmp_hi, &tmp_lo);
-			and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-			result.parts.frac_hi = tmp_hi;
-			result.parts.frac_lo = tmp_lo;
-			return result;
-		}
-	} else {
-		if (shift_out & (0x1ull < 64)) {
-			add128(cfrac_hi, cfrac_lo, 0x0ll, 0x1ll, &cfrac_hi, &cfrac_lo);
-		}
-	}
-
-	++cexp;
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    1, &tmp_hi, &tmp_lo);
-	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		++cexp;
-		rshift128(cfrac_hi, cfrac_lo, 1, &cfrac_hi, &cfrac_lo);
-	}
-
-	/* check overflow */
-	if (cexp >= FLOAT128_MAX_EXPONENT) {
-		/* FIXME: overflow, return infinity */
-		result.parts.exp = FLOAT128_MAX_EXPONENT;
-		result.parts.frac_hi = 0x0ll;
-		result.parts.frac_lo = 0x0ll;
-		return result;
-	}
-
-	result.parts.exp = (uint32_t) cexp;
-
-	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &tmp_hi, &tmp_lo);
-	and128(cfrac_hi, cfrac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	result.parts.frac_hi = tmp_hi;
-	result.parts.frac_lo = tmp_lo;
-
-	return result;	
-}
-
-/**
- * Counts leading zeroes in byte.
- *
- * @param i Byte for which to count leading zeroes.
- * @return Number of detected leading zeroes.
- */
-int count_zeroes8(uint8_t i)
-{
-	return zeroTable[i];
-}
-
-/** 
- * Counts leading zeroes in 32bit unsigned integer.
- *
- * @param i Integer for which to count leading zeroes.
- * @return Number of detected leading zeroes.
- */
-int count_zeroes32(uint32_t i)
-{
-	int j;
-	for (j = 0; j < 32; j += 8) {
-		if (i & (0xFF << (24 - j))) {
-			return (j + count_zeroes8(i >> (24 - j)));
-		}
-	}
-
-	return 32;
-}
-
-/**
- * Counts leading zeroes in 64bit unsigned integer.
- *
- * @param i Integer for which to count leading zeroes.
- * @return Number of detected leading zeroes.
- */
-int count_zeroes64(uint64_t i)
-{
-	int j;
-	for (j = 0; j < 64; j += 8) {
-		if (i & (0xFFll << (56 - j))) {
-			return (j + count_zeroes8(i >> (56 - j)));
-		}
-	}
-
-	return 64;
-}
-
-/**
- * Round and normalize number expressed by exponent and fraction with
- * first bit (equal to hidden bit) at 30th bit.
- *
- * @param exp Exponent part.
- * @param fraction Fraction with hidden bit shifted to 30th bit.
- */
-void round_float32(int32_t *exp, uint32_t *fraction)
-{
-	/* rounding - if first bit after fraction is set then round up */
-	(*fraction) += (0x1 << (32 - FLOAT32_FRACTION_SIZE - 3));
-	
-	if ((*fraction) & 
-	    (FLOAT32_HIDDEN_BIT_MASK << (32 - FLOAT32_FRACTION_SIZE - 1))) {
-		/* rounding overflow */
-		++(*exp);
-		(*fraction) >>= 1;
-	}
-	
-	if (((*exp) >= FLOAT32_MAX_EXPONENT) || ((*exp) < 0)) {
-		/* overflow - set infinity as result */
-		(*exp) = FLOAT32_MAX_EXPONENT;
-		(*fraction) = 0;
-	}
-}
-
-/**
- * Round and normalize number expressed by exponent and fraction with
- * first bit (equal to hidden bit) at 62nd bit.
- *
- * @param exp Exponent part.
- * @param fraction Fraction with hidden bit shifted to 62nd bit.
- */
-void round_float64(int32_t *exp, uint64_t *fraction)
-{
-	/* rounding - if first bit after fraction is set then round up */
-	(*fraction) += (0x1 << (64 - FLOAT64_FRACTION_SIZE - 3));
-	
-	if ((*fraction) & 
-	    (FLOAT64_HIDDEN_BIT_MASK << (64 - FLOAT64_FRACTION_SIZE - 3))) {
-		/* rounding overflow */
-		++(*exp);
-		(*fraction) >>= 1;
-	}
-	
-	if (((*exp) >= FLOAT64_MAX_EXPONENT) || ((*exp) < 0)) {
-		/* overflow - set infinity as result */
-		(*exp) = FLOAT64_MAX_EXPONENT;
-		(*fraction) = 0;
-	}
-}
-
-/**
- * Round and normalize number expressed by exponent and fraction with
- * first bit (equal to hidden bit) at 126th bit.
- *
- * @param exp Exponent part.
- * @param frac_hi High part of fraction part with hidden bit shifted to 126th bit.
- * @param frac_lo Low part of fraction part with hidden bit shifted to 126th bit.
- */
-void round_float128(int32_t *exp, uint64_t *frac_hi, uint64_t *frac_lo)
-{
-	uint64_t tmp_hi, tmp_lo;
-
-	/* rounding - if first bit after fraction is set then round up */
-	lshift128(0x0ll, 0x1ll, (128 - FLOAT128_FRACTION_SIZE - 3), &tmp_hi, &tmp_lo);
-	add128(*frac_hi, *frac_lo, tmp_hi, tmp_lo, frac_hi, frac_lo);
-
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    (128 - FLOAT128_FRACTION_SIZE - 3), &tmp_hi, &tmp_lo);
-	and128(*frac_hi, *frac_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		/* rounding overflow */
-		++(*exp);
-		rshift128(*frac_hi, *frac_lo, 1, frac_hi, frac_lo);
-	}
-
-	if (((*exp) >= FLOAT128_MAX_EXPONENT) || ((*exp) < 0)) {
-		/* overflow - set infinity as result */
-		(*exp) = FLOAT128_MAX_EXPONENT;
-		(*frac_hi) = 0;
-		(*frac_lo) = 0;
-	}
-}
-
-/**
- * Logical shift left on the 128-bit operand.
- *
- * @param a_hi High part of the input operand.
- * @param a_lo Low part of the input operand.
- * @param shift Number of bits by witch to shift.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void lshift128(
-    uint64_t a_hi, uint64_t a_lo, int shift,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	if (shift <= 0) {
-		/* do nothing */
-	} else if (shift >= 128) {
-		a_hi = 0;
-		a_lo = 0;
-	} else if (shift >= 64) {
-		a_hi = a_lo << (shift - 64);
-		a_lo = 0;
-	} else {
-		a_hi <<= shift;
-		a_hi |= a_lo >> (64 - shift);
-		a_lo <<= shift;
-	}
-
-	*r_hi = a_hi;
-	*r_lo = a_lo;
-}
-
-/**
- * Logical shift right on the 128-bit operand.
- *
- * @param a_hi High part of the input operand.
- * @param a_lo Low part of the input operand.
- * @param shift Number of bits by witch to shift.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void rshift128(
-    uint64_t a_hi, uint64_t a_lo, int shift,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	if (shift <= 0) {
-		/* do nothing */
-	} else 	if (shift >= 128) {
-		a_hi = 0;
-		a_lo = 0;
-	} else if (shift >= 64) {
-		a_lo = a_hi >> (shift - 64);
-		a_hi = 0;
-	} else {
-		a_lo >>= shift;
-		a_lo |= a_hi << (64 - shift);
-		a_hi >>= shift;
-	}
-
-	*r_hi = a_hi;
-	*r_lo = a_lo;
-}
-
-/**
- * Bitwise AND on 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void and128(
-    uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_hi = a_hi & b_hi;
-	*r_lo = a_lo & b_lo;
-}
-
-/**
- * Bitwise inclusive OR on 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void or128(
-    uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_hi = a_hi | b_hi;
-	*r_lo = a_lo | b_lo;
-}
-
-/**
- * Bitwise exclusive OR on 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void xor128(
-    uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_hi = a_hi ^ b_hi;
-	*r_lo = a_lo ^ b_lo;
-}
-
-/**
- * Bitwise NOT on the 128-bit operand.
- *
- * @param a_hi High part of the input operand.
- * @param a_lo Low part of the input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void not128(
-    uint64_t a_hi, uint64_t a_lo,
-	uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_hi = ~a_hi;
-	*r_lo = ~a_lo;
-}
-
-/**
- * Equality comparison of 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @return 1 if operands are equal, 0 otherwise.
- */
-int eq128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
-{
-	return (a_hi == b_hi) && (a_lo == b_lo);
-}
-
-/**
- * Lower-or-equal comparison of 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @return 1 if a is lower or equal to b, 0 otherwise.
- */
-int le128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
-{
-	return (a_hi < b_hi) || ((a_hi == b_hi) && (a_lo <= b_lo));
-}
-
-/**
- * Lower-than comparison of 128-bit operands.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @return 1 if a is lower than b, 0 otherwise.
- */
-int lt128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo)
-{
-	return (a_hi < b_hi) || ((a_hi == b_hi) && (a_lo < b_lo));
-}
-
-/**
- * Addition of two 128-bit unsigned integers.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void add128(uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	uint64_t low = a_lo + b_lo;
-	*r_lo = low;
-	/* detect overflow to add a carry */
-	*r_hi = a_hi + b_hi + (low < a_lo);
-}
-
-/**
- * Substraction of two 128-bit unsigned integers.
- *
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void sub128(uint64_t a_hi, uint64_t a_lo,
-    uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hi, uint64_t *r_lo)
-{
-	*r_lo = a_lo - b_lo;
-	/* detect underflow to substract a carry */
-	*r_hi = a_hi - b_hi - (a_lo < b_lo);
-}
-
-/**
- * Multiplication of two 64-bit unsigned integers.
- * 
- * @param a First input operand.
- * @param b Second input operand.
- * @param r_hi Address to store high part of the result.
- * @param r_lo Address to store low part of the result.
- */
-void mul64(uint64_t a, uint64_t b, uint64_t *r_hi, uint64_t *r_lo)
-{
-	uint64_t low, high, middle1, middle2;
-	uint32_t alow, blow;
-
-	alow = a & 0xFFFFFFFF;
-	blow = b & 0xFFFFFFFF;
-
-	a >>= 32;
-	b >>= 32;
-
-	low = ((uint64_t) alow) * blow;
-	middle1 = a * blow;
-	middle2 = alow * b;
-	high = a * b;
-
-	middle1 += middle2;
-	high += (((uint64_t) (middle1 < middle2)) << 32) + (middle1 >> 32);
-	middle1 <<= 32;
-	low += middle1;
-	high += (low < middle1);
-	*r_lo = low;
-	*r_hi = high;
-}
-
-/**
- * Multiplication of two 128-bit unsigned integers.
- * 
- * @param a_hi High part of the first input operand.
- * @param a_lo Low part of the first input operand.
- * @param b_hi High part of the second input operand.
- * @param b_lo Low part of the second input operand.
- * @param r_hihi Address to store first (highest) quarter of the result.
- * @param r_hilo Address to store second quarter of the result.
- * @param r_lohi Address to store third quarter of the result.
- * @param r_lolo Address to store fourth (lowest) quarter of the result.
- */
-void mul128(uint64_t a_hi, uint64_t a_lo, uint64_t b_hi, uint64_t b_lo,
-    uint64_t *r_hihi, uint64_t *r_hilo, uint64_t *r_lohi, uint64_t *r_lolo)
-{
-	uint64_t hihi, hilo, lohi, lolo;
-	uint64_t tmp1, tmp2;
-
-	mul64(a_lo, b_lo, &lohi, &lolo);
-	mul64(a_lo, b_hi, &hilo, &tmp2);
-	add128(hilo, tmp2, 0x0ll, lohi, &hilo, &lohi);
-	mul64(a_hi, b_hi, &hihi, &tmp1);
-	add128(hihi, tmp1, 0x0ll, hilo, &hihi, &hilo);
-	mul64(a_hi, b_lo, &tmp1, &tmp2);
-	add128(tmp1, tmp2, 0x0ll, lohi, &tmp1, &lohi);
-	add128(hihi, hilo, 0x0ll, tmp1, &hihi, &hilo);
-
-	*r_hihi = hihi;
-	*r_hilo = hilo;
-	*r_lohi = lohi;
-	*r_lolo = lolo;
-}
-
-/**
- * Estimate the quotient of 128-bit unsigned divident and 64-bit unsigned
- * divisor.
- * 
- * @param a_hi High part of the divident.
- * @param a_lo Low part of the divident.
- * @param b Divisor.
- * @return Quotient approximation.
- */
-uint64_t div128est(uint64_t a_hi, uint64_t a_lo, uint64_t b)
-{
-	uint64_t b_hi, b_lo;
-	uint64_t rem_hi, rem_lo;
-	uint64_t tmp_hi, tmp_lo;
-	uint64_t result;
-
-	if (b <= a_hi) {
-		return 0xFFFFFFFFFFFFFFFFull;
-	}
-
-	b_hi = b >> 32;
-	result = ((b_hi << 32) <= a_hi) ? (0xFFFFFFFFull << 32) : (a_hi / b_hi) << 32;
-	mul64(b, result, &tmp_hi, &tmp_lo);
-	sub128(a_hi, a_lo, tmp_hi, tmp_lo, &rem_hi, &rem_lo);
-	
-	while ((int64_t) rem_hi < 0) {
-		result -= 0x1ll << 32;
-		b_lo = b << 32;
-		add128(rem_hi, rem_lo, b_hi, b_lo, &rem_hi, &rem_lo);
-	}
-
-	rem_hi = (rem_hi << 32) | (rem_lo >> 32);
-	if ((b_hi << 32) <= rem_hi) {
-		result |= 0xFFFFFFFF;
-	} else {
-		result |= rem_hi / b_hi;
-	}
-
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/comparison.c
===================================================================
--- uspace/lib/softfloat/generic/comparison.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,442 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Comparison functions.
- */
-
-#include <sftypes.h>
-#include <comparison.h>
-#include <common.h>
-
-/**
- * Determines whether the given float represents NaN (either signalling NaN or
- * quiet NaN).
- *
- * @param f Single-precision float.
- * @return 1 if float is NaN, 0 otherwise.
- */
-int is_float32_nan(float32 f)
-{
-	/* NaN : exp = 0xff and nonzero fraction */
-	return ((f.parts.exp == 0xFF) && (f.parts.fraction));
-}
-
-/**
- * Determines whether the given float represents NaN (either signalling NaN or
- * quiet NaN).
- *
- * @param d Double-precision float.
- * @return 1 if float is NaN, 0 otherwise.
- */
-int is_float64_nan(float64 d)
-{
-	/* NaN : exp = 0x7ff and nonzero fraction */
-	return ((d.parts.exp == 0x7FF) && (d.parts.fraction));
-}
-
-/**
- * Determines whether the given float represents NaN (either signalling NaN or
- * quiet NaN).
- *
- * @param ld Quadruple-precision float.
- * @return 1 if float is NaN, 0 otherwise.
- */
-int is_float128_nan(float128 ld)
-{
-	/* NaN : exp = 0x7fff and nonzero fraction */
-	return ((ld.parts.exp == 0x7FF) &&
-	    !eq128(ld.parts.frac_hi, ld.parts.frac_lo, 0x0ll, 0x0ll));
-}
-
-/**
- * Determines whether the given float represents signalling NaN.
- *
- * @param f Single-precision float.
- * @return 1 if float is signalling NaN, 0 otherwise.
- */
-int is_float32_signan(float32 f)
-{
-	/* SigNaN : exp = 0xff and fraction = 0xxxxx..x (binary),
-	 * where at least one x is nonzero */
-	return ((f.parts.exp == 0xFF) &&
-	    (f.parts.fraction < 0x400000) && (f.parts.fraction));
-}
-
-/**
- * Determines whether the given float represents signalling NaN.
- *
- * @param d Double-precision float.
- * @return 1 if float is signalling NaN, 0 otherwise.
- */
-int is_float64_signan(float64 d)
-{
-	/* SigNaN : exp = 0x7ff and fraction = 0xxxxx..x (binary),
-	 * where at least one x is nonzero */
-	return ((d.parts.exp == 0x7FF) &&
-	    (d.parts.fraction) && (d.parts.fraction < 0x8000000000000ll));
-}
-
-/**
- * Determines whether the given float represents signalling NaN.
- *
- * @param ld Quadruple-precision float.
- * @return 1 if float is signalling NaN, 0 otherwise.
- */
-int is_float128_signan(float128 ld)
-{
-	/* SigNaN : exp = 0x7fff and fraction = 0xxxxx..x (binary),
-	 * where at least one x is nonzero */
-	return ((ld.parts.exp == 0x7FFF) &&
-	    (ld.parts.frac_hi || ld.parts.frac_lo) &&
-	    lt128(ld.parts.frac_hi, ld.parts.frac_lo, 0x800000000000ll, 0x0ll));
-
-}
-
-/**
- * Determines whether the given float represents positive or negative infinity.
- *
- * @param f Single-precision float.
- * @return 1 if float is infinite, 0 otherwise.
- */
-int is_float32_infinity(float32 f)
-{
-	/* NaN : exp = 0x7ff and zero fraction */
-	return ((f.parts.exp == 0xFF) && (f.parts.fraction == 0x0));
-}
-
-/**
- * Determines whether the given float represents positive or negative infinity.
- *
- * @param d Double-precision float.
- * @return 1 if float is infinite, 0 otherwise.
- */
-int is_float64_infinity(float64 d)
-{
-	/* NaN : exp = 0x7ff and zero fraction */
-	return ((d.parts.exp == 0x7FF) && (d.parts.fraction == 0x0));
-}
-
-/**
- * Determines whether the given float represents positive or negative infinity.
- *
- * @param ld Quadruple-precision float.
- * @return 1 if float is infinite, 0 otherwise.
- */
-int is_float128_infinity(float128 ld)
-{
-	/* NaN : exp = 0x7fff and zero fraction */
-	return ((ld.parts.exp == 0x7FFF) &&
-	    eq128(ld.parts.frac_hi, ld.parts.frac_lo, 0x0ll, 0x0ll));
-}
-
-/**
- * Determines whether the given float represents positive or negative zero.
- *
- * @param f Single-precision float.
- * @return 1 if float is zero, 0 otherwise.
- */
-int is_float32_zero(float32 f)
-{
-	return (((f.bin) & 0x7FFFFFFF) == 0);
-}
-
-/**
- * Determines whether the given float represents positive or negative zero.
- *
- * @param d Double-precision float.
- * @return 1 if float is zero, 0 otherwise.
- */
-int is_float64_zero(float64 d)
-{
-	return (((d.bin) & 0x7FFFFFFFFFFFFFFFll) == 0);
-}
-
-/**
- * Determines whether the given float represents positive or negative zero.
- *
- * @param ld Quadruple-precision float.
- * @return 1 if float is zero, 0 otherwise.
- */
-int is_float128_zero(float128 ld)
-{
-	uint64_t tmp_hi;
-	uint64_t tmp_lo;
-	
-	and128(ld.bin.hi, ld.bin.lo,
-	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
-	
-	return eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll);
-}
-
-/**
- * Determine whether two floats are equal. NaNs are not recognized.
- *
- * @a First single-precision operand.
- * @b Second single-precision operand.
- * @return 1 if both floats are equal, 0 otherwise.
- */
-int is_float32_eq(float32 a, float32 b)
-{
-	/* a equals to b or both are zeros (with any sign) */
-	return ((a.bin == b.bin) ||
-	    (((a.bin | b.bin) & 0x7FFFFFFF) == 0));
-}
-
-/**
- * Determine whether two floats are equal. NaNs are not recognized.
- *
- * @a First double-precision operand.
- * @b Second double-precision operand.
- * @return 1 if both floats are equal, 0 otherwise.
- */
-int is_float64_eq(float64 a, float64 b)
-{
-	/* a equals to b or both are zeros (with any sign) */
-	return ((a.bin == b.bin) ||
-	    (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0));
-}
-
-/**
- * Determine whether two floats are equal. NaNs are not recognized.
- *
- * @a First quadruple-precision operand.
- * @b Second quadruple-precision operand.
- * @return 1 if both floats are equal, 0 otherwise.
- */
-int is_float128_eq(float128 a, float128 b)
-{
-	uint64_t tmp_hi;
-	uint64_t tmp_lo;
-	
-	/* both are zeros (with any sign) */
-	or128(a.bin.hi, a.bin.lo,
-	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
-	and128(tmp_hi, tmp_lo,
-	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
-	int both_zero = eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll);
-	
-	/* a equals to b */
-	int are_equal = eq128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
-	
-	return are_equal || both_zero;
-}
-
-/**
- * Lower-than comparison between two floats. NaNs are not recognized.
- *
- * @a First single-precision operand.
- * @b Second single-precision operand.
- * @return 1 if a is lower than b, 0 otherwise.
- */
-int is_float32_lt(float32 a, float32 b) 
-{
-	if (((a.bin | b.bin) & 0x7FFFFFFF) == 0) {
-		/* +- zeroes */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, smaller is that with greater binary value */
-		return (a.bin > b.bin);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return (a.bin < b.bin);
-}
-
-/**
- * Lower-than comparison between two floats. NaNs are not recognized.
- *
- * @a First double-precision operand.
- * @b Second double-precision operand.
- * @return 1 if a is lower than b, 0 otherwise.
- */
-int is_float64_lt(float64 a, float64 b)
-{
-	if (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0) {
-		/* +- zeroes */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, smaller is that with greater binary value */
-		return (a.bin > b.bin);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return (a.bin < b.bin);
-}
-
-/**
- * Lower-than comparison between two floats. NaNs are not recognized.
- *
- * @a First quadruple-precision operand.
- * @b Second quadruple-precision operand.
- * @return 1 if a is lower than b, 0 otherwise.
- */
-int is_float128_lt(float128 a, float128 b)
-{
-	uint64_t tmp_hi;
-	uint64_t tmp_lo;
-	
-	or128(a.bin.hi, a.bin.lo,
-	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
-	and128(tmp_hi, tmp_lo,
-	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
-	if (eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll)) {
-		/* +- zeroes */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, smaller is that with greater binary value */
-		return lt128(b.bin.hi, b.bin.lo, a.bin.hi, a.bin.lo);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return lt128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
-}
-
-/**
- * Greater-than comparison between two floats. NaNs are not recognized.
- *
- * @a First single-precision operand.
- * @b Second single-precision operand.
- * @return 1 if a is greater than b, 0 otherwise.
- */
-int is_float32_gt(float32 a, float32 b) 
-{
-	if (((a.bin | b.bin) & 0x7FFFFFFF) == 0) {
-		/* zeroes are equal with any sign */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, greater is that with smaller binary value */
-		return (a.bin < b.bin);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return (a.bin > b.bin);
-}
-
-/**
- * Greater-than comparison between two floats. NaNs are not recognized.
- *
- * @a First double-precision operand.
- * @b Second double-precision operand.
- * @return 1 if a is greater than b, 0 otherwise.
- */
-int is_float64_gt(float64 a, float64 b)
-{
-	if (((a.bin | b.bin) & 0x7FFFFFFFFFFFFFFFll) == 0) {
-		/* zeroes are equal with any sign */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, greater is that with smaller binary value */
-		return (a.bin < b.bin);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return (a.bin > b.bin);
-}
-
-/**
- * Greater-than comparison between two floats. NaNs are not recognized.
- *
- * @a First quadruple-precision operand.
- * @b Second quadruple-precision operand.
- * @return 1 if a is greater than b, 0 otherwise.
- */
-int is_float128_gt(float128 a, float128 b)
-{
-	uint64_t tmp_hi;
-	uint64_t tmp_lo;
-	
-	or128(a.bin.hi, a.bin.lo,
-	    b.bin.hi, b.bin.lo, &tmp_hi, &tmp_lo);
-	and128(tmp_hi, tmp_lo,
-	    0x7FFFFFFFFFFFFFFFll, 0xFFFFFFFFFFFFFFFFll, &tmp_hi, &tmp_lo);
-	if (eq128(tmp_hi, tmp_lo, 0x0ll, 0x0ll)) {
-		/* zeroes are equal with any sign */
-		return 0;
-	}
-	
-	if ((a.parts.sign) && (b.parts.sign)) {
-		/* if both are negative, greater is that with smaller binary value */
-		return lt128(a.bin.hi, a.bin.lo, b.bin.hi, b.bin.lo);
-	}
-	
-	/*
-	 * lets negate signs - now will be positive numbers always
-	 * bigger than negative (first bit will be set for unsigned
-	 * integer comparison)
-	 */
-	a.parts.sign = !a.parts.sign;
-	b.parts.sign = !b.parts.sign;
-	return lt128(b.bin.hi, b.bin.lo, a.bin.hi, a.bin.lo);
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/conversion.c
===================================================================
--- uspace/lib/softfloat/generic/conversion.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,1041 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Conversion of precision and conversion between integers and floats.
- */
-
-#include <sftypes.h>
-#include <conversion.h>
-#include <comparison.h>
-#include <common.h>
-
-float64 float32_to_float64(float32 a)
-{
-	float64 result;
-	uint64_t frac;
-	
-	result.parts.sign = a.parts.sign;
-	result.parts.fraction = a.parts.fraction;
-	result.parts.fraction <<= (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE);
-	
-	if ((is_float32_infinity(a)) || (is_float32_nan(a))) {
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		// TODO; check if its correct for SigNaNs
-		return result;
-	}
-	
-	result.parts.exp = a.parts.exp + ((int) FLOAT64_BIAS - FLOAT32_BIAS);
-	if (a.parts.exp == 0) {
-		/* normalize denormalized numbers */
-		
-		if (result.parts.fraction == 0) { /* fix zero */
-			result.parts.exp = 0;
-			return result;
-		}
-			
-		frac = result.parts.fraction;
-		
-		while (!(frac & FLOAT64_HIDDEN_BIT_MASK)) {
-			frac <<= 1;
-			--result.parts.exp;
-		}
-		
-		++result.parts.exp;
-		result.parts.fraction = frac;
-	}
-	
-	return result;
-}
-
-float128 float32_to_float128(float32 a)
-{
-	float128 result;
-	uint64_t frac_hi, frac_lo;
-	uint64_t tmp_hi, tmp_lo;
-	
-	result.parts.sign = a.parts.sign;
-	result.parts.frac_hi = 0;
-	result.parts.frac_lo = a.parts.fraction;
-	lshift128(result.parts.frac_hi, result.parts.frac_lo,
-	    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE),
-	    &frac_hi, &frac_lo);
-	result.parts.frac_hi = frac_hi;
-	result.parts.frac_lo = frac_lo;
-	
-	if ((is_float32_infinity(a)) || (is_float32_nan(a))) {
-		result.parts.exp = FLOAT128_MAX_EXPONENT;
-		// TODO; check if its correct for SigNaNs
-		return result;
-	}
-	
-	result.parts.exp = a.parts.exp + ((int) FLOAT128_BIAS - FLOAT32_BIAS);
-	if (a.parts.exp == 0) {
-		/* normalize denormalized numbers */
-		
-		if (eq128(result.parts.frac_hi,
-		    result.parts.frac_lo, 0x0ll, 0x0ll)) { /* fix zero */
-			result.parts.exp = 0;
-			return result;
-		}
-		
-		frac_hi = result.parts.frac_hi;
-		frac_lo = result.parts.frac_lo;
-		
-		and128(frac_hi, frac_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hi, &tmp_lo);
-		while (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-			lshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
-			--result.parts.exp;
-		}
-		
-		++result.parts.exp;
-		result.parts.frac_hi = frac_hi;
-		result.parts.frac_lo = frac_lo;
-	}
-	
-	return result;
-}
-
-float128 float64_to_float128(float64 a)
-{
-	float128 result;
-	uint64_t frac_hi, frac_lo;
-	uint64_t tmp_hi, tmp_lo;
-	
-	result.parts.sign = a.parts.sign;
-	result.parts.frac_hi = 0;
-	result.parts.frac_lo = a.parts.fraction;
-	lshift128(result.parts.frac_hi, result.parts.frac_lo,
-	    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE),
-	    &frac_hi, &frac_lo);
-	result.parts.frac_hi = frac_hi;
-	result.parts.frac_lo = frac_lo;
-	
-	if ((is_float64_infinity(a)) || (is_float64_nan(a))) {
-		result.parts.exp = FLOAT128_MAX_EXPONENT;
-		// TODO; check if its correct for SigNaNs
-		return result;
-	}
-	
-	result.parts.exp = a.parts.exp + ((int) FLOAT128_BIAS - FLOAT64_BIAS);
-	if (a.parts.exp == 0) {
-		/* normalize denormalized numbers */
-		
-		if (eq128(result.parts.frac_hi,
-		    result.parts.frac_lo, 0x0ll, 0x0ll)) { /* fix zero */
-			result.parts.exp = 0;
-			return result;
-		}
-		
-		frac_hi = result.parts.frac_hi;
-		frac_lo = result.parts.frac_lo;
-		
-		and128(frac_hi, frac_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hi, &tmp_lo);
-		while (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-			lshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
-			--result.parts.exp;
-		}
-		
-		++result.parts.exp;
-		result.parts.frac_hi = frac_hi;
-		result.parts.frac_lo = frac_lo;
-	}
-	
-	return result;
-}
-
-float32 float64_to_float32(float64 a)
-{
-	float32 result;
-	int32_t exp;
-	uint64_t frac;
-	
-	result.parts.sign = a.parts.sign;
-	
-	if (is_float64_nan(a)) {
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		
-		if (is_float64_signan(a)) {
-			/* set first bit of fraction nonzero */
-			result.parts.fraction = FLOAT32_HIDDEN_BIT_MASK >> 1;
-			return result;
-		}
-		
-		/* fraction nonzero but its first bit is zero */
-		result.parts.fraction = 0x1;
-		return result;
-	}
-	
-	if (is_float64_infinity(a)) {
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		return result;
-	}
-	
-	exp = (int) a.parts.exp - FLOAT64_BIAS + FLOAT32_BIAS;
-	
-	if (exp >= FLOAT32_MAX_EXPONENT) {
-		/* FIXME: overflow */
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		return result;
-	} else if (exp <= 0) {
-		/* underflow or denormalized */
-		
-		result.parts.exp = 0;
-		
-		exp *= -1;	
-		if (exp > FLOAT32_FRACTION_SIZE) {
-			/* FIXME: underflow */
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* denormalized */
-		
-		frac = a.parts.fraction; 
-		frac |= FLOAT64_HIDDEN_BIT_MASK; /* denormalize and set hidden bit */
-		
-		frac >>= (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1);
-		
-		while (exp > 0) {
-			--exp;
-			frac >>= 1;
-		}
-		result.parts.fraction = frac;
-		
-		return result;
-	}
-	
-	result.parts.exp = exp;
-	result.parts.fraction =
-	    a.parts.fraction >> (FLOAT64_FRACTION_SIZE - FLOAT32_FRACTION_SIZE);
-	return result;
-}
-
-float32 float128_to_float32(float128 a)
-{
-	float32 result;
-	int32_t exp;
-	uint64_t frac_hi, frac_lo;
-	
-	result.parts.sign = a.parts.sign;
-	
-	if (is_float128_nan(a)) {
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		
-		if (is_float128_signan(a)) {
-			/* set first bit of fraction nonzero */
-			result.parts.fraction = FLOAT32_HIDDEN_BIT_MASK >> 1;
-			return result;
-		}
-		
-		/* fraction nonzero but its first bit is zero */
-		result.parts.fraction = 0x1;
-		return result;
-	}
-	
-	if (is_float128_infinity(a)) {
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		return result;
-	}
-	
-	exp = (int) a.parts.exp - FLOAT128_BIAS + FLOAT32_BIAS;
-	
-	if (exp >= FLOAT32_MAX_EXPONENT) {
-		/* FIXME: overflow */
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		return result;
-	} else if (exp <= 0) {
-		/* underflow or denormalized */
-		
-		result.parts.exp = 0;
-		
-		exp *= -1;
-		if (exp > FLOAT32_FRACTION_SIZE) {
-			/* FIXME: underflow */
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* denormalized */
-		
-		frac_hi = a.parts.frac_hi;
-		frac_lo = a.parts.frac_lo;
-		
-		/* denormalize and set hidden bit */
-		frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
-		
-		rshift128(frac_hi, frac_lo,
-		    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1),
-		    &frac_hi, &frac_lo);
-		
-		while (exp > 0) {
-			--exp;
-			rshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
-		}
-		result.parts.fraction = frac_lo;
-		
-		return result;
-	}
-	
-	result.parts.exp = exp;
-	frac_hi = a.parts.frac_hi;
-	frac_lo = a.parts.frac_lo;
-	rshift128(frac_hi, frac_lo,
-	    (FLOAT128_FRACTION_SIZE - FLOAT32_FRACTION_SIZE + 1),
-	    &frac_hi, &frac_lo);
-	result.parts.fraction = frac_lo;
-	return result;
-}
-
-float64 float128_to_float64(float128 a)
-{
-	float64 result;
-	int32_t exp;
-	uint64_t frac_hi, frac_lo;
-	
-	result.parts.sign = a.parts.sign;
-	
-	if (is_float128_nan(a)) {
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		
-		if (is_float128_signan(a)) {
-			/* set first bit of fraction nonzero */
-			result.parts.fraction = FLOAT64_HIDDEN_BIT_MASK >> 1;
-			return result;
-		}
-		
-		/* fraction nonzero but its first bit is zero */
-		result.parts.fraction = 0x1;
-		return result;
-	}
-	
-	if (is_float128_infinity(a)) {
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		return result;
-	}
-	
-	exp = (int) a.parts.exp - FLOAT128_BIAS + FLOAT64_BIAS;
-	
-	if (exp >= FLOAT64_MAX_EXPONENT) {
-		/* FIXME: overflow */
-		result.parts.fraction = 0;
-		result.parts.exp = FLOAT64_MAX_EXPONENT;
-		return result;
-	} else if (exp <= 0) {
-		/* underflow or denormalized */
-		
-		result.parts.exp = 0;
-		
-		exp *= -1;
-		if (exp > FLOAT64_FRACTION_SIZE) {
-			/* FIXME: underflow */
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* denormalized */
-		
-		frac_hi = a.parts.frac_hi;
-		frac_lo = a.parts.frac_lo;
-		
-		/* denormalize and set hidden bit */
-		frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
-		
-		rshift128(frac_hi, frac_lo,
-		    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE + 1),
-		    &frac_hi, &frac_lo);
-		
-		while (exp > 0) {
-			--exp;
-			rshift128(frac_hi, frac_lo, 1, &frac_hi, &frac_lo);
-		}
-		result.parts.fraction = frac_lo;
-		
-		return result;
-	}
-	
-	result.parts.exp = exp;
-	frac_hi = a.parts.frac_hi;
-	frac_lo = a.parts.frac_lo;
-	rshift128(frac_hi, frac_lo,
-	    (FLOAT128_FRACTION_SIZE - FLOAT64_FRACTION_SIZE + 1),
-	    &frac_hi, &frac_lo);
-	result.parts.fraction = frac_lo;
-	return result;
-}
-
-/** Helper procedure for converting float32 to uint32.
- *
- * @param a Floating point number in normalized form
- *     (NaNs or Inf are not checked).
- * @return Converted unsigned integer.
- */
-static uint32_t _float32_to_uint32_helper(float32 a)
-{
-	uint32_t frac;
-	
-	if (a.parts.exp < FLOAT32_BIAS) {
-		/* TODO: rounding */
-		return 0;
-	}
-	
-	frac = a.parts.fraction;
-	
-	frac |= FLOAT32_HIDDEN_BIT_MASK;
-	/* shift fraction to left so hidden bit will be the most significant bit */
-	frac <<= 32 - FLOAT32_FRACTION_SIZE - 1; 
-	
-	frac >>= 32 - (a.parts.exp - FLOAT32_BIAS) - 1;
-	if ((a.parts.sign == 1) && (frac != 0)) {
-		frac = ~frac;
-		++frac;
-	}
-	
-	return frac;
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint32_t float32_to_uint32(float32 a)
-{
-	if (is_float32_nan(a))
-		return UINT32_MAX;
-	
-	if (is_float32_infinity(a) || (a.parts.exp >= (32 + FLOAT32_BIAS))) {
-		if (a.parts.sign)
-			return UINT32_MIN;
-		
-		return UINT32_MAX;
-	}
-	
-	return _float32_to_uint32_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int32_t float32_to_int32(float32 a)
-{
-	if (is_float32_nan(a))
-		return INT32_MAX;
-	
-	if (is_float32_infinity(a) || (a.parts.exp >= (32 + FLOAT32_BIAS))) {
-		if (a.parts.sign)
-			return INT32_MIN;
-		
-		return INT32_MAX;
-	}
-	
-	return _float32_to_uint32_helper(a);
-}
-
-/** Helper procedure for converting float32 to uint64.
- *
- * @param a Floating point number in normalized form
- *     (NaNs or Inf are not checked).
- * @return Converted unsigned integer.
- */
-static uint64_t _float32_to_uint64_helper(float32 a)
-{
-	uint64_t frac;
-	
-	if (a.parts.exp < FLOAT32_BIAS) {
-		// TODO: rounding
-		return 0;
-	}
-	
-	frac = a.parts.fraction;
-	
-	frac |= FLOAT32_HIDDEN_BIT_MASK;
-	/* shift fraction to left so hidden bit will be the most significant bit */
-	frac <<= 64 - FLOAT32_FRACTION_SIZE - 1;
-	
-	frac >>= 64 - (a.parts.exp - FLOAT32_BIAS) - 1;
-	if ((a.parts.sign == 1) && (frac != 0)) {
-		frac = ~frac;
-		++frac;
-	}
-	
-	return frac;
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint64_t float32_to_uint64(float32 a)
-{
-	if (is_float32_nan(a))
-		return UINT64_MAX;
-	
-	if (is_float32_infinity(a) || (a.parts.exp >= (64 + FLOAT32_BIAS))) {
-		if (a.parts.sign)
-			return UINT64_MIN;
-		
-		return UINT64_MAX;
-	}
-	
-	return _float32_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int64_t float32_to_int64(float32 a)
-{
-	if (is_float32_nan(a))
-		return INT64_MAX;
-	
-	if (is_float32_infinity(a) || (a.parts.exp >= (64 + FLOAT32_BIAS))) {
-		if (a.parts.sign)
-			return INT64_MIN;
-		
-		return INT64_MAX;
-	}
-	
-	return _float32_to_uint64_helper(a);
-}
-
-/** Helper procedure for converting float64 to uint64.
- *
- * @param a Floating point number in normalized form
- *     (NaNs or Inf are not checked).
- * @return Converted unsigned integer.
- */
-static uint64_t _float64_to_uint64_helper(float64 a)
-{
-	uint64_t frac;
-	
-	if (a.parts.exp < FLOAT64_BIAS) {
-		// TODO: rounding
-		return 0;
-	}
-	
-	frac = a.parts.fraction;
-	
-	frac |= FLOAT64_HIDDEN_BIT_MASK;
-	/* shift fraction to left so hidden bit will be the most significant bit */
-	frac <<= 64 - FLOAT64_FRACTION_SIZE - 1;
-	
-	frac >>= 64 - (a.parts.exp - FLOAT64_BIAS) - 1;
-	if ((a.parts.sign == 1) && (frac != 0)) {
-		frac = ~frac;
-		++frac;
-	}
-	
-	return frac;
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint32_t float64_to_uint32(float64 a)
-{
-	if (is_float64_nan(a))
-		return UINT32_MAX;
-	
-	if (is_float64_infinity(a) || (a.parts.exp >= (32 + FLOAT64_BIAS))) {
-		if (a.parts.sign)
-			return UINT32_MIN;
-		
-		return UINT32_MAX;
-	}
-	
-	return (uint32_t) _float64_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int32_t float64_to_int32(float64 a)
-{
-	if (is_float64_nan(a))
-		return INT32_MAX;
-	
-	if (is_float64_infinity(a) || (a.parts.exp >= (32 + FLOAT64_BIAS))) {
-		if (a.parts.sign)
-			return INT32_MIN;
-		
-		return INT32_MAX;
-	}
-	
-	return (int32_t) _float64_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens 
- *  - now its the biggest or the smallest int
- */
-uint64_t float64_to_uint64(float64 a)
-{
-	if (is_float64_nan(a))
-		return UINT64_MAX;
-	
-	if (is_float64_infinity(a) || (a.parts.exp >= (64 + FLOAT64_BIAS))) {
-		if (a.parts.sign)
-			return UINT64_MIN;
-		
-		return UINT64_MAX;
-	}
-	
-	return _float64_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens 
- *  - now its the biggest or the smallest int
- */
-int64_t float64_to_int64(float64 a)
-{
-	if (is_float64_nan(a))
-		return INT64_MAX;
-	
-	if (is_float64_infinity(a) || (a.parts.exp >= (64 + FLOAT64_BIAS))) {
-		if (a.parts.sign)
-			return INT64_MIN;
-		
-		return INT64_MAX;
-	}
-	
-	return _float64_to_uint64_helper(a);
-}
-
-/** Helper procedure for converting float128 to uint64.
- *
- * @param a Floating point number in normalized form
- *     (NaNs or Inf are not checked).
- * @return Converted unsigned integer.
- */
-static uint64_t _float128_to_uint64_helper(float128 a)
-{
-	uint64_t frac_hi, frac_lo;
-	
-	if (a.parts.exp < FLOAT128_BIAS) {
-		// TODO: rounding
-		return 0;
-	}
-	
-	frac_hi = a.parts.frac_hi;
-	frac_lo = a.parts.frac_lo;
-	
-	frac_hi |= FLOAT128_HIDDEN_BIT_MASK_HI;
-	/* shift fraction to left so hidden bit will be the most significant bit */
-	lshift128(frac_hi, frac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 1), &frac_hi, &frac_lo);
-	
-	rshift128(frac_hi, frac_lo,
-	    (128 - (a.parts.exp - FLOAT128_BIAS) - 1), &frac_hi, &frac_lo);
-	if ((a.parts.sign == 1) && !eq128(frac_hi, frac_lo, 0x0ll, 0x0ll)) {
-		not128(frac_hi, frac_lo, &frac_hi, &frac_lo);
-		add128(frac_hi, frac_lo, 0x0ll, 0x1ll, &frac_hi, &frac_lo);
-	}
-	
-	return frac_lo;
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint32_t float128_to_uint32(float128 a)
-{
-	if (is_float128_nan(a))
-		return UINT32_MAX;
-	
-	if (is_float128_infinity(a) || (a.parts.exp >= (32 + FLOAT128_BIAS))) {
-		if (a.parts.sign)
-			return UINT32_MIN;
-		
-		return UINT32_MAX;
-	}
-	
-	return (uint32_t) _float128_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int32_t float128_to_int32(float128 a)
-{
-	if (is_float128_nan(a))
-		return INT32_MAX;
-	
-	if (is_float128_infinity(a) || (a.parts.exp >= (32 + FLOAT128_BIAS))) {
-		if (a.parts.sign)
-			return INT32_MIN;
-		
-		return INT32_MAX;
-	}
-	
-	return (int32_t) _float128_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-uint64_t float128_to_uint64(float128 a)
-{
-	if (is_float128_nan(a))
-		return UINT64_MAX;
-	
-	if (is_float128_infinity(a) || (a.parts.exp >= (64 + FLOAT128_BIAS))) {
-		if (a.parts.sign)
-			return UINT64_MIN;
-		
-		return UINT64_MAX;
-	}
-	
-	return _float128_to_uint64_helper(a);
-}
-
-/*
- * FIXME: Im not sure what to return if overflow/underflow happens
- *  - now its the biggest or the smallest int
- */
-int64_t float128_to_int64(float128 a)
-{
-	if (is_float128_nan(a))
-		return INT64_MAX;
-	
-	if (is_float128_infinity(a) || (a.parts.exp >= (64 + FLOAT128_BIAS))) {
-		if (a.parts.sign)
-			return INT64_MIN;
-		
-		return INT64_MAX;
-	}
-	
-	return _float128_to_uint64_helper(a);
-}
-
-float32 uint32_to_float32(uint32_t i)
-{
-	int counter;
-	int32_t exp;
-	float32 result;
-	
-	result.parts.sign = 0;
-	result.parts.fraction = 0;
-	
-	counter = count_zeroes32(i);
-	
-	exp = FLOAT32_BIAS + 32 - counter - 1;
-	
-	if (counter == 32) {
-		result.bin = 0;
-		return result;
-	}
-	
-	if (counter > 0) {
-		i <<= counter - 1;
-	} else {
-		i >>= 1;
-	}
-	
-	round_float32(&exp, &i);
-	
-	result.parts.fraction = i >> (32 - FLOAT32_FRACTION_SIZE - 2);
-	result.parts.exp = exp;
-	
-	return result;
-}
-
-float32 int32_to_float32(int32_t i)
-{
-	float32 result;
-	
-	if (i < 0)
-		result = uint32_to_float32((uint32_t) (-i));
-	else
-		result = uint32_to_float32((uint32_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-float32 uint64_to_float32(uint64_t i)
-{
-	int counter;
-	int32_t exp;
-	uint32_t j;
-	float32 result;
-	
-	result.parts.sign = 0;
-	result.parts.fraction = 0;
-	
-	counter = count_zeroes64(i);
-	
-	exp = FLOAT32_BIAS + 64 - counter - 1;
-	
-	if (counter == 64) {
-		result.bin = 0;
-		return result;
-	}
-	
-	/* Shift all to the first 31 bits (31st will be hidden 1) */
-	if (counter > 33) {
-		i <<= counter - 1 - 32;
-	} else {
-		i >>= 1 + 32 - counter;
-	}
-	
-	j = (uint32_t) i;
-	round_float32(&exp, &j);
-	
-	result.parts.fraction = j >> (32 - FLOAT32_FRACTION_SIZE - 2);
-	result.parts.exp = exp;
-	return result;
-}
-
-float32 int64_to_float32(int64_t i)
-{
-	float32 result;
-	
-	if (i < 0)
-		result = uint64_to_float32((uint64_t) (-i));
-	else
-		result = uint64_to_float32((uint64_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-float64 uint32_to_float64(uint32_t i)
-{
-	int counter;
-	int32_t exp;
-	float64 result;
-	uint64_t frac;
-	
-	result.parts.sign = 0;
-	result.parts.fraction = 0;
-	
-	counter = count_zeroes32(i);
-	
-	exp = FLOAT64_BIAS + 32 - counter - 1;
-	
-	if (counter == 32) {
-		result.bin = 0;
-		return result;
-	}
-	
-	frac = i;
-	frac <<= counter + 32 - 1;
-	
-	round_float64(&exp, &frac);
-	
-	result.parts.fraction = frac >> (64 - FLOAT64_FRACTION_SIZE - 2);
-	result.parts.exp = exp;
-	
-	return result;
-}
-
-float64 int32_to_float64(int32_t i)
-{
-	float64 result;
-	
-	if (i < 0)
-		result = uint32_to_float64((uint32_t) (-i));
-	else
-		result = uint32_to_float64((uint32_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-
-float64 uint64_to_float64(uint64_t i)
-{
-	int counter;
-	int32_t exp;
-	float64 result;
-	
-	result.parts.sign = 0;
-	result.parts.fraction = 0;
-	
-	counter = count_zeroes64(i);
-	
-	exp = FLOAT64_BIAS + 64 - counter - 1;
-	
-	if (counter == 64) {
-		result.bin = 0;
-		return result;
-	}
-	
-	if (counter > 0) {
-		i <<= counter - 1;
-	} else {
-		i >>= 1;
-	}
-	
-	round_float64(&exp, &i);
-	
-	result.parts.fraction = i >> (64 - FLOAT64_FRACTION_SIZE - 2);
-	result.parts.exp = exp;
-	return result;
-}
-
-float64 int64_to_float64(int64_t i)
-{
-	float64 result;
-	
-	if (i < 0)
-		result = uint64_to_float64((uint64_t) (-i));
-	else
-		result = uint64_to_float64((uint64_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-float128 uint32_to_float128(uint32_t i)
-{
-	int counter;
-	int32_t exp;
-	float128 result;
-	uint64_t frac_hi, frac_lo;
-	
-	result.parts.sign = 0;
-	result.parts.frac_hi = 0;
-	result.parts.frac_lo = 0;
-	
-	counter = count_zeroes32(i);
-	
-	exp = FLOAT128_BIAS + 32 - counter - 1;
-	
-	if (counter == 32) {
-		result.bin.hi = 0;
-		result.bin.lo = 0;
-		return result;
-	}
-	
-	frac_hi = 0;
-	frac_lo = i;
-	lshift128(frac_hi, frac_lo, (counter + 96 - 1), &frac_hi, &frac_lo);
-	
-	round_float128(&exp, &frac_hi, &frac_lo);
-	
-	rshift128(frac_hi, frac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 2), &frac_hi, &frac_lo);
-	result.parts.frac_hi = frac_hi;
-	result.parts.frac_lo = frac_lo;
-	result.parts.exp = exp;
-	
-	return result;
-}
-
-float128 int32_to_float128(int32_t i)
-{
-	float128 result;
-	
-	if (i < 0)
-		result = uint32_to_float128((uint32_t) (-i));
-	else
-		result = uint32_to_float128((uint32_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-
-float128 uint64_to_float128(uint64_t i)
-{
-	int counter;
-	int32_t exp;
-	float128 result;
-	uint64_t frac_hi, frac_lo;
-	
-	result.parts.sign = 0;
-	result.parts.frac_hi = 0;
-	result.parts.frac_lo = 0;
-	
-	counter = count_zeroes64(i);
-	
-	exp = FLOAT128_BIAS + 64 - counter - 1;
-	
-	if (counter == 64) {
-		result.bin.hi = 0;
-		result.bin.lo = 0;
-		return result;
-	}
-	
-	frac_hi = 0;
-	frac_lo = i;
-	lshift128(frac_hi, frac_lo, (counter + 64 - 1), &frac_hi, &frac_lo);
-	
-	round_float128(&exp, &frac_hi, &frac_lo);
-	
-	rshift128(frac_hi, frac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 2), &frac_hi, &frac_lo);
-	result.parts.frac_hi = frac_hi;
-	result.parts.frac_lo = frac_lo;
-	result.parts.exp = exp;
-	
-	return result;
-}
-
-float128 int64_to_float128(int64_t i)
-{
-	float128 result;
-	
-	if (i < 0)
-		result = uint64_to_float128((uint64_t) (-i));
-	else
-		result = uint64_to_float128((uint64_t) i);
-	
-	result.parts.sign = i < 0;
-	
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/div.c
===================================================================
--- uspace/lib/softfloat/generic/div.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,542 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Division functions.
- */
-
-#include <sftypes.h>
-#include <add.h>
-#include <div.h>
-#include <comparison.h>
-#include <mul.h>
-#include <common.h>
-
-/** Divide two single-precision floats.
- *
- * @param a Nominator.
- * @param b Denominator.
- *
- * @return Result of division.
- *
- */
-float32 div_float32(float32 a, float32 b)
-{
-	float32 result;
-	int32_t aexp, bexp, cexp;
-	uint64_t afrac, bfrac, cfrac;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float32_nan(a)) {
-		if (is_float32_signan(a)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return a;
-	}
-	
-	if (is_float32_nan(b)) {
-		if (is_float32_signan(b)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return b;
-	}
-	
-	if (is_float32_infinity(a)) {
-		if (is_float32_infinity(b)) {
-			/*FIXME: inf / inf */
-			result.bin = FLOAT32_NAN;
-			return result;
-		}
-		/* inf / num */
-		result.parts.exp = a.parts.exp;
-		result.parts.fraction = a.parts.fraction;
-		return result;
-	}
-	
-	if (is_float32_infinity(b)) {
-		if (is_float32_zero(a)) {
-			/* FIXME 0 / inf */
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-		/* FIXME: num / inf*/
-		result.parts.exp = 0;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	if (is_float32_zero(b)) {
-		if (is_float32_zero(a)) {
-			/*FIXME: 0 / 0*/
-			result.bin = FLOAT32_NAN;
-			return result;
-		}
-		/* FIXME: division by zero */
-		result.parts.exp = 0;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	afrac = a.parts.fraction;
-	aexp = a.parts.exp;
-	bfrac = b.parts.fraction;
-	bexp = b.parts.exp;
-	
-	/* denormalized numbers */
-	if (aexp == 0) {
-		if (afrac == 0) {
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* normalize it*/
-		afrac <<= 1;
-		/* afrac is nonzero => it must stop */
-		while (!(afrac & FLOAT32_HIDDEN_BIT_MASK)) {
-			afrac <<= 1;
-			aexp--;
-		}
-	}
-	
-	if (bexp == 0) {
-		bfrac <<= 1;
-		/* bfrac is nonzero => it must stop */
-		while (!(bfrac & FLOAT32_HIDDEN_BIT_MASK)) {
-			bfrac <<= 1;
-			bexp--;
-		}
-	}
-	
-	afrac = (afrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE - 1);
-	bfrac = (bfrac | FLOAT32_HIDDEN_BIT_MASK) << (32 - FLOAT32_FRACTION_SIZE);
-	
-	if (bfrac <= (afrac << 1)) {
-		afrac >>= 1;
-		aexp++;
-	}
-	
-	cexp = aexp - bexp + FLOAT32_BIAS - 2;
-	
-	cfrac = (afrac << 32) / bfrac;
-	if ((cfrac & 0x3F) == 0) { 
-		cfrac |= (bfrac * cfrac != afrac << 32);
-	}
-	
-	/* pack and round */
-	
-	/* find first nonzero digit and shift result and detect possibly underflow */
-	while ((cexp > 0) && (cfrac) && (!(cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)))) {
-		cexp--;
-		cfrac <<= 1;
-		/* TODO: fix underflow */
-	}
-	
-	cfrac += (0x1 << 6); /* FIXME: 7 is not sure*/
-	
-	if (cfrac & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
-		++cexp;
-		cfrac >>= 1;
-	}
-	
-	/* check overflow */
-	if (cexp >= FLOAT32_MAX_EXPONENT) {
-		/* FIXME: overflow, return infinity */
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	if (cexp < 0) {
-		/* FIXME: underflow */
-		result.parts.exp = 0;
-		if ((cexp + FLOAT32_FRACTION_SIZE) < 0) {
-			result.parts.fraction = 0;
-			return result;
-		}
-		cfrac >>= 1;
-		while (cexp < 0) {
-			cexp++;
-			cfrac >>= 1;
-		}
-	} else {
-		result.parts.exp = (uint32_t) cexp;
-	}
-	
-	result.parts.fraction = ((cfrac >> 6) & (~FLOAT32_HIDDEN_BIT_MASK)); 
-	
-	return result;
-}
-
-/** Divide two double-precision floats.
- *
- * @param a Nominator.
- * @param b Denominator.
- *
- * @return Result of division.
- *
- */
-float64 div_float64(float64 a, float64 b) 
-{
-	float64 result;
-	int64_t aexp, bexp, cexp;
-	uint64_t afrac, bfrac, cfrac; 
-	uint64_t remlo, remhi;
-	uint64_t tmplo, tmphi;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float64_nan(a)) {
-		if (is_float64_signan(b)) {
-			// FIXME: SigNaN
-			return b;
-		}
-		
-		if (is_float64_signan(a)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return a;
-	}
-	
-	if (is_float64_nan(b)) {
-		if (is_float64_signan(b)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return b;
-	}
-	
-	if (is_float64_infinity(a)) {
-		if (is_float64_infinity(b) || is_float64_zero(b)) {
-			// FIXME: inf / inf
-			result.bin = FLOAT64_NAN;
-			return result;
-		}
-		/* inf / num */
-		result.parts.exp = a.parts.exp;
-		result.parts.fraction = a.parts.fraction;
-		return result;
-	}
-	
-	if (is_float64_infinity(b)) {
-		if (is_float64_zero(a)) {
-			/* FIXME 0 / inf */
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-		/* FIXME: num / inf*/
-		result.parts.exp = 0;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	if (is_float64_zero(b)) {
-		if (is_float64_zero(a)) {
-			/*FIXME: 0 / 0*/
-			result.bin = FLOAT64_NAN;
-			return result;
-		}
-		/* FIXME: division by zero */
-		result.parts.exp = 0;
-		result.parts.fraction = 0;
-		return result;
-	}
-	
-	afrac = a.parts.fraction;
-	aexp = a.parts.exp;
-	bfrac = b.parts.fraction;
-	bexp = b.parts.exp;
-	
-	/* denormalized numbers */
-	if (aexp == 0) {
-		if (afrac == 0) {
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-		
-		/* normalize it*/
-		aexp++;
-		/* afrac is nonzero => it must stop */	
-		while (!(afrac & FLOAT64_HIDDEN_BIT_MASK)) {
-			afrac <<= 1;
-			aexp--;
-		}
-	}
-	
-	if (bexp == 0) {
-		bexp++;
-		/* bfrac is nonzero => it must stop */	
-		while (!(bfrac & FLOAT64_HIDDEN_BIT_MASK)) {
-			bfrac <<= 1;
-			bexp--;
-		}
-	}
-	
-	afrac = (afrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 2);
-	bfrac = (bfrac | FLOAT64_HIDDEN_BIT_MASK) << (64 - FLOAT64_FRACTION_SIZE - 1);
-	
-	if (bfrac <= (afrac << 1)) {
-		afrac >>= 1;
-		aexp++;
-	}
-	
-	cexp = aexp - bexp + FLOAT64_BIAS - 2; 
-	
-	cfrac = div128est(afrac, 0x0ll, bfrac);
-	
-	if ((cfrac & 0x1FF) <= 2) {
-		mul64(bfrac, cfrac, &tmphi, &tmplo);
-		sub128(afrac, 0x0ll, tmphi, tmplo, &remhi, &remlo);
-		
-		while ((int64_t) remhi < 0) {
-			cfrac--;
-			add128(remhi, remlo, 0x0ll, bfrac, &remhi, &remlo);
-		}
-		cfrac |= (remlo != 0);
-	}
-	
-	/* round and shift */
-	result = finish_float64(cexp, cfrac, result.parts.sign);
-	return result;
-}
-
-/** Divide two quadruple-precision floats.
- *
- * @param a Nominator.
- * @param b Denominator.
- *
- * @return Result of division.
- *
- */
-float128 div_float128(float128 a, float128 b)
-{
-	float128 result;
-	int64_t aexp, bexp, cexp;
-	uint64_t afrac_hi, afrac_lo, bfrac_hi, bfrac_lo, cfrac_hi, cfrac_lo;
-	uint64_t shift_out;
-	uint64_t rem_hihi, rem_hilo, rem_lohi, rem_lolo;
-	uint64_t tmp_hihi, tmp_hilo, tmp_lohi, tmp_lolo;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float128_nan(a)) {
-		if (is_float128_signan(b)) {
-			// FIXME: SigNaN
-			return b;
-		}
-		
-		if (is_float128_signan(a)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return a;
-	}
-	
-	if (is_float128_nan(b)) {
-		if (is_float128_signan(b)) {
-			// FIXME: SigNaN
-		}
-		/* NaN */
-		return b;
-	}
-	
-	if (is_float128_infinity(a)) {
-		if (is_float128_infinity(b) || is_float128_zero(b)) {
-			// FIXME: inf / inf
-			result.bin.hi = FLOAT128_NAN_HI;
-			result.bin.lo = FLOAT128_NAN_LO;
-			return result;
-		}
-		/* inf / num */
-		result.parts.exp = a.parts.exp;
-		result.parts.frac_hi = a.parts.frac_hi;
-		result.parts.frac_lo = a.parts.frac_lo;
-		return result;
-	}
-	
-	if (is_float128_infinity(b)) {
-		if (is_float128_zero(a)) {
-			// FIXME 0 / inf
-			result.parts.exp = 0;
-			result.parts.frac_hi = 0;
-			result.parts.frac_lo = 0;
-			return result;
-		}
-		// FIXME: num / inf
-		result.parts.exp = 0;
-		result.parts.frac_hi = 0;
-		result.parts.frac_lo = 0;
-		return result;
-	}
-	
-	if (is_float128_zero(b)) {
-		if (is_float128_zero(a)) {
-			// FIXME: 0 / 0
-			result.bin.hi = FLOAT128_NAN_HI;
-			result.bin.lo = FLOAT128_NAN_LO;
-			return result;
-		}
-		// FIXME: division by zero
-		result.parts.exp = 0;
-		result.parts.frac_hi = 0;
-		result.parts.frac_lo = 0;
-		return result;
-	}
-	
-	afrac_hi = a.parts.frac_hi;
-	afrac_lo = a.parts.frac_lo;
-	aexp = a.parts.exp;
-	bfrac_hi = b.parts.frac_hi;
-	bfrac_lo = b.parts.frac_lo;
-	bexp = b.parts.exp;
-	
-	/* denormalized numbers */
-	if (aexp == 0) {
-		if (eq128(afrac_hi, afrac_lo, 0x0ll, 0x0ll)) {
-			result.parts.exp = 0;
-			result.parts.frac_hi = 0;
-			result.parts.frac_lo = 0;
-			return result;
-		}
-		
-		/* normalize it*/
-		aexp++;
-		/* afrac is nonzero => it must stop */
-		and128(afrac_hi, afrac_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hihi, &tmp_lolo);
-		while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
-			lshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
-			aexp--;
-		}
-	}
-	
-	if (bexp == 0) {
-		bexp++;
-		/* bfrac is nonzero => it must stop */
-		and128(bfrac_hi, bfrac_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &tmp_hihi, &tmp_lolo);
-		while (!lt128(0x0ll, 0x0ll, tmp_hihi, tmp_lolo)) {
-			lshift128(bfrac_hi, bfrac_lo, 1, &bfrac_hi, &bfrac_lo);
-			bexp--;
-		}
-	}
-	
-	or128(afrac_hi, afrac_lo,
-	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &afrac_hi, &afrac_lo);
-	lshift128(afrac_hi, afrac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 1), &afrac_hi, &afrac_lo);
-	or128(bfrac_hi, bfrac_lo,
-	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &bfrac_hi, &bfrac_lo);
-	lshift128(bfrac_hi, bfrac_lo,
-	    (128 - FLOAT128_FRACTION_SIZE - 1), &bfrac_hi, &bfrac_lo);
-	
-	if (le128(bfrac_hi, bfrac_lo, afrac_hi, afrac_lo)) {
-		rshift128(afrac_hi, afrac_lo, 1, &afrac_hi, &afrac_lo);
-		aexp++;
-	}
-	
-	cexp = aexp - bexp + FLOAT128_BIAS - 2;
-	
-	cfrac_hi = div128est(afrac_hi, afrac_lo, bfrac_hi);
-	
-	mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_hi,
-	    &tmp_lolo /* dummy */, &tmp_hihi, &tmp_hilo, &tmp_lohi);
-	
-	/* sub192(afrac_hi, afrac_lo, 0,
-	 *     tmp_hihi, tmp_hilo, tmp_lohi
-	 *     &rem_hihi, &rem_hilo, &rem_lohi); */
-	sub128(afrac_hi, afrac_lo, tmp_hihi, tmp_hilo, &rem_hihi, &rem_hilo);
-	if (tmp_lohi > 0) {
-		sub128(rem_hihi, rem_hilo, 0x0ll, 0x1ll, &rem_hihi, &rem_hilo);
-	}
-	rem_lohi = -tmp_lohi;
-	
-	while ((int64_t) rem_hihi < 0) {
-		--cfrac_hi;
-		/* add192(rem_hihi, rem_hilo, rem_lohi,
-		 *     0, bfrac_hi, bfrac_lo,
-		 *     &rem_hihi, &rem_hilo, &rem_lohi); */
-		add128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo, &rem_hilo, &rem_lohi);
-		if (lt128(rem_hilo, rem_lohi, bfrac_hi, bfrac_lo)) {
-			++rem_hihi;
-		}
-	}
-	
-	cfrac_lo = div128est(rem_hilo, rem_lohi, bfrac_lo);
-	
-	if ((cfrac_lo & 0x3FFF) <= 4) {
-		mul128(bfrac_hi, bfrac_lo, 0x0ll, cfrac_lo,
-		    &tmp_hihi /* dummy */, &tmp_hilo, &tmp_lohi, &tmp_lolo);
-		
-		/* sub192(rem_hilo, rem_lohi, 0,
-		 *     tmp_hilo, tmp_lohi, tmp_lolo,
-		 *     &rem_hilo, &rem_lohi, &rem_lolo); */
-		sub128(rem_hilo, rem_lohi, tmp_hilo, tmp_lohi, &rem_hilo, &rem_lohi);
-		if (tmp_lolo > 0) {
-			sub128(rem_hilo, rem_lohi, 0x0ll, 0x1ll, &rem_hilo, &rem_lohi);
-		}
-		rem_lolo = -tmp_lolo;
-		
-		while ((int64_t) rem_hilo < 0) {
-			--cfrac_lo;
-			/* add192(rem_hilo, rem_lohi, rem_lolo,
-			 *     0, bfrac_hi, bfrac_lo,
-			 *     &rem_hilo, &rem_lohi, &rem_lolo); */
-			add128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo, &rem_lohi, &rem_lolo);
-			if (lt128(rem_lohi, rem_lolo, bfrac_hi, bfrac_lo)) {
-				++rem_hilo;
-			}
-		}
-		
-		cfrac_lo |= ((rem_hilo | rem_lohi | rem_lolo) != 0 );
-	}
-	
-	shift_out = cfrac_lo << (64 - (128 - FLOAT128_FRACTION_SIZE - 1));
-	rshift128(cfrac_hi, cfrac_lo, (128 - FLOAT128_FRACTION_SIZE - 1),
-	    &cfrac_hi, &cfrac_lo);
-	
-	result = finish_float128(cexp, cfrac_hi, cfrac_lo, result.parts.sign, shift_out);
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/mul.c
===================================================================
--- uspace/lib/softfloat/generic/mul.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,383 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Multiplication functions.
- */
-
-#include <sftypes.h>
-#include <mul.h>
-#include <comparison.h>
-#include <common.h>
-
-/** Multiply two single-precision floats.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of multiplication.
- *
- */
-float32 mul_float32(float32 a, float32 b)
-{
-	float32 result;
-	uint64_t frac1, frac2;
-	int32_t exp;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float32_nan(a) || is_float32_nan(b)) {
-		/* TODO: fix SigNaNs */
-		if (is_float32_signan(a)) {
-			result.parts.fraction = a.parts.fraction;
-			result.parts.exp = a.parts.exp;
-			return result;
-		}
-		if (is_float32_signan(b)) { /* TODO: fix SigNaN */
-			result.parts.fraction = b.parts.fraction;
-			result.parts.exp = b.parts.exp;
-			return result;
-		}
-		/* set NaN as result */
-		result.bin = FLOAT32_NAN;
-		return result;
-	}
-	
-	if (is_float32_infinity(a)) {
-		if (is_float32_zero(b)) {
-			/* FIXME: zero * infinity */
-			result.bin = FLOAT32_NAN;
-			return result;
-		}
-		result.parts.fraction = a.parts.fraction;
-		result.parts.exp = a.parts.exp;
-		return result;
-	}
-	
-	if (is_float32_infinity(b)) {
-		if (is_float32_zero(a)) {
-			/* FIXME: zero * infinity */
-			result.bin = FLOAT32_NAN;
-			return result;
-		}
-		result.parts.fraction = b.parts.fraction;
-		result.parts.exp = b.parts.exp;
-		return result;
-	}
-	
-	/* exp is signed so we can easy detect underflow */
-	exp = a.parts.exp + b.parts.exp;
-	exp -= FLOAT32_BIAS;
-	
-	if (exp >= FLOAT32_MAX_EXPONENT) {
-		/* FIXME: overflow */
-		/* set infinity as result */
-		result.bin = FLOAT32_INF;
-		result.parts.sign = a.parts.sign ^ b.parts.sign;
-		return result;
-	}
-	
-	if (exp < 0) { 
-		/* FIXME: underflow */
-		/* return signed zero */
-		result.parts.fraction = 0x0;
-		result.parts.exp = 0x0;
-		return result;
-	}
-	
-	frac1 = a.parts.fraction;
-	if (a.parts.exp > 0) {
-		frac1 |= FLOAT32_HIDDEN_BIT_MASK;
-	} else {
-		++exp;
-	}
-	
-	frac2 = b.parts.fraction;
-	
-	if (b.parts.exp > 0) {
-		frac2 |= FLOAT32_HIDDEN_BIT_MASK;
-	} else {
-		++exp;
-	}
-	
-	frac1 <<= 1; /* one bit space for rounding */
-	
-	frac1 = frac1 * frac2;
-	
-	/* round and return */
-	while ((exp < FLOAT32_MAX_EXPONENT) &&
-	    (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 2)))) {
-		/* 23 bits of fraction + one more for hidden bit (all shifted 1 bit left) */
-		++exp;
-		frac1 >>= 1;
-	}
-	
-	/* rounding */
-	/* ++frac1; FIXME: not works - without it is ok */
-	frac1 >>= 1; /* shift off rounding space */
-	
-	if ((exp < FLOAT32_MAX_EXPONENT) &&
-	    (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 1)))) {
-		++exp;
-		frac1 >>= 1;
-	}
-	
-	if (exp >= FLOAT32_MAX_EXPONENT) {
-		/* TODO: fix overflow */
-		/* return infinity*/
-		result.parts.exp = FLOAT32_MAX_EXPONENT;
-		result.parts.fraction = 0x0;
-		return result;
-	}
-	
-	exp -= FLOAT32_FRACTION_SIZE;
-	
-	if (exp <= FLOAT32_FRACTION_SIZE) {
-		/* denormalized number */
-		frac1 >>= 1; /* denormalize */
-		while ((frac1 > 0) && (exp < 0)) {
-			frac1 >>= 1;
-			++exp;
-		}
-		if (frac1 == 0) {
-			/* FIXME : underflow */
-			result.parts.exp = 0;
-			result.parts.fraction = 0;
-			return result;
-		}
-	}
-	result.parts.exp = exp; 
-	result.parts.fraction = frac1 & ((1 << FLOAT32_FRACTION_SIZE) - 1);
-	
-	return result;
-}
-
-/** Multiply two double-precision floats.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of multiplication.
- *
- */
-float64 mul_float64(float64 a, float64 b)
-{
-	float64 result;
-	uint64_t frac1, frac2;
-	int32_t exp;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float64_nan(a) || is_float64_nan(b)) {
-		/* TODO: fix SigNaNs */
-		if (is_float64_signan(a)) {
-			result.parts.fraction = a.parts.fraction;
-			result.parts.exp = a.parts.exp;
-			return result;
-		}
-		if (is_float64_signan(b)) { /* TODO: fix SigNaN */
-			result.parts.fraction = b.parts.fraction;
-			result.parts.exp = b.parts.exp;
-			return result;
-		}
-		/* set NaN as result */
-		result.bin = FLOAT64_NAN;
-		return result;
-	}
-	
-	if (is_float64_infinity(a)) {
-		if (is_float64_zero(b)) {
-			/* FIXME: zero * infinity */
-			result.bin = FLOAT64_NAN;
-			return result;
-		}
-		result.parts.fraction = a.parts.fraction;
-		result.parts.exp = a.parts.exp;
-		return result;
-	}
-	
-	if (is_float64_infinity(b)) {
-		if (is_float64_zero(a)) {
-			/* FIXME: zero * infinity */
-			result.bin = FLOAT64_NAN;
-			return result;
-		}
-		result.parts.fraction = b.parts.fraction;
-		result.parts.exp = b.parts.exp;
-		return result;
-	}
-	
-	/* exp is signed so we can easy detect underflow */
-	exp = a.parts.exp + b.parts.exp - FLOAT64_BIAS;
-	
-	frac1 = a.parts.fraction;
-	
-	if (a.parts.exp > 0) {
-		frac1 |= FLOAT64_HIDDEN_BIT_MASK;
-	} else {
-		++exp;
-	}
-	
-	frac2 = b.parts.fraction;
-	
-	if (b.parts.exp > 0) {
-		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
-	} else {
-		++exp;
-	}
-	
-	frac1 <<= (64 - FLOAT64_FRACTION_SIZE - 1);
-	frac2 <<= (64 - FLOAT64_FRACTION_SIZE - 2);
-	
-	mul64(frac1, frac2, &frac1, &frac2);
-	
-	frac1 |= (frac2 != 0);
-	if (frac1 & (0x1ll << 62)) {
-		frac1 <<= 1;
-		exp--;
-	}
-	
-	result = finish_float64(exp, frac1, result.parts.sign);
-	return result;
-}
-
-/** Multiply two quadruple-precision floats.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of multiplication.
- *
- */
-float128 mul_float128(float128 a, float128 b)
-{
-	float128 result;
-	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
-	int32_t exp;
-	
-	result.parts.sign = a.parts.sign ^ b.parts.sign;
-	
-	if (is_float128_nan(a) || is_float128_nan(b)) {
-		/* TODO: fix SigNaNs */
-		if (is_float128_signan(a)) {
-			result.parts.frac_hi = a.parts.frac_hi;
-			result.parts.frac_lo = a.parts.frac_lo;
-			result.parts.exp = a.parts.exp;
-			return result;
-		}
-		if (is_float128_signan(b)) { /* TODO: fix SigNaN */
-			result.parts.frac_hi = b.parts.frac_hi;
-			result.parts.frac_lo = b.parts.frac_lo;
-			result.parts.exp = b.parts.exp;
-			return result;
-		}
-		/* set NaN as result */
-		result.bin.hi = FLOAT128_NAN_HI;
-		result.bin.lo = FLOAT128_NAN_LO;
-		return result;
-	}
-	
-	if (is_float128_infinity(a)) {
-		if (is_float128_zero(b)) {
-			/* FIXME: zero * infinity */
-			result.bin.hi = FLOAT128_NAN_HI;
-			result.bin.lo = FLOAT128_NAN_LO;
-			return result;
-		}
-		result.parts.frac_hi = a.parts.frac_hi;
-		result.parts.frac_lo = a.parts.frac_lo;
-		result.parts.exp = a.parts.exp;
-		return result;
-	}
-	
-	if (is_float128_infinity(b)) {
-		if (is_float128_zero(a)) {
-			/* FIXME: zero * infinity */
-			result.bin.hi = FLOAT128_NAN_HI;
-			result.bin.lo = FLOAT128_NAN_LO;
-			return result;
-		}
-		result.parts.frac_hi = b.parts.frac_hi;
-		result.parts.frac_lo = b.parts.frac_lo;
-		result.parts.exp = b.parts.exp;
-		return result;
-	}
-	
-	/* exp is signed so we can easy detect underflow */
-	exp = a.parts.exp + b.parts.exp - FLOAT128_BIAS - 1;
-	
-	frac1_hi = a.parts.frac_hi;
-	frac1_lo = a.parts.frac_lo;
-	
-	if (a.parts.exp > 0) {
-		or128(frac1_hi, frac1_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &frac1_hi, &frac1_lo);
-	} else {
-		++exp;
-	}
-	
-	frac2_hi = b.parts.frac_hi;
-	frac2_lo = b.parts.frac_lo;
-	
-	if (b.parts.exp > 0) {
-		or128(frac2_hi, frac2_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &frac2_hi, &frac2_lo);
-	} else {
-		++exp;
-	}
-	
-	lshift128(frac2_hi, frac2_lo,
-	    128 - FLOAT128_FRACTION_SIZE, &frac2_hi, &frac2_lo);
-	
-	tmp_hi = frac1_hi;
-	tmp_lo = frac1_lo;
-	mul128(frac1_hi, frac1_lo, frac2_hi, frac2_lo,
-	    &frac1_hi, &frac1_lo, &frac2_hi, &frac2_lo);
-	add128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
-	frac2_hi |= (frac2_lo != 0x0ll);
-	
-	if ((FLOAT128_HIDDEN_BIT_MASK_HI << 1) <= frac1_hi) {
-		frac2_hi >>= 1;
-		if (frac1_lo & 0x1ll) {
-			frac2_hi |= (0x1ull < 64);
-		}
-		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-		++exp;
-	}
-	
-	result = finish_float128(exp, frac1_hi, frac1_lo, result.parts.sign, frac2_hi);
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/other.c
===================================================================
--- uspace/lib/softfloat/generic/other.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,37 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Other functions (power, complex).
- */
-
-
-/** @}
- */
Index: pace/lib/softfloat/generic/softfloat.c
===================================================================
--- uspace/lib/softfloat/generic/softfloat.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,1325 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat generic
- * @ingroup sfl
- * @brief Architecture independent parts of FPU software emulation library.
- * @{
- */
-/** @file Softfloat API.
- */
-
-#include <softfloat.h>
-#include <sftypes.h>
-
-#include <add.h>
-#include <sub.h>
-#include <mul.h>
-#include <div.h>
-
-#include <conversion.h>
-#include <comparison.h>
-#include <other.h>
-
-/* Arithmetic functions */
-
-float __addsf3(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	float_t res;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if (fa.data.parts.sign != fb.data.parts.sign) {
-		if (fa.data.parts.sign) {
-			fa.data.parts.sign = 0;
-			res.data = sub_float(fb.data, fa.data);
-			
-			return res.val;
-		}
-		
-		fb.data.parts.sign = 0;
-		res.data = sub_float(fa.data, fb.data);
-		
-		return res.val;
-	}
-	
-	res.data = add_float(fa.data, fb.data);
-	return res.val;
-}
-
-double __adddf3(double a, double b)
-{
-	double_t da;
-	double_t db;
-	double_t res;
-	
-	da.val = a;
-	db.val = b;
-	
-	if (da.data.parts.sign != db.data.parts.sign) {
-		if (da.data.parts.sign) {
-			da.data.parts.sign = 0;
-			res.data = sub_double(db.data, da.data);
-			
-			return res.val;
-		}
-		
-		db.data.parts.sign = 0;
-		res.data = sub_double(da.data, db.data);
-		
-		return res.val;
-	}
-	
-	res.data = add_double(da.data, db.data);
-	return res.val;
-}
-
-long double __addtf3(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	long_double_t res;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if (ta.data.parts.sign != tb.data.parts.sign) {
-		if (ta.data.parts.sign) {
-			ta.data.parts.sign = 0;
-			res.data = sub_long_double(tb.data, ta.data);
-			
-			return res.val;
-		}
-		
-		tb.data.parts.sign = 0;
-		res.data = sub_long_double(ta.data, tb.data);
-		
-		return res.val;
-	}
-	
-	res.data = add_long_double(ta.data, tb.data);
-	return res.val;
-}
-
-float __subsf3(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	float_t res;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if (fa.data.parts.sign != fb.data.parts.sign) {
-		fb.data.parts.sign = !fb.data.parts.sign;
-		res.data = add_float(fa.data, fb.data);
-		
-		return res.val;
-	}
-	
-	res.data = sub_float(fa.data, fb.data);
-	return res.val;
-}
-
-double __subdf3(double a, double b)
-{
-	double_t da;
-	double_t db;
-	double_t res;
-	
-	da.val = a;
-	db.val = b;
-	
-	if (da.data.parts.sign != db.data.parts.sign) {
-		db.data.parts.sign = !db.data.parts.sign;
-		res.data = add_double(da.data, db.data);
-		
-		return res.val;
-	}
-	
-	res.data = sub_double(da.data, db.data);
-	return res.val;
-}
-
-long double __subtf3(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	long_double_t res;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if (ta.data.parts.sign != tb.data.parts.sign) {
-		tb.data.parts.sign = !tb.data.parts.sign;
-		res.data = add_long_double(ta.data, tb.data);
-		
-		return res.val;
-	}
-	
-	res.data = sub_long_double(ta.data, tb.data);
-	return res.val;
-}
-
-float __mulsf3(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	float_t res;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	res.data = mul_float(fa.data, fb.data);
-	return res.val;
-}
-
-double __muldf3(double a, double b)
-{
-	double_t da;
-	double_t db;
-	double_t res;
-	
-	da.val = a;
-	db.val = b;
-	
-	res.data = mul_double(da.data, db.data);
-	return res.val;
-}
-
-long double __multf3(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	long_double_t res;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	res.data = mul_long_double(ta.data, tb.data);
-	return res.val;
-}
-
-float __divsf3(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	float_t res;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	res.data = div_float(fa.data, fb.data);
-	return res.val;
-}
-
-double __divdf3(double a, double b)
-{
-	double_t da;
-	double_t db;
-	double_t res;
-	
-	da.val = a;
-	db.val = b;
-	
-	res.data = div_double(da.data, db.data);
-	return res.val;
-}
-
-long double __divtf3(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	long_double_t res;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	res.data = div_long_double(ta.data, tb.data);
-	return res.val;
-}
-
-float __negsf2(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	fa.data.parts.sign = !fa.data.parts.sign;
-	
-	return fa.val;
-}
-
-double __negdf2(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	da.data.parts.sign = !da.data.parts.sign;
-	
-	return da.val;
-}
-
-long double __negtf2(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	ta.data.parts.sign = !ta.data.parts.sign;
-	
-	return ta.val;
-}
-
-/* Conversion functions */
-
-double __extendsfdf2(float a)
-{
-	float_t fa;
-	double_t res;
-	
-	fa.val = a;
-	res.data = float_to_double(fa.data);
-	
-	return res.val;
-}
-
-long double __extendsftf2(float a)
-{
-	float_t fa;
-	long_double_t res;
-	
-	fa.val = a;
-	res.data = float_to_long_double(fa.data);
-	
-	return res.val;
-}
-
-long double __extenddftf2(double a)
-{
-	double_t da;
-	long_double_t res;
-	
-	da.val = a;
-	res.data = double_to_long_double(da.data);
-	
-	return res.val;
-}
-
-float __truncdfsf2(double a)
-{
-	double_t da;
-	float_t res;
-	
-	da.val = a;
-	res.data = double_to_float(da.data);
-	
-	return res.val;
-}
-
-float __trunctfsf2(long double a)
-{
-	long_double_t ta;
-	float_t res;
-	
-	ta.val = a;
-	res.data = long_double_to_float(ta.data);
-	
-	return res.val;
-}
-
-double __trunctfdf2(long double a)
-{
-	long_double_t ta;
-	double_t res;
-	
-	ta.val = a;
-	res.data = long_double_to_double(ta.data);
-	
-	return res.val;
-}
-
-int __fixsfsi(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_int(fa.data);
-}
-
-int __fixdfsi(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_int(da.data);
-}
-
-int __fixtfsi(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_int(ta.data);
-}
- 
-long __fixsfdi(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_long(fa.data);
-}
-
-long __fixdfdi(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_long(da.data);
-}
-
-long __fixtfdi(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_long(ta.data);
-}
- 
-long long __fixsfti(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_llong(fa.data);
-}
-
-long long __fixdfti(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_llong(da.data);
-}
-
-long long __fixtfti(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_llong(ta.data);
-}
-
-unsigned int __fixunssfsi(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_uint(fa.data);
-}
-
-unsigned int __fixunsdfsi(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_uint(da.data);
-}
-
-unsigned int __fixunstfsi(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_uint(ta.data);
-}
- 
-unsigned long __fixunssfdi(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_ulong(fa.data);
-}
-
-unsigned long __fixunsdfdi(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_ulong(da.data);
-}
-
-unsigned long __fixunstfdi(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_ulong(ta.data);
-}
- 
-unsigned long long __fixunssfti(float a)
-{
-	float_t fa;
-	
-	fa.val = a;
-	return float_to_ullong(fa.data);
-}
-
-unsigned long long __fixunsdfti(double a)
-{
-	double_t da;
-	
-	da.val = a;
-	return double_to_ullong(da.data);
-}
-
-unsigned long long __fixunstfti(long double a)
-{
-	long_double_t ta;
-	
-	ta.val = a;
-	return long_double_to_ullong(ta.data);
-}
- 
-float __floatsisf(int i)
-{
-	float_t res;
-	
-	res.data = int_to_float(i);
-	return res.val;
-}
-
-double __floatsidf(int i)
-{
-	double_t res;
-	
-	res.data = int_to_double(i);
-	return res.val;
-}
-
-long double __floatsitf(int i)
-{
-	long_double_t res;
-	
-	res.data = int_to_long_double(i);
-	return res.val;
-}
- 
-float __floatdisf(long i)
-{
-	float_t res;
-	
-	res.data = long_to_float(i);
-	return res.val;
-}
-
-double __floatdidf(long i)
-{
-	double_t res;
-	
-	res.data = long_to_double(i);
-	return res.val;
-}
-
-long double __floatditf(long i)
-{
-	long_double_t res;
-	
-	res.data = long_to_long_double(i);
-	return res.val;
-}
-
-float __floattisf(long long i)
-{
-	float_t res;
-	
-	res.data = llong_to_float(i);
-	return res.val;
-}
-
-double __floattidf(long long i)
-{
-	double_t res;
-	
-	res.data = llong_to_double(i);
-	return res.val;
-}
-
-long double __floattitf(long long i)
-{
-	long_double_t res;
-	
-	res.data = llong_to_long_double(i);
-	return res.val;
-}
-
-float __floatunsisf(unsigned int i)
-{
-	float_t res;
-	
-	res.data = uint_to_float(i);
-	return res.val;
-}
-
-double __floatunsidf(unsigned int i)
-{
-	double_t res;
-	
-	res.data = uint_to_double(i);
-	return res.val;
-}
-
-long double __floatunsitf(unsigned int i)
-{
-	long_double_t res;
-	
-	res.data = uint_to_long_double(i);
-	return res.val;
-}
- 
-float __floatundisf(unsigned long i)
-{
-	float_t res;
-	
-	res.data = ulong_to_float(i);
-	return res.val;
-}
-
-double __floatundidf(unsigned long i)
-{
-	double_t res;
-	
-	res.data = ulong_to_double(i);
-	return res.val;
-}
-
-long double __floatunditf(unsigned long i)
-{
-	long_double_t res;
-	
-	res.data = ulong_to_long_double(i);
-	return res.val;
-}
- 
-float __floatuntisf(unsigned long long i)
-{
-	float_t res;
-	
-	res.data = ullong_to_float(i);
-	return res.val;
-}
-
-double __floatuntidf(unsigned long long i)
-{
-	double_t res;
-	
-	res.data = ullong_to_double(i);
-	return res.val;
-}
-
-long double __floatuntitf(unsigned long long i)
-{
-	long_double_t res;
-	
-	res.data = ullong_to_long_double(i);
-	return res.val;
-}
-
-/* Comparison functions */
-
-int __cmpsf2(float a, float b) 
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		/* no special constant for unordered - maybe signaled? */
-		return 1;
-	}
-	
-	if (is_float_eq(fa.data, fb.data))
-		return 0;
-	
-	if (is_float_lt(fa.data, fb.data))
-		return -1;
-	
-	return 1;
-}
-
-int __cmpdf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		/* no special constant for unordered - maybe signaled? */
-		return 1;
-	}
-	
-	if (is_double_eq(da.data, db.data))
-		return 0;
-	
-	if (is_double_lt(da.data, db.data))
-		return -1;
-	
-	return 1;
-}
-
-int __cmptf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		/* no special constant for unordered - maybe signaled? */
-		return 1;
-	}
-	
-	if (is_long_double_eq(ta.data, tb.data))
-		return 0;
-	
-	if (is_long_double_lt(ta.data, tb.data))
-		return -1;
-	
-	return 1;
-}
-
-int __unordsf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	return ((is_float_nan(fa.data)) || (is_float_nan(fb.data)));
-}
-
-int __unorddf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	return ((is_double_nan(da.data)) || (is_double_nan(db.data)));
-}
-
-int __unordtf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	return ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)));
-}
-
-int __eqsf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	return is_float_eq(fa.data, fb.data) - 1;
-}
-
-int __eqdf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	return is_double_eq(da.data, db.data) - 1;
-}
-
-int __eqtf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	return is_long_double_eq(ta.data, tb.data) - 1;
-}
-
-int __nesf2(float a, float b)
-{
-	/* strange behavior, but it was in gcc documentation */
-	return __eqsf2(a, b);
-}
-
-int __nedf2(double a, double b)
-{
-	/* strange behavior, but it was in gcc documentation */
-	return __eqdf2(a, b);
-}
-
-int __netf2(long double a, long double b)
-{
-	/* strange behavior, but it was in gcc documentation */
-	return __eqtf2(a, b);
-}
-
-int __gesf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_float_eq(fa.data, fb.data))
-		return 0;
-	
-	if (is_float_gt(fa.data, fb.data))
-		return 1;
-	
-	return -1;
-}
-
-int __gedf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_double_eq(da.data, db.data))
-		return 0;
-	
-	if (is_double_gt(da.data, db.data))
-		return 1;
-	
-	return -1;
-}
-
-int __getf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_long_double_eq(ta.data, tb.data))
-		return 0;
-	
-	if (is_long_double_gt(ta.data, tb.data))
-		return 1;
-	
-	return -1;
-}
-
-int __ltsf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_float_lt(fa.data, fb.data))
-		return -1;
-	
-	return 0;
-}
-
-int __ltdf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_double_lt(da.data, db.data))
-		return -1;
-	
-	return 0;
-}
-
-int __lttf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_long_double_lt(ta.data, tb.data))
-		return -1;
-	
-	return 0;
-}
-
-int __lesf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_float_eq(fa.data, fb.data))
-		return 0;
-	
-	if (is_float_lt(fa.data, fb.data))
-		return -1;
-	
-	return 1;
-}
-
-int __ledf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_double_eq(da.data, db.data))
-		return 0;
-	
-	if (is_double_lt(da.data, db.data))
-		return -1;
-	
-	return 1;
-}
-
-int __letf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return 1;
-	}
-	
-	if (is_long_double_eq(ta.data, tb.data))
-		return 0;
-	
-	if (is_long_double_lt(ta.data, tb.data))
-		return -1;
-	
-	return 1;
-}
-
-int __gtsf2(float a, float b)
-{
-	float_t fa;
-	float_t fb;
-	
-	fa.val = a;
-	fb.val = b;
-	
-	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_float_gt(fa.data, fb.data))
-		return 1;
-	
-	return 0;
-}
-
-int __gtdf2(double a, double b)
-{
-	double_t da;
-	double_t db;
-	
-	da.val = a;
-	db.val = b;
-	
-	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_double_gt(da.data, db.data))
-		return 1;
-	
-	return 0;
-}
-
-int __gttf2(long double a, long double b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = a;
-	tb.val = b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
-		// TODO: sigNaNs
-		return -1;
-	}
-	
-	if (is_long_double_gt(ta.data, tb.data))
-		return 1;
-	
-	return 0;
-}
-
-/* SPARC quadruple-precision wrappers */
-
-void _Qp_add(long double *c, long double *a, long double *b)
-{
-	*c = __addtf3(*a, *b);
-}
-
-void _Qp_sub(long double *c, long double *a, long double *b)
-{
-	*c = __subtf3(*a, *b);
-}
-
-void _Qp_mul(long double *c, long double *a, long double *b)
-{
-	*c = __multf3(*a, *b);
-}
-
-void _Qp_div(long double *c, long double *a, long double *b)
-{
-	*c = __divtf3(*a, *b);
-}
-
-void _Qp_neg(long double *c, long double *a)
-{
-	*c = __negtf2(*a);
-}
-
-void _Qp_stoq(long double *c, float a)
-{
-	*c = __extendsftf2(a);
-}
-
-void _Qp_dtoq(long double *c, double a)
-{
-	*c = __extenddftf2(a);
-}
-
-float _Qp_qtos(long double *a)
-{
-	return __trunctfsf2(*a);
-}
-
-double _Qp_qtod(long double *a)
-{
-	return __trunctfdf2(*a);
-}
-
-int _Qp_qtoi(long double *a)
-{
-	return __fixtfsi(*a);
-}
-
-unsigned int _Qp_qtoui(long double *a)
-{
-	return __fixunstfsi(*a);
-}
-
-long _Qp_qtox(long double *a)
-{
-	return __fixtfdi(*a);
-}
-
-unsigned long _Qp_qtoux(long double *a)
-{
-	return __fixunstfdi(*a);
-}
-
-void _Qp_itoq(long double *c, int a)
-{
-	*c = __floatsitf(a);
-}
-
-void _Qp_uitoq(long double *c, unsigned int a)
-{
-	*c = __floatunsitf(a);
-}
-
-void _Qp_xtoq(long double *c, long a)
-{
-	*c = __floatditf(a);
-}
-
-void _Qp_uxtoq(long double *c, unsigned long a)
-{
-	*c = __floatunditf(a);
-}
-
-int _Qp_cmp(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 3;
-	
-	if (is_long_double_eq(ta.data, tb.data))
-		return 0;
-	
-	if (is_long_double_lt(ta.data, tb.data))
-		return 1;
-	
-	return 2;
-}
-
-int _Qp_cmpe(long double *a, long double *b)
-{
-	/* strange, but is defined this way in SPARC Compliance Definition */
-	return _Qp_cmp(a, b);
-}
-
-int _Qp_feq(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_eq(ta.data, tb.data);
-}
-
-int _Qp_fge(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_eq(ta.data, tb.data) ||
-	    is_long_double_gt(ta.data, tb.data);
-}
-
-int _Qp_fgt(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_gt(ta.data, tb.data);
-}
-
-int _Qp_fle(long double*a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_eq(ta.data, tb.data) ||
-	    is_long_double_lt(ta.data, tb.data);
-}
-
-int _Qp_flt(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return is_long_double_lt(ta.data, tb.data);
-}
-
-int _Qp_fne(long double *a, long double *b)
-{
-	long_double_t ta;
-	long_double_t tb;
-	
-	ta.val = *a;
-	tb.val = *b;
-	
-	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
-		return 0;
-	
-	return !is_long_double_eq(ta.data, tb.data);
-}
-
-double __aeabi_i2d(int i)
-{
-	return __floatsidf(i);
-}
-
-double __aeabi_ui2d(unsigned int i)
-{
-	return __floatunsidf(i);
-}
-
-int __aeabi_d2iz(double a)
-{
-	return __fixdfsi(a);
-}
-
-unsigned int __aeabi_d2uiz(double a)
-{
-	return __fixunsdfsi(a);
-}
-
-int __aeabi_dcmpge(double a, double b)
-{
-	return __gedf2(a, b);
-}
-
-int __aeabi_dcmpgt(double a, double b)
-{
-	return __gtdf2(a, b);
-}
-
-int __aeabi_dcmplt(double a, double b)
-{
-	return __ltdf2(a, b);
-}
-
-double __aeabi_dadd(double a, double b)
-{
-	return __adddf3(a, b);
-}
-
-double __aeabi_dsub(double a, double b)
-{
-	return __subdf3(a, b);
-}
-
-double __aeabi_dmul(double a, double b)
-{
-	return __muldf3(a, b);
-}
-
-double __aeabi_ddiv(double a, double b)
-{
-	return __divdf3(a, b);
-}
-
-/** @}
- */
Index: pace/lib/softfloat/generic/sub.c
===================================================================
--- uspace/lib/softfloat/generic/sub.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,441 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Substraction functions.
- */
-
-#include <sftypes.h>
-#include <sub.h>
-#include <comparison.h>
-#include <common.h>
-
-/** Subtract two single-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of substraction.
- *
- */
-float32 sub_float32(float32 a, float32 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2, frac1, frac2;
-	float32 result;
-	
-	result.bin = 0;
-	
-	expdiff = a.parts.exp - b.parts.exp;
-	if ((expdiff < 0 ) || ((expdiff == 0) &&
-	    (a.parts.fraction < b.parts.fraction))) {
-		if (is_float32_nan(b)) {
-			if (is_float32_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return b;
-		}
-		
-		if (b.parts.exp == FLOAT32_MAX_EXPONENT) {
-			/* num -(+-inf) = -+inf */
-			b.parts.sign = !b.parts.sign;
-			return b;
-		}
-		
-		result.parts.sign = !a.parts.sign;
-		
-		frac1 = b.parts.fraction;
-		exp1 = b.parts.exp;
-		frac2 = a.parts.fraction;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float32_nan(a)) {
-			if ((is_float32_signan(a)) || (is_float32_signan(b))) {
-				// TODO: fix SigNaN
-			}
-			
-			return a;
-		}
-		
-		if (a.parts.exp == FLOAT32_MAX_EXPONENT) {
-			if (b.parts.exp == FLOAT32_MAX_EXPONENT) {
-				/* inf - inf => nan */
-				// TODO: fix exception
-				result.bin = FLOAT32_NAN;
-				return result;
-			}
-			
-			return a;
-		}
-		
-		result.parts.sign = a.parts.sign;
-		
-		frac1 = a.parts.fraction;
-		exp1 = a.parts.exp;
-		frac2 = b.parts.fraction;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		result.parts.fraction = frac1 - frac2;
-		if (result.parts.fraction > frac1) {
-			// TODO: underflow exception
-			return result;
-		}
-		
-		result.parts.exp = 0;
-		return result;
-	}
-	
-	/* add hidden bit */
-	frac1 |= FLOAT32_HIDDEN_BIT_MASK;
-	
-	if (exp2 == 0) {
-		/* denormalized */
-		--expdiff;
-	} else {
-		/* normalized */
-		frac2 |= FLOAT32_HIDDEN_BIT_MASK;
-	}
-	
-	/* create some space for rounding */
-	frac1 <<= 6;
-	frac2 <<= 6;
-	
-	if (expdiff > FLOAT32_FRACTION_SIZE + 1)
-		goto done;
-	
-	frac1 = frac1 - (frac2 >> expdiff);
-	
-done:
-	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
-	while ((exp1 > 0) && (!(frac1 & (FLOAT32_HIDDEN_BIT_MASK << 6 )))) {
-		--exp1;
-		frac1 <<= 1;
-		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	frac1 += 0x20;
-	
-	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	/* Clear hidden bit and shift */
-	result.parts.fraction = ((frac1 >> 6) & (~FLOAT32_HIDDEN_BIT_MASK));
-	result.parts.exp = exp1;
-	
-	return result;
-}
-
-/** Subtract two double-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of substraction.
- *
- */
-float64 sub_float64(float64 a, float64 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2;
-	uint64_t frac1, frac2;
-	float64 result;
-	
-	result.bin = 0;
-	
-	expdiff = a.parts.exp - b.parts.exp;
-	if ((expdiff < 0 ) ||
-	    ((expdiff == 0) && (a.parts.fraction < b.parts.fraction))) {
-		if (is_float64_nan(b)) {
-			if (is_float64_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return b;
-		}
-		
-		if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
-			/* num -(+-inf) = -+inf */
-			b.parts.sign = !b.parts.sign;
-			return b;
-		}
-		
-		result.parts.sign = !a.parts.sign;
-		
-		frac1 = b.parts.fraction;
-		exp1 = b.parts.exp;
-		frac2 = a.parts.fraction;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float64_nan(a)) {
-			if (is_float64_signan(a) || is_float64_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return a;
-		}
-		
-		if (a.parts.exp == FLOAT64_MAX_EXPONENT) {
-			if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
-				/* inf - inf => nan */
-				// TODO: fix exception
-				result.bin = FLOAT64_NAN;
-				return result;
-			}
-			
-			return a;
-		}
-		
-		result.parts.sign = a.parts.sign;
-		
-		frac1 = a.parts.fraction;
-		exp1 = a.parts.exp;
-		frac2 = b.parts.fraction;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		result.parts.fraction = frac1 - frac2;
-		if (result.parts.fraction > frac1) {
-			// TODO: underflow exception
-			return result;
-		}
-		
-		result.parts.exp = 0;
-		return result;
-	}
-	
-	/* add hidden bit */
-	frac1 |= FLOAT64_HIDDEN_BIT_MASK;
-	
-	if (exp2 == 0) {
-		/* denormalized */
-		--expdiff;
-	} else {
-		/* normalized */
-		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
-	}
-	
-	/* create some space for rounding */
-	frac1 <<= 6;
-	frac2 <<= 6;
-	
-	if (expdiff > FLOAT64_FRACTION_SIZE + 1)
-		goto done;
-	
-	frac1 = frac1 - (frac2 >> expdiff);
-	
-done:
-	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
-	while ((exp1 > 0) && (!(frac1 & (FLOAT64_HIDDEN_BIT_MASK << 6 )))) {
-		--exp1;
-		frac1 <<= 1;
-		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	frac1 += 0x20;
-	
-	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) {
-		++exp1;
-		frac1 >>= 1;
-	}
-	
-	/* Clear hidden bit and shift */
-	result.parts.fraction = ((frac1 >> 6) & (~FLOAT64_HIDDEN_BIT_MASK));
-	result.parts.exp = exp1;
-	
-	return result;
-}
-
-/** Subtract two quadruple-precision floats with the same sign.
- *
- * @param a First input operand.
- * @param b Second input operand.
- *
- * @return Result of substraction.
- *
- */
-float128 sub_float128(float128 a, float128 b)
-{
-	int expdiff;
-	uint32_t exp1, exp2;
-	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
-	float128 result;
-	
-	result.bin.hi = 0;
-	result.bin.lo = 0;
-	
-	expdiff = a.parts.exp - b.parts.exp;
-	if ((expdiff < 0 ) || ((expdiff == 0) &&
-	    lt128(a.parts.frac_hi, a.parts.frac_lo, b.parts.frac_hi, b.parts.frac_lo))) {
-		if (is_float128_nan(b)) {
-			if (is_float128_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return b;
-		}
-		
-		if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
-			/* num -(+-inf) = -+inf */
-			b.parts.sign = !b.parts.sign;
-			return b;
-		}
-		
-		result.parts.sign = !a.parts.sign;
-		
-		frac1_hi = b.parts.frac_hi;
-		frac1_lo = b.parts.frac_lo;
-		exp1 = b.parts.exp;
-		frac2_hi = a.parts.frac_hi;
-		frac2_lo = a.parts.frac_lo;
-		exp2 = a.parts.exp;
-		expdiff *= -1;
-	} else {
-		if (is_float128_nan(a)) {
-			if (is_float128_signan(a) || is_float128_signan(b)) {
-				// TODO: fix SigNaN
-			}
-			
-			return a;
-		}
-		
-		if (a.parts.exp == FLOAT128_MAX_EXPONENT) {
-			if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
-				/* inf - inf => nan */
-				// TODO: fix exception
-				result.bin.hi = FLOAT128_NAN_HI;
-				result.bin.lo = FLOAT128_NAN_LO;
-				return result;
-			}
-			return a;
-		}
-		
-		result.parts.sign = a.parts.sign;
-		
-		frac1_hi = a.parts.frac_hi;
-		frac1_lo = a.parts.frac_lo;
-		exp1 = a.parts.exp;
-		frac2_hi = b.parts.frac_hi;
-		frac2_lo = b.parts.frac_lo;
-		exp2 = b.parts.exp;
-	}
-	
-	if (exp1 == 0) {
-		/* both are denormalized */
-		sub128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &tmp_hi, &tmp_lo);
-		result.parts.frac_hi = tmp_hi;
-		result.parts.frac_lo = tmp_lo;
-		if (lt128(frac1_hi, frac1_lo, result.parts.frac_hi, result.parts.frac_lo)) {
-			// TODO: underflow exception
-			return result;
-		}
-		
-		result.parts.exp = 0;
-		return result;
-	}
-	
-	/* add hidden bit */
-	or128(frac1_hi, frac1_lo,
-	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &frac1_hi, &frac1_lo);
-	
-	if (exp2 == 0) {
-		/* denormalized */
-		--expdiff;
-	} else {
-		/* normalized */
-		or128(frac2_hi, frac2_lo,
-		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-		    &frac2_hi, &frac2_lo);
-	}
-	
-	/* create some space for rounding */
-	lshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-	lshift128(frac2_hi, frac2_lo, 6, &frac2_hi, &frac2_lo);
-	
-	if (expdiff > FLOAT128_FRACTION_SIZE + 1)
-		goto done;
-	
-	rshift128(frac2_hi, frac2_lo, expdiff, &tmp_hi, &tmp_lo);
-	sub128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
-	
-done:
-	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 6,
-	    &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	while ((exp1 > 0) && (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo))) {
-		--exp1;
-		lshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
-		
-		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 6,
-		    &tmp_hi, &tmp_lo);
-		and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	}
-	
-	/* rounding - if first bit after fraction is set then round up */
-	add128(frac1_hi, frac1_lo, 0x0ll, 0x20ll, &frac1_hi, &frac1_lo);
-	
-	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
-	   &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
-		++exp1;
-		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
-	}
-	
-	/* Clear hidden bit and shift */
-	rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
-	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
-	    &tmp_hi, &tmp_lo);
-	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
-	result.parts.frac_hi = tmp_hi;
-	result.parts.frac_lo = tmp_lo;
-	
-	result.parts.exp = exp1;
-	
-	return result;
-}
-
-/** @}
- */
Index: pace/lib/softfloat/include/add.h
===================================================================
--- uspace/lib/softfloat/include/add.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Addition functions.
- */
-
-#ifndef __ADD_H__
-#define __ADD_H__
-
-extern float32 add_float32(float32, float32);
-extern float64 add_float64(float64, float64);
-extern float96 add_float96(float96, float96);
-extern float128 add_float128(float128, float128);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/common.h
===================================================================
--- uspace/lib/softfloat/include/common.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,76 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Common helper operations.
- */
-
-#ifndef __COMMON_H__
-#define __COMMON_H__
-
-#include <sftypes.h>
-
-extern float64 finish_float64(int32_t, uint64_t, char);
-extern float128 finish_float128(int32_t, uint64_t, uint64_t, char, uint64_t);
-
-extern int count_zeroes8(uint8_t);
-extern int count_zeroes32(uint32_t);
-extern int count_zeroes64(uint64_t);
-
-extern void round_float32(int32_t *, uint32_t *);
-extern void round_float64(int32_t *, uint64_t *);
-extern void round_float128(int32_t *, uint64_t *, uint64_t *);
-
-extern void lshift128(uint64_t, uint64_t, int, uint64_t *, uint64_t *);
-extern void rshift128(uint64_t, uint64_t, int, uint64_t *, uint64_t *);
-
-extern void and128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void or128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void xor128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void not128(uint64_t, uint64_t, uint64_t *, uint64_t *);
-
-extern int eq128(uint64_t, uint64_t, uint64_t, uint64_t);
-extern int le128(uint64_t, uint64_t, uint64_t, uint64_t);
-extern int lt128(uint64_t, uint64_t, uint64_t, uint64_t);
-
-extern void add128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void sub128(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t *, uint64_t *);
-
-extern void mul64(uint64_t, uint64_t, uint64_t *, uint64_t *);
-extern void mul128(uint64_t, uint64_t, uint64_t, uint64_t,
-    uint64_t *, uint64_t *, uint64_t *, uint64_t *);
-
-extern uint64_t div128est(uint64_t, uint64_t, uint64_t);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/comparison.h
===================================================================
--- uspace/lib/softfloat/include/comparison.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,82 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Comparison functions.
- */
-
-#ifndef __COMPARISON_H__
-#define __COMPARISON_H__
-
-extern int is_float32_nan(float32);
-extern int is_float32_signan(float32);
-
-extern int is_float32_infinity(float32);
-extern int is_float32_zero(float32);
-
-extern int is_float32_eq(float32, float32);
-extern int is_float32_lt(float32, float32);
-extern int is_float32_gt(float32, float32);
-
-extern int is_float64_nan(float64);
-extern int is_float64_signan(float64);
-
-extern int is_float64_infinity(float64);
-extern int is_float64_zero(float64);
-
-extern int is_float64_eq(float64, float64);
-extern int is_float64_lt(float64, float64);
-extern int is_float64_gt(float64, float64);
-
-extern int is_float96_nan(float96);
-extern int is_float96_signan(float96);
-
-extern int is_float96_infinity(float96);
-extern int is_float96_zero(float96);
-
-extern int is_float96_eq(float96, float96);
-extern int is_float96_lt(float96, float96);
-extern int is_float96_gt(float96, float96);
-
-extern int is_float128_nan(float128);
-extern int is_float128_signan(float128);
-
-extern int is_float128_infinity(float128);
-extern int is_float128_zero(float128);
-
-extern int is_float128_eq(float128, float128);
-extern int is_float128_lt(float128, float128);
-extern int is_float128_gt(float128, float128);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/conversion.h
===================================================================
--- uspace/lib/softfloat/include/conversion.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,104 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Conversion of precision and conversion between integers and floats.
- */
-
-#ifndef __CONVERSION_H__
-#define __CONVERSION_H__
-
-extern float64 float32_to_float64(float32);
-extern float96 float32_to_float96(float32);
-extern float128 float32_to_float128(float32);
-extern float96 float64_to_float96(float64);
-extern float128 float64_to_float128(float64);
-extern float128 float96_to_float128(float96);
-
-extern float32 float64_to_float32(float64);
-extern float32 float96_to_float32(float96);
-extern float64 float96_to_float64(float96);
-extern float32 float128_to_float32(float128);
-extern float64 float128_to_float64(float128);
-extern float96 float128_to_float96(float128);
-
-extern uint32_t float32_to_uint32(float32);
-extern int32_t float32_to_int32(float32);
-
-extern uint64_t float32_to_uint64(float32);
-extern int64_t float32_to_int64(float32);
-
-extern uint32_t float64_to_uint32(float64);
-extern int32_t float64_to_int32(float64);
-
-extern uint64_t float64_to_uint64(float64);
-extern int64_t float64_to_int64(float64);
-
-extern uint32_t float96_to_uint32(float96);
-extern int32_t float96_to_int32(float96);
-
-extern uint64_t float96_to_uint64(float96);
-extern int64_t float96_to_int64(float96);
-
-extern uint32_t float128_to_uint32(float128);
-extern int32_t float128_to_int32(float128);
-
-extern uint64_t float128_to_uint64(float128);
-extern int64_t float128_to_int64(float128);
-
-extern float32 uint32_to_float32(uint32_t);
-extern float32 int32_to_float32(int32_t);
-
-extern float32 uint64_to_float32(uint64_t);
-extern float32 int64_to_float32(int64_t);
-
-extern float64 uint32_to_float64(uint32_t);
-extern float64 int32_to_float64(int32_t);
-
-extern float64 uint64_to_float64(uint64_t);
-extern float64 int64_to_float64(int64_t);
-
-extern float96 uint32_to_float96(uint32_t);
-extern float96 int32_to_float96(int32_t);
-
-extern float96 uint64_to_float96(uint64_t);
-extern float96 int64_to_float96(int64_t);
-
-extern float128 uint32_to_float128(uint32_t);
-extern float128 int32_to_float128(int32_t);
-
-extern float128 uint64_to_float128(uint64_t);
-extern float128 int64_to_float128(int64_t);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/div.h
===================================================================
--- uspace/lib/softfloat/include/div.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Division functions.
- */
-
-#ifndef __DIV_H__
-#define __DIV_H__
-
-extern float32 div_float32(float32, float32);
-extern float64 div_float64(float64, float64);
-extern float96 div_float96(float96, float96);
-extern float128 div_float128(float128, float128);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/mul.h
===================================================================
--- uspace/lib/softfloat/include/mul.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Multiplication functions.
- */
-
-#ifndef __MUL_H__
-#define __MUL_H__
-
-extern float32 mul_float32(float32, float32);
-extern float64 mul_float64(float64, float64);
-extern float96 mul_float96(float96, float96);
-extern float128 mul_float128(float128, float128);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/other.h
===================================================================
--- uspace/lib/softfloat/include/other.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,41 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * 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 softfloat
- * @{
- */
-/** @file Other functions (power, complex).
- */
-
-#ifndef __OTHER_H__
-#define __OTHER_H__
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/sftypes.h
===================================================================
--- uspace/lib/softfloat/include/sftypes.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,608 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Floating point types and constants.
- */
-
-#ifndef __SFTYPES_H__
-#define __SFTYPES_H__
-
-#include <byteorder.h>
-#include <stdint.h>
-
-/*
- * For recognizing NaNs or infinity use specialized comparison
- * functions, comparing with these constants is not sufficient.
- */
-
-#define FLOAT32_NAN     UINT32_C(0x7FC00001)
-#define FLOAT32_SIGNAN  UINT32_C(0x7F800001)
-#define FLOAT32_INF     UINT32_C(0x7F800000)
-
-#define FLOAT64_NAN     UINT64_C(0x7FF8000000000001)
-#define FLOAT64_SIGNAN  UINT64_C(0x7FF0000000000001)
-#define FLOAT64_INF     UINT64_C(0x7FF0000000000000)
-
-#define FLOAT96_NAN_HI     UINT64_C(0x7FFF80000000)
-#define FLOAT96_NAN_LO     UINT32_C(0x00010000)
-#define FLOAT96_SIGNAN_HI  UINT64_C(0x7FFF00000000)
-#define FLOAT96_SIGNAN_LO  UINT32_C(0x00010000)
-
-#define FLOAT128_NAN_HI     UINT64_C(0x7FFF800000000000)
-#define FLOAT128_NAN_LO     UINT64_C(0x0000000000000001)
-#define FLOAT128_SIGNAN_HI  UINT64_C(0x7FFF000000000000)
-#define FLOAT128_SIGNAN_LO  UINT64_C(0x0000000000000001)
-#define FLOAT128_INF_HI     UINT64_C(0x7FFF000000000000)
-#define FLOAT128_INF_LO     UINT64_C(0x0000000000000000)
-
-#define FLOAT32_FRACTION_SIZE   23
-#define FLOAT64_FRACTION_SIZE   52
-#define FLOAT96_FRACTION_SIZE   64
-#define FLOAT128_FRACTION_SIZE  112
-#define FLOAT128_FRAC_HI_SIZE   48
-#define FLOAT128_FRAC_LO_SIZE   64
-
-#define FLOAT32_HIDDEN_BIT_MASK      UINT32_C(0x800000)
-#define FLOAT64_HIDDEN_BIT_MASK      UINT64_C(0x10000000000000)
-#define FLOAT128_HIDDEN_BIT_MASK_HI  UINT64_C(0x1000000000000)
-#define FLOAT128_HIDDEN_BIT_MASK_LO  UINT64_C(0x0000000000000000)
-
-#define FLOAT32_MAX_EXPONENT   0xFF
-#define FLOAT64_MAX_EXPONENT   0x7FF
-#define FLOAT96_MAX_EXPONENT   0x7FFF
-#define FLOAT128_MAX_EXPONENT  0x7FFF
-
-#define FLOAT32_BIAS   0x7F
-#define FLOAT64_BIAS   0x3FF
-#define FLOAT96_BIAS   0x3FFF
-#define FLOAT128_BIAS  0x3FFF
-
-#if defined(__BE__)
-
-typedef union {
-	uint32_t bin;
-	
-	struct {
-		uint32_t sign : 1;
-		uint32_t exp : 8;
-		uint32_t fraction : 23;
-	} parts __attribute__((packed));
-} float32;
-
-typedef union {
-	uint64_t bin;
-	
-	struct {
-		uint64_t sign : 1;
-		uint64_t exp : 11;
-		uint64_t fraction : 52;
-	} parts __attribute__((packed));
-} float64;
-
-typedef union {
-	struct {
-		uint64_t hi;
-		uint32_t lo;
-	} bin __attribute__((packed));
-	
-	struct {
-		uint64_t padding : 16;
-		uint64_t sign : 1;
-		uint64_t exp : 15;
-		uint64_t fraction : 64;
-	} parts __attribute__((packed));
-} float96;
-
-typedef union {
-	struct {
-		uint64_t hi;
-		uint64_t lo;
-	} bin __attribute__((packed));
-	
-	struct {
-		uint64_t sign : 1;
-		uint64_t exp : 15;
-		uint64_t frac_hi : 48;
-		uint64_t frac_lo : 64;
-	} parts __attribute__((packed));
-} float128;
-
-#elif defined(__LE__)
-
-typedef union {
-	uint32_t bin;
-	
-	struct {
-		uint32_t fraction : 23;
-		uint32_t exp : 8;
-		uint32_t sign : 1;
-	} parts __attribute__((packed));
-} float32;
-
-typedef union {
-	uint64_t bin;
-	
-	struct {
-		uint64_t fraction : 52;
-		uint64_t exp : 11;
-		uint64_t sign : 1;
-	} parts __attribute__((packed));
-} float64;
-
-typedef union {
-	struct {
-		uint32_t lo;
-		uint64_t hi;
-	} bin __attribute__((packed));
-	
-	struct {
-		uint64_t fraction : 64;
-		uint64_t exp : 15;
-		uint64_t sign : 1;
-		uint64_t padding : 16;
-	} parts __attribute__((packed));
-} float96;
-
-typedef union {
-	struct {
-		uint64_t lo;
-		uint64_t hi;
-	} bin __attribute__((packed));
-	
-	struct {
-		uint64_t frac_lo : 64;
-		uint64_t frac_hi : 48;
-		uint64_t exp : 15;
-		uint64_t sign : 1;
-	} parts __attribute__((packed));
-} float128;
-
-#else
-	#error Unknown endianess
-#endif
-
-typedef union {
-	float val;
-	
-#if defined(FLOAT_SIZE_32)
-	float32 data;
-#elif defined(FLOAT_SIZE_64)
-	float64 data;
-#elif defined(FLOAT_SIZE_96)
-	float96 data;
-#elif defined(FLOAT_SIZE_128)
-	float128 data;
-#else
-	#error Unsupported float size
-#endif
-} float_t;
-
-typedef union {
-	double val;
-	
-#if defined(DOUBLE_SIZE_32)
-	float32 data;
-#elif defined(DOUBLE_SIZE_64)
-	float64 data;
-#elif defined(DOUBLE_SIZE_96)
-	float96 data;
-#elif defined(DOUBLE_SIZE_128)
-	float128 data;
-#else
-	#error Unsupported double size
-#endif
-} double_t;
-
-typedef union {
-	long double val;
-	
-#if defined(LONG_DOUBLE_SIZE_32)
-	float32 data;
-#elif defined(LONG_DOUBLE_SIZE_64)
-	float64 data;
-#elif defined(LONG_DOUBLE_SIZE_96)
-	float96 data;
-#elif defined(LONG_DOUBLE_SIZE_128)
-	float128 data;
-#else
-	#error Unsupported long double size
-#endif
-} long_double_t;
-
-
-#if defined(INT_SIZE_8)
-
-#define _to_int   _to_int8
-#define from_int  int8
-
-#elif defined(INT_SIZE_16)
-
-#define _to_int   _to_int16
-#define from_int  int16
-
-#elif defined(INT_SIZE_32)
-
-#define _to_int   _to_int32
-#define from_int  int32
-
-#elif defined(INT_SIZE_64)
-
-#define _to_int   _to_int64
-#define from_int  int64
-
-#endif
-
-
-#if defined(UINT_SIZE_8)
-
-#define _to_uint   _to_uint8
-#define from_uint  uint8
-
-#elif defined(UINT_SIZE_16)
-
-#define _to_uint   _to_uint16
-#define from_uint  uint16
-
-#elif defined(UINT_SIZE_32)
-
-#define _to_uint   _to_uint32
-#define from_uint  uint32
-
-#elif defined(UINT_SIZE_64)
-
-#define _to_uint   _to_uint64
-#define from_uint  uint64
-
-#endif
-
-
-#if defined(LONG_SIZE_8)
-
-#define _to_long   _to_int8
-#define from_long  int8
-
-#elif defined(LONG_SIZE_16)
-
-#define _to_long   _to_int16
-#define from_long  int16
-
-#elif defined(LONG_SIZE_32)
-
-#define _to_long   _to_int32
-#define from_long  int32
-
-#elif defined(LONG_SIZE_64)
-
-#define _to_long   _to_int64
-#define from_long  int64
-
-#endif
-
-
-#if defined(ULONG_SIZE_8)
-
-#define _to_ulong   _to_uint8
-#define from_ulong  uint8
-
-#elif defined(ULONG_SIZE_16)
-
-#define _to_ulong   _to_uint16
-#define from_ulong  uint16
-
-#elif defined(ULONG_SIZE_32)
-
-#define _to_ulong   _to_uint32
-#define from_ulong  uint32
-
-#elif defined(ULONG_SIZE_64)
-
-#define _to_ulong   _to_uint64
-#define from_ulong  uint64
-
-#endif
-
-
-#if defined(LLONG_SIZE_8)
-
-#define _to_llong   _to_int8
-#define from_llong  int8
-
-#elif defined(LLONG_SIZE_16)
-
-#define _to_llong   _to_int16
-#define from_llong  int16
-
-#elif defined(LLONG_SIZE_32)
-
-#define _to_llong   _to_int32
-#define from_llong  int32
-
-#elif defined(LLONG_SIZE_64)
-
-#define _to_llong   _to_int64
-#define from_llong  int64
-
-#endif
-
-
-#if defined(ULLONG_SIZE_8)
-
-#define _to_ullong   _to_uint8
-#define from_ullong  uint8
-
-#elif defined(ULLONG_SIZE_16)
-
-#define _to_ullong   _to_uint16
-#define from_ullong  uint16
-
-#elif defined(ULLONG_SIZE_32)
-
-#define _to_ullong   _to_uint32
-#define from_ullong  uint32
-
-#elif defined(ULLONG_SIZE_64)
-
-#define _to_ullong   _to_uint64
-#define from_ullong  uint64
-
-#endif
-
-
-#if defined(FLOAT_SIZE_32)
-
-#define add_float     add_float32
-#define sub_float     sub_float32
-#define mul_float     mul_float32
-#define div_float     div_float32
-#define _to_float     _to_float32
-#define from_float    float32
-#define is_float_nan  is_float32_nan
-#define is_float_eq   is_float32_eq
-#define is_float_lt   is_float32_lt
-#define is_float_gt   is_float32_gt
-
-#elif defined(FLOAT_SIZE_64)
-
-#define add_float     add_float64
-#define sub_float     sub_float64
-#define mul_float     mul_float64
-#define div_float     div_float64
-#define _to_float     _to_float64
-#define from_float    float64
-#define is_float_nan  is_float64_nan
-#define is_float_eq   is_float64_eq
-#define is_float_lt   is_float64_lt
-#define is_float_gt   is_float64_gt
-
-#elif defined(FLOAT_SIZE_96)
-
-#define add_float     add_float96
-#define sub_float     sub_float96
-#define mul_float     mul_float96
-#define div_float     div_float96
-#define _to_float     _to_float96
-#define from_float    float96
-#define is_float_nan  is_float96_nan
-#define is_float_eq   is_float96_eq
-#define is_float_lt   is_float96_lt
-#define is_float_gt   is_float96_gt
-
-#elif defined(FLOAT_SIZE_128)
-
-#define add_float     add_float128
-#define sub_float     sub_float128
-#define mul_float     mul_float128
-#define div_float     div_float128
-#define _to_float     _to_float128
-#define from_float    float128
-#define is_float_nan  is_float128_nan
-#define is_float_eq   is_float128_eq
-#define is_float_lt   is_float128_lt
-#define is_float_gt   is_float128_gt
-
-#endif
-
-
-#if defined(DOUBLE_SIZE_32)
-
-#define add_double     add_float32
-#define sub_double     sub_float32
-#define mul_double     mul_float32
-#define div_double     div_float32
-#define _to_double     _to_float32
-#define from_double    float32
-#define is_double_nan  is_float32_nan
-#define is_double_eq   is_float32_eq
-#define is_double_lt   is_float32_lt
-#define is_double_gt   is_float32_gt
-
-#elif defined(DOUBLE_SIZE_64)
-
-#define add_double     add_float64
-#define sub_double     sub_float64
-#define mul_double     mul_float64
-#define div_double     div_float64
-#define _to_double     _to_float64
-#define from_double    float64
-#define is_double_nan  is_float64_nan
-#define is_double_eq   is_float64_eq
-#define is_double_lt   is_float64_lt
-#define is_double_gt   is_float64_gt
-
-#elif defined(DOUBLE_SIZE_96)
-
-#define add_double     add_float96
-#define sub_double     sub_float96
-#define mul_double     mul_float96
-#define div_double     div_float96
-#define _to_double     _to_float96
-#define from_double    float96
-#define is_double_nan  is_float96_nan
-#define is_double_eq   is_float96_eq
-#define is_double_lt   is_float96_lt
-#define is_double_gt   is_float96_gt
-
-#elif defined(DOUBLE_SIZE_128)
-
-#define add_double     add_float128
-#define sub_double     sub_float128
-#define mul_double     mul_float128
-#define div_double     div_float128
-#define _to_double     _to_float128
-#define from_double    float128
-#define is_double_nan  is_float128_nan
-#define is_double_eq   is_float128_eq
-#define is_double_lt   is_float128_lt
-#define is_double_gt   is_float128_gt
-
-#endif
-
-
-#if defined(LONG_DOUBLE_SIZE_32)
-
-#define add_long_double     add_float32
-#define sub_long_double     sub_float32
-#define mul_long_double     mul_float32
-#define div_long_double     div_float32
-#define _to_long_double     _to_float32
-#define from_long_double    float32
-#define is_long_double_nan  is_float32_nan
-#define is_long_double_eq   is_float32_eq
-#define is_long_double_lt   is_float32_lt
-#define is_long_double_gt   is_float32_gt
-
-#elif defined(LONG_DOUBLE_SIZE_64)
-
-#define add_long_double     add_float64
-#define sub_long_double     sub_float64
-#define mul_long_double     mul_float64
-#define div_long_double     div_float64
-#define _to_long_double     _to_float64
-#define from_long_double    float64
-#define is_long_double_nan  is_float64_nan
-#define is_long_double_eq   is_float64_eq
-#define is_long_double_lt   is_float64_lt
-#define is_long_double_gt   is_float64_gt
-
-#elif defined(LONG_DOUBLE_SIZE_96)
-
-#define add_long_double     add_float96
-#define sub_long_double     sub_float96
-#define mul_long_double     mul_float96
-#define div_long_double     div_float96
-#define _to_long_double     _to_float96
-#define from_long_double    float96
-#define is_long_double_nan  is_float96_nan
-#define is_long_double_eq   is_float96_eq
-#define is_long_double_lt   is_float96_lt
-#define is_long_double_gt   is_float96_gt
-
-#elif defined(LONG_DOUBLE_SIZE_128)
-
-#define add_long_double     add_float128
-#define sub_long_double     sub_float128
-#define mul_long_double     mul_float128
-#define div_long_double     div_float128
-#define _to_long_double     _to_float128
-#define from_long_double    float128
-#define is_long_double_nan  is_float128_nan
-#define is_long_double_eq   is_float128_eq
-#define is_long_double_lt   is_float128_lt
-#define is_long_double_gt   is_float128_gt
-
-#endif
-
-
-#define CONCAT(a, b)       CONCAT_ARGS(a, b)
-#define CONCAT_ARGS(a, b)  a ## b
-
-#define float32_to_float32(arg)    (arg)
-#define float64_to_float64(arg)    (arg)
-#define float96_to_float96(arg)    (arg)
-#define float128_to_float128(arg)  (arg)
-
-#define float_to_double       CONCAT(from_float, _to_double)
-#define float_to_long_double  CONCAT(from_float, _to_long_double)
-#define float_to_int          CONCAT(from_float, _to_int)
-#define float_to_uint         CONCAT(from_float, _to_uint)
-#define float_to_long         CONCAT(from_float, _to_long)
-#define float_to_ulong        CONCAT(from_float, _to_ulong)
-#define float_to_llong        CONCAT(from_float, _to_llong)
-#define float_to_ullong       CONCAT(from_float, _to_ullong)
-
-#define double_to_float        CONCAT(from_double, _to_float)
-#define double_to_long_double  CONCAT(from_double, _to_long_double)
-#define double_to_int          CONCAT(from_double, _to_int)
-#define double_to_uint         CONCAT(from_double, _to_uint)
-#define double_to_long         CONCAT(from_double, _to_long)
-#define double_to_ulong        CONCAT(from_double, _to_ulong)
-#define double_to_llong        CONCAT(from_double, _to_llong)
-#define double_to_ullong       CONCAT(from_double, _to_ullong)
-
-#define long_double_to_float   CONCAT(from_long_double, _to_float)
-#define long_double_to_double  CONCAT(from_long_double, _to_double)
-#define long_double_to_int     CONCAT(from_long_double, _to_int)
-#define long_double_to_uint    CONCAT(from_long_double, _to_uint)
-#define long_double_to_long    CONCAT(from_long_double, _to_long)
-#define long_double_to_ulong   CONCAT(from_long_double, _to_ulong)
-#define long_double_to_llong   CONCAT(from_long_double, _to_llong)
-#define long_double_to_ullong  CONCAT(from_long_double, _to_ullong)
-
-#define int_to_float        CONCAT(from_int, _to_float)
-#define int_to_double       CONCAT(from_int, _to_double)
-#define int_to_long_double  CONCAT(from_int, _to_long_double)
-
-#define uint_to_float        CONCAT(from_uint, _to_float)
-#define uint_to_double       CONCAT(from_uint, _to_double)
-#define uint_to_long_double  CONCAT(from_uint, _to_long_double)
-
-#define long_to_float        CONCAT(from_long, _to_float)
-#define long_to_double       CONCAT(from_long, _to_double)
-#define long_to_long_double  CONCAT(from_long, _to_long_double)
-
-#define ulong_to_float        CONCAT(from_ulong, _to_float)
-#define ulong_to_double       CONCAT(from_ulong, _to_double)
-#define ulong_to_long_double  CONCAT(from_ulong, _to_long_double)
-
-#define llong_to_float        CONCAT(from_llong, _to_float)
-#define llong_to_double       CONCAT(from_llong, _to_double)
-#define llong_to_long_double  CONCAT(from_llong, _to_long_double)
-
-#define ullong_to_float        CONCAT(from_ullong, _to_float)
-#define ullong_to_double       CONCAT(from_ullong, _to_double)
-#define ullong_to_long_double  CONCAT(from_ullong, _to_long_double)
-
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/softfloat.h
===================================================================
--- uspace/lib/softfloat/include/softfloat.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,226 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Softfloat API.
- */
-
-#ifndef __SOFTFLOAT_H__
-#define __SOFTFLOAT_H__
-
-extern float __addsf3(float, float);
-extern double __adddf3(double, double);
-extern long double __addtf3(long double, long double);
-extern long double __addxf3(long double, long double);
-
-extern float __subsf3(float, float);
-extern double __subdf3(double, double);
-extern long double __subtf3(long double, long double);
-extern long double __subxf3(long double, long double);
-
-extern float __mulsf3(float, float);
-extern double __muldf3(double, double);
-extern long double __multf3(long double, long double);
-extern long double __mulxf3(long double, long double);
-
-extern float __divsf3(float, float);
-extern double __divdf3(double, double);
-extern long double __divtf3(long double, long double);
-extern long double __divxf3(long double, long double);
-
-extern float __negsf2(float);
-extern double __negdf2(double);
-extern long double __negtf2(long double);
-extern long double __negxf2(long double);
-
-extern double __extendsfdf2(float);
-extern long double __extendsftf2(float);
-extern long double __extendsfxf2(float);
-extern long double __extenddftf2(double);
-extern long double __extenddfxf2(double);
-
-extern double __truncxfdf2(long double);
-extern double __trunctfdf2(long double);
-extern float __truncxfsf2(long double);
-extern float __trunctfsf2(long double);
-extern float __truncdfsf2(double);
-
-extern int __fixsfsi(float);
-extern int __fixdfsi(double);
-extern int __fixtfsi(long double);
-extern int __fixxfsi(long double);
-
-extern long __fixsfdi(float);
-extern long __fixdfdi(double);
-extern long __fixtfdi(long double);
-extern long __fixxfdi(long double);
-
-extern long long __fixsfti(float);
-extern long long __fixdfti(double);
-extern long long __fixtfti(long double);
-extern long long __fixxfti(long double);
-
-extern unsigned int __fixunssfsi(float);
-extern unsigned int __fixunsdfsi(double);
-extern unsigned int __fixunstfsi(long double);
-extern unsigned int __fixunsxfsi(long double);
-
-extern unsigned long __fixunssfdi(float);
-extern unsigned long __fixunsdfdi(double);
-extern unsigned long __fixunstfdi(long double);
-extern unsigned long __fixunsxfdi(long double);
-
-extern unsigned long long __fixunssfti(float);
-extern unsigned long long __fixunsdfti(double);
-extern unsigned long long __fixunstfti(long double);
-extern unsigned long long __fixunsxfti(long double);
-
-extern float __floatsisf(int);
-extern double __floatsidf(int);
-extern long double __floatsitf(int);
-extern long double __floatsixf(int);
-
-extern float __floatdisf(long);
-extern double __floatdidf(long);
-extern long double __floatditf(long);
-extern long double __floatdixf(long);
-
-extern float __floattisf(long long);
-extern double __floattidf(long long);
-extern long double __floattitf(long long);
-extern long double __floattixf(long long);
-
-extern float __floatunsisf(unsigned int);
-extern double __floatunsidf(unsigned int);
-extern long double __floatunsitf(unsigned int);
-extern long double __floatunsixf(unsigned int);
-
-extern float __floatundisf(unsigned long);
-extern double __floatundidf(unsigned long);
-extern long double __floatunditf(unsigned long);
-extern long double __floatundixf(unsigned long);
-
-extern float __floatuntisf(unsigned long long);
-extern double __floatuntidf(unsigned long long);
-extern long double __floatuntitf(unsigned long long);
-extern long double __floatuntixf(unsigned long long);
-
-extern int __cmpsf2(float, float);
-extern int __cmpdf2(double, double);
-extern int __cmptf2(long double, long double);
-
-extern int __unordsf2(float, float);
-extern int __unorddf2(double, double);
-extern int __unordtf2(long double, long double);
-
-extern int __eqsf2(float, float);
-extern int __eqdf2(double, double);
-extern int __eqtf2(long double, long double);
-
-extern int __nesf2(float, float);
-extern int __nedf2(double, double);
-extern int __netf2(long double, long double);
-
-extern int __gesf2(float, float);
-extern int __gedf2(double, double);
-extern int __getf2(long double, long double);
-
-extern int __ltsf2(float, float);
-extern int __ltdf2(double, double);
-extern int __lttf2(long double, long double);
-
-extern int __lesf2(float, float);
-extern int __ledf2(double, double);
-extern int __letf2(long double, long double);
-
-extern int __gtsf2(float, float);
-extern int __gtdf2(double, double);
-extern int __gttf2(long double, long double);
-
-/* Not implemented yet */
-extern float __powisf2(float, int);
-extern double __powidf2 (double, int);
-extern long double __powitf2(long double, int);
-extern long double __powixf2(long double, int);
-
-/* SPARC quadruple-precision wrappers */
-extern void _Qp_add(long double *, long double *, long double *);
-extern void _Qp_sub(long double *, long double *, long double *);
-extern void _Qp_mul(long double *, long double *, long double *);
-extern void _Qp_div(long double *, long double *, long double *);
-extern void _Qp_neg(long double *, long double *);
-
-extern void _Qp_stoq(long double *, float);
-extern void _Qp_dtoq(long double *, double);
-extern float _Qp_qtos(long double *);
-extern double _Qp_qtod(long double *);
-
-extern int _Qp_qtoi(long double *);
-extern unsigned int _Qp_qtoui(long double *);
-extern long _Qp_qtox(long double *);
-extern unsigned long _Qp_qtoux(long double *);
-
-extern void _Qp_itoq(long double *, int);
-extern void _Qp_uitoq(long double *, unsigned int);
-extern void _Qp_xtoq(long double *, long);
-extern void _Qp_uxtoq(long double *, unsigned long);
-
-extern int _Qp_cmp(long double *, long double *);
-extern int _Qp_cmpe(long double *, long double *);
-extern int _Qp_feq(long double *, long double *);
-extern int _Qp_fge(long double *, long double *);
-extern int _Qp_fgt(long double *, long double *);
-extern int _Qp_fle(long double*, long double *);
-extern int _Qp_flt(long double *, long double *);
-extern int _Qp_fne(long double *, long double *);
-
-/* ARM EABI */
-extern double __aeabi_i2d(int);
-extern double __aeabi_ui2d(unsigned int);
-extern unsigned int __aeabi_d2uiz(double);
-extern int __aeabi_d2iz(double);
-
-extern int __aeabi_dcmpge(double, double);
-extern int __aeabi_dcmpgt(double, double);
-extern int __aeabi_dcmplt(double, double);
-
-extern double __aeabi_dadd(double, double);
-extern double __aeabi_dsub(double, double);
-extern double __aeabi_dmul(double, double);
-extern double __aeabi_ddiv(double, double);
-
-/* Not implemented yet */
-extern void _Qp_sqrt(long double *, long double *);
-
-#endif
-
-/** @}
- */
Index: pace/lib/softfloat/include/sub.h
===================================================================
--- uspace/lib/softfloat/include/sub.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2005 Josef Cejka
- * Copyright (c) 2011 Petr Koupy
- * 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 softfloat
- * @{
- */
-/** @file Substraction functions.
- */
-
-#ifndef __SUB_H__
-#define __SUB_H__
-
-extern float32 sub_float32(float32, float32);
-extern float64 sub_float64(float64, float64);
-extern float96 sub_float96(float96, float96);
-extern float128 sub_float128(float128, float128);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/softfloat/mul.c
===================================================================
--- uspace/lib/softfloat/mul.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/mul.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Multiplication functions.
+ */
+
+#include "sftypes.h"
+#include "mul.h"
+#include "comparison.h"
+#include "common.h"
+
+/** Multiply two single-precision floats.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of multiplication.
+ *
+ */
+float32 mul_float32(float32 a, float32 b)
+{
+	float32 result;
+	uint64_t frac1, frac2;
+	int32_t exp;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float32_nan(a) || is_float32_nan(b)) {
+		/* TODO: fix SigNaNs */
+		if (is_float32_signan(a)) {
+			result.parts.fraction = a.parts.fraction;
+			result.parts.exp = a.parts.exp;
+			return result;
+		}
+		if (is_float32_signan(b)) { /* TODO: fix SigNaN */
+			result.parts.fraction = b.parts.fraction;
+			result.parts.exp = b.parts.exp;
+			return result;
+		}
+		/* set NaN as result */
+		result.bin = FLOAT32_NAN;
+		return result;
+	}
+	
+	if (is_float32_infinity(a)) {
+		if (is_float32_zero(b)) {
+			/* FIXME: zero * infinity */
+			result.bin = FLOAT32_NAN;
+			return result;
+		}
+		result.parts.fraction = a.parts.fraction;
+		result.parts.exp = a.parts.exp;
+		return result;
+	}
+	
+	if (is_float32_infinity(b)) {
+		if (is_float32_zero(a)) {
+			/* FIXME: zero * infinity */
+			result.bin = FLOAT32_NAN;
+			return result;
+		}
+		result.parts.fraction = b.parts.fraction;
+		result.parts.exp = b.parts.exp;
+		return result;
+	}
+	
+	/* exp is signed so we can easy detect underflow */
+	exp = a.parts.exp + b.parts.exp;
+	exp -= FLOAT32_BIAS;
+	
+	if (exp >= FLOAT32_MAX_EXPONENT) {
+		/* FIXME: overflow */
+		/* set infinity as result */
+		result.bin = FLOAT32_INF;
+		result.parts.sign = a.parts.sign ^ b.parts.sign;
+		return result;
+	}
+	
+	if (exp < 0) { 
+		/* FIXME: underflow */
+		/* return signed zero */
+		result.parts.fraction = 0x0;
+		result.parts.exp = 0x0;
+		return result;
+	}
+	
+	frac1 = a.parts.fraction;
+	if (a.parts.exp > 0) {
+		frac1 |= FLOAT32_HIDDEN_BIT_MASK;
+	} else {
+		++exp;
+	}
+	
+	frac2 = b.parts.fraction;
+	
+	if (b.parts.exp > 0) {
+		frac2 |= FLOAT32_HIDDEN_BIT_MASK;
+	} else {
+		++exp;
+	}
+	
+	frac1 <<= 1; /* one bit space for rounding */
+	
+	frac1 = frac1 * frac2;
+	
+	/* round and return */
+	while ((exp < FLOAT32_MAX_EXPONENT) &&
+	    (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 2)))) {
+		/* 23 bits of fraction + one more for hidden bit (all shifted 1 bit left) */
+		++exp;
+		frac1 >>= 1;
+	}
+	
+	/* rounding */
+	/* ++frac1; FIXME: not works - without it is ok */
+	frac1 >>= 1; /* shift off rounding space */
+	
+	if ((exp < FLOAT32_MAX_EXPONENT) &&
+	    (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 1)))) {
+		++exp;
+		frac1 >>= 1;
+	}
+	
+	if (exp >= FLOAT32_MAX_EXPONENT) {
+		/* TODO: fix overflow */
+		/* return infinity*/
+		result.parts.exp = FLOAT32_MAX_EXPONENT;
+		result.parts.fraction = 0x0;
+		return result;
+	}
+	
+	exp -= FLOAT32_FRACTION_SIZE;
+	
+	if (exp <= FLOAT32_FRACTION_SIZE) {
+		/* denormalized number */
+		frac1 >>= 1; /* denormalize */
+		while ((frac1 > 0) && (exp < 0)) {
+			frac1 >>= 1;
+			++exp;
+		}
+		if (frac1 == 0) {
+			/* FIXME : underflow */
+			result.parts.exp = 0;
+			result.parts.fraction = 0;
+			return result;
+		}
+	}
+	result.parts.exp = exp; 
+	result.parts.fraction = frac1 & ((1 << FLOAT32_FRACTION_SIZE) - 1);
+	
+	return result;
+}
+
+/** Multiply two double-precision floats.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of multiplication.
+ *
+ */
+float64 mul_float64(float64 a, float64 b)
+{
+	float64 result;
+	uint64_t frac1, frac2;
+	int32_t exp;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float64_nan(a) || is_float64_nan(b)) {
+		/* TODO: fix SigNaNs */
+		if (is_float64_signan(a)) {
+			result.parts.fraction = a.parts.fraction;
+			result.parts.exp = a.parts.exp;
+			return result;
+		}
+		if (is_float64_signan(b)) { /* TODO: fix SigNaN */
+			result.parts.fraction = b.parts.fraction;
+			result.parts.exp = b.parts.exp;
+			return result;
+		}
+		/* set NaN as result */
+		result.bin = FLOAT64_NAN;
+		return result;
+	}
+	
+	if (is_float64_infinity(a)) {
+		if (is_float64_zero(b)) {
+			/* FIXME: zero * infinity */
+			result.bin = FLOAT64_NAN;
+			return result;
+		}
+		result.parts.fraction = a.parts.fraction;
+		result.parts.exp = a.parts.exp;
+		return result;
+	}
+	
+	if (is_float64_infinity(b)) {
+		if (is_float64_zero(a)) {
+			/* FIXME: zero * infinity */
+			result.bin = FLOAT64_NAN;
+			return result;
+		}
+		result.parts.fraction = b.parts.fraction;
+		result.parts.exp = b.parts.exp;
+		return result;
+	}
+	
+	/* exp is signed so we can easy detect underflow */
+	exp = a.parts.exp + b.parts.exp - FLOAT64_BIAS;
+	
+	frac1 = a.parts.fraction;
+	
+	if (a.parts.exp > 0) {
+		frac1 |= FLOAT64_HIDDEN_BIT_MASK;
+	} else {
+		++exp;
+	}
+	
+	frac2 = b.parts.fraction;
+	
+	if (b.parts.exp > 0) {
+		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
+	} else {
+		++exp;
+	}
+	
+	frac1 <<= (64 - FLOAT64_FRACTION_SIZE - 1);
+	frac2 <<= (64 - FLOAT64_FRACTION_SIZE - 2);
+	
+	mul64(frac1, frac2, &frac1, &frac2);
+	
+	frac1 |= (frac2 != 0);
+	if (frac1 & (0x1ll << 62)) {
+		frac1 <<= 1;
+		exp--;
+	}
+	
+	result = finish_float64(exp, frac1, result.parts.sign);
+	return result;
+}
+
+/** Multiply two quadruple-precision floats.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of multiplication.
+ *
+ */
+float128 mul_float128(float128 a, float128 b)
+{
+	float128 result;
+	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
+	int32_t exp;
+	
+	result.parts.sign = a.parts.sign ^ b.parts.sign;
+	
+	if (is_float128_nan(a) || is_float128_nan(b)) {
+		/* TODO: fix SigNaNs */
+		if (is_float128_signan(a)) {
+			result.parts.frac_hi = a.parts.frac_hi;
+			result.parts.frac_lo = a.parts.frac_lo;
+			result.parts.exp = a.parts.exp;
+			return result;
+		}
+		if (is_float128_signan(b)) { /* TODO: fix SigNaN */
+			result.parts.frac_hi = b.parts.frac_hi;
+			result.parts.frac_lo = b.parts.frac_lo;
+			result.parts.exp = b.parts.exp;
+			return result;
+		}
+		/* set NaN as result */
+		result.bin.hi = FLOAT128_NAN_HI;
+		result.bin.lo = FLOAT128_NAN_LO;
+		return result;
+	}
+	
+	if (is_float128_infinity(a)) {
+		if (is_float128_zero(b)) {
+			/* FIXME: zero * infinity */
+			result.bin.hi = FLOAT128_NAN_HI;
+			result.bin.lo = FLOAT128_NAN_LO;
+			return result;
+		}
+		result.parts.frac_hi = a.parts.frac_hi;
+		result.parts.frac_lo = a.parts.frac_lo;
+		result.parts.exp = a.parts.exp;
+		return result;
+	}
+	
+	if (is_float128_infinity(b)) {
+		if (is_float128_zero(a)) {
+			/* FIXME: zero * infinity */
+			result.bin.hi = FLOAT128_NAN_HI;
+			result.bin.lo = FLOAT128_NAN_LO;
+			return result;
+		}
+		result.parts.frac_hi = b.parts.frac_hi;
+		result.parts.frac_lo = b.parts.frac_lo;
+		result.parts.exp = b.parts.exp;
+		return result;
+	}
+	
+	/* exp is signed so we can easy detect underflow */
+	exp = a.parts.exp + b.parts.exp - FLOAT128_BIAS - 1;
+	
+	frac1_hi = a.parts.frac_hi;
+	frac1_lo = a.parts.frac_lo;
+	
+	if (a.parts.exp > 0) {
+		or128(frac1_hi, frac1_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &frac1_hi, &frac1_lo);
+	} else {
+		++exp;
+	}
+	
+	frac2_hi = b.parts.frac_hi;
+	frac2_lo = b.parts.frac_lo;
+	
+	if (b.parts.exp > 0) {
+		or128(frac2_hi, frac2_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &frac2_hi, &frac2_lo);
+	} else {
+		++exp;
+	}
+	
+	lshift128(frac2_hi, frac2_lo,
+	    128 - FLOAT128_FRACTION_SIZE, &frac2_hi, &frac2_lo);
+	
+	tmp_hi = frac1_hi;
+	tmp_lo = frac1_lo;
+	mul128(frac1_hi, frac1_lo, frac2_hi, frac2_lo,
+	    &frac1_hi, &frac1_lo, &frac2_hi, &frac2_lo);
+	add128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
+	frac2_hi |= (frac2_lo != 0x0ll);
+	
+	if ((FLOAT128_HIDDEN_BIT_MASK_HI << 1) <= frac1_hi) {
+		frac2_hi >>= 1;
+		if (frac1_lo & 0x1ll) {
+			frac2_hi |= (0x1ull < 64);
+		}
+		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+		++exp;
+	}
+	
+	result = finish_float128(exp, frac1_hi, frac1_lo, result.parts.sign, frac2_hi);
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/mul.h
===================================================================
--- uspace/lib/softfloat/mul.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/mul.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Multiplication functions.
+ */
+
+#ifndef __MUL_H__
+#define __MUL_H__
+
+extern float32 mul_float32(float32, float32);
+extern float64 mul_float64(float64, float64);
+extern float96 mul_float96(float96, float96);
+extern float128 mul_float128(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/other.c
===================================================================
--- uspace/lib/softfloat/other.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/other.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Other functions (power, complex).
+ */
+
+
+/** @}
+ */
Index: uspace/lib/softfloat/other.h
===================================================================
--- uspace/lib/softfloat/other.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/other.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * 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 softfloat
+ * @{
+ */
+/** @file Other functions (power, complex).
+ */
+
+#ifndef __OTHER_H__
+#define __OTHER_H__
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/sftypes.h
===================================================================
--- uspace/lib/softfloat/sftypes.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/sftypes.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Floating point types and constants.
+ */
+
+#ifndef __SFTYPES_H__
+#define __SFTYPES_H__
+
+#include <byteorder.h>
+#include <stdint.h>
+
+/*
+ * For recognizing NaNs or infinity use specialized comparison
+ * functions, comparing with these constants is not sufficient.
+ */
+
+#define FLOAT32_NAN     UINT32_C(0x7FC00001)
+#define FLOAT32_SIGNAN  UINT32_C(0x7F800001)
+#define FLOAT32_INF     UINT32_C(0x7F800000)
+
+#define FLOAT64_NAN     UINT64_C(0x7FF8000000000001)
+#define FLOAT64_SIGNAN  UINT64_C(0x7FF0000000000001)
+#define FLOAT64_INF     UINT64_C(0x7FF0000000000000)
+
+#define FLOAT96_NAN_HI     UINT64_C(0x7FFF80000000)
+#define FLOAT96_NAN_LO     UINT32_C(0x00010000)
+#define FLOAT96_SIGNAN_HI  UINT64_C(0x7FFF00000000)
+#define FLOAT96_SIGNAN_LO  UINT32_C(0x00010000)
+
+#define FLOAT128_NAN_HI     UINT64_C(0x7FFF800000000000)
+#define FLOAT128_NAN_LO     UINT64_C(0x0000000000000001)
+#define FLOAT128_SIGNAN_HI  UINT64_C(0x7FFF000000000000)
+#define FLOAT128_SIGNAN_LO  UINT64_C(0x0000000000000001)
+#define FLOAT128_INF_HI     UINT64_C(0x7FFF000000000000)
+#define FLOAT128_INF_LO     UINT64_C(0x0000000000000000)
+
+#define FLOAT32_FRACTION_SIZE   23
+#define FLOAT64_FRACTION_SIZE   52
+#define FLOAT96_FRACTION_SIZE   64
+#define FLOAT128_FRACTION_SIZE  112
+#define FLOAT128_FRAC_HI_SIZE   48
+#define FLOAT128_FRAC_LO_SIZE   64
+
+#define FLOAT32_HIDDEN_BIT_MASK      UINT32_C(0x800000)
+#define FLOAT64_HIDDEN_BIT_MASK      UINT64_C(0x10000000000000)
+#define FLOAT128_HIDDEN_BIT_MASK_HI  UINT64_C(0x1000000000000)
+#define FLOAT128_HIDDEN_BIT_MASK_LO  UINT64_C(0x0000000000000000)
+
+#define FLOAT32_MAX_EXPONENT   0xFF
+#define FLOAT64_MAX_EXPONENT   0x7FF
+#define FLOAT96_MAX_EXPONENT   0x7FFF
+#define FLOAT128_MAX_EXPONENT  0x7FFF
+
+#define FLOAT32_BIAS   0x7F
+#define FLOAT64_BIAS   0x3FF
+#define FLOAT96_BIAS   0x3FFF
+#define FLOAT128_BIAS  0x3FFF
+
+#if defined(__BE__)
+
+typedef union {
+	uint32_t bin;
+	
+	struct {
+		uint32_t sign : 1;
+		uint32_t exp : 8;
+		uint32_t fraction : 23;
+	} parts __attribute__((packed));
+} float32;
+
+typedef union {
+	uint64_t bin;
+	
+	struct {
+		uint64_t sign : 1;
+		uint64_t exp : 11;
+		uint64_t fraction : 52;
+	} parts __attribute__((packed));
+} float64;
+
+typedef union {
+	struct {
+		uint64_t hi;
+		uint32_t lo;
+	} bin __attribute__((packed));
+	
+	struct {
+		uint64_t padding : 16;
+		uint64_t sign : 1;
+		uint64_t exp : 15;
+		uint64_t fraction : 64;
+	} parts __attribute__((packed));
+} float96;
+
+typedef union {
+	struct {
+		uint64_t hi;
+		uint64_t lo;
+	} bin __attribute__((packed));
+	
+	struct {
+		uint64_t sign : 1;
+		uint64_t exp : 15;
+		uint64_t frac_hi : 48;
+		uint64_t frac_lo : 64;
+	} parts __attribute__((packed));
+} float128;
+
+#elif defined(__LE__)
+
+typedef union {
+	uint32_t bin;
+	
+	struct {
+		uint32_t fraction : 23;
+		uint32_t exp : 8;
+		uint32_t sign : 1;
+	} parts __attribute__((packed));
+} float32;
+
+typedef union {
+	uint64_t bin;
+	
+	struct {
+		uint64_t fraction : 52;
+		uint64_t exp : 11;
+		uint64_t sign : 1;
+	} parts __attribute__((packed));
+} float64;
+
+typedef union {
+	struct {
+		uint32_t lo;
+		uint64_t hi;
+	} bin __attribute__((packed));
+	
+	struct {
+		uint64_t fraction : 64;
+		uint64_t exp : 15;
+		uint64_t sign : 1;
+		uint64_t padding : 16;
+	} parts __attribute__((packed));
+} float96;
+
+typedef union {
+	struct {
+		uint64_t lo;
+		uint64_t hi;
+	} bin __attribute__((packed));
+	
+	struct {
+		uint64_t frac_lo : 64;
+		uint64_t frac_hi : 48;
+		uint64_t exp : 15;
+		uint64_t sign : 1;
+	} parts __attribute__((packed));
+} float128;
+
+#else
+	#error Unknown endianess
+#endif
+
+typedef union {
+	float val;
+	
+#if defined(FLOAT_SIZE_32)
+	float32 data;
+#elif defined(FLOAT_SIZE_64)
+	float64 data;
+#elif defined(FLOAT_SIZE_96)
+	float96 data;
+#elif defined(FLOAT_SIZE_128)
+	float128 data;
+#else
+	#error Unsupported float size
+#endif
+} float_t;
+
+typedef union {
+	double val;
+	
+#if defined(DOUBLE_SIZE_32)
+	float32 data;
+#elif defined(DOUBLE_SIZE_64)
+	float64 data;
+#elif defined(DOUBLE_SIZE_96)
+	float96 data;
+#elif defined(DOUBLE_SIZE_128)
+	float128 data;
+#else
+	#error Unsupported double size
+#endif
+} double_t;
+
+typedef union {
+	long double val;
+	
+#if defined(LONG_DOUBLE_SIZE_32)
+	float32 data;
+#elif defined(LONG_DOUBLE_SIZE_64)
+	float64 data;
+#elif defined(LONG_DOUBLE_SIZE_96)
+	float96 data;
+#elif defined(LONG_DOUBLE_SIZE_128)
+	float128 data;
+#else
+	#error Unsupported long double size
+#endif
+} long_double_t;
+
+
+#if defined(INT_SIZE_8)
+
+#define _to_int   _to_int8
+#define from_int  int8
+
+#elif defined(INT_SIZE_16)
+
+#define _to_int   _to_int16
+#define from_int  int16
+
+#elif defined(INT_SIZE_32)
+
+#define _to_int   _to_int32
+#define from_int  int32
+
+#elif defined(INT_SIZE_64)
+
+#define _to_int   _to_int64
+#define from_int  int64
+
+#endif
+
+
+#if defined(UINT_SIZE_8)
+
+#define _to_uint   _to_uint8
+#define from_uint  uint8
+
+#elif defined(UINT_SIZE_16)
+
+#define _to_uint   _to_uint16
+#define from_uint  uint16
+
+#elif defined(UINT_SIZE_32)
+
+#define _to_uint   _to_uint32
+#define from_uint  uint32
+
+#elif defined(UINT_SIZE_64)
+
+#define _to_uint   _to_uint64
+#define from_uint  uint64
+
+#endif
+
+
+#if defined(LONG_SIZE_8)
+
+#define _to_long   _to_int8
+#define from_long  int8
+
+#elif defined(LONG_SIZE_16)
+
+#define _to_long   _to_int16
+#define from_long  int16
+
+#elif defined(LONG_SIZE_32)
+
+#define _to_long   _to_int32
+#define from_long  int32
+
+#elif defined(LONG_SIZE_64)
+
+#define _to_long   _to_int64
+#define from_long  int64
+
+#endif
+
+
+#if defined(ULONG_SIZE_8)
+
+#define _to_ulong   _to_uint8
+#define from_ulong  uint8
+
+#elif defined(ULONG_SIZE_16)
+
+#define _to_ulong   _to_uint16
+#define from_ulong  uint16
+
+#elif defined(ULONG_SIZE_32)
+
+#define _to_ulong   _to_uint32
+#define from_ulong  uint32
+
+#elif defined(ULONG_SIZE_64)
+
+#define _to_ulong   _to_uint64
+#define from_ulong  uint64
+
+#endif
+
+
+#if defined(LLONG_SIZE_8)
+
+#define _to_llong   _to_int8
+#define from_llong  int8
+
+#elif defined(LLONG_SIZE_16)
+
+#define _to_llong   _to_int16
+#define from_llong  int16
+
+#elif defined(LLONG_SIZE_32)
+
+#define _to_llong   _to_int32
+#define from_llong  int32
+
+#elif defined(LLONG_SIZE_64)
+
+#define _to_llong   _to_int64
+#define from_llong  int64
+
+#endif
+
+
+#if defined(ULLONG_SIZE_8)
+
+#define _to_ullong   _to_uint8
+#define from_ullong  uint8
+
+#elif defined(ULLONG_SIZE_16)
+
+#define _to_ullong   _to_uint16
+#define from_ullong  uint16
+
+#elif defined(ULLONG_SIZE_32)
+
+#define _to_ullong   _to_uint32
+#define from_ullong  uint32
+
+#elif defined(ULLONG_SIZE_64)
+
+#define _to_ullong   _to_uint64
+#define from_ullong  uint64
+
+#endif
+
+
+#if defined(FLOAT_SIZE_32)
+
+#define add_float     add_float32
+#define sub_float     sub_float32
+#define mul_float     mul_float32
+#define div_float     div_float32
+#define _to_float     _to_float32
+#define from_float    float32
+#define is_float_nan  is_float32_nan
+#define is_float_eq   is_float32_eq
+#define is_float_lt   is_float32_lt
+#define is_float_gt   is_float32_gt
+
+#elif defined(FLOAT_SIZE_64)
+
+#define add_float     add_float64
+#define sub_float     sub_float64
+#define mul_float     mul_float64
+#define div_float     div_float64
+#define _to_float     _to_float64
+#define from_float    float64
+#define is_float_nan  is_float64_nan
+#define is_float_eq   is_float64_eq
+#define is_float_lt   is_float64_lt
+#define is_float_gt   is_float64_gt
+
+#elif defined(FLOAT_SIZE_96)
+
+#define add_float     add_float96
+#define sub_float     sub_float96
+#define mul_float     mul_float96
+#define div_float     div_float96
+#define _to_float     _to_float96
+#define from_float    float96
+#define is_float_nan  is_float96_nan
+#define is_float_eq   is_float96_eq
+#define is_float_lt   is_float96_lt
+#define is_float_gt   is_float96_gt
+
+#elif defined(FLOAT_SIZE_128)
+
+#define add_float     add_float128
+#define sub_float     sub_float128
+#define mul_float     mul_float128
+#define div_float     div_float128
+#define _to_float     _to_float128
+#define from_float    float128
+#define is_float_nan  is_float128_nan
+#define is_float_eq   is_float128_eq
+#define is_float_lt   is_float128_lt
+#define is_float_gt   is_float128_gt
+
+#endif
+
+
+#if defined(DOUBLE_SIZE_32)
+
+#define add_double     add_float32
+#define sub_double     sub_float32
+#define mul_double     mul_float32
+#define div_double     div_float32
+#define _to_double     _to_float32
+#define from_double    float32
+#define is_double_nan  is_float32_nan
+#define is_double_eq   is_float32_eq
+#define is_double_lt   is_float32_lt
+#define is_double_gt   is_float32_gt
+
+#elif defined(DOUBLE_SIZE_64)
+
+#define add_double     add_float64
+#define sub_double     sub_float64
+#define mul_double     mul_float64
+#define div_double     div_float64
+#define _to_double     _to_float64
+#define from_double    float64
+#define is_double_nan  is_float64_nan
+#define is_double_eq   is_float64_eq
+#define is_double_lt   is_float64_lt
+#define is_double_gt   is_float64_gt
+
+#elif defined(DOUBLE_SIZE_96)
+
+#define add_double     add_float96
+#define sub_double     sub_float96
+#define mul_double     mul_float96
+#define div_double     div_float96
+#define _to_double     _to_float96
+#define from_double    float96
+#define is_double_nan  is_float96_nan
+#define is_double_eq   is_float96_eq
+#define is_double_lt   is_float96_lt
+#define is_double_gt   is_float96_gt
+
+#elif defined(DOUBLE_SIZE_128)
+
+#define add_double     add_float128
+#define sub_double     sub_float128
+#define mul_double     mul_float128
+#define div_double     div_float128
+#define _to_double     _to_float128
+#define from_double    float128
+#define is_double_nan  is_float128_nan
+#define is_double_eq   is_float128_eq
+#define is_double_lt   is_float128_lt
+#define is_double_gt   is_float128_gt
+
+#endif
+
+
+#if defined(LONG_DOUBLE_SIZE_32)
+
+#define add_long_double     add_float32
+#define sub_long_double     sub_float32
+#define mul_long_double     mul_float32
+#define div_long_double     div_float32
+#define _to_long_double     _to_float32
+#define from_long_double    float32
+#define is_long_double_nan  is_float32_nan
+#define is_long_double_eq   is_float32_eq
+#define is_long_double_lt   is_float32_lt
+#define is_long_double_gt   is_float32_gt
+
+#elif defined(LONG_DOUBLE_SIZE_64)
+
+#define add_long_double     add_float64
+#define sub_long_double     sub_float64
+#define mul_long_double     mul_float64
+#define div_long_double     div_float64
+#define _to_long_double     _to_float64
+#define from_long_double    float64
+#define is_long_double_nan  is_float64_nan
+#define is_long_double_eq   is_float64_eq
+#define is_long_double_lt   is_float64_lt
+#define is_long_double_gt   is_float64_gt
+
+#elif defined(LONG_DOUBLE_SIZE_96)
+
+#define add_long_double     add_float96
+#define sub_long_double     sub_float96
+#define mul_long_double     mul_float96
+#define div_long_double     div_float96
+#define _to_long_double     _to_float96
+#define from_long_double    float96
+#define is_long_double_nan  is_float96_nan
+#define is_long_double_eq   is_float96_eq
+#define is_long_double_lt   is_float96_lt
+#define is_long_double_gt   is_float96_gt
+
+#elif defined(LONG_DOUBLE_SIZE_128)
+
+#define add_long_double     add_float128
+#define sub_long_double     sub_float128
+#define mul_long_double     mul_float128
+#define div_long_double     div_float128
+#define _to_long_double     _to_float128
+#define from_long_double    float128
+#define is_long_double_nan  is_float128_nan
+#define is_long_double_eq   is_float128_eq
+#define is_long_double_lt   is_float128_lt
+#define is_long_double_gt   is_float128_gt
+
+#endif
+
+
+#define CONCAT(a, b)       CONCAT_ARGS(a, b)
+#define CONCAT_ARGS(a, b)  a ## b
+
+#define float32_to_float32(arg)    (arg)
+#define float64_to_float64(arg)    (arg)
+#define float96_to_float96(arg)    (arg)
+#define float128_to_float128(arg)  (arg)
+
+#define float_to_double       CONCAT(from_float, _to_double)
+#define float_to_long_double  CONCAT(from_float, _to_long_double)
+#define float_to_int          CONCAT(from_float, _to_int)
+#define float_to_uint         CONCAT(from_float, _to_uint)
+#define float_to_long         CONCAT(from_float, _to_long)
+#define float_to_ulong        CONCAT(from_float, _to_ulong)
+#define float_to_llong        CONCAT(from_float, _to_llong)
+#define float_to_ullong       CONCAT(from_float, _to_ullong)
+
+#define double_to_float        CONCAT(from_double, _to_float)
+#define double_to_long_double  CONCAT(from_double, _to_long_double)
+#define double_to_int          CONCAT(from_double, _to_int)
+#define double_to_uint         CONCAT(from_double, _to_uint)
+#define double_to_long         CONCAT(from_double, _to_long)
+#define double_to_ulong        CONCAT(from_double, _to_ulong)
+#define double_to_llong        CONCAT(from_double, _to_llong)
+#define double_to_ullong       CONCAT(from_double, _to_ullong)
+
+#define long_double_to_float   CONCAT(from_long_double, _to_float)
+#define long_double_to_double  CONCAT(from_long_double, _to_double)
+#define long_double_to_int     CONCAT(from_long_double, _to_int)
+#define long_double_to_uint    CONCAT(from_long_double, _to_uint)
+#define long_double_to_long    CONCAT(from_long_double, _to_long)
+#define long_double_to_ulong   CONCAT(from_long_double, _to_ulong)
+#define long_double_to_llong   CONCAT(from_long_double, _to_llong)
+#define long_double_to_ullong  CONCAT(from_long_double, _to_ullong)
+
+#define int_to_float        CONCAT(from_int, _to_float)
+#define int_to_double       CONCAT(from_int, _to_double)
+#define int_to_long_double  CONCAT(from_int, _to_long_double)
+
+#define uint_to_float        CONCAT(from_uint, _to_float)
+#define uint_to_double       CONCAT(from_uint, _to_double)
+#define uint_to_long_double  CONCAT(from_uint, _to_long_double)
+
+#define long_to_float        CONCAT(from_long, _to_float)
+#define long_to_double       CONCAT(from_long, _to_double)
+#define long_to_long_double  CONCAT(from_long, _to_long_double)
+
+#define ulong_to_float        CONCAT(from_ulong, _to_float)
+#define ulong_to_double       CONCAT(from_ulong, _to_double)
+#define ulong_to_long_double  CONCAT(from_ulong, _to_long_double)
+
+#define llong_to_float        CONCAT(from_llong, _to_float)
+#define llong_to_double       CONCAT(from_llong, _to_double)
+#define llong_to_long_double  CONCAT(from_llong, _to_long_double)
+
+#define ullong_to_float        CONCAT(from_ullong, _to_float)
+#define ullong_to_double       CONCAT(from_ullong, _to_double)
+#define ullong_to_long_double  CONCAT(from_ullong, _to_long_double)
+
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/softfloat.c
===================================================================
--- uspace/lib/softfloat/softfloat.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/softfloat.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,1353 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat generic
+ * @ingroup sfl
+ * @brief Architecture independent parts of FPU software emulation library.
+ * @{
+ */
+/** @file Softfloat API.
+ */
+
+#include "softfloat.h"
+#include "sftypes.h"
+#include "add.h"
+#include "sub.h"
+#include "mul.h"
+#include "div.h"
+#include "conversion.h"
+#include "comparison.h"
+#include "other.h"
+
+/* Arithmetic functions */
+
+float __addsf3(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	float_t res;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if (fa.data.parts.sign != fb.data.parts.sign) {
+		if (fa.data.parts.sign) {
+			fa.data.parts.sign = 0;
+			res.data = sub_float(fb.data, fa.data);
+			
+			return res.val;
+		}
+		
+		fb.data.parts.sign = 0;
+		res.data = sub_float(fa.data, fb.data);
+		
+		return res.val;
+	}
+	
+	res.data = add_float(fa.data, fb.data);
+	return res.val;
+}
+
+double __adddf3(double a, double b)
+{
+	double_t da;
+	double_t db;
+	double_t res;
+	
+	da.val = a;
+	db.val = b;
+	
+	if (da.data.parts.sign != db.data.parts.sign) {
+		if (da.data.parts.sign) {
+			da.data.parts.sign = 0;
+			res.data = sub_double(db.data, da.data);
+			
+			return res.val;
+		}
+		
+		db.data.parts.sign = 0;
+		res.data = sub_double(da.data, db.data);
+		
+		return res.val;
+	}
+	
+	res.data = add_double(da.data, db.data);
+	return res.val;
+}
+
+long double __addtf3(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	long_double_t res;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if (ta.data.parts.sign != tb.data.parts.sign) {
+		if (ta.data.parts.sign) {
+			ta.data.parts.sign = 0;
+			res.data = sub_long_double(tb.data, ta.data);
+			
+			return res.val;
+		}
+		
+		tb.data.parts.sign = 0;
+		res.data = sub_long_double(ta.data, tb.data);
+		
+		return res.val;
+	}
+	
+	res.data = add_long_double(ta.data, tb.data);
+	return res.val;
+}
+
+float __subsf3(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	float_t res;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if (fa.data.parts.sign != fb.data.parts.sign) {
+		fb.data.parts.sign = !fb.data.parts.sign;
+		res.data = add_float(fa.data, fb.data);
+		
+		return res.val;
+	}
+	
+	res.data = sub_float(fa.data, fb.data);
+	return res.val;
+}
+
+double __subdf3(double a, double b)
+{
+	double_t da;
+	double_t db;
+	double_t res;
+	
+	da.val = a;
+	db.val = b;
+	
+	if (da.data.parts.sign != db.data.parts.sign) {
+		db.data.parts.sign = !db.data.parts.sign;
+		res.data = add_double(da.data, db.data);
+		
+		return res.val;
+	}
+	
+	res.data = sub_double(da.data, db.data);
+	return res.val;
+}
+
+long double __subtf3(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	long_double_t res;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if (ta.data.parts.sign != tb.data.parts.sign) {
+		tb.data.parts.sign = !tb.data.parts.sign;
+		res.data = add_long_double(ta.data, tb.data);
+		
+		return res.val;
+	}
+	
+	res.data = sub_long_double(ta.data, tb.data);
+	return res.val;
+}
+
+float __mulsf3(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	float_t res;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	res.data = mul_float(fa.data, fb.data);
+	return res.val;
+}
+
+double __muldf3(double a, double b)
+{
+	double_t da;
+	double_t db;
+	double_t res;
+	
+	da.val = a;
+	db.val = b;
+	
+	res.data = mul_double(da.data, db.data);
+	return res.val;
+}
+
+long double __multf3(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	long_double_t res;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	res.data = mul_long_double(ta.data, tb.data);
+	return res.val;
+}
+
+float __divsf3(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	float_t res;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	res.data = div_float(fa.data, fb.data);
+	return res.val;
+}
+
+double __divdf3(double a, double b)
+{
+	double_t da;
+	double_t db;
+	double_t res;
+	
+	da.val = a;
+	db.val = b;
+	
+	res.data = div_double(da.data, db.data);
+	return res.val;
+}
+
+long double __divtf3(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	long_double_t res;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	res.data = div_long_double(ta.data, tb.data);
+	return res.val;
+}
+
+float __negsf2(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	fa.data.parts.sign = !fa.data.parts.sign;
+	
+	return fa.val;
+}
+
+double __negdf2(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	da.data.parts.sign = !da.data.parts.sign;
+	
+	return da.val;
+}
+
+long double __negtf2(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	ta.data.parts.sign = !ta.data.parts.sign;
+	
+	return ta.val;
+}
+
+/* Conversion functions */
+
+double __extendsfdf2(float a)
+{
+	float_t fa;
+	double_t res;
+	
+	fa.val = a;
+	res.data = float_to_double(fa.data);
+	
+	return res.val;
+}
+
+long double __extendsftf2(float a)
+{
+	float_t fa;
+	long_double_t res;
+	
+	fa.val = a;
+	res.data = float_to_long_double(fa.data);
+	
+	return res.val;
+}
+
+long double __extenddftf2(double a)
+{
+	double_t da;
+	long_double_t res;
+	
+	da.val = a;
+	res.data = double_to_long_double(da.data);
+	
+	return res.val;
+}
+
+float __truncdfsf2(double a)
+{
+	double_t da;
+	float_t res;
+	
+	da.val = a;
+	res.data = double_to_float(da.data);
+	
+	return res.val;
+}
+
+float __trunctfsf2(long double a)
+{
+	long_double_t ta;
+	float_t res;
+	
+	ta.val = a;
+	res.data = long_double_to_float(ta.data);
+	
+	return res.val;
+}
+
+double __trunctfdf2(long double a)
+{
+	long_double_t ta;
+	double_t res;
+	
+	ta.val = a;
+	res.data = long_double_to_double(ta.data);
+	
+	return res.val;
+}
+
+int __fixsfsi(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_int(fa.data);
+}
+
+int __fixdfsi(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_int(da.data);
+}
+
+int __fixtfsi(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_int(ta.data);
+}
+ 
+long __fixsfdi(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_long(fa.data);
+}
+
+long __fixdfdi(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_long(da.data);
+}
+
+long __fixtfdi(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_long(ta.data);
+}
+ 
+long long __fixsfti(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_llong(fa.data);
+}
+
+long long __fixdfti(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_llong(da.data);
+}
+
+long long __fixtfti(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_llong(ta.data);
+}
+
+unsigned int __fixunssfsi(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_uint(fa.data);
+}
+
+unsigned int __fixunsdfsi(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_uint(da.data);
+}
+
+unsigned int __fixunstfsi(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_uint(ta.data);
+}
+ 
+unsigned long __fixunssfdi(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_ulong(fa.data);
+}
+
+unsigned long __fixunsdfdi(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_ulong(da.data);
+}
+
+unsigned long __fixunstfdi(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_ulong(ta.data);
+}
+ 
+unsigned long long __fixunssfti(float a)
+{
+	float_t fa;
+	
+	fa.val = a;
+	return float_to_ullong(fa.data);
+}
+
+unsigned long long __fixunsdfti(double a)
+{
+	double_t da;
+	
+	da.val = a;
+	return double_to_ullong(da.data);
+}
+
+unsigned long long __fixunstfti(long double a)
+{
+	long_double_t ta;
+	
+	ta.val = a;
+	return long_double_to_ullong(ta.data);
+}
+ 
+float __floatsisf(int i)
+{
+	float_t res;
+	
+	res.data = int_to_float(i);
+	return res.val;
+}
+
+double __floatsidf(int i)
+{
+	double_t res;
+	
+	res.data = int_to_double(i);
+	return res.val;
+}
+
+long double __floatsitf(int i)
+{
+	long_double_t res;
+	
+	res.data = int_to_long_double(i);
+	return res.val;
+}
+ 
+float __floatdisf(long i)
+{
+	float_t res;
+	
+	res.data = long_to_float(i);
+	return res.val;
+}
+
+double __floatdidf(long i)
+{
+	double_t res;
+	
+	res.data = long_to_double(i);
+	return res.val;
+}
+
+long double __floatditf(long i)
+{
+	long_double_t res;
+	
+	res.data = long_to_long_double(i);
+	return res.val;
+}
+
+float __floattisf(long long i)
+{
+	float_t res;
+	
+	res.data = llong_to_float(i);
+	return res.val;
+}
+
+double __floattidf(long long i)
+{
+	double_t res;
+	
+	res.data = llong_to_double(i);
+	return res.val;
+}
+
+long double __floattitf(long long i)
+{
+	long_double_t res;
+	
+	res.data = llong_to_long_double(i);
+	return res.val;
+}
+
+float __floatunsisf(unsigned int i)
+{
+	float_t res;
+	
+	res.data = uint_to_float(i);
+	return res.val;
+}
+
+double __floatunsidf(unsigned int i)
+{
+	double_t res;
+	
+	res.data = uint_to_double(i);
+	return res.val;
+}
+
+long double __floatunsitf(unsigned int i)
+{
+	long_double_t res;
+	
+	res.data = uint_to_long_double(i);
+	return res.val;
+}
+ 
+float __floatundisf(unsigned long i)
+{
+	float_t res;
+	
+	res.data = ulong_to_float(i);
+	return res.val;
+}
+
+double __floatundidf(unsigned long i)
+{
+	double_t res;
+	
+	res.data = ulong_to_double(i);
+	return res.val;
+}
+
+long double __floatunditf(unsigned long i)
+{
+	long_double_t res;
+	
+	res.data = ulong_to_long_double(i);
+	return res.val;
+}
+ 
+float __floatuntisf(unsigned long long i)
+{
+	float_t res;
+	
+	res.data = ullong_to_float(i);
+	return res.val;
+}
+
+double __floatuntidf(unsigned long long i)
+{
+	double_t res;
+	
+	res.data = ullong_to_double(i);
+	return res.val;
+}
+
+long double __floatuntitf(unsigned long long i)
+{
+	long_double_t res;
+	
+	res.data = ullong_to_long_double(i);
+	return res.val;
+}
+
+/* Comparison functions */
+
+int __cmpsf2(float a, float b) 
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		/* no special constant for unordered - maybe signaled? */
+		return 1;
+	}
+	
+	if (is_float_eq(fa.data, fb.data))
+		return 0;
+	
+	if (is_float_lt(fa.data, fb.data))
+		return -1;
+	
+	return 1;
+}
+
+int __cmpdf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		/* no special constant for unordered - maybe signaled? */
+		return 1;
+	}
+	
+	if (is_double_eq(da.data, db.data))
+		return 0;
+	
+	if (is_double_lt(da.data, db.data))
+		return -1;
+	
+	return 1;
+}
+
+int __cmptf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		/* no special constant for unordered - maybe signaled? */
+		return 1;
+	}
+	
+	if (is_long_double_eq(ta.data, tb.data))
+		return 0;
+	
+	if (is_long_double_lt(ta.data, tb.data))
+		return -1;
+	
+	return 1;
+}
+
+int __unordsf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	return ((is_float_nan(fa.data)) || (is_float_nan(fb.data)));
+}
+
+int __unorddf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	return ((is_double_nan(da.data)) || (is_double_nan(db.data)));
+}
+
+int __unordtf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	return ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)));
+}
+
+int __eqsf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	return is_float_eq(fa.data, fb.data) - 1;
+}
+
+int __eqdf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	return is_double_eq(da.data, db.data) - 1;
+}
+
+int __eqtf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	return is_long_double_eq(ta.data, tb.data) - 1;
+}
+
+int __nesf2(float a, float b)
+{
+	/* strange behavior, but it was in gcc documentation */
+	return __eqsf2(a, b);
+}
+
+int __nedf2(double a, double b)
+{
+	/* strange behavior, but it was in gcc documentation */
+	return __eqdf2(a, b);
+}
+
+int __netf2(long double a, long double b)
+{
+	/* strange behavior, but it was in gcc documentation */
+	return __eqtf2(a, b);
+}
+
+int __gesf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_float_eq(fa.data, fb.data))
+		return 0;
+	
+	if (is_float_gt(fa.data, fb.data))
+		return 1;
+	
+	return -1;
+}
+
+int __gedf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_double_eq(da.data, db.data))
+		return 0;
+	
+	if (is_double_gt(da.data, db.data))
+		return 1;
+	
+	return -1;
+}
+
+int __getf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_long_double_eq(ta.data, tb.data))
+		return 0;
+	
+	if (is_long_double_gt(ta.data, tb.data))
+		return 1;
+	
+	return -1;
+}
+
+int __ltsf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_float_lt(fa.data, fb.data))
+		return -1;
+	
+	return 0;
+}
+
+int __ltdf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_double_lt(da.data, db.data))
+		return -1;
+	
+	return 0;
+}
+
+int __lttf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_long_double_lt(ta.data, tb.data))
+		return -1;
+	
+	return 0;
+}
+
+int __lesf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_float_eq(fa.data, fb.data))
+		return 0;
+	
+	if (is_float_lt(fa.data, fb.data))
+		return -1;
+	
+	return 1;
+}
+
+int __ledf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_double_eq(da.data, db.data))
+		return 0;
+	
+	if (is_double_lt(da.data, db.data))
+		return -1;
+	
+	return 1;
+}
+
+int __letf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return 1;
+	}
+	
+	if (is_long_double_eq(ta.data, tb.data))
+		return 0;
+	
+	if (is_long_double_lt(ta.data, tb.data))
+		return -1;
+	
+	return 1;
+}
+
+int __gtsf2(float a, float b)
+{
+	float_t fa;
+	float_t fb;
+	
+	fa.val = a;
+	fb.val = b;
+	
+	if ((is_float_nan(fa.data)) || (is_float_nan(fb.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_float_gt(fa.data, fb.data))
+		return 1;
+	
+	return 0;
+}
+
+int __gtdf2(double a, double b)
+{
+	double_t da;
+	double_t db;
+	
+	da.val = a;
+	db.val = b;
+	
+	if ((is_double_nan(da.data)) || (is_double_nan(db.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_double_gt(da.data, db.data))
+		return 1;
+	
+	return 0;
+}
+
+int __gttf2(long double a, long double b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = a;
+	tb.val = b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data))) {
+		// TODO: sigNaNs
+		return -1;
+	}
+	
+	if (is_long_double_gt(ta.data, tb.data))
+		return 1;
+	
+	return 0;
+}
+
+/* SPARC quadruple-precision wrappers */
+
+void _Qp_add(long double *c, long double *a, long double *b)
+{
+	*c = __addtf3(*a, *b);
+}
+
+void _Qp_sub(long double *c, long double *a, long double *b)
+{
+	*c = __subtf3(*a, *b);
+}
+
+void _Qp_mul(long double *c, long double *a, long double *b)
+{
+	*c = __multf3(*a, *b);
+}
+
+void _Qp_div(long double *c, long double *a, long double *b)
+{
+	*c = __divtf3(*a, *b);
+}
+
+void _Qp_neg(long double *c, long double *a)
+{
+	*c = __negtf2(*a);
+}
+
+void _Qp_stoq(long double *c, float a)
+{
+	*c = __extendsftf2(a);
+}
+
+void _Qp_dtoq(long double *c, double a)
+{
+	*c = __extenddftf2(a);
+}
+
+float _Qp_qtos(long double *a)
+{
+	return __trunctfsf2(*a);
+}
+
+double _Qp_qtod(long double *a)
+{
+	return __trunctfdf2(*a);
+}
+
+int _Qp_qtoi(long double *a)
+{
+	return __fixtfsi(*a);
+}
+
+unsigned int _Qp_qtoui(long double *a)
+{
+	return __fixunstfsi(*a);
+}
+
+long _Qp_qtox(long double *a)
+{
+	return __fixtfdi(*a);
+}
+
+unsigned long _Qp_qtoux(long double *a)
+{
+	return __fixunstfdi(*a);
+}
+
+void _Qp_itoq(long double *c, int a)
+{
+	*c = __floatsitf(a);
+}
+
+void _Qp_uitoq(long double *c, unsigned int a)
+{
+	*c = __floatunsitf(a);
+}
+
+void _Qp_xtoq(long double *c, long a)
+{
+	*c = __floatditf(a);
+}
+
+void _Qp_uxtoq(long double *c, unsigned long a)
+{
+	*c = __floatunditf(a);
+}
+
+int _Qp_cmp(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 3;
+	
+	if (is_long_double_eq(ta.data, tb.data))
+		return 0;
+	
+	if (is_long_double_lt(ta.data, tb.data))
+		return 1;
+	
+	return 2;
+}
+
+int _Qp_cmpe(long double *a, long double *b)
+{
+	/* strange, but is defined this way in SPARC Compliance Definition */
+	return _Qp_cmp(a, b);
+}
+
+int _Qp_feq(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_eq(ta.data, tb.data);
+}
+
+int _Qp_fge(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_eq(ta.data, tb.data) ||
+	    is_long_double_gt(ta.data, tb.data);
+}
+
+int _Qp_fgt(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_gt(ta.data, tb.data);
+}
+
+int _Qp_fle(long double*a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_eq(ta.data, tb.data) ||
+	    is_long_double_lt(ta.data, tb.data);
+}
+
+int _Qp_flt(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return is_long_double_lt(ta.data, tb.data);
+}
+
+int _Qp_fne(long double *a, long double *b)
+{
+	long_double_t ta;
+	long_double_t tb;
+	
+	ta.val = *a;
+	tb.val = *b;
+	
+	if ((is_long_double_nan(ta.data)) || (is_long_double_nan(tb.data)))
+		return 0;
+	
+	return !is_long_double_eq(ta.data, tb.data);
+}
+
+double __aeabi_i2d(int i)
+{
+	return __floatsidf(i);
+}
+
+double __aeabi_ui2d(unsigned int i)
+{
+	return __floatunsidf(i);
+}
+
+int __aeabi_f2iz(float a)
+{
+	return __fixsfsi(a);
+}
+
+int __aeabi_d2iz(double a)
+{
+	return __fixdfsi(a);
+}
+
+unsigned int __aeabi_d2uiz(double a)
+{
+	return __fixunsdfsi(a);
+}
+
+int __aeabi_dcmpge(double a, double b)
+{
+	return __gedf2(a, b);
+}
+
+int __aeabi_dcmpgt(double a, double b)
+{
+	return __gtdf2(a, b);
+}
+
+int __aeabi_dcmplt(double a, double b)
+{
+	return __ltdf2(a, b);
+}
+
+int __aeabi_dcmpeq(double a, double b)
+{
+	return __eqdf2(a, b);
+}
+
+float __aeabi_fadd(float a, float b)
+{
+	return __addsf3(a, b);
+}
+
+float __aeabi_fsub(float a, float b)
+{
+	return __subsf3(a, b);
+}
+
+float __aeabi_fmul(float a, float b)
+{
+	return __mulsf3(a, b);
+}
+
+float __aeabi_fdiv(float a, float b)
+{
+	return __divsf3(a, b);
+}
+
+double __aeabi_dadd(double a, double b)
+{
+	return __adddf3(a, b);
+}
+
+double __aeabi_dsub(double a, double b)
+{
+	return __subdf3(a, b);
+}
+
+double __aeabi_dmul(double a, double b)
+{
+	return __muldf3(a, b);
+}
+
+double __aeabi_ddiv(double a, double b)
+{
+	return __divdf3(a, b);
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/softfloat.h
===================================================================
--- uspace/lib/softfloat/softfloat.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/softfloat.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Softfloat API.
+ */
+
+#ifndef __SOFTFLOAT_H__
+#define __SOFTFLOAT_H__
+
+extern float __addsf3(float, float);
+extern double __adddf3(double, double);
+extern long double __addtf3(long double, long double);
+extern long double __addxf3(long double, long double);
+
+extern float __subsf3(float, float);
+extern double __subdf3(double, double);
+extern long double __subtf3(long double, long double);
+extern long double __subxf3(long double, long double);
+
+extern float __mulsf3(float, float);
+extern double __muldf3(double, double);
+extern long double __multf3(long double, long double);
+extern long double __mulxf3(long double, long double);
+
+extern float __divsf3(float, float);
+extern double __divdf3(double, double);
+extern long double __divtf3(long double, long double);
+extern long double __divxf3(long double, long double);
+
+extern float __negsf2(float);
+extern double __negdf2(double);
+extern long double __negtf2(long double);
+extern long double __negxf2(long double);
+
+extern double __extendsfdf2(float);
+extern long double __extendsftf2(float);
+extern long double __extendsfxf2(float);
+extern long double __extenddftf2(double);
+extern long double __extenddfxf2(double);
+
+extern double __truncxfdf2(long double);
+extern double __trunctfdf2(long double);
+extern float __truncxfsf2(long double);
+extern float __trunctfsf2(long double);
+extern float __truncdfsf2(double);
+
+extern int __fixsfsi(float);
+extern int __fixdfsi(double);
+extern int __fixtfsi(long double);
+extern int __fixxfsi(long double);
+
+extern long __fixsfdi(float);
+extern long __fixdfdi(double);
+extern long __fixtfdi(long double);
+extern long __fixxfdi(long double);
+
+extern long long __fixsfti(float);
+extern long long __fixdfti(double);
+extern long long __fixtfti(long double);
+extern long long __fixxfti(long double);
+
+extern unsigned int __fixunssfsi(float);
+extern unsigned int __fixunsdfsi(double);
+extern unsigned int __fixunstfsi(long double);
+extern unsigned int __fixunsxfsi(long double);
+
+extern unsigned long __fixunssfdi(float);
+extern unsigned long __fixunsdfdi(double);
+extern unsigned long __fixunstfdi(long double);
+extern unsigned long __fixunsxfdi(long double);
+
+extern unsigned long long __fixunssfti(float);
+extern unsigned long long __fixunsdfti(double);
+extern unsigned long long __fixunstfti(long double);
+extern unsigned long long __fixunsxfti(long double);
+
+extern float __floatsisf(int);
+extern double __floatsidf(int);
+extern long double __floatsitf(int);
+extern long double __floatsixf(int);
+
+extern float __floatdisf(long);
+extern double __floatdidf(long);
+extern long double __floatditf(long);
+extern long double __floatdixf(long);
+
+extern float __floattisf(long long);
+extern double __floattidf(long long);
+extern long double __floattitf(long long);
+extern long double __floattixf(long long);
+
+extern float __floatunsisf(unsigned int);
+extern double __floatunsidf(unsigned int);
+extern long double __floatunsitf(unsigned int);
+extern long double __floatunsixf(unsigned int);
+
+extern float __floatundisf(unsigned long);
+extern double __floatundidf(unsigned long);
+extern long double __floatunditf(unsigned long);
+extern long double __floatundixf(unsigned long);
+
+extern float __floatuntisf(unsigned long long);
+extern double __floatuntidf(unsigned long long);
+extern long double __floatuntitf(unsigned long long);
+extern long double __floatuntixf(unsigned long long);
+
+extern int __cmpsf2(float, float);
+extern int __cmpdf2(double, double);
+extern int __cmptf2(long double, long double);
+
+extern int __unordsf2(float, float);
+extern int __unorddf2(double, double);
+extern int __unordtf2(long double, long double);
+
+extern int __eqsf2(float, float);
+extern int __eqdf2(double, double);
+extern int __eqtf2(long double, long double);
+
+extern int __nesf2(float, float);
+extern int __nedf2(double, double);
+extern int __netf2(long double, long double);
+
+extern int __gesf2(float, float);
+extern int __gedf2(double, double);
+extern int __getf2(long double, long double);
+
+extern int __ltsf2(float, float);
+extern int __ltdf2(double, double);
+extern int __lttf2(long double, long double);
+
+extern int __lesf2(float, float);
+extern int __ledf2(double, double);
+extern int __letf2(long double, long double);
+
+extern int __gtsf2(float, float);
+extern int __gtdf2(double, double);
+extern int __gttf2(long double, long double);
+
+/* Not implemented yet */
+extern float __powisf2(float, int);
+extern double __powidf2 (double, int);
+extern long double __powitf2(long double, int);
+extern long double __powixf2(long double, int);
+
+/* SPARC quadruple-precision wrappers */
+extern void _Qp_add(long double *, long double *, long double *);
+extern void _Qp_sub(long double *, long double *, long double *);
+extern void _Qp_mul(long double *, long double *, long double *);
+extern void _Qp_div(long double *, long double *, long double *);
+extern void _Qp_neg(long double *, long double *);
+
+extern void _Qp_stoq(long double *, float);
+extern void _Qp_dtoq(long double *, double);
+extern float _Qp_qtos(long double *);
+extern double _Qp_qtod(long double *);
+
+extern int _Qp_qtoi(long double *);
+extern unsigned int _Qp_qtoui(long double *);
+extern long _Qp_qtox(long double *);
+extern unsigned long _Qp_qtoux(long double *);
+
+extern void _Qp_itoq(long double *, int);
+extern void _Qp_uitoq(long double *, unsigned int);
+extern void _Qp_xtoq(long double *, long);
+extern void _Qp_uxtoq(long double *, unsigned long);
+
+extern int _Qp_cmp(long double *, long double *);
+extern int _Qp_cmpe(long double *, long double *);
+extern int _Qp_feq(long double *, long double *);
+extern int _Qp_fge(long double *, long double *);
+extern int _Qp_fgt(long double *, long double *);
+extern int _Qp_fle(long double*, long double *);
+extern int _Qp_flt(long double *, long double *);
+extern int _Qp_fne(long double *, long double *);
+
+/* ARM EABI */
+extern double __aeabi_i2d(int);
+extern double __aeabi_ui2d(unsigned int);
+extern unsigned int __aeabi_d2uiz(double);
+
+extern int __aeabi_f2iz(float);
+extern int __aeabi_d2iz(double);
+
+extern int __aeabi_dcmpge(double, double);
+extern int __aeabi_dcmpgt(double, double);
+extern int __aeabi_dcmplt(double, double);
+extern int __aeabi_dcmpeq(double, double);
+
+extern float __aeabi_fadd(float, float);
+extern float __aeabi_fsub(float, float);
+extern float __aeabi_fmul(float, float);
+extern float __aeabi_fdiv(float, float);
+
+extern double __aeabi_dadd(double, double);
+extern double __aeabi_dsub(double, double);
+extern double __aeabi_dmul(double, double);
+extern double __aeabi_ddiv(double, double);
+
+/* Not implemented yet */
+extern void _Qp_sqrt(long double *, long double *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softfloat/sub.c
===================================================================
--- uspace/lib/softfloat/sub.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/sub.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Substraction functions.
+ */
+
+#include "sftypes.h"
+#include "sub.h"
+#include "comparison.h"
+#include "common.h"
+
+/** Subtract two single-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of substraction.
+ *
+ */
+float32 sub_float32(float32 a, float32 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2, frac1, frac2;
+	float32 result;
+	
+	result.bin = 0;
+	
+	expdiff = a.parts.exp - b.parts.exp;
+	if ((expdiff < 0 ) || ((expdiff == 0) &&
+	    (a.parts.fraction < b.parts.fraction))) {
+		if (is_float32_nan(b)) {
+			if (is_float32_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return b;
+		}
+		
+		if (b.parts.exp == FLOAT32_MAX_EXPONENT) {
+			/* num -(+-inf) = -+inf */
+			b.parts.sign = !b.parts.sign;
+			return b;
+		}
+		
+		result.parts.sign = !a.parts.sign;
+		
+		frac1 = b.parts.fraction;
+		exp1 = b.parts.exp;
+		frac2 = a.parts.fraction;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float32_nan(a)) {
+			if ((is_float32_signan(a)) || (is_float32_signan(b))) {
+				// TODO: fix SigNaN
+			}
+			
+			return a;
+		}
+		
+		if (a.parts.exp == FLOAT32_MAX_EXPONENT) {
+			if (b.parts.exp == FLOAT32_MAX_EXPONENT) {
+				/* inf - inf => nan */
+				// TODO: fix exception
+				result.bin = FLOAT32_NAN;
+				return result;
+			}
+			
+			return a;
+		}
+		
+		result.parts.sign = a.parts.sign;
+		
+		frac1 = a.parts.fraction;
+		exp1 = a.parts.exp;
+		frac2 = b.parts.fraction;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		result.parts.fraction = frac1 - frac2;
+		if (result.parts.fraction > frac1) {
+			// TODO: underflow exception
+			return result;
+		}
+		
+		result.parts.exp = 0;
+		return result;
+	}
+	
+	/* add hidden bit */
+	frac1 |= FLOAT32_HIDDEN_BIT_MASK;
+	
+	if (exp2 == 0) {
+		/* denormalized */
+		--expdiff;
+	} else {
+		/* normalized */
+		frac2 |= FLOAT32_HIDDEN_BIT_MASK;
+	}
+	
+	/* create some space for rounding */
+	frac1 <<= 6;
+	frac2 <<= 6;
+	
+	if (expdiff > FLOAT32_FRACTION_SIZE + 1)
+		goto done;
+	
+	frac1 = frac1 - (frac2 >> expdiff);
+	
+done:
+	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
+	while ((exp1 > 0) && (!(frac1 & (FLOAT32_HIDDEN_BIT_MASK << 6 )))) {
+		--exp1;
+		frac1 <<= 1;
+		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	frac1 += 0x20;
+	
+	if (frac1 & (FLOAT32_HIDDEN_BIT_MASK << 7)) {
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	/* Clear hidden bit and shift */
+	result.parts.fraction = ((frac1 >> 6) & (~FLOAT32_HIDDEN_BIT_MASK));
+	result.parts.exp = exp1;
+	
+	return result;
+}
+
+/** Subtract two double-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of substraction.
+ *
+ */
+float64 sub_float64(float64 a, float64 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2;
+	uint64_t frac1, frac2;
+	float64 result;
+	
+	result.bin = 0;
+	
+	expdiff = a.parts.exp - b.parts.exp;
+	if ((expdiff < 0 ) ||
+	    ((expdiff == 0) && (a.parts.fraction < b.parts.fraction))) {
+		if (is_float64_nan(b)) {
+			if (is_float64_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return b;
+		}
+		
+		if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
+			/* num -(+-inf) = -+inf */
+			b.parts.sign = !b.parts.sign;
+			return b;
+		}
+		
+		result.parts.sign = !a.parts.sign;
+		
+		frac1 = b.parts.fraction;
+		exp1 = b.parts.exp;
+		frac2 = a.parts.fraction;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float64_nan(a)) {
+			if (is_float64_signan(a) || is_float64_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return a;
+		}
+		
+		if (a.parts.exp == FLOAT64_MAX_EXPONENT) {
+			if (b.parts.exp == FLOAT64_MAX_EXPONENT) {
+				/* inf - inf => nan */
+				// TODO: fix exception
+				result.bin = FLOAT64_NAN;
+				return result;
+			}
+			
+			return a;
+		}
+		
+		result.parts.sign = a.parts.sign;
+		
+		frac1 = a.parts.fraction;
+		exp1 = a.parts.exp;
+		frac2 = b.parts.fraction;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		result.parts.fraction = frac1 - frac2;
+		if (result.parts.fraction > frac1) {
+			// TODO: underflow exception
+			return result;
+		}
+		
+		result.parts.exp = 0;
+		return result;
+	}
+	
+	/* add hidden bit */
+	frac1 |= FLOAT64_HIDDEN_BIT_MASK;
+	
+	if (exp2 == 0) {
+		/* denormalized */
+		--expdiff;
+	} else {
+		/* normalized */
+		frac2 |= FLOAT64_HIDDEN_BIT_MASK;
+	}
+	
+	/* create some space for rounding */
+	frac1 <<= 6;
+	frac2 <<= 6;
+	
+	if (expdiff > FLOAT64_FRACTION_SIZE + 1)
+		goto done;
+	
+	frac1 = frac1 - (frac2 >> expdiff);
+	
+done:
+	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
+	while ((exp1 > 0) && (!(frac1 & (FLOAT64_HIDDEN_BIT_MASK << 6 )))) {
+		--exp1;
+		frac1 <<= 1;
+		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	frac1 += 0x20;
+	
+	if (frac1 & (FLOAT64_HIDDEN_BIT_MASK << 7)) {
+		++exp1;
+		frac1 >>= 1;
+	}
+	
+	/* Clear hidden bit and shift */
+	result.parts.fraction = ((frac1 >> 6) & (~FLOAT64_HIDDEN_BIT_MASK));
+	result.parts.exp = exp1;
+	
+	return result;
+}
+
+/** Subtract two quadruple-precision floats with the same sign.
+ *
+ * @param a First input operand.
+ * @param b Second input operand.
+ *
+ * @return Result of substraction.
+ *
+ */
+float128 sub_float128(float128 a, float128 b)
+{
+	int expdiff;
+	uint32_t exp1, exp2;
+	uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
+	float128 result;
+	
+	result.bin.hi = 0;
+	result.bin.lo = 0;
+	
+	expdiff = a.parts.exp - b.parts.exp;
+	if ((expdiff < 0 ) || ((expdiff == 0) &&
+	    lt128(a.parts.frac_hi, a.parts.frac_lo, b.parts.frac_hi, b.parts.frac_lo))) {
+		if (is_float128_nan(b)) {
+			if (is_float128_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return b;
+		}
+		
+		if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
+			/* num -(+-inf) = -+inf */
+			b.parts.sign = !b.parts.sign;
+			return b;
+		}
+		
+		result.parts.sign = !a.parts.sign;
+		
+		frac1_hi = b.parts.frac_hi;
+		frac1_lo = b.parts.frac_lo;
+		exp1 = b.parts.exp;
+		frac2_hi = a.parts.frac_hi;
+		frac2_lo = a.parts.frac_lo;
+		exp2 = a.parts.exp;
+		expdiff *= -1;
+	} else {
+		if (is_float128_nan(a)) {
+			if (is_float128_signan(a) || is_float128_signan(b)) {
+				// TODO: fix SigNaN
+			}
+			
+			return a;
+		}
+		
+		if (a.parts.exp == FLOAT128_MAX_EXPONENT) {
+			if (b.parts.exp == FLOAT128_MAX_EXPONENT) {
+				/* inf - inf => nan */
+				// TODO: fix exception
+				result.bin.hi = FLOAT128_NAN_HI;
+				result.bin.lo = FLOAT128_NAN_LO;
+				return result;
+			}
+			return a;
+		}
+		
+		result.parts.sign = a.parts.sign;
+		
+		frac1_hi = a.parts.frac_hi;
+		frac1_lo = a.parts.frac_lo;
+		exp1 = a.parts.exp;
+		frac2_hi = b.parts.frac_hi;
+		frac2_lo = b.parts.frac_lo;
+		exp2 = b.parts.exp;
+	}
+	
+	if (exp1 == 0) {
+		/* both are denormalized */
+		sub128(frac1_hi, frac1_lo, frac2_hi, frac2_lo, &tmp_hi, &tmp_lo);
+		result.parts.frac_hi = tmp_hi;
+		result.parts.frac_lo = tmp_lo;
+		if (lt128(frac1_hi, frac1_lo, result.parts.frac_hi, result.parts.frac_lo)) {
+			// TODO: underflow exception
+			return result;
+		}
+		
+		result.parts.exp = 0;
+		return result;
+	}
+	
+	/* add hidden bit */
+	or128(frac1_hi, frac1_lo,
+	    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &frac1_hi, &frac1_lo);
+	
+	if (exp2 == 0) {
+		/* denormalized */
+		--expdiff;
+	} else {
+		/* normalized */
+		or128(frac2_hi, frac2_lo,
+		    FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+		    &frac2_hi, &frac2_lo);
+	}
+	
+	/* create some space for rounding */
+	lshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+	lshift128(frac2_hi, frac2_lo, 6, &frac2_hi, &frac2_lo);
+	
+	if (expdiff > FLOAT128_FRACTION_SIZE + 1)
+		goto done;
+	
+	rshift128(frac2_hi, frac2_lo, expdiff, &tmp_hi, &tmp_lo);
+	sub128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
+	
+done:
+	/* TODO: find first nonzero digit and shift result and detect possibly underflow */
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 6,
+	    &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	while ((exp1 > 0) && (!lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo))) {
+		--exp1;
+		lshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+		/* TODO: fix underflow - frac1 == 0 does not necessary means underflow... */
+		
+		lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 6,
+		    &tmp_hi, &tmp_lo);
+		and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	}
+	
+	/* rounding - if first bit after fraction is set then round up */
+	add128(frac1_hi, frac1_lo, 0x0ll, 0x20ll, &frac1_hi, &frac1_lo);
+	
+	lshift128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO, 7,
+	   &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	if (lt128(0x0ll, 0x0ll, tmp_hi, tmp_lo)) {
+		++exp1;
+		rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
+	}
+	
+	/* Clear hidden bit and shift */
+	rshift128(frac1_hi, frac1_lo, 6, &frac1_hi, &frac1_lo);
+	not128(FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
+	    &tmp_hi, &tmp_lo);
+	and128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &tmp_hi, &tmp_lo);
+	result.parts.frac_hi = tmp_hi;
+	result.parts.frac_lo = tmp_lo;
+	
+	result.parts.exp = exp1;
+	
+	return result;
+}
+
+/** @}
+ */
Index: uspace/lib/softfloat/sub.h
===================================================================
--- uspace/lib/softfloat/sub.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/lib/softfloat/sub.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Josef Cejka
+ * Copyright (c) 2011 Petr Koupy
+ * 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 softfloat
+ * @{
+ */
+/** @file Substraction functions.
+ */
+
+#ifndef __SUB_H__
+#define __SUB_H__
+
+extern float32 sub_float32(float32, float32);
+extern float64 sub_float64(float64, float64);
+extern float96 sub_float96(float96, float96);
+extern float128 sub_float128(float128, float128);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/usb/include/usb/debug.h
===================================================================
--- uspace/lib/usb/include/usb/debug.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/usb/include/usb/debug.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -38,4 +38,5 @@
 #include <inttypes.h>
 #include <usb/usb.h>
+#include <io/log.h>
 #include <assert.h>
 
@@ -43,52 +44,13 @@
     const uint8_t *, size_t);
 
-/** Logging level. */
-typedef enum {
-	/** Fatal, unrecoverable, error.
-	 * Such error prevents the driver from working at all.
-	 */
-	USB_LOG_LEVEL_FATAL,
+#define USB_LOG_LEVEL_FATAL LVL_FATAL
+#define USB_LOG_LEVEL_ERROR LVL_ERROR
+#define USB_LOG_LEVEL_WARNING LVL_WARN
+#define USB_LOG_LEVEL_INFO LVL_NOTE
+#define USB_LOG_LEVEL_DEBUG LVL_DEBUG
+#define USB_LOG_LEVEL_DEBUG2 LVL_DEBUG2
 
-	/** Serious but recoverable error
-	 * Shall be used for errors fatal for single device but not for
-	 * driver itself.
-	 */
-	USB_LOG_LEVEL_ERROR,
-
-	/** Warning.
-	 * Problems from which the driver is able to recover gracefully.
-	 */
-	USB_LOG_LEVEL_WARNING,
-
-	/** Information message.
-	 * This should be the last level that is printed by default to
-	 * the screen.
-	 * Typical usage is to inform that new device was found and what
-	 * are its capabilities.
-	 * Do not use for repetitive actions (such as device polling).
-	 */
-	USB_LOG_LEVEL_INFO,
-
-	/** Debugging message. */
-	USB_LOG_LEVEL_DEBUG,
-
-	/** More detailed debugging message. */
-	USB_LOG_LEVEL_DEBUG2,
-
-	/** Terminating constant for logging levels. */
-	USB_LOG_LEVEL_MAX
-} usb_log_level_t;
-
-/** Default log level. */
-#ifdef CONFIG_USB_VERBOSE
-	#define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_DEBUG
-#else
-	#define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_INFO
-#endif
-
-void usb_log_enable(usb_log_level_t, const char *);
-
-void usb_log_printf(usb_log_level_t, const char *, ...)
-	PRINTF_ATTRIBUTE(2, 3);
+#define usb_log_printf(level, format, ...) \
+	log_msg(LOG_DEFAULT, level, format, ##__VA_ARGS__)
 
 /** Log fatal error. */
Index: uspace/lib/usb/src/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/lib/usb/src/debug.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -40,115 +40,4 @@
 #include <ddf/log.h>
 #include <usb/debug.h>
-
-/** Level of logging messages. */
-static usb_log_level_t log_level = USB_LOG_LEVEL_WARNING;
-
-/** Prefix for logging messages. */
-static const char *log_prefix = "usb";
-
-/** Serialization mutex for logging functions. */
-static FIBRIL_MUTEX_INITIALIZE(log_serializer);
-
-/** File where to store the log. */
-static FILE *log_stream = NULL;
-
-
-/** Enable logging.
- *
- * @param level Maximal enabled level (including this one).
- * @param message_prefix Prefix for each printed message.
- */
-void usb_log_enable(usb_log_level_t level, const char *message_prefix)
-{
-	log_prefix = message_prefix;
-	log_level = level;
-	if (log_stream == NULL) {
-		char *fname;
-		int rc = asprintf(&fname, "/log/%s", message_prefix);
-		if (rc > 0) {
-			log_stream = fopen(fname, "w");
-			if (log_stream != NULL)
-				setvbuf(log_stream, NULL, _IOFBF, BUFSIZ);
-			
-			free(fname);
-		}
-	}
-}
-
-/** Get log level name prefix.
- *
- * @param level Log level.
- * @return String prefix for the message.
- */
-static const char *log_level_name(usb_log_level_t level)
-{
-	switch (level) {
-		case USB_LOG_LEVEL_FATAL:
-			return " FATAL";
-		case USB_LOG_LEVEL_ERROR:
-			return " ERROR";
-		case USB_LOG_LEVEL_WARNING:
-			return " WARN";
-		case USB_LOG_LEVEL_INFO:
-			return " info";
-		default:
-			return "";
-	}
-}
-
-/** Print logging message.
- *
- * @param level Verbosity level of the message.
- * @param format Formatting directive.
- */
-void usb_log_printf(usb_log_level_t level, const char *format, ...)
-{
-	FILE *screen_stream = NULL;
-	switch (level) {
-		case USB_LOG_LEVEL_FATAL:
-		case USB_LOG_LEVEL_ERROR:
-			screen_stream = stderr;
-			break;
-		default:
-			screen_stream = stdout;
-			break;
-	}
-	assert(screen_stream != NULL);
-
-	va_list args;
-
-	/*
-	 * Serialize access to log files.
-	 * Print to screen only messages with higher level than the one
-	 * specified during logging initialization.
-	 * Print also to file, to it print one more (lower) level as well.
-	 */
-	fibril_mutex_lock(&log_serializer);
-
-	const char *level_name = log_level_name(level);
-
-	if ((log_stream != NULL) && (level <= log_level + 1)) {
-		va_start(args, format);
-
-		fprintf(log_stream, "[%s]%s: ", log_prefix, level_name);
-		vfprintf(log_stream, format, args);
-		fflush(log_stream);
-
-		va_end(args);
-	}
-
-	if (level <= log_level) {
-		va_start(args, format);
-
-		fprintf(screen_stream, "[%s]%s: ", log_prefix, level_name);
-		vfprintf(screen_stream, format, args);
-		fflush(screen_stream);
-
-		va_end(args);
-	}
-
-	fibril_mutex_unlock(&log_serializer);
-}
-
 
 #define REMAINDER_STR_FMT " (%zu)..."
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/devman/devman.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -151,5 +151,5 @@
 	fibril_mutex_unlock(&drivers_list->drivers_mutex);
 
-	log_msg(LVL_NOTE, "Driver `%s' was added to the list of available "
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Driver `%s' was added to the list of available "
 	    "drivers.", drv->name);
 }
@@ -242,5 +242,5 @@
 bool read_match_ids(const char *conf_path, match_id_list_t *ids)
 {
-	log_msg(LVL_DEBUG, "read_match_ids(conf_path=\"%s\")", conf_path);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "read_match_ids(conf_path=\"%s\")", conf_path);
 	
 	bool suc = false;
@@ -252,5 +252,5 @@
 	fd = open(conf_path, O_RDONLY);
 	if (fd < 0) {
-		log_msg(LVL_ERROR, "Unable to open `%s' for reading: %s.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to open `%s' for reading: %s.",
 		    conf_path, str_error(fd));
 		goto cleanup;
@@ -261,5 +261,5 @@
 	lseek(fd, 0, SEEK_SET);
 	if (len == 0) {
-		log_msg(LVL_ERROR, "Configuration file '%s' is empty.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Configuration file '%s' is empty.",
 		    conf_path);
 		goto cleanup;
@@ -268,5 +268,5 @@
 	buf = malloc(len + 1);
 	if (buf == NULL) {
-		log_msg(LVL_ERROR, "Memory allocation failed when parsing file "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed when parsing file "
 		    "'%s'.", conf_path);
 		goto cleanup;
@@ -275,5 +275,5 @@
 	ssize_t read_bytes = read_all(fd, buf, len);
 	if (read_bytes <= 0) {
-		log_msg(LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
 		    read_bytes);
 		goto cleanup;
@@ -314,5 +314,5 @@
 bool get_driver_info(const char *base_path, const char *name, driver_t *drv)
 {
-	log_msg(LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
 	    base_path, name);
 	
@@ -346,5 +346,5 @@
 	struct stat s;
 	if (stat(drv->binary_path, &s) == ENOENT) { /* FIXME!! */
-		log_msg(LVL_ERROR, "Driver not found at path `%s'.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Driver not found at path `%s'.",
 		    drv->binary_path);
 		goto cleanup;
@@ -374,5 +374,5 @@
 int lookup_available_drivers(driver_list_t *drivers_list, const char *dir_path)
 {
-	log_msg(LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
 	
 	int drv_cnt = 0;
@@ -408,5 +408,5 @@
 	dev_node_t *dev;
 	
-	log_msg(LVL_DEBUG, "create_root_nodes()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "create_root_nodes()");
 	
 	fibril_rwlock_write_lock(&tree->rwlock);
@@ -495,5 +495,5 @@
 void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
 {
-	log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
 	    dev->pfun->pathname, drv->name);
 	
@@ -520,5 +520,5 @@
 	assert(drv != NULL);
 	
-	log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
 	    dev->pfun->pathname, drv->name);
 	
@@ -545,9 +545,9 @@
 	assert(fibril_mutex_is_locked(&drv->driver_mutex));
 	
-	log_msg(LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
 	
 	rc = task_spawnl(NULL, drv->binary_path, drv->binary_path, NULL);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Spawning driver `%s' (%s) failed: %s.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Spawning driver `%s' (%s) failed: %s.",
 		    drv->name, drv->binary_path, str_error(rc));
 		return false;
@@ -594,5 +594,5 @@
 	link_t *link;
 
-	log_msg(LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
 	    driver->name);
 
@@ -614,5 +614,5 @@
 		}
 
-		log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
 		    (int)atomic_get(&dev->refcnt));
 		dev_add_ref(dev);
@@ -650,5 +650,5 @@
 	 * immediately and possibly started here as well.
 	 */
-	log_msg(LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
 	driver->state = DRIVER_RUNNING;
 
@@ -667,5 +667,5 @@
 void initialize_running_driver(driver_t *driver, dev_tree_t *tree)
 {
-	log_msg(LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
 	    driver->name);
 	
@@ -761,5 +761,5 @@
 	 * access any structures that would affect driver_t.
 	 */
-	log_msg(LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
 	    drv->name, dev->pfun->name);
 	
@@ -827,5 +827,5 @@
 	driver_t *drv = find_best_match_driver(drivers_list, dev);
 	if (drv == NULL) {
-		log_msg(LVL_ERROR, "No driver found for device `%s'.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "No driver found for device `%s'.",
 		    dev->pfun->pathname);
 		return false;
@@ -867,5 +867,5 @@
 	assert(dev != NULL);
 	
-	log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_remove(%p)", dev);
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
@@ -890,5 +890,5 @@
 	assert(dev != NULL);
 	
-	log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_gone(%p)", dev);
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
@@ -911,5 +911,5 @@
 	devman_handle_t handle;
 	
-	log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_online(%p)", fun);
 
 	fibril_rwlock_read_lock(&tree->rwlock);
@@ -939,5 +939,5 @@
 	devman_handle_t handle;
 	
-	log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_offline(%p)", fun);
 
 	fibril_rwlock_read_lock(&tree->rwlock);
@@ -970,5 +970,5 @@
 bool init_device_tree(dev_tree_t *tree, driver_list_t *drivers_list)
 {
-	log_msg(LVL_DEBUG, "init_device_tree()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "init_device_tree()");
 	
 	tree->current_handle = 0;
@@ -1261,5 +1261,5 @@
 	fun->pathname = (char *) malloc(pathsize);
 	if (fun->pathname == NULL) {
-		log_msg(LVL_ERROR, "Failed to allocate device path.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate device path.");
 		return false;
 	}
@@ -1289,5 +1289,5 @@
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
-	log_msg(LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
 	    dev, pfun, pfun->pathname);
 
@@ -1313,5 +1313,5 @@
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
-	log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
 	
 	/* Remove node from the handle-to-node map. */
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/devman/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -73,5 +73,5 @@
 	char *drv_name = NULL;
 
-	log_msg(LVL_DEBUG, "devman_driver_register");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register");
 	
 	/* Get driver name. */
@@ -82,5 +82,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "The `%s' driver is trying to register.",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.",
 	    drv_name);
 	
@@ -88,5 +88,5 @@
 	driver = find_driver(&drivers_list, drv_name);
 	if (driver == NULL) {
-		log_msg(LVL_ERROR, "No driver named `%s' was found.", drv_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name);
 		free(drv_name);
 		drv_name = NULL;
@@ -102,5 +102,5 @@
 	if (driver->sess) {
 		/* We already have a connection to the driver. */
-		log_msg(LVL_ERROR, "Driver '%s' already started.\n",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n",
 		    driver->name);
 		fibril_mutex_unlock(&driver->driver_mutex);
@@ -112,5 +112,5 @@
 	case DRIVER_NOT_STARTED:
 		/* Somebody started the driver manually. */
-		log_msg(LVL_NOTE, "Driver '%s' started manually.\n",
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n",
 		    driver->name);
 		driver->state = DRIVER_STARTING;
@@ -125,5 +125,5 @@
 	
 	/* Create connection to the driver. */
-	log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.",
 	    driver->name);
 	driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
@@ -136,5 +136,5 @@
 	async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
 	
-	log_msg(LVL_NOTE,
+	log_msg(LOG_DEFAULT, LVL_NOTE,
 	    "The `%s' driver was successfully registered as running.",
 	    driver->name);
@@ -147,5 +147,5 @@
 	fid_t fid = fibril_create(init_running_drv, driver);
 	if (fid == 0) {
-		log_msg(LVL_ERROR, "Failed to create initialization fibril " \
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create initialization fibril " \
 		    "for driver `%s'.", driver->name);
 		fibril_mutex_unlock(&driver->driver_mutex);
@@ -176,5 +176,5 @@
 	callid = async_get_call(&call);
 	if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
-		log_msg(LVL_ERROR, 
+		log_msg(LOG_DEFAULT, LVL_ERROR, 
 		    "Invalid protocol when trying to receive match id.");
 		async_answer_0(callid, EINVAL); 
@@ -184,5 +184,5 @@
 	
 	if (match_id == NULL) {
-		log_msg(LVL_ERROR, "Failed to allocate match id.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id.");
 		async_answer_0(callid, ENOMEM);
 		return ENOMEM;
@@ -198,5 +198,5 @@
 	if (rc != EOK) {
 		delete_match_id(match_id);
-		log_msg(LVL_ERROR, "Failed to receive match id string: %s.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.",
 		    str_error(rc));
 		return rc;
@@ -205,5 +205,5 @@
 	list_append(&match_id->link, &match_ids->ids);
 	
-	log_msg(LVL_DEBUG, "Received match id `%s', score %d.",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.",
 	    match_id->id, match_id->score);
 	return rc;
@@ -248,5 +248,5 @@
 	if (fun->state == FUN_ON_LINE) {
 		fibril_rwlock_write_unlock(&device_tree.rwlock);
-		log_msg(LVL_WARN, "Function %s is already on line.",
+		log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.",
 		    fun->pathname);
 		return EOK;
@@ -264,5 +264,5 @@
 	}
 	
-	log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
 	
 	if (fun->ftype == fun_inner) {
@@ -282,5 +282,5 @@
 		fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
 		if (assign_fibril == 0) {
-			log_msg(LVL_ERROR, "Failed to create fibril for "
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for "
 			    "assigning driver.");
 			/* XXX Cleanup */
@@ -305,5 +305,5 @@
 	if (fun->state == FUN_OFF_LINE) {
 		fibril_rwlock_write_unlock(&device_tree.rwlock);
-		log_msg(LVL_WARN, "Function %s is already off line.",
+		log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already off line.",
 		    fun->pathname);
 		return EOK;
@@ -311,5 +311,5 @@
 	
 	if (fun->ftype == fun_inner) {
-		log_msg(LVL_DEBUG, "Offlining inner function %s.",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.",
 		    fun->pathname);
 		
@@ -359,5 +359,5 @@
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&device_tree.rwlock);
-			log_msg(LVL_ERROR, "Failed unregistering tree service.");
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service.");
 			return EIO;
 		}
@@ -391,5 +391,5 @@
 	if (ftype != fun_inner && ftype != fun_exposed) {
 		/* Unknown function type */
-		log_msg(LVL_ERROR, 
+		log_msg(LOG_DEFAULT, LVL_ERROR, 
 		    "Unknown function type %d provided by driver.",
 		    (int) ftype);
@@ -507,8 +507,8 @@
 	if (rc == EOK) {
 		loc_service_add_to_cat(fun->service_id, cat_id);
-		log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.",
 		    fun->pathname, cat_name);
 	} else {
-		log_msg(LVL_ERROR, "Failed adding function `%s' to category "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category "
 		    "`%s'.", fun->pathname, cat_name);
 	}
@@ -529,5 +529,5 @@
 	int rc;
 	
-	log_msg(LVL_DEBUG, "devman_drv_fun_online()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()");
 	
 	fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
@@ -620,5 +620,5 @@
 	fibril_rwlock_write_lock(&tree->rwlock);
 	
-	log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
 	
 	/* Check function state */
@@ -653,5 +653,5 @@
 			/* Verify that driver succeeded and removed all functions */
 			if (gone_rc != EOK || !list_empty(&dev->functions)) {
-				log_msg(LVL_ERROR, "Driver did not remove "
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove "
 				    "functions for device that is gone. "
 				    "Device node is now defunct.");
@@ -692,5 +692,5 @@
 			rc = loc_service_unregister(fun->service_id);
 			if (rc != EOK) {
-				log_msg(LVL_ERROR, "Failed unregistering tree "
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree "
 				    "service.");
 				fibril_rwlock_write_unlock(&tree->rwlock);
@@ -712,5 +712,5 @@
 	fun_del_ref(fun);
 	
-	log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded.");
 	async_answer_0(callid, EOK);
 }
@@ -726,5 +726,5 @@
 	
 	initialize_running_driver(driver, &device_tree);
-	log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.",
 	    driver->name);
 	return 0;
@@ -742,5 +742,5 @@
 	client = async_get_client_data();
 	if (client == NULL) {
-		log_msg(LVL_ERROR, "Failed to allocate client data.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data.");
 		return;
 	}
@@ -1229,5 +1229,5 @@
 	 */
 	if (dev == NULL) {
-		log_msg(LVL_ERROR, "IPC forwarding failed - no device or "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
 		    "function with handle %" PRIun " was found.", handle);
 		async_answer_0(iid, ENOENT);
@@ -1236,5 +1236,5 @@
 
 	if (fun == NULL && !drv_to_parent) {
-		log_msg(LVL_ERROR, NAME ": devman_forward error - cannot "
+		log_msg(LOG_DEFAULT, LVL_ERROR, NAME ": devman_forward error - cannot "
 		    "connect to handle %" PRIun ", refers to a device.",
 		    handle);
@@ -1264,5 +1264,5 @@
 	
 	if (driver == NULL) {
-		log_msg(LVL_ERROR, "IPC forwarding refused - " \
+		log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - " \
 		    "the device %" PRIun " is not in usable state.", handle);
 		async_answer_0(iid, ENOENT);
@@ -1277,5 +1277,5 @@
 	
 	if (!driver->sess) {
-		log_msg(LVL_ERROR,
+		log_msg(LOG_DEFAULT, LVL_ERROR,
 		    "Could not forward to driver `%s'.", driver->name);
 		async_answer_0(iid, EINVAL);
@@ -1284,9 +1284,9 @@
 
 	if (fun != NULL) {
-		log_msg(LVL_DEBUG,
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
 		    "Forwarding request for `%s' function to driver `%s'.",
 		    fun->pathname, driver->name);
 	} else {
-		log_msg(LVL_DEBUG,
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
 		    "Forwarding request for `%s' device to driver `%s'.",
 		    dev->pfun->pathname, driver->name);
@@ -1320,5 +1320,5 @@
 	
 	if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
-		log_msg(LVL_WARN, "devman_connection_loc(): function "
+		log_msg(LOG_DEFAULT, LVL_WARN, "devman_connection_loc(): function "
 		    "not found.\n");
 		fibril_rwlock_read_unlock(&device_tree.rwlock);
@@ -1338,5 +1338,5 @@
 	async_exchange_end(exch);
 	
-	log_msg(LVL_DEBUG,
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
 	    "Forwarding loc service request for `%s' function to driver `%s'.",
 	    fun->pathname, driver->name);
@@ -1394,5 +1394,5 @@
 static bool devman_init(void)
 {
-	log_msg(LVL_DEBUG, "devman_init - looking for available drivers.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - looking for available drivers.");
 	
 	/* Initialize list of available drivers. */
@@ -1400,13 +1400,13 @@
 	if (lookup_available_drivers(&drivers_list,
 	    DRIVER_DEFAULT_STORE) == 0) {
-		log_msg(LVL_FATAL, "No drivers found.");
+		log_msg(LOG_DEFAULT, LVL_FATAL, "No drivers found.");
 		return false;
 	}
 	
-	log_msg(LVL_DEBUG, "devman_init - list of drivers has been initialized.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - list of drivers has been initialized.");
 	
 	/* Create root device node. */
 	if (!init_device_tree(&device_tree, &drivers_list)) {
-		log_msg(LVL_FATAL, "Failed to initialize device tree.");
+		log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to initialize device tree.");
 		return false;
 	}
@@ -1428,5 +1428,5 @@
 	printf("%s: HelenOS Device Manager\n", NAME);
 	
-	int rc = log_init(NAME, LVL_WARN);
+	int rc = log_init(NAME);
 	if (rc != EOK) {
 		printf("%s: Error initializing logging subsystem.\n", NAME);
@@ -1440,5 +1440,5 @@
 	
 	if (!devman_init()) {
-		log_msg(LVL_ERROR, "Error while initializing service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error while initializing service.");
 		return -1;
 	}
@@ -1447,5 +1447,5 @@
 	rc = service_register(SERVICE_DEVMAN);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering as a service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering as a service.");
 		return rc;
 	}
Index: uspace/srv/fs/udf/Makefile
===================================================================
--- uspace/srv/fs/udf/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2012 Julia Medvedeva
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX)
+BINARY = udf
+
+SOURCES = \
+	udf.c \
+	udf_volume.c \
+	udf_ops.c \
+	udf_osta.c \
+	udf_cksum.c \
+	udf_file.c \
+	udf_idx.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/udf/udf.c
===================================================================
--- uspace/srv/fs/udf/udf.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf.c
+ * @brief UDF 1.02 file system driver for HelenOS.
+ */
+
+#include <ipc/services.h>
+#include <ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <task.h>
+#include <libfs.h>
+#include <str.h>
+#include <io/log.h>
+#include "../../vfs/vfs.h"
+#include "udf.h"
+#include "udf_idx.h"
+
+#define NAME  "udf"
+
+vfs_info_t udf_vfs_info = {
+	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,
+	.instance = 0,
+};
+
+int main(int argc, char *argv[])
+{
+	log_init(NAME);
+	log_msg(LOG_DEFAULT, LVL_NOTE, "HelenOS UDF 1.02 file system server");
+	
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			udf_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			log_msg(LOG_DEFAULT, LVL_FATAL, "Unrecognized parameters");
+			return 1;
+		}
+	}
+	
+	async_sess_t *vfs_sess =
+	    service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
+		log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to connect to VFS");
+		return 2;
+	}
+	
+	int rc = fs_register(vfs_sess, &udf_vfs_info, &udf_ops,
+	    &udf_libfs_ops);
+	if (rc != EOK)
+		goto err;
+	
+	rc = udf_idx_init();
+	if (rc != EOK)
+		goto err;
+	
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Accepting connections");
+	task_retval(0);
+	async_manager();
+	
+	/* Not reached */
+	return 0;
+	
+err:
+	log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to register file system (%d)", rc);
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf.h
===================================================================
--- uspace/srv/fs/udf/udf.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_UDF_H_
+#define UDF_UDF_H_
+
+#include <fibril_synch.h>
+#include <libfs.h>
+#include <atomic.h>
+#include <sys/types.h>
+#include <bool.h>
+#include "../../vfs/vfs.h"
+#include "udf_types.h"
+
+#define UDF_NODE(node) \
+	((node) ? (udf_node_t *) (node)->data : NULL)
+
+#define FS_NODE(node) \
+	((node) ? (fs_node_t *) ((node)->fs_node) : NULL)
+
+#define BS_BLOCK     0
+#define MIN_SIZE     512
+#define MAX_SIZE     8192
+#define DEFAULT_VOL  0
+
+#define NODE_DIR   0
+#define NODE_FILE  1
+
+#define MAX_FILE_NAME_LEN  512
+
+#define MIN_FID_LEN  38
+
+#define SPACE_TABLE   0
+#define SPACE_BITMAP  1
+
+typedef struct udf_partition {
+	/* Partition info */
+	uint16_t number;
+	uint32_t access_type;
+	uint32_t start;
+	uint32_t lenght;
+} udf_partition_t;
+
+typedef struct udf_lvolume {
+	udf_partition_t **partitions;
+	size_t partition_cnt;
+	uint32_t logical_block_size;
+	fs_index_t root_dir;
+} udf_lvolume_t;
+
+typedef struct {
+	service_id_t service_id;
+	size_t open_nodes_count;
+	udf_charspec_t charset;
+	
+	uint32_t sector_size;
+	udf_lvolume_t *volumes;
+	udf_partition_t *partitions;
+	size_t partition_cnt;
+	udf_unallocated_space_descriptor_t *uasd;
+	uint64_t uaspace_start;
+	uint64_t uaspace_lenght;
+	uint8_t space_type;
+} udf_instance_t;
+
+typedef struct udf_allocator {
+	uint32_t length;
+	uint32_t position;
+} udf_allocator_t;
+
+typedef struct udf_node {
+	udf_instance_t *instance;
+	fs_node_t *fs_node;
+	fibril_mutex_t lock;
+	
+	fs_index_t index;  /* FID logical block */
+	link_t link;
+	size_t ref_cnt;
+	size_t link_cnt;
+	
+	uint8_t type;  /* 1 - file, 0 - directory */
+	uint64_t data_size;
+	uint8_t *data;
+	udf_allocator_t *allocators;
+	size_t alloc_size;
+} udf_node_t;
+
+extern vfs_out_ops_t udf_ops;
+extern libfs_ops_t udf_libfs_ops;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_cksum.c
===================================================================
--- uspace/srv/fs/udf/udf_cksum.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_cksum.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_cksum.c
+ * @brief Implementation of various checksum functions.
+ */
+
+#include "udf_cksum.h"
+
+/** CRC 010041 */
+static uint16_t crc_table[256] = {
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+/** Unicode checksum
+ *
+ */
+uint16_t udf_unicode_cksum(uint16_t *buf, size_t len)
+{
+	uint16_t crc = 0;
+	
+	while (len-- > 0) {
+		/*
+		 * Take high order byte first (corresponds to a big endian
+		 * byte stream).
+		 */
+		crc = crc_table[(crc >> 8 ^ (*buf >> 8)) & 0xff] ^ (crc << 8);
+		crc = crc_table[(crc >> 8 ^ (*buf++ & 0xff)) & 0xff] ^ (crc << 8);
+	}
+	
+	return crc;
+}
+
+/** Calculate descriptor tag checksum
+ *
+ */
+uint8_t udf_tag_checksum(uint8_t *tag)
+{
+	uint8_t result = 0;
+	
+	for (size_t i = 0; i < UDF_TAG_SIZE; i++) {
+		if (i == 4)
+			continue;
+		
+		result = (result + tag[i]) % 256;
+	}
+	
+	return result;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_cksum.h
===================================================================
--- uspace/srv/fs/udf/udf_cksum.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_cksum.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_CKSUM_H_
+#define UDF_CKSUM_H_
+
+#include <sys/types.h>
+#include <bool.h>
+
+#define UDF_TAG_SIZE  16
+
+extern uint16_t udf_unicode_cksum(uint16_t *, size_t);
+extern uint8_t udf_tag_checksum(uint8_t *);
+
+#endif /* UDF_CKSUM_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_file.c
===================================================================
--- uspace/srv/fs/udf/udf_file.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_file.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_file.c
+ * @brief Implementation of file operations. Reading and writing functions.
+ */
+
+#include <block.h>
+#include <libfs.h>
+#include <errno.h>
+#include <malloc.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include <mem.h>
+#include "udf.h"
+#include "udf_file.h"
+#include "udf_cksum.h"
+#include "udf_volume.h"
+
+/** Read extended allocator in allocation sequence
+ *
+ * @paran node     UDF node
+ * @param icb_flag Type of allocators in sequence.
+ *                 According to ECMA 167 4/14.8.8
+ * @param pos      Position with which we read
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_read_extended_allocator(udf_node_t *node, uint16_t icb_flag,
+    uint32_t pos)
+{
+	block_t *block = NULL;
+	int rc = block_get(&block, node->instance->service_id, pos,
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+	
+	udf_ext_ad_t *exd = (udf_ext_ad_t *) block->data;
+	uint32_t start = node->instance->partitions[
+	    FLE16(exd->extent_location.partition_num)].start +
+	    FLE32(exd->extent_location.lblock_num);
+	
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Extended allocator: start=%d, block_num=%d, len=%d", start,
+	    FLE32(exd->extent_location.lblock_num), FLE32(exd->info_length));
+	
+	uint32_t len = FLE32(exd->info_length);
+	block_put(block);
+	
+	return udf_read_allocation_sequence(node, NULL, icb_flag, start, len);
+}
+
+/** Read ICB sequence of allocators in (Extended) File entry descriptor
+ *
+ * @parem node     UDF node
+ * @param af       (Extended) File entry descriptor
+ * @param icb_flag Type of allocators in sequence.
+ *                 According to ECMA 167 4/14.8.8
+ * @param start_alloc Offset of the allocator
+ * @param len         Length of sequence
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_allocation_sequence(udf_node_t *node, uint8_t *af,
+    uint16_t icb_flag, uint32_t start_alloc, uint32_t len)
+{
+	node->alloc_size = 0;
+	
+	switch (icb_flag) {
+	case UDF_SHORT_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = short_ad_t");
+		
+		/*
+		 * Identify number of current partition. Virtual partition
+		 * could placed inside of physical partition. It means that same
+		 * sector could be inside of both partition physical and virtual.
+		 */
+		size_t pd_num = (size_t) -1;
+		size_t min_start = 0;
+		
+		for (size_t i = 0; i < node->instance->partition_cnt; i++) {
+			if ((node->index >= node->instance->partitions[i].start) &&
+			    (node->index < node->instance->partitions[i].start +
+			    node->instance->partitions[i].lenght)) {
+				if (node->instance->partitions[i].start >= min_start) {
+					min_start = node->instance->partitions[i].start;
+					pd_num = i;
+				}
+			}
+		}
+		
+		if (pd_num == (size_t) -1)
+			return ENOENT;
+		
+		/*
+		 * According to doc, in this we should stop our loop if pass
+		 * all allocators. Count of items in sequence of allocators
+		 * cnt = len / sizeof(udf_long_ad_t)
+		 * But in case of Blu-Ray data len could be zero.
+		 * It means that we have only two conditions for stopping
+		 * which we check inside of loop.
+		 */
+		
+		while (true) {
+			udf_short_ad_t *short_d =
+			    (udf_short_ad_t *) (af + start_alloc +
+			    node->alloc_size * sizeof(udf_short_ad_t));
+			
+			if (FLE32(short_d->length) == 0)
+				break;
+			
+			/*
+			 * ECMA 167 4/12 - next sequence of allocation descriptors
+			 * condition according to 167 4/14.6.8
+			 */
+			if (FLE32(short_d->length) >> 30 == 3) {
+				udf_read_extended_allocator(node, icb_flag,
+				    node->instance->partitions[pd_num].start +
+				    FLE32(short_d->position));
+				break;
+			}
+			
+			node->allocators = realloc(node->allocators,
+			    (node->alloc_size + 1) * sizeof(udf_allocator_t));
+			node->allocators[node->alloc_size].length =
+			    EXT_LENGTH(FLE32(short_d->length));
+			node->allocators[node->alloc_size].position =
+			    node->instance->partitions[pd_num].start + FLE32(short_d->position);
+			node->alloc_size++;
+		}
+		
+		node->allocators = realloc(node->allocators,
+		    node->alloc_size * sizeof(udf_allocator_t));
+		break;
+		
+	case UDF_LONG_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = long_ad_t");
+		
+		while (true) {
+			udf_long_ad_t *long_d =
+			    (udf_long_ad_t *) (af + start_alloc +
+			    node->alloc_size * sizeof(udf_long_ad_t));
+			
+			if (FLE32(long_d->length) == 0)
+				break;
+			
+			uint32_t pos_long_ad = udf_long_ad_to_pos(node->instance, long_d);
+			
+			/*
+			 * ECMA 167 4/12 - next sequence of allocation descriptors
+			 * condition according to 167 4/14.6.8
+			 */
+			if (FLE32(long_d->length) >> 30 == 3) {
+				udf_read_extended_allocator(node, icb_flag, pos_long_ad);
+				break;
+			}
+			
+			node->allocators = realloc(node->allocators,
+			    (node->alloc_size + 1) * sizeof(udf_allocator_t));
+			node->allocators[node->alloc_size].length =
+			    EXT_LENGTH(FLE32(long_d->length));
+			node->allocators[node->alloc_size].position = pos_long_ad;
+			
+			node->alloc_size++;
+		}
+		
+		node->allocators = realloc(node->allocators,
+		    node->alloc_size * sizeof(udf_allocator_t));
+		break;
+		
+	case UDF_EXTENDED_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = extended_ad_t");
+		break;
+		
+	case UDF_DATA_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = 3, node contains data itself");
+		
+		node->data = malloc(node->data_size);
+		if (!node->data)
+			return ENOMEM;
+		
+		memcpy(node->data, (af + start_alloc), node->data_size);
+		node->alloc_size = 0;
+		break;
+	}
+	
+	return EOK;
+}
+
+/** Read ICB sequence of descriptors
+ *
+ * Read sequence of descriptors (file entry descriptors or
+ * extended file entry descriptors). Each descriptor contains
+ * sequence of allocators.
+ *
+ * @param node    UDF node
+ *
+ * @return    EOK on success or a negative error code.
+ */
+int udf_read_icb(udf_node_t *node)
+{
+	while (true) {
+		fs_index_t pos = node->index;
+		
+		block_t *block = NULL;
+		int rc = block_get(&block, node->instance->service_id, pos,
+		    BLOCK_FLAGS_NONE);
+		if (rc != EOK)
+			return rc;
+		
+		udf_descriptor_tag_t *data = (udf_descriptor_tag_t *) block->data;
+		if (data->checksum != udf_tag_checksum((uint8_t *) data)) {
+			block_put(block);
+			return EINVAL;
+		}
+		
+		/* One sector size descriptors */
+		switch (FLE16(data->id)) {
+		case UDF_FILE_ENTRY:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
+			
+			udf_file_entry_descriptor_t *file =
+			    (udf_file_entry_descriptor_t *) block->data;
+			uint16_t icb_flag = FLE16(file->icbtag.flags) & UDF_ICBFLAG_MASK;
+			node->data_size = FLE64(file->info_lenght);
+			node->type = (file->icbtag.file_type == UDF_ICBTYPE_DIR) ? NODE_DIR : NODE_FILE;
+			
+			rc = udf_read_allocation_sequence(node, (uint8_t *) file, icb_flag,
+			    FLE32(file->ea_lenght) + UDF_FE_OFFSET, FLE32(file->ad_lenght));
+			block_put(block);
+			return rc;
+			
+		case UDF_EFILE_ENTRY:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
+			
+			udf_extended_file_entry_descriptor_t *efile =
+			    (udf_extended_file_entry_descriptor_t *) block->data;
+			icb_flag = FLE16(efile->icbtag.flags) & UDF_ICBFLAG_MASK;
+			node->data_size = FLE64(efile->info_lenght);
+			node->type = (efile->icbtag.file_type == UDF_ICBTYPE_DIR) ? NODE_DIR : NODE_FILE;
+			
+			rc = udf_read_allocation_sequence(node, (uint8_t *) efile, icb_flag,
+			    FLE32(efile->ea_lenght) + UDF_EFE_OFFSET, FLE32(efile->ad_lenght));
+			block_put(block);
+			return rc;
+			
+		case UDF_ICB_TERMINAL:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Terminal entry descriptor found");
+			block_put(block);
+			return EOK;
+		}
+		
+		pos++;
+		
+		rc = block_put(block);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	return EOK;
+}
+
+/** Read data from disk - filling UDF node by allocators
+ *
+ * @param node UDF node
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_node_get_core(udf_node_t *node)
+{
+	node->link_cnt = 1;
+	return udf_read_icb(node);
+}
+
+/** Read directory entry if all FIDs is saved inside of descriptor
+ *
+ * @param fid  Returned value
+ * @param node UDF node
+ * @param pos  Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_get_fid_in_data(udf_file_identifier_descriptor_t **fid,
+    udf_node_t *node, aoff64_t pos)
+{
+	size_t fid_sum = 0;
+	size_t n = 0;
+	
+	while (node->data_size - fid_sum >= MIN_FID_LEN) {
+		udf_descriptor_tag_t *desc =
+		    (udf_descriptor_tag_t *) (node->data + fid_sum);
+		if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+			if (fid_sum == 0)
+				return EINVAL;
+			else
+				return ENOENT;
+		}
+		
+		*fid = (udf_file_identifier_descriptor_t *)
+		    (node->data + fid_sum);
+		
+		/* According to ECMA 167 4/14.4.9 */
+		size_t padding = 4 * (((*fid)->lenght_file_id +
+		    FLE16((*fid)->lenght_iu) + 38 + 3) / 4) -
+		    ((*fid)->lenght_file_id + FLE16((*fid)->lenght_iu) + 38);
+		size_t size_fid = (*fid)->lenght_file_id +
+		    FLE16((*fid)->lenght_iu) + padding + 38;
+		
+		fid_sum += size_fid;
+		
+		/* aAcording to ECMA 167 4/8.6 */
+		if (((*fid)->lenght_file_id != 0) &&
+		    (((*fid)->file_characteristics & 4) == 0)) {
+			n++;
+			
+			if (n == pos + 1)
+				return EOK;
+		}
+	}
+	
+	return ENOENT;
+}
+
+/** Read directory entry
+ *
+ * @param fid   Returned value
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid(udf_file_identifier_descriptor_t **fid, block_t **block,
+    udf_node_t *node, aoff64_t pos)
+{
+	if (node->data == NULL)
+		return udf_get_fid_in_allocator(fid, block, node, pos);
+	
+	return udf_get_fid_in_data(fid, node, pos);
+}
+
+/** Read directory entry if all FIDS is saved in allocators.
+ *
+ * @param fid   Returned value
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid_in_allocator(udf_file_identifier_descriptor_t **fid,
+    block_t **block, udf_node_t *node, aoff64_t pos)
+{
+	void *buf = malloc(node->instance->sector_size);
+	
+	// FIXME: Check for NULL return value
+	
+	size_t j = 0;
+	size_t n = 0;
+	size_t len = 0;
+	
+	while (j < node->alloc_size) {
+		size_t i = 0;
+		while (i * node->instance->sector_size < node->allocators[j].length) {
+			int rc = block_get(block, node->instance->service_id,
+			    node->allocators[j].position + i, BLOCK_FLAGS_NONE);
+			if (rc != EOK) {
+				// FIXME: Memory leak
+				return rc;
+			}
+			
+			/*
+			 * Last item in allocator is a part of sector. We take
+			 * this fragment and join it to part of sector in next allocator.
+			 */
+			if ((node->allocators[j].length / node->instance->sector_size == i) &&
+			    (node->allocators[j].length - i * node->instance->sector_size <
+			    MIN_FID_LEN)) {
+				size_t len = node->allocators[j].length - i * node->instance->sector_size;
+				memcpy(buf, (*block)->data, len);
+				block_put(*block);
+				*block = NULL;
+				break;
+			}
+			
+			rc = udf_get_fid_in_sector(fid, block, node, pos, &n, &buf, &len);
+			if (rc == EOK) {
+				// FIXME: Memory leak
+				return EOK;
+			}
+			
+			if (rc == EINVAL) {
+				// FIXME: Memory leak
+				return ENOENT;
+			}
+			
+			if (rc == ENOENT) {
+				if (block) {
+					rc = block_put(*block);
+					*block = NULL;
+					
+					if (rc != EOK)
+						return rc;
+				}
+			}
+			
+			i++;
+		}
+		
+		j++;
+	}
+	
+	if (buf)
+		free(buf);
+	
+	return ENOENT;
+}
+
+/** Read FIDs in sector inside of current allocator
+ *
+ * @param fid   Returned value.
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number FID which we need to find
+ * @param n     Count of FIDs which we already have passed
+ * @param buf   Part of FID from last sector (current allocator or previous)
+ * @param len   Length of buf
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid_in_sector(udf_file_identifier_descriptor_t **fid,
+    block_t **block, udf_node_t *node, aoff64_t pos, size_t *n, void **buf,
+    size_t *len)
+{
+	void *fidbuf = malloc(node->instance->sector_size);
+	
+	// FIXME: Check for NULL return value
+	
+	bool buf_flag;
+	
+	if (*len > 0) {
+		memcpy(fidbuf, *buf, *len);
+		buf_flag = true;
+	} else
+		buf_flag = false;
+	
+	size_t fid_sum = 0;
+	while (node->instance->sector_size - fid_sum > 0) {
+		if (node->instance->sector_size - fid_sum >= MIN_FID_LEN) {
+			void *fid_data;
+			
+			if (buf_flag) {
+				memcpy((fidbuf + *len), (*block)->data,
+				    node->instance->sector_size - *len);
+				fid_data = fidbuf;
+			} else
+				fid_data = (*block)->data + fid_sum;
+			
+			udf_descriptor_tag_t *desc =
+			    (udf_descriptor_tag_t *) fid_data;
+			
+			if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+				if (fidbuf)
+					free(fidbuf);
+				
+				if (*buf) {
+					free(*buf);
+					*buf = NULL;
+					*len = 0;
+				}
+				
+				return EINVAL;
+			}
+			
+			*fid = (udf_file_identifier_descriptor_t *) fid_data;
+			
+			/* According to ECMA 167 4/14.4.9 */
+			size_t padding = 4 * (((*fid)->lenght_file_id +
+			    FLE16((*fid)->lenght_iu) + 38 + 3) / 4) -
+			    ((*fid)->lenght_file_id + FLE16((*fid)->lenght_iu) + 38);
+			size_t size_fid = (*fid)->lenght_file_id +
+			    FLE16((*fid)->lenght_iu) + padding + 38;
+			if (buf_flag)
+				fid_sum += size_fid - *len;
+			else
+				fid_sum += size_fid;
+			
+			/* According to ECMA 167 4/8.6 */
+			if (((*fid)->lenght_file_id != 0) &&
+			    (((*fid)->file_characteristics & 4) == 0)) {
+				(*n)++;
+				if (*n == pos + 1) {
+					if (fidbuf)
+						free(fidbuf);
+					
+					return EOK;
+				}
+			}
+			
+			if (fidbuf) {
+				buf_flag = false;
+				free(fidbuf);
+				fidbuf = NULL;
+			}
+			
+			if (*buf) {
+				free(*buf);
+				*buf = NULL;
+				*len = 0;
+			}
+		} else {
+			if (*buf)
+				free(*buf);
+			
+			*len = node->instance->sector_size - fid_sum;
+			*buf = malloc(*len);
+			buf_flag = false;
+			memcpy(*buf, ((*block)->data + fid_sum), *len);
+			
+			return ENOENT;
+		}
+	}
+	
+	return ENOENT;
+}
+
+/** Read file if it is saved in allocators.
+ *
+ * @param read_len Returned value. Length file or part file which we could read.
+ * @param callid
+ * @param node     UDF node
+ * @param pos      Position in file since we have to read.
+ * @param len      Length of data for reading
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_file(size_t *read_len, ipc_callid_t callid, udf_node_t *node,
+    aoff64_t pos, size_t len)
+{
+	size_t i = 0;
+	size_t l = 0;
+	
+	while (i < node->alloc_size) {
+		if (pos >= l + node->allocators[i].length) {
+			l += node->allocators[i].length;
+			i++;
+		} else
+			break;
+	}
+	
+	size_t sector_cnt = ALL_UP(l, node->instance->sector_size);
+	size_t sector_num = pos / node->instance->sector_size;
+	
+	block_t *block = NULL;
+	int rc = block_get(&block, node->instance->service_id,
+	    node->allocators[i].position + (sector_num - sector_cnt),
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return rc;
+	}
+	
+	size_t sector_pos = pos % node->instance->sector_size;
+	
+	if (sector_pos + len < node->instance->sector_size)
+		*read_len = len;
+	else
+		*read_len = node->instance->sector_size - sector_pos;
+	
+	if (ALL_UP(node->allocators[i].length, node->instance->sector_size) ==
+	    sector_num - sector_cnt + 1) {
+		if (pos + len > node->allocators[i].length + l)
+			*read_len = node->allocators[i].length -
+			    (sector_num - sector_cnt) * node->instance->sector_size -
+			    sector_pos;
+		else
+			*read_len = len;
+	}
+	
+	async_data_read_finalize(callid, block->data + sector_pos, *read_len);
+	return block_put(block);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_file.h
===================================================================
--- uspace/srv/fs/udf/udf_file.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_file.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_FILE_H_
+#define UDF_FILE_H_
+
+#include <sys/types.h>
+#include <ipc/loc.h>
+#include <block.h>
+#include "udf_types.h"
+
+#define UDF_TAG_FILESET  256
+#define UDF_TAG_FILEID   257
+
+#define UDF_ICB_TERMINAL   260
+#define UDF_FILE_ENTRY     261
+#define UDF_UASPACE_ENTRY  263
+#define UDF_SPACE_BITMAP   264
+#define UDF_EFILE_ENTRY    266
+
+#define UDF_FE_OFFSET   176
+#define UDF_EFE_OFFSET  216
+#define UDF_SB_OFFSET   24
+
+/* ECMA 4/14.11 */
+#define UDF_UASE_OFFSET  40
+
+/* ECMA 167 4/14.6.8 */
+#define UDF_ICBFLAG_MASK  7
+
+/* ECMA 167 4/17 */
+#define UDF_ICBTYPE_UASE  1
+#define UDF_ICBTYPE_DIR   4
+
+/* ECMA 167 4/14.6.8 */
+#define UDF_SHORT_AD     0
+#define UDF_LONG_AD      1
+#define UDF_EXTENDED_AD  2
+
+/* File in allocation descriptor */
+#define UDF_DATA_AD  3
+
+/* File Set Descriptor (ECMA 167 4/14.1) */
+typedef struct udf_fileset_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_timestamp_t recording_date_and_time;
+	uint16_t interchange_level;
+	uint16_t max_interchange_level;
+	uint32_t charset_list;
+	uint32_t max_charset_list;
+	uint32_t fileset_number;
+	uint32_t fileset_descriptor_number;
+	udf_charspec_t logical_volume_id_charset;
+	udf_dstring logical_volume_id[128];
+	udf_charspec_t fileset_charset;
+	udf_dstring fileset_id[32];
+	udf_dstring copyright_file_id[32];
+	udf_dstring abstract_file_id[32];
+	udf_long_ad_t root_dir_icb;
+	udf_regid_t domain_id;
+	udf_long_ad_t next_extent;
+	udf_long_ad_t system_stream_dir_icb;
+	uint8_t reserved[32];
+} __attribute__((packed)) udf_fileset_descriptor_t;
+
+/* File identifier descriptor format (ECMA 167 4/14.4) */
+typedef struct udf_file_identifier_descriptor {
+	udf_descriptor_tag_t tag;
+	uint16_t file_version_number;
+	uint8_t file_characteristics;
+	uint8_t lenght_file_id;
+	udf_long_ad_t icb;
+	uint16_t lenght_iu;
+	uint8_t implementation_use[0];
+	udf_dstring file_id[0];
+}__attribute__((packed)) udf_file_identifier_descriptor_t;
+
+/* ICB tag - Information Control Block  (ECMA 167 4/14.6) */
+typedef struct udf_icbtag {
+	uint32_t prior_recorder_nimber;
+	uint16_t strategy_type;
+	uint8_t strategy_parameter[2];
+	uint16_t max_number;
+	uint8_t reserved[1];
+	uint8_t file_type;
+	udf_lb_addr_t parent_icb;
+	uint16_t flags;
+} __attribute__((packed)) udf_icbtag_t;
+
+/* File Entry format (ECMA 167 4/14.9) */
+typedef struct udf_file_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t uid;
+	uint32_t gid;
+	uint32_t permission;
+	uint16_t file_link_count;
+	uint8_t record_format;
+	uint8_t record_display_attributes;
+	uint32_t record_lenght;
+	uint64_t info_lenght;
+	uint64_t lblocks_recorded;
+	udf_timestamp_t access_data_and_time;
+	udf_timestamp_t mod_data_and_time;
+	udf_timestamp_t attribute_data_and_time;
+	uint32_t checkpoint;
+	udf_long_ad_t extended_attribute_icb;
+	udf_regid_t implementation_id;
+	uint64_t unique_id;
+	uint32_t ea_lenght;
+	uint32_t ad_lenght;
+	uint8_t extended_attributes [0];
+	uint8_t allocation_descriptors[0];
+} __attribute__((packed)) udf_file_entry_descriptor_t;
+
+/* Extended File Entry format (ECMA 167 4/14.17) */
+typedef struct udf_extended_file_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t uid;
+	uint32_t gid;
+	uint32_t permission;
+	uint16_t file_link_count;
+	uint8_t record_format;
+	uint8_t record_display_attributes;
+	uint32_t record_lenght;
+	uint64_t info_lenght;
+	uint64_t object_size;
+	uint64_t lblocks_recorded;
+	udf_timestamp_t access_data_and_time;
+	udf_timestamp_t mod_data_and_time;
+	udf_timestamp_t creation_data_and_time;
+	udf_timestamp_t attribute_data_and_time;
+	uint32_t checkpoint;
+	udf_long_ad_t extended_attribute_icb;
+	udf_regid_t implementation_id;
+	uint64_t unique_id;
+	uint32_t ea_lenght;
+	uint32_t ad_lenght;
+	uint8_t extended_attributes [0];
+	uint8_t allocation_descriptors[0];
+} __attribute__((packed)) udf_extended_file_entry_descriptor_t;
+
+/* Terminal Entry Descriptor (ECMA 167 4/14.8) */
+typedef struct terminal_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+} __attribute__((packed)) udf_terminal_entry_descriptor;
+
+/* Unallocated Space Entry format (ECMA 167 4/14.11)*/
+typedef struct udf_unallocated_space_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t ad_lenght;
+	uint8_t allocation_descriptors[0];
+}__attribute__((packed)) udf_unallocated_space_entry_descriptor_t;
+
+/* Space Bitmap Descriptor format (ECMA 167 4/14.12) */
+typedef struct udf_space_bitmap_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t bits_number;
+	uint32_t byts_number;
+	uint8_t bitmap[0];
+}__attribute__((packed)) udf_space_bitmap_descriptor_t;
+
+extern int udf_node_get_core(udf_node_t *);
+extern int udf_read_icb(udf_node_t *);
+extern int udf_read_allocation_sequence(udf_node_t *, uint8_t *, uint16_t,
+    uint32_t, uint32_t);
+extern int udf_read_file(size_t *, ipc_callid_t, udf_node_t *, aoff64_t,
+    size_t);
+extern int udf_get_fid(udf_file_identifier_descriptor_t **, block_t **,
+    udf_node_t *, aoff64_t);
+extern int udf_get_fid_in_allocator(udf_file_identifier_descriptor_t **,
+    block_t **, udf_node_t *, aoff64_t);
+extern int udf_get_fid_in_sector(udf_file_identifier_descriptor_t **,
+    block_t **, udf_node_t *, aoff64_t, size_t *, void **, size_t *);
+
+#endif /* UDF_FILE_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_idx.c
===================================================================
--- uspace/srv/fs/udf/udf_idx.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_idx.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_idx.c
+ * @brief Very simple UDF hashtable for nodes
+ */
+
+#include "../../vfs/vfs.h"
+#include <errno.h>
+#include <str.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <malloc.h>
+#include <adt/hash_table.h>
+#include <adt/list.h>
+#include "udf_idx.h"
+#include "udf.h"
+
+#define UDF_IDX_KEYS  2
+#define UDF_IDX_KEY   1
+
+#define UDF_IDX_SERVICE_ID_KEY  0
+#define UDF_IDX_BUCKETS         1024
+
+static FIBRIL_MUTEX_INITIALIZE(udf_idx_lock);
+
+static hash_table_t udf_idx;
+
+/** Calculate value of hash by key
+ *
+ * @param Key for calculation of function
+ *
+ * @return Value of hash function
+ *
+ */
+static hash_index_t udf_idx_hash(unsigned long key[])
+{
+	/* TODO: This is very simple and probably can be improved */
+	return key[UDF_IDX_KEY] % UDF_IDX_BUCKETS;
+}
+
+/** Compare two items of hash table
+ *
+ * @param key  Key of hash table item. Include several items.
+ * @param keys Number of parts of key.
+ * @param item Item of hash table
+ *
+ * @return True if input value of key equivalent key of node from hash table
+ *
+ */
+static int udf_idx_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	assert(keys > 0);
+	
+	udf_node_t *node = hash_table_get_instance(item, udf_node_t, link);
+	
+	if (node->instance->service_id !=
+	    ((service_id_t) key[UDF_IDX_SERVICE_ID_KEY]))
+		return false;
+	
+	assert(keys == 2);
+	return (node->index == key[UDF_IDX_KEY]);
+}
+
+/** Remove callback
+ *
+ */
+static void udf_idx_remove_cb(link_t *link)
+{
+	/* We don't use remove callback for this hash table */
+}
+
+static hash_table_operations_t udf_idx_ops = {
+	.hash = udf_idx_hash,
+	.compare = udf_idx_compare,
+	.remove_callback = udf_idx_remove_cb,
+};
+
+/** Initialization of hash table
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_init(void)
+{
+	if (!hash_table_create(&udf_idx, UDF_IDX_BUCKETS, UDF_IDX_KEYS,
+	    &udf_idx_ops))
+		return ENOMEM;
+	
+	return EOK;
+}
+
+/** Delete hash table
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_fini(void)
+{
+	hash_table_destroy(&udf_idx);
+	return EOK;
+}
+
+/** Get node from hash table
+ *
+ * @param udfn     Returned value - UDF node
+ * @param instance UDF instance
+ * @param index    Absolute position of ICB (sector)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_get(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
+{
+	fibril_mutex_lock(&udf_idx_lock);
+	
+	unsigned long key[] = {
+		[UDF_IDX_SERVICE_ID_KEY] = instance->service_id,
+		[UDF_IDX_KEY] = index
+	};
+	
+	link_t *already_open = hash_table_find(&udf_idx, key);
+	if (already_open) {
+		udf_node_t *node = hash_table_get_instance(already_open,
+		    udf_node_t, link);
+		node->ref_cnt++;
+		
+		*udfn = node;
+		
+		fibril_mutex_unlock(&udf_idx_lock);
+		return EOK;
+	}
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return ENOENT;
+}
+
+/** Create new node in hash table
+ *
+ * @param udfn     Returned value - new UDF node
+ * @param instance UDF instance
+ * @param index    Absolute position of ICB (sector)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_add(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
+{
+	fibril_mutex_lock(&udf_idx_lock);
+	
+	udf_node_t *udf_node = malloc(sizeof(udf_node_t));
+	if (udf_node == NULL) {
+		fibril_mutex_unlock(&udf_idx_lock);
+		return ENOMEM;
+	}
+	
+	fs_node_t *fs_node = malloc(sizeof(fs_node_t));
+	if (fs_node == NULL) {
+		free(udf_node);
+		fibril_mutex_unlock(&udf_idx_lock);
+		return ENOMEM;
+	}
+	
+	fs_node_initialize(fs_node);
+	
+	udf_node->index = index;
+	udf_node->instance = instance;
+	udf_node->ref_cnt = 1;
+	udf_node->link_cnt = 0;
+	udf_node->fs_node = fs_node;
+	udf_node->data = NULL;
+	udf_node->allocators = NULL;
+	
+	fibril_mutex_initialize(&udf_node->lock);
+	link_initialize(&udf_node->link);
+	fs_node->data = udf_node;
+	
+	unsigned long key[] = {
+		[UDF_IDX_SERVICE_ID_KEY] = instance->service_id,
+		[UDF_IDX_KEY] = index
+	};
+	
+	hash_table_insert(&udf_idx, key, &udf_node->link);
+	instance->open_nodes_count++;
+	
+	*udfn = udf_node;
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return EOK;
+}
+
+/** Delete node from hash table
+ *
+ * @param node UDF node
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_del(udf_node_t *node)
+{
+	assert(node->ref_cnt == 0);
+	
+	fibril_mutex_lock(&udf_idx_lock);
+	
+	unsigned long key[] = {
+		[UDF_IDX_SERVICE_ID_KEY] = node->instance->service_id,
+		[UDF_IDX_KEY] = node->index
+	};
+	
+	hash_table_remove(&udf_idx, key, UDF_IDX_KEYS);
+	
+	assert(node->instance->open_nodes_count > 0);
+	node->instance->open_nodes_count--;
+	
+	free(node->fs_node);
+	free(node);
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_idx.h
===================================================================
--- uspace/srv/fs/udf/udf_idx.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_idx.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_IDX_H_
+#define UDF_IDX_H_
+
+#include "udf.h"
+
+extern int udf_idx_init(void);
+extern int udf_idx_fini(void);
+extern int udf_idx_get(udf_node_t **, udf_instance_t *, fs_index_t);
+extern int udf_idx_add(udf_node_t **, udf_instance_t *, fs_index_t);
+extern int udf_idx_del(udf_node_t *);
+
+#endif /* UDF_IDX_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_ops.c
===================================================================
--- uspace/srv/fs/udf/udf_ops.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_ops.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_ops.c
+ * @brief Implementation of VFS operations for the UDF file system
+ *        server.
+ */
+
+#include <libfs.h>
+#include <block.h>
+#include <ipc/services.h>
+#include <ipc/loc.h>
+#include <macros.h>
+#include <async.h>
+#include <errno.h>
+#include <str.h>
+#include <byteorder.h>
+#include <adt/hash_table.h>
+#include <adt/list.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <sys/mman.h>
+#include <align.h>
+#include <malloc.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include "../../vfs/vfs.h"
+#include "udf.h"
+#include "udf_cksum.h"
+#include "udf_volume.h"
+#include "udf_idx.h"
+#include "udf_file.h"
+#include "udf_osta.h"
+
+/** Mutex protecting the list of cached free nodes. */
+static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
+
+/** List of cached free nodes. */
+static LIST_INITIALIZE(ffn_list);
+
+static int udf_node_get(fs_node_t **rfn, service_id_t service_id,
+    fs_index_t index)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *node;
+	rc = udf_idx_get(&node, instance, index);
+	if (rc != EOK) {
+		rc = udf_idx_add(&node, instance, index);
+		if (rc != EOK)
+			return rc;
+		
+		rc = udf_node_get_core(node);
+		if (rc != EOK) {
+			udf_idx_del(node);
+			return rc;
+		}
+	}
+	
+	*rfn = FS_NODE(node);
+	return EOK;
+}
+
+static int udf_root_get(fs_node_t **rfn, service_id_t service_id)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	return udf_node_get(rfn, service_id,
+	    instance->volumes[DEFAULT_VOL].root_dir);
+}
+
+static service_id_t udf_service_get(fs_node_t *node)
+{
+	udf_node_t *udfn = UDF_NODE(node);
+	if (udfn)
+		return udfn->instance->service_id;
+	
+	return 0;
+}
+
+static int udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	char *name = malloc(MAX_FILE_NAME_LEN + 1);
+	if (name == NULL)
+		return ENOMEM;
+	
+	block_t *block = NULL;
+	udf_file_identifier_descriptor_t *fid = NULL;
+	size_t pos = 0;
+	
+	while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
+		udf_long_ad_t long_ad = fid->icb;
+		
+		udf_to_unix_name(name, MAX_FILE_NAME_LEN,
+		    (char *) fid->implementation_use + FLE16(fid->lenght_iu),
+		    fid->lenght_file_id, &UDF_NODE(pfn)->instance->charset);
+		
+		if (stricmp(name, component) == 0) {
+			int rc = udf_node_get(rfn, udf_service_get(pfn),
+			    udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
+			
+			if (block != NULL)
+				block_put(block);
+			
+			free(name);
+			return rc;
+		}
+		
+		if (block != NULL) {
+			int rc = block_put(block);
+			if (rc != EOK)
+				return rc;
+		}
+		
+		pos++;
+	}
+	
+	free(name);
+	return ENOENT;
+}
+
+static int udf_node_open(fs_node_t *fn)
+{
+	return EOK;
+}
+
+static int udf_node_put(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (!node)
+		return EINVAL;
+	
+	fibril_mutex_lock(&node->lock);
+	node->ref_cnt--;
+	fibril_mutex_unlock(&node->lock);
+	
+	/* Delete node from hash table and memory */
+	if (!node->ref_cnt)
+		udf_idx_del(node);
+	
+	return EOK;
+}
+
+static int udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
+{
+	return ENOTSUP;
+}
+
+static int udf_destroy_node(fs_node_t *fn)
+{
+	return ENOTSUP;
+}
+
+static int udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	return ENOTSUP;
+}
+
+static int udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	return ENOTSUP;
+}
+
+static int udf_has_children(bool *has_children, fs_node_t *fn)
+{
+	*has_children = true;
+	return EOK;
+}
+
+static fs_index_t udf_index_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->index;
+	
+	return 0;
+}
+
+static aoff64_t udf_size_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->data_size;
+	
+	return 0;
+}
+
+static unsigned int udf_lnkcnt_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->link_cnt;
+	
+	return 0;
+}
+
+static bool udf_is_directory(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->type == NODE_DIR;
+	
+	return false;
+}
+
+static bool udf_is_file(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->type == NODE_FILE;
+	
+	return false;
+}
+
+libfs_ops_t udf_libfs_ops = {
+	.root_get = udf_root_get,
+	.match = udf_match,
+	.node_get = udf_node_get,
+	.node_open = udf_node_open,
+	.node_put = udf_node_put,
+	.create = udf_create_node,
+	.destroy = udf_destroy_node,
+	.link = udf_link,
+	.unlink = udf_unlink,
+	.has_children = udf_has_children,
+	.index_get = udf_index_get,
+	.size_get = udf_size_get,
+	.lnkcnt_get = udf_lnkcnt_get,
+	.is_directory = udf_is_directory,
+	.is_file = udf_is_file,
+	.service_get = udf_service_get
+};
+
+static int udf_mounted(service_id_t service_id, const char *opts,
+    fs_index_t *index, aoff64_t *size, unsigned *linkcnt)
+{
+	enum cache_mode cmode;
+	
+	/* Check for option enabling write through. */
+	if (str_cmp(opts, "wtcache") == 0)
+		cmode = CACHE_MODE_WT;
+	else
+		cmode = CACHE_MODE_WB;
+	
+	udf_instance_t *instance = malloc(sizeof(udf_instance_t));
+	if (!instance)
+		return ENOMEM;
+	
+	instance->sector_size = 0;
+	
+	/* Check for block size. Will be enhanced later */
+	if (str_cmp(opts, "bs=512") == 0)
+		instance->sector_size = 512;
+	else if (str_cmp(opts, "bs=1024") == 0)
+		instance->sector_size = 1024;
+	else if (str_cmp(opts, "bs=2048") == 0)
+		instance->sector_size = 2048;
+	
+	/* initialize block cache */
+	int rc = block_init(EXCHANGE_SERIALIZE, service_id, MAX_SIZE);
+	if (rc != EOK)
+		return rc;
+	
+	rc = fs_instance_create(service_id, instance);
+	if (rc != EOK) {
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	instance->service_id = service_id;
+	instance->open_nodes_count = 0;
+	
+	/* Check Volume Recognition Sequence */
+	rc = udf_volume_recongnition(service_id);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	/* Search for Anchor Volume Descriptor */
+	udf_anchor_volume_descriptor_t avd;
+	rc = udf_get_anchor_volume_descriptor(service_id, &avd);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
+	    instance->sector_size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
+	    PRIu32 " (sector)]", avd.main_extent.length,
+	    avd.main_extent.location);
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
+	    PRIu32 " (sector)]", avd.reserve_extent.length,
+	    avd.reserve_extent.location);
+	
+	/* Initialize the block cache */
+	rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
+	if (rc != EOK) {
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	/* Read Volume Descriptor Sequence */
+	rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	fs_node_t *rfn;
+	rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	udf_node_t *node = UDF_NODE(rfn);
+	*index = instance->volumes[DEFAULT_VOL].root_dir;
+	*size = node->data_size;
+	*linkcnt = node->link_cnt;
+	
+	return EOK;
+}
+
+static int udf_unmounted(service_id_t service_id)
+{
+	fs_node_t *fn;
+	int rc = udf_root_get(&fn, service_id);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *nodep = UDF_NODE(fn);
+	udf_instance_t *instance = nodep->instance;
+	
+	/*
+	 * We expect exactly two references on the root node.
+	 * One for the udf_root_get() above and one created in
+	 * udf_mounted().
+	 */
+	if (nodep->ref_cnt != 2) {
+		udf_node_put(fn);
+		return EBUSY;
+	}
+	
+	/*
+	 * Put the root node twice.
+	 */
+	udf_node_put(fn);
+	udf_node_put(fn);
+	
+	fs_instance_destroy(service_id);
+	free(instance);
+	block_cache_fini(service_id);
+	block_fini(service_id);
+	
+	return EOK;
+}
+
+static int udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	fs_node_t *rfn;
+	rc = udf_node_get(&rfn, service_id, index);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *node = UDF_NODE(rfn);
+	
+	ipc_callid_t callid;
+	size_t len = 0;
+	if (!async_data_read_receive(&callid, &len)) {
+		async_answer_0(callid, EINVAL);
+		udf_node_put(rfn);
+		return EINVAL;
+	}
+	
+	if (node->type == NODE_FILE) {
+		if (pos >= node->data_size) {
+			*rbytes = 0;
+			async_data_read_finalize(callid, NULL, 0);
+			udf_node_put(rfn);
+			return EOK;
+		}
+		
+		size_t read_len = 0;
+		if (node->data == NULL)
+			rc = udf_read_file(&read_len, callid, node, pos, len);
+		else {
+			/* File in allocation descriptors area */
+			read_len = (len < node->data_size) ? len : node->data_size;
+			async_data_read_finalize(callid, node->data + pos, read_len);
+			rc = EOK;
+		}
+		
+		*rbytes = read_len;
+		(void) udf_node_put(rfn);
+		return rc;
+	} else {
+		block_t *block = NULL;
+		udf_file_identifier_descriptor_t *fid = NULL;
+		if (udf_get_fid(&fid, &block, node, pos) == EOK) {
+			char *name = malloc(MAX_FILE_NAME_LEN + 1);
+			
+			// FIXME: Check for NULL return value
+			
+			udf_to_unix_name(name, MAX_FILE_NAME_LEN,
+			    (char *) fid->implementation_use + FLE16(fid->lenght_iu),
+			    fid->lenght_file_id, &node->instance->charset);
+			
+			async_data_read_finalize(callid, name, str_size(name) + 1);
+			*rbytes = 1;
+			free(name);
+			udf_node_put(rfn);
+			
+			if (block != NULL)
+				return block_put(block);
+			
+			return EOK;
+		} else {
+			*rbytes = 0;
+			udf_node_put(rfn);
+			async_answer_0(callid, ENOENT);
+			return ENOENT;
+		}
+	}
+}
+
+static int udf_close(service_id_t service_id, fs_index_t index)
+{
+	return EOK;
+}
+
+static int udf_sync(service_id_t service_id, fs_index_t index)
+{
+	return ENOTSUP;
+}
+
+static int udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
+	return ENOTSUP;
+}
+
+static int udf_truncate(service_id_t service_id, fs_index_t index,
+    aoff64_t size)
+{
+	return ENOTSUP;
+}
+
+static int udf_destroy(service_id_t service_id, fs_index_t index)
+{
+	return ENOTSUP;
+}
+
+vfs_out_ops_t udf_ops = {
+	.mounted = udf_mounted,
+	.unmounted = udf_unmounted,
+	.read = udf_read,
+	.write = udf_write,
+	.truncate = udf_truncate,
+	.close = udf_close,
+	.destroy = udf_destroy,
+	.sync = udf_sync
+};
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_osta.c
===================================================================
--- uspace/srv/fs/udf/udf_osta.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_osta.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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.
+ */
+
+/*
+ * OSTA compliant Unicode compression, uncompression routines,
+ * file name translation routine for OS/2, Windows 95, Windows NT,
+ * Macintosh and UNIX.
+ * Copyright 1995 Micro Design International, Inc.
+ * Written by Jason M. Rinn.
+ * Micro Design International gives permission for the free use of the
+ * following source code.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+/**
+ * @file udf_osta.c
+ * @brief OSTA compliant functions.
+ */
+
+#include <malloc.h>
+#include <str.h>
+#include <macros.h>
+#include <errno.h>
+#include "udf_osta.h"
+#include "udf_cksum.h"
+
+/** Calculate length of UTF-16 string
+ *
+ * FIXME: This is wrong! UTF-16 is not a fixed-width encoding,
+ *        it is a variable-width encoding (mind the surrogate
+ *        pairs).
+ *
+ */
+static size_t utf16_length(uint16_t *string) {
+	size_t len = 0;
+	
+	while (*string++ != 0)
+		len++;
+	
+	return len;
+}
+
+/** Illegal UNIX characters are NULL and slash.
+ *
+ */
+static bool legal_check(uint16_t ch)
+{
+	if ((ch == 0x0000) || (ch == 0x002F))
+		return false;
+	
+	return true;
+}
+
+/** Convert OSTA CS0 compressed Unicode name to Unicode.
+ *
+ * The Unicode output will be in the byte order that the local compiler
+ * uses for 16-bit values.
+ *
+ * NOTE: This routine only performs error checking on the comp_id.
+ * It is up to the user to ensure that the Unicode buffer is large
+ * enough, and that the compressed Unicode name is correct.
+ *
+ * @param[in]  number_of_bytes Number of bytes read from media
+ * @param[in]  udf_compressed  Bytes read from media
+ * @param[out] unicode         Uncompressed unicode characters
+ * @param[in]  unicode_max_len Size of output array
+ *
+ * @return Number of Unicode characters which were uncompressed.
+ *
+ */
+static size_t udf_uncompress_unicode(size_t number_of_bytes,
+    uint8_t *udf_compressed, uint16_t *unicode, size_t unicode_max_len)
+{
+	/* Use udf_compressed to store current byte being read. */
+	uint8_t comp_id = udf_compressed[0];
+	
+	/* First check for valid compID. */
+	if ((comp_id != 8) && (comp_id != 16))
+		return 0;
+	
+	size_t unicode_idx = 0;
+	size_t byte_idx = 1;
+	
+	/* Loop through all the bytes. */
+	while ((byte_idx < number_of_bytes) && (unicode_idx < unicode_max_len)) {
+		if (comp_id == 16) {
+			/*
+			 * Move the first byte to the high bits of the
+			 * Unicode char.
+			 */
+			unicode[unicode_idx] = udf_compressed[byte_idx++] << 8;
+		} else
+			unicode[unicode_idx] = 0;
+		
+		if (byte_idx < number_of_bytes) {
+			/* Then the next byte to the low bits. */
+			unicode[unicode_idx] |= udf_compressed[byte_idx++];
+		}
+		
+		unicode_idx++;
+	}
+	
+	return unicode_idx;
+}
+
+/** Translate a long file name
+ *
+ * Translate a long file name to one using a MAXLEN and an illegal char set
+ * in accord with the OSTA requirements. Assumes the name has already been
+ * translated to Unicode.
+ *
+ * @param[out] new_name Translated name. Must be of length MAXLEN
+ * @param[in]  udf_name Name from UDF volume
+ * @param[in]  udf_len  Length of UDF Name
+ *
+ * @return Number of Unicode characters in translated name.
+ *
+ */
+size_t udf_translate_name(uint16_t *new_name, uint16_t *udf_name,
+    size_t udf_len)
+{
+	bool needs_crc = false;
+	bool has_ext = false;
+	size_t ext_idx = 0;
+	size_t new_idx = 0;
+	size_t new_ext_idx = 0;
+	
+	for (size_t idx = 0; idx < udf_len; idx++) {
+		uint16_t current = udf_name[idx];
+		
+		if ((!legal_check(current)) || (!ascii_check(current))) {
+			needs_crc = true;
+			
+			/*
+			 * Replace Illegal and non-displayable chars with
+			 * underscore.
+			 */
+			current = ILLEGAL_CHAR_MARK;
+			
+			/*
+			 * Skip any other illegal or non-displayable
+			 * characters.
+			 */
+			while ((idx + 1 < udf_len) &&
+			    (!legal_check(udf_name[idx + 1]) ||
+			    (!ascii_check(udf_name[idx + 1]))))
+				idx++;
+		}
+		
+		/* Record position of extension, if one is found. */
+		if ((current == PERIOD) && ((udf_len - idx - 1) <= EXT_SIZE)) {
+			if (udf_len == idx + 1) {
+				/* A trailing period is NOT an extension. */
+				has_ext = false;
+			} else {
+				has_ext = true;
+				ext_idx = idx;
+				new_ext_idx = new_idx;
+			}
+		}
+		
+		if (new_idx < MAXLEN)
+			new_name[new_idx++] = current;
+		else
+			needs_crc = true;
+	}
+	
+	if (needs_crc) {
+		uint16_t ext[EXT_SIZE];
+		size_t local_ext_idx = 0;
+		
+		if (has_ext) {
+			size_t max_filename_len;
+			
+			/* Translate extension, and store it in ext. */
+			for (size_t idx = 0; (idx < EXT_SIZE) &&
+			    (ext_idx + idx + 1 < udf_len); idx++) {
+				uint16_t current = udf_name[ext_idx + idx + 1];
+				
+				if ((!legal_check(current)) || (!ascii_check(current))) {
+					needs_crc = true;
+					
+					/*
+					 * Replace Illegal and non-displayable
+					 * chars with underscore.
+					 */
+					current = ILLEGAL_CHAR_MARK;
+					
+					/*
+					 * Skip any other illegal or
+					 * non-displayable characters.
+					 */
+					while ((idx + 1 < EXT_SIZE) &&
+					    ((!legal_check(udf_name[ext_idx + idx + 2])) ||
+					    (!ascii_check(udf_name[ext_idx + idx + 2]))))
+						idx++;
+				}
+				
+				ext[local_ext_idx++] = current;
+			}
+			
+			/*
+			 * Truncate filename to leave room for extension and
+			 * CRC.
+			 */
+			max_filename_len = ((MAXLEN - 5) - local_ext_idx - 1);
+			if (new_idx > max_filename_len)
+				new_idx = max_filename_len;
+			else
+				new_idx = new_ext_idx;
+		} else if (new_idx > MAXLEN - 5) {
+			/* If no extension, make sure to leave room for CRC. */
+			new_idx = MAXLEN - 5;
+		}
+		
+		/* Add mark for CRC. */
+		new_name[new_idx++] = CRC_MARK;
+		
+		/* Calculate CRC from original filename. */
+		uint16_t value_crc = udf_unicode_cksum(udf_name, udf_len);
+		
+		/* Convert 16-bits of CRC to hex characters. */
+		const char hex_char[] = "0123456789ABCDEF";
+		
+		new_name[new_idx++] = hex_char[(value_crc & 0xf000) >> 12];
+		new_name[new_idx++] = hex_char[(value_crc & 0x0f00) >> 8];
+		new_name[new_idx++] = hex_char[(value_crc & 0x00f0) >> 4];
+		new_name[new_idx++] = hex_char[(value_crc & 0x000f)];
+		
+		/* Place a translated extension at end, if found. */
+		if (has_ext) {
+			new_name[new_idx++] = PERIOD;
+			
+			for (size_t idx = 0; idx < local_ext_idx; idx++)
+				new_name[new_idx++] = ext[idx];
+		}
+	}
+	
+	return new_idx;
+}
+
+/** Decode from dchar to utf8
+ *
+ * @param result     Returned value - utf8 string
+ * @param result_len Length of output string
+ * @param id         Input string
+ * @param len        Length of input string
+ * @param chsp       Decode method
+ *
+ */
+void udf_to_unix_name(char *result, size_t result_len, char *id, size_t len,
+    udf_charspec_t *chsp)
+{
+	const char *osta_id = "OSTA Compressed Unicode";
+	size_t ucode_chars, nice_uchars;
+	
+	uint16_t *raw_name = malloc(MAX_BUF * sizeof(uint16_t));
+	uint16_t *unix_name = malloc(MAX_BUF * sizeof(uint16_t));
+	
+	// FIXME: Check for malloc returning NULL
+	
+	bool is_osta_typ0 = (chsp->type == 0) &&
+	    (str_cmp((char *) chsp->info, osta_id) == 0);
+	
+	if (is_osta_typ0) {
+		*raw_name = 0;
+		*unix_name = 0;
+		
+		ucode_chars =
+		    udf_uncompress_unicode(len, (uint8_t *) id, raw_name, MAX_BUF);
+		ucode_chars = min(ucode_chars, utf16_length(raw_name));
+		nice_uchars =
+		    udf_translate_name(unix_name, raw_name, ucode_chars);
+		
+		/* Output UTF-8 */
+		unix_name[nice_uchars] = 0;
+		utf16_to_str(result, result_len, unix_name);
+	} else {
+		/* Assume 8 bit char length byte Latin-1 */
+		str_ncpy(result, result_len, (char *) (id + 1),
+		    str_size((char *) (id + 1)));
+	}
+	
+	free(raw_name);
+	free(unix_name);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_osta.h
===================================================================
--- uspace/srv/fs/udf/udf_osta.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_osta.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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.
+ */
+
+/*
+ * OSTA compliant Unicode compression, uncompression routines,
+ * file name translation routine for OS/2, Windows 95, Windows NT,
+ * Macintosh and UNIX.
+ * Copyright 1995 Micro Design International, Inc.
+ * Written by Jason M. Rinn.
+ * Micro Design International gives permission for the free use of the
+ * following source code.
+ */
+
+#ifndef UDF_OSTA_H_
+#define UDF_OSTA_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include "udf_types.h"
+
+#define MAXLEN    255
+#define MAX_BUF   1024
+#define EXT_SIZE  5
+
+#define ILLEGAL_CHAR_MARK  0x005F
+#define CRC_MARK           0x0023
+#define PERIOD             0x002E
+
+extern size_t udf_translate_name(uint16_t *, uint16_t *, size_t);
+extern void udf_to_unix_name(char *, size_t, char *, size_t, udf_charspec_t *);
+
+#endif /* UDF_OSTA_H_ */
Index: uspace/srv/fs/udf/udf_types.h
===================================================================
--- uspace/srv/fs/udf/udf_types.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_types.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_types.h
+ * @brief UDF common types
+ */
+
+#ifndef UDF_UDF_TYPES_H_
+#define UDF_UDF_TYPES_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include <byteorder.h>
+
+#define GET_LE16(x)  x = uint16_t_le2host(x)
+#define GET_LE32(x)  x = uint32_t_le2host(x)
+
+#define FLE16(x)  uint16_t_le2host(x)
+#define FLE32(x)  uint32_t_le2host(x)
+#define FLE64(x)  uint64_t_le2host(x)
+
+#define ALL_UP(n, b)  ((n) / (b) + ((n) % (b) != 0))
+
+#define EXT_LENGTH(x)  (x & 0x3FFFFFFF)
+
+typedef uint8_t udf_dstring;
+
+/* Timestamp descriptor (ECMA 167 1/7.3) */
+typedef struct udf_timestamp {
+	uint16_t type_and_tz;
+	uint16_t year;
+	uint8_t month;
+	uint8_t day;
+	uint8_t hour;
+	uint8_t min;
+	uint8_t sec;
+	uint8_t centisec;
+	uint8_t h_of_mcsec;
+	uint8_t mcsec;
+} __attribute__((packed)) udf_timestamp_t;
+
+/* Universal descriptor tag (ECMA 167 3/7.2) */
+typedef struct udf_descriptor_tag {
+	uint16_t id;
+	uint16_t version;
+	uint8_t checksum;
+	uint8_t reserved;
+	uint16_t serial;
+	uint16_t descriptor_crc;
+	uint16_t descriptor_crc_length;
+	uint32_t location;
+} __attribute__((packed)) udf_descriptor_tag_t;
+
+/* Entity descriptor (ECMA 167 1/7.4) */
+typedef struct udf_regid {
+	uint8_t flags;
+	uint8_t id[23];
+	uint8_t id_suffix[8];
+} __attribute__((packed)) udf_regid_t;
+
+/* Character set specification (ECMA 167 1/7.2.1) */
+typedef struct udf_charspec {
+	uint8_t type;
+	uint8_t info[63];
+} __attribute__((packed)) udf_charspec_t;
+
+/* Recorded address (ECMA 167 4/7.1) */
+typedef struct udf_lb_addr {
+	uint32_t lblock_num;     /* Relative to start of the partition (from 0) */
+	uint16_t partition_num;  /* Relative to logical volume or not? */
+} __attribute__((packed)) udf_lb_addr_t;
+
+/* Long Allocation Descriptor (ECMA 167 4/14.14.2) */
+typedef struct udf_long_ad {
+	uint32_t length;
+	udf_lb_addr_t location;
+	uint8_t implementation_use[6];
+} __attribute__((packed)) udf_long_ad_t;
+
+/* Short Allocation Descriptor (ECMA 167 4/14.14.1) */
+typedef struct udf_short_ad {
+	uint32_t length;
+	uint32_t position;
+} __attribute__((packed)) udf_short_ad_t;
+
+/* Extended Allocation Descriptor (ECMA 167 4/14.14.3) */
+typedef struct udf_ext_ad {
+	uint32_t extent_length;
+	uint32_t recorded_length;
+	uint32_t info_length;
+	udf_lb_addr_t extent_location;
+	uint8_t implementation_use[2];
+} __attribute__((packed)) udf_ext_ad_t;
+
+/* Extent descriptor (ECMA 167 3/7.1) */
+typedef struct udf_extent {
+	uint32_t length;    /* Bytes */
+	uint32_t location;  /* Sectors */
+} __attribute__((packed)) udf_extent_t;
+
+/* Terminating Descriptor (ECMA 167 3/10.9) */
+typedef struct udf_terminating_descriptor {
+	udf_descriptor_tag_t tag;
+	uint8_t reserved[496];
+} __attribute__((packed)) udf_terminating_descriptor_t;
+
+/* Unallocated Space Descriptor (ECMA 167 3/10.8) */
+typedef struct udf_unallocated_space_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint32_t allocation_descriptors_num;
+	udf_extent_t allocation_descriptors[0];
+} __attribute__((packed)) udf_unallocated_space_descriptor_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_volume.c
===================================================================
--- uspace/srv/fs/udf/udf_volume.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_volume.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+/**
+ * @file udf_volume.c
+ * @brief Implementation of volume recognition operations.
+ */
+
+#include <byteorder.h>
+#include <block.h>
+#include <libfs.h>
+#include <errno.h>
+#include <str.h>
+#include <malloc.h>
+#include <mem.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include "udf.h"
+#include "udf_volume.h"
+#include "udf_osta.h"
+#include "udf_cksum.h"
+#include "udf_file.h"
+
+/** Convert long_ad to absolute sector position
+ *
+ * Convert address sector concerning origin of partition to position
+ * sector concerning origin of start of disk.
+ *
+ * @param instance UDF instance
+ * @param long_ad  UDF long address
+ *
+ * @return Position of sector concerning origin of start of disk.
+ *
+ */
+fs_index_t udf_long_ad_to_pos(udf_instance_t *instance, udf_long_ad_t *long_ad)
+{
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Long_Ad to Pos: "
+	    "partition_num=%" PRIu16 ", partition_block=%" PRIu32,
+	    FLE16(long_ad->location.partition_num),
+	    FLE32(long_ad->location.lblock_num));
+	
+	return instance->partitions[
+	    FLE16(long_ad->location.partition_num)].start +
+	    FLE32(long_ad->location.lblock_num);
+}
+
+/** Check type and version of VRS
+ *
+ * Not exactly clear which values could have type and version.
+ *
+ * @param service_id
+ * @param addr       Position sector with Volume Descriptor
+ * @param vd         Returned value - Volume Descriptor.
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_volume_recongnition_structure_test(service_id_t service_id,
+    aoff64_t addr, udf_vrs_descriptor_t *vd)
+{
+	return block_read_bytes_direct(service_id, addr,
+	    sizeof(udf_vrs_descriptor_t), vd);
+}
+
+/** Read Volume Recognition Sequence
+ *
+ * It is a first udf data which we read.
+ * It stars from fixed address VRS_ADDR = 32768 (bytes)
+ *
+ * @param service_id
+ *
+ * @return    EOK on success or a negative error code.
+ */
+int udf_volume_recongnition(service_id_t service_id) 
+{
+	aoff64_t addr = VRS_ADDR;
+	bool nsr_found = false;
+
+	udf_vrs_descriptor_t *vd = malloc(sizeof(udf_vrs_descriptor_t));
+	if (!vd)
+		return ENOMEM;
+	
+	int rc = udf_volume_recongnition_structure_test(service_id, addr, vd);
+	if (rc != EOK) {
+		free(vd);
+		return rc;
+	}
+	
+	for (size_t i = 0; i < VRS_DEPTH; i++) {
+		addr += sizeof(udf_vrs_descriptor_t);
+		
+		rc = udf_volume_recongnition_structure_test(service_id, addr, vd);
+		if (rc != EOK) {
+			free(vd);
+			return rc;
+		}
+		
+		/*
+		 * UDF standard identifier. According to ECMA 167 2/9.1.2
+		 */
+		if ((str_lcmp(VRS_NSR2, (char *) vd->identifier, VRS_ID_LEN) == 0) ||
+		    (str_lcmp(VRS_NSR3, (char *) vd->identifier, VRS_ID_LEN) == 0)) {
+			nsr_found = true;
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "VRS: NSR found");
+			continue;
+		}
+		
+		if (str_lcmp(VRS_END, (char *) vd->identifier, VRS_ID_LEN) == 0) {
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "VRS: end found");
+			break;
+		}
+	}
+	
+	free(vd);
+	
+	if (nsr_found)
+		return EOK;
+	else
+		return EINVAL;
+}
+
+/** Convert descriptor tag fields from little-endian to current byte order
+ *
+ */
+static void udf_prepare_tag(udf_descriptor_tag_t *tag)
+{
+	GET_LE16(tag->id);
+	GET_LE16(tag->version);
+	GET_LE16(tag->serial);
+	GET_LE16(tag->descriptor_crc);
+	GET_LE16(tag->descriptor_crc_length);
+	GET_LE32(tag->location);
+}
+
+/** Read AVD by using one of default sector size from array
+ *
+ * @param service_id
+ * @param avd         Returned value - Anchor Volume Descriptor
+ * @param sector_size Expected sector size
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_get_anchor_volume_descriptor_by_ssize(service_id_t service_id,
+    udf_anchor_volume_descriptor_t *avd, uint32_t sector_size)
+{
+	int rc = block_read_bytes_direct(service_id,
+	    UDF_AVDP_SECTOR * sector_size,
+	    sizeof(udf_anchor_volume_descriptor_t), avd);
+	if (rc != EOK)
+		return rc;
+	
+	if (avd->tag.checksum != udf_tag_checksum((uint8_t *) &avd->tag))
+		return EINVAL;
+	
+	// TODO: Should be tested in big-endian mode
+	udf_prepare_tag(&avd->tag);
+	
+	if (avd->tag.id != UDF_TAG_AVDP)
+		return EINVAL;
+	
+	GET_LE32(avd->main_extent.length);
+	GET_LE32(avd->main_extent.location);
+	GET_LE32(avd->reserve_extent.length);
+	GET_LE32(avd->reserve_extent.location);
+	
+	return EOK;
+}
+
+/** Identification of the sector size
+ *
+ * We try to read Anchor Volume Descriptor by using one item from
+ * sequence of default values. If we could read avd, we found sector size.
+ *
+ * @param service_id
+ * @param avd        Returned value - Anchor Volume Descriptor
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_anchor_volume_descriptor(service_id_t service_id,
+    udf_anchor_volume_descriptor_t *avd)
+{
+	uint32_t default_sector_size[] = {512, 1024, 2048, 4096, 8192, 0};
+	
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	if (instance->sector_size) {
+		return udf_get_anchor_volume_descriptor_by_ssize(service_id, avd,
+		    instance->sector_size);
+	} else {
+		size_t i = 0;
+		while (default_sector_size[i] != 0) {
+			rc = udf_get_anchor_volume_descriptor_by_ssize(service_id, avd,
+			    default_sector_size[i]);
+			if (rc == EOK) {
+				instance->sector_size = default_sector_size[i];
+				return EOK;
+			}
+			
+			i++;
+		}
+	}
+	
+	return EINVAL;
+}
+
+/** Check on prevailing primary volume descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param pvd  Array of primary volumes descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_pvd(udf_primary_volume_descriptor_t *pvd,
+    size_t cnt, udf_primary_volume_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * PVD, each of which has same contents of the corresponding
+		 * Volume Identifier, Volume set identifier
+		 * and Descriptor char set field.
+		 */
+		if ((bcmp((uint8_t *) pvd[i].volume_id,
+		    (uint8_t *) desc->volume_id, 32) == 0) &&
+		    (bcmp((uint8_t *) pvd[i].volume_set_id,
+		    (uint8_t *) desc->volume_set_id, 128) == 0) &&
+		    (bcmp((uint8_t *) &pvd[i].descriptor_charset,
+		    (uint8_t *) &desc->descriptor_charset, 64) == 0) &&
+		    (FLE32(desc->sequence_number) > FLE32(pvd[i].sequence_number))) {
+			memcpy(&pvd[i], desc, sizeof(udf_primary_volume_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Check on prevailing logic volume descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find  prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param lvd  Array of logic volumes descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_lvd(udf_logical_volume_descriptor_t *lvd,
+    size_t cnt, udf_logical_volume_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * LVD, each of which has same contents of the corresponding
+		 * Logic Volume Identifier and Descriptor char set field.
+		 */
+		if ((bcmp((uint8_t *) lvd[i].logical_volume_id,
+		    (uint8_t *) desc->logical_volume_id, 128) == 0) &&
+		    (bcmp((uint8_t *) &lvd[i].charset,
+		    (uint8_t *) &desc->charset, 64) == 0) &&
+		    (FLE32(desc->sequence_number) > FLE32(lvd[i].sequence_number))) {
+			memcpy(&lvd[i], desc, sizeof(udf_logical_volume_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Check on prevailing partition descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find  prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param pvd  Array of partition descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_pd(udf_partition_descriptor_t *pd, size_t cnt,
+    udf_partition_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * Partition descriptors with identical Partition Number
+		 */
+		if ((FLE16(pd[i].number) == FLE16(desc->number)) &&
+		    (FLE32(desc->sequence_number) > FLE32(pd[i].sequence_number))) {
+			memcpy(&pd[i], desc, sizeof(udf_partition_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Read information about virtual partition
+ *
+ * Fill start and length fields for partition. This function quite similar of
+ * udf_read_icd. But in this we can meet only two descriptors and
+ * we have to read only one allocator.
+ *
+ * @param instance UDF instance
+ * @param pos      Position (Extended) File entry descriptor
+ * @param id       Index of partition in instance::partitions array
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_read_virtual_partition(udf_instance_t *instance, uint32_t pos,
+    uint32_t id)
+{
+	block_t *block = NULL;
+	int rc = block_get(&block, instance->service_id, pos,
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+	
+	udf_descriptor_tag_t *desc = (udf_descriptor_tag_t *) (block->data);
+	if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+		block_put(block);
+		return EINVAL;
+	}
+	
+	/*
+	 * We think that we have only one allocator. It is means that virtual
+	 * partition, like physical, isn't fragmented.
+	 * According to doc the type of allocator is short_ad.
+	 */
+	switch (FLE16(desc->id)) {
+	case UDF_FILE_ENTRY:
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
+		
+		udf_file_entry_descriptor_t *fed =
+		    (udf_file_entry_descriptor_t *) block->data;
+		uint32_t start_alloc = FLE32(fed->ea_lenght) + UDF_FE_OFFSET;
+		udf_short_ad_t *short_d =
+		    (udf_short_ad_t *) ((uint8_t *) fed + start_alloc);
+		instance->partitions[id].start = FLE32(short_d->position);
+		instance->partitions[id].lenght = FLE32(short_d->length);
+		break;
+		
+	case UDF_EFILE_ENTRY:
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
+		
+		udf_extended_file_entry_descriptor_t *efed =
+		    (udf_extended_file_entry_descriptor_t *) block->data;
+		start_alloc = FLE32(efed->ea_lenght) + UDF_EFE_OFFSET;
+		short_d = (udf_short_ad_t *) ((uint8_t *) efed + start_alloc);
+		instance->partitions[id].start = FLE32(short_d->position);
+		instance->partitions[id].lenght = FLE32(short_d->length);
+		break;
+	}
+	
+	return block_put(block);
+}
+
+/** Search partition in array of partitions
+ *
+ * Used only in function udf_fill_volume_info
+ *
+ * @param pd     Array of partitions
+ * @param pd_cnt Count items in array
+ * @param id     Number partition (not index) which we want to find
+ *
+ * @return Index of partition or (size_t) -1 if we didn't find anything
+ *
+ */
+static size_t udf_find_partition(udf_partition_descriptor_t *pd, size_t pd_cnt,
+    size_t id)
+{
+	for (size_t i = 0; i < pd_cnt; i++) {
+		if (FLE16(pd[i].number) == id)
+			return i;
+	}
+	
+	return (size_t) -1;
+}
+
+/** Fill instance structures by information about partitions and logic
+ *
+ * @param lvd      Array of logic volumes descriptors
+ * @param lvd_cnt  Count of items in lvd array
+ * @param pd       Array of partition descriptors
+ * @param pd_cnt   Count of items in pd array
+ * @param instance UDF instance
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_fill_volume_info(udf_logical_volume_descriptor_t *lvd,
+    size_t lvd_cnt, udf_partition_descriptor_t *pd, size_t pd_cnt,
+    udf_instance_t *instance)
+{
+	instance->volumes = calloc(lvd_cnt, sizeof(udf_lvolume_t));
+	if (instance->volumes == NULL)
+		return ENOMEM;
+	
+	instance->partitions = calloc(pd_cnt, sizeof(udf_partition_t));
+	if (instance->partitions == NULL) {
+		free(instance->volumes);
+		return ENOMEM;
+	}
+	
+	instance->partition_cnt = pd_cnt;
+	
+	/*
+	 * Fill information about logical volumes. We will save
+	 * information about all partitions placed inside each volumes.
+	 */
+	
+	size_t vir_pd_cnt = 0;
+	for (size_t i = 0; i < lvd_cnt; i++) {
+		instance->volumes[i].partitions =
+		    calloc(FLE32(lvd[i].number_of_partitions_maps),
+		    sizeof(udf_partition_t *));
+		if (instance->volumes[i].partitions == NULL) {
+			// FIXME: Memory leak, cleanup code missing
+			return ENOMEM;
+		}
+		
+		instance->volumes[i].partition_cnt = 0;
+		instance->volumes[i].logical_block_size =
+		    FLE32(lvd[i].logical_block_size);
+		
+		/*
+		 * In theory we could have more than 1 logical volume. But now
+		 * for current work of driver we will think that it single and all
+		 * partitions from array pd belong to only first lvd
+		 */
+		
+		uint8_t *idx = lvd[i].partition_map;
+		for (size_t j = 0; j < FLE32(lvd[i].number_of_partitions_maps);
+		    j++) {
+			udf_type1_partition_map_t *pm1 =
+			    (udf_type1_partition_map_t *) idx;
+			
+			if (pm1->partition_map_type == 1) {
+				size_t pd_num = udf_find_partition(pd, pd_cnt,
+				    FLE16(pm1->partition_number));
+				if (pd_num == (size_t) -1) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOENT;
+				}
+				
+				/*
+				 * Fill information about physical partitions. We will save all
+				 * partitions (physical and virtual) inside one array
+				 * instance::partitions
+				 */
+				instance->partitions[j].access_type =
+				    FLE32(pd[pd_num].access_type);
+				instance->partitions[j].lenght =
+				    FLE32(pd[pd_num].length);
+				instance->partitions[j].number =
+				    FLE16(pm1->partition_number);
+				instance->partitions[j].start =
+				    FLE32(pd[pd_num].starting_location);
+				
+				instance->volumes[i].partitions[
+				    instance->volumes[i].partition_cnt] =
+				    &instance->partitions[j];
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+				    "found and filled", i, pm1->partition_map_type);
+				
+				instance->volumes[i].partition_cnt++;
+				idx += pm1->partition_map_lenght;
+				continue;
+			}
+			
+			udf_type2_partition_map_t *pm2 =
+			    (udf_type2_partition_map_t *) idx;
+			
+			if (pm2->partition_map_type == 2) {
+				// TODO: check partition_ident for metadata_partition_map
+				
+				udf_metadata_partition_map_t *metadata =
+				    (udf_metadata_partition_map_t *) idx;
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Metadata file location=%u",
+				    FLE32(metadata->metadata_fileloc));
+				
+				vir_pd_cnt++;
+				instance->partitions = realloc(instance->partitions,
+				    (pd_cnt + vir_pd_cnt) * sizeof(udf_partition_t));
+				if (instance->partitions == NULL) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOMEM;
+				}
+				
+				instance->partition_cnt++;
+				
+				size_t pd_num = udf_find_partition(pd, pd_cnt,
+				    FLE16(metadata->partition_number));
+				if (pd_num == (size_t) -1) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOENT;
+				}
+				
+				instance->partitions[j].number =
+				    FLE16(metadata->partition_number);
+				int rc = udf_read_virtual_partition(instance,
+				    FLE32(metadata->metadata_fileloc) +
+				    FLE32(pd[pd_num].starting_location), j);
+				if (rc != EOK) {
+					// FIXME: Memory leak, cleanup code missing
+					return rc;
+				}
+				
+				/* Virtual partition placed inside physical */
+				instance->partitions[j].start +=
+				    FLE32(pd[pd_num].starting_location);
+				
+				instance->volumes[i].partitions[
+				    instance->volumes[i].partition_cnt] =
+				    &instance->partitions[j];
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Virtual partition: num=%d, start=%d",
+				    instance->partitions[j].number,
+				    instance->partitions[j].start);
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+				    "found and filled", i, pm2->partition_map_type);
+				
+				instance->volumes[i].partition_cnt++;
+				idx += metadata->partition_map_length;
+				continue;
+			}
+			
+			/* Not type 1 nor type 2 */
+			udf_general_type_t *pm = (udf_general_type_t *) idx;
+			
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+			    "found and skipped", i, pm->partition_map_type);
+			
+			idx += pm->partition_map_lenght;
+		}
+	}
+	
+	return EOK;
+}
+
+/** Read volume descriptors sequence
+ *
+ * @param service_id
+ * @param addr       UDF extent descriptor (ECMA 167 3/7.1)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_volume_descriptor_sequence(service_id_t service_id,
+    udf_extent_t addr)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	aoff64_t pos = addr.location;
+	aoff64_t end = pos + (addr.length / instance->sector_size) - 1;
+	
+	if (pos == end)
+		return EINVAL;
+	
+	size_t max_descriptors = ALL_UP(addr.length, instance->sector_size);
+	
+	udf_primary_volume_descriptor_t *pvd = calloc(max_descriptors,
+	    sizeof(udf_primary_volume_descriptor_t));
+	if (pvd == NULL)
+		return ENOMEM;
+	
+	udf_logical_volume_descriptor_t *lvd = calloc(max_descriptors,
+	    instance->sector_size);
+	if (lvd == NULL) {
+		free(pvd);
+		return ENOMEM;
+	}
+	
+	udf_partition_descriptor_t *pd = calloc(max_descriptors,
+	    sizeof(udf_partition_descriptor_t));
+	if (pd == NULL) {
+		free(pvd);
+		free(lvd);
+		return ENOMEM;
+	}
+	
+	size_t pvd_cnt = 0;
+	size_t lvd_cnt = 0;
+	size_t pd_cnt = 0;
+	
+	while (pos <= end) {
+		block_t *block = NULL;
+		rc = block_get(&block, service_id, pos, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			free(pvd);
+			free(lvd);
+			free(pd);
+			return rc;
+		}
+		
+		udf_volume_descriptor_t *vol =
+		    (udf_volume_descriptor_t *) block->data;
+		
+		switch (FLE16(vol->common.tag.id)) {
+		/* One sector size descriptors */
+		case UDF_TAG_PVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Primary volume descriptor found");
+			
+			if (!udf_check_prevailing_pvd(pvd, pvd_cnt, &vol->volume)) {
+				memcpy(&pvd[pvd_cnt], &vol->volume,
+				    sizeof(udf_primary_volume_descriptor_t));
+				pvd_cnt++;
+			}
+			
+			pos++;
+			break;
+			
+		case UDF_TAG_VDP:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Volume descriptor pointer found");
+			pos++;
+			break;
+			
+		case UDF_TAG_IUVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG,
+			    "Volume: Implementation use volume descriptor found");
+			pos++;
+			break;
+			
+		case UDF_TAG_PD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Partition descriptor found");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Partition number: %u, contents: '%.6s', "
+			    "access type: %" PRIu32, FLE16(vol->partition.number),
+			    vol->partition.contents.id, FLE32(vol->partition.access_type));
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Partition start: %" PRIu32 " (sector), "
+			    "size: %" PRIu32 " (sectors)",
+			    FLE32(vol->partition.starting_location),
+			    FLE32(vol->partition.length));
+			
+			if (!udf_check_prevailing_pd(pd, pd_cnt, &vol->partition)) {
+				memcpy(&pd[pd_cnt], &vol->partition,
+				    sizeof(udf_partition_descriptor_t));
+				pd_cnt++;
+			}
+			
+			udf_partition_header_descriptor_t *phd =
+			    (udf_partition_header_descriptor_t *) vol->partition.contents_use;
+			if (FLE32(phd->unallocated_space_table.length)) {
+				log_msg(LOG_DEFAULT, LVL_DEBUG,
+				    "space table: length=%" PRIu32 ", pos=%" PRIu32,
+				    FLE32(phd->unallocated_space_table.length),
+				    FLE32(phd->unallocated_space_table.position));
+				
+				instance->space_type = SPACE_TABLE;
+				instance->uaspace_start =
+				    FLE32(vol->partition.starting_location) +
+				    FLE32(phd->unallocated_space_table.position);
+				instance->uaspace_lenght =
+				    FLE32(phd->unallocated_space_table.length);
+			}
+			
+			if (FLE32(phd->unallocated_space_bitmap.length)) {
+				log_msg(LOG_DEFAULT, LVL_DEBUG,
+				    "space bitmap: length=%" PRIu32 ", pos=%" PRIu32,
+				    FLE32(phd->unallocated_space_bitmap.length),
+				    FLE32(phd->unallocated_space_bitmap.position));
+				
+				instance->space_type = SPACE_BITMAP;
+				instance->uaspace_start =
+				    FLE32(vol->partition.starting_location) +
+				    FLE32(phd->unallocated_space_bitmap.position);
+				instance->uaspace_lenght =
+				    FLE32(phd->unallocated_space_bitmap.length);
+			}
+			
+			pos++;
+			break;
+			
+		/* Relative size descriptors */
+		case UDF_TAG_LVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Logical volume descriptor found");
+			
+			aoff64_t sct =
+			    ALL_UP((sizeof(udf_logical_volume_descriptor_t) +
+			    FLE32(vol->logical.map_table_length)),
+			    sizeof(udf_common_descriptor_t));
+			pos += sct;
+			char tmp[130];
+			
+			udf_to_unix_name(tmp, 129,
+			    (char *) vol->logical.logical_volume_id, 128,
+			    &vol->logical.charset);
+			
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Logical Volume ID: '%s', "
+			    "logical block size: %" PRIu32 " (bytes)", tmp,
+			    FLE32(vol->logical.logical_block_size));
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Map table size: %" PRIu32 " (bytes), "
+			    "number of partition maps: %" PRIu32,
+			    FLE32(vol->logical.map_table_length),
+			    FLE32(vol->logical.number_of_partitions_maps));
+			
+			if (!udf_check_prevailing_lvd(lvd, lvd_cnt, &vol->logical)) {
+				memcpy(&lvd[lvd_cnt], &vol->logical,
+				    sizeof(udf_logical_volume_descriptor_t) +
+				    FLE32(vol->logical.map_table_length));
+				lvd_cnt++;
+			}
+			
+			break;
+			
+		case UDF_TAG_USD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Unallocated space descriptor found");
+			
+			sct = ALL_UP((sizeof(udf_unallocated_space_descriptor_t) +
+			    FLE32(vol->unallocated.allocation_descriptors_num)*
+			    sizeof(udf_extent_t)), sizeof(udf_common_descriptor_t));
+			instance->uaspace_start = pos;
+			instance->uaspace_lenght = sct;
+			instance->uasd = (udf_unallocated_space_descriptor_t *)
+			    malloc(sct * instance->sector_size);
+			if (instance->uasd == NULL) {
+				// FIXME: Memory leak, cleanup missing
+				return ENOMEM;
+			}
+			
+			memcpy(instance->uasd, block->data, instance->sector_size);
+			pos += sct;
+			break;
+			
+		case UDF_TAG_LVID:
+			log_msg(LOG_DEFAULT, LVL_DEBUG,
+			    "Volume: Logical volume integrity descriptor found");
+			
+			pos++;
+			break;
+			
+		case UDF_TAG_TD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Terminating descriptor found");
+			
+			/* Found terminating descriptor. Exiting */
+			pos = end + 1;
+			break;
+			
+		default:
+			pos++;
+		}
+		
+		rc = block_put(block);
+		if (rc != EOK) {
+			free(pvd);
+			free(lvd);
+			free(pd);
+			return rc;
+		}
+	}
+	
+	/* Fill the instance */
+	udf_fill_volume_info(lvd, lvd_cnt, pd, pd_cnt, instance);
+	
+	for (size_t i = 0; i < lvd_cnt; i++) {
+		pos = udf_long_ad_to_pos(instance,
+		    (udf_long_ad_t *) &lvd[i].logical_volume_conents_use);
+		
+		block_t *block = NULL;
+		rc = block_get(&block, instance->service_id, pos,
+		    BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			// FIXME: Memory leak, cleanup missing
+			return rc;
+		}
+		
+		udf_descriptor_tag_t *desc = block->data;
+		
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "First tag ID=%" PRIu16, desc->id);
+		
+		if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+			// FIXME: Memory leak, cleanup missing
+			return EINVAL;
+		}
+		
+		udf_prepare_tag(desc);
+		
+		udf_fileset_descriptor_t *fd = block->data;
+		memcpy((uint8_t *) &instance->charset,
+		    (uint8_t *) &fd->fileset_charset, sizeof(fd->fileset_charset));
+		
+		instance->volumes[i].root_dir = udf_long_ad_to_pos(instance,
+		    &fd->root_dir_icb);
+	}
+	
+	free(pvd);
+	free(lvd);
+	free(pd);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_volume.h
===================================================================
--- uspace/srv/fs/udf/udf_volume.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/fs/udf/udf_volume.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 fs
+ * @{
+ */
+
+#ifndef UDF_UDF_VOLUME_H_
+#define UDF_UDF_VOLUME_H_
+
+#include <sys/types.h>
+#include <ipc/loc.h>
+#include "udf_types.h"
+
+/* Descriptor Tag Identifier (ECMA 167 3/7.2.1) */
+#define UDF_TAG_PVD   0x0001  /* Primary Volume Descriptor */
+#define UDF_TAG_AVDP  0x0002  /* Anchor Volume Descriptor */
+#define UDF_TAG_VDP   0x0003  /* Volume Descriptor Pointer */
+#define UDF_TAG_IUVD  0x0004  /* Implementation Use Volume Descriptor */
+#define UDF_TAG_PD    0x0005  /* Partition Descriptor */
+#define UDF_TAG_LVD   0x0006  /* Logical Volume Descriptor */
+#define UDF_TAG_USD   0x0007  /* Unallocated Space Descriptor */
+#define UDF_TAG_TD    0x0008  /* Terminating Descriptor */
+#define UDF_TAG_LVID  0x0009  /* Logical Volume Integrity Descriptor */
+
+/* Start adress of Anchor Volume Descriptor */
+#define UDF_AVDP_SECTOR  256
+
+/* Volume Recognition Sequence params */
+#define VRS_ADDR     32768
+#define VRS_TYPE     0
+#define VRS_VERSION  1
+#define VRS_BEGIN    "BEA01"
+#define VRS_END      "TEA01"
+#define VRS_NSR2     "NSR02"
+#define VRS_NSR3     "NSR03"
+#define VRS_DEPTH    10
+#define VRS_ID_LEN   5
+
+/* Volume Structure Descriptor (ECMA 167 2/9.1) */
+typedef struct udf_vrs_descriptor {
+	uint8_t type;           /* Structure type */
+	uint8_t identifier[5];  /* Standart identifier */
+	uint8_t version;        /* Structure version */
+	uint8_t data[2041];     /* Structure data */
+} __attribute__((packed)) udf_vrs_descriptor_t;
+
+/* Anchor volume descriptor (ECMA 167 3/10.2) */
+typedef struct udf_anchor_volume_descriptor {
+	udf_descriptor_tag_t tag;     /* Descriptor tag */
+	udf_extent_t main_extent;     /* Main Volume Descriptor Sequence Extent */
+	udf_extent_t reserve_extent;  /* Reserve Volume Descriptor Sequence Extent */
+	uint8_t reserved[480];        /* Structure data */
+} __attribute__((packed)) udf_anchor_volume_descriptor_t;
+
+/* Common Volume Descriptor */
+typedef struct udf_common_descriptor {
+	udf_descriptor_tag_t tag;
+	uint8_t reserved[496];
+} __attribute__((packed)) udf_common_descriptor_t;
+
+/* Volume Descriptor Pointer (ECMA 167 3/10.3) */
+typedef struct udf_volume_pointer_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	udf_extent_t next_sequence;
+	uint8_t reserved[484];
+} __attribute__((packed)) udf_volume_pointer_descriptor_t;
+
+/* Primary Volume Descriptor (ECMA 167 3/10.1) */
+typedef struct udf_primary_volume_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint32_t primary_volume_descriptor_num;
+	udf_dstring volume_id[32];
+	uint16_t max_sequence_number;
+	uint16_t interchange_level;
+	uint16_t max_interchange_level;
+	uint32_t charset_list;
+	uint32_t max_charset_list;
+	udf_dstring volume_set_id[128];
+	udf_charspec_t descriptor_charset;
+	udf_charspec_t explanatory_charset;
+	udf_extent_t volume_abstract;
+	udf_extent_t volume_copyright_notice;
+	udf_regid_t application_id;
+	udf_timestamp_t recording_data_and_time;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[64];
+	uint32_t predecessor_vds_location;
+	uint16_t flags;
+	uint8_t reserved[22];
+} __attribute__((packed)) udf_primary_volume_descriptor_t;
+
+
+/* Partition Descriptor (ECMA 167 3/10.5) */
+typedef struct udf_partition_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint16_t flags;
+	uint16_t number;
+	udf_regid_t contents;
+	uint8_t contents_use[128];
+	uint32_t access_type;
+	uint32_t starting_location;
+	uint32_t length;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[128];
+	uint8_t reserved[156];
+} __attribute__((packed)) udf_partition_descriptor_t;
+
+/* Logical Volume Descriptor (ECMA 167 3/10.6) */
+typedef struct udf_logical_volume_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	udf_charspec_t charset;
+	udf_dstring logical_volume_id[128];
+	uint32_t logical_block_size;
+	udf_regid_t domain_id;
+	uint8_t logical_volume_conents_use[16];
+	uint32_t map_table_length;
+	uint32_t number_of_partitions_maps;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[128];
+	udf_extent_t integrity_sequence_extent;
+	uint8_t partition_map[0];
+} __attribute__((packed)) udf_logical_volume_descriptor_t;
+
+typedef struct udf_volume_descriptor {
+	union {
+		udf_common_descriptor_t common;
+		udf_terminating_descriptor_t terminating;
+		udf_volume_pointer_descriptor_t pointer;
+		udf_partition_descriptor_t partition;
+		udf_logical_volume_descriptor_t logical;
+		udf_unallocated_space_descriptor_t unallocated;
+		udf_primary_volume_descriptor_t volume;
+	};
+} __attribute__((packed)) udf_volume_descriptor_t;
+
+typedef struct udf_general_type {
+	uint8_t partition_map_type;
+	uint8_t partition_map_lenght;
+} __attribute__((packed)) udf_general_type_t;
+
+typedef struct udf_type1_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_lenght;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+} __attribute__((packed)) udf_type1_partition_map_t;
+
+typedef struct udf_type2_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_length;
+	uint8_t reserved1[2];
+	udf_regid_t partition_ident;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+} __attribute__((packed)) udf_type2_partition_map_t;
+
+/* Metadata Partition Map (UDF 2.4.0 2.2.10) */
+typedef struct udf_metadata_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_length;
+	uint8_t reserved1[2];
+	udf_regid_t partition_ident;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+	uint32_t metadata_fileloc;
+	uint32_t metadata_mirror_fileloc;
+	uint32_t metadata_bitmap_fileloc;
+	uint32_t alloc_unit_size;
+	uint16_t align_unit_size;
+	uint8_t flags;
+	uint8_t reserved2[5];
+} __attribute__((packed)) udf_metadata_partition_map_t;
+
+/* Partition Header Descriptor (ECMA 167 4/14.3) */
+typedef struct udf_partition_header_descriptor {
+	udf_short_ad_t unallocated_space_table;
+	udf_short_ad_t unallocated_space_bitmap;
+	udf_short_ad_t partition_integrity_table;
+	udf_short_ad_t freed_space_table;
+	udf_short_ad_t freed_space_bitmap;
+	uint8_t reserved[88];
+} __attribute__((packed)) udf_partition_header_descriptor_t;
+
+extern int udf_volume_recongnition(service_id_t);
+extern int udf_get_anchor_volume_descriptor(service_id_t,
+    udf_anchor_volume_descriptor_t *);
+extern int udf_read_volume_descriptor_sequence(service_id_t, udf_extent_t);
+extern fs_index_t udf_long_ad_to_pos(udf_instance_t *, udf_long_ad_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/hid/console/console.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -37,5 +37,4 @@
 #include <adt/prodcons.h>
 #include <io/input.h>
-#include <ipc/console.h>
 #include <ipc/vfs.h>
 #include <errno.h>
@@ -43,8 +42,8 @@
 #include <loc.h>
 #include <event.h>
+#include <io/con_srv.h>
 #include <io/kbd_event.h>
 #include <io/keycode.h>
 #include <io/chargrid.h>
-#include <io/console.h>
 #include <io/output.h>
 #include <align.h>
@@ -80,4 +79,5 @@
 	chargrid_t *frontbuf;    /**< Front buffer */
 	frontbuf_handle_t fbid;  /**< Front buffer handle */
+	con_srvs_t srvs;         /**< Console service setup */
 } console_t;
 
@@ -114,4 +114,44 @@
 };
 
+static int cons_open(con_srvs_t *, con_srv_t *);
+static int cons_close(con_srv_t *);
+static int cons_read(con_srv_t *, void *, size_t);
+static int cons_write(con_srv_t *, void *, size_t);
+static void cons_sync(con_srv_t *);
+static void cons_clear(con_srv_t *);
+static void cons_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int cons_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int cons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int cons_get_color_cap(con_srv_t *, console_caps_t *);
+static void cons_set_style(con_srv_t *, console_style_t);
+static void cons_set_color(con_srv_t *, console_color_t, console_color_t,
+    console_color_attr_t);
+static void cons_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
+static void cons_set_cursor_visibility(con_srv_t *, bool);
+static int cons_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = cons_open,
+	.close = cons_close,
+	.read = cons_read,
+	.write = cons_write,
+	.sync = cons_sync,
+	.clear = cons_clear,
+	.set_pos = cons_set_pos,
+	.get_pos = cons_get_pos,
+	.get_size = cons_get_size,
+	.get_color_cap = cons_get_color_cap,
+	.set_style = cons_set_style,
+	.set_color = cons_set_color,
+	.set_rgb_color = cons_set_rgb_color,
+	.set_cursor_visibility = cons_set_cursor_visibility,
+	.get_event = cons_get_event
+};
+
+static console_t *srv_to_console(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
+
 static void cons_update(console_t *cons)
 {
@@ -138,13 +178,4 @@
 	fibril_mutex_unlock(&cons->mtx);
 	fibril_mutex_unlock(&switch_mtx);
-}
-
-static void cons_clear(console_t *cons)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_clear(cons->frontbuf);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	cons_update(cons);
 }
 
@@ -288,8 +319,8 @@
 }
 
-static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_set_cursor(cons->frontbuf, col, row);
+static void cons_set_cursor_vis(console_t *cons, bool visible)
+{
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_set_cursor_visibility(cons->frontbuf, visible);
 	fibril_mutex_unlock(&cons->mtx);
 	
@@ -297,61 +328,18 @@
 }
 
-static void cons_set_cursor_visibility(console_t *cons, bool visible)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_set_cursor_visibility(cons->frontbuf, visible);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	cons_update_cursor(cons);
-}
-
-static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	sysarg_t col;
-	sysarg_t row;
-	
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_get_cursor(cons->frontbuf, &col, &row);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	async_answer_2(iid, EOK, col, row);
-}
-
-static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	void *buf;
-	size_t size;
-	int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
-	
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	size_t off = 0;
-	while (off < size)
-		cons_write_char(cons, str_decode(buf, &off, size));
-	
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	char *buf = (char *) malloc(size);
-	if (buf == NULL) {
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
+static int cons_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int cons_close(con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int cons_read(con_srv_t *srv, void *buf, size_t size)
+{
+	uint8_t *bbuf = buf;
+	console_t *cons = srv_to_console(srv);
 	size_t pos = 0;
 	
@@ -364,5 +352,5 @@
 		/* Copy to the buffer remaining characters. */
 		while ((pos < size) && (cons->char_remains_len > 0)) {
-			buf[pos] = cons->char_remains[0];
+			bbuf[pos] = cons->char_remains[0];
 			pos++;
 			
@@ -389,12 +377,85 @@
 		}
 	}
-	
-	(void) async_data_read_finalize(callid, buf, size);
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void cons_set_style(console_t *cons, console_style_t style)
-{
+
+	return size;
+}
+
+static int cons_write(con_srv_t *srv, void *data, size_t size)
+{
+	console_t *cons = srv_to_console(srv);
+
+	size_t off = 0;
+	while (off < size)
+		cons_write_char(cons, str_decode(data, &off, size));
+	return size;
+}
+
+static void cons_sync(con_srv_t *srv)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	cons_update(cons);
+}
+
+static void cons_clear(con_srv_t *srv)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_clear(cons->frontbuf);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	cons_update(cons);
+}
+
+static void cons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_set_cursor(cons->frontbuf, col, row);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	cons_update_cursor(cons);
+}
+
+static int cons_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_get_cursor(cons->frontbuf, col, row);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static int cons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	*cols = cons->cols;
+	*rows = cons->rows;
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static int cons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	*ccaps = cons->ccaps;
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static void cons_set_style(con_srv_t *srv, console_style_t style)
+{
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_style(cons->frontbuf, style);
@@ -402,7 +463,9 @@
 }
 
-static void cons_set_color(console_t *cons, console_color_t bgcolor,
+static void cons_set_color(con_srv_t *srv, console_color_t bgcolor,
     console_color_t fgcolor, console_color_attr_t attr)
 {
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
@@ -410,7 +473,9 @@
 }
 
-static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
+static void cons_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
     pixel_t fgcolor)
 {
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
@@ -418,11 +483,20 @@
 }
 
-static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
+static void cons_set_cursor_visibility(con_srv_t *srv, bool visible)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	cons_set_cursor_vis(cons, visible);
+}
+
+static int cons_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	console_t *cons = srv_to_console(srv);
 	link_t *link = prodcons_consume(&cons->input_pc);
-	kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-	
-	async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
-	free(event);
+	kbd_event_t *kevent = list_get_instance(link, kbd_event_t, link);
+	
+	*event = *kevent;
+	free(kevent);
+	return EOK;
 }
 
@@ -447,69 +521,9 @@
 	
 	if (atomic_postinc(&cons->refcnt) == 0)
-		cons_set_cursor_visibility(cons, true);
-	
-	/* Accept the connection */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_READ:
-			cons_read(cons, callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			cons_write(cons, callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			cons_update(cons);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			cons_clear(cons);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GOTO:
-			cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_POS:
-			cons_get_cursor(cons, callid, &call);
-			break;
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, cons->cols, cons->rows);
-			break;
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, cons->ccaps);
-			break;
-		case CONSOLE_SET_STYLE:
-			cons_set_style(cons, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_COLOR:
-			cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
-			    IPC_GET_ARG3(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CURSOR_VISIBILITY:
-			cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_EVENT:
-			cons_get_event(cons, callid, &call);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
-}
+		cons_set_cursor_vis(cons, true);
+	
+	con_conn(iid, icall, &cons->srvs);
+}
+
 
 static int input_connect(const char *svc)
@@ -624,4 +638,8 @@
 		}
 		
+		con_srvs_init(&consoles[i].srvs);
+		consoles[i].srvs.ops = &con_ops;
+		consoles[i].srvs.sarg = &consoles[i];
+		
 		char vc[LOC_NAME_MAXLEN + 1];
 		snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
Index: uspace/srv/hid/remcons/remcons.c
===================================================================
--- uspace/srv/hid/remcons/remcons.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/hid/remcons/remcons.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -34,10 +34,8 @@
 
 #include <async.h>
+#include <errno.h>
+#include <io/con_srv.h>
 #include <stdio.h>
-#include <adt/prodcons.h>
-#include <ipc/input.h>
-#include <ipc/console.h>
-#include <ipc/vfs.h>
-#include <errno.h>
+#include <stdlib.h>
 #include <str_error.h>
 #include <loc.h>
@@ -45,6 +43,4 @@
 #include <io/keycode.h>
 #include <align.h>
-#include <malloc.h>
-#include <as.h>
 #include <fibril_synch.h>
 #include <task.h>
@@ -75,116 +71,131 @@
     sizeof(telnet_force_character_mode_command) / sizeof(telnet_cmd_t);
 
-
-/** Handling client requests (VFS and console interface).
- *
- * @param user Telnet user the requests belong to.
- */
-static void client_connection_message_loop(telnet_user_t *user)
-{
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = 0;
-
-		/*
-		 * The getterm task might terminate while we are here,
-		 * waiting for a call. Also, the socket might be closed
-		 * meanwhile.
-		 * We want to detect this situation early, so we use a
-		 * timeout variant of async_get_call().
-		 */
-		while (callid == 0) {
-			callid = async_get_call_timeout(&call, 1000);
-
-			if (telnet_user_is_zombie(user)) {
-				if (callid != 0) {
-					async_answer_0(callid, EINTR);
-				}
-				return;
-			}
-		}
-		
-		if (!IPC_GET_IMETHOD(call)) {
-			return;
-		}
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, 100, 1);
-			break;
-		case CONSOLE_GET_POS:
-			fibril_mutex_lock(&user->guard);
-			async_answer_2(callid, EOK, user->cursor_x, 0);
-			fibril_mutex_unlock(&user->guard);
-			break;
-		case CONSOLE_GET_EVENT: {
-			kbd_event_t event;
-			int rc = telnet_user_get_next_keyboard_event(user, &event);
-			if (rc != EOK) {
-				/* Silently ignore. */
-				async_answer_0(callid, EOK);
-				break;
-			}
-			async_answer_4(callid, EOK, event.type, event.key, event.mods, event.c);
-			break;
-		}
-		case CONSOLE_GOTO: {
-			int new_x = IPC_GET_ARG1(call);
-			telnet_user_update_cursor_x(user, new_x);
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-		case VFS_OUT_READ:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case VFS_OUT_WRITE: {
-			uint8_t *buf;
-			size_t size;
-			int rc = async_data_write_accept((void **)&buf, false, 0, 0, 0, &size);
-
-			if (rc != EOK) {
-				async_answer_0(callid, rc);
-				break;
-			}
-
-			rc = telnet_user_send_data(user, buf, size);
-			free(buf);
-
-			if (rc != EOK) {
-				async_answer_0(callid, rc);
-				break;
-			}
-
-			async_answer_1(callid, EOK, size);
-			break;
-		}
-		case VFS_OUT_SYNC:
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			async_answer_0(callid, EOK);
-			break;
-
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, CONSOLE_CAP_NONE);
-			break;
-		case CONSOLE_SET_STYLE:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case CONSOLE_SET_COLOR:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			async_answer_0(callid, ENOTSUP);
-			break;
-
-		case CONSOLE_CURSOR_VISIBILITY:
-			async_answer_0(callid, ENOTSUP);
-			break;
-
-		default:
-			async_answer_0(callid, EINVAL);
-			break;
-		}
-	}
+static int remcons_open(con_srvs_t *, con_srv_t *);
+static int remcons_close(con_srv_t *);
+static int remcons_write(con_srv_t *, void *, size_t);
+static void remcons_sync(con_srv_t *);
+static void remcons_clear(con_srv_t *);
+static void remcons_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int remcons_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int remcons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int remcons_get_color_cap(con_srv_t *, console_caps_t *);
+static int remcons_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = remcons_open,
+	.close = remcons_close,
+	.read = NULL,
+	.write = remcons_write,
+	.sync = remcons_sync,
+	.clear = remcons_clear,
+	.set_pos = remcons_set_pos,
+	.get_pos = remcons_get_pos,
+	.get_size = remcons_get_size,
+	.get_color_cap = remcons_get_color_cap,
+	.set_style = NULL,
+	.set_color = NULL,
+	.set_rgb_color = NULL,
+	.set_cursor_visibility = NULL,
+	.get_event = remcons_get_event
+};
+
+static telnet_user_t *srv_to_user(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
+
+static int remcons_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_log(user, "New client connected (%p).", srv);
+
+	/* Force character mode. */
+	send(user->socket, (void *)telnet_force_character_mode_command,
+	    telnet_force_character_mode_command_count, 0);
+
+	return EOK;
+}
+
+static int remcons_close(con_srv_t *srv)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_notify_client_disconnected(user);
+	telnet_user_log(user, "Client disconnected (%p).", srv);
+
+	return EOK;
+}
+
+static int remcons_write(con_srv_t *srv, void *data, size_t size)
+{
+	telnet_user_t *user = srv_to_user(srv);
+	int rc;
+
+	rc = telnet_user_send_data(user, data, size);
+	if (rc != EOK)
+		return rc;
+
+	return size;
+}
+
+static void remcons_sync(con_srv_t *srv)
+{
+	(void) srv;
+}
+
+static void remcons_clear(con_srv_t *srv)
+{
+	(void) srv;
+}
+
+static void remcons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_update_cursor_x(user, col);
+}
+
+static int remcons_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	*col = user->cursor_x;
+	*row = 0;
+
+	return EOK;
+}
+
+static int remcons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	(void) srv;
+
+	*cols = 100;
+	*rows = 1;
+
+	return EOK;
+}
+
+static int remcons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
+{
+	(void) srv;
+	*ccaps = CONSOLE_CAP_NONE;
+
+	return EOK;
+}
+
+static int remcons_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	telnet_user_t *user = srv_to_user(srv);
+	int rc;
+
+	rc = telnet_user_get_next_keyboard_event(user, event);
+	if (rc != EOK) {
+		/* XXX What? */
+		memset(event, 0, sizeof(*event));
+		return EOK;
+	}
+
+	return EOK;
 }
 
@@ -198,17 +209,7 @@
 		return;
 	}
-	async_answer_0(iid, EOK);
-
-	telnet_user_log(user, "New client connected (%" PRIxn").", iid);
-
-	/* Force character mode. */
-	send(user->socket, (void *)telnet_force_character_mode_command,
-	    telnet_force_character_mode_command_count, 0);
 
 	/* Handle messages. */
-	client_connection_message_loop(user);
-
-	telnet_user_notify_client_disconnected(user);
-	telnet_user_log(user, "Client disconnected (%" PRIxn").", iid);
+	con_conn(iid, icall, &user->srvs);
 }
 
@@ -232,4 +233,5 @@
 		fibril_mutex_lock(&user->guard);
 		user->task_finished = true;
+		user->srvs.aborted = true;
 		fibril_condvar_signal(&user->refcount_cv);
 		fibril_mutex_unlock(&user->guard);
@@ -251,4 +253,5 @@
 	fibril_mutex_lock(&user->guard);
 	user->task_finished = true;
+	user->srvs.aborted = true;
 	fibril_condvar_signal(&user->refcount_cv);
 	fibril_mutex_unlock(&user->guard);
@@ -295,4 +298,5 @@
 			closesocket(user->socket);
 			user->socket_closed = true;
+			user->srvs.aborted = true;
 			continue;
 		} else if (user->socket_closed) {
@@ -380,4 +384,11 @@
 		assert(user);
 
+		con_srvs_init(&user->srvs);
+		user->srvs.ops = &con_ops;
+		user->srvs.sarg = user;
+		user->srvs.abort_timeout = 1000;
+
+		telnet_user_add(user);
+
 		fid_t fid = fibril_create(network_user_fibril, user);
 		assert(fid);
Index: uspace/srv/hid/remcons/user.c
===================================================================
--- uspace/srv/hid/remcons/user.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/hid/remcons/user.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -35,7 +35,4 @@
 #include <stdio.h>
 #include <adt/prodcons.h>
-#include <ipc/input.h>
-#include <ipc/console.h>
-#include <ipc/vfs.h>
 #include <errno.h>
 #include <str_error.h>
@@ -95,12 +92,14 @@
 	user->locsrv_connection_count = 0;
 
-
+	user->cursor_x = 0;
+
+	return user;
+}
+
+void telnet_user_add(telnet_user_t *user)
+{
 	fibril_mutex_lock(&users_guard);
 	list_append(&user->link, &users);
 	fibril_mutex_unlock(&users_guard);
-
-	user->cursor_x = 0;
-
-	return user;
 }
 
@@ -199,4 +198,5 @@
 		if ((recv_length == 0) || (recv_length == ENOTCONN)) {
 			user->socket_closed = true;
+			user->srvs.aborted = true;
 			return ENOENT;
 		}
Index: uspace/srv/hid/remcons/user.h
===================================================================
--- uspace/srv/hid/remcons/user.h	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/hid/remcons/user.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -36,6 +36,8 @@
 #define TELNET_USER_H_
 
+#include <adt/prodcons.h>
 #include <fibril_synch.h>
 #include <inttypes.h>
+#include <io/con_srv.h>
 #include "remcons.h"
 
@@ -55,4 +57,6 @@
 	/** Path name of the service. */
 	char *service_name;
+	/** Console service setup */
+	con_srvs_t srvs;
 
 	/** Producer-consumer of kbd_event_t. */
@@ -77,4 +81,5 @@
 
 extern telnet_user_t *telnet_user_create(int);
+extern void telnet_user_add(telnet_user_t *);
 extern void telnet_user_destroy(telnet_user_t *);
 extern telnet_user_t *telnet_user_get_for_client_connection(service_id_t);
Index: uspace/srv/locsrv/locsrv.c
===================================================================
--- uspace/srv/locsrv/locsrv.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/locsrv/locsrv.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -1353,4 +1353,7 @@
 	categ_dir_add_cat(&cdir, cat);
 
+	cat = category_new("clock");
+	categ_dir_add_cat(&cdir, cat);
+
 	cat = category_new("test3");
 	categ_dir_add_cat(&cdir, cat);
Index: uspace/srv/logger/Makefile
===================================================================
--- uspace/srv/logger/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/logger/Makefile	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2012 Vojtech Horky
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = logger
+STATIC_NEEDED = y
+
+SOURCES = \
+	ctl.c \
+	initlvl.c \
+	level.c \
+	logs.c \
+	main.c \
+	writer.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/logger/ctl.c
===================================================================
--- uspace/srv/logger/ctl.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/logger/ctl.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+
+/** @file
+ */
+
+#include <unistd.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <errno.h>
+#include <io/logctl.h>
+#include <ipc/logger.h>
+#include "logger.h"
+
+static int handle_log_level_change(sysarg_t new_level)
+{
+	void *full_name;
+	int rc = async_data_write_accept(&full_name, true, 0, 0, 0, NULL);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	logger_log_t *log = find_log_by_name_and_lock(full_name);
+	free(full_name);
+	if (log == NULL)
+		return ENOENT;
+
+	log->logged_level = new_level;
+
+	log_unlock(log);
+
+	return EOK;
+}
+
+void logger_connection_handler_control(ipc_callid_t callid)
+{
+	async_answer_0(callid, EOK);
+	logger_log("control: new client.\n");
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call))
+			break;
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOGGER_CONTROL_SET_DEFAULT_LEVEL: {
+			int rc = set_default_logging_level(IPC_GET_ARG1(call));
+			async_answer_0(callid, rc);
+			break;
+		}
+		case LOGGER_CONTROL_SET_LOG_LEVEL: {
+			int rc = handle_log_level_change(IPC_GET_ARG1(call));
+			async_answer_0(callid, rc);
+			break;
+		}
+		default:
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+	}
+
+	logger_log("control: client terminated.\n");
+}
+
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/initlvl.c
===================================================================
--- uspace/srv/logger/initlvl.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/logger/initlvl.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+
+/** @file
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <sysinfo.h>
+#include <str.h>
+#include "logger.h"
+
+static void parse_single_level_setting(char *setting)
+{
+	char *tmp;
+	char *key = strtok_r(setting, "=", &tmp);
+	char *value = strtok_r(NULL, "=", &tmp);
+	if (key == NULL)
+		return;
+	if (value == NULL) {
+		log_level_t level;
+		int rc = log_level_from_str(key, &level);
+		if (rc != EOK)
+			return;
+		set_default_logging_level(level);
+		return;
+	}
+
+
+	log_level_t level;
+	int rc = log_level_from_str(value, &level);
+	if (rc != EOK)
+		return;
+
+	logger_log_t *log = find_or_create_log_and_lock(key, 0);
+	if (log == NULL)
+		return;
+
+	log->logged_level = level;
+	log->ref_counter++;
+
+	log_unlock(log);
+}
+
+void parse_level_settings(char *settings)
+{
+	char *tmp;
+	char *single_setting = strtok_r(settings, " ", &tmp);
+	while (single_setting != NULL) {
+		parse_single_level_setting(single_setting);
+		single_setting = strtok_r(NULL, " ", &tmp);
+	}
+}
+
+void parse_initial_settings(void)
+{
+	size_t argument_size;
+	void *argument = sysinfo_get_data("init_args.logger", &argument_size);
+	if (argument == NULL)
+		return;
+
+	char level_str[200];
+	str_cpy(level_str, 200, (const char *) argument);
+
+	parse_level_settings(level_str);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/level.c
===================================================================
--- uspace/srv/logger/level.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/logger/level.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+
+/** @file
+ */
+
+#include <errno.h>
+#include "logger.h"
+
+log_level_t default_logging_level = LVL_NOTE;
+static FIBRIL_MUTEX_INITIALIZE(default_logging_level_guard);
+
+log_level_t get_default_logging_level(void)
+{
+	fibril_mutex_lock(&default_logging_level_guard);
+	log_level_t result = default_logging_level;
+	fibril_mutex_unlock(&default_logging_level_guard);
+	return result;
+}
+
+int set_default_logging_level(log_level_t new_level)
+{
+	if (new_level >= LVL_LIMIT)
+		return ERANGE;
+	fibril_mutex_lock(&default_logging_level_guard);
+	default_logging_level = new_level;
+	fibril_mutex_unlock(&default_logging_level_guard);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/logger.h
===================================================================
--- uspace/srv/logger/logger.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/logger/logger.h	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+/** @file Common logger service definitions.
+ */
+
+#ifndef LOGGER_H_
+#define LOGGER_H_
+
+#include <adt/list.h>
+#include <adt/prodcons.h>
+#include <io/log.h>
+#include <async.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <stdio.h>
+
+#define NAME "logger"
+#define LOG_LEVEL_USE_DEFAULT (LVL_LIMIT + 1)
+
+#ifdef LOGGER_LOG
+#define logger_log(fmt, ...) printf(NAME ": " fmt, ##__VA_ARGS__)
+#else
+#define logger_log(fmt, ...) (void)0
+#endif
+
+typedef struct logger_log logger_log_t;
+
+typedef struct {
+	fibril_mutex_t guard;
+	char *filename;
+	FILE *logfile;
+} logger_dest_t;
+
+struct logger_log {
+	link_t link;
+
+	size_t ref_counter;
+
+	fibril_mutex_t guard;
+
+	char *name;
+	char *full_name;
+	logger_log_t *parent;
+	log_level_t logged_level;
+	logger_dest_t *dest;
+};
+
+#define MAX_REFERENCED_LOGS_PER_CLIENT 100
+
+typedef struct {
+	size_t logs_count;
+	logger_log_t *logs[MAX_REFERENCED_LOGS_PER_CLIENT];
+} logger_registered_logs_t;
+
+logger_log_t *find_log_by_name_and_lock(const char *name);
+logger_log_t *find_or_create_log_and_lock(const char *, sysarg_t);
+logger_log_t *find_log_by_id_and_lock(sysarg_t);
+bool shall_log_message(logger_log_t *, log_level_t);
+void log_unlock(logger_log_t *);
+void write_to_log(logger_log_t *, log_level_t, const char *);
+void log_release(logger_log_t *);
+
+void registered_logs_init(logger_registered_logs_t *);
+bool register_log(logger_registered_logs_t *, logger_log_t *);
+void unregister_logs(logger_registered_logs_t *);
+
+log_level_t get_default_logging_level(void);
+int set_default_logging_level(log_level_t);
+
+
+void logger_connection_handler_control(ipc_callid_t);
+void logger_connection_handler_writer(ipc_callid_t);
+
+void parse_initial_settings(void);
+void parse_level_settings(char *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/logger/logs.c
===================================================================
--- uspace/srv/logger/logs.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/logger/logs.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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 logger
+ * @{
+ */
+#include <assert.h>
+#include <malloc.h>
+#include <str.h>
+#include <stdio.h>
+#include <errno.h>
+#include "logger.h"
+
+
+static FIBRIL_MUTEX_INITIALIZE(log_list_guard);
+static LIST_INITIALIZE(log_list);
+
+
+static logger_log_t *find_log_by_name_and_parent_no_list_lock(const char *name, logger_log_t *parent)
+{
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if ((parent == log->parent) && (str_cmp(log->name, name) == 0))
+			return log;
+	}
+
+	return NULL;
+}
+
+static int create_dest(const char *name, logger_dest_t **dest)
+{
+	logger_dest_t *result = malloc(sizeof(logger_dest_t));
+	if (result == NULL)
+		return ENOMEM;
+	int rc = asprintf(&result->filename, "/log/%s", name);
+	if (rc < 0) {
+		free(result);
+		return ENOMEM;
+	}
+	result->logfile = NULL;
+	fibril_mutex_initialize(&result->guard);
+	*dest = result;
+	return EOK;
+}
+
+static logger_log_t *create_log_no_locking(const char *name, logger_log_t *parent)
+{
+	logger_log_t *result = calloc(1, sizeof(logger_log_t));
+	if (result == NULL)
+		return NULL;
+
+	result->name = str_dup(name);
+	if (result->name == NULL)
+		goto error;
+
+	/*
+	 * Notice that we create new dest as the last
+	 * operation that can fail and thus there is no code
+	 * to deallocate dest.
+	 */
+	if (parent == NULL) {
+		result->full_name = str_dup(name);
+		if (result->full_name == NULL)
+			goto error;
+		int rc = create_dest(name, &result->dest);
+		if (rc != EOK)
+			goto error;
+	} else {
+		int rc = asprintf(&result->full_name, "%s/%s",
+		    parent->full_name, name);
+		if (rc < 0)
+			goto error;
+		result->dest = parent->dest;
+	}
+
+	/* Following initializations cannot fail. */
+	result->logged_level = LOG_LEVEL_USE_DEFAULT;
+	fibril_mutex_initialize(&result->guard);
+	link_initialize(&result->link);
+	result->parent = parent;
+
+	return result;
+
+error:
+	free(result->name);
+	free(result->full_name);
+	free(result);
+	return NULL;
+
+}
+
+logger_log_t *find_or_create_log_and_lock(const char *name, sysarg_t parent_id)
+{
+	logger_log_t *result = NULL;
+	logger_log_t *parent = (logger_log_t *) parent_id;
+
+	fibril_mutex_lock(&log_list_guard);
+
+	result = find_log_by_name_and_parent_no_list_lock(name, parent);
+	if (result == NULL) {
+		result = create_log_no_locking(name, parent);
+		if (result == NULL)
+			goto leave;
+		list_append(&result->link, &log_list);
+		if (result->parent != NULL) {
+			fibril_mutex_lock(&result->parent->guard);
+			result->parent->ref_counter++;
+			fibril_mutex_unlock(&result->parent->guard);
+		}
+	}
+
+	fibril_mutex_lock(&result->guard);
+
+leave:
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+logger_log_t *find_log_by_name_and_lock(const char *name)
+{
+	logger_log_t *result = NULL;
+
+	fibril_mutex_lock(&log_list_guard);
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if (str_cmp(log->full_name, name) == 0) {
+			fibril_mutex_lock(&log->guard);
+			result = log;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+logger_log_t *find_log_by_id_and_lock(sysarg_t id)
+{
+	logger_log_t *result = NULL;
+
+	fibril_mutex_lock(&log_list_guard);
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if ((sysarg_t) log == id) {
+			fibril_mutex_lock(&log->guard);
+			result = log;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+static log_level_t get_actual_log_level(logger_log_t *log)
+{
+	/* Find recursively proper log level. */
+	if (log->logged_level == LOG_LEVEL_USE_DEFAULT) {
+		if (log->parent == NULL)
+			return get_default_logging_level();
+		else
+			return get_actual_log_level(log->parent);
+	}
+	return log->logged_level;
+}
+
+bool shall_log_message(logger_log_t *log, log_level_t level)
+{
+	fibril_mutex_lock(&log_list_guard);
+	bool result = level <= get_actual_log_level(log);
+	fibril_mutex_unlock(&log_list_guard);
+	return result;
+}
+
+void log_unlock(logger_log_t *log)
+{
+	assert(fibril_mutex_is_locked(&log->guard));
+	fibril_mutex_unlock(&log->guard);
+}
+
+/** Decreases reference counter on the log and destory the log if
+ * necessary.
+ *
+ * Precondition: log is locked.
+ *
+ * @param log Log to release from using by the caller.
+ */
+void log_release(logger_log_t *log)
+{
+	assert(fibril_mutex_is_locked(&log->guard));
+	assert(log->ref_counter > 0);
+
+	/* We are definitely not the last ones. */
+	if (log->ref_counter > 1) {
+		log->ref_counter--;
+		fibril_mutex_unlock(&log->guard);
+		return;
+	}
+
+	/*
+	 * To prevent deadlock, we need to get the list lock first.
+	 * Deadlock scenario:
+	 * Us: LOCKED(log), want to LOCK(list)
+	 * Someone else calls find_log_by_name_and_lock(log->fullname) ->
+	 *   LOCKED(list), wants to LOCK(log)
+	 */
+	fibril_mutex_unlock(&log->guard);
+
+	/* Ensuring correct locking order. */
+	fibril_mutex_lock(&log_list_guard);
+	/*
+	 * The reference must be still valid because we have not decreased
+	 * the reference counter.
+	 */
+	fibril_mutex_lock(&log->guard);
+	assert(log->ref_counter > 0);
+	log->ref_counter--;
+
+	if (log->ref_counter > 0) {
+		/*
+		 * Meanwhile, someone else increased the ref counter.
+		 * No big deal, we just return immediatelly.
+		 */
+		fibril_mutex_unlock(&log->guard);
+		fibril_mutex_unlock(&log_list_guard);
+		return;
+	}
+
+	/*
+	 * Here we are on a destroy path. We need to
+	 * - remove ourselves from the list
+	 * - decrease reference of the parent (if not top-level log)
+	 *   - we must do that after we relaase list lock to prevent
+	 *     deadlock with ourselves
+	 * - destroy dest (if top-level log)
+	 */
+	assert(log->ref_counter == 0);
+
+	list_remove(&log->link);
+	fibril_mutex_unlock(&log_list_guard);
+	fibril_mutex_unlock(&log->guard);
+
+	if (log->parent == NULL) {
+		fclose(log->dest->logfile);
+		free(log->dest->filename);
+		free(log->dest);
+	} else {
+		fibril_mutex_lock(&log->parent->guard);
+		log_release(log->parent);
+	}
+
+	logger_log("Destroyed log %s.\n", log->full_name);
+
+	free(log->name);
+	free(log->full_name);
+
+	free(log);
+}
+
+
+void write_to_log(logger_log_t *log, log_level_t level, const char *message)
+{
+	assert(fibril_mutex_is_locked(&log->guard));
+	assert(log->dest != NULL);
+	fibril_mutex_lock(&log->dest->guard);
+	if (log->dest->logfile == NULL)
+		log->dest->logfile = fopen(log->dest->filename, "a");
+
+	if (log->dest->logfile != NULL) {
+		fprintf(log->dest->logfile, "[%s] %s: %s\n",
+		    log->full_name, log_level_str(level),
+		    (const char *) message);
+		fflush(log->dest->logfile);
+	}
+
+	fibril_mutex_unlock(&log->dest->guard);
+}
+
+void registered_logs_init(logger_registered_logs_t *logs)
+{
+	logs->logs_count = 0;
+}
+
+bool register_log(logger_registered_logs_t *logs, logger_log_t *new_log)
+{
+	if (logs->logs_count >= MAX_REFERENCED_LOGS_PER_CLIENT) {
+		return false;
+	}
+
+	assert(fibril_mutex_is_locked(&new_log->guard));
+	new_log->ref_counter++;
+
+	logs->logs[logs->logs_count] = new_log;
+	logs->logs_count++;
+
+	return true;
+}
+
+void unregister_logs(logger_registered_logs_t *logs)
+{
+	for (size_t i = 0; i < logs->logs_count; i++) {
+		logger_log_t *log = logs->logs[i];
+		fibril_mutex_lock(&log->guard);
+		log_release(log);
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/main.c
===================================================================
--- uspace/srv/logger/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/logger/main.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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.
+ */
+
+/**
+ * @defgroup logger Logging service.
+ * @brief HelenOS logging service.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <ipc/services.h>
+#include <ipc/logger.h>
+#include <io/log.h>
+#include <io/logctl.h>
+#include <ns.h>
+#include <async.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <malloc.h>
+#include "logger.h"
+
+static void connection_handler(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	logger_interface_t iface = IPC_GET_ARG1(*icall);
+
+	switch (iface) {
+	case LOGGER_INTERFACE_CONTROL:
+		logger_connection_handler_control(iid);
+		break;
+	case LOGGER_INTERFACE_WRITER:
+		logger_connection_handler_writer(iid);
+		break;
+	default:
+		async_answer_0(iid, EINVAL);
+		break;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS Logging Service\n");
+	
+	parse_initial_settings();
+	for (int i = 1; i < argc; i++) {
+		parse_level_settings(argv[i]);
+	}
+
+	async_set_client_connection(connection_handler);
+	
+	int rc = service_register(SERVICE_LOGGER);
+	if (rc != EOK) {
+		printf(NAME ": failed to register: %s.\n", str_error(rc));
+		return -1;
+	}
+	
+	printf(NAME ": Accepting connections\n");
+	async_manager();
+	
+	/* Never reached */
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/writer.c
===================================================================
--- uspace/srv/logger/writer.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
+++ uspace/srv/logger/writer.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * 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.
+ */
+
+/**
+ * @defgroup logger Logging service.
+ * @brief HelenOS logging service.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <ipc/services.h>
+#include <ipc/logger.h>
+#include <io/log.h>
+#include <io/logctl.h>
+#include <ns.h>
+#include <async.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <malloc.h>
+#include "logger.h"
+
+
+static logger_log_t *handle_create_log(sysarg_t parent)
+{
+	void *name;
+	int rc = async_data_write_accept(&name, true, 1, 0, 0, NULL);
+	if (rc != EOK)
+		return NULL;
+
+	logger_log_t *log = find_or_create_log_and_lock(name, parent);
+
+	free(name);
+
+	return log;
+}
+
+static int handle_receive_message(sysarg_t log_id, sysarg_t level)
+{
+	logger_log_t *log = find_log_by_id_and_lock(log_id);
+	if (log == NULL)
+		return ENOENT;
+
+	void *message = NULL;
+	int rc = async_data_write_accept(&message, true, 1, 0, 0, NULL);
+	if (rc != EOK)
+		goto leave;
+
+	if (!shall_log_message(log, level)) {
+		rc = EOK;
+		goto leave;
+	}
+
+	printf("[%s] %s: %s\n",
+	    log->full_name, log_level_str(level),
+	    (const char *) message);
+	write_to_log(log, level, message);
+
+	rc = EOK;
+
+leave:
+	log_unlock(log);
+	free(message);
+
+	return rc;
+}
+
+void logger_connection_handler_writer(ipc_callid_t callid)
+{
+	/* Acknowledge the connection. */
+	async_answer_0(callid, EOK);
+
+	logger_log("writer: new client.\n");
+
+	logger_registered_logs_t registered_logs;
+	registered_logs_init(&registered_logs);
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call))
+			break;
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOGGER_WRITER_CREATE_LOG: {
+			logger_log_t *log = handle_create_log(IPC_GET_ARG1(call));
+			if (log == NULL) {
+				async_answer_0(callid, ENOMEM);
+				break;
+			}
+			if (!register_log(&registered_logs, log)) {
+				log_unlock(log);
+				async_answer_0(callid, ELIMIT);
+				break;
+			}
+			log_unlock(log);
+			async_answer_1(callid, EOK, (sysarg_t) log);
+			break;
+		}
+		case LOGGER_WRITER_MESSAGE: {
+			int rc = handle_receive_message(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			async_answer_0(callid, rc);
+			break;
+		}
+		default:
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+	}
+
+	unregister_logs(&registered_logs);
+	logger_log("writer: client terminated.\n");
+}
+
+
+/**
+ * @}
+ */
Index: uspace/srv/net/ethip/arp.c
===================================================================
--- uspace/srv/net/ethip/arp.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/ethip/arp.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -59,5 +59,5 @@
 	ethip_link_addr_t *laddr;
 
-	log_msg(LVL_DEBUG, "arp_received()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "arp_received()");
 
 	rc = arp_pdu_decode(frame->data, frame->size, &packet);
@@ -65,10 +65,10 @@
 		return;
 
-	log_msg(LVL_DEBUG, "ARP PDU decoded, opcode=%d, tpa=%x",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ARP PDU decoded, opcode=%d, tpa=%x",
 	    packet.opcode, packet.target_proto_addr.ipv4);
 
 	laddr = ethip_nic_addr_find(nic, &packet.target_proto_addr);
 	if (laddr != NULL) {
-		log_msg(LVL_DEBUG, "Request/reply to my address");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Request/reply to my address");
 
 		(void) atrans_add(&packet.sender_proto_addr,
@@ -122,5 +122,5 @@
 	size_t fsize;
 
-	log_msg(LVL_DEBUG, "arp_send_packet()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "arp_send_packet()");
 
 	rc = arp_pdu_encode(packet, &pdata, &psize);
Index: uspace/srv/net/ethip/ethip.c
===================================================================
--- uspace/srv/net/ethip/ethip.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/ethip/ethip.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -77,5 +77,5 @@
 	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering server.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
 		return rc;
 	}
@@ -96,5 +96,5 @@
 	char *svc_name = NULL;
 
-	log_msg(LVL_DEBUG, "ethip_iplink_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_iplink_init()");
 
 	iplink_srv_init(&nic->iplink);
@@ -104,5 +104,5 @@
 	rc = asprintf(&svc_name, "net/eth%u", ++link_num);
 	if (rc < 0) {
-		log_msg(LVL_ERROR, "Out of memory.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Out of memory.");
 		goto error;
 	}
@@ -110,5 +110,5 @@
 	rc = loc_service_register(svc_name, &sid);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service %s.", svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service %s.", svc_name);
 		goto error;
 	}
@@ -118,5 +118,5 @@
 	rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed resolving category 'iplink'.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
 		goto error;
 	}
@@ -124,5 +124,5 @@
 	rc = loc_service_add_to_cat(sid, iplink_cat);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed adding %s to category.", svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding %s to category.", svc_name);
 		goto error;
 	}
@@ -142,8 +142,8 @@
 
 	sid = (service_id_t)IPC_GET_ARG1(*icall);
-	log_msg(LVL_DEBUG, "ethip_client_conn(%u)", (unsigned)sid);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_client_conn(%u)", (unsigned)sid);
 	nic = ethip_nic_find_by_iplink_sid(sid);
 	if (nic == NULL) {
-		log_msg(LVL_WARN, "Uknown service ID.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Uknown service ID.");
 		return;
 	}
@@ -154,5 +154,5 @@
 static int ethip_open(iplink_srv_t *srv)
 {
-	log_msg(LVL_DEBUG, "ethip_open()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_open()");
 	return EOK;
 }
@@ -160,5 +160,5 @@
 static int ethip_close(iplink_srv_t *srv)
 {
-	log_msg(LVL_DEBUG, "ethip_close()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_close()");
 	return EOK;
 }
@@ -173,9 +173,9 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "ethip_send()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_send()");
 
 	rc = arp_translate(nic, &sdu->lsrc, &sdu->ldest, &dest_mac_addr);
 	if (rc != EOK) {
-		log_msg(LVL_WARN, "Failed to look up IP address 0x%" PRIx32,
+		log_msg(LOG_DEFAULT, LVL_WARN, "Failed to look up IP address 0x%" PRIx32,
 		    sdu->ldest.ipv4);
 		return rc;
@@ -200,5 +200,5 @@
 int ethip_received(iplink_srv_t *srv, void *data, size_t size)
 {
-	log_msg(LVL_DEBUG, "ethip_received(): srv=%p", srv);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_received(): srv=%p", srv);
 	ethip_nic_t *nic = (ethip_nic_t *)srv->arg;
 	eth_frame_t frame;
@@ -206,10 +206,10 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "ethip_received()");
-
-	log_msg(LVL_DEBUG, " - eth_pdu_decode");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_received()");
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - eth_pdu_decode");
 	rc = eth_pdu_decode(data, size, &frame);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, " - eth_pdu_decode failed");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, " - eth_pdu_decode failed");
 		return rc;
 	}
@@ -220,14 +220,14 @@
 		break;
 	case ETYPE_IP:
-		log_msg(LVL_DEBUG, " - construct SDU");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, " - construct SDU");
 		sdu.lsrc.ipv4 = (192 << 24) | (168 << 16) | (0 << 8) | 1;
 		sdu.ldest.ipv4 = (192 << 24) | (168 << 16) | (0 << 8) | 4;
 		sdu.data = frame.data;
 		sdu.size = frame.size;
-		log_msg(LVL_DEBUG, " - call iplink_ev_recv");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, " - call iplink_ev_recv");
 		rc = iplink_ev_recv(&nic->iplink, &sdu);
 		break;
 	default:
-		log_msg(LVL_DEBUG, "Unknown ethertype 0x%" PRIx16,
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Unknown ethertype 0x%" PRIx16,
 		    frame.etype_len);
 	}
@@ -239,5 +239,5 @@
 static int ethip_get_mtu(iplink_srv_t *srv, size_t *mtu)
 {
-	log_msg(LVL_DEBUG, "ethip_get_mtu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_get_mtu()");
 	*mtu = 1500;
 	return EOK;
@@ -248,5 +248,5 @@
 	ethip_nic_t *nic = (ethip_nic_t *)srv->arg;
 
-	log_msg(LVL_DEBUG, "ethip_addr_add(0x%" PRIx32 ")", addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_addr_add(0x%" PRIx32 ")", addr->ipv4);
 	return ethip_nic_addr_add(nic, addr);
 }
@@ -256,5 +256,5 @@
 	ethip_nic_t *nic = (ethip_nic_t *)srv->arg;
 
-	log_msg(LVL_DEBUG, "ethip_addr_remove(0x%" PRIx32 ")", addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_addr_remove(0x%" PRIx32 ")", addr->ipv4);
 	return ethip_nic_addr_add(nic, addr);
 }
@@ -266,5 +266,5 @@
 	printf(NAME ": HelenOS IP over Ethernet service\n");
 
-	if (log_init(NAME, LVL_WARN) != EOK) {
+	if (log_init(NAME) != EOK) {
 		printf(NAME ": Failed to initialize logging.\n");
 		return 1;
Index: uspace/srv/net/ethip/ethip_nic.c
===================================================================
--- uspace/srv/net/ethip/ethip_nic.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/ethip/ethip_nic.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -68,5 +68,5 @@
 	rc = loc_category_get_id("nic", &iplink_cat, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed resolving category 'nic'.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'nic'.");
 		fibril_mutex_unlock(&ethip_discovery_lock);
 		return ENOENT;
@@ -75,5 +75,5 @@
 	rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed getting list of IP links.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP links.");
 		fibril_mutex_unlock(&ethip_discovery_lock);
 		return EIO;
@@ -93,9 +93,9 @@
 
 		if (!already_known) {
-			log_msg(LVL_DEBUG, "Found NIC '%lu'",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Found NIC '%lu'",
 			    (unsigned long) svcs[i]);
 			rc = ethip_nic_open(svcs[i]);
 			if (rc != EOK)
-				log_msg(LVL_ERROR, "Could not open NIC.");
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not open NIC.");
 		}
 	}
@@ -110,5 +110,5 @@
 
 	if (nic == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating NIC structure. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating NIC structure. "
 		    "Out of memory.");
 		return NULL;
@@ -126,5 +126,5 @@
 
 	if (laddr == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating NIC address structure. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating NIC address structure. "
 		    "Out of memory.");
 		return NULL;
@@ -153,5 +153,5 @@
 	nic_address_t nic_address;
 	
-	log_msg(LVL_DEBUG, "ethip_nic_open()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_open()");
 	ethip_nic_t *nic = ethip_nic_new();
 	if (nic == NULL)
@@ -160,5 +160,5 @@
 	int rc = loc_service_get_name(sid, &nic->svc_name);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed getting service name.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
 		goto error;
 	}
@@ -166,5 +166,5 @@
 	nic->sess = loc_service_connect(EXCHANGE_SERIALIZE, sid, 0);
 	if (nic->sess == NULL) {
-		log_msg(LVL_ERROR, "Failed connecting '%s'", nic->svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting '%s'", nic->svc_name);
 		goto error;
 	}
@@ -174,10 +174,10 @@
 	rc = nic_callback_create(nic->sess, ethip_nic_cb_conn, nic);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed creating callback connection "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed creating callback connection "
 		    "from '%s'", nic->svc_name);
 		goto error;
 	}
 
-	log_msg(LVL_DEBUG, "Opened NIC '%s'", nic->svc_name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened NIC '%s'", nic->svc_name);
 	list_append(&nic->nic_list, &ethip_nic_list);
 	in_list = true;
@@ -189,5 +189,5 @@
 	rc = nic_get_address(nic->sess, &nic_address);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Error getting MAC address of NIC '%s'.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting MAC address of NIC '%s'.",
 		    nic->svc_name);
 		goto error;
@@ -198,10 +198,10 @@
 	rc = nic_set_state(nic->sess, NIC_STATE_ACTIVE);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Error activating NIC '%s'.",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error activating NIC '%s'.",
 		    nic->svc_name);
 		goto error;
 	}
 
-	log_msg(LVL_DEBUG, "Initialized IP link service, MAC = 0x%" PRIx64,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Initialized IP link service, MAC = 0x%" PRIx64,
 	    nic->mac_addr.addr);
 
@@ -225,5 +225,5 @@
     ipc_call_t *call)
 {
-	log_msg(LVL_DEBUG, "ethip_nic_addr_changed()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_changed()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -236,21 +236,21 @@
 	size_t size;
 
-	log_msg(LVL_DEBUG, "ethip_nic_received() nic=%p", nic);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_received() nic=%p", nic);
 
 	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "data_write_accept() failed");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "data_write_accept() failed");
 		return;
 	}
 
-	log_msg(LVL_DEBUG, "Ethernet PDU contents (%zu bytes)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Ethernet PDU contents (%zu bytes)",
 	    size);
 
-	log_msg(LVL_DEBUG, "call ethip_received");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "call ethip_received");
 	rc = ethip_received(&nic->iplink, data, size);
-	log_msg(LVL_DEBUG, "free data");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "free data");
 	free(data);
 
-	log_msg(LVL_DEBUG, "ethip_nic_received() done, rc=%d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_received() done, rc=%d", rc);
 	async_answer_0(callid, rc);
 }
@@ -259,5 +259,5 @@
     ipc_call_t *call)
 {
-	log_msg(LVL_DEBUG, "ethip_nic_device_state()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_device_state()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -267,5 +267,5 @@
 	ethip_nic_t *nic = (ethip_nic_t *)arg;
 
-	log_msg(LVL_DEBUG, "ethnip_nic_cb_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethnip_nic_cb_conn()");
 
 	while (true) {
@@ -298,5 +298,5 @@
 	int rc = loc_register_cat_change_cb(ethip_nic_cat_change_cb);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering callback for NIC "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback for NIC "
 		    "discovery (%d).", rc);
 		return rc;
@@ -308,19 +308,19 @@
 ethip_nic_t *ethip_nic_find_by_iplink_sid(service_id_t iplink_sid)
 {
-	log_msg(LVL_DEBUG, "ethip_nic_find_by_iplink_sid(%u)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_find_by_iplink_sid(%u)",
 	    (unsigned) iplink_sid);
 
 	list_foreach(ethip_nic_list, link) {
-		log_msg(LVL_DEBUG, "ethip_nic_find_by_iplink_sid - element");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_find_by_iplink_sid - element");
 		ethip_nic_t *nic = list_get_instance(link, ethip_nic_t,
 		    nic_list);
 
 		if (nic->iplink_sid == iplink_sid) {
-			log_msg(LVL_DEBUG, "ethip_nic_find_by_iplink_sid - found %p", nic);
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_find_by_iplink_sid - found %p", nic);
 			return nic;
 		}
 	}
 
-	log_msg(LVL_DEBUG, "ethip_nic_find_by_iplink_sid - not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_find_by_iplink_sid - not found");
 	return NULL;
 }
@@ -329,7 +329,7 @@
 {
 	int rc;
-	log_msg(LVL_DEBUG, "ethip_nic_send(size=%zu)", size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_send(size=%zu)", size);
 	rc = nic_send_frame(nic->sess, data, size);
-	log_msg(LVL_DEBUG, "nic_send_frame -> %d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "nic_send_frame -> %d", rc);
 	return rc;
 }
@@ -339,5 +339,5 @@
 	ethip_link_addr_t *laddr;
 
-	log_msg(LVL_DEBUG, "ethip_nic_addr_add()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_add()");
 	laddr = ethip_nic_addr_new(addr);
 	if (laddr == NULL)
@@ -352,5 +352,5 @@
 	ethip_link_addr_t *laddr;
 
-	log_msg(LVL_DEBUG, "ethip_nic_addr_remove()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_remove()");
 
 	laddr = ethip_nic_addr_find(nic, addr);
@@ -366,5 +366,5 @@
     iplink_srv_addr_t *addr)
 {
-	log_msg(LVL_DEBUG, "ethip_nic_addr_find()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_find()");
 
 	list_foreach(nic->addr_list, link) {
Index: uspace/srv/net/ethip/pdu.c
===================================================================
--- uspace/srv/net/ethip/pdu.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/ethip/pdu.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -69,7 +69,8 @@
 	    frame->size);
 
-	log_msg(LVL_DEBUG, "Encoding Ethernet frame src=%llx dest=%llx etype=%x",
-	    frame->src, frame->dest, frame->etype_len);
-	log_msg(LVL_DEBUG, "Encoded Ethernet frame (%zu bytes)", size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Encoding Ethernet frame "
+	    "src=%" PRIx64 " dest=%" PRIx64 " etype=%x",
+	    frame->src.addr, frame->dest.addr, frame->etype_len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Encoded Ethernet frame (%zu bytes)", size);
 
 	*rdata = data;
@@ -83,8 +84,8 @@
 	eth_header_t *hdr;
 
-	log_msg(LVL_DEBUG, "eth_pdu_decode()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "eth_pdu_decode()");
 
 	if (size < sizeof(eth_header_t)) {
-		log_msg(LVL_DEBUG, "PDU too short (%zu)", size);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
 		return EINVAL;
 	}
@@ -104,7 +105,8 @@
 	    frame->size);
 
-	log_msg(LVL_DEBUG, "Decoding Ethernet frame src=%llx dest=%llx etype=%x",
-	    frame->src, frame->dest, frame->etype_len);
-	log_msg(LVL_DEBUG, "Decoded Ethernet frame payload (%zu bytes)", frame->size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Decoding Ethernet frame "
+	    "src=%" PRIx64 " dest=%" PRIx64 " etype=%x",
+	    frame->src.addr, frame->dest.addr, frame->etype_len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Decoded Ethernet frame payload (%zu bytes)", frame->size);
 
 	return EOK;
@@ -143,5 +145,5 @@
 	uint16_t fopcode;
 
-	log_msg(LVL_DEBUG, "arp_pdu_encode()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "arp_pdu_encode()");
 
 	size = sizeof(arp_eth_packet_fmt_t);
@@ -183,8 +185,8 @@
 	arp_eth_packet_fmt_t *pfmt;
 
-	log_msg(LVL_DEBUG, "arp_pdu_decode()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "arp_pdu_decode()");
 
 	if (size < sizeof(arp_eth_packet_fmt_t)) {
-		log_msg(LVL_DEBUG, "ARP PDU too short (%zu)", size);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ARP PDU too short (%zu)", size);
 		return EINVAL;
 	}
@@ -193,5 +195,5 @@
 
 	if (uint16_t_be2host(pfmt->hw_addr_space) != AHRD_ETHERNET) {
-		log_msg(LVL_DEBUG, "HW address space != %u (%" PRIu16 ")",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "HW address space != %u (%" PRIu16 ")",
 		    AHRD_ETHERNET, uint16_t_be2host(pfmt->hw_addr_space));
 		return EINVAL;
@@ -199,5 +201,5 @@
 
 	if (uint16_t_be2host(pfmt->proto_addr_space) != 0x0800) {
-		log_msg(LVL_DEBUG, "Proto address space != %u (%" PRIu16 ")",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Proto address space != %u (%" PRIu16 ")",
 		    ETYPE_IP, uint16_t_be2host(pfmt->proto_addr_space));
 		return EINVAL;
@@ -205,5 +207,5 @@
 
 	if (pfmt->hw_addr_size != ETH_ADDR_SIZE) {
-		log_msg(LVL_DEBUG, "HW address size != %zu (%zu)",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "HW address size != %zu (%zu)",
 		    (size_t)ETH_ADDR_SIZE, (size_t)pfmt->hw_addr_size);
 		return EINVAL;
@@ -211,5 +213,5 @@
 
 	if (pfmt->proto_addr_size != IPV4_ADDR_SIZE) {
-		log_msg(LVL_DEBUG, "Proto address size != %zu (%zu)",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Proto address size != %zu (%zu)",
 		    (size_t)IPV4_ADDR_SIZE, (size_t)pfmt->proto_addr_size);
 		return EINVAL;
@@ -220,5 +222,5 @@
 	case AOP_REPLY: packet->opcode = aop_reply; break;
 	default:
-		log_msg(LVL_DEBUG, "Invalid ARP opcode (%" PRIu16 ")",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Invalid ARP opcode (%" PRIu16 ")",
 		    uint16_t_be2host(pfmt->opcode));
 		return EINVAL;
@@ -231,5 +233,5 @@
 	packet->target_proto_addr.ipv4 =
 	    uint32_t_be2host(pfmt->target_proto_addr);
-	log_msg(LVL_DEBUG, "packet->tpa = %x\n", pfmt->target_proto_addr);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "packet->tpa = %x\n", pfmt->target_proto_addr);
 
 	return EOK;
Index: uspace/srv/net/inetsrv/addrobj.c
===================================================================
--- uspace/srv/net/inetsrv/addrobj.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/addrobj.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -59,5 +59,5 @@
 
 	if (addr == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating address object. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating address object. "
 		    "Out of memory.");
 		return NULL;
@@ -114,5 +114,5 @@
 	uint32_t mask;
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find(%x)", (unsigned)addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find(%x)", (unsigned)addr->ipv4);
 
 	fibril_mutex_lock(&addr_list_lock);
@@ -125,5 +125,5 @@
 		if ((naddr->naddr.ipv4 & mask) == (addr->ipv4 & mask)) {
 			fibril_mutex_unlock(&addr_list_lock);
-			log_msg(LVL_DEBUG, "inet_addrobj_find: found %p",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find: found %p",
 			    naddr);
 			return naddr;
@@ -131,5 +131,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find: Not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find: Not found");
 	fibril_mutex_unlock(&addr_list_lock);
 
@@ -147,5 +147,5 @@
 	assert(fibril_mutex_is_locked(&addr_list_lock));
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find_by_name_locked('%s', '%s')",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked('%s', '%s')",
 	    name, ilink->svc_name);
 
@@ -155,5 +155,5 @@
 
 		if (naddr->ilink == ilink && str_cmp(naddr->name, name) == 0) {
-			log_msg(LVL_DEBUG, "inet_addrobj_find_by_name_locked: found %p",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked: found %p",
 			    naddr);
 			return naddr;
@@ -161,5 +161,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find_by_name_locked: Not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked: Not found");
 
 	return NULL;
@@ -177,5 +177,5 @@
 	inet_addrobj_t *aobj;
 
-	log_msg(LVL_DEBUG, "inet_addrobj_find_by_name('%s', '%s')",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name('%s', '%s')",
 	    name, ilink->svc_name);
 
@@ -194,5 +194,5 @@
 inet_addrobj_t *inet_addrobj_get_by_id(sysarg_t id)
 {
-	log_msg(LVL_DEBUG, "inet_addrobj_get_by_id(%zu)", (size_t)id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_get_by_id(%zu)", (size_t)id);
 
 	fibril_mutex_lock(&addr_list_lock);
Index: uspace/srv/net/inetsrv/icmp.c
===================================================================
--- uspace/srv/net/inetsrv/icmp.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/icmp.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -57,5 +57,5 @@
 	uint8_t type;
 
-	log_msg(LVL_DEBUG, "icmp_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "icmp_recv()");
 
 	if (dgram->size < 1)
@@ -84,5 +84,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "icmp_recv_echo_request()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "icmp_recv_echo_request()");
 
 	if (dgram->size < sizeof(icmp_echo_t))
@@ -124,5 +124,5 @@
 	uint16_t ident;
 
-	log_msg(LVL_DEBUG, "icmp_recv_echo_reply()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "icmp_recv_echo_reply()");
 
 	if (dgram->size < sizeof(icmp_echo_t))
Index: uspace/srv/net/inetsrv/inet_link.c
===================================================================
--- uspace/srv/net/inetsrv/inet_link.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/inet_link.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -64,14 +64,14 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_iplink_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
 	rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "failed decoding PDU");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "failed decoding PDU");
 		return rc;
 	}
 
-	log_msg(LVL_DEBUG, "call inet_recv_packet()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet()");
 	rc = inet_recv_packet(&packet);
-	log_msg(LVL_DEBUG, "call inet_recv_packet -> %d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet -> %d", rc);
 	free(packet.data);
 
@@ -91,5 +91,5 @@
 	rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed resolving category 'iplink'.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
 		fibril_mutex_unlock(&inet_discovery_lock);
 		return ENOENT;
@@ -98,5 +98,5 @@
 	rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed getting list of IP links.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP links.");
 		fibril_mutex_unlock(&inet_discovery_lock);
 		return EIO;
@@ -116,9 +116,9 @@
 
 		if (!already_known) {
-			log_msg(LVL_DEBUG, "Found IP link '%lu'",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Found IP link '%lu'",
 			    (unsigned long) svcs[i]);
 			rc = inet_link_open(svcs[i]);
 			if (rc != EOK)
-				log_msg(LVL_ERROR, "Could not open IP link.");
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not open IP link.");
 		}
 	}
@@ -133,5 +133,5 @@
 
 	if (ilink == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating link structure. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating link structure. "
 		    "Out of memory.");
 		return NULL;
@@ -156,5 +156,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_link_open()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_link_open()");
 	ilink = inet_link_new();
 	if (ilink == NULL)
@@ -166,5 +166,5 @@
 	rc = loc_service_get_name(sid, &ilink->svc_name);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed getting service name.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
 		goto error;
 	}
@@ -172,5 +172,5 @@
 	ilink->sess = loc_service_connect(EXCHANGE_SERIALIZE, sid, 0);
 	if (ilink->sess == NULL) {
-		log_msg(LVL_ERROR, "Failed connecting '%s'", ilink->svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting '%s'", ilink->svc_name);
 		goto error;
 	}
@@ -178,5 +178,5 @@
 	rc = iplink_open(ilink->sess, &inet_iplink_ev_ops, &ilink->iplink);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed opening IP link '%s'",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening IP link '%s'",
 		    ilink->svc_name);
 		goto error;
@@ -185,10 +185,10 @@
 	rc = iplink_get_mtu(ilink->iplink, &ilink->def_mtu);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed determinning MTU of link '%s'",
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed determinning MTU of link '%s'",
 		    ilink->svc_name);
 		goto error;
 	}
 
-	log_msg(LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
 	list_append(&ilink->link_list, &inet_link_list);
 
@@ -209,5 +209,5 @@
 	rc = inet_addrobj_add(addr);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed setting IP address on internet link.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
 		inet_addrobj_delete(addr);
 		/* XXX Roll back */
@@ -218,5 +218,5 @@
 	rc = iplink_addr_add(ilink->iplink, &iaddr);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed setting IP address on internet link.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
 		inet_addrobj_remove(addr);
 		inet_addrobj_delete(addr);
@@ -245,5 +245,5 @@
 	rc = loc_register_cat_change_cb(inet_link_cat_change_cb);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering callback for IP link "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback for IP link "
 		    "discovery (%d).", rc);
 		return rc;
Index: uspace/srv/net/inetsrv/inetcfg.c
===================================================================
--- uspace/srv/net/inetsrv/inetcfg.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/inetcfg.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -61,5 +61,5 @@
 	ilink = inet_link_get_by_id(link_id);
 	if (ilink == NULL) {
-		log_msg(LVL_DEBUG, "Link %lu not found.",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %lu not found.",
 		    (unsigned long) link_id);
 		return ENOENT;
@@ -77,5 +77,5 @@
 	rc = inet_addrobj_add(addr);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "Duplicate address name '%s'.", addr->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Duplicate address name '%s'.", addr->name);
 		inet_addrobj_delete(addr);
 		return rc;
@@ -85,5 +85,5 @@
 	rc = iplink_addr_add(ilink->iplink, &iaddr);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed setting IP address on internet link.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
 		inet_addrobj_remove(addr);
 		inet_addrobj_delete(addr);
@@ -130,5 +130,5 @@
 	ilink = inet_link_get_by_id(link_id);
 	if (ilink == NULL) {
-		log_msg(LVL_DEBUG, "Link %zu not found.", (size_t) link_id);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu not found.", (size_t) link_id);
 		return ENOENT;
 	}
@@ -136,5 +136,5 @@
 	addr = inet_addrobj_find_by_name(name, ilink);
 	if (addr == NULL) {
-		log_msg(LVL_DEBUG, "Address '%s' not found.", name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Address '%s' not found.", name);
 		return ENOENT;
 	}
@@ -228,5 +228,5 @@
 	sroute = inet_sroute_find_by_name(name);
 	if (sroute == NULL) {
-		log_msg(LVL_DEBUG, "Static route '%s' not found.", name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Static route '%s' not found.", name);
 		return ENOENT;
 	}
@@ -245,5 +245,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_addr_create_static_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_addr_create_static_srv()");
 
 	rc = async_data_write_accept((void **) &name, true, 0, LOC_NAME_MAXLEN,
@@ -269,5 +269,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_addr_delete_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_addr_delete_srv()");
 
 	addr_id = IPC_GET_ARG1(*call);
@@ -287,5 +287,5 @@
 
 	addr_id = IPC_GET_ARG1(*call);
-	log_msg(LVL_DEBUG, "inetcfg_addr_get_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_addr_get_srv()");
 
 	ainfo.naddr.ipv4 = 0;
@@ -321,5 +321,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_addr_get_id_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_addr_get_id_srv()");
 
 	link_id = IPC_GET_ARG1(*call);
@@ -348,5 +348,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_get_addr_list_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_get_addr_list_srv()");
 
 	if (!async_data_read_receive(&rcallid, &max_size)) {
@@ -382,5 +382,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_get_link_list_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_get_link_list_srv()");
 
 	if (!async_data_read_receive(&rcallid, &max_size)) {
@@ -415,5 +415,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_get_sroute_list_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_get_sroute_list_srv()");
 
 	if (!async_data_read_receive(&rcallid, &max_size)) {
@@ -449,5 +449,5 @@
 
 	link_id = IPC_GET_ARG1(*call);
-	log_msg(LVL_DEBUG, "inetcfg_link_get_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_link_get_srv()");
 
 	linfo.name = NULL;
@@ -482,5 +482,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_sroute_create_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_sroute_create_srv()");
 
 	rc = async_data_write_accept((void **) &name, true, 0, LOC_NAME_MAXLEN,
@@ -506,5 +506,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_sroute_delete_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_sroute_delete_srv()");
 
 	sroute_id = IPC_GET_ARG1(*call);
@@ -524,5 +524,5 @@
 
 	sroute_id = IPC_GET_ARG1(*call);
-	log_msg(LVL_DEBUG, "inetcfg_sroute_get_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_sroute_get_srv()");
 
 	srinfo.dest.ipv4 = 0;
@@ -557,5 +557,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetcfg_sroute_get_id_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_sroute_get_id_srv()");
 
 	rc = async_data_write_accept((void **) &name, true, 0, LOC_NAME_MAXLEN,
@@ -574,5 +574,5 @@
 void inet_cfg_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	log_msg(LVL_DEBUG, "inet_cfg_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_cfg_conn()");
 
 	/* Accept the connection */
Index: uspace/srv/net/inetsrv/inetping.c
===================================================================
--- uspace/srv/net/inetsrv/inetping.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/inetping.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -76,5 +76,5 @@
 	client = inetping_client_find(ident);
 	if (client == NULL) {
-		log_msg(LVL_DEBUG, "Unknown ICMP ident. Dropping.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Unknown ICMP ident. Dropping.");
 		return ENOENT;
 	}
@@ -107,5 +107,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetping_send_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_send_srv()");
 
 	rc = async_data_write_accept((void **) &sdu.data, false, 0, 0, 0,
@@ -133,5 +133,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetping_get_srcaddr_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_get_srcaddr_srv()");
 
 	remote.ipv4 = IPC_GET_ARG1(*call);
@@ -192,5 +192,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inetping_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_conn()");
 
 	/* Accept the connection */
Index: uspace/srv/net/inetsrv/inetsrv.c
===================================================================
--- uspace/srv/net/inetsrv/inetsrv.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/inetsrv.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -66,5 +66,5 @@
 static int inet_init(void)
 {
-	log_msg(LVL_DEBUG, "inet_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_init()");
 	
 	async_set_client_connection(inet_client_conn);
@@ -72,5 +72,5 @@
 	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering server (%d).", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server (%d).", rc);
 		return EEXIST;
 	}
@@ -80,5 +80,5 @@
 	    INET_PORT_DEFAULT);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
 		return EEXIST;
 	}
@@ -87,5 +87,5 @@
 	    INET_PORT_CFG);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
 		return EEXIST;
 	}
@@ -94,5 +94,5 @@
 	    INET_PORT_PING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
 		return EEXIST;
 	}
@@ -108,5 +108,5 @@
     ipc_call_t *call)
 {
-	log_msg(LVL_DEBUG, "inet_callback_create_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_callback_create_srv()");
 
 	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
@@ -143,5 +143,5 @@
 
 	if (dir->aobj == NULL) {
-		log_msg(LVL_DEBUG, "inet_send: No route to destination.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send: No route to destination.");
 		return ENOENT;
 	}
@@ -194,5 +194,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_get_srcaddr_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_get_srcaddr_srv()");
 
 	remote.ipv4 = IPC_GET_ARG1(*call);
@@ -212,5 +212,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_send_srv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send_srv()");
 
 	dgram.src.ipv4 = IPC_GET_ARG1(*call);
@@ -238,5 +238,5 @@
 
 	proto = IPC_GET_ARG1(*call);
-	log_msg(LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
 
 	if (proto > UINT8_MAX) {
@@ -272,5 +272,5 @@
 	inet_client_t client;
 
-	log_msg(LVL_DEBUG, "inet_default_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_default_conn()");
 
 	/* Accept the connection */
@@ -378,5 +378,5 @@
 	inet_client_t *client;
 
-	log_msg(LVL_DEBUG, "inet_recv_dgram_local()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_recv_dgram_local()");
 
 	/* ICMP messages are handled internally */
@@ -386,5 +386,5 @@
 	client = inet_client_find(proto);
 	if (client == NULL) {
-		log_msg(LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
 		    proto);
 		return ENOENT;
@@ -428,5 +428,5 @@
 	printf(NAME ": HelenOS Internet Protocol service\n");
 
-	if (log_init(NAME, LVL_WARN) != EOK) {
+	if (log_init(NAME) != EOK) {
 		printf(NAME ": Failed to initialize logging.\n");
 		return 1;
Index: uspace/srv/net/inetsrv/pdu.c
===================================================================
--- uspace/srv/net/inetsrv/pdu.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/pdu.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -204,8 +204,8 @@
 	uint16_t foff;
 
-	log_msg(LVL_DEBUG, "inet_pdu_decode()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode()");
 
 	if (size < sizeof(ip_header_t)) {
-		log_msg(LVL_DEBUG, "PDU too short (%zu)", size);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
 		return EINVAL;
 	}
@@ -216,5 +216,5 @@
 	    hdr->ver_ihl);
 	if (version != 4) {
-		log_msg(LVL_DEBUG, "Version (%d) != 4", version);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 4", version);
 		return EINVAL;
 	}
@@ -222,10 +222,10 @@
 	tot_len = uint16_t_be2host(hdr->tot_len);
 	if (tot_len < sizeof(ip_header_t)) {
-		log_msg(LVL_DEBUG, "Total Length too small (%zu)", tot_len);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length too small (%zu)", tot_len);
 		return EINVAL;
 	}
 
 	if (tot_len > size) {
-		log_msg(LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
 			tot_len, size);
 		return EINVAL;
@@ -256,5 +256,5 @@
 	packet->data = calloc(packet->size, 1);
 	if (packet->data == NULL) {
-		log_msg(LVL_WARN, "Out of memory.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Out of memory.");
 		return ENOMEM;
 	}
Index: uspace/srv/net/inetsrv/reass.c
===================================================================
--- uspace/srv/net/inetsrv/reass.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/reass.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -86,5 +86,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "inet_reass_queue_packet()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_reass_queue_packet()");
 
 	fibril_mutex_lock(&reass_dgram_map_lock);
@@ -95,5 +95,5 @@
 		/* Only happens when we are out of memory */
 		fibril_mutex_unlock(&reass_dgram_map_lock);
-		log_msg(LVL_DEBUG, "Allocation failed, packet dropped.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Allocation failed, packet dropped.");
 		return ENOMEM;
 	}
Index: uspace/srv/net/inetsrv/sroute.c
===================================================================
--- uspace/srv/net/inetsrv/sroute.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/inetsrv/sroute.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -57,5 +57,5 @@
 
 	if (sroute == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating static route object. "
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating static route object. "
 		    "Out of memory.");
 		return NULL;
@@ -100,5 +100,5 @@
 	inet_sroute_t *best;
 
-	log_msg(LVL_DEBUG, "inet_sroute_find(%x)", (unsigned)addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find(%x)", (unsigned)addr->ipv4);
 
 	fibril_mutex_lock(&sroute_list_lock);
@@ -117,5 +117,5 @@
 		if ((sroute->dest.ipv4 & mask) == (addr->ipv4 & mask)) {
 			fibril_mutex_unlock(&sroute_list_lock);
-			log_msg(LVL_DEBUG, "inet_sroute_find: found %p",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find: found %p",
 			    sroute);
 			return sroute;
@@ -123,5 +123,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "inet_sroute_find: Not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find: Not found");
 	fibril_mutex_unlock(&sroute_list_lock);
 
@@ -136,5 +136,5 @@
 inet_sroute_t *inet_sroute_find_by_name(const char *name)
 {
-	log_msg(LVL_DEBUG, "inet_sroute_find_by_name('%s')",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find_by_name('%s')",
 	    name);
 
@@ -147,5 +147,5 @@
 		if (str_cmp(sroute->name, name) == 0) {
 			fibril_mutex_unlock(&sroute_list_lock);
-			log_msg(LVL_DEBUG, "inet_sroute_find_by_name: found %p",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find_by_name: found %p",
 			    sroute);
 			return sroute;
@@ -153,5 +153,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "inet_sroute_find_by_name: Not found");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_find_by_name: Not found");
 	fibril_mutex_unlock(&sroute_list_lock);
 
@@ -166,5 +166,5 @@
 inet_sroute_t *inet_sroute_get_by_id(sysarg_t id)
 {
-	log_msg(LVL_DEBUG, "inet_sroute_get_by_id(%zu)", (size_t)id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_sroute_get_by_id(%zu)", (size_t)id);
 
 	fibril_mutex_lock(&sroute_list_lock);
Index: uspace/srv/net/loopip/loopip.c
===================================================================
--- uspace/srv/net/loopip/loopip.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/loopip/loopip.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -75,5 +75,5 @@
 {
 	while (true) {
-		log_msg(LVL_DEBUG, "loopip_recv_fibril(): Wait for one item");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_recv_fibril(): Wait for one item");
 		link_t *link = prodcons_consume(&loopip_rcv_queue);
 		rqueue_entry_t *rqe = list_get_instance(link, rqueue_entry_t, link);
@@ -96,5 +96,5 @@
 	rc = loc_server_register(NAME);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering server.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
 		return rc;
 	}
@@ -108,5 +108,5 @@
 	rc = loc_service_register(svc_name, &sid);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed registering service %s.", svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service %s.", svc_name);
 		return rc;
 	}
@@ -114,5 +114,5 @@
 	rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed resolving category 'iplink'.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
 		return rc;
 	}
@@ -120,5 +120,5 @@
 	rc = loc_service_add_to_cat(sid, iplink_cat);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed adding %s to category.", svc_name);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding %s to category.", svc_name);
 		return rc;
 	}
@@ -135,5 +135,5 @@
 static void loopip_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	log_msg(LVL_DEBUG, "loopip_client_conn()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_client_conn()");
 	iplink_conn(iid, icall, &loopip_iplink);
 }
@@ -141,5 +141,5 @@
 static int loopip_open(iplink_srv_t *srv)
 {
-	log_msg(LVL_DEBUG, "loopip_open()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_open()");
 	return EOK;
 }
@@ -147,5 +147,5 @@
 static int loopip_close(iplink_srv_t *srv)
 {
-	log_msg(LVL_DEBUG, "loopip_close()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_close()");
 	return EOK;
 }
@@ -155,5 +155,5 @@
 	rqueue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "loopip_send()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_send()");
 
 	rqe = calloc(1, sizeof(rqueue_entry_t));
@@ -184,5 +184,5 @@
 static int loopip_get_mtu(iplink_srv_t *srv, size_t *mtu)
 {
-	log_msg(LVL_DEBUG, "loopip_get_mtu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_get_mtu()");
 	*mtu = 1500;
 	return EOK;
@@ -191,5 +191,5 @@
 static int loopip_addr_add(iplink_srv_t *srv, iplink_srv_addr_t *addr)
 {
-	log_msg(LVL_DEBUG, "loopip_addr_add(0x%" PRIx32 ")", addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_addr_add(0x%" PRIx32 ")", addr->ipv4);
 	return EOK;
 }
@@ -197,5 +197,5 @@
 static int loopip_addr_remove(iplink_srv_t *srv, iplink_srv_addr_t *addr)
 {
-	log_msg(LVL_DEBUG, "loopip_addr_remove(0x%" PRIx32 ")", addr->ipv4);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_addr_remove(0x%" PRIx32 ")", addr->ipv4);
 	return EOK;
 }
@@ -207,5 +207,5 @@
 	printf(NAME ": HelenOS loopback IP link provider\n");
 
-	if (log_init(NAME, LVL_WARN) != EOK) {
+	if (log_init(NAME) != EOK) {
 		printf(NAME ": Failed to initialize logging.\n");
 		return 1;
Index: uspace/srv/net/tcp/conn.c
===================================================================
--- uspace/srv/net/tcp/conn.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/conn.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -164,5 +164,5 @@
 static void tcp_conn_free(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_free(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_free(%p)", conn->name, conn);
 	tcp_tqueue_fini(&conn->retransmit);
 
@@ -184,5 +184,5 @@
 void tcp_conn_addref(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG2, "%s: tcp_conn_addref(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "%s: tcp_conn_addref(%p)", conn->name, conn);
 	atomic_inc(&conn->refcnt);
 }
@@ -196,5 +196,5 @@
 void tcp_conn_delref(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG2, "%s: tcp_conn_delref(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "%s: tcp_conn_delref(%p)", conn->name, conn);
 
 	if (atomic_predec(&conn->refcnt) == 0)
@@ -211,5 +211,5 @@
 void tcp_conn_delete(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_delete(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_delete(%p)", conn->name, conn);
 
 	assert(conn->deleted == false);
@@ -245,5 +245,5 @@
 	tcp_cstate_t old_state;
 
-	log_msg(LVL_DEBUG, "tcp_conn_state_set(%p)", conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set(%p)", conn);
 
 	old_state = conn->cstate;
@@ -253,8 +253,8 @@
 	/* Run user callback function */
 	if (conn->cstate_cb != NULL) {
-		log_msg(LVL_DEBUG, "tcp_conn_state_set() - run user CB");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - run user CB");
 		conn->cstate_cb(conn, conn->cstate_cb_arg);
 	} else {
-		log_msg(LVL_DEBUG, "tcp_conn_state_set() - no user CB");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - no user CB");
 	}
 
@@ -293,13 +293,13 @@
 	case st_syn_received:
 	case st_established:
-		log_msg(LVL_DEBUG, "%s: FIN sent -> Fin-Wait-1", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN sent -> Fin-Wait-1", conn->name);
 		tcp_conn_state_set(conn, st_fin_wait_1);
 		break;
 	case st_close_wait:
-		log_msg(LVL_DEBUG, "%s: FIN sent -> Last-Ack", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN sent -> Last-Ack", conn->name);
 		tcp_conn_state_set(conn, st_last_ack);
 		break;
 	default:
-		log_msg(LVL_ERROR, "%s: Connection state %d", conn->name,
+		log_msg(LOG_DEFAULT, LVL_ERROR, "%s: Connection state %d", conn->name,
 		    conn->cstate);
 		assert(false);
@@ -312,5 +312,5 @@
 static bool tcp_socket_match(tcp_sock_t *sock, tcp_sock_t *patt)
 {
-	log_msg(LVL_DEBUG2, "tcp_socket_match(sock=(%x,%u), pat=(%x,%u))",
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_socket_match(sock=(%x,%u), pat=(%x,%u))",
 	    sock->addr.ipv4, sock->port, patt->addr.ipv4, patt->port);
 
@@ -323,5 +323,5 @@
 		return false;
 
-	log_msg(LVL_DEBUG2, " -> match");
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " -> match");
 
 	return true;
@@ -331,5 +331,5 @@
 static bool tcp_sockpair_match(tcp_sockpair_t *sp, tcp_sockpair_t *pattern)
 {
-	log_msg(LVL_DEBUG2, "tcp_sockpair_match(%p, %p)", sp, pattern);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_sockpair_match(%p, %p)", sp, pattern);
 
 	if (!tcp_socket_match(&sp->local, &pattern->local))
@@ -353,5 +353,5 @@
 tcp_conn_t *tcp_conn_find_ref(tcp_sockpair_t *sp)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_find_ref(%p)", sp);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_find_ref(%p)", sp);
 
 	fibril_mutex_lock(&conn_list_lock);
@@ -360,5 +360,5 @@
 		tcp_conn_t *conn = list_get_instance(link, tcp_conn_t, link);
 		tcp_sockpair_t *csp = &conn->ident;
-		log_msg(LVL_DEBUG2, "compare with conn (f:(%x,%u), l:(%x,%u))",
+		log_msg(LOG_DEFAULT, LVL_DEBUG2, "compare with conn (f:(%x,%u), l:(%x,%u))",
 		    csp->foreign.addr.ipv4, csp->foreign.port,
 		    csp->local.addr.ipv4, csp->local.port);
@@ -380,5 +380,5 @@
 static void tcp_conn_reset(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_reset()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_reset()", conn->name);
 	tcp_conn_state_set(conn, st_closed);
 	conn->reset = true;
@@ -398,5 +398,5 @@
 {
 	/* TODO */
-	log_msg(LVL_DEBUG, "%s: tcp_reset_signal()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_reset_signal()", conn->name);
 }
 
@@ -422,5 +422,5 @@
 		return true;
 	case st_closed:
-		log_msg(LVL_WARN, "state=%d", (int) conn->cstate);
+		log_msg(LOG_DEFAULT, LVL_WARN, "state=%d", (int) conn->cstate);
 		assert(false);
 	}
@@ -436,13 +436,13 @@
 static void tcp_conn_sa_listen(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_sa_listen(%p, %p)", conn, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_listen(%p, %p)", conn, seg);
 
 	if ((seg->ctrl & CTL_RST) != 0) {
-		log_msg(LVL_DEBUG, "Ignoring incoming RST.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Ignoring incoming RST.");
 		return;
 	}
 
 	if ((seg->ctrl & CTL_ACK) != 0) {
-		log_msg(LVL_DEBUG, "Incoming ACK, send acceptable RST.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Incoming ACK, send acceptable RST.");
 		tcp_reply_rst(&conn->ident, seg);
 		return;
@@ -450,9 +450,9 @@
 
 	if ((seg->ctrl & CTL_SYN) == 0) {
-		log_msg(LVL_DEBUG, "SYN not present. Ignoring segment.");
-		return;
-	}
-
-	log_msg(LVL_DEBUG, "Got SYN, sending SYN, ACK.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "SYN not present. Ignoring segment.");
+		return;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Got SYN, sending SYN, ACK.");
 
 	conn->rcv_nxt = seg->seq + 1;
@@ -460,8 +460,8 @@
 
 
-	log_msg(LVL_DEBUG, "rcv_nxt=%u", conn->rcv_nxt);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "rcv_nxt=%u", conn->rcv_nxt);
 
 	if (seg->len > 1)
-		log_msg(LVL_WARN, "SYN combined with data, ignoring data.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "SYN combined with data, ignoring data.");
 
 	/* XXX select ISS */
@@ -493,15 +493,15 @@
 static void tcp_conn_sa_syn_sent(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_sa_syn_sent(%p, %p)", conn, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_syn_sent(%p, %p)", conn, seg);
 
 	if ((seg->ctrl & CTL_ACK) != 0) {
-		log_msg(LVL_DEBUG, "snd_una=%u, seg.ack=%u, snd_nxt=%u",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "snd_una=%u, seg.ack=%u, snd_nxt=%u",
 		    conn->snd_una, seg->ack, conn->snd_nxt);
 		if (!seq_no_ack_acceptable(conn, seg->ack)) {
 			if ((seg->ctrl & CTL_RST) == 0) {
-				log_msg(LVL_WARN, "ACK not acceptable, send RST");
+				log_msg(LOG_DEFAULT, LVL_WARN, "ACK not acceptable, send RST");
 				tcp_reply_rst(&conn->ident, seg);
 			} else {
-				log_msg(LVL_WARN, "RST,ACK not acceptable, drop");
+				log_msg(LOG_DEFAULT, LVL_WARN, "RST,ACK not acceptable, drop");
 			}
 			return;
@@ -512,5 +512,5 @@
 		/* If we get here, we have either an acceptable ACK or no ACK */
 		if ((seg->ctrl & CTL_ACK) != 0) {
-			log_msg(LVL_DEBUG, "%s: Connection reset. -> Closed",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Connection reset. -> Closed",
 			    conn->name);
 			/* Reset connection */
@@ -518,5 +518,5 @@
 			return;
 		} else {
-			log_msg(LVL_DEBUG, "%s: RST without ACK, drop",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: RST without ACK, drop",
 			    conn->name);
 			return;
@@ -527,5 +527,5 @@
 
 	if ((seg->ctrl & CTL_SYN) == 0) {
-		log_msg(LVL_DEBUG, "No SYN bit, ignoring segment.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "No SYN bit, ignoring segment.");
 		return;
 	}
@@ -544,5 +544,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "Sent SYN, got SYN.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Sent SYN, got SYN.");
 
 	/*
@@ -551,5 +551,5 @@
 	 * will always be accepted as new window setting.
 	 */
-	log_msg(LVL_DEBUG, "SND.WND := %" PRIu32 ", SND.WL1 := %" PRIu32 ", "
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "SND.WND := %" PRIu32 ", SND.WL1 := %" PRIu32 ", "
 	    "SND.WL2 = %" PRIu32, seg->wnd, seg->seq, seg->seq);
 	conn->snd_wnd = seg->wnd;
@@ -558,9 +558,9 @@
 
 	if (seq_no_syn_acked(conn)) {
-		log_msg(LVL_DEBUG, "%s: syn acked -> Established", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: syn acked -> Established", conn->name);
 		tcp_conn_state_set(conn, st_established);
 		tcp_tqueue_ctrl_seg(conn, CTL_ACK /* XXX */);
 	} else {
-		log_msg(LVL_DEBUG, "%s: syn not acked -> Syn-Received",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: syn not acked -> Syn-Received",
 		    conn->name);
 		tcp_conn_state_set(conn, st_syn_received);
@@ -582,9 +582,9 @@
 	tcp_segment_t *pseg;
 
-	log_msg(LVL_DEBUG, "tcp_conn_sa_seq(%p, %p)", conn, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_seq(%p, %p)", conn, seg);
 
 	/* Discard unacceptable segments ("old duplicates") */
 	if (!seq_no_segment_acceptable(conn, seg)) {
-		log_msg(LVL_DEBUG, "Replying ACK to unacceptable segment.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Replying ACK to unacceptable segment.");
 		tcp_tqueue_ctrl_seg(conn, CTL_ACK);
 		tcp_segment_delete(seg);
@@ -682,5 +682,5 @@
 	assert(seq_no_in_rcv_wnd(conn, seg->seq));
 
-	log_msg(LVL_WARN, "SYN is in receive window, should send reset. XXX");
+	log_msg(LOG_DEFAULT, LVL_WARN, "SYN is in receive window, should send reset. XXX");
 
 	/*
@@ -705,5 +705,5 @@
 	if (!seq_no_ack_acceptable(conn, seg->ack)) {
 		/* ACK is not acceptable, send RST. */
-		log_msg(LVL_WARN, "Segment ACK not acceptable, sending RST.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Segment ACK not acceptable, sending RST.");
 		tcp_reply_rst(&conn->ident, seg);
 		tcp_segment_delete(seg);
@@ -711,5 +711,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "%s: SYN ACKed -> Established", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: SYN ACKed -> Established", conn->name);
 
 	tcp_conn_state_set(conn, st_established);
@@ -730,14 +730,14 @@
 static cproc_t tcp_conn_seg_proc_ack_est(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg);
-
-	log_msg(LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg);
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u",
 	    (unsigned)seg->ack, (unsigned)conn->snd_una,
 	    (unsigned)conn->snd_nxt);
 
 	if (!seq_no_ack_acceptable(conn, seg->ack)) {
-		log_msg(LVL_DEBUG, "ACK not acceptable.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ACK not acceptable.");
 		if (!seq_no_ack_duplicate(conn, seg->ack)) {
-			log_msg(LVL_WARN, "Not acceptable, not duplicate. "
+			log_msg(LOG_DEFAULT, LVL_WARN, "Not acceptable, not duplicate. "
 			    "Send ACK and drop.");
 			/* Not acceptable, not duplicate. Send ACK and drop. */
@@ -746,5 +746,5 @@
 			return cp_done;
 		} else {
-			log_msg(LVL_DEBUG, "Ignoring duplicate ACK.");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Ignoring duplicate ACK.");
 		}
 	} else {
@@ -758,5 +758,5 @@
 		conn->snd_wl2 = seg->ack;
 
-		log_msg(LVL_DEBUG, "Updating send window, SND.WND=%" PRIu32
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Updating send window, SND.WND=%" PRIu32
 		    ", SND.WL1=%" PRIu32 ", SND.WL2=%" PRIu32,
 		    conn->snd_wnd, conn->snd_wl1, conn->snd_wl2);
@@ -785,5 +785,5 @@
 
 	if (conn->fin_is_acked) {
-		log_msg(LVL_DEBUG, "%s: FIN acked -> Fin-Wait-2", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN acked -> Fin-Wait-2", conn->name);
 		tcp_conn_state_set(conn, st_fin_wait_2);
 	}
@@ -850,5 +850,5 @@
 
 	if (conn->fin_is_acked) {
-		log_msg(LVL_DEBUG, "%s: FIN acked -> Closed", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN acked -> Closed", conn->name);
 		tcp_conn_remove(conn);
 		tcp_conn_state_set(conn, st_closed);
@@ -881,9 +881,9 @@
 static cproc_t tcp_conn_seg_proc_ack(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_ack(%p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_ack(%p, %p)",
 	    conn->name, conn, seg);
 
 	if ((seg->ctrl & CTL_ACK) == 0) {
-		log_msg(LVL_WARN, "Segment has no ACK. Dropping.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Segment has no ACK. Dropping.");
 		tcp_segment_delete(seg);
 		return cp_done;
@@ -940,5 +940,5 @@
 	size_t xfer_size;
 
-	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_text(%p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_text(%p, %p)",
 	    conn->name, conn, seg);
 
@@ -982,5 +982,5 @@
 	fibril_condvar_broadcast(&conn->rcv_buf_cv);
 
-	log_msg(LVL_DEBUG, "Received %zu bytes of data.", xfer_size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Received %zu bytes of data.", xfer_size);
 
 	/* Advance RCV.NXT */
@@ -998,7 +998,7 @@
 		tcp_conn_trim_seg_to_wnd(conn, seg);
 	} else {
-		log_msg(LVL_DEBUG, "%s: Nothing left in segment, dropping "
-		    "(xfer_size=%zu, SEG.LEN=%zu, seg->ctrl=%u)",
-		    conn->name, xfer_size, seg->len, (unsigned)seg->ctrl);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Nothing left in segment, dropping "
+		    "(xfer_size=%zu, SEG.LEN=%" PRIu32 ", seg->ctrl=%u)",
+		    conn->name, xfer_size, seg->len, (unsigned int) seg->ctrl);
 		/* Nothing left in segment */
 		tcp_segment_delete(seg);
@@ -1018,12 +1018,12 @@
 static cproc_t tcp_conn_seg_proc_fin(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_fin(%p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_fin(%p, %p)",
 	    conn->name, conn, seg);
-	log_msg(LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len,
 	    (unsigned) seg->ctrl);
 
 	/* Only process FIN if no text is left in segment. */
 	if (tcp_segment_text_size(seg) == 0 && (seg->ctrl & CTL_FIN) != 0) {
-		log_msg(LVL_DEBUG, " - FIN found in segment.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, " - FIN found in segment.");
 
 		/* Send ACK */
@@ -1042,15 +1042,15 @@
 		case st_syn_received:
 		case st_established:
-			log_msg(LVL_DEBUG, "%s: FIN received -> Close-Wait",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Close-Wait",
 			    conn->name);
 			tcp_conn_state_set(conn, st_close_wait);
 			break;
 		case st_fin_wait_1:
-			log_msg(LVL_DEBUG, "%s: FIN received -> Closing",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Closing",
 			    conn->name);
 			tcp_conn_state_set(conn, st_closing);
 			break;
 		case st_fin_wait_2:
-			log_msg(LVL_DEBUG, "%s: FIN received -> Time-Wait",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Time-Wait",
 			    conn->name);
 			tcp_conn_state_set(conn, st_time_wait);
@@ -1091,5 +1091,5 @@
 static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_conn_seg_process(%p, %p)", conn, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_seg_process(%p, %p)", conn, seg);
 	tcp_segment_dump(seg);
 
@@ -1097,5 +1097,5 @@
 	/* XXX Permit valid ACKs, URGs and RSTs */
 /*	if (!seq_no_segment_acceptable(conn, seg)) {
-		log_msg(LVL_WARN, "Segment not acceptable, dropping.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Segment not acceptable, dropping.");
 		if ((seg->ctrl & CTL_RST) == 0) {
 			tcp_tqueue_ctrl_seg(conn, CTL_ACK);
@@ -1131,5 +1131,5 @@
 	 */
 	if (seg->len > 0) {
-		log_msg(LVL_DEBUG, "Re-insert segment %p. seg->len=%zu",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Re-insert segment %p. seg->len=%zu",
 		    seg, (size_t) seg->len);
 		tcp_iqueue_insert_seg(&conn->incoming, seg);
@@ -1146,5 +1146,5 @@
 void tcp_conn_segment_arrived(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "%c: tcp_conn_segment_arrived(%p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_segment_arrived(%p)",
 	    conn->name, seg);
 
@@ -1165,5 +1165,5 @@
 		tcp_conn_sa_queue(conn, seg); break;
 	case st_closed:
-		log_msg(LVL_DEBUG, "state=%d", (int) conn->cstate);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "state=%d", (int) conn->cstate);
 		assert(false);
 	}
@@ -1178,10 +1178,10 @@
 	tcp_conn_t *conn = (tcp_conn_t *) arg;
 
-	log_msg(LVL_DEBUG, "tw_timeout_func(%p)", conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tw_timeout_func(%p)", conn);
 
 	fibril_mutex_lock(&conn->lock);
 
 	if (conn->cstate == st_closed) {
-		log_msg(LVL_DEBUG, "Connection already closed.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Connection already closed.");
 		fibril_mutex_unlock(&conn->lock);
 		tcp_conn_delref(conn);
@@ -1189,5 +1189,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name);
 	tcp_conn_remove(conn);
 	tcp_conn_state_set(conn, st_closed);
@@ -1240,5 +1240,5 @@
 void tcp_unexpected_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_unexpected_segment(%p, %p)", sp, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_unexpected_segment(%p, %p)", sp, seg);
 
 	if ((seg->ctrl & CTL_RST) == 0)
@@ -1268,5 +1268,5 @@
 	tcp_segment_t *rseg;
 
-	log_msg(LVL_DEBUG, "tcp_reply_rst(%p, %p)", sp, seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_reply_rst(%p, %p)", sp, seg);
 
 	rseg = tcp_segment_make_rst(seg);
Index: uspace/srv/net/tcp/iqueue.c
===================================================================
--- uspace/srv/net/tcp/iqueue.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/iqueue.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -67,9 +67,9 @@
 	tcp_iqueue_entry_t *qe;
 	link_t *link;
-	log_msg(LVL_DEBUG, "tcp_iqueue_insert_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_iqueue_insert_seg()");
 
 	iqe = calloc(1, sizeof(tcp_iqueue_entry_t));
 	if (iqe == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating IQE.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating IQE.");
 		return;
 	}
@@ -108,9 +108,9 @@
 	link_t *link;
 
-	log_msg(LVL_DEBUG, "tcp_get_ready_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_get_ready_seg()");
 
 	link = list_first(&iqueue->list);
 	if (link == NULL) {
-		log_msg(LVL_DEBUG, "iqueue is empty");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "iqueue is empty");
 		return ENOENT;
 	}
@@ -119,5 +119,5 @@
 
 	while (!seq_no_segment_acceptable(iqueue->conn, iqe->seg)) {
-		log_msg(LVL_DEBUG, "Skipping unacceptable segment (RCV.NXT=%"
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Skipping unacceptable segment (RCV.NXT=%"
 		    PRIu32 ", RCV.NXT+RCV.WND=%" PRIu32 ", SEG.SEQ=%" PRIu32
 		    ", SEG.LEN=%" PRIu32 ")", iqueue->conn->rcv_nxt,
@@ -130,5 +130,5 @@
          	link = list_first(&iqueue->list);
 		if (link == NULL) {
-			log_msg(LVL_DEBUG, "iqueue is empty");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "iqueue is empty");
 			return ENOENT;
 		}
@@ -139,5 +139,5 @@
 	/* Do not return segments that are not ready for processing */
 	if (!seq_no_segment_ready(iqueue->conn, iqe->seg)) {
-		log_msg(LVL_DEBUG, "Next segment not ready: SEG.SEQ=%u, "
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Next segment not ready: SEG.SEQ=%u, "
 		    "RCV.NXT=%u, SEG.LEN=%u", iqe->seg->seq,
 		    iqueue->conn->rcv_nxt, iqe->seg->len);
@@ -145,5 +145,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "Returning ready segment %p", iqe->seg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Returning ready segment %p", iqe->seg);
 	list_remove(&iqe->link);
 	*seg = iqe->seg;
Index: uspace/srv/net/tcp/ncsim.c
===================================================================
--- uspace/srv/net/tcp/ncsim.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/ncsim.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -74,5 +74,5 @@
 	link_t *link;
 
-	log_msg(LVL_DEBUG, "tcp_ncsim_bounce_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ncsim_bounce_seg()");
 	tcp_rqueue_bounce_seg(sp, seg);
 	return;
@@ -80,5 +80,5 @@
 	if (0 /*random() % 4 == 3*/) {
 		/* Drop segment */
-		log_msg(LVL_ERROR, "NCSim dropping segment");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "NCSim dropping segment");
 		tcp_segment_delete(seg);
 		return;
@@ -87,5 +87,5 @@
 	sqe = calloc(1, sizeof(tcp_squeue_entry_t));
 	if (sqe == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating SQE.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating SQE.");
 		return;
 	}
@@ -126,5 +126,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_ncsim_fibril()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ncsim_fibril()");
 
 
@@ -139,5 +139,5 @@
 			sqe = list_get_instance(link, tcp_squeue_entry_t, link);
 
-			log_msg(LVL_DEBUG, "NCSim - Sleep");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "NCSim - Sleep");
 			rc = fibril_condvar_wait_timeout(&sim_queue_cv,
 			    &sim_queue_lock, sqe->delay);
@@ -147,5 +147,5 @@
 		fibril_mutex_unlock(&sim_queue_lock);
 
-		log_msg(LVL_DEBUG, "NCSim - End Sleep");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "NCSim - End Sleep");
 		tcp_rqueue_bounce_seg(&sqe->sp, sqe->seg);
 		free(sqe);
@@ -161,9 +161,9 @@
 	fid_t fid;
 
-	log_msg(LVL_DEBUG, "tcp_ncsim_fibril_start()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ncsim_fibril_start()");
 
 	fid = fibril_create(tcp_ncsim_fibril, NULL);
 	if (fid == 0) {
-		log_msg(LVL_ERROR, "Failed creating ncsim fibril.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed creating ncsim fibril.");
 		return;
 	}
Index: uspace/srv/net/tcp/rqueue.c
===================================================================
--- uspace/srv/net/tcp/rqueue.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/rqueue.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -74,5 +74,5 @@
 	tcp_sockpair_t rident;
 
-	log_msg(LVL_DEBUG, "tcp_rqueue_bounce_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_bounce_seg()");
 
 #ifdef BOUNCE_TRANSCODE
@@ -81,10 +81,10 @@
 
 	if (tcp_pdu_encode(sp, seg, &pdu) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
 		return;
 	}
 
 	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
 		return;
 	}
@@ -112,5 +112,5 @@
 {
 	tcp_rqueue_entry_t *rqe;
-	log_msg(LVL_DEBUG, "tcp_rqueue_insert_seg()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_insert_seg()");
 
 	tcp_segment_dump(seg);
@@ -118,5 +118,5 @@
 	rqe = calloc(1, sizeof(tcp_rqueue_entry_t));
 	if (rqe == NULL) {
-		log_msg(LVL_ERROR, "Failed allocating RQE.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating RQE.");
 		return;
 	}
@@ -134,5 +134,5 @@
 	tcp_rqueue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "tcp_rqueue_fibril()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_fibril()");
 
 	while (true) {
@@ -152,9 +152,9 @@
 	fid_t fid;
 
-	log_msg(LVL_DEBUG, "tcp_rqueue_fibril_start()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_rqueue_fibril_start()");
 
 	fid = fibril_create(tcp_rqueue_fibril, NULL);
 	if (fid == 0) {
-		log_msg(LVL_ERROR, "Failed creating rqueue fibril.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed creating rqueue fibril.");
 		return;
 	}
Index: uspace/srv/net/tcp/segment.c
===================================================================
--- uspace/srv/net/tcp/segment.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/segment.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -248,11 +248,11 @@
 void tcp_segment_dump(tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG2, "Segment dump:");
-	log_msg(LVL_DEBUG2, " - ctrl = %u", (unsigned)seg->ctrl);
-	log_msg(LVL_DEBUG2, " - seq = % " PRIu32, seg->seq);
-	log_msg(LVL_DEBUG2, " - ack = % " PRIu32, seg->ack);
-	log_msg(LVL_DEBUG2, " - len = % " PRIu32, seg->len);
-	log_msg(LVL_DEBUG2, " - wnd = % " PRIu32, seg->wnd);
-	log_msg(LVL_DEBUG2, " - up = % " PRIu32, seg->up);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "Segment dump:");
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - ctrl = %u", (unsigned)seg->ctrl);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - seq = %" PRIu32, seg->seq);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - ack = %" PRIu32, seg->ack);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - len = %" PRIu32, seg->len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - wnd = %" PRIu32, seg->wnd);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - up = %" PRIu32, seg->up);
 }
 
Index: uspace/srv/net/tcp/sock.c
===================================================================
--- uspace/srv/net/tcp/sock.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/sock.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -91,5 +91,5 @@
 static void tcp_sock_notify_data(socket_core_t *sock_core)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
 	async_exch_t *exch = async_exchange_begin(sock_core->sess);
 	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
@@ -100,5 +100,5 @@
 static void tcp_sock_notify_aconn(socket_core_t *lsock_core)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
 	async_exch_t *exch = async_exchange_begin(lsock_core->sess);
 	async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
@@ -111,8 +111,8 @@
 	tcp_sockdata_t *sock;
 
-	log_msg(LVL_DEBUG, "tcp_sock_create()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_create()");
 	*rsock = NULL;
 
-	sock = calloc(sizeof(tcp_sockdata_t), 1);
+	sock = calloc(1, sizeof(tcp_sockdata_t));
 	if (sock == NULL)
 		return ENOMEM;
@@ -133,5 +133,5 @@
 static void tcp_sock_uncreate(tcp_sockdata_t *sock)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_uncreate()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_uncreate()");
 	free(sock);
 }
@@ -142,5 +142,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_finish_setup()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_finish_setup()");
 
 	sock->recv_fibril = fibril_create(tcp_sock_recv_fibril, sock);
@@ -171,5 +171,5 @@
 	ipc_call_t answer;
 
-	log_msg(LVL_DEBUG, "tcp_sock_socket()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_socket()");
 
 	rc = tcp_sock_create(client, &sock);
@@ -208,6 +208,6 @@
 	tcp_sockdata_t *socket;
 
-	log_msg(LVL_DEBUG, "tcp_sock_bind()");
-	log_msg(LVL_DEBUG, " - async_data_write_accept");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_bind()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
 	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
 	if (rc != EOK) {
@@ -216,5 +216,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - call socket_bind");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_bind");
 	rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
 	    addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
@@ -225,5 +225,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - call socket_cores_find");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
 	sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
 	if (sock_core != NULL) {
@@ -233,5 +233,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - success");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
 	async_answer_0(callid, EOK);
 }
@@ -250,5 +250,5 @@
 	int i;
 
-	log_msg(LVL_DEBUG, "tcp_sock_listen()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_listen()");
 
 	socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -277,5 +277,5 @@
 
 	socket->backlog = backlog;
-	socket->lconn = calloc(sizeof(tcp_conn_t *), backlog);
+	socket->lconn = calloc(backlog, sizeof(tcp_conn_t *));
 	if (socket->lconn == NULL) {
 		fibril_mutex_unlock(&socket->lock);
@@ -284,5 +284,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - open connections");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - open connections");
 
 	lsocket.addr.ipv4 = TCP_IPV4_ANY;
@@ -293,5 +293,5 @@
 	for (i = 0; i < backlog; i++) {
 
-		lconn = calloc(sizeof(tcp_sock_lconn_t), 1);
+		lconn = calloc(1, sizeof(tcp_sock_lconn_t));
 		if (lconn == NULL) {
 			/* XXX Clean up */
@@ -337,5 +337,5 @@
 	tcp_sock_t fsocket;
 
-	log_msg(LVL_DEBUG, "tcp_sock_connect()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect()");
 
 	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
@@ -377,5 +377,5 @@
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, rc);
-			log_msg(LVL_DEBUG, "tcp_sock_connect: Failed to "
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect: Failed to "
 			    "determine local address.");
 			return;
@@ -383,5 +383,5 @@
 
 		socket->laddr.ipv4 = loc_addr.ipv4;
-		log_msg(LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
 	}
 
@@ -431,5 +431,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_accept()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept()");
 
 	socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -445,5 +445,5 @@
 	fibril_mutex_lock(&socket->lock);
 
-	log_msg(LVL_DEBUG, " - verify socket->conn");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - verify socket->conn");
 	if (socket->conn != NULL) {
 		fibril_mutex_unlock(&socket->lock);
@@ -498,5 +498,5 @@
 
 	asocket->conn = conn;
-	log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept():create asocket\n");
 
 	rc = tcp_sock_finish_setup(asocket, &asock_id);
@@ -510,5 +510,5 @@
 	fibril_add_ready(asocket->recv_fibril);
 
-	log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): find acore\n");
 
 	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
@@ -521,5 +521,5 @@
 	
 	/* Push one fragment notification to client's queue */
-	log_msg(LVL_DEBUG, "tcp_sock_accept(): notify data\n");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): notify data\n");
 	fibril_mutex_unlock(&socket->lock);
 }
@@ -539,5 +539,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_send()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_send()");
 	socket_id = SOCKET_GET_SOCKET_ID(call);
 	fragments = SOCKET_GET_DATA_FRAGMENTS(call);
@@ -611,5 +611,5 @@
 static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_sendto()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_sendto()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -629,5 +629,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
 
 	socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -651,13 +651,13 @@
 	(void)flags;
 
-	log_msg(LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
 	fibril_mutex_lock(&socket->recv_buffer_lock);
 	while (socket->recv_buffer_used == 0 && socket->recv_error == TCP_EOK) {
-		log_msg(LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
 		fibril_condvar_wait(&socket->recv_buffer_cv,
 		    &socket->recv_buffer_lock);
 	}
 
-	log_msg(LVL_DEBUG, "Got data in sock recv_buffer");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
 
 	data_len = socket->recv_buffer_used;
@@ -679,5 +679,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "**** recv result -> %d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv result -> %d", rc);
 	if (rc != EOK) {
 		fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -694,5 +694,5 @@
 		addr.sin_port = host2uint16_t_be(rsock->port);
 
-		log_msg(LVL_DEBUG, "addr read receive");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
 		if (!async_data_read_receive(&rcallid, &addr_length)) {
 			fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -705,5 +705,5 @@
 			addr_length = sizeof(addr);
 
-		log_msg(LVL_DEBUG, "addr read finalize");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
 		rc = async_data_read_finalize(rcallid, &addr, addr_length);
 		if (rc != EOK) {
@@ -715,5 +715,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "data read receive");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
 	if (!async_data_read_receive(&rcallid, &length)) {
 		fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -726,9 +726,9 @@
 		length = data_len;
 
-	log_msg(LVL_DEBUG, "data read finalize");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
 	rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
 
 	socket->recv_buffer_used -= length;
-	log_msg(LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
 	    socket->recv_buffer_used);
 	if (socket->recv_buffer_used > 0) {
@@ -758,5 +758,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_close()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
 	socket_id = SOCKET_GET_SOCKET_ID(call);
 
@@ -798,5 +798,5 @@
 static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_getsockopt()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -804,5 +804,5 @@
 static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_setsockopt()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -815,5 +815,5 @@
 	tcp_sockdata_t *socket = lconn->socket;
 
-	log_msg(LVL_DEBUG, "tcp_sock_cstate_cb()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb()");
 	fibril_mutex_lock(&socket->lock);
 	assert(conn == lconn->conn);
@@ -828,5 +828,5 @@
 	list_append(&lconn->ready_list, &socket->ready);
 
-	log_msg(LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
 
 	/* Push one accept notification to client's queue */
@@ -842,10 +842,10 @@
 	tcp_error_t trc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_recv_fibril()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recv_fibril()");
 
 	fibril_mutex_lock(&sock->recv_buffer_lock);
 
 	while (true) {
-		log_msg(LVL_DEBUG, "call tcp_uc_receive()");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "call tcp_uc_receive()");
 		while (sock->recv_buffer_used != 0 && sock->sock_core != NULL)
 			fibril_condvar_wait(&sock->recv_buffer_cv,
@@ -863,5 +863,5 @@
 		}
 
-		log_msg(LVL_DEBUG, "got data - broadcast recv_buffer_cv");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "got data - broadcast recv_buffer_cv");
 
 		sock->recv_buffer_used = data_len;
@@ -895,5 +895,5 @@
 			break;
 
-		log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
 		    (int)IPC_GET_IMETHOD(call));
 
@@ -940,5 +940,5 @@
 
 	/* Clean up */
-	log_msg(LVL_DEBUG, "tcp_sock_connection: Clean up");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: Clean up");
 	async_hangup(client.sess);
 	socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
Index: uspace/srv/net/tcp/tcp.c
===================================================================
--- uspace/srv/net/tcp/tcp.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/tcp.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -69,5 +69,5 @@
 	size_t pdu_raw_size;
 
-	log_msg(LVL_DEBUG, "tcp_inet_ev_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_inet_ev_recv()");
 
 	pdu_raw = dgram->data;
@@ -76,5 +76,5 @@
 	/* Split into header and payload. */
 
-	log_msg(LVL_DEBUG, "tcp_inet_ev_recv() - split header/payload");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_inet_ev_recv() - split header/payload");
 
 	tcp_pdu_t *pdu;
@@ -84,5 +84,5 @@
 
 	if (pdu_raw_size < sizeof(tcp_header_t)) {
-		log_msg(LVL_WARN, "pdu_raw_size = %zu < sizeof(tcp_header_t) = %zu",
+		log_msg(LOG_DEFAULT, LVL_WARN, "pdu_raw_size = %zu < sizeof(tcp_header_t) = %zu",
 		    pdu_raw_size, sizeof(tcp_header_t));
 		return EINVAL;
@@ -96,5 +96,5 @@
 
 	if (pdu_raw_size < hdr_size) {
-		log_msg(LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
+		log_msg(LOG_DEFAULT, LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
 		    pdu_raw_size, hdr_size);
 		return EINVAL;
@@ -102,14 +102,14 @@
 
 	if (hdr_size < sizeof(tcp_header_t)) {
-		log_msg(LVL_WARN, "hdr_size = %zu < sizeof(tcp_header_t) = %zu",
+		log_msg(LOG_DEFAULT, LVL_WARN, "hdr_size = %zu < sizeof(tcp_header_t) = %zu",
 		    hdr_size, sizeof(tcp_header_t));		return EINVAL;
 	}
 
-	log_msg(LVL_DEBUG, "pdu_raw_size=%zu, hdr_size=%zu",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "pdu_raw_size=%zu, hdr_size=%zu",
 	    pdu_raw_size, hdr_size);
 	pdu = tcp_pdu_create(pdu_raw, hdr_size, pdu_raw + hdr_size,
 	    pdu_raw_size - hdr_size);
 	if (pdu == NULL) {
-		log_msg(LVL_WARN, "Failed creating PDU. Dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Failed creating PDU. Dropped.");
 		return ENOMEM;
 	}
@@ -117,5 +117,5 @@
 	pdu->src_addr.ipv4 = dgram->src.ipv4;
 	pdu->dest_addr.ipv4 = dgram->dest.ipv4;
-	log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
 	    pdu->src_addr.ipv4, pdu->dest_addr.ipv4);
 
@@ -137,5 +137,5 @@
 	pdu_raw = malloc(pdu_raw_size);
 	if (pdu_raw == NULL) {
-		log_msg(LVL_ERROR, "Failed to transmit PDU. Out of memory.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to transmit PDU. Out of memory.");
 		return;
 	}
@@ -153,5 +153,5 @@
 	rc = inet_send(&dgram, INET_TTL_MAX, 0);
 	if (rc != EOK)
-		log_msg(LVL_ERROR, "Failed to transmit PDU.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to transmit PDU.");
 }
 
@@ -162,8 +162,8 @@
 	tcp_sockpair_t rident;
 
-	log_msg(LVL_DEBUG, "tcp_received_pdu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_received_pdu()");
 
 	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. PDU dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. PDU dropped.");
 		return;
 	}
@@ -177,5 +177,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_init()");
 
 	tcp_rqueue_init();
@@ -189,5 +189,5 @@
 	rc = inet_init(IP_PROTO_TCP, &tcp_inet_ev_ops);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed connecting to internet service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting to internet service.");
 		return ENOENT;
 	}
@@ -195,5 +195,5 @@
 	rc = tcp_sock_init();
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed initializing socket service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing socket service.");
 		return ENOENT;
 	}
@@ -208,5 +208,5 @@
 	printf(NAME ": TCP (Transmission Control Protocol) network module\n");
 
-	rc = log_init(NAME, LVL_WARN);
+	rc = log_init(NAME);
 	if (rc != EOK) {
 		printf(NAME ": Failed to initialize log.\n");
Index: uspace/srv/net/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tcp/tqueue.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/tqueue.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -88,5 +88,5 @@
 	tcp_segment_t *seg;
 
-	log_msg(LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
 
 	seg = tcp_segment_make_ctrl(ctrl);
@@ -99,5 +99,5 @@
 	tcp_tqueue_entry_t *tqe;
 
-	log_msg(LVL_DEBUG, "%s: tcp_tqueue_seg(%p, %p)", conn->name, conn,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_tqueue_seg(%p, %p)", conn->name, conn,
 	    seg);
 
@@ -109,5 +109,5 @@
 		rt_seg = tcp_segment_dup(seg);
 		if (rt_seg == NULL) {
-			log_msg(LVL_ERROR, "Memory allocation failed.");
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed.");
 			/* XXX Handle properly */
 			return;
@@ -116,5 +116,5 @@
 		tqe = calloc(1, sizeof(tcp_tqueue_entry_t));
 		if (tqe == NULL) {
-			log_msg(LVL_ERROR, "Memory allocation failed.");
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed.");
 			/* XXX Handle properly */
 			return;
@@ -165,5 +165,5 @@
 	tcp_segment_t *seg;
 
-	log_msg(LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
 
 	/* Number of free sequence numbers in send window */
@@ -172,5 +172,5 @@
 
 	xfer_seqlen = min(snd_buf_seqlen, avail_wnd);
-	log_msg(LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %zu, "
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %" PRIu32 ", "
 	    "xfer_seqlen = %zu", conn->name, snd_buf_seqlen, conn->snd_wnd,
 	    xfer_seqlen);
@@ -185,5 +185,5 @@
 
 	if (send_fin) {
-		log_msg(LVL_DEBUG, "%s: Sending out FIN.", conn->name);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Sending out FIN.", conn->name);
 		/* We are sending out FIN */
 		ctrl = CTL_FIN;
@@ -194,5 +194,5 @@
 	seg = tcp_segment_make_data(ctrl, conn->snd_buf, data_size);
 	if (seg == NULL) {
-		log_msg(LVL_ERROR, "Memory allocation failure.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failure.");
 		return;
 	}
@@ -223,5 +223,5 @@
 	link_t *cur, *next;
 
-	log_msg(LVL_DEBUG, "%s: tcp_tqueue_ack_received(%p)", conn->name,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_tqueue_ack_received(%p)", conn->name,
 	    conn);
 
@@ -239,6 +239,6 @@
 
 			if ((tqe->seg->ctrl & CTL_FIN) != 0) {
-				log_msg(LVL_DEBUG, "Fin has been acked");
-				log_msg(LVL_DEBUG, "SND.UNA=%" PRIu32
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Fin has been acked");
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "SND.UNA=%" PRIu32
 				    " SEG.SEQ=%" PRIu32 " SEG.LEN=%" PRIu32,
 				    conn->snd_una, tqe->seg->seq, tqe->seg->len);
@@ -267,5 +267,5 @@
 void tcp_conn_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_conn_transmit_segment(%p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_transmit_segment(%p, %p)",
 	    conn->name, conn, seg);
 
@@ -282,9 +282,9 @@
 void tcp_transmit_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
 {
-	log_msg(LVL_DEBUG, "tcp_transmit_segment(f:(%x,%u),l:(%x,%u), %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_transmit_segment(f:(%x,%u),l:(%x,%u), %p)",
 	    sp->foreign.addr.ipv4, sp->foreign.port,
 	    sp->local.addr.ipv4, sp->local.port, seg);
 
-	log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
 	    seg->seq, seg->wnd);
 
@@ -300,5 +300,5 @@
 
 	if (tcp_pdu_encode(sp, seg, &pdu) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. Segment dropped.");
 		return;
 	}
@@ -315,10 +315,10 @@
 	link_t *link;
 
-	log_msg(LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
 
 	fibril_mutex_lock(&conn->lock);
 
 	if (conn->cstate == st_closed) {
-		log_msg(LVL_DEBUG, "Connection already closed.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Connection already closed.");
 		fibril_mutex_unlock(&conn->lock);
 		tcp_conn_delref(conn);
@@ -328,5 +328,5 @@
 	link = list_first(&conn->retransmit.list);
 	if (link == NULL) {
-		log_msg(LVL_DEBUG, "Nothing to retransmit");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Nothing to retransmit");
 		fibril_mutex_unlock(&conn->lock);
 		tcp_conn_delref(conn);
@@ -338,5 +338,5 @@
 	rt_seg = tcp_segment_dup(tqe->seg);
 	if (rt_seg == NULL) {
-		log_msg(LVL_ERROR, "Memory allocation failed.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed.");
 		fibril_mutex_unlock(&conn->lock);
 		tcp_conn_delref(conn);
@@ -345,5 +345,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "### %s: retransmitting segment", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: retransmitting segment", conn->name);
 	tcp_conn_transmit_segment(tqe->conn, rt_seg);
 
@@ -358,5 +358,5 @@
 static void tcp_tqueue_timer_set(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
 
 	/* Clear first to make sure we update refcnt correctly */
@@ -371,5 +371,5 @@
 static void tcp_tqueue_timer_clear(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
 
 	if (fibril_timer_clear(conn->retransmit.timer) == fts_active)
Index: uspace/srv/net/tcp/ucall.c
===================================================================
--- uspace/srv/net/tcp/ucall.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/tcp/ucall.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -70,5 +70,5 @@
 	tcp_conn_t *nconn;
 
-	log_msg(LVL_DEBUG, "tcp_uc_open(%p, %p, %s, %s, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open(%p, %p, %s, %s, %p)",
 	    lsock, fsock, acpass == ap_active ? "active" : "passive",
 	    oflags == tcp_open_nonblock ? "nonblock" : "none", conn);
@@ -88,5 +88,5 @@
 
 	/* Wait for connection to be established or reset */
-	log_msg(LVL_DEBUG, "tcp_uc_open: Wait for connection.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Wait for connection.");
 	fibril_mutex_lock(&nconn->lock);
 	while (nconn->cstate == st_listen ||
@@ -97,5 +97,5 @@
 
 	if (nconn->cstate != st_established) {
-		log_msg(LVL_DEBUG, "tcp_uc_open: Connection was reset.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Connection was reset.");
 		assert(nconn->cstate == st_closed);
 		fibril_mutex_unlock(&nconn->lock);
@@ -104,8 +104,8 @@
 
 	fibril_mutex_unlock(&nconn->lock);
-	log_msg(LVL_DEBUG, "tcp_uc_open: Connection was established.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Connection was established.");
 
 	*conn = nconn;
-	log_msg(LVL_DEBUG, "tcp_uc_open -> %p", nconn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open -> %p", nconn);
 	return TCP_EOK;
 }
@@ -118,5 +118,5 @@
 	size_t xfer_size;
 
-	log_msg(LVL_DEBUG, "%s: tcp_uc_send()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_send()", conn->name);
 
 	fibril_mutex_lock(&conn->lock);
@@ -141,5 +141,5 @@
 		buf_free = conn->snd_buf_size - conn->snd_buf_used;
 		while (buf_free == 0 && !conn->reset) {
-			log_msg(LVL_DEBUG, "%s: buf_free == 0, waiting.",
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: buf_free == 0, waiting.",
 			    conn->name);
 			fibril_condvar_wait(&conn->snd_buf_cv, &conn->lock);
@@ -175,5 +175,5 @@
 	size_t xfer_size;
 
-	log_msg(LVL_DEBUG, "%s: tcp_uc_receive()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_receive()", conn->name);
 
 	fibril_mutex_lock(&conn->lock);
@@ -186,5 +186,5 @@
 	/* Wait for data to become available */
 	while (conn->rcv_buf_used == 0 && !conn->rcv_buf_fin && !conn->reset) {
-		log_msg(LVL_DEBUG, "tcp_uc_receive() - wait for data");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_receive() - wait for data");
 		fibril_condvar_wait(&conn->rcv_buf_cv, &conn->lock);
 	}
@@ -223,5 +223,5 @@
 	tcp_tqueue_ctrl_seg(conn, CTL_ACK);
 
-	log_msg(LVL_DEBUG, "%s: tcp_uc_receive() - returning %zu bytes",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_receive() - returning %zu bytes",
 	    conn->name, xfer_size);
 
@@ -234,5 +234,5 @@
 tcp_error_t tcp_uc_close(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "%s: tcp_uc_close()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_close()", conn->name);
 
 	fibril_mutex_lock(&conn->lock);
@@ -258,5 +258,5 @@
 void tcp_uc_abort(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "tcp_uc_abort()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_abort()");
 }
 
@@ -264,5 +264,5 @@
 void tcp_uc_status(tcp_conn_t *conn, tcp_conn_status_t *cstatus)
 {
-	log_msg(LVL_DEBUG, "tcp_uc_status()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_status()");
 	cstatus->cstate = conn->cstate;
 }
@@ -276,5 +276,5 @@
 void tcp_uc_delete(tcp_conn_t *conn)
 {
-	log_msg(LVL_DEBUG, "tcp_uc_delete()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_delete()");
 	tcp_conn_delete(conn);
 }
@@ -282,5 +282,5 @@
 void tcp_uc_set_cstate_cb(tcp_conn_t *conn, tcp_cstate_cb_t cb, void *arg)
 {
-	log_msg(LVL_DEBUG, "tcp_uc_set_ctate_cb(%p, %p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_set_ctate_cb(%p, %p, %p)",
 	    conn, cb, arg);
 
@@ -298,5 +298,5 @@
 	tcp_conn_t *conn;
 
-	log_msg(LVL_DEBUG, "tcp_as_segment_arrived(f:(%x,%u), l:(%x,%u))",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_as_segment_arrived(f:(%x,%u), l:(%x,%u))",
 	    sp->foreign.addr.ipv4, sp->foreign.port,
 	    sp->local.addr.ipv4, sp->local.port);
@@ -304,5 +304,5 @@
 	conn = tcp_conn_find_ref(sp);
 	if (conn == NULL) {
-		log_msg(LVL_WARN, "No connection found.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "No connection found.");
 		tcp_unexpected_segment(sp, seg);
 		return;
@@ -312,5 +312,5 @@
 
 	if (conn->cstate == st_closed) {
-		log_msg(LVL_WARN, "Connection is closed.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Connection is closed.");
 		tcp_unexpected_segment(sp, seg);
 		fibril_mutex_unlock(&conn->lock);
@@ -339,5 +339,5 @@
 void tcp_to_user(void)
 {
-	log_msg(LVL_DEBUG, "tcp_to_user()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_to_user()");
 }
 
Index: uspace/srv/net/udp/assoc.c
===================================================================
--- uspace/srv/net/udp/assoc.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/udp/assoc.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -104,5 +104,5 @@
 static void udp_assoc_free(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "%s: udp_assoc_free(%p)", assoc->name, assoc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_free(%p)", assoc->name, assoc);
 
 	while (!list_empty(&assoc->rcv_queue)) {
@@ -127,5 +127,5 @@
 void udp_assoc_addref(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "%s: upd_assoc_addref(%p)", assoc->name, assoc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: upd_assoc_addref(%p)", assoc->name, assoc);
 	atomic_inc(&assoc->refcnt);
 }
@@ -139,5 +139,5 @@
 void udp_assoc_delref(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "%s: udp_assoc_delref(%p)", assoc->name, assoc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_delref(%p)", assoc->name, assoc);
 
 	if (atomic_predec(&assoc->refcnt) == 0)
@@ -154,5 +154,5 @@
 void udp_assoc_delete(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "%s: udp_assoc_delete(%p)", assoc->name, assoc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_assoc_delete(%p)", assoc->name, assoc);
 
 	assert(assoc->deleted == false);
@@ -192,5 +192,5 @@
 void udp_assoc_set_foreign(udp_assoc_t *assoc, udp_sock_t *fsock)
 {
-	log_msg(LVL_DEBUG, "udp_assoc_set_foreign(%p, %p)", assoc, fsock);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_foreign(%p, %p)", assoc, fsock);
 	fibril_mutex_lock(&assoc->lock);
 	assoc->ident.foreign = *fsock;
@@ -205,5 +205,5 @@
 void udp_assoc_set_local(udp_assoc_t *assoc, udp_sock_t *lsock)
 {
-	log_msg(LVL_DEBUG, "udp_assoc_set_local(%p, %p)", assoc, lsock);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_set_local(%p, %p)", assoc, lsock);
 	fibril_mutex_lock(&assoc->lock);
 	assoc->ident.local = *lsock;
@@ -228,5 +228,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_assoc_send(%p, %p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send(%p, %p, %p)",
 	    assoc, fsock, msg);
 
@@ -261,13 +261,13 @@
 	udp_rcv_queue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "udp_assoc_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv()");
 
 	fibril_mutex_lock(&assoc->lock);
 	while (list_empty(&assoc->rcv_queue)) {
-		log_msg(LVL_DEBUG, "udp_assoc_recv() - waiting");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - waiting");
 		fibril_condvar_wait(&assoc->rcv_queue_cv, &assoc->lock);
 	}
 
-	log_msg(LVL_DEBUG, "udp_assoc_recv() - got a message");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_recv() - got a message");
 	link = list_first(&assoc->rcv_queue);
 	rqe = list_get_instance(link, udp_rcv_queue_entry_t, link);
@@ -291,9 +291,9 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_assoc_received(%p, %p)", rsp, msg);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_received(%p, %p)", rsp, msg);
 
 	assoc = udp_assoc_find_ref(rsp);
 	if (assoc == NULL) {
-		log_msg(LVL_DEBUG, "No association found. Message dropped.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "No association found. Message dropped.");
 		/* XXX Generate ICMP error. */
 		/* XXX Might propagate error directly by error return. */
@@ -303,5 +303,5 @@
 	rc = udp_assoc_queue_msg(assoc, rsp, msg);
 	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "Out of memory. Message dropped.");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Out of memory. Message dropped.");
 		/* XXX Generate ICMP error? */
 	}
@@ -313,5 +313,5 @@
 	udp_rcv_queue_entry_t *rqe;
 
-	log_msg(LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_queue_msg(%p, %p, %p)",
 	    assoc, sp, msg);
 
@@ -336,5 +336,5 @@
 static bool udp_socket_match(udp_sock_t *sock, udp_sock_t *patt)
 {
-	log_msg(LVL_DEBUG, "udp_socket_match(sock=(%x,%u), pat=(%x,%u))",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_socket_match(sock=(%x,%u), pat=(%x,%u))",
 	    sock->addr.ipv4, sock->port, patt->addr.ipv4, patt->port);
 
@@ -347,5 +347,5 @@
 		return false;
 
-	log_msg(LVL_DEBUG, " -> match");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " -> match");
 
 	return true;
@@ -355,5 +355,5 @@
 static bool udp_sockpair_match(udp_sockpair_t *sp, udp_sockpair_t *pattern)
 {
-	log_msg(LVL_DEBUG, "udp_sockpair_match(%p, %p)", sp, pattern);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sockpair_match(%p, %p)", sp, pattern);
 
 	if (!udp_socket_match(&sp->local, &pattern->local))
@@ -363,5 +363,5 @@
 		return false;
 
-	log_msg(LVL_DEBUG, "Socket pair matched.");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Socket pair matched.");
 	return true;
 }
@@ -379,5 +379,5 @@
 static udp_assoc_t *udp_assoc_find_ref(udp_sockpair_t *sp)
 {
-	log_msg(LVL_DEBUG, "udp_assoc_find_ref(%p)", sp);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_find_ref(%p)", sp);
 
 	fibril_mutex_lock(&assoc_list_lock);
@@ -386,5 +386,5 @@
 		udp_assoc_t *assoc = list_get_instance(link, udp_assoc_t, link);
 		udp_sockpair_t *asp = &assoc->ident;
-		log_msg(LVL_DEBUG, "compare with assoc (f:(%x,%u), l:(%x,%u))",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "compare with assoc (f:(%x,%u), l:(%x,%u))",
 		    asp->foreign.addr.ipv4, asp->foreign.port,
 		    asp->local.addr.ipv4, asp->local.port);
@@ -395,5 +395,5 @@
 
 		if (udp_sockpair_match(sp, asp)) {
-			log_msg(LVL_DEBUG, "Returning assoc %p", assoc);
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Returning assoc %p", assoc);
 			udp_assoc_addref(assoc);
 			fibril_mutex_unlock(&assoc_list_lock);
Index: uspace/srv/net/udp/sock.c
===================================================================
--- uspace/srv/net/udp/sock.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/udp/sock.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -88,5 +88,5 @@
 static void udp_sock_notify_data(socket_core_t *sock_core)
 {
-	log_msg(LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
 	async_exch_t *exch = async_exchange_begin(sock_core->sess);
 	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
@@ -103,6 +103,6 @@
 	ipc_call_t answer;
 
-	log_msg(LVL_DEBUG, "udp_sock_socket()");
-	sock = calloc(sizeof(udp_sockdata_t), 1);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_socket()");
+	sock = calloc(1, sizeof(udp_sockdata_t));
 	if (sock == NULL) {
 		async_answer_0(callid, ENOMEM);
@@ -167,6 +167,6 @@
 	udp_error_t urc;
 
-	log_msg(LVL_DEBUG, "udp_sock_bind()");
-	log_msg(LVL_DEBUG, " - async_data_write_accept");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_bind()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
 
 	addr = NULL;
@@ -178,5 +178,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - call socket_bind");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_bind");
 	rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
 	    addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
@@ -192,5 +192,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - call socket_cores_find");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
 	sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
 	if (sock_core == NULL) {
@@ -222,5 +222,5 @@
 	}
 
-	log_msg(LVL_DEBUG, " - success");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
 	async_answer_0(callid, rc);
 out:
@@ -231,5 +231,5 @@
 static void udp_sock_listen(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_listen()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_listen()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -237,5 +237,5 @@
 static void udp_sock_connect(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_connect()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connect()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -243,5 +243,5 @@
 static void udp_sock_accept(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_accept()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_accept()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -264,5 +264,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_sock_send()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_send()");
 
 	addr = NULL;
@@ -323,5 +323,5 @@
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, rc);
-			log_msg(LVL_DEBUG, "udp_sock_sendto: Failed to "
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_sendto: Failed to "
 			    "determine local address.");
 			return;
@@ -329,5 +329,5 @@
 
 		socket->assoc->ident.local.addr.ipv4 = loc_addr.ipv4;
-		log_msg(LVL_DEBUG, "Local IP address is %x",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Local IP address is %x",
 		    socket->assoc->ident.local.addr.ipv4);
 	}
@@ -405,5 +405,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
 
 	socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -427,13 +427,13 @@
 	(void)flags;
 
-	log_msg(LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
 	fibril_mutex_lock(&socket->recv_buffer_lock);
 	while (socket->recv_buffer_used == 0 && socket->recv_error == UDP_EOK) {
-		log_msg(LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
 		fibril_condvar_wait(&socket->recv_buffer_cv,
 		    &socket->recv_buffer_lock);
 	}
 
-	log_msg(LVL_DEBUG, "Got data in sock recv_buffer");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
 
 	rsock = socket->recv_fsock;
@@ -441,5 +441,5 @@
 	urc = socket->recv_error;
 
-	log_msg(LVL_DEBUG, "**** recv data_len=%zu", data_len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv data_len=%zu", data_len);
 
 	switch (urc) {
@@ -458,5 +458,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
 	if (rc != EOK) {
 		fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -472,5 +472,5 @@
 		addr.sin_port = host2uint16_t_be(rsock.port);
 
-		log_msg(LVL_DEBUG, "addr read receive");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
 		if (!async_data_read_receive(&rcallid, &addr_length)) {
 			fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -483,5 +483,5 @@
 			addr_length = sizeof(addr);
 
-		log_msg(LVL_DEBUG, "addr read finalize");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
 		rc = async_data_read_finalize(rcallid, &addr, addr_length);
 		if (rc != EOK) {
@@ -493,5 +493,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "data read receive");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
 	if (!async_data_read_receive(&rcallid, &length)) {
 		fibril_mutex_unlock(&socket->recv_buffer_lock);
@@ -504,5 +504,5 @@
 		length = data_len;
 
-	log_msg(LVL_DEBUG, "data read finalize");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
 	rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
 
@@ -510,5 +510,5 @@
 		rc = EOVERFLOW;
 
-	log_msg(LVL_DEBUG, "read_data_length <- %zu", length);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "read_data_length <- %zu", length);
 	IPC_SET_ARG2(answer, 0);
 	SOCKET_SET_READ_DATA_LENGTH(answer, length);
@@ -531,5 +531,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "tcp_sock_close()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
 	socket_id = SOCKET_GET_SOCKET_ID(call);
 
@@ -557,5 +557,5 @@
 static void udp_sock_getsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_getsockopt()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_getsockopt()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -563,5 +563,5 @@
 static void udp_sock_setsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
 {
-	log_msg(LVL_DEBUG, "udp_sock_setsockopt()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_setsockopt()");
 	async_answer_0(callid, ENOTSUP);
 }
@@ -574,8 +574,8 @@
 	size_t rcvd;
 
-	log_msg(LVL_DEBUG, "udp_sock_recv_fibril()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recv_fibril()");
 
 	while (true) {
-		log_msg(LVL_DEBUG, "[] wait for rcv buffer empty()");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] wait for rcv buffer empty()");
 		fibril_mutex_lock(&sock->recv_buffer_lock);
 		while (sock->recv_buffer_used != 0) {
@@ -584,5 +584,5 @@
 		}
 
-		log_msg(LVL_DEBUG, "[] call udp_uc_receive()");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] call udp_uc_receive()");
 		urc = udp_uc_receive(sock->assoc, sock->recv_buffer,
 		    UDP_FRAGMENT_SIZE, &rcvd, &xflags, &sock->recv_fsock);
@@ -597,5 +597,5 @@
 		}
 
-		log_msg(LVL_DEBUG, "[] got data - broadcast recv_buffer_cv");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "[] got data - broadcast recv_buffer_cv");
 
 		sock->recv_buffer_used = rcvd;
@@ -622,10 +622,10 @@
 
 	while (true) {
-		log_msg(LVL_DEBUG, "udp_sock_connection: wait");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: wait");
 		callid = async_get_call(&call);
 		if (!IPC_GET_IMETHOD(call))
 			break;
 
-		log_msg(LVL_DEBUG, "udp_sock_connection: METHOD=%d",
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: METHOD=%d",
 		    (int)IPC_GET_IMETHOD(call));
 
@@ -670,5 +670,5 @@
 
 	/* Clean up */
-	log_msg(LVL_DEBUG, "udp_sock_connection: Clean up");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: Clean up");
 	async_hangup(client.sess);
 	socket_cores_release(NULL, &client.sockets, &gsock, udp_free_sock_data);
Index: uspace/srv/net/udp/ucall.c
===================================================================
--- uspace/srv/net/udp/ucall.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/udp/ucall.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -47,5 +47,5 @@
 	udp_assoc_t *nassoc;
 
-	log_msg(LVL_DEBUG, "udp_uc_create()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_create()");
 	nassoc = udp_assoc_new(NULL, NULL);
 	if (nassoc == NULL)
@@ -59,5 +59,5 @@
 udp_error_t udp_uc_set_foreign(udp_assoc_t *assoc, udp_sock_t *fsock)
 {
-	log_msg(LVL_DEBUG, "udp_uc_set_foreign(%p, %p)", assoc, fsock);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_set_foreign(%p, %p)", assoc, fsock);
 
 	udp_assoc_set_foreign(assoc, fsock);
@@ -67,5 +67,5 @@
 udp_error_t udp_uc_set_local(udp_assoc_t *assoc, udp_sock_t *lsock)
 {
-	log_msg(LVL_DEBUG, "udp_uc_set_local(%p, %p)", assoc, lsock);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_set_local(%p, %p)", assoc, lsock);
 
 	udp_assoc_set_local(assoc, lsock);
@@ -79,5 +79,5 @@
 	udp_msg_t msg;
 
-	log_msg(LVL_DEBUG, "%s: udp_uc_send()", assoc->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_uc_send()", assoc->name);
 
 	msg.data = data;
@@ -103,5 +103,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "%s: udp_uc_receive()", assoc->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: udp_uc_receive()", assoc->name);
 	rc = udp_assoc_recv(assoc, &msg, fsock);
 	switch (rc) {
@@ -118,5 +118,5 @@
 void udp_uc_status(udp_assoc_t *assoc, udp_assoc_status_t *astatus)
 {
-	log_msg(LVL_DEBUG, "udp_uc_status()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_status()");
 //	cstatus->cstate = conn->cstate;
 }
@@ -124,5 +124,5 @@
 void udp_uc_destroy(udp_assoc_t *assoc)
 {
-	log_msg(LVL_DEBUG, "udp_uc_destroy()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_uc_destroy()");
 	udp_assoc_remove(assoc);
 	udp_assoc_delete(assoc);
Index: uspace/srv/net/udp/udp.c
===================================================================
--- uspace/srv/net/udp/udp.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/udp/udp.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -50,9 +50,9 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_init()");
 
 	rc = udp_inet_init();
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed connecting to internet service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting to internet service.");
 		return ENOENT;
 	}
@@ -60,5 +60,5 @@
 	rc = udp_sock_init();
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed initializing socket service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing socket service.");
 		return ENOENT;
 	}
@@ -73,5 +73,5 @@
 	printf(NAME ": UDP (User Datagram Protocol) service\n");
 
-	rc = log_init(NAME, LVL_DEBUG);
+	rc = log_init(NAME);
 	if (rc != EOK) {
 		printf(NAME ": Failed to initialize log.\n");
Index: uspace/srv/net/udp/udp_inet.c
===================================================================
--- uspace/srv/net/udp/udp_inet.c	(revision 6cd10acfc0149d4728e582f5922234de9820fc86)
+++ uspace/srv/net/udp/udp_inet.c	(revision be1dcc2699d4c96f7d72aa17f9743e49dfc9ec30)
@@ -61,5 +61,5 @@
 	udp_pdu_t *pdu;
 
-	log_msg(LVL_DEBUG, "udp_inet_ev_recv()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_inet_ev_recv()");
 
 	pdu = udp_pdu_new();
@@ -69,5 +69,5 @@
 	pdu->src.ipv4 = dgram->src.ipv4;
 	pdu->dest.ipv4 = dgram->dest.ipv4;
-	log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
 	    pdu->src.ipv4, pdu->dest.ipv4);
 
@@ -84,5 +84,5 @@
 	inet_dgram_t dgram;
 
-	log_msg(LVL_DEBUG, "udp_transmit_pdu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_transmit_pdu()");
 
 	dgram.src.ipv4 = pdu->src.ipv4;
@@ -94,5 +94,5 @@
 	rc = inet_send(&dgram, INET_TTL_MAX, 0);
 	if (rc != EOK)
-		log_msg(LVL_ERROR, "Failed to transmit PDU.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to transmit PDU.");
 
 	return rc;
@@ -105,8 +105,8 @@
 	udp_sockpair_t rident;
 
-	log_msg(LVL_DEBUG, "udp_received_pdu()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_received_pdu()");
 
 	if (udp_pdu_decode(pdu, &rident, &dmsg) != EOK) {
-		log_msg(LVL_WARN, "Not enough memory. PDU dropped.");
+		log_msg(LOG_DEFAULT, LVL_WARN, "Not enough memory. PDU dropped.");
 		return;
 	}
@@ -124,9 +124,9 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "udp_inet_init()");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_inet_init()");
 
 	rc = inet_init(IP_PROTO_UDP, &udp_inet_ev_ops);
 	if (rc != EOK) {
-		log_msg(LVL_ERROR, "Failed connecting to internet service.");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting to internet service.");
 		return ENOENT;
 	}
