Index: Makefile
===================================================================
--- Makefile	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ Makefile	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -43,5 +43,5 @@
 	$(MAKE) -C kernel clean
 	$(MAKE) -C kernel EXTRA_TOOL=stanse
-	$(STANSE) --checker ReachabilityChecker --checker ThreadChecker:contrib/$(STANSE)/ThreadChecker.xml --jobfile kernel/kernel.job
+	$(STANSE) --checker ReachabilityChecker --jobfile kernel/kernel.job
 
 cscope:
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ boot/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 2009 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.
+#
+
+TMP = distroot
+INITRD = initrd
+
+INIT_TASKS = \
+	$(USPACEDIR)/srv/ns/ns \
+	$(USPACEDIR)/srv/loader/loader \
+	$(USPACEDIR)/app/init/init \
+	$(USPACEDIR)/srv/devmap/devmap \
+	$(USPACEDIR)/srv/bd/rd/rd \
+	$(USPACEDIR)/srv/vfs/vfs
+ifeq ($(RDFMT),tmpfs)
+	INIT_TASKS += $(USPACEDIR)/srv/fs/tmpfs/tmpfs
+endif
+ifeq ($(RDFMT),fat)
+	INIT_TASKS += $(USPACEDIR)/srv/fs/fat/fat
+endif
+
+RD_SRVS = \
+	$(USPACEDIR)/srv/fb/fb \
+	$(USPACEDIR)/srv/kbd/kbd \
+	$(USPACEDIR)/srv/console/console \
+	$(USPACEDIR)/srv/clip/clip \
+	$(USPACEDIR)/srv/fs/devfs/devfs \
+	$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
+	$(USPACEDIR)/srv/fs/fat/fat \
+	$(USPACEDIR)/srv/bd/file_bd/file_bd \
+	$(USPACEDIR)/srv/part/mbr_part/mbr_part
+
+RD_APPS = \
+	$(USPACEDIR)/app/edit/edit \
+	$(USPACEDIR)/app/getvc/getvc \
+	$(USPACEDIR)/app/redir/redir \
+	$(USPACEDIR)/app/tetris/tetris \
+	$(USPACEDIR)/app/tester/tester \
+	$(USPACEDIR)/app/trace/trace \
+	$(USPACEDIR)/app/klog/klog \
+	$(USPACEDIR)/app/bdsh/bdsh
+
+COMPONENTS = \
+	$(KERNELDIR)/kernel.bin \
+	$(USPACEDIR)/srv/ns/ns \
+	$(USPACEDIR)/app/init/init \
+	$(USPACEDIR)/srv/loader/loader \
+	$(USPACEDIR)/srv/devmap/devmap \
+	$(USPACEDIR)/srv/bd/rd/rd \
+	$(USPACEDIR)/srv/vfs/vfs
+ifeq ($(RDFMT),tmpfs)
+	COMPONENTS += $(USPACEDIR)/srv/fs/tmpfs/tmpfs
+endif
+ifeq ($(RDFMT),fat)
+	COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
+endif
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/amd64/Makefile.inc	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -27,53 +27,31 @@
 #
 
-TMP = distroot
+include Makefile.common
 
-INIT_TASKS = \
-	$(USPACEDIR)/srv/ns/ns \
-	$(USPACEDIR)/srv/loader/loader \
-	$(USPACEDIR)/app/init/init \
-	$(USPACEDIR)/srv/devmap/devmap \
-	$(USPACEDIR)/srv/bd/rd/rd \
-	$(USPACEDIR)/srv/vfs/vfs
-ifeq ($(RDFMT),tmpfs)
-	INIT_TASKS += $(USPACEDIR)/srv/fs/tmpfs/tmpfs
-endif
-ifeq ($(RDFMT),fat)
-	INIT_TASKS += $(USPACEDIR)/srv/fs/fat/fat
-endif
+RD_SRVS += \
+	$(USPACEDIR)/srv/pci/pci \
+	$(USPACEDIR)/srv/bd/ata_bd/ata_bd
 
-RD_SRVS = \
-	$(USPACEDIR)/srv/pci/pci \
-	$(USPACEDIR)/srv/fb/fb \
-	$(USPACEDIR)/srv/kbd/kbd \
-	$(USPACEDIR)/srv/console/console \
-	$(USPACEDIR)/srv/fs/devfs/devfs \
-	$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
-	$(USPACEDIR)/srv/fs/fat/fat \
-	$(USPACEDIR)/srv/bd/ata_bd/ata_bd \
-	$(USPACEDIR)/srv/bd/file_bd/file_bd \
-	$(USPACEDIR)/srv/part/mbr_part/mbr_part
-
-RD_APPS = \
-	$(USPACEDIR)/app/edit/edit \
-	$(USPACEDIR)/app/getvc/getvc \
-	$(USPACEDIR)/app/redir/redir \
-	$(USPACEDIR)/app/tetris/tetris \
-	$(USPACEDIR)/app/tester/tester \
-	$(USPACEDIR)/app/trace/trace \
-	$(USPACEDIR)/app/klog/klog \
-	$(USPACEDIR)/app/bdsh/bdsh
+MODULES := $(notdir $(COMPONENTS))
 
 build: $(BASE)/image.iso
 
-$(BASE)/image.iso: arch/$(BARCH)/grub/stage2_eltorito arch/$(BARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_SRVS) $(RD_APPS)
+$(BASE)/image.iso: arch/$(BARCH)/grub/stage2_eltorito $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_SRVS) $(RD_APPS)
 	mkdir -p $(TMP)/boot/grub
 	cp arch/$(BARCH)/grub/stage2_eltorito $(TMP)/boot/grub/
-ifneq ($(RDFMT),tmpfs)
-	cat arch/$(BARCH)/grub/menu.lst | grep -v "tmpfs" > $(TMP)/boot/grub/menu.lst
-endif
-ifneq ($(RDFMT),fat)
-	cat arch/$(BARCH)/grub/menu.lst | grep -v "fat" > $(TMP)/boot/grub/menu.lst
-endif
+	
+	echo "default 0" > $(TMP)/boot/grub/menu.lst
+	echo "timeout 10" >> $(TMP)/boot/grub/menu.lst
+	echo "" >> $(TMP)/boot/grub/menu.lst
+	echo "title=HelenOS" >> $(TMP)/boot/grub/menu.lst
+	echo "	root (cd)" >> $(TMP)/boot/grub/menu.lst
+	for module in $(MODULES) $(INITRD).img ; do \
+		if [ $$module == kernel.bin ] ; then \
+			echo "	kernel /boot/$$module" >> $(TMP)/boot/grub/menu.lst ; \
+		else \
+			echo "	module /boot/$$module" >> $(TMP)/boot/grub/menu.lst ; \
+		fi \
+	done
+	
 	cp $(KERNELDIR)/kernel.bin $(TMP)/boot/
 	for task in $(INIT_TASKS) ; do \
@@ -86,12 +64,13 @@
 		cp $$file $(USPACEDIR)/dist/app/ ; \
 	done
+	
 ifeq ($(RDFMT),tmpfs)
-	$(BASE)/tools/mktmpfs.py $(USPACEDIR)/dist/ $(TMP)/boot/initrd.fs
+	$(BASE)/tools/mktmpfs.py $(USPACEDIR)/dist/ $(TMP)/boot/$(INITRD).fs
 endif
 ifeq ($(RDFMT),fat)
-	$(BASE)/tools/mkfat.py $(USPACEDIR)/dist/ $(TMP)/boot/initrd.fs
+	$(BASE)/tools/mkfat.py $(USPACEDIR)/dist/ $(TMP)/boot/$(INITRD).fs
 endif
-	$(BASE)/tools/mkhord.py 4096 $(TMP)/boot/initrd.fs $(TMP)/boot/initrd.img
-	rm $(TMP)/boot/initrd.fs
+	$(BASE)/tools/mkhord.py 4096 $(TMP)/boot/$(INITRD).fs $(TMP)/boot/$(INITRD).img
+	rm $(TMP)/boot/$(INITRD).fs
 	mkisofs -J -r -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o $@ $(TMP)/
 
Index: ot/arch/amd64/grub/menu.lst
===================================================================
--- boot/arch/amd64/grub/menu.lst	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ 	(revision )
@@ -1,15 +1,0 @@
-default 0
-timeout 10
-
-title=HelenOS
-	root (cd)
-	kernel /boot/kernel.bin
-	module /boot/ns
-	module /boot/init
-	module /boot/devmap
-	module /boot/rd
-	module /boot/vfs
-	module /boot/tmpfs
-	module /boot/fat
-	module /boot/loader
-	module /boot/initrd.img
Index: boot/arch/arm32/loader/Makefile.build
===================================================================
--- boot/arch/arm32/loader/Makefile.build	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/arm32/loader/Makefile.build	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -51,19 +51,4 @@
 	../../../genarch/division.c
 
-COMPONENTS = \
-	$(KERNELDIR)/kernel.bin \
-	$(USPACEDIR)/srv/ns/ns \
-	$(USPACEDIR)/srv/loader/loader \
-	$(USPACEDIR)/app/init/init \
-	$(USPACEDIR)/srv/devmap/devmap \
-	$(USPACEDIR)/srv/bd/rd/rd \
-	$(USPACEDIR)/srv/vfs/vfs
-ifeq ($(RDFMT),tmpfs)
-	COMPONENTS += $(USPACEDIR)/srv/fs/tmpfs/tmpfs
-endif
-ifeq ($(RDFMT),fat)
-	COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
-endif
-
 OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 COMPONENT_OBJECTS := $(addsuffix .co,$(basename $(notdir $(COMPONENTS)))) $(INITRD).co
Index: boot/arch/arm32/loader/Makefile.common
===================================================================
--- boot/arch/arm32/loader/Makefile.common	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/arm32/loader/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -31,4 +31,6 @@
 #
 
+include ../../../Makefile.common
+
 DEPEND = Makefile.depend
 DEPEND_PREV = $(DEPEND).prev
@@ -37,27 +39,7 @@
 LINK = _link.ld
 COMPS = _components
-INITRD = initrd
 
 KERNELDIR = ../../../../kernel
 USPACEDIR = ../../../../uspace
 
-RD_SRVS = \
-	$(USPACEDIR)/srv/fb/fb \
-	$(USPACEDIR)/srv/kbd/kbd \
-	$(USPACEDIR)/srv/console/console \
-	$(USPACEDIR)/srv/fs/devfs/devfs \
-	$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
-	$(USPACEDIR)/srv/fs/fat/fat \
-	$(USPACEDIR)/srv/bd/file_bd/file_bd \
-	$(USPACEDIR)/srv/part/mbr_part/mbr_part \
-	$(USPACEDIR)/srv/bd/gxe_bd/gxe_bd
-
-RD_APPS = \
-	$(USPACEDIR)/app/edit/edit \
-	$(USPACEDIR)/app/getvc/getvc \
-	$(USPACEDIR)/app/redir/redir \
-	$(USPACEDIR)/app/tetris/tetris \
-	$(USPACEDIR)/app/tester/tester \
-	$(USPACEDIR)/app/trace/trace \
-	$(USPACEDIR)/app/klog/klog \
-	$(USPACEDIR)/app/bdsh/bdsh
+RD_SRVS += $(USPACEDIR)/srv/bd/gxe_bd/gxe_bd
Index: boot/arch/ia64/loader/Makefile.build
===================================================================
--- boot/arch/ia64/loader/Makefile.build	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/ia64/loader/Makefile.build	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -49,19 +49,4 @@
 	boot.S
 
-COMPONENTS = \
-	$(KERNELDIR)/kernel.bin \
-	$(USPACEDIR)/srv/ns/ns \
-	$(USPACEDIR)/srv/loader/loader \
-	$(USPACEDIR)/app/init/init \
-	$(USPACEDIR)/srv/devmap/devmap \
-	$(USPACEDIR)/srv/bd/rd/rd \
-	$(USPACEDIR)/srv/vfs/vfs
-ifeq ($(RDFMT),tmpfs)
-	COMPONENTS += $(USPACEDIR)/srv/fs/tmpfs/tmpfs
-endif
-ifeq ($(RDFMT),fat)
-	COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
-endif
-
 OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 COMPONENT_OBJECTS := $(addsuffix .co,$(basename $(notdir $(COMPONENTS)))) $(INITRD).co
Index: boot/arch/ia64/loader/Makefile.common
===================================================================
--- boot/arch/ia64/loader/Makefile.common	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/ia64/loader/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -31,4 +31,6 @@
 #
 
+include ../../../Makefile.common
+
 DEPEND = Makefile.depend
 DEPEND_PREV = $(DEPEND).prev
@@ -38,26 +40,5 @@
 LINK = _link.ld
 COMPS = _components
-INITRD = initrd
 
 KERNELDIR = ../../../../kernel
 USPACEDIR = ../../../../uspace
-
-RD_SRVS = \
-	$(USPACEDIR)/srv/fb/fb \
-	$(USPACEDIR)/srv/kbd/kbd \
-	$(USPACEDIR)/srv/console/console \
-	$(USPACEDIR)/srv/fs/devfs/devfs \
-	$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
-	$(USPACEDIR)/srv/fs/fat/fat \
-	$(USPACEDIR)/srv/bd/file_bd/file_bd \
-	$(USPACEDIR)/srv/part/mbr_part/mbr_part
-
-RD_APPS = \
-	$(USPACEDIR)/app/edit/edit \
-	$(USPACEDIR)/app/getvc/getvc \
-	$(USPACEDIR)/app/redir/redir \
-	$(USPACEDIR)/app/tetris/tetris \
-	$(USPACEDIR)/app/tester/tester \
-	$(USPACEDIR)/app/trace/trace \
-	$(USPACEDIR)/app/klog/klog \
-	$(USPACEDIR)/app/bdsh/bdsh
Index: boot/arch/mips32/loader/Makefile.build
===================================================================
--- boot/arch/mips32/loader/Makefile.build	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/mips32/loader/Makefile.build	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -49,19 +49,4 @@
 	boot.S
 
-COMPONENTS = \
-	$(KERNELDIR)/kernel.bin \
-	$(USPACEDIR)/srv/ns/ns \
-	$(USPACEDIR)/srv/loader/loader \
-	$(USPACEDIR)/app/init/init \
-	$(USPACEDIR)/srv/devmap/devmap \
-	$(USPACEDIR)/srv/bd/rd/rd \
-	$(USPACEDIR)/srv/vfs/vfs
-ifeq ($(RDFMT),tmpfs)
-	COMPONENTS += $(USPACEDIR)/srv/fs/tmpfs/tmpfs
-endif
-ifeq ($(RDFMT),fat)
-	COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
-endif
-
 OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 COMPONENT_OBJECTS := $(addsuffix .co,$(basename $(notdir $(COMPONENTS)))) $(INITRD).co
Index: boot/arch/mips32/loader/Makefile.common
===================================================================
--- boot/arch/mips32/loader/Makefile.common	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/mips32/loader/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -31,4 +31,6 @@
 #
 
+include ../../../Makefile.common
+
 DEPEND = Makefile.depend
 DEPEND_PREV = $(DEPEND).prev
@@ -38,27 +40,7 @@
 LINK = _link.ld
 COMPS = _components
-INITRD = initrd
 
 KERNELDIR = ../../../../kernel
 USPACEDIR = ../../../../uspace
 
-RD_SRVS = \
-	$(USPACEDIR)/srv/fb/fb \
-	$(USPACEDIR)/srv/kbd/kbd \
-	$(USPACEDIR)/srv/console/console \
-	$(USPACEDIR)/srv/fs/devfs/devfs \
-	$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
-	$(USPACEDIR)/srv/fs/fat/fat \
-	$(USPACEDIR)/srv/bd/file_bd/file_bd \
-	$(USPACEDIR)/srv/part/mbr_part/mbr_part \
-	$(USPACEDIR)/srv/bd/gxe_bd/gxe_bd
-
-RD_APPS = \
-	$(USPACEDIR)/app/edit/edit \
-	$(USPACEDIR)/app/getvc/getvc \
-	$(USPACEDIR)/app/redir/redir \
-	$(USPACEDIR)/app/tetris/tetris \
-	$(USPACEDIR)/app/tester/tester \
-	$(USPACEDIR)/app/trace/trace \
-	$(USPACEDIR)/app/klog/klog \
-	$(USPACEDIR)/app/bdsh/bdsh
+RD_SRVS += $(USPACEDIR)/srv/bd/gxe_bd/gxe_bd
Index: boot/arch/ppc32/Makefile.inc
===================================================================
--- boot/arch/ppc32/Makefile.inc	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/ppc32/Makefile.inc	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -27,5 +27,5 @@
 #
 
-TMP = distroot
+include Makefile.common
 
 build: $(BASE)/image.iso
Index: boot/arch/ppc32/loader/Makefile.build
===================================================================
--- boot/arch/ppc32/loader/Makefile.build	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/ppc32/loader/Makefile.build	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -52,19 +52,4 @@
 	boot.S
 
-COMPONENTS = \
-	$(KERNELDIR)/kernel.bin \
-	$(USPACEDIR)/srv/ns/ns \
-	$(USPACEDIR)/app/init/init \
-	$(USPACEDIR)/srv/loader/loader \
-	$(USPACEDIR)/srv/devmap/devmap \
-	$(USPACEDIR)/srv/bd/rd/rd \
-	$(USPACEDIR)/srv/vfs/vfs
-ifeq ($(RDFMT),tmpfs)
-	COMPONENTS += $(USPACEDIR)/srv/fs/tmpfs/tmpfs
-endif
-ifeq ($(RDFMT),fat)
-	COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
-endif
-
 OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 COMPONENT_OBJECTS := $(addsuffix .co,$(basename $(notdir $(COMPONENTS)))) $(INITRD).co
Index: boot/arch/ppc32/loader/Makefile.common
===================================================================
--- boot/arch/ppc32/loader/Makefile.common	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/ppc32/loader/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -31,4 +31,6 @@
 #
 
+include ../../../Makefile.common
+
 DEPEND = Makefile.depend
 DEPEND_PREV = $(DEPEND).prev
@@ -37,26 +39,5 @@
 LINK = _link.ld
 COMPS = _components
-INITRD = initrd
 
 KERNELDIR = ../../../../kernel
 USPACEDIR = ../../../../uspace
-
-RD_SRVS = \
-	$(USPACEDIR)/srv/fb/fb \
-	$(USPACEDIR)/srv/kbd/kbd \
-	$(USPACEDIR)/srv/console/console \
-	$(USPACEDIR)/srv/fs/devfs/devfs \
-	$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
-	$(USPACEDIR)/srv/fs/fat/fat \
-	$(USPACEDIR)/srv/bd/file_bd/file_bd \
-	$(USPACEDIR)/srv/part/mbr_part/mbr_part
-
-RD_APPS = \
-	$(USPACEDIR)/app/edit/edit \
-	$(USPACEDIR)/app/getvc/getvc \
-	$(USPACEDIR)/app/redir/redir \
-	$(USPACEDIR)/app/tetris/tetris \
-	$(USPACEDIR)/app/tester/tester \
-	$(USPACEDIR)/app/trace/trace \
-	$(USPACEDIR)/app/klog/klog \
-	$(USPACEDIR)/app/bdsh/bdsh
Index: boot/arch/sparc64/Makefile.inc
===================================================================
--- boot/arch/sparc64/Makefile.inc	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/sparc64/Makefile.inc	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -27,5 +27,5 @@
 #
 
-TMP = distroot
+include Makefile.common
 
 ifeq ($(CONFIG_AOUT_ISOFS_B),y)
Index: boot/arch/sparc64/loader/Makefile.build
===================================================================
--- boot/arch/sparc64/loader/Makefile.build	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/sparc64/loader/Makefile.build	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -52,19 +52,4 @@
 	boot.S
 
-COMPONENTS = \
-	$(KERNELDIR)/kernel.bin \
-	$(USPACEDIR)/srv/ns/ns \
-	$(USPACEDIR)/app/init/init \
-	$(USPACEDIR)/srv/loader/loader \
-	$(USPACEDIR)/srv/devmap/devmap \
-	$(USPACEDIR)/srv/bd/rd/rd \
-	$(USPACEDIR)/srv/vfs/vfs
-ifeq ($(RDFMT),tmpfs)
-	COMPONENTS += $(USPACEDIR)/srv/fs/tmpfs/tmpfs
-endif
-ifeq ($(RDFMT),fat)
-	COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
-endif
-
 OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 
Index: boot/arch/sparc64/loader/Makefile.common
===================================================================
--- boot/arch/sparc64/loader/Makefile.common	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ boot/arch/sparc64/loader/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -31,4 +31,6 @@
 #
 
+include ../../../Makefile.common
+
 DEPEND = Makefile.depend
 DEPEND_PREV = $(DEPEND).prev
@@ -37,26 +39,7 @@
 LINK = _link.ld
 COMPS = _components
-INITRD = initrd
 
 KERNELDIR = ../../../../kernel
 USPACEDIR = ../../../../uspace
-
-RD_SRVS = \
-	$(USPACEDIR)/srv/fb/fb \
-	$(USPACEDIR)/srv/kbd/kbd \
-	$(USPACEDIR)/srv/console/console \
-	$(USPACEDIR)/srv/fs/devfs/devfs \
-	$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
-	$(USPACEDIR)/srv/bd/file_bd/file_bd \
-	$(USPACEDIR)/srv/part/mbr_part/mbr_part
-
-RD_APPS = \
-	$(USPACEDIR)/app/edit/edit \
-	$(USPACEDIR)/app/getvc/getvc \
-	$(USPACEDIR)/app/redir/redir \
-	$(USPACEDIR)/app/tetris/tetris \
-	$(USPACEDIR)/app/trace/trace \
-	$(USPACEDIR)/app/klog/klog \
-	$(USPACEDIR)/app/bdsh/bdsh
 
 RD_SRVS_GENERIC = \
Index: kernel/arch/amd64/src/amd64.c
===================================================================
--- kernel/arch/amd64/src/amd64.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/amd64/src/amd64.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -67,4 +67,5 @@
 #include <ddi/irq.h>
 #include <sysinfo/sysinfo.h>
+#include <memstr.h>
 
 /** Disable I/O on non-privileged levels
Index: kernel/arch/arm32/Makefile.inc
===================================================================
--- kernel/arch/arm32/Makefile.inc	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/arm32/Makefile.inc	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -61,5 +61,6 @@
 	arch/$(KARCH)/src/mm/page.c \
 	arch/$(KARCH)/src/mm/tlb.c \
-	arch/$(KARCH)/src/mm/page_fault.c
+	arch/$(KARCH)/src/mm/page_fault.c \
+	arch/$(KARCH)/src/ras.c
 
 ifeq ($(MACHINE),testarm)
Index: kernel/arch/arm32/include/atomic.h
===================================================================
--- kernel/arch/arm32/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/arm32/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -37,4 +37,6 @@
 #define KERN_arm32_ATOMIC_H_
 
+#include <arch/asm.h>
+
 /** Atomic addition.
  *
@@ -47,19 +49,14 @@
 static inline long atomic_add(atomic_t *val, int i)
 {
-	int ret;
-	volatile long *mem = &(val->count);
-	
-	asm volatile (
-		"1:\n"
-			"ldr r2, [%[mem]]\n"
-			"add r3, r2, %[i]\n"
-			"str r3, %[ret]\n"
-			"swp r3, r3, [%[mem]]\n"
-			"cmp r3, r2\n"
-			"bne 1b\n"
-		: [ret] "=m" (ret)
-		: [mem] "r" (mem), [i] "r" (i)
-		: "r3", "r2"
-	);
+	long ret;
+
+	/*
+	 * This implementation is for UP pre-ARMv6 systems where we do not have
+	 * the LDREX and STREX instructions.
+	 */
+	ipl_t ipl = interrupts_disable();
+	val->count += i;
+	ret = val->count;
+	interrupts_restore(ipl);
 	
 	return ret;
Index: kernel/arch/arm32/include/mm/as.h
===================================================================
--- kernel/arch/arm32/include/mm/as.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/arm32/include/mm/as.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -54,5 +54,4 @@
 #define as_destructor_arch(as)			(as != as)
 #define as_create_arch(as, flags)		(as != as)
-#define as_install_arch(as)
 #define as_deinstall_arch(as)
 #define as_invalidate_translation_cache(as, page, cnt)
Index: kernel/arch/arm32/include/ras.h
===================================================================
--- kernel/arch/arm32/include/ras.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ kernel/arch/arm32/include/ras.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009 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 arm32
+ * @{
+ */
+/** @file
+ *  @brief Declarations related to Restartable Atomic Sequences.
+ */
+
+#ifndef KERN_arm32_RAS_H_
+#define KERN_arm32_RAS_H_
+
+#include <arch/exception.h>
+#include <arch/types.h>
+
+#define RAS_START	0
+#define RAS_END		1
+
+extern uintptr_t *ras_page;
+
+extern void ras_init(void);
+extern void ras_check(int, istate_t *);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/arm32/src/arm32.c
===================================================================
--- kernel/arch/arm32/src/arm32.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/arm32/src/arm32.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -48,4 +48,5 @@
 #include <macros.h>
 #include <string.h>
+#include <arch/ras.h>
 
 #ifdef MACHINE_testarm
@@ -88,4 +89,7 @@
 	exception_init();
 	interrupt_init();
+
+	/* Initialize Restartable Atomic Sequences support. */
+	ras_init();
 	
 	machine_output_init();
@@ -136,5 +140,4 @@
 	uint8_t *stck;
 	
-	tlb_invalidate_all();
 	stck = &THREAD->kstack[THREAD_STACK_SIZE - SP_DELTA];
 	supervisor_sp = (uintptr_t) stck;
Index: kernel/arch/arm32/src/exc_handler.S
===================================================================
--- kernel/arch/arm32/src/exc_handler.S	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/arm32/src/exc_handler.S	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -148,5 +148,5 @@
 	mov r0, #0
 	mov r1, r13
-	bl exc_dispatch
+	bl ras_check 
 	LOAD_REGS_FROM_STACK
 
@@ -156,5 +156,5 @@
 	mov r0, #5
 	mov r1, r13
-	bl exc_dispatch
+	bl ras_check 
 	LOAD_REGS_FROM_STACK
 
@@ -164,5 +164,5 @@
 	mov r0, #6
 	mov r1, r13
-	bl exc_dispatch
+	bl ras_check 
 	LOAD_REGS_FROM_STACK
 
@@ -171,5 +171,5 @@
 	mov r0, #1
 	mov r1, r13
-	bl exc_dispatch
+	bl ras_check 
 	LOAD_REGS_FROM_STACK
 
@@ -179,5 +179,5 @@
 	mov r0, #3
 	mov r1, r13
-	bl exc_dispatch
+	bl ras_check 
 	LOAD_REGS_FROM_STACK
 
@@ -187,5 +187,5 @@
 	mov r0, #4
 	mov r1, r13
-	bl exc_dispatch
+	bl ras_check 
 	LOAD_REGS_FROM_STACK
 
@@ -195,5 +195,5 @@
 	mov r0, #2
 	mov r1, r13
-	bl exc_dispatch
+	bl ras_check
 	LOAD_REGS_FROM_STACK
 
Index: kernel/arch/arm32/src/mm/as.c
===================================================================
--- kernel/arch/arm32/src/mm/as.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/arm32/src/mm/as.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,6 +36,8 @@
 #include <arch/mm/as.h>
 #include <genarch/mm/as_pt.h>
+#include <genarch/mm/page_pt.h>
 #include <genarch/mm/asid_fifo.h>
 #include <mm/as.h>
+#include <mm/tlb.h>
 #include <arch.h>
 
@@ -49,4 +51,9 @@
 }
 
+void as_install_arch(as_t *as)
+{
+	tlb_invalidate_all();
+}
+
 /** @}
  */
Index: kernel/arch/arm32/src/ras.c
===================================================================
--- kernel/arch/arm32/src/ras.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ kernel/arch/arm32/src/ras.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009 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 arm32
+ * @{
+ */
+/** @file
+ *  @brief Kernel part of Restartable Atomic Sequences support.
+ */
+
+#include <arch/ras.h>
+#include <mm/mm.h>
+#include <mm/frame.h>
+#include <mm/page.h>
+#include <mm/tlb.h>
+#include <mm/asid.h>
+#include <interrupt.h>
+#include <arch/exception.h>
+#include <arch.h>
+#include <memstr.h>
+#include <arch/types.h>
+
+uintptr_t *ras_page = NULL;
+
+void ras_init(void)
+{
+	ras_page = frame_alloc(ONE_FRAME, FRAME_KA);
+	memsetb(ras_page, FRAME_SIZE, 0); 
+	ras_page[RAS_START] = 0;
+	ras_page[RAS_END] = 0xffffffff;
+	/*
+	 * Userspace needs to be able to write to this page. The page is 
+	 * cached in TLB as PAGE_KERNEL. Purge it from TLB and map it
+	 * read/write PAGE_USER.
+	 */
+	tlb_invalidate_pages(ASID_KERNEL, (uintptr_t)ras_page, 1);
+	page_table_lock(AS, true);
+	page_mapping_insert(AS, (uintptr_t)ras_page, (uintptr_t)KA2PA(ras_page),
+	    PAGE_READ | PAGE_WRITE | PAGE_USER);
+	page_table_unlock(AS, true);
+}
+
+void ras_check(int n, istate_t *istate)
+{
+	uintptr_t rewrite_pc = istate->pc;
+
+	if (istate_from_uspace(istate)) {
+		if (ras_page[RAS_START]) {
+			if ((ras_page[RAS_START] < istate->pc) &&
+			    (ras_page[RAS_END] > istate->pc)) {
+				rewrite_pc = ras_page[RAS_START];
+			}
+			ras_page[RAS_START] = 0;
+			ras_page[RAS_END] = 0xffffffff;
+		}	
+	}
+
+	exc_dispatch(n, istate);
+
+	istate->pc = rewrite_pc;
+}
+
Index: kernel/arch/arm32/src/userspace.c
===================================================================
--- kernel/arch/arm32/src/userspace.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/arm32/src/userspace.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -35,4 +35,5 @@
 
 #include <userspace.h>
+#include <arch/ras.h>
 
 /** Struct for holding all general purpose registers.
@@ -74,8 +75,11 @@
 	ustate.r1 = 0;
 
+	/* pass the RAS page address in %r2 */
+	ustate.r2 = (uintptr_t) ras_page;
+
 	/* clear other registers */
-	ustate.r2 = ustate.r3  = ustate.r4  = ustate.r5 =
-	    ustate.r6  = ustate.r7  = ustate.r8  = ustate.r9 = ustate.r10 = 
-	    ustate.r11 = ustate.r12 = ustate.lr = 0;
+	ustate.r3  = ustate.r4  = ustate.r5 = ustate.r6 = ustate.r7 =
+	    ustate.r8 = ustate.r9 = ustate.r10 = ustate.r11 = ustate.r12 =
+	    ustate.lr = 0;
 
 	/* set user stack */
Index: kernel/arch/ia32/src/ia32.c
===================================================================
--- kernel/arch/ia32/src/ia32.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/ia32/src/ia32.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -68,4 +68,5 @@
 #include <sysinfo/sysinfo.h>
 #include <arch/boot/boot.h>
+#include <memstr.h>
 
 #ifdef CONFIG_SMP
Index: kernel/arch/ia64/src/cpu/cpu.c
===================================================================
--- kernel/arch/ia64/src/cpu/cpu.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/ia64/src/cpu/cpu.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -37,4 +37,5 @@
 #include <arch/register.h>
 #include <print.h>
+#include <memstr.h>
 
 void cpu_arch_init(void)
Index: kernel/arch/ppc32/src/mm/as.c
===================================================================
--- kernel/arch/ppc32/src/mm/as.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/ppc32/src/mm/as.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -35,4 +35,5 @@
 #include <arch/mm/as.h>
 #include <genarch/mm/as_pt.h>
+#include <genarch/mm/page_pt.h>
 #include <genarch/mm/asid_fifo.h>
 #include <arch.h>
Index: kernel/arch/ppc32/src/mm/tlb.c
===================================================================
--- kernel/arch/ppc32/src/mm/tlb.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/ppc32/src/mm/tlb.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -38,4 +38,5 @@
 #include <interrupt.h>
 #include <mm/as.h>
+#include <mm/page.h>
 #include <arch.h>
 #include <print.h>
Index: kernel/arch/ppc32/src/ppc32.c
===================================================================
--- kernel/arch/ppc32/src/ppc32.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/ppc32/src/ppc32.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -44,4 +44,5 @@
 #include <genarch/ofw/pci.h>
 #include <userspace.h>
+#include <mm/page.h>
 #include <proc/uarg.h>
 #include <console/console.h>
Index: kernel/arch/sparc64/src/drivers/kbd.c
===================================================================
--- kernel/arch/sparc64/src/drivers/kbd.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/sparc64/src/drivers/kbd.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -39,4 +39,5 @@
 #include <console/console.h>
 #include <ddi/irq.h>
+#include <mm/page.h>
 #include <arch/mm/page.h>
 #include <arch/types.h>
Index: kernel/arch/sparc64/src/mm/page.c
===================================================================
--- kernel/arch/sparc64/src/mm/page.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/sparc64/src/mm/page.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -33,4 +33,5 @@
  */
 
+#include <mm/page.h>
 #include <arch/mm/page.h>
 #include <arch/mm/tlb.h>
Index: kernel/arch/sparc64/src/mm/sun4u/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4u/tlb.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/sparc64/src/mm/sun4u/tlb.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -50,4 +50,5 @@
 #include <panic.h>
 #include <arch/asm.h>
+#include <genarch/mm/page_ht.h>
 
 #ifdef CONFIG_TSB
Index: kernel/arch/sparc64/src/mm/sun4v/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4v/tlb.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/arch/sparc64/src/mm/sun4v/tlb.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -54,4 +54,5 @@
 #include <arch/cpu.h>
 #include <arch/mm/pagesize.h>
+#include <genarch/mm/page_ht.h>
 
 #ifdef CONFIG_TSB
Index: kernel/genarch/src/drivers/via-cuda/cuda.c
===================================================================
--- kernel/genarch/src/drivers/via-cuda/cuda.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/genarch/src/drivers/via-cuda/cuda.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -41,4 +41,5 @@
 #include <ddi/device.h>
 #include <synch/spinlock.h>
+#include <memstr.h>
 
 static irq_ownership_t cuda_claim(irq_t *irq);
Index: kernel/genarch/src/fb/fb.c
===================================================================
--- kernel/genarch/src/fb/fb.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/genarch/src/fb/fb.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -41,4 +41,5 @@
 #include <console/console.h>
 #include <sysinfo/sysinfo.h>
+#include <mm/page.h>
 #include <mm/slab.h>
 #include <align.h>
Index: kernel/generic/include/arch.h
===================================================================
--- kernel/generic/include/arch.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/include/arch.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -39,4 +39,5 @@
 #include <proc/thread.h>
 #include <proc/task.h>
+#include <mm/as.h>
 
 #define DEFAULT_CONTEXT		0
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/include/proc/task.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -55,4 +55,5 @@
 #include <udebug/udebug.h>
 #include <ipc/kbox.h>
+#include <mm/as.h>
 
 #define TASK_NAME_BUFLEN	20
Index: kernel/generic/include/proc/thread.h
===================================================================
--- kernel/generic/include/proc/thread.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/include/proc/thread.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -225,34 +225,33 @@
 
 extern void thread_init(void);
-extern thread_t *thread_create(void (* func)(void *), void *arg, task_t *task,
-    int flags, char *name, bool uncounted);
-extern void thread_attach(thread_t *t, task_t *task);
-extern void thread_ready(thread_t *t);
+extern thread_t *thread_create(void (*)(void *), void *, task_t *, int, char *,
+    bool);
+extern void thread_attach(thread_t *, task_t *);
+extern void thread_ready(thread_t *);
 extern void thread_exit(void) __attribute__((noreturn));
 
 #ifndef thread_create_arch
-extern void thread_create_arch(thread_t *t);
+extern void thread_create_arch(thread_t *);
 #endif
 #ifndef thr_constructor_arch
-extern void thr_constructor_arch(thread_t *t);
+extern void thr_constructor_arch(thread_t *);
 #endif
 #ifndef thr_destructor_arch
-extern void thr_destructor_arch(thread_t *t);
-#endif
-
-extern void thread_sleep(uint32_t sec);
-extern void thread_usleep(uint32_t usec);
+extern void thr_destructor_arch(thread_t *);
+#endif
+
+extern void thread_sleep(uint32_t);
+extern void thread_usleep(uint32_t);
 
 #define thread_join(t) \
 	thread_join_timeout((t), SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE)
-extern int thread_join_timeout(thread_t *t, uint32_t usec, int flags);
-extern void thread_detach(thread_t *t);
-
-extern void thread_register_call_me(void (* call_me)(void *),
-    void *call_me_with);
+extern int thread_join_timeout(thread_t *, uint32_t, int);
+extern void thread_detach(thread_t *);
+
+extern void thread_register_call_me(void (*)(void *), void *);
 extern void thread_print_list(void);
-extern void thread_destroy(thread_t *t);
+extern void thread_destroy(thread_t *);
 extern void thread_update_accounting(void);
-extern bool thread_exists(thread_t *t);
+extern bool thread_exists(thread_t *);
 
 /** Fpu context slab cache. */
@@ -260,8 +259,9 @@
 
 /* Thread syscall prototypes. */
-extern unative_t sys_thread_create(uspace_arg_t *uspace_uarg,
-    char *uspace_name, size_t name_len, thread_id_t *uspace_thread_id);
-extern unative_t sys_thread_exit(int uspace_status);
-extern unative_t sys_thread_get_id(thread_id_t *uspace_thread_id);
+extern unative_t sys_thread_create(uspace_arg_t *, char *, size_t,
+    thread_id_t *);
+extern unative_t sys_thread_exit(int);
+extern unative_t sys_thread_get_id(thread_id_t *);
+extern unative_t sys_thread_usleep(uint32_t);
 
 #endif
Index: kernel/generic/include/string.h
===================================================================
--- kernel/generic/include/string.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/include/string.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -87,5 +87,5 @@
 extern void str_cpy(char *dest, size_t size, const char *src);
 extern void str_ncpy(char *dest, size_t size, const char *src, size_t n);
-extern void wstr_nstr(char *dst, const wchar_t *src, size_t size);
+extern void wstr_to_str(char *dest, size_t size, const wchar_t *src);
 
 extern char *str_chr(const char *str, wchar_t ch);
Index: kernel/generic/include/synch/futex.h
===================================================================
--- kernel/generic/include/synch/futex.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/include/synch/futex.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -38,6 +38,4 @@
 #include <arch/types.h>
 #include <synch/waitq.h>
-#include <genarch/mm/page_ht.h>
-#include <genarch/mm/page_pt.h>
 
 /** Kernel-side futex structure. */
@@ -54,7 +52,6 @@
 
 extern void futex_init(void);
-extern unative_t sys_futex_sleep_timeout(uintptr_t uaddr, uint32_t usec,
-    int flags);
-extern unative_t sys_futex_wakeup(uintptr_t uaddr);
+extern unative_t sys_futex_sleep(uintptr_t);
+extern unative_t sys_futex_wakeup(uintptr_t);
 
 extern void futex_cleanup(void);
Index: kernel/generic/include/syscall/syscall.h
===================================================================
--- kernel/generic/include/syscall/syscall.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/include/syscall/syscall.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -43,4 +43,5 @@
 	SYS_THREAD_EXIT,
 	SYS_THREAD_GET_ID,
+	SYS_THREAD_USLEEP,
 	
 	SYS_TASK_GET_ID,
Index: kernel/generic/src/console/kconsole.c
===================================================================
--- kernel/generic/src/console/kconsole.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/src/console/kconsole.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -289,5 +289,5 @@
 			
 			char tmp[STR_BOUNDS(MAX_CMDLINE)];
-			wstr_nstr(tmp, current + beg, position - beg + 1);
+			wstr_to_str(tmp, position - beg + 1, current + beg);
 			
 			int found;
@@ -665,5 +665,5 @@
 		
 		char cmdline[STR_BOUNDS(MAX_CMDLINE)];
-		wstr_nstr(cmdline, tmp, STR_BOUNDS(MAX_CMDLINE));
+		wstr_to_str(cmdline, STR_BOUNDS(MAX_CMDLINE), tmp);
 		
 		if ((!kcon) && (len == 4) && (str_lcmp(cmdline, "exit", 4) == 0))
Index: kernel/generic/src/lib/string.c
===================================================================
--- kernel/generic/src/lib/string.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/src/lib/string.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -537,5 +537,5 @@
  * null-terminated and containing only complete characters.
  *
- * @param dst   Destination buffer.
+ * @param dest   Destination buffer.
  * @param count Size of the destination buffer (must be > 0).
  * @param src   Source string.
@@ -571,5 +571,5 @@
  * have to be null-terminated.
  *
- * @param dst   Destination buffer.
+ * @param dest   Destination buffer.
  * @param count Size of the destination buffer (must be > 0).
  * @param src   Source string.
@@ -596,36 +596,32 @@
 }
 
-/** Copy NULL-terminated wide string to string
- *
- * Copy source wide string @a src to destination buffer @a dst.
- * No more than @a size bytes are written. NULL-terminator is always
- * written after the last succesfully copied character (i.e. if the
- * destination buffer is has at least 1 byte, it will be always
- * NULL-terminated).
- *
- * @param src   Source wide string.
- * @param dst   Destination buffer.
- * @param count Size of the destination buffer.
- *
- */
-void wstr_nstr(char *dst, const wchar_t *src, size_t size)
-{
-	/* No space for the NULL-terminator in the buffer */
-	if (size == 0)
-		return;
-	
+/** Convert wide string to string.
+ *
+ * Convert wide string @a src to string. The output is written to the buffer
+ * specified by @a dest and @a size. @a size must be non-zero and the string
+ * written will always be well-formed.
+ *
+ * @param dest	Destination buffer.
+ * @param size	Size of the destination buffer.
+ * @param src	Source wide string.
+ */
+void wstr_to_str(char *dest, size_t size, const wchar_t *src)
+{
 	wchar_t ch;
-	size_t src_idx = 0;
-	size_t dst_off = 0;
+	size_t src_idx;
+	size_t dest_off;
+
+	/* There must be space for a null terminator in the buffer. */
+	ASSERT(size > 0);
+
+	src_idx = 0;
+	dest_off = 0;
 	
 	while ((ch = src[src_idx++]) != 0) {
-		if (chr_encode(ch, dst, &dst_off, size) != EOK)
+		if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
 			break;
 	}
-	
-	if (dst_off >= size)
-		dst[size - 1] = 0;
-	else
-		dst[dst_off] = 0;
+
+	dest[dest_off] = '\0';
 }
 
Index: kernel/generic/src/mm/backend_phys.c
===================================================================
--- kernel/generic/src/mm/backend_phys.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/src/mm/backend_phys.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -40,4 +40,5 @@
 #include <arch/types.h>
 #include <mm/as.h>
+#include <mm/page.h>
 #include <mm/frame.h>
 #include <mm/slab.h>
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/src/proc/task.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -54,4 +54,5 @@
 #include <func.h>
 #include <string.h>
+#include <memstr.h>
 #include <syscall/copy.h>
 #include <macros.h>
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/src/proc/thread.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -501,5 +501,12 @@
 void thread_sleep(uint32_t sec)
 {
-	thread_usleep(sec * 1000000);
+	/* Sleep in 1000 second steps to support
+	   full argument range */
+	while (sec > 0) {
+		uint32_t period = (sec > 1000) ? 1000 : sec;
+	
+		thread_usleep(period * 1000000);
+		sec -= period;
+	}
 }
 
@@ -575,7 +582,7 @@
 {
 	waitq_t wq;
-				  
+	
 	waitq_initialize(&wq);
-
+	
 	(void) waitq_sleep_timeout(&wq, usec, SYNCH_FLAGS_NON_BLOCKING);
 }
@@ -812,4 +819,11 @@
 }
 
+/** Syscall wrapper for sleeping. */
+unative_t sys_thread_usleep(uint32_t usec)
+{
+	thread_usleep(usec);
+	return 0;
+}
+
 /** @}
  */
Index: kernel/generic/src/synch/futex.c
===================================================================
--- kernel/generic/src/synch/futex.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/src/synch/futex.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -90,5 +90,5 @@
 /** Initialize kernel futex structure.
  *
- * @param futex Kernel futex structure.
+ * @param futex		Kernel futex structure.
  */
 void futex_initialize(futex_t *futex)
@@ -102,13 +102,11 @@
 /** Sleep in futex wait queue.
  *
- * @param uaddr Userspace address of the futex counter.
- * @param usec If non-zero, number of microseconds this thread is willing to
- *     sleep.
- * @param flags Select mode of operation.
- *
- * @return One of ESYNCH_TIMEOUT, ESYNCH_OK_ATOMIC and ESYNCH_OK_BLOCKED. See
- *     synch.h. If there is no physical mapping for uaddr ENOENT is returned.
- */
-unative_t sys_futex_sleep_timeout(uintptr_t uaddr, uint32_t usec, int flags)
+ * @param uaddr		Userspace address of the futex counter.
+ *
+ * @return		If there is no physical mapping for uaddr ENOENT is
+ *			returned. Otherwise returns a wait result as defined in
+ *			synch.h.
+ */
+unative_t sys_futex_sleep(uintptr_t uaddr)
 {
 	futex_t *futex;
@@ -140,7 +138,5 @@
 	udebug_stoppable_begin();
 #endif
-	rc = waitq_sleep_timeout(&futex->wq, usec, flags |
-	    SYNCH_FLAGS_INTERRUPTIBLE);
-
+	rc = waitq_sleep_timeout(&futex->wq, 0, SYNCH_FLAGS_INTERRUPTIBLE); 
 #ifdef CONFIG_UDEBUG
 	udebug_stoppable_end();
@@ -151,7 +147,7 @@
 /** Wakeup one thread waiting in futex wait queue.
  *
- * @param uaddr Userspace address of the futex counter.
- *
- * @return ENOENT if there is no physical mapping for uaddr.
+ * @param uaddr		Userspace address of the futex counter.
+ *
+ * @return		ENOENT if there is no physical mapping for uaddr.
  */
 unative_t sys_futex_wakeup(uintptr_t uaddr)
@@ -190,7 +186,7 @@
  * If the structure does not exist already, a new one is created.
  *
- * @param paddr Physical address of the userspace futex counter.
- *
- * @return Address of the kernel futex structure.
+ * @param paddr		Physical address of the userspace futex counter.
+ *
+ * @return		Address of the kernel futex structure.
  */
 futex_t *futex_find(uintptr_t paddr)
@@ -284,8 +280,8 @@
 /** Compute hash index into futex hash table.
  *
- * @param key Address where the key (i.e. physical address of futex counter) is
- *     stored.
- *
- * @return Index into futex hash table.
+ * @param key		Address where the key (i.e. physical address of futex
+ *			counter) is stored.
+ *
+ * @return		Index into futex hash table.
  */
 size_t futex_ht_hash(unative_t *key)
@@ -296,8 +292,8 @@
 /** Compare futex hash table item with a key.
  *
- * @param key Address where the key (i.e. physical address of futex counter) is
- *     stored.
- *
- * @return True if the item matches the key. False otherwise.
+ * @param key		Address where the key (i.e. physical address of futex
+ *			counter) is stored.
+ *
+ * @return		True if the item matches the key. False otherwise.
  */
 bool futex_ht_compare(unative_t *key, size_t keys, link_t *item)
@@ -313,5 +309,5 @@
 /** Callback for removal items from futex hash table.
  *
- * @param item Item removed from the hash table.
+ * @param item		Item removed from the hash table.
  */
 void futex_ht_remove_callback(link_t *item)
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/src/syscall/syscall.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -62,13 +62,9 @@
 
 #ifdef CONFIG_UDEBUG
-	bool debug;
-
 	/*
 	 * Early check for undebugged tasks. We do not lock anything as this
-	 * test need not be precise in either way.
+	 * test need not be precise in either direction.
 	 */
-	debug = THREAD->udebug.active;
-	
-	if (debug) {
+	if (THREAD->udebug.active) {
 		udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, 0, false);
 	}
@@ -87,5 +83,5 @@
 	
 #ifdef CONFIG_UDEBUG
-	if (debug) {
+	if (THREAD->udebug.active) {
 		udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, rc, true);
 	
@@ -111,4 +107,5 @@
 	(syshandler_t) sys_thread_exit,
 	(syshandler_t) sys_thread_get_id,
+	(syshandler_t) sys_thread_usleep,
 	
 	(syshandler_t) sys_task_get_id,
@@ -117,5 +114,5 @@
 	
 	/* Synchronization related syscalls. */
-	(syshandler_t) sys_futex_sleep_timeout,
+	(syshandler_t) sys_futex_sleep,
 	(syshandler_t) sys_futex_wakeup,
 	(syshandler_t) sys_smc_coherence,
Index: kernel/generic/src/udebug/udebug_ops.c
===================================================================
--- kernel/generic/src/udebug/udebug_ops.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ kernel/generic/src/udebug/udebug_ops.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -50,4 +50,5 @@
 #include <udebug/udebug.h>
 #include <udebug/udebug_ops.h>
+#include <memstr.h>
 
 /**
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/Makefile	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -48,4 +48,5 @@
 	srv/devmap \
 	srv/part/mbr_part \
+	srv/clip \
 	app/edit \
 	app/tetris \
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/app/bdsh/input.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,6 +36,10 @@
 #include <io/keycode.h>
 #include <io/style.h>
+#include <io/color.h>
 #include <vfs/vfs.h>
+#include <clipboard.h>
+#include <macros.h>
 #include <errno.h>
+#include <assert.h>
 #include <bool.h>
 
@@ -47,5 +51,51 @@
 #include "exec.h"
 
-static void read_line(char *, int);
+#define HISTORY_LEN 10
+
+/** Text input field. */
+typedef struct {
+	/** Buffer holding text currently being edited */
+	wchar_t buffer[INPUT_MAX + 1];
+	/** Screen coordinates of the top-left corner of the text field */
+	int col0, row0;
+	/** Screen dimensions */
+	int con_cols, con_rows;
+	/** Number of characters in @c buffer */
+	int nc;
+	/** Caret position within buffer */
+	int pos;
+	/** Selection mark position within buffer */
+	int sel_start;
+
+	/** History (dynamically allocated strings) */
+	char *history[1 + HISTORY_LEN];
+	/** Number of entries in @c history, not counting [0] */
+	int hnum;
+	/** Current position in history */
+	int hpos;
+	/** Exit flag */
+	bool done;
+} tinput_t;
+
+/** Seek direction */
+typedef enum {
+	seek_backward = -1,
+	seek_forward = 1
+} seek_dir_t;
+
+static tinput_t tinput;
+
+static char *tinput_read(tinput_t *ti);
+static void tinput_insert_string(tinput_t *ti, const char *str);
+static void tinput_sel_get_bounds(tinput_t *ti, int *sa, int *sb);
+static bool tinput_sel_active(tinput_t *ti);
+static void tinput_sel_all(tinput_t *ti);
+static void tinput_sel_delete(tinput_t *ti);
+static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev);
+static void tinput_key_shift(tinput_t *ti, console_event_t *ev);
+static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev);
+static void tinput_key_unmod(tinput_t *ti, console_event_t *ev);
+static void tinput_pre_seek(tinput_t *ti, bool shift_held);
+static void tinput_post_seek(tinput_t *ti, bool shift_held);
 
 /* Tokenizes input from console, sees if the first word is a built-in, if so
@@ -99,52 +149,623 @@
 }
 
-static void read_line(char *buffer, int n)
+static void tinput_display_tail(tinput_t *ti, int start, int pad)
+{
+	static wchar_t dbuf[INPUT_MAX + 1];
+	int sa, sb;
+	int i, p;
+
+	tinput_sel_get_bounds(ti, &sa, &sb);
+
+	console_goto(fphone(stdout), (ti->col0 + start) % ti->con_cols,
+	    ti->row0 + (ti->col0 + start) / ti->con_cols);
+	console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+
+	p = start;
+	if (p < sa) {
+		memcpy(dbuf, ti->buffer + p, (sa - p) * sizeof(wchar_t));
+		dbuf[sa - p] = '\0';
+		printf("%ls", dbuf);
+		p = sa;
+	}
+
+	if (p < sb) {
+		fflush(stdout);
+		console_set_color(fphone(stdout), COLOR_BLACK, COLOR_RED, 0);
+		memcpy(dbuf, ti->buffer + p,
+		    (sb - p) * sizeof(wchar_t));
+		dbuf[sb - p] = '\0';
+		printf("%ls", dbuf);
+		p = sb;
+	}
+
+	fflush(stdout);
+	console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+
+	if (p < ti->nc) {
+		memcpy(dbuf, ti->buffer + p,
+		    (ti->nc - p) * sizeof(wchar_t));
+		dbuf[ti->nc - p] = '\0';
+		printf("%ls", dbuf);
+	}
+
+	for (i = 0; i < pad; ++i)
+		putchar(' ');
+	fflush(stdout);
+}
+
+static char *tinput_get_str(tinput_t *ti)
+{
+	return wstr_to_astr(ti->buffer);
+}
+
+static void tinput_position_caret(tinput_t *ti)
+{
+	console_goto(fphone(stdout), (ti->col0 + ti->pos) % ti->con_cols,
+	    ti->row0 + (ti->col0 + ti->pos) / ti->con_cols);
+}
+
+/** Update row0 in case the screen could have scrolled. */
+static void tinput_update_origin(tinput_t *ti)
+{
+	int width, rows;
+
+	width = ti->col0 + ti->nc;
+	rows = (width / ti->con_cols) + 1;
+
+	/* Update row0 if the screen scrolled. */
+	if (ti->row0 + rows > ti->con_rows)
+		ti->row0 = ti->con_rows - rows;	
+}
+
+static void tinput_insert_char(tinput_t *ti, wchar_t c)
+{
+	int i;
+	int new_width, new_height;
+
+	if (ti->nc == INPUT_MAX)
+		return;
+
+	new_width = ti->col0 + ti->nc + 1;
+	if (new_width % ti->con_cols == 0) {
+		/* Advancing to new line. */
+		new_height = (new_width / ti->con_cols) + 1;
+		if (new_height >= ti->con_rows)
+			return; /* Disallow text longer than 1 page for now. */
+	}
+
+	for (i = ti->nc; i > ti->pos; --i)
+		ti->buffer[i] = ti->buffer[i - 1];
+
+	ti->buffer[ti->pos] = c;
+	ti->pos += 1;
+	ti->nc += 1;
+	ti->buffer[ti->nc] = '\0';
+	ti->sel_start = ti->pos;
+
+	tinput_display_tail(ti, ti->pos - 1, 0);
+	tinput_update_origin(ti);
+	tinput_position_caret(ti);
+}
+
+static void tinput_insert_string(tinput_t *ti, const char *str)
+{
+	int i;
+	int new_width, new_height;
+	int ilen;
+	wchar_t c;
+	size_t off;
+
+	ilen = min((ssize_t) str_length(str), INPUT_MAX - ti->nc);
+	if (ilen == 0)
+		return;
+
+	new_width = ti->col0 + ti->nc + ilen;
+	new_height = (new_width / ti->con_cols) + 1;
+	if (new_height >= ti->con_rows)
+		return; /* Disallow text longer than 1 page for now. */
+
+	for (i = ti->nc - 1; i >= ti->pos; --i)
+		ti->buffer[i + ilen] = ti->buffer[i];
+
+	off = 0; i = 0;
+	while (i < ilen) {
+		c = str_decode(str, &off, STR_NO_LIMIT);
+		if (c == '\0')
+			break;
+
+		/* Filter out non-printable chars. */
+		if (c < 32)
+			c = 32;
+
+		ti->buffer[ti->pos + i] = c;
+		++i;
+	}
+
+	ti->pos += ilen;
+	ti->nc += ilen;
+	ti->buffer[ti->nc] = '\0';
+	ti->sel_start = ti->pos;
+
+	tinput_display_tail(ti, ti->pos - ilen, 0);
+	tinput_update_origin(ti);
+	tinput_position_caret(ti);
+}
+
+static void tinput_backspace(tinput_t *ti)
+{
+	int i;
+
+	if (tinput_sel_active(ti)) {
+		tinput_sel_delete(ti);
+		return;
+	}
+
+	if (ti->pos == 0)
+		return;
+
+	for (i = ti->pos; i < ti->nc; ++i)
+		ti->buffer[i - 1] = ti->buffer[i];
+	ti->pos -= 1;
+	ti->nc -= 1;
+	ti->buffer[ti->nc] = '\0';
+	ti->sel_start = ti->pos;
+
+	tinput_display_tail(ti, ti->pos, 1);
+	tinput_position_caret(ti);
+}
+
+static void tinput_delete(tinput_t *ti)
+{
+	if (tinput_sel_active(ti)) {
+		tinput_sel_delete(ti);
+		return;
+	}
+
+	if (ti->pos == ti->nc)
+		return;
+
+	ti->pos += 1;
+	ti->sel_start = ti->pos;
+
+	tinput_backspace(ti);
+}
+
+static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir, bool shift_held)
+{
+	tinput_pre_seek(ti, shift_held);
+
+	if (dir == seek_forward) {
+		if (ti->pos < ti->nc)
+			ti->pos += 1;
+	} else {
+		if (ti->pos > 0)
+			ti->pos -= 1;
+	}
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_seek_word(tinput_t *ti, seek_dir_t dir, bool shift_held)
+{
+	tinput_pre_seek(ti, shift_held);
+
+	if (dir == seek_forward) {
+		if (ti->pos == ti->nc)
+			return;
+
+		while (1) {
+			ti->pos += 1;
+
+			if (ti->pos == ti->nc)
+				break;
+
+			if (ti->buffer[ti->pos - 1] == ' ' &&
+			    ti->buffer[ti->pos] != ' ')
+				break;
+		}
+	} else {
+		if (ti->pos == 0)
+			return;
+
+		while (1) {
+			ti->pos -= 1;
+
+			if (ti->pos == 0)
+				break;
+
+			if (ti->buffer[ti->pos - 1] == ' ' &&
+			    ti->buffer[ti->pos] != ' ')
+				break;
+		}
+
+	}
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir, bool shift_held)
+{
+	tinput_pre_seek(ti, shift_held);
+
+	if (dir == seek_forward) {
+		if (ti->pos + ti->con_cols <= ti->nc)
+			ti->pos = ti->pos + ti->con_cols;
+	} else {
+		if (ti->pos - ti->con_cols >= 0)
+			ti->pos = ti->pos - ti->con_cols;
+	}
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_seek_max(tinput_t *ti, seek_dir_t dir, bool shift_held)
+{
+	tinput_pre_seek(ti, shift_held);
+
+	if (dir == seek_backward)
+		ti->pos = 0;
+	else
+		ti->pos = ti->nc;
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_pre_seek(tinput_t *ti, bool shift_held)
+{
+	if (tinput_sel_active(ti) && !shift_held) {
+		/* Unselect and redraw. */
+		ti->sel_start = ti->pos;
+		tinput_display_tail(ti, 0, 0);
+		tinput_position_caret(ti);
+	}
+}
+
+static void tinput_post_seek(tinput_t *ti, bool shift_held)
+{
+	if (shift_held) {
+		/* Selecting text. Need redraw. */
+		tinput_display_tail(ti, 0, 0);
+	} else {
+		/* Shift not held. Keep selection empty. */
+		ti->sel_start = ti->pos;
+	}
+	tinput_position_caret(ti);
+}
+
+static void tinput_history_insert(tinput_t *ti, char *str)
+{
+	int i;
+
+	if (ti->hnum < HISTORY_LEN) {
+		ti->hnum += 1;
+	} else {
+		if (ti->history[HISTORY_LEN] != NULL)
+			free(ti->history[HISTORY_LEN]);
+	}
+
+	for (i = ti->hnum; i > 1; --i)
+		ti->history[i] = ti->history[i - 1];
+
+	ti->history[1] = str_dup(str);
+
+	if (ti->history[0] != NULL) {
+		free(ti->history[0]);
+		ti->history[0] = NULL;
+	}
+}
+
+static void tinput_set_str(tinput_t *ti, char *str)
+{
+	str_to_wstr(ti->buffer, INPUT_MAX, str);
+	ti->nc = wstr_length(ti->buffer);
+	ti->pos = ti->nc;
+	ti->sel_start = ti->pos;
+}
+
+static void tinput_sel_get_bounds(tinput_t *ti, int *sa, int *sb)
+{
+	if (ti->sel_start < ti->pos) {
+		*sa = ti->sel_start;
+		*sb = ti->pos;
+	} else {
+		*sa = ti->pos;
+		*sb = ti->sel_start;
+	}
+}
+
+static bool tinput_sel_active(tinput_t *ti)
+{
+	return ti->sel_start != ti->pos;
+}
+
+static void tinput_sel_all(tinput_t *ti)
+{
+	ti->sel_start = 0;
+	ti->pos = ti->nc;
+	tinput_display_tail(ti, 0, 0);
+	tinput_position_caret(ti);
+}
+
+static void tinput_sel_delete(tinput_t *ti)
+{
+	int sa, sb;
+
+	tinput_sel_get_bounds(ti, &sa, &sb);
+	if (sa == sb)
+		return;
+
+	memmove(ti->buffer + sa, ti->buffer + sb,
+	    (ti->nc - sb) * sizeof(wchar_t));
+	ti->pos = ti->sel_start = sa;
+	ti->nc -= (sb - sa);
+	ti->buffer[ti->nc] = '\0';
+
+	tinput_display_tail(ti, sa, sb - sa);
+	tinput_position_caret(ti);
+}
+
+static void tinput_sel_copy_to_cb(tinput_t *ti)
+{
+	int sa, sb;
+	wchar_t tmp_c;
+	char *str;
+
+	tinput_sel_get_bounds(ti, &sa, &sb);
+
+	if (sb < ti->nc) {
+		tmp_c = ti->buffer[sb];
+		ti->buffer[sb] = '\0';
+	}
+
+	str = wstr_to_astr(ti->buffer + sa);
+
+	if (sb < ti->nc)
+		ti->buffer[sb] = tmp_c;
+
+	if (str == NULL)
+		goto error;
+
+	if (clipboard_put_str(str) != EOK)
+		goto error;
+
+	free(str);
+	return;
+error:
+	return;
+	/* TODO: Give the user some warning. */
+}
+
+static void tinput_paste_from_cb(tinput_t *ti)
+{
+	char *str;
+	int rc;
+
+	rc = clipboard_get_str(&str);
+	if (rc != EOK || str == NULL)
+		return; /* TODO: Give the user some warning. */
+
+	tinput_insert_string(ti, str);
+	free(str);
+}
+
+static void tinput_history_seek(tinput_t *ti, int offs)
+{
+	int pad;
+
+	if (ti->hpos + offs < 0 || ti->hpos + offs > ti->hnum)
+		return;
+
+	if (ti->history[ti->hpos] != NULL) {
+		free(ti->history[ti->hpos]);
+		ti->history[ti->hpos] = NULL;
+	}
+
+	ti->history[ti->hpos] = tinput_get_str(ti);
+	ti->hpos += offs;
+
+	pad = ti->nc - str_length(ti->history[ti->hpos]);
+	if (pad < 0) pad = 0;
+
+	tinput_set_str(ti, ti->history[ti->hpos]);
+	tinput_display_tail(ti, 0, pad);
+	tinput_update_origin(ti);
+	tinput_position_caret(ti);
+}
+
+/** Initialize text input field.
+ *
+ * Must be called before using the field. It clears the history.
+ */
+static void tinput_init(tinput_t *ti)
+{
+	ti->hnum = 0;
+	ti->hpos = 0;
+	ti->history[0] = NULL;
+}
+
+/** Read in one line of input. */
+static char *tinput_read(tinput_t *ti)
 {
 	console_event_t ev;
-	size_t offs, otmp;
-	wchar_t dec;
-
-	offs = 0;
-	while (true) {
+	char *str;
+
+	fflush(stdout);
+
+	if (console_get_size(fphone(stdin), &ti->con_cols, &ti->con_rows) != EOK)
+		return NULL;
+	if (console_get_pos(fphone(stdin), &ti->col0, &ti->row0) != EOK)
+		return NULL;
+
+	ti->pos = ti->sel_start = 0;
+	ti->nc = 0;
+	ti->buffer[0] = '\0';
+	ti->done = false;
+
+	while (!ti->done) {
 		fflush(stdout);
 		if (!console_get_event(fphone(stdin), &ev))
-			return;
-		
+			return NULL;
+
 		if (ev.type != KEY_PRESS)
 			continue;
-		
-		if (ev.key == KC_ENTER || ev.key == KC_NENTER)
-			break;
-		if (ev.key == KC_BACKSPACE) {
-			if (offs > 0) {
-				/*
-				 * Back up until we reach valid start of
-				 * character.
-				 */
-				while (offs > 0) {
-					--offs; otmp = offs;
-					dec = str_decode(buffer, &otmp, n);
-					if (dec != U_SPECIAL)
-						break;
-				}
-				putchar('\b');
-			}
-			continue;
+
+		if ((ev.mods & KM_CTRL) != 0 &&
+		    (ev.mods & (KM_ALT | KM_SHIFT)) == 0) {
+			tinput_key_ctrl(ti, &ev);
 		}
+
+		if ((ev.mods & KM_SHIFT) != 0 &&
+		    (ev.mods & (KM_CTRL | KM_ALT)) == 0) {
+			tinput_key_shift(ti, &ev);
+		}
+
+		if ((ev.mods & KM_CTRL) != 0 &&
+		    (ev.mods & KM_SHIFT) != 0 &&
+		    (ev.mods & KM_ALT) == 0) {
+			tinput_key_ctrl_shift(ti, &ev);
+		}
+
+		if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
+			tinput_key_unmod(ti, &ev);
+		}
+
 		if (ev.c >= ' ') {
-			if (chr_encode(ev.c, buffer, &offs, n - 1) == EOK)
-				putchar(ev.c);
+			tinput_sel_delete(ti);
+			tinput_insert_char(ti, ev.c);
 		}
 	}
+
+	ti->pos = ti->nc;
+	tinput_position_caret(ti);
 	putchar('\n');
-	buffer[offs] = '\0';
-}
-
-/* TODO:
- * Implement something like editline() / readline(), if even
- * just for command history and making arrows work. */
+
+	str = tinput_get_str(ti);
+	if (str_cmp(str, "") != 0)
+		tinput_history_insert(ti, str);
+
+	ti->hpos = 0;
+
+	return str;
+}
+
+static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_LEFT:
+		tinput_seek_word(ti, seek_backward, false);
+		break;
+	case KC_RIGHT:
+		tinput_seek_word(ti, seek_forward, false);
+		break;
+	case KC_UP:
+		tinput_seek_vertical(ti, seek_backward, false);
+		break;
+	case KC_DOWN:
+		tinput_seek_vertical(ti, seek_forward, false);
+		break;
+	case KC_X:
+		tinput_sel_copy_to_cb(ti);
+		tinput_sel_delete(ti);
+		break;
+	case KC_C:
+		tinput_sel_copy_to_cb(ti);
+		break;
+	case KC_V:
+		tinput_sel_delete(ti);
+		tinput_paste_from_cb(ti);
+		break;
+	case KC_A:
+		tinput_sel_all(ti);
+		break;
+	default:
+		break;
+	}
+}
+
+static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_LEFT:
+		tinput_seek_word(ti, seek_backward, true);
+		break;
+	case KC_RIGHT:
+		tinput_seek_word(ti, seek_forward, true);
+		break;
+	case KC_UP:
+		tinput_seek_vertical(ti, seek_backward, true);
+		break;
+	case KC_DOWN:
+		tinput_seek_vertical(ti, seek_forward, true);
+		break;
+	default:
+		break;
+	}
+}
+
+static void tinput_key_shift(tinput_t *ti, console_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_LEFT:
+		tinput_seek_cell(ti, seek_backward, true);
+		break;
+	case KC_RIGHT:
+		tinput_seek_cell(ti, seek_forward, true);
+		break;
+	case KC_UP:
+		tinput_seek_vertical(ti, seek_backward, true);
+		break;
+	case KC_DOWN:
+		tinput_seek_vertical(ti, seek_forward, true);
+		break;
+	case KC_HOME:
+		tinput_seek_max(ti, seek_backward, true);
+		break;
+	case KC_END:
+		tinput_seek_max(ti, seek_forward, true);
+		break;
+	default:
+		break;
+	}
+}
+
+static void tinput_key_unmod(tinput_t *ti, console_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_ENTER:
+	case KC_NENTER:
+		ti->done = true;
+		break;
+	case KC_BACKSPACE:
+		tinput_backspace(ti);
+		break;
+	case KC_DELETE:
+		tinput_delete(ti);
+		break;
+	case KC_LEFT:
+		tinput_seek_cell(ti, seek_backward, false);
+		break;
+	case KC_RIGHT:
+		tinput_seek_cell(ti, seek_forward, false);
+		break;
+	case KC_HOME:
+		tinput_seek_max(ti, seek_backward, false);
+		break;
+	case KC_END:
+		tinput_seek_max(ti, seek_forward, false);
+		break;
+	case KC_UP:
+		tinput_history_seek(ti, +1);
+		break;
+	case KC_DOWN:
+		tinput_history_seek(ti, -1);
+		break;
+	default:
+		break;
+	}
+}
+
 void get_input(cliuser_t *usr)
 {
-	char line[INPUT_MAX];
+	char *str;
 
 	fflush(stdout);
@@ -154,11 +775,18 @@
 	console_set_style(fphone(stdout), STYLE_NORMAL);
 
-	read_line(line, INPUT_MAX);
-	/* Make sure we don't have rubbish or a C/R happy user */
-	if (str_cmp(line, "") == 0 || str_cmp(line, "\n") == 0)
-		return;
-	usr->line = str_dup(line);
-
+	str = tinput_read(&tinput);
+
+	/* Check for empty input. */
+	if (str_cmp(str, "") == 0) {
+		free(str);
+		return;
+	}
+
+	usr->line = str;
 	return;
 }
 
+void input_init(void)
+{
+	tinput_init(&tinput);
+}
Index: uspace/app/bdsh/input.h
===================================================================
--- uspace/app/bdsh/input.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/app/bdsh/input.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -8,4 +8,5 @@
 extern void get_input(cliuser_t *);
 extern int tok_input(cliuser_t *);
+extern void input_init(void);
 
 #endif
Index: uspace/app/bdsh/scli.c
===================================================================
--- uspace/app/bdsh/scli.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/app/bdsh/scli.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -64,4 +64,7 @@
 	usr->prompt = (char *) NULL;
 	usr->lasterr = 0;
+
+	input_init();
+
 	return (int) cli_set_prompt(usr);
 }
Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/app/edit/edit.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,4 +36,5 @@
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <vfs/vfs.h>
@@ -44,4 +45,5 @@
 #include <align.h>
 #include <macros.h>
+#include <clipboard.h>
 #include <bool.h>
 
@@ -73,4 +75,7 @@
 	tag_t caret_pos;
 
+	/** Start of selection */
+	tag_t sel_start;
+
 	/** 
 	 * Ideal column where the caret should try to get. This is used
@@ -101,10 +106,20 @@
 #define ED_INFTY 65536
 
+/** Maximum filename length that can be entered. */
+#define INFNAME_MAX_LEN 128
+
 static void key_handle_unmod(console_event_t const *ev);
 static void key_handle_ctrl(console_event_t const *ev);
+static void key_handle_shift(console_event_t const *ev);
+static void key_handle_movement(unsigned int key, bool shift);
+
 static int file_save(char const *fname);
+static void file_save_as(void);
 static int file_insert(char *fname);
 static int file_save_range(char const *fname, spt_t const *spos,
     spt_t const *epos);
+static char *filename_prompt(char const *prompt, char const *init_value);
+static char *range_get_str(spt_t const *spos, spt_t const *epos);
+
 static void pane_text_display(void);
 static void pane_row_display(void);
@@ -112,4 +127,5 @@
 static void pane_status_display(void);
 static void pane_caret_display(void);
+
 static void insert_char(wchar_t c);
 static void delete_char_before(void);
@@ -117,6 +133,18 @@
 static void caret_update(void);
 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir);
+
+static bool selection_active(void);
+static void selection_sel_all(void);
+static void selection_get_points(spt_t *pa, spt_t *pb);
+static void selection_delete(void);
+static void selection_copy(void);
+static void insert_clipboard_data(void);
+
 static void pt_get_sof(spt_t *pt);
 static void pt_get_eof(spt_t *pt);
+static int tag_cmp(tag_t const *a, tag_t const *b);
+static int spt_cmp(spt_t const *a, spt_t const *b);
+static int coord_cmp(coord_t const *a, coord_t const *b);
+
 static void status_display(char const *str);
 
@@ -150,19 +178,23 @@
 
 	if (argc == 2) {
-		doc.file_name = argv[1];
+		doc.file_name = str_dup(argv[1]);
 	} else if (argc > 1) {
 		printf("Invalid arguments.\n");
 		return -2;
 	} else {
-		doc.file_name = "/edit.txt";
+		doc.file_name = NULL;
 	}
 
 	new_file = false;
 
-	if (file_insert(doc.file_name) != EOK)
+	if (doc.file_name == NULL || file_insert(doc.file_name) != EOK)
 		new_file = true;
 
 	/* Move to beginning of file. */
 	caret_move(-ED_INFTY, -ED_INFTY, dir_before);
+
+	/* Place selection start tag. */
+	tag_get_pt(&pane.caret_pos, &pt);
+	sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
 
 	/* Initial display */
@@ -170,6 +202,6 @@
 	pane_text_display();
 	pane_status_display();
-	if (new_file)
-		status_display("File not found. Created empty file.");
+	if (new_file && doc.file_name != NULL)
+		status_display("File not found. Starting empty file.");
 	pane_caret_display();
 
@@ -184,7 +216,12 @@
 			/* Handle key press. */
 			if (((ev.mods & KM_ALT) == 0) &&
+			    ((ev.mods & KM_SHIFT) == 0) &&
 			     (ev.mods & KM_CTRL) != 0) {
 				key_handle_ctrl(&ev);
-			} else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
+			} else if (((ev.mods & KM_ALT) == 0) &&
+			    ((ev.mods & KM_CTRL) == 0) &&
+			     (ev.mods & KM_SHIFT) != 0) {
+				key_handle_shift(&ev);
+			} else if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
 				key_handle_unmod(&ev);
 			}
@@ -201,5 +238,4 @@
 		if (pane.rflags & REDRAW_CARET)
 			pane_caret_display();
-			
 	}
 
@@ -214,41 +250,35 @@
 	switch (ev->key) {
 	case KC_ENTER:
+		selection_delete();
 		insert_char('\n');
 		caret_update();
 		break;
 	case KC_LEFT:
-		caret_move(0, -1, dir_before);
-		break;
 	case KC_RIGHT:
-		caret_move(0, 0, dir_after);
-		break;
 	case KC_UP:
-		caret_move(-1, 0, dir_before);
-		break;
 	case KC_DOWN:
-		caret_move(+1, 0, dir_before);
-		break;
 	case KC_HOME:
-		caret_move(0, -ED_INFTY, dir_before);
-		break;
 	case KC_END:
-		caret_move(0, +ED_INFTY, dir_before);
-		break;
 	case KC_PAGE_UP:
-		caret_move(-pane.rows, 0, dir_before);
-		break;
 	case KC_PAGE_DOWN:
-		caret_move(+pane.rows, 0, dir_before);
+		key_handle_movement(ev->key, false);
 		break;
 	case KC_BACKSPACE:
-		delete_char_before();
+		if (selection_active())
+			selection_delete();
+		else
+			delete_char_before();
 		caret_update();
 		break;
 	case KC_DELETE:
-		delete_char_after();
+		if (selection_active())
+			selection_delete();
+		else
+			delete_char_after();
 		caret_update();
 		break;
 	default:
 		if (ev->c >= 32 || ev->c == '\t') {
+			selection_delete();
 			insert_char(ev->c);
 			caret_update();
@@ -258,4 +288,28 @@
 }
 
+/** Handle Shift-key combination. */
+static void key_handle_shift(console_event_t const *ev)
+{
+	switch (ev->key) {
+	case KC_LEFT:
+	case KC_RIGHT:
+	case KC_UP:
+	case KC_DOWN:
+	case KC_HOME:
+	case KC_END:
+	case KC_PAGE_UP:
+	case KC_PAGE_DOWN:
+		key_handle_movement(ev->key, true);
+		break;
+	default:
+		if (ev->c >= 32 || ev->c == '\t') {
+			selection_delete();
+			insert_char(ev->c);
+			caret_update();
+		}
+		break;
+	}
+}
+
 /** Handle Ctrl-key combination. */
 static void key_handle_ctrl(console_event_t const *ev)
@@ -266,5 +320,29 @@
 		break;
 	case KC_S:
-		(void) file_save(doc.file_name);
+		if (doc.file_name != NULL)
+			file_save(doc.file_name);
+		else
+			file_save_as();
+		break;
+	case KC_E:
+		file_save_as();
+		break;
+	case KC_C:
+		selection_copy();
+		break;
+	case KC_V:
+		selection_delete();
+		insert_clipboard_data();
+		pane.rflags |= REDRAW_TEXT;
+		caret_update();
+		break;
+	case KC_X:
+		selection_copy();
+		selection_delete();
+		pane.rflags |= REDRAW_TEXT;
+		caret_update();
+		break;
+	case KC_A:
+		selection_sel_all();
 		break;
 	default:
@@ -273,4 +351,67 @@
 }
 
+static void key_handle_movement(unsigned int key, bool select)
+{
+	spt_t pt;
+	spt_t caret_pt;
+	coord_t c_old, c_new;
+	bool had_sel;
+
+	/* Check if we had selection before. */
+	tag_get_pt(&pane.caret_pos, &caret_pt);
+	tag_get_pt(&pane.sel_start, &pt);
+	had_sel = !spt_equal(&caret_pt, &pt);
+
+	switch (key) {
+	case KC_LEFT:
+		caret_move(0, -1, dir_before);
+		break;
+	case KC_RIGHT:
+		caret_move(0, 0, dir_after);
+		break;
+	case KC_UP:
+		caret_move(-1, 0, dir_before);
+		break;
+	case KC_DOWN:
+		caret_move(+1, 0, dir_before);
+		break;
+	case KC_HOME:
+		caret_move(0, -ED_INFTY, dir_before);
+		break;
+	case KC_END:
+		caret_move(0, +ED_INFTY, dir_before);
+		break;
+	case KC_PAGE_UP:
+		caret_move(-pane.rows, 0, dir_before);
+		break;
+	case KC_PAGE_DOWN:
+		caret_move(+pane.rows, 0, dir_before);
+		break;
+	default:
+		break;
+	}
+
+	if (select == false) {
+		/* Move sel_start to the same point as caret. */
+		sheet_remove_tag(&doc.sh, &pane.sel_start);
+		tag_get_pt(&pane.caret_pos, &pt);
+		sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
+	}
+
+	if (select) {
+		tag_get_pt(&pane.caret_pos, &pt);
+		spt_get_coord(&caret_pt, &c_old);
+		spt_get_coord(&pt, &c_new);
+
+		if (c_old.row == c_new.row)
+			pane.rflags |= REDRAW_ROW;
+		else
+			pane.rflags |= REDRAW_TEXT;
+
+	} else if (had_sel == true) {
+		/* Redraw because text was unselected. */
+		pane.rflags |= REDRAW_TEXT;
+	}
+}
 
 /** Save the document. */
@@ -285,7 +426,104 @@
 
 	rc = file_save_range(fname, &sp, &ep);
-	status_display("File saved.");
+
+	switch (rc) {
+	case EINVAL:
+		status_display("Error opening file!");
+		break;
+	case EIO:
+		status_display("Error writing data!");
+		break;
+	default:
+		status_display("File saved.");
+		break;
+	}
 
 	return rc;
+}
+
+/** Change document name and save. */
+static void file_save_as(void)
+{
+	char *old_fname, *fname;
+	int rc;
+
+	old_fname = (doc.file_name != NULL) ? doc.file_name : "";
+	fname = filename_prompt("Save As", old_fname);
+	if (fname == NULL) {
+		status_display("Save cancelled.");
+		return;
+	}
+
+	rc = file_save(fname);
+	if (rc != EOK)
+		return;
+
+	if (doc.file_name != NULL)
+		free(doc.file_name);
+	doc.file_name = fname;
+}
+
+/** Ask for a file name. */
+static char *filename_prompt(char const *prompt, char const *init_value)
+{
+	console_event_t ev;
+	char *str;
+	wchar_t buffer[INFNAME_MAX_LEN + 1];
+	int max_len;
+	int nc;
+	bool done;
+
+	asprintf(&str, "%s: %s", prompt, init_value);
+	status_display(str);
+	console_goto(con, 1 + str_length(str), scr_rows - 1);
+	free(str);
+
+	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
+
+	max_len = min(INFNAME_MAX_LEN, scr_columns - 4 - str_length(prompt));
+	str_to_wstr(buffer, max_len + 1, init_value);
+	nc = wstr_length(buffer);
+	done = false;
+
+	while (!done) {
+		console_get_event(con, &ev);
+
+		if (ev.type == KEY_PRESS) {
+			/* Handle key press. */
+			if (((ev.mods & KM_ALT) == 0) &&
+			     (ev.mods & KM_CTRL) != 0) {
+				;
+			} else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
+				switch (ev.key) {
+				case KC_ESCAPE:
+					return NULL;
+				case KC_BACKSPACE:
+					if (nc > 0) {
+						putchar('\b');
+						fflush(stdout);
+						--nc;
+					}
+					break;
+				case KC_ENTER:
+					done = true;
+					break;
+				default:
+					if (ev.c >= 32 && nc < max_len) {
+						putchar(ev.c);
+						fflush(stdout);
+						buffer[nc++] = ev.c;
+					}
+					break;
+				}
+			}
+		}
+	}
+
+	buffer[nc] = '\0';
+	str = wstr_to_astr(buffer);
+
+	console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+
+	return str;
 }
 
@@ -359,7 +597,44 @@
 	} while (!spt_equal(&bep, epos));
 
-	fclose(f);
+	if (fclose(f) != EOK)
+		return EIO;
 
 	return EOK;
+}
+
+/** Return contents of range as a new string. */
+static char *range_get_str(spt_t const *spos, spt_t const *epos)
+{
+	char *buf;
+	spt_t sp, bep;
+	size_t bytes;
+	size_t buf_size, bpos;
+
+	buf_size = 1;
+
+	buf = malloc(buf_size);
+	if (buf == NULL)
+		return NULL;
+
+	bpos = 0;
+	sp = *spos;
+
+	while (true) {
+		sheet_copy_out(&doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
+		    &bep);
+		bytes = str_size(&buf[bpos]);
+		bpos += bytes;
+		sp = bep;
+
+		if (spt_equal(&bep, epos))
+			break;
+
+		buf_size *= 2;
+		buf = realloc(buf, buf_size);
+		if (buf == NULL)
+			return NULL;
+	}
+
+	return buf;
 }
 
@@ -408,5 +683,5 @@
 {
 	int i, j, fill;
-	spt_t rb, re, dep;
+	spt_t rb, re, dep, pt;
 	coord_t rbc, rec;
 	char row_buf[ROW_BUF_SIZE];
@@ -414,4 +689,19 @@
 	size_t pos, size;
 	unsigned s_column;
+	coord_t csel_start, csel_end, ctmp;
+
+	/* Determine selection start and end. */
+
+	tag_get_pt(&pane.sel_start, &pt);
+	spt_get_coord(&pt, &csel_start);
+
+	tag_get_pt(&pane.caret_pos, &pt);
+	spt_get_coord(&pt, &csel_end);
+
+	if (coord_cmp(&csel_start, &csel_end) > 0) {
+		ctmp = csel_start;
+		csel_start = csel_end;
+		csel_end = ctmp;
+	}
 
 	/* Draw rows from the sheet. */
@@ -434,9 +724,28 @@
 		/* Display text from the buffer. */
 
+		if (coord_cmp(&csel_start, &rbc) <= 0 &&
+		    coord_cmp(&rbc, &csel_end) < 0) {
+			fflush(stdout);
+			console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
+			fflush(stdout);
+		}
+
 		console_goto(con, 0, i);
 		size = str_size(row_buf);
 		pos = 0;
-		s_column = 1;
+		s_column = pane.sh_column;
 		while (pos < size) {
+			if (csel_start.row == rbc.row && csel_start.column == s_column) {
+				fflush(stdout);
+				console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
+				fflush(stdout);
+			}
+	
+			if (csel_end.row == rbc.row && csel_end.column == s_column) {
+				fflush(stdout);
+				console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+				fflush(stdout);
+			}
+	
 			c = str_decode(row_buf, &pos, size);
 			if (c != '\t') {
@@ -453,4 +762,10 @@
 		}
 
+		if (csel_end.row == rbc.row && csel_end.column == s_column) {
+			fflush(stdout);
+			console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+			fflush(stdout);
+		}
+
 		/* Fill until the end of display area. */
 
@@ -463,4 +778,5 @@
 			putchar(' ');
 		fflush(stdout);
+		console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
 	}
 
@@ -473,4 +789,5 @@
 	spt_t caret_pt;
 	coord_t coord;
+	char *fname;
 	int n;
 
@@ -478,8 +795,10 @@
 	spt_get_coord(&caret_pt, &coord);
 
+	fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
+
 	console_goto(con, 0, scr_rows - 1);
 	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
-	n = printf(" %d, %d: File '%s'. Ctrl-S Save  Ctrl-Q Quit",
-	    coord.row, coord.column, doc.file_name);
+	n = printf(" %d, %d: File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
+	    "Ctrl-E Save As", coord.row, coord.column, fname);
 	printf("%*s", scr_columns - 1 - n, "");
 	fflush(stdout);
@@ -648,4 +967,102 @@
 }
 
+/** Check for non-empty selection. */
+static bool selection_active(void)
+{
+	return (tag_cmp(&pane.caret_pos, &pane.sel_start) != 0);
+}
+
+static void selection_get_points(spt_t *pa, spt_t *pb)
+{
+	spt_t pt;
+
+	tag_get_pt(&pane.sel_start, pa);
+	tag_get_pt(&pane.caret_pos, pb);
+
+	if (spt_cmp(pa, pb) > 0) {
+		pt = *pa;
+		*pa = *pb;
+		*pb = pt;
+	}
+}
+
+/** Delete selected text. */
+static void selection_delete(void)
+{
+	spt_t pa, pb;
+	coord_t ca, cb;
+	int rel;
+
+	tag_get_pt(&pane.sel_start, &pa);
+	tag_get_pt(&pane.caret_pos, &pb);
+	spt_get_coord(&pa, &ca);
+	spt_get_coord(&pb, &cb);
+	rel = coord_cmp(&ca, &cb);
+
+	if (rel == 0)
+		return;
+
+	if (rel < 0)
+		sheet_delete(&doc.sh, &pa, &pb);
+	else
+		sheet_delete(&doc.sh, &pb, &pa);
+
+	if (ca.row == cb.row)
+		pane.rflags |= REDRAW_ROW;
+	else
+		pane.rflags |= REDRAW_TEXT;
+}
+
+static void selection_sel_all(void)
+{
+	spt_t spt, ept;
+
+	pt_get_sof(&spt);
+	pt_get_eof(&ept);
+	sheet_remove_tag(&doc.sh, &pane.sel_start);
+	sheet_place_tag(&doc.sh, &spt, &pane.sel_start);
+	sheet_remove_tag(&doc.sh, &pane.caret_pos);
+	sheet_place_tag(&doc.sh, &ept, &pane.caret_pos);
+
+	pane.rflags |= REDRAW_TEXT;
+	caret_update();
+}
+
+static void selection_copy(void)
+{
+	spt_t pa, pb;
+	char *str;
+
+	selection_get_points(&pa, &pb);
+	str = range_get_str(&pa, &pb);
+	if (str == NULL || clipboard_put_str(str) != EOK) {
+		status_display("Copying to clipboard failed!");
+	}
+	free(str);
+}
+
+static void insert_clipboard_data(void)
+{
+	char *str;
+	size_t off;
+	wchar_t c;
+	int rc;
+
+	rc = clipboard_get_str(&str);
+	if (rc != EOK || str == NULL)
+		return;
+
+	off = 0;
+
+	while (true) {
+		c = str_decode(str, &off, STR_NO_LIMIT);
+		if (c == '\0')
+			break;
+
+		insert_char(c);
+	}
+
+	free(str);
+}
 
 /** Get start-of-file s-point. */
@@ -669,4 +1086,35 @@
 
 	sheet_get_cell_pt(&doc.sh, &coord, dir_after, pt);
+}
+
+/** Compare tags. */
+static int tag_cmp(tag_t const *a, tag_t const *b)
+{
+	spt_t pa, pb;
+
+	tag_get_pt(a, &pa);
+	tag_get_pt(b, &pb);
+
+	return spt_cmp(&pa, &pb);
+}
+
+/** Compare s-points. */
+static int spt_cmp(spt_t const *a, spt_t const *b)
+{
+	coord_t ca, cb;
+
+	spt_get_coord(a, &ca);
+	spt_get_coord(b, &cb);
+
+	return coord_cmp(&ca, &cb);
+}
+
+/** Compare coordinats. */
+static int coord_cmp(coord_t const *a, coord_t const *b)
+{
+	if (a->row - b->row != 0)
+		return a->row - b->row;
+
+	return a->column - b->column;
 }
 
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/app/init/init.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -235,4 +235,5 @@
 	spawn("/srv/kbd");
 	spawn("/srv/console");
+	spawn("/srv/clip");
 	spawn("/srv/fhc");
 	spawn("/srv/obio");
Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/app/trace/trace.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -48,5 +48,5 @@
 #include <io/console.h>
 #include <io/keycode.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 
 #include <libc.h>
Index: uspace/lib/libblock/libblock.c
===================================================================
--- uspace/lib/libblock/libblock.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libblock/libblock.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -47,5 +47,5 @@
 #include <as.h>
 #include <assert.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <adt/list.h>
 #include <adt/hash_table.h>
Index: uspace/lib/libblock/libblock.h
===================================================================
--- uspace/lib/libblock/libblock.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libblock/libblock.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,9 +36,9 @@
 
 #ifndef LIBBLOCK_LIBBLOCK_H_
-#define	LIBBLOCK_LIBBLOCK_H_ 
+#define LIBBLOCK_LIBBLOCK_H_
 
 #include <stdint.h>
 #include "../../srv/vfs/vfs.h"
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <adt/hash_table.h>
 #include <adt/list.h>
Index: uspace/lib/libc/Makefile.build
===================================================================
--- uspace/lib/libc/Makefile.build	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/Makefile.build	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -50,4 +50,5 @@
 	generic/as.c \
 	generic/cap.c \
+	generic/clipboard.c \
 	generic/devmap.c \
 	generic/event.c \
@@ -56,5 +57,5 @@
 	generic/string.c \
 	generic/fibril.c \
-	generic/fibril_sync.c \
+	generic/fibril_synch.c \
 	generic/pcb.c \
 	generic/smc.c \
Index: uspace/lib/libc/arch/amd64/include/atomic.h
===================================================================
--- uspace/lib/libc/arch/amd64/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/amd64/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -37,4 +37,8 @@
 #ifndef LIBC_amd64_ATOMIC_H_
 #define LIBC_amd64_ATOMIC_H_
+
+#define LIBC_ARCH_ATOMIC_H_
+
+#include <atomicdflt.h>
 
 static inline void atomic_inc(atomic_t *val) {
Index: uspace/lib/libc/arch/arm32/include/atomic.h
===================================================================
--- uspace/lib/libc/arch/arm32/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/arm32/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -37,4 +37,50 @@
 #define LIBC_arm32_ATOMIC_H_
 
+#define LIBC_ARCH_ATOMIC_H_
+#define CAS 
+
+#include <atomicdflt.h>
+#include <bool.h>
+#include <sys/types.h>
+
+extern uintptr_t *ras_page;
+
+static inline bool cas(atomic_t *val, long ov, long nv)
+{
+	long ret = 0;
+
+	/*
+	 * The following instructions between labels 1 and 2 constitute a
+	 * Restartable Atomic Seqeunce. Should the sequence be non-atomic,
+	 * the kernel will restart it.
+	 */
+	asm volatile (
+		"1:\n"
+		"	adr %[ret], 1b\n"
+		"	str %[ret], %[rp0]\n"
+		"	adr %[ret], 2f\n"
+		"	str %[ret], %[rp1]\n"
+		"	ldr %[ret], %[addr]\n"
+		"	cmp %[ret], %[ov]\n"
+		"	streq %[nv], %[addr]\n"
+		"2:\n"
+		"	moveq %[ret], #1\n"
+		"	movne %[ret], #0\n"
+		: [ret] "+&r" (ret),
+		  [rp0] "=m" (ras_page[0]),
+		  [rp1] "=m" (ras_page[1]),
+		  [addr] "+m" (val->count)
+		: [ov] "r" (ov),
+		  [nv] "r" (nv)
+		: "memory"
+	);
+
+	ras_page[0] = 0;
+	asm volatile ("" ::: "memory");	
+	ras_page[1] = 0xffffffff;
+
+	return (bool) ret;
+}
+
 /** Atomic addition.
  *
@@ -46,20 +92,31 @@
 static inline long atomic_add(atomic_t *val, int i)
 {
-	int ret;
-	volatile long * mem = &(val->count);
+	long ret = 0;
 
+	/*
+	 * The following instructions between labels 1 and 2 constitute a
+	 * Restartable Atomic Seqeunce. Should the sequence be non-atomic,
+	 * the kernel will restart it.
+	 */
 	asm volatile (
-	"1:\n"
-		"ldr r2, [%1]\n"
-		"add r3, r2, %2\n"
-		"str r3, %0\n"
-		"swp r3, r3, [%1]\n"
-		"cmp r3, r2\n"
-		"bne 1b\n"
+		"1:\n"
+		"	adr %[ret], 1b\n"
+		"	str %[ret], %[rp0]\n"
+		"	adr %[ret], 2f\n"
+		"	str %[ret], %[rp1]\n"
+		"	ldr %[ret], %[addr]\n"
+		"	add %[ret], %[ret], %[imm]\n"
+		"	str %[ret], %[addr]\n"
+		"2:\n"
+		: [ret] "+&r" (ret),
+		  [rp0] "=m" (ras_page[0]),
+		  [rp1] "=m" (ras_page[1]),
+		  [addr] "+m" (val->count)
+		: [imm] "r" (i)
+	);
 
-		: "=m" (ret)
-		: "r" (mem), "r" (i)
-		: "r3", "r2"
-	);
+	ras_page[0] = 0;
+	asm volatile ("" ::: "memory");	
+	ras_page[1] = 0xffffffff;
 
 	return ret;
Index: uspace/lib/libc/arch/arm32/src/entry.s
===================================================================
--- uspace/lib/libc/arch/arm32/src/entry.s	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/arm32/src/entry.s	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,6 +36,11 @@
 #
 # r1 contains the PCB pointer
+# r2 contains the RAS page address
 #
 __entry:
+	# Store the RAS page address into the ras_page variable
+	ldr r0, =ras_page
+	str r2, [r0]
+
 	# Pass pcb_ptr to __main as the first argument (in r0)
 	mov r0, r1
@@ -43,2 +48,9 @@
 
 	bl __exit
+
+.data
+
+.global ras_page
+ras_page:
+	.long 0
+
Index: uspace/lib/libc/arch/arm32/src/syscall.c
===================================================================
--- uspace/lib/libc/arch/arm32/src/syscall.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/arm32/src/syscall.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -60,6 +60,7 @@
 	register sysarg_t __arm_reg_r5 asm("r5") = p6;
 	register sysarg_t __arm_reg_r6 asm("r6") = id;
-
-	asm volatile ( "swi"
+	
+	asm volatile (
+		"swi 0"
 		: "=r" (__arm_reg_r0)
 		: "r" (__arm_reg_r0),
@@ -71,5 +72,5 @@
 		  "r" (__arm_reg_r6)
 	);
-
+	
 	return __arm_reg_r0;
 }
Index: uspace/lib/libc/arch/ia32/Makefile.inc
===================================================================
--- uspace/lib/libc/arch/ia32/Makefile.inc	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/ia32/Makefile.inc	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -39,4 +39,5 @@
 	arch/$(UARCH)/src/setjmp.S
 
+GCC_CFLAGS += -march=pentium
 LFLAGS += -N
 
Index: uspace/lib/libc/arch/ia32/include/atomic.h
===================================================================
--- uspace/lib/libc/arch/ia32/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/ia32/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -35,4 +35,8 @@
 #ifndef LIBC_ia32_ATOMIC_H_
 #define LIBC_ia32_ATOMIC_H_
+
+#define LIBC_ARCH_ATOMIC_H_
+
+#include <atomicdflt.h>
 
 static inline void atomic_inc(atomic_t *val) {
Index: uspace/lib/libc/arch/ia64/include/atomic.h
===================================================================
--- uspace/lib/libc/arch/ia64/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/ia64/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -35,4 +35,8 @@
 #ifndef LIBC_ia64_ATOMIC_H_
 #define LIBC_ia64_ATOMIC_H_
+
+#define LIBC_ARCH_ATOMIC_H_
+
+#include <atomicdflt.h>
 
 static inline void atomic_inc(atomic_t *val)
Index: uspace/lib/libc/arch/mips32/include/atomic.h
===================================================================
--- uspace/lib/libc/arch/mips32/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/mips32/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,4 +36,8 @@
 #ifndef LIBC_mips32_ATOMIC_H_
 #define LIBC_mips32_ATOMIC_H_
+
+#define LIBC_ARCH_ATOMIC_H_
+
+#include <atomicdflt.h>
 
 #define atomic_inc(x)	((void) atomic_add(x, 1))
Index: uspace/lib/libc/arch/ppc32/include/atomic.h
===================================================================
--- uspace/lib/libc/arch/ppc32/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/ppc32/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -35,4 +35,8 @@
 #ifndef LIBC_ppc32_ATOMIC_H_
 #define LIBC_ppc32_ATOMIC_H_
+
+#define LIBC_ARCH_ATOMIC_H_
+
+#include <atomicdflt.h>
 
 static inline void atomic_inc(atomic_t *val)
Index: uspace/lib/libc/arch/sparc64/include/atomic.h
===================================================================
--- uspace/lib/libc/arch/sparc64/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/arch/sparc64/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,4 +36,7 @@
 #define LIBC_sparc64_ATOMIC_H_
 
+#define LIBC_ARCH_ATOMIC_H_
+
+#include <atomicdflt.h>
 #include <sys/types.h>
 
Index: uspace/lib/libc/generic/clipboard.c
===================================================================
--- uspace/lib/libc/generic/clipboard.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/lib/libc/generic/clipboard.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2009 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 System clipboard API.
+ *
+ * The clipboard data is managed by the clipboard service and it is shared by
+ * the entire system.
+ *
+ */
+
+#include <clipboard.h>
+#include <ipc/services.h>
+#include <ipc/clipboard.h>
+#include <async.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+
+static int clip_phone = -1;
+
+/** Connect to clipboard server
+ *
+ */
+static void clip_connect(void)
+{
+	while (clip_phone < 0)
+		clip_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_CLIPBOARD, 0, 0);
+}
+
+/** Copy string to clipboard.
+ *
+ * Sets the clipboard contents to @a str. Passing an empty string or NULL
+ * makes the clipboard empty.
+ *
+ * @param str String to put to clipboard or NULL.
+ *
+ * @return Zero on success or negative error code.
+ *
+ */
+int clipboard_put_str(const char *str)
+{
+	size_t size = str_size(str);
+	
+	if (size == 0) {
+		async_serialize_start();
+		clip_connect();
+		
+		ipcarg_t rc = async_req_1_0(clip_phone, CLIPBOARD_PUT_DATA, CLIPBOARD_TAG_NONE);
+		
+		async_serialize_end();
+		
+		return (int) rc;
+	} else {
+		async_serialize_start();
+		clip_connect();
+		
+		aid_t req = async_send_1(clip_phone, CLIPBOARD_PUT_DATA, CLIPBOARD_TAG_BLOB, NULL);
+		ipcarg_t rc = async_data_write_start(clip_phone, (void *) str, size);
+		if (rc != EOK) {
+			ipcarg_t rc_orig;
+			async_wait_for(req, &rc_orig);
+			async_serialize_end();
+			if (rc_orig == EOK)
+				return (int) rc;
+			else
+				return (int) rc_orig;
+		}
+		
+		async_wait_for(req, &rc);
+		async_serialize_end();
+		
+		return (int) rc;
+	}
+}
+
+/** Get a copy of clipboard contents.
+ *
+ * Returns a new string that can be deallocated with free().
+ *
+ * @param str Here pointer to the newly allocated string is stored.
+ *
+ * @return Zero on success or negative error code.
+ *
+ */
+int clipboard_get_str(char **str)
+{
+	/* Loop until clipboard read succesful */
+	while (true) {
+		async_serialize_start();
+		clip_connect();
+		
+		ipcarg_t size;
+		ipcarg_t tag;
+		ipcarg_t rc = async_req_0_2(clip_phone, CLIPBOARD_CONTENT, &size, &tag);
+		
+		async_serialize_end();
+		
+		if (rc != EOK)
+			return (int) rc;
+		
+		char *sbuf;
+		
+		switch (tag) {
+		case CLIPBOARD_TAG_NONE:
+			sbuf = malloc(1);
+			if (sbuf == NULL)
+				return ENOMEM;
+			
+			sbuf[0] = 0;
+			*str = sbuf;
+			return EOK;
+		case CLIPBOARD_TAG_BLOB:
+			sbuf = malloc(size + 1);
+			if (sbuf == NULL)
+				return ENOMEM;
+			
+			async_serialize_start();
+			
+			aid_t req = async_send_1(clip_phone, CLIPBOARD_GET_DATA, tag, NULL);
+			rc = async_data_read_start(clip_phone, (void *) sbuf, size);
+			if (rc == EOVERFLOW) {
+				/*
+				 * The data in the clipboard has changed since
+				 * the last call of CLIPBOARD_CONTENT
+				 */
+				async_serialize_end();
+				break;
+			}
+			
+			if (rc != EOK) {
+				ipcarg_t rc_orig;
+				async_wait_for(req, &rc_orig);
+				async_serialize_end();
+				if (rc_orig == EOK)
+					return (int) rc;
+				else
+					return (int) rc_orig;
+			}
+			
+			async_wait_for(req, &rc);
+			async_serialize_end();
+			
+			if (rc == EOK) {
+				sbuf[size] = 0;
+				*str = sbuf;
+			}
+			
+			return rc;
+		default:
+			return EINVAL;
+		}
+	}
+}
+
+/** @}
+ */
Index: pace/lib/libc/generic/fibril_sync.c
===================================================================
--- uspace/lib/libc/generic/fibril_sync.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ 	(revision )
@@ -1,308 +1,0 @@
-/*
- * Copyright (c) 2009 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 libc
- * @{
- */
-/** @file
- */
-
-#include <fibril_sync.h>
-#include <fibril.h>
-#include <async.h>
-#include <async_priv.h>
-#include <adt/list.h>
-#include <futex.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <assert.h>
-
-static void optimize_execution_power(void)
-{
-	/*
-	 * When waking up a worker fibril previously blocked in fibril
-	 * synchronization, chances are that there is an idle manager fibril
-	 * waiting for IPC, that could start executing the awakened worker
-	 * fibril right away. We try to detect this and bring the manager
-	 * fibril back to fruitful work.
-	 */
-	if (atomic_get(&threads_in_ipc_wait) > 0)
-		ipc_poke();
-}
-
-void fibril_mutex_initialize(fibril_mutex_t *fm)
-{
-	fm->counter = 1;
-	list_initialize(&fm->waiters);
-}
-
-void fibril_mutex_lock(fibril_mutex_t *fm)
-{
-	futex_down(&async_futex);
-	if (fm->counter-- <= 0) {
-		awaiter_t wdata;
-
-		wdata.fid = fibril_get_id();
-		wdata.active = false;
-		wdata.wu_event.inlist = true;
-		link_initialize(&wdata.wu_event.link);
-		list_append(&wdata.wu_event.link, &fm->waiters);
-		fibril_switch(FIBRIL_TO_MANAGER);
-	} else {
-		futex_up(&async_futex);
-	}
-}
-
-bool fibril_mutex_trylock(fibril_mutex_t *fm)
-{
-	bool locked = false;
-	
-	futex_down(&async_futex);
-	if (fm->counter > 0) {
-		fm->counter--;
-		locked = true;
-	}
-	futex_up(&async_futex);
-	
-	return locked;
-}
-
-static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm)
-{
-	assert(fm->counter <= 0);
-	if (fm->counter++ < 0) {
-		link_t *tmp;
-		awaiter_t *wdp;
-	
-		assert(!list_empty(&fm->waiters));
-		tmp = fm->waiters.next;
-		wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
-		wdp->active = true;
-		wdp->wu_event.inlist = false;
-		list_remove(&wdp->wu_event.link);
-		fibril_add_ready(wdp->fid);
-		optimize_execution_power();
-	}
-}
-
-void fibril_mutex_unlock(fibril_mutex_t *fm)
-{
-	futex_down(&async_futex);
-	_fibril_mutex_unlock_unsafe(fm);
-	futex_up(&async_futex);
-}
-
-void fibril_rwlock_initialize(fibril_rwlock_t *frw)
-{
-	frw->writers = 0;
-	frw->readers = 0;
-	list_initialize(&frw->waiters);
-}
-
-void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
-{
-	futex_down(&async_futex);
-	if (frw->writers) {
-		fibril_t *f = (fibril_t *) fibril_get_id();
-		awaiter_t wdata;
-
-		wdata.fid = (fid_t) f;
-		wdata.active = false;
-		wdata.wu_event.inlist = true;
-		link_initialize(&wdata.wu_event.link);
-		f->flags &= ~FIBRIL_WRITER;
-		list_append(&wdata.wu_event.link, &frw->waiters);
-		fibril_switch(FIBRIL_TO_MANAGER);
-	} else {
-		frw->readers++;
-		futex_up(&async_futex);
-	}
-}
-
-void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
-{
-	futex_down(&async_futex);
-	if (frw->writers || frw->readers) {
-		fibril_t *f = (fibril_t *) fibril_get_id();
-		awaiter_t wdata;
-
-		wdata.fid = (fid_t) f;
-		wdata.active = false;
-		wdata.wu_event.inlist = true;
-		link_initialize(&wdata.wu_event.link);
-		f->flags |= FIBRIL_WRITER;
-		list_append(&wdata.wu_event.link, &frw->waiters);
-		fibril_switch(FIBRIL_TO_MANAGER);
-	} else {
-		frw->writers++;
-		futex_up(&async_futex);
-	}
-}
-
-static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
-{
-	futex_down(&async_futex);
-	assert(frw->readers || (frw->writers == 1));
-	if (frw->readers) {
-		if (--frw->readers)
-			goto out;
-	} else {
-		frw->writers--;
-	}
-	
-	assert(!frw->readers && !frw->writers);
-	
-	while (!list_empty(&frw->waiters)) {
-		link_t *tmp = frw->waiters.next;
-		awaiter_t *wdp;
-		fibril_t *f;
-		
-		wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
-		f = (fibril_t *) wdp->fid;
-		
-		if (f->flags & FIBRIL_WRITER) {
-			if (frw->readers)
-				break;
-			wdp->active = true;
-			wdp->wu_event.inlist = false;
-			list_remove(&wdp->wu_event.link);
-			fibril_add_ready(wdp->fid);
-			frw->writers++;
-			optimize_execution_power();
-			break;
-		} else {
-			wdp->active = true;
-			wdp->wu_event.inlist = false;
-			list_remove(&wdp->wu_event.link);
-			fibril_add_ready(wdp->fid);
-			frw->readers++;
-			optimize_execution_power();
-		}
-	}
-out:
-	futex_up(&async_futex);
-}
-
-void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
-{
-	_fibril_rwlock_common_unlock(frw);
-}
-
-void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
-{
-	_fibril_rwlock_common_unlock(frw);
-}
-
-void fibril_condvar_initialize(fibril_condvar_t *fcv)
-{
-	list_initialize(&fcv->waiters);
-}
-
-int
-fibril_condvar_wait_timeout(fibril_condvar_t *fcv, fibril_mutex_t *fm,
-    suseconds_t timeout)
-{
-	awaiter_t wdata;
-
-	if (timeout < 0)
-		return ETIMEOUT;
-
-	wdata.fid = fibril_get_id();
-	wdata.active = false;
-	
-	wdata.to_event.inlist = timeout > 0;
-	wdata.to_event.occurred = false;
-	link_initialize(&wdata.to_event.link);
-
-	wdata.wu_event.inlist = true;
-	link_initialize(&wdata.wu_event.link);
-
-	futex_down(&async_futex);
-	if (timeout) {
-		gettimeofday(&wdata.to_event.expires, NULL);
-		tv_add(&wdata.to_event.expires, timeout);
-		async_insert_timeout(&wdata);
-	}
-	list_append(&wdata.wu_event.link, &fcv->waiters);
-	_fibril_mutex_unlock_unsafe(fm);
-	fibril_switch(FIBRIL_TO_MANAGER);
-	fibril_mutex_lock(fm);
-
-	/* async_futex not held after fibril_switch() */
-	futex_down(&async_futex);
-	if (wdata.to_event.inlist)
-		list_remove(&wdata.to_event.link);
-	if (wdata.wu_event.inlist)
-		list_remove(&wdata.wu_event.link);
-	futex_up(&async_futex);
-	
-	return wdata.to_event.occurred ? ETIMEOUT : EOK;
-}
-
-void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm)
-{
-	int rc;
-
-	rc = fibril_condvar_wait_timeout(fcv, fm, 0);
-	assert(rc == EOK);
-}
-
-static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once)
-{
-	link_t *tmp;
-	awaiter_t *wdp;
-
-	futex_down(&async_futex);
-	while (!list_empty(&fcv->waiters)) {
-		tmp = fcv->waiters.next;
-		wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
-		list_remove(&wdp->wu_event.link);
-		wdp->wu_event.inlist = false;
-		if (!wdp->active) {
-			wdp->active = true;
-			fibril_add_ready(wdp->fid);
-			optimize_execution_power();
-			if (once)
-				break;
-		}
-	}
-	futex_up(&async_futex);
-}
-
-void fibril_condvar_signal(fibril_condvar_t *fcv)
-{
-	_fibril_condvar_wakeup_common(fcv, true);
-}
-
-void fibril_condvar_broadcast(fibril_condvar_t *fcv)
-{
-	_fibril_condvar_wakeup_common(fcv, false);
-}
-
-/** @}
- */
Index: uspace/lib/libc/generic/fibril_synch.c
===================================================================
--- uspace/lib/libc/generic/fibril_synch.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/lib/libc/generic/fibril_synch.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2009 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <fibril_synch.h>
+#include <fibril.h>
+#include <async.h>
+#include <async_priv.h>
+#include <adt/list.h>
+#include <futex.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <assert.h>
+
+static void optimize_execution_power(void)
+{
+	/*
+	 * When waking up a worker fibril previously blocked in fibril
+	 * synchronization, chances are that there is an idle manager fibril
+	 * waiting for IPC, that could start executing the awakened worker
+	 * fibril right away. We try to detect this and bring the manager
+	 * fibril back to fruitful work.
+	 */
+	if (atomic_get(&threads_in_ipc_wait) > 0)
+		ipc_poke();
+}
+
+void fibril_mutex_initialize(fibril_mutex_t *fm)
+{
+	fm->counter = 1;
+	list_initialize(&fm->waiters);
+}
+
+void fibril_mutex_lock(fibril_mutex_t *fm)
+{
+	futex_down(&async_futex);
+	if (fm->counter-- <= 0) {
+		awaiter_t wdata;
+
+		wdata.fid = fibril_get_id();
+		wdata.active = false;
+		wdata.wu_event.inlist = true;
+		link_initialize(&wdata.wu_event.link);
+		list_append(&wdata.wu_event.link, &fm->waiters);
+		fibril_switch(FIBRIL_TO_MANAGER);
+	} else {
+		futex_up(&async_futex);
+	}
+}
+
+bool fibril_mutex_trylock(fibril_mutex_t *fm)
+{
+	bool locked = false;
+	
+	futex_down(&async_futex);
+	if (fm->counter > 0) {
+		fm->counter--;
+		locked = true;
+	}
+	futex_up(&async_futex);
+	
+	return locked;
+}
+
+static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm)
+{
+	assert(fm->counter <= 0);
+	if (fm->counter++ < 0) {
+		link_t *tmp;
+		awaiter_t *wdp;
+	
+		assert(!list_empty(&fm->waiters));
+		tmp = fm->waiters.next;
+		wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
+		wdp->active = true;
+		wdp->wu_event.inlist = false;
+		list_remove(&wdp->wu_event.link);
+		fibril_add_ready(wdp->fid);
+		optimize_execution_power();
+	}
+}
+
+void fibril_mutex_unlock(fibril_mutex_t *fm)
+{
+	futex_down(&async_futex);
+	_fibril_mutex_unlock_unsafe(fm);
+	futex_up(&async_futex);
+}
+
+void fibril_rwlock_initialize(fibril_rwlock_t *frw)
+{
+	frw->writers = 0;
+	frw->readers = 0;
+	list_initialize(&frw->waiters);
+}
+
+void fibril_rwlock_read_lock(fibril_rwlock_t *frw)
+{
+	futex_down(&async_futex);
+	if (frw->writers) {
+		fibril_t *f = (fibril_t *) fibril_get_id();
+		awaiter_t wdata;
+
+		wdata.fid = (fid_t) f;
+		wdata.active = false;
+		wdata.wu_event.inlist = true;
+		link_initialize(&wdata.wu_event.link);
+		f->flags &= ~FIBRIL_WRITER;
+		list_append(&wdata.wu_event.link, &frw->waiters);
+		fibril_switch(FIBRIL_TO_MANAGER);
+	} else {
+		frw->readers++;
+		futex_up(&async_futex);
+	}
+}
+
+void fibril_rwlock_write_lock(fibril_rwlock_t *frw)
+{
+	futex_down(&async_futex);
+	if (frw->writers || frw->readers) {
+		fibril_t *f = (fibril_t *) fibril_get_id();
+		awaiter_t wdata;
+
+		wdata.fid = (fid_t) f;
+		wdata.active = false;
+		wdata.wu_event.inlist = true;
+		link_initialize(&wdata.wu_event.link);
+		f->flags |= FIBRIL_WRITER;
+		list_append(&wdata.wu_event.link, &frw->waiters);
+		fibril_switch(FIBRIL_TO_MANAGER);
+	} else {
+		frw->writers++;
+		futex_up(&async_futex);
+	}
+}
+
+static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw)
+{
+	futex_down(&async_futex);
+	assert(frw->readers || (frw->writers == 1));
+	if (frw->readers) {
+		if (--frw->readers)
+			goto out;
+	} else {
+		frw->writers--;
+	}
+	
+	assert(!frw->readers && !frw->writers);
+	
+	while (!list_empty(&frw->waiters)) {
+		link_t *tmp = frw->waiters.next;
+		awaiter_t *wdp;
+		fibril_t *f;
+		
+		wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
+		f = (fibril_t *) wdp->fid;
+		
+		if (f->flags & FIBRIL_WRITER) {
+			if (frw->readers)
+				break;
+			wdp->active = true;
+			wdp->wu_event.inlist = false;
+			list_remove(&wdp->wu_event.link);
+			fibril_add_ready(wdp->fid);
+			frw->writers++;
+			optimize_execution_power();
+			break;
+		} else {
+			wdp->active = true;
+			wdp->wu_event.inlist = false;
+			list_remove(&wdp->wu_event.link);
+			fibril_add_ready(wdp->fid);
+			frw->readers++;
+			optimize_execution_power();
+		}
+	}
+out:
+	futex_up(&async_futex);
+}
+
+void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
+{
+	_fibril_rwlock_common_unlock(frw);
+}
+
+void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
+{
+	_fibril_rwlock_common_unlock(frw);
+}
+
+void fibril_condvar_initialize(fibril_condvar_t *fcv)
+{
+	list_initialize(&fcv->waiters);
+}
+
+int
+fibril_condvar_wait_timeout(fibril_condvar_t *fcv, fibril_mutex_t *fm,
+    suseconds_t timeout)
+{
+	awaiter_t wdata;
+
+	if (timeout < 0)
+		return ETIMEOUT;
+
+	wdata.fid = fibril_get_id();
+	wdata.active = false;
+	
+	wdata.to_event.inlist = timeout > 0;
+	wdata.to_event.occurred = false;
+	link_initialize(&wdata.to_event.link);
+
+	wdata.wu_event.inlist = true;
+	link_initialize(&wdata.wu_event.link);
+
+	futex_down(&async_futex);
+	if (timeout) {
+		gettimeofday(&wdata.to_event.expires, NULL);
+		tv_add(&wdata.to_event.expires, timeout);
+		async_insert_timeout(&wdata);
+	}
+	list_append(&wdata.wu_event.link, &fcv->waiters);
+	_fibril_mutex_unlock_unsafe(fm);
+	fibril_switch(FIBRIL_TO_MANAGER);
+	fibril_mutex_lock(fm);
+
+	/* async_futex not held after fibril_switch() */
+	futex_down(&async_futex);
+	if (wdata.to_event.inlist)
+		list_remove(&wdata.to_event.link);
+	if (wdata.wu_event.inlist)
+		list_remove(&wdata.wu_event.link);
+	futex_up(&async_futex);
+	
+	return wdata.to_event.occurred ? ETIMEOUT : EOK;
+}
+
+void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm)
+{
+	int rc;
+
+	rc = fibril_condvar_wait_timeout(fcv, fm, 0);
+	assert(rc == EOK);
+}
+
+static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once)
+{
+	link_t *tmp;
+	awaiter_t *wdp;
+
+	futex_down(&async_futex);
+	while (!list_empty(&fcv->waiters)) {
+		tmp = fcv->waiters.next;
+		wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
+		list_remove(&wdp->wu_event.link);
+		wdp->wu_event.inlist = false;
+		if (!wdp->active) {
+			wdp->active = true;
+			fibril_add_ready(wdp->fid);
+			optimize_execution_power();
+			if (once)
+				break;
+		}
+	}
+	futex_up(&async_futex);
+}
+
+void fibril_condvar_signal(fibril_condvar_t *fcv)
+{
+	_fibril_condvar_wakeup_common(fcv, true);
+}
+
+void fibril_condvar_broadcast(fibril_condvar_t *fcv)
+{
+	_fibril_condvar_wakeup_common(fcv, false);
+}
+
+/** @}
+ */
Index: uspace/lib/libc/generic/futex.c
===================================================================
--- uspace/lib/libc/generic/futex.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/generic/futex.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,49 +36,5 @@
 #include <atomic.h>
 #include <libc.h>
-#include <stdio.h>
 #include <sys/types.h>
-#include <kernel/synch/synch.h>
-
-/*
- * Note about race conditions.
- * Because of non-atomic nature of operations performed sequentially on the
- * futex counter and the futex wait queue, there is a race condition:
- *
- * (wq->missed_wakeups == 1) && (futex->count = 1)
- *
- * Scenario 1 (wait queue timeout vs. futex_up()):
- * 1. assume wq->missed_wakeups == 0 && futex->count == -1
- *    (ie. thread A sleeping, thread B in the critical section)
- * 2. A receives timeout and gets removed from the wait queue
- * 3. B wants to leave the critical section and calls futex_up()
- * 4. B thus changes futex->count from -1 to 0
- * 5. B has to call SYS_FUTEX_WAKEUP syscall to wake up the sleeping thread
- * 6. B finds the wait queue empty and changes wq->missed_wakeups from 0 to 1
- * 7. A fixes futex->count (i.e. the number of waiting threads) by changing it
- *    from 0 to 1
- *
- * Scenario 2 (conditional down operation vs. futex_up)
- * 1. assume wq->missed_wakeups == 0 && futex->count == 0
- *    (i.e. thread A is in the critical section)
- * 2. thread B performs futex_trydown() operation and changes futex->count from
- *    0 to -1
- *    B is now obliged to call SYS_FUTEX_SLEEP syscall
- * 3. A wants to leave the critical section and does futex_up()
- * 4. A thus changes futex->count from -1 to 0 and must call SYS_FUTEX_WAKEUP
- *    syscall
- * 5. B finds the wait queue empty and immediatelly aborts the conditional sleep
- * 6. No thread is queueing in the wait queue so wq->missed_wakeups changes from
- *    0 to 1
- * 6. B fixes futex->count (i.e. the number of waiting threads) by changing it
- *    from 0 to 1
- *
- * Both scenarios allow two threads to be in the critical section
- * simultaneously. One without kernel intervention and the other through
- * wq->missed_wakeups being 1.
- *
- * To mitigate this problem, futex_down_timeout() detects that the syscall
- * didn't sleep in the wait queue, fixes the futex counter and RETRIES the
- * whole operation again.
- */
 
 /** Initialize futex counter.
@@ -92,81 +48,28 @@
 }
 
-int futex_down(futex_t *futex)
-{
-	return futex_down_timeout(futex, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
-}
-
-int futex_trydown(futex_t *futex)
-{
-	return futex_down_timeout(futex, SYNCH_NO_TIMEOUT,
-	    SYNCH_FLAGS_NON_BLOCKING);
-}
-
 /** Try to down the futex.
  *
  * @param futex		Futex.
- * @param usec		Microseconds to wait. Zero value means sleep without
- * 			timeout.
- * @param flags		Select mode of operation. See comment for
- * 			waitq_sleep_timeout(). 
+ * @return		Non-zero if the futex was acquired.
+ * @return		Zero if the futex was not acquired.
+ */
+int futex_trydown(futex_t *futex)
+{
+	return cas(futex, 1, 0);
+}
+
+/** Down the futex.
  *
- * @return		ENOENT if there is no such virtual address. One of
- * 			ESYNCH_OK_ATOMIC and ESYNCH_OK_BLOCKED on success or
- * 			ESYNCH_TIMEOUT if the lock was not acquired because of
- * 			a timeout or ESYNCH_WOULD_BLOCK if the operation could
- * 			not be carried out atomically (if requested so).
+ * @param futex		Futex.
+ * @return		ENOENT if there is no such virtual address.
+ * @return		Zero in the uncontended case. 
+ * @return		Otherwise one of ESYNCH_OK_ATOMIC or ESYNCH_OK_BLOCKED.
  */
-int futex_down_timeout(futex_t *futex, uint32_t usec, int flags)
+int futex_down(futex_t *futex)
 {
-	int rc;
-	
-	while (atomic_predec(futex) < 0) {
-		rc = __SYSCALL3(SYS_FUTEX_SLEEP, (sysarg_t) &futex->count,
-		    (sysarg_t) usec, (sysarg_t) flags);
-		
-		switch (rc) {
-		case ESYNCH_OK_ATOMIC:
-			/*
-			 * Because of a race condition between timeout and
-			 * futex_up() and between conditional
-			 * futex_down_timeout() and futex_up(), we have to give
-			 * up and try again in this special case.
-			 */
-			atomic_inc(futex);
-			break;
+	if (atomic_predec(futex) < 0)
+		return __SYSCALL1(SYS_FUTEX_SLEEP, (sysarg_t) &futex->count);
 
-		case ESYNCH_TIMEOUT:
-			atomic_inc(futex);
-			return ESYNCH_TIMEOUT;
-			break;
-
-		case ESYNCH_WOULD_BLOCK:
-			/*
-			 * The conditional down operation should be implemented
-			 * this way. The userspace-only variant tends to
-			 * accumulate missed wakeups in the kernel futex wait
-			 * queue.
-			 */
-			atomic_inc(futex);
-			return ESYNCH_WOULD_BLOCK;
-			break;
-
-		case ESYNCH_OK_BLOCKED:
-			/*
-			 * Enter the critical section.
-			 * The futex counter has already been incremented for
-			 * us.
-			 */
-			return ESYNCH_OK_BLOCKED;
-			break;
-		default:
-			return rc;
-		}
-	}
-
-	/*
-	 * Enter the critical section.
-	 */
-	return ESYNCH_OK_ATOMIC;
+	return 0;
 }
 
@@ -174,14 +77,10 @@
  *
  * @param futex		Futex.
- *
- * @return		ENOENT if there is no such virtual address. Otherwise
- * 			zero.
+ * @return		ENOENT if there is no such virtual address.
+ * @return		Zero in the uncontended case.
  */
 int futex_up(futex_t *futex)
 {
-	long val;
-	
-	val = atomic_postinc(futex);
-	if (val < 0)
+	if (atomic_postinc(futex) < 0)
 		return __SYSCALL1(SYS_FUTEX_WAKEUP, (sysarg_t) &futex->count);
 		
Index: uspace/lib/libc/generic/io/console.c
===================================================================
--- uspace/lib/libc/generic/io/console.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/generic/io/console.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -94,4 +94,17 @@
 }
 
+int console_get_pos(int phone, int *col, int *row)
+{
+	ipcarg_t col_v;
+	ipcarg_t row_v;
+	int rc;
+
+	rc = async_req_0_2(phone, CONSOLE_GET_POS, &col_v, &row_v);
+
+	*col = (int) col_v;
+	*row = (int) row_v;
+	return rc;
+}
+
 void console_goto(int phone, int col, int row)
 {
Index: uspace/lib/libc/generic/io/io.c
===================================================================
--- uspace/lib/libc/generic/io/io.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/generic/io/io.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -341,9 +341,14 @@
 size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
 {
-	size_t left = size * nmemb;
-	size_t done = 0;
-	
+	size_t left, done;
+
+	if (size == 0 || nmemb == 0)
+		return 0;
+
 	/* Make sure no data is pending write. */
 	_fflushbuf(stream);
+
+	left = size * nmemb;
+	done = 0;
 	
 	while ((left > 0) && (!stream->error) && (!stream->eof)) {
@@ -365,7 +370,13 @@
 static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
 {
-	size_t left = size * nmemb;
-	size_t done = 0;
-	
+	size_t left;
+	size_t done;
+
+	if (size == 0 || nmemb == 0)
+		return 0;
+
+	left = size * nmemb;
+	done = 0;
+
 	while ((left > 0) && (!stream->error)) {
 		ssize_t wr;
@@ -421,5 +432,8 @@
 	uint8_t b;
 	bool need_flush;
-	
+
+	if (size == 0 || nmemb == 0)
+		return 0;
+
 	/* If not buffered stream, write out directly. */
 	if (stream->btype == _IONBF) {
@@ -480,5 +494,5 @@
 	
 	if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
-		size_t wr = fwrite(buf, sz, 1, stream);
+		size_t wr = fwrite(buf, 1, sz, stream);
 		
 		if (wr < sz)
Index: uspace/lib/libc/generic/string.c
===================================================================
--- uspace/lib/libc/generic/string.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/generic/string.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -471,5 +471,5 @@
  * null-terminated and containing only complete characters.
  *
- * @param dst   Destination buffer.
+ * @param dest   Destination buffer.
  * @param count Size of the destination buffer (must be > 0).
  * @param src   Source string.
@@ -505,5 +505,5 @@
  * have to be null-terminated.
  *
- * @param dst   Destination buffer.
+ * @param dest   Destination buffer.
  * @param count Size of the destination buffer (must be > 0).
  * @param src   Source string.
@@ -537,5 +537,5 @@
  * null-terminated and containing only complete characters.
  *
- * @param dst   Destination buffer.
+ * @param dest   Destination buffer.
  * @param count Size of the destination buffer.
  * @param src   Source string.
@@ -549,36 +549,113 @@
 }
 
-/** Copy NULL-terminated wide string to string
- *
- * Copy source wide string @a src to destination buffer @a dst.
- * No more than @a size bytes are written. NULL-terminator is always
- * written after the last succesfully copied character (i.e. if the
- * destination buffer is has at least 1 byte, it will be always
- * NULL-terminated).
- *
- * @param src   Source wide string.
- * @param dst   Destination buffer.
- * @param count Size of the destination buffer.
- *
- */
-void wstr_nstr(char *dst, const wchar_t *src, size_t size)
-{
-	/* No space for the NULL-terminator in the buffer */
-	if (size == 0)
-		return;
-	
+/** Convert wide string to string.
+ *
+ * Convert wide string @a src to string. The output is written to the buffer
+ * specified by @a dest and @a size. @a size must be non-zero and the string
+ * written will always be well-formed.
+ *
+ * @param dest	Destination buffer.
+ * @param size	Size of the destination buffer.
+ * @param src	Source wide string.
+ */
+void wstr_to_str(char *dest, size_t size, const wchar_t *src)
+{
 	wchar_t ch;
-	size_t src_idx = 0;
-	size_t dst_off = 0;
-	
+	size_t src_idx;
+	size_t dest_off;
+
+	/* There must be space for a null terminator in the buffer. */
+	assert(size > 0);
+	
+	src_idx = 0;
+	dest_off = 0;
+
 	while ((ch = src[src_idx++]) != 0) {
-		if (chr_encode(ch, dst, &dst_off, size) != EOK)
+		if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
 			break;
 	}
-	
-	if (dst_off >= size)
-		dst[size - 1] = 0;
-	else
-		dst[dst_off] = 0;
+
+	dest[dest_off] = '\0';
+}
+
+/** Convert wide string to new string.
+ *
+ * Convert wide string @a src to string. Space for the new string is allocated
+ * on the heap.
+ *
+ * @param src	Source wide string.
+ * @return	New string.
+ */
+char *wstr_to_astr(const wchar_t *src)
+{
+	char dbuf[STR_BOUNDS(1)];
+	char *str;
+	wchar_t ch;
+
+	size_t src_idx;
+	size_t dest_off;
+	size_t dest_size;
+
+	/* Compute size of encoded string. */
+
+	src_idx = 0;
+	dest_size = 0;
+
+	while ((ch = src[src_idx++]) != 0) {
+		dest_off = 0;
+		if (chr_encode(ch, dbuf, &dest_off, STR_BOUNDS(1)) != EOK)
+			break;
+		dest_size += dest_off;
+	}
+
+	str = malloc(dest_size + 1);
+	if (str == NULL)
+		return NULL;
+
+	/* Encode string. */
+
+	src_idx = 0;
+	dest_off = 0;
+
+	while ((ch = src[src_idx++]) != 0) {
+		if (chr_encode(ch, str, &dest_off, dest_size) != EOK)
+			break;
+	}
+
+	str[dest_size] = '\0';
+	return str;
+}
+
+
+/** Convert string to wide string.
+ *
+ * Convert string @a src to wide string. The output is written to the
+ * buffer specified by @a dest and @a dlen. @a dlen must be non-zero
+ * and the wide string written will always be null-terminated.
+ *
+ * @param dest	Destination buffer.
+ * @param dlen	Length of destination buffer (number of wchars).
+ * @param src	Source string.
+ */
+void str_to_wstr(wchar_t *dest, size_t dlen, const char *src)
+{
+	size_t offset;
+	size_t di;
+	wchar_t c;
+
+	assert(dlen > 0);
+
+	offset = 0;
+	di = 0;
+
+	do {
+		if (di >= dlen - 1)
+			break;
+
+		c = str_decode(src, &offset, STR_NO_LIMIT);
+		dest[di++] = c;
+	} while (c != '\0');
+
+	dest[dlen - 1] = '\0';
 }
 
Index: uspace/lib/libc/generic/time.c
===================================================================
--- uspace/lib/libc/generic/time.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/generic/time.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -31,5 +31,5 @@
  */
 /** @file
- */ 
+ */
 
 #include <sys/time.h>
@@ -40,7 +40,7 @@
 #include <unistd.h>
 #include <atomic.h>
-#include <futex.h>
 #include <sysinfo.h>
 #include <ipc/services.h>
+#include <libc.h>
 
 #include <sysinfo.h>
@@ -189,27 +189,20 @@
 
 /** Wait unconditionally for specified number of microseconds */
-int usleep(unsigned long usec)
-{
-	atomic_t futex = FUTEX_INITIALIZER;
-
-	futex_initialize(&futex, 0);
-	futex_down_timeout(&futex, usec, 0);
+int usleep(useconds_t usec)
+{
+	(void) __SYSCALL1(SYS_THREAD_USLEEP, usec);
 	return 0;
 }
 
 /** Wait unconditionally for specified number of seconds */
-unsigned int sleep(unsigned int seconds)
-{
-	atomic_t futex = FUTEX_INITIALIZER;
-
-	futex_initialize(&futex, 0);
-	
+unsigned int sleep(unsigned int sec)
+{
 	/* Sleep in 1000 second steps to support
 	   full argument range */
-	while (seconds > 0) {
-		unsigned int period = (seconds > 1000) ? 1000 : seconds;
+	while (sec > 0) {
+		unsigned int period = (sec > 1000) ? 1000 : sec;
 	
-		futex_down_timeout(&futex, period * 1000000, 0);
-		seconds -= period;
+		usleep(period * 1000000);
+		sec -= period;
 	}
 	return 0;
Index: uspace/lib/libc/include/atomic.h
===================================================================
--- uspace/lib/libc/include/atomic.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/include/atomic.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2006 Jakub Jermar
+ * Copyright (c) 2009 Jakub Jermar
  * All rights reserved.
  *
@@ -36,19 +36,5 @@
 #define LIBC_ATOMIC_H_
 
-typedef struct atomic {
-	volatile long count;
-} atomic_t;
-
 #include <libarch/atomic.h>
-
-static inline void atomic_set(atomic_t *val, long i)
-{
-        val->count = i;
-}
-
-static inline long atomic_get(atomic_t *val)
-{
-        return val->count;
-}
 
 #endif
Index: uspace/lib/libc/include/atomicdflt.h
===================================================================
--- uspace/lib/libc/include/atomicdflt.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/lib/libc/include/atomicdflt.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2006 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ATOMICDFLT_H_
+#define LIBC_ATOMICDFLT_H_
+
+#ifndef LIBC_ARCH_ATOMIC_H_
+#error This file cannot be included directly, include atomic.h instead.
+#endif
+
+#include <bool.h>
+
+typedef struct atomic {
+	volatile long count;
+} atomic_t;
+
+static inline void atomic_set(atomic_t *val, long i)
+{
+        val->count = i;
+}
+
+static inline long atomic_get(atomic_t *val)
+{
+        return val->count;
+}
+
+#ifndef CAS 
+static inline bool cas(atomic_t *val, long ov, long nv)
+{
+	return __sync_bool_compare_and_swap(&val->count, ov, nv);
+}
+#endif
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/libc/include/clipboard.h
===================================================================
--- uspace/lib/libc/include/clipboard.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/lib/libc/include/clipboard.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009 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_CLIPBOARD_H_
+#define LIBC_CLIPBOARD_H_
+
+extern int clipboard_put_str(const char *);
+extern int clipboard_get_str(char **);
+
+#endif
+
+/** @}
+ */
Index: pace/lib/libc/include/fibril_sync.h
===================================================================
--- uspace/lib/libc/include/fibril_sync.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ 	(revision )
@@ -1,107 +1,0 @@
-/*
- * Copyright (c) 2009 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 libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_FIBRIL_SYNC_H_
-#define LIBC_FIBRIL_SYNC_H_
-
-#include <async.h>
-#include <fibril.h>
-#include <adt/list.h>
-#include <libarch/tls.h>
-#include <sys/time.h>
-
-typedef struct {
-	int counter;
-	link_t waiters;
-} fibril_mutex_t;
-
-#define FIBRIL_MUTEX_INITIALIZE(name) \
-	fibril_mutex_t name = {	\
-		.counter = 1, \
-		.waiters = { \
-			.prev = &name.waiters, \
-			.next = &name.waiters, \
-		} \
-	}
-
-typedef struct {
-	unsigned writers;
-	unsigned readers;
-	link_t waiters;
-} fibril_rwlock_t;
-
-#define FIBRIL_RWLOCK_INITIALIZE(name) \
-	fibril_rwlock_t name = { \
-		.readers = 0, \
-		.writers = 0, \
-		.waiters = { \
-			.prev = &name.waiters, \
-			.next = &name.waiters, \
-		} \
-	}
-
-typedef struct {
-	link_t waiters;
-} fibril_condvar_t;
-
-#define FIBRIL_CONDVAR_INITIALIZE(name) \
-	fibril_condvar_t name = { \
-		.waiters = { \
-			.next = &name.waiters, \
-			.prev = &name.waiters, \
-		} \
-	}
-
-extern void fibril_mutex_initialize(fibril_mutex_t *);
-extern void fibril_mutex_lock(fibril_mutex_t *);
-extern bool fibril_mutex_trylock(fibril_mutex_t *);
-extern void fibril_mutex_unlock(fibril_mutex_t *);
-
-extern void fibril_rwlock_initialize(fibril_rwlock_t *);
-extern void fibril_rwlock_read_lock(fibril_rwlock_t *);
-extern void fibril_rwlock_write_lock(fibril_rwlock_t *);
-extern void fibril_rwlock_read_unlock(fibril_rwlock_t *);
-extern void fibril_rwlock_write_unlock(fibril_rwlock_t *);
-
-extern void fibril_condvar_initialize(fibril_condvar_t *);
-extern int fibril_condvar_wait_timeout(fibril_condvar_t *, fibril_mutex_t *,
-    suseconds_t);
-extern void fibril_condvar_wait(fibril_condvar_t *, fibril_mutex_t *);
-extern void fibril_condvar_signal(fibril_condvar_t *);
-extern void fibril_condvar_broadcast(fibril_condvar_t *);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/libc/include/fibril_synch.h
===================================================================
--- uspace/lib/libc/include/fibril_synch.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/lib/libc/include/fibril_synch.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2009 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_FIBRIL_SYNCH_H_
+#define LIBC_FIBRIL_SYNCH_H_
+
+#include <async.h>
+#include <fibril.h>
+#include <adt/list.h>
+#include <libarch/tls.h>
+#include <sys/time.h>
+
+typedef struct {
+	int counter;
+	link_t waiters;
+} fibril_mutex_t;
+
+#define FIBRIL_MUTEX_INITIALIZE(name) \
+	fibril_mutex_t name = {	\
+		.counter = 1, \
+		.waiters = { \
+			.prev = &name.waiters, \
+			.next = &name.waiters, \
+		} \
+	}
+
+typedef struct {
+	unsigned writers;
+	unsigned readers;
+	link_t waiters;
+} fibril_rwlock_t;
+
+#define FIBRIL_RWLOCK_INITIALIZE(name) \
+	fibril_rwlock_t name = { \
+		.readers = 0, \
+		.writers = 0, \
+		.waiters = { \
+			.prev = &name.waiters, \
+			.next = &name.waiters, \
+		} \
+	}
+
+typedef struct {
+	link_t waiters;
+} fibril_condvar_t;
+
+#define FIBRIL_CONDVAR_INITIALIZE(name) \
+	fibril_condvar_t name = { \
+		.waiters = { \
+			.next = &name.waiters, \
+			.prev = &name.waiters, \
+		} \
+	}
+
+extern void fibril_mutex_initialize(fibril_mutex_t *);
+extern void fibril_mutex_lock(fibril_mutex_t *);
+extern bool fibril_mutex_trylock(fibril_mutex_t *);
+extern void fibril_mutex_unlock(fibril_mutex_t *);
+
+extern void fibril_rwlock_initialize(fibril_rwlock_t *);
+extern void fibril_rwlock_read_lock(fibril_rwlock_t *);
+extern void fibril_rwlock_write_lock(fibril_rwlock_t *);
+extern void fibril_rwlock_read_unlock(fibril_rwlock_t *);
+extern void fibril_rwlock_write_unlock(fibril_rwlock_t *);
+
+extern void fibril_condvar_initialize(fibril_condvar_t *);
+extern int fibril_condvar_wait_timeout(fibril_condvar_t *, fibril_mutex_t *,
+    suseconds_t);
+extern void fibril_condvar_wait(fibril_condvar_t *, fibril_mutex_t *);
+extern void fibril_condvar_signal(fibril_condvar_t *);
+extern void fibril_condvar_broadcast(fibril_condvar_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/libc/include/futex.h
===================================================================
--- uspace/lib/libc/include/futex.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/include/futex.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -46,5 +46,4 @@
 extern int futex_down(futex_t *futex);
 extern int futex_trydown(futex_t *futex);
-extern int futex_down_timeout(futex_t *futex, uint32_t usec, int flags);
 extern int futex_up(futex_t *futex);
 
Index: uspace/lib/libc/include/io/console.h
===================================================================
--- uspace/lib/libc/include/io/console.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/include/io/console.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -69,4 +69,5 @@
 
 extern int console_get_size(int phone, int *cols, int *rows);
+extern int console_get_pos(int phone, int *col, int *row);
 extern void console_goto(int phone, int col, int row);
 
Index: uspace/lib/libc/include/ipc/clipboard.h
===================================================================
--- uspace/lib/libc/include/ipc/clipboard.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/lib/libc/include/ipc/clipboard.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009 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 libcipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IPC_CLIPBOARD_H_
+#define LIBC_IPC_CLIPBOARD_H_
+
+#include <ipc/ipc.h>
+
+typedef enum {
+	CLIPBOARD_PUT_DATA = IPC_FIRST_USER_METHOD,
+	CLIPBOARD_GET_DATA,
+	CLIPBOARD_CONTENT
+} clipboard_request_t;
+
+typedef enum {
+	CLIPBOARD_TAG_NONE,
+	CLIPBOARD_TAG_BLOB
+} clipboard_tag_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/libc/include/ipc/console.h
===================================================================
--- uspace/lib/libc/include/ipc/console.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/include/ipc/console.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -43,4 +43,5 @@
 	CONSOLE_GET_COLOR_CAP,
 	CONSOLE_GET_EVENT,
+	CONSOLE_GET_POS,
 	CONSOLE_GOTO,
 	CONSOLE_CLEAR,
Index: uspace/lib/libc/include/ipc/services.h
===================================================================
--- uspace/lib/libc/include/ipc/services.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/include/ipc/services.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -47,5 +47,6 @@
 	SERVICE_DEVMAP,
 	SERVICE_FHC,
-	SERVICE_OBIO
+	SERVICE_OBIO,
+	SERVICE_CLIPBOARD
 } services_t;
 
Index: uspace/lib/libc/include/string.h
===================================================================
--- uspace/lib/libc/include/string.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/include/string.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -73,5 +73,7 @@
 extern void str_append(char *dest, size_t size, const char *src);
 
-extern void wstr_nstr(char *dst, const wchar_t *src, size_t size);
+extern void wstr_to_str(char *dest, size_t size, const wchar_t *src);
+extern char *wstr_to_astr(const wchar_t *src);
+extern void str_to_wstr(wchar_t *dest, size_t dlen, const char *src);
 
 extern char *str_chr(const char *str, wchar_t ch);
Index: uspace/lib/libc/include/unistd.h
===================================================================
--- uspace/lib/libc/include/unistd.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/lib/libc/include/unistd.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -51,4 +51,6 @@
 #endif
 
+typedef uint32_t useconds_t;
+
 extern int dup2(int oldfd, int newfd);
 
@@ -68,6 +70,6 @@
 
 extern void _exit(int status) __attribute__ ((noreturn));
-extern int usleep(unsigned long usec);
-extern unsigned int sleep(unsigned int seconds);
+extern int usleep(useconds_t uses);
+extern unsigned int sleep(unsigned int se);
 
 #endif
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -55,5 +55,5 @@
 #include <async.h>
 #include <as.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <string.h>
 #include <devmap.h>
Index: uspace/srv/bd/ata_bd/ata_bd.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/bd/ata_bd/ata_bd.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -37,14 +37,14 @@
 
 #include <sys/types.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <string.h>
 
 enum {
-	CTL_READ_START	= 0,
+	CTL_READ_START  = 0,
 	CTL_WRITE_START = 1,
 };
 
 enum {
-	STATUS_FAILURE	= 0
+	STATUS_FAILURE = 0
 };
 
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -45,5 +45,5 @@
 #include <async.h>
 #include <as.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <devmap.h>
 #include <sys/types.h>
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -43,5 +43,5 @@
 #include <async.h>
 #include <as.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <devmap.h>
 #include <sys/types.h>
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/bd/rd/rd.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -51,5 +51,5 @@
 #include <align.h>
 #include <async.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <stdio.h>
 #include <devmap.h>
Index: uspace/srv/clip/Makefile
===================================================================
--- uspace/srv/clip/Makefile	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/srv/clip/Makefile	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2009 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 Makefile.common
+
+.PHONY: all clean
+
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
+
+clean:
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/clip/Makefile.build
===================================================================
--- uspace/srv/clip/Makefile.build	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/srv/clip/Makefile.build	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2009 Martin Decky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	clip.c
+
+CFLAGS += -D$(UARCH)
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/clip/Makefile.common
===================================================================
--- uspace/srv/clip/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/srv/clip/Makefile.common	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2009 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = clip
Index: uspace/srv/clip/clip.c
===================================================================
--- uspace/srv/clip/clip.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/srv/clip/clip.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2009 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 <bool.h>
+#include <ipc/ipc.h>
+#include <async.h>
+#include <ipc/services.h>
+#include <ipc/clipboard.h>
+#include <malloc.h>
+#include <fibril_synch.h>
+#include <errno.h>
+
+#define NAME  "clip"
+
+static char *clip_data = NULL;
+static size_t clip_size = 0;
+static clipboard_tag_t clip_tag = CLIPBOARD_TAG_NONE;
+static FIBRIL_MUTEX_INITIALIZE(clip_mtx);
+
+static void clip_put_data(ipc_callid_t rid, ipc_call_t *request)
+{
+	ipc_callid_t callid;
+	size_t size;
+	
+	switch (IPC_GET_ARG1(*request)) {
+	case CLIPBOARD_TAG_NONE:
+		fibril_mutex_lock(&clip_mtx);
+		
+		if (clip_data)
+			free(clip_data);
+		
+		clip_data = NULL;
+		clip_size = 0;
+		clip_tag = CLIPBOARD_TAG_NONE;
+		
+		fibril_mutex_unlock(&clip_mtx);
+		ipc_answer_0(rid, EOK);
+		break;
+	case CLIPBOARD_TAG_BLOB:
+		if (!async_data_write_receive(&callid, &size)) {
+			ipc_answer_0(callid, EINVAL);
+			ipc_answer_0(rid, EINVAL);
+			break;
+		}
+		
+		char *data = malloc(size);
+		if (!data) {
+			ipc_answer_0(callid, ENOMEM);
+			ipc_answer_0(rid, ENOMEM);
+			break;
+		}
+		
+		ipcarg_t retval = async_data_write_finalize(callid, data, size);
+		if (retval != EOK) {
+			ipc_answer_0(rid, retval);
+			free(data);
+			break;
+		}
+		
+		fibril_mutex_lock(&clip_mtx);
+		
+		if (clip_data)
+			free(clip_data);
+		
+		clip_data = data;
+		clip_size = size;
+		clip_tag = CLIPBOARD_TAG_BLOB;
+		
+		fibril_mutex_unlock(&clip_mtx);
+		ipc_answer_0(rid, EOK);
+		break;
+	default:
+		ipc_answer_0(rid, EINVAL);
+	}
+}
+
+static void clip_get_data(ipc_callid_t rid, ipc_call_t *request)
+{
+	fibril_mutex_lock(&clip_mtx);
+	
+	ipc_callid_t callid;
+	size_t size;
+	
+	/* Check for clipboard data tag compatibility */
+	switch (IPC_GET_ARG1(*request)) {
+	case CLIPBOARD_TAG_BLOB:
+		if (!async_data_read_receive(&callid, &size)) {
+			ipc_answer_0(callid, EINVAL);
+			ipc_answer_0(rid, EINVAL);
+			break;
+		}
+		
+		if (clip_tag != CLIPBOARD_TAG_BLOB) {
+			/* So far we only understand BLOB */
+			ipc_answer_0(callid, EOVERFLOW);
+			ipc_answer_0(rid, EOVERFLOW);
+			break;
+		}
+		
+		if (clip_size != size) {
+			/* The client expects different size of data */
+			ipc_answer_0(callid, EOVERFLOW);
+			ipc_answer_0(rid, EOVERFLOW);
+			break;
+		}
+		
+		ipcarg_t retval = async_data_read_finalize(callid, clip_data, size);
+		if (retval != EOK) {
+			ipc_answer_0(rid, retval);
+			break;
+		}
+		
+		ipc_answer_0(rid, EOK);
+	default:
+		/*
+		 * Sorry, we don't know how to get unknown or NONE
+		 * data from the clipbard
+		 */
+		ipc_answer_0(rid, EINVAL);
+		break;
+	}
+	
+	fibril_mutex_unlock(&clip_mtx);
+}
+
+static void clip_content(ipc_callid_t rid, ipc_call_t *request)
+{
+	fibril_mutex_lock(&clip_mtx);
+	
+	size_t size = clip_size;
+	clipboard_tag_t tag = clip_tag;
+	
+	fibril_mutex_unlock(&clip_mtx);
+	ipc_answer_2(rid, EOK, (ipcarg_t) size, (ipcarg_t) clip_tag);
+}
+
+static void clip_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	/* Accept connection */
+	ipc_answer_0(iid, EOK);
+	
+	bool cont = true;
+	while (cont) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		switch (IPC_GET_METHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			cont = false;
+			continue;
+		case CLIPBOARD_PUT_DATA:
+			clip_put_data(callid, &call);
+			break;
+		case CLIPBOARD_GET_DATA:
+			clip_get_data(callid, &call);
+			break;
+		case CLIPBOARD_CONTENT:
+			clip_content(callid, &call);
+			break;
+		default:
+			if (!(callid & IPC_CALLID_NOTIFICATION))
+				ipc_answer_0(callid, ENOENT);
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS clipboard service\n");
+	
+	async_set_client_connection(clip_connection);
+	
+	ipcarg_t phonead;
+	if (ipc_connect_to_me(PHONE_NS, SERVICE_CLIPBOARD, 0, 0, &phonead) != 0) 
+		return -1;
+	
+	printf(NAME ": Accepting connections\n");
+	async_manager();
+	
+	/* Never reached */
+	return 0;
+}
Index: uspace/srv/clip/clip.h
===================================================================
--- uspace/srv/clip/clip.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
+++ uspace/srv/clip/clip.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2009 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CLIP_MAIN_H_
+#define CLIP_MAIN_H_
+
+#endif
Index: uspace/srv/console/console.c
===================================================================
--- uspace/srv/console/console.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/console/console.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -50,5 +50,5 @@
 #include <event.h>
 #include <devmap.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 
 #include "console.h"
@@ -601,4 +601,8 @@
 				    IPC_GET_ARG2(call));
 			break;
+		case CONSOLE_GET_POS:
+			arg1 = cons->scr.position_x;
+			arg2 = cons->scr.position_y;
+			break;
 		case CONSOLE_GET_SIZE:
 			arg1 = fb_info.cols;
Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/devmap/devmap.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -42,5 +42,5 @@
 #include <errno.h>
 #include <bool.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <stdlib.h>
 #include <string.h>
@@ -867,5 +867,5 @@
 }
 
-/** 
+/**
  * @}
  */
Index: uspace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/fs/devfs/devfs_ops.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -42,5 +42,5 @@
 #include <string.h>
 #include <libfs.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <adt/hash_table.h>
 #include <sys/stat.h>
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/fs/fat/fat.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,5 +36,5 @@
 #include "fat_fat.h"
 #include <ipc/ipc.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <libfs.h>
 #include <atomic.h>
Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -46,5 +46,5 @@
 #include <align.h>
 #include <assert.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <mem.h>
 
Index: uspace/srv/fs/fat/fat_idx.c
===================================================================
--- uspace/srv/fs/fat/fat_idx.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/fs/fat/fat_idx.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -43,5 +43,5 @@
 #include <adt/list.h>
 #include <assert.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 
 /** Each instance of this type describes one interval of freed VFS indices. */
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -52,5 +52,5 @@
 #include <adt/list.h>
 #include <assert.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <sys/mman.h>
 #include <align.h>
Index: uspace/srv/loader/arch/arm32/arm32.s
===================================================================
--- uspace/srv/loader/arch/arm32/arm32.s	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/loader/arch/arm32/arm32.s	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,4 +36,7 @@
 # Jump to a program entry point
 program_run:
+	# load ras_page address to r2
+	ldr r2, =ras_page
+	ldr r2, [r2]
 	# pcb is passed to the entry point in r1 (where it already is)
 	mov r15, r0
Index: uspace/srv/part/mbr_part/mbr_part.c
===================================================================
--- uspace/srv/part/mbr_part/mbr_part.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/part/mbr_part/mbr_part.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -61,5 +61,5 @@
 #include <async.h>
 #include <as.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <devmap.h>
 #include <sys/types.h>
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/vfs/vfs.h	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -36,5 +36,5 @@
 #include <ipc/ipc.h>
 #include <adt/list.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <sys/types.h>
 #include <devmap.h>
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/vfs/vfs_file.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -42,5 +42,5 @@
 #include <bool.h>
 #include <fibril.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include "vfs.h"
 
Index: uspace/srv/vfs/vfs_lookup.c
===================================================================
--- uspace/srv/vfs/vfs_lookup.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/vfs/vfs_lookup.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -43,5 +43,5 @@
 #include <stdarg.h>
 #include <bool.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <adt/list.h>
 #include <vfs/canonify.h>
Index: uspace/srv/vfs/vfs_node.c
===================================================================
--- uspace/srv/vfs/vfs_node.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/vfs/vfs_node.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -39,5 +39,5 @@
 #include <stdlib.h>
 #include <string.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <adt/hash_table.h>
 #include <assert.h>
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/vfs/vfs_ops.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -44,5 +44,5 @@
 #include <string.h>
 #include <bool.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <adt/list.h>
 #include <unistd.h>
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision 58d5803d422309587aa1e5c37ec90f119d64af5d)
+++ uspace/srv/vfs/vfs_register.c	(revision 387416b0bf7b246ca6a9df2aea472d75776a5b48)
@@ -46,5 +46,5 @@
 #include <ctype.h>
 #include <bool.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <adt/list.h>
 #include <as.h>
