Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ HelenOS.config	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -498,4 +498,6 @@
 @ "1152x720"
 @ "1152x864"
+@ "1280x720"
+@ "1280x800"
 @ "1280x960"
 @ "1280x1024"
@@ -544,2 +546,4 @@
 ! CONFIG_BAREBONE (n/y)
 
+% Line debugging information
+! [CONFIG_STRIP_BINARIES!=y] CONFIG_LINE_DEBUG (n/y)
Index: boot/Makefile
===================================================================
--- boot/Makefile	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/Makefile	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -48,5 +48,5 @@
 endif
 ifeq ($(RDFMT),fat)
-	$(MKFAT) $(DIST_PATH) $@
+	$(MKFAT) 1048576 $(DIST_PATH) $@
 endif
 
Index: boot/Makefile.build
===================================================================
--- boot/Makefile.build	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/Makefile.build	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -61,4 +61,11 @@
 	GCC_CFLAGS += -Werror
 	ICC_CFLAGS += -Werror
+endif
+
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	GCC_CFLAGS += -g
+	ICC_CFLAGS += -g
+	SUNCC_CFLAGS += -g
+	CLANG_CFLAGS += -g
 endif
 
Index: boot/arch/arm32/Makefile.inc
===================================================================
--- boot/arch/arm32/Makefile.inc	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/arm32/Makefile.inc	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -55,4 +55,5 @@
 	$(COMPS_C) \
 	genarch/src/division.c \
+	generic/src/memstr.c \
 	generic/src/printf_core.c \
 	generic/src/vprintf.c \
Index: boot/arch/arm32/src/asm.S
===================================================================
--- boot/arch/arm32/src/asm.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/arm32/src/asm.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -35,5 +35,4 @@
 .global boot_stack
 .global halt
-.global memcpy
 .global jump_to_kernel
 
@@ -55,63 +54,4 @@
 	b halt
 
-memcpy:
-	add r3, r1, #3
-	bic r3, r3, #3
-	cmp r1, r3
-	stmdb sp!, {r4, r5, lr}
-	mov r5, r0
-	beq 4f
-	
-	1:
-		cmp r2, #0
-		movne ip, #0
-		beq 3f
-	
-	2:
-		ldrb r3, [ip, r1]
-		strb r3, [ip, r0]
-		add ip, ip, #1
-		cmp ip, r2
-		bne 2b
-	
-	3:
-		mov r0, r5
-		ldmia sp!, {r4, r5, pc}
-	
-	4:
-		add r3, r0, #3
-		bic r3, r3, #3
-		cmp r0, r3
-		bne 1b
-		movs r4, r2, lsr #2
-		moveq lr, r4
-		beq 6f
-		mov lr, #0
-		mov ip, lr
-	
-	5:
-		ldr r3, [ip, r1]
-		add lr, lr, #1
-		cmp lr, r4
-		str r3, [ip, r0]
-		add ip, ip, #4
-		bne 5b
-	
-	6:
-		ands r4, r2, #3
-		beq 3b
-		mov r3, lr, lsl #2
-		add r0, r3, r0
-		add ip, r3, r1
-		mov r2, #0
-	
-	7:
-		ldrb r3, [r2, ip]
-		strb r3, [r2, r0]
-		add r2, r2, #1
-		cmp r2, r4
-		bne 7b
-		b 3b
-
 jump_to_kernel:
 	#
Index: boot/arch/ia64/Makefile.inc
===================================================================
--- boot/arch/ia64/Makefile.inc	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/ia64/Makefile.inc	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -49,4 +49,5 @@
 	genarch/src/division.c \
 	generic/src/balloc.c \
+	generic/src/memstr.c \
 	generic/src/printf_core.c \
 	generic/src/vprintf.c \
Index: boot/arch/ia64/src/asm.S
===================================================================
--- boot/arch/ia64/src/asm.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/ia64/src/asm.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -1,5 +1,5 @@
 #
 # Copyright (c) 2006 Martin Decky
-# Copyright (c) 2006 Jakub Jermar 
+# Copyright (c) 2006 Jakub Jermar
 # All rights reserved.
 #
@@ -39,76 +39,4 @@
 	br halt
 
-memcpy:
-	alloc loc0 = ar.pfs, 3, 1, 0, 0
-
-	adds r14 = 7, in1
-	mov r2 = ar.lc
-	mov r8 = in0 ;;
-	and r14 = -8, r14 ;;
-	cmp.ne p6, p7 = r14, in1
-(p7)	br.cond.dpnt 3f ;;
-0:
-	cmp.ne p6, p7 = 0, in2
-(p7)	br.cond.dpnt 2f ;;
-(p6)	adds r14 = -1, in2
-(p6)	mov r16 = r0
-(p6)	mov r17 = r0 ;;
-(p6)	mov ar.lc = r14
-1:
-	add r14 = r16, in1 
-	add r15 = r16, in0
-	adds r17 = 1, r17 ;;
-	ld1 r14 = [r14]
-	mov r16 = r17 ;;
-	st1 [r15] = r14
-	br.cloop.sptk.few 1b ;;
-2:
-	mov ar.lc = r2
-	mov ar.pfs = loc0
-	br.ret.sptk.many rp
-3:
-	adds r14 = 7, in0 ;;
-	and r14 = -8, r14 ;;
-	cmp.eq p6, p7 = r14, in0
-(p7)	br.cond.dptk 0b
-	shr.u r18 = in2, 3 ;;
-	cmp.ne p6, p7 = 0, r18
-(p7)	br.cond.dpnt 5f	;;
-(p6)	adds r14 = -1, r18
-(p6)	mov r16 = r0
-(p6)	mov r17 = r0 ;;
-(p6)	mov ar.lc = r14
-4:
-	shladd r14 = r16, 3, r0
-	adds r16 = 1, r17 ;;
-	add r15 = in1, r14
-	add r14 = in0, r14
-	mov r17 = r16 ;;
-	ld8 r15 = [r15] ;;
-	st8 [r14] = r15
-	br.cloop.sptk.few 4b
-5:
-	and r15 = 7, in2
-	shladd r14 = r18, 3, r0
-	mov r16 = r0
-	mov r18 = r0 ;;
-	cmp.eq p6, p7 = 0, r15
-	add in0 = r14, in0
-	adds r15 = -1, r15
-	add r17 = r14, in1 
-(p6)	br.cond.dpnt 2b ;;
-	mov ar.lc = r15
-6:
-	add r14 = r16, r17
-	add r15 = r16, in0
-	adds r16 = 1, r18 ;;
-	ld1 r14 = [r14]
-	mov r18 = r16 ;;
-	st1 [r15] = r14
-	br.cloop.sptk.few 6b ;;
-	mov ar.lc = r2
-	mov ar.pfs = loc0
-	br.ret.sptk.many rp
-
 jump_to_kernel:
 	alloc loc0 = ar.pfs, 1, 1, 0, 0
Index: boot/arch/mips32/Makefile.inc
===================================================================
--- boot/arch/mips32/Makefile.inc	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/mips32/Makefile.inc	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -61,4 +61,5 @@
 	genarch/src/division.c \
 	genarch/src/multiplication.c \
+	generic/src/memstr.c \
 	generic/src/printf_core.c \
 	generic/src/vprintf.c \
Index: boot/arch/mips32/src/asm.S
===================================================================
--- boot/arch/mips32/src/asm.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/mips32/src/asm.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -36,5 +36,4 @@
 .global start
 .global halt
-.global memcpy
 .global jump_to_kernel
 
@@ -127,70 +126,4 @@
 	nop
 
-memcpy:
-	addiu $v0, $a1, 3
-	li $v1, -4
-	and $v0, $v0, $v1
-	beq $a1, $v0, 3f
-	move $t0, $a0
-	move $t2, $a0
-	
-	0:
-		beq $a2, $zero, 2f
-		move $a3, $zero
-	
-	1:
-		addu $v0, $a1, $a3
-		lbu $a0, 0($v0)
-		addu $v1, $t0, $a3
-		addiu $a3, $a3, 1
-		bne $a3, $a2, 1b
-		sb $a0, 0($v1)
-	
-	2:
-		jr $ra
-		move $v0, $t2
-	
-	3:
-		addiu $v0, $a0, 3
-		and $v0, $v0, $v1
-		bne $a0, $v0, 0b
-		srl $t1, $a2, 2
-		
-		beq $t1, $zero, 5f
-		move $a3, $zero
-		
-		move $a3, $zero
-		move $a0, $zero
-	
-	4:
-		addu $v0, $a1, $a0
-		lw $v1, 0($v0)
-		addiu $a3, $a3, 1
-		addu $v0, $t0, $a0
-		sw $v1, 0($v0)
-		bne $a3, $t1, 4b
-		addiu $a0, $a0, 4
-	
-	5:
-		andi $a2, $a2, 0x3
-		beq $a2, $zero, 2b
-		nop
-		
-		sll $v0, $a3, 2
-		addu $t1, $v0, $t0
-		move $a3, $zero
-		addu $t0, $v0, $a1
-	
-	6:
-		addu $v0, $t0, $a3
-		lbu $a0, 0($v0)
-		addu $v1, $t1, $a3
-		addiu $a3, $a3, 1
-		bne $a3, $a2, 6b
-		sb $a0, 0($v1)
-		
-		jr $ra
-		move $v0, $t2
-
 jump_to_kernel:
 	#
Index: boot/arch/ppc32/Makefile.inc
===================================================================
--- boot/arch/ppc32/Makefile.inc	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/ppc32/Makefile.inc	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -56,4 +56,5 @@
 	genarch/src/multiplication.c \
 	generic/src/balloc.c \
+	generic/src/memstr.c \
 	generic/src/printf_core.c \
 	generic/src/vprintf.c \
Index: boot/arch/ppc32/src/asm.S
===================================================================
--- boot/arch/ppc32/src/asm.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/ppc32/src/asm.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -60,5 +60,4 @@
 .global start
 .global halt
-.global memcpy
 .global jump_to_kernel
 .global real_mode
@@ -78,60 +77,4 @@
 halt:
 	b halt
-
-memcpy:
-	srwi. r7, r5, 3
-	addi r6, r3, -4
-	addi r4, r4, -4
-	beq 2f
-	
-	andi. r0, r6, 3
-	mtctr r7
-	bne 5f
-	
-	1:
-		lwz r7, 4(r4)
-		lwzu r8, 8(r4)
-		stw r7, 4(r6)
-		stwu r8, 8(r6)
-		bdnz 1b
-		
-		andi. r5, r5, 7
-	
-	2:
-		cmplwi 0, r5, 4
-		blt 3f
-		
-		lwzu r0, 4(r4)
-		addi r5, r5, -4
-		stwu r0, 4(r6)
-	
-	3:
-		cmpwi 0, r5, 0
-		beqlr
-		mtctr r5
-		addi r4, r4, 3
-		addi r6, r6, 3
-	
-	4:
-		lbzu r0, 1(r4)
-		stbu r0, 1(r6)
-		bdnz 4b
-		blr
-	
-	5:
-		subfic r0, r0, 4
-		mtctr r0
-	
-	6:
-		lbz r7, 4(r4)
-		addi r4, r4, 1
-		stb r7, 4(r6)
-		addi r6, r6, 1
-		bdnz 6b
-		subf r5, r0, r5
-		rlwinm. r7, r5, 32-3, 3, 31
-		beq 2b
-		mtctr r7
-		b 1b
 
 jump_to_kernel:
Index: boot/arch/sparc64/Makefile.inc
===================================================================
--- boot/arch/sparc64/Makefile.inc	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/sparc64/Makefile.inc	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -54,4 +54,5 @@
 	genarch/src/ofw_tree.c \
 	generic/src/balloc.c \
+	generic/src/memstr.c \
 	generic/src/printf_core.c \
 	generic/src/vprintf.c \
Index: boot/arch/sparc64/src/asm.S
===================================================================
--- boot/arch/sparc64/src/asm.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ boot/arch/sparc64/src/asm.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -42,5 +42,4 @@
 .global start
 .global halt
-.global memcpy
 .global jump_to_kernel
 
@@ -98,73 +97,4 @@
 	ba %xcc, halt
 	nop
-
-memcpy:
-	! Save dst
-	
-	mov %o0, %o3
-	add %o1, 7, %g1
-	and %g1, -8, %g1
-	cmp %o1, %g1
-	be,pn %xcc, 3f
-	add %o0, 7, %g1
-	mov 0, %g3
-	
-	0:
-		brz,pn %o2, 2f
-		mov 0, %g2
-	
-	1:
-		ldub [%g3 + %o1], %g1
-		add %g2, 1, %g2
-		cmp %o2, %g2
-		stb %g1, [%g3 + %o0]
-		bne,pt %xcc, 1b
-		mov %g2, %g3
-	
-	2:
-		! Exit point
-		
-		jmp %o7 + 8
-		mov %o3, %o0
-	
-	3:
-		and %g1, -8, %g1
-		cmp %o0, %g1
-		bne,pt %xcc, 0b
-		mov 0, %g3
-		srlx %o2, 3, %g4
-		brz,pn %g4, 5f
-		mov 0, %g5
-	
-	4:
-		sllx %g3, 3, %g2
-		add %g5, 1, %g3
-		ldx [%o1 + %g2], %g1
-		mov %g3, %g5
-		cmp %g4, %g3
-		bne,pt %xcc, 4b
-		stx %g1, [%o0 + %g2]
-	
-	5:
-		and %o2, 7, %o2
-		brz,pn %o2, 2b
-		sllx %g4, 3, %g1
-		mov 0, %g2
-		add %g1, %o0, %o0
-		add %g1, %o1, %g4
-		mov 0, %g3
-	
-	6:
-		ldub [%g2 + %g4], %g1
-		stb %g1, [%g2 + %o0]
-		add %g3, 1, %g2
-		cmp %o2, %g2
-		bne,pt %xcc, 6b
-		mov %g2, %g3
-	
-	! Exit point
-	
-	jmp %o7 + 8
-	mov %o3, %o0
 
 jump_to_kernel:
Index: boot/generic/src/memstr.c
===================================================================
--- boot/generic/src/memstr.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
+++ boot/generic/src/memstr.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#include <memstr.h>
+#include <typedefs.h>
+
+/** Copy block of memory.
+ *
+ * Copy cnt bytes from src address to dst address.The source and destination
+ * memory areas cannot overlap.
+ *
+ * @param src		Source address to copy from.
+ * @param dst		Destination address to copy to.
+ * @param cnt		Number of bytes to copy.
+ *
+ * @return		Destination address.
+ */
+void *memcpy(void *dst, const void *src, size_t cnt)
+{
+	size_t i;
+
+	for (i = 0; i < cnt; i++)
+		((uint8_t *) dst)[i] = ((uint8_t *) src)[i];
+
+	return dst;
+}
+
+/** @}
+ */
Index: contrib/conf/ia32-qe.sh
===================================================================
--- contrib/conf/ia32-qe.sh	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ contrib/conf/ia32-qe.sh	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -5,5 +5,5 @@
 # Create a disk image if it does not exist
 if [ ! -f "$DISK_IMG" ]; then
-	tools/mkfat.py uspace/dist/data "$DISK_IMG"
+	tools/mkfat.py 1048576 uspace/dist/data "$DISK_IMG"
 fi
 
Index: contrib/conf/mips32-gx.sh
===================================================================
--- contrib/conf/mips32-gx.sh	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ contrib/conf/mips32-gx.sh	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -5,5 +5,5 @@
 # Create a disk image if it does not exist
 if [ ! -f "$DISK_IMG" ]; then
-	tools/mkfat.py uspace/dist/data "$DISK_IMG"
+	tools/mkfat.py 1048576 uspace/dist/data "$DISK_IMG"
 fi
 
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/Makefile	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -120,4 +120,11 @@
 ifeq ($(CONFIG_LTO),y)
 	GCC_CFLAGS += -flto
+endif
+
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	GCC_CFLAGS += -g
+	ICC_CFLAGS += -g
+	SUNCC_CFLAGS += -g
+	CLANG_CFLAGS += -g
 endif
 
@@ -401,5 +408,9 @@
 
 $(DISASM): $(RAW)
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	$(OBJDUMP) -d -S $< > $@
+else
 	$(OBJDUMP) -d $< > $@
+endif
 
 $(RAW): $(LINK) $(ARCH_OBJECTS) $(GENARCH_OBJECTS) $(GENERIC_OBJECTS) $(SYMTAB_OBJECTS)
Index: kernel/arch/abs32le/src/debug/stacktrace.c
===================================================================
--- kernel/arch/abs32le/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/abs32le/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -37,30 +37,30 @@
 #include <typedefs.h>
 
-bool kernel_frame_pointer_validate(uintptr_t fp)
+bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
 	return true;
 }
 
-bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return true;
 }
 
-bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
 	return true;
 }
 
-bool uspace_frame_pointer_validate(uintptr_t fp)
+bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
 	return true;
 }
 
-bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return true;
 }
 
-bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
 	return true;
Index: kernel/arch/amd64/_link.ld.in
===================================================================
--- kernel/arch/amd64/_link.ld.in	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/_link.ld.in	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -53,4 +53,17 @@
 	}
 	
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); }
+	.debug_abbrev 0 : { *(.debug_abbrev); }
+	.debug_aranges 0 : { *(.debug_aranges); }
+	.debug_info 0 : { *(.debug_info); }
+	.debug_line 0 : { *(.debug_line); }
+	.debug_loc 0 : { *(.debug_loc); }
+	.debug_pubnames 0 : { *(.debug_pubnames); }
+	.debug_pubtypes 0 : { *(.debug_pubtypes); }
+	.debug_ranges 0 : { *(.debug_ranges); }
+	.debug_str 0 : { *(.debug_str); }
+#endif
+	
 	/DISCARD/ : {
 		*(*);
Index: kernel/arch/amd64/include/pm.h
===================================================================
--- kernel/arch/amd64/include/pm.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/include/pm.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -65,6 +65,5 @@
 #endif /* CONFIG_FB */
 
-#define gdtselector(des)  ((des) << 3)
-#define idtselector(des)  ((des) << 4)
+#define GDT_SELECTOR(des)  ((des) << 3)
 
 #define PL_KERNEL  0
@@ -168,5 +167,4 @@
 
 extern ptr_16_64_t gdtr;
-extern ptr_16_32_t bootstrap_gdtr;
 extern ptr_16_32_t protected_ap_gdtr;
 
Index: kernel/arch/amd64/src/asm.S
===================================================================
--- kernel/arch/amd64/src/asm.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/asm.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -244,5 +244,5 @@
 	 */
 	xorq %rdx, %rdx
-	cmpq $(gdtselector(KTEXT_DES)), ISTATE_OFFSET_CS(%rsp)
+	cmpq $(GDT_SELECTOR(KTEXT_DES)), ISTATE_OFFSET_CS(%rsp)
 	cmovnzq %rdx, %rbp
 
Index: kernel/arch/amd64/src/boot/boot.S
===================================================================
--- kernel/arch/amd64/src/boot/boot.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/boot/boot.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -85,5 +85,5 @@
 	
 	/* Kernel data + stack */
-	movw $gdtselector(KDATA_DES), %cx
+	movw $GDT_SELECTOR(KDATA_DES), %cx
 	movw %cx, %es
 	movw %cx, %ds
@@ -94,9 +94,9 @@
 	 * when _visible_ part of GS does not point to user-mode segment.
 	 */
-	movw $gdtselector(UDATA_DES), %cx
+	movw $GDT_SELECTOR(UDATA_DES), %cx
 	movw %cx, %fs
 	movw %cx, %gs
 	
-	jmpl $gdtselector(KTEXT32_DES), $multiboot_meeting_point
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $multiboot_meeting_point
 	multiboot_meeting_point:
 	
@@ -182,5 +182,5 @@
 	
 	/* At this point we are in compatibility mode */
-	jmpl $gdtselector(KTEXT_DES), $start64
+	jmpl $GDT_SELECTOR(KTEXT_DES), $start64
 
 /** Print string to EGA display (in light red) and halt.
@@ -645,7 +645,6 @@
 .section K_DATA_START, "aw", @progbits
 
-.global bootstrap_gdtr
 bootstrap_gdtr:
-	.word gdtselector(GDT_ITEMS)
+	.word GDT_SELECTOR(GDT_ITEMS)
 	.long KA2PA(gdt)
 
Index: kernel/arch/amd64/src/boot/vesa_ret.inc
===================================================================
--- kernel/arch/amd64/src/boot/vesa_ret.inc	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/boot/vesa_ret.inc	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -7,5 +7,5 @@
 	
 	/* Kernel data + stack */
-	movw $gdtselector(KDATA_DES), %cx
+	movw $GDT_SELECTOR(KDATA_DES), %cx
 	movw %cx, %es
 	movw %cx, %ds
@@ -17,7 +17,7 @@
 	 */
 	
-	movw $gdtselector(UDATA_DES), %cx
+	movw $GDT_SELECTOR(UDATA_DES), %cx
 	movw %cx, %fs
 	movw %cx, %gs
 	
-	jmpl $gdtselector(KTEXT32_DES), $vesa_meeting_point
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $vesa_meeting_point
Index: kernel/arch/amd64/src/ddi/ddi.c
===================================================================
--- kernel/arch/amd64/src/ddi/ddi.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/ddi/ddi.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -153,5 +153,5 @@
 	tss_descriptor_t *tss_desc = (tss_descriptor_t *) &gdt_p[TSS_DES];
 	tss_desc->type = AR_TSS;
-	tr_load(gdtselector(TSS_DES));
+	tr_load(GDT_SELECTOR(TSS_DES));
 	
 	/*
Index: kernel/arch/amd64/src/debug/stacktrace.c
===================================================================
--- kernel/arch/amd64/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -40,12 +40,12 @@
 #define FRAME_OFFSET_RA       1
 
-bool kernel_frame_pointer_validate(uintptr_t fp)
+bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
-	uint64_t *stack = (void *) fp;
+	uint64_t *stack = (void *) ctx->fp;
 	*prev = stack[FRAME_OFFSET_FP_PREV];
 	
@@ -53,7 +53,7 @@
 }
 
-bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	uint64_t *stack = (void *) fp;
+	uint64_t *stack = (void *) ctx->fp;
 	*ra = stack[FRAME_OFFSET_RA];
 	
@@ -61,19 +61,19 @@
 }
 
-bool uspace_frame_pointer_validate(uintptr_t fp)
+bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return !copy_from_uspace((void *) prev,
-	    (uint64_t *) fp + FRAME_OFFSET_FP_PREV, sizeof(*prev));
+	    (uint64_t *) ctx->fp + FRAME_OFFSET_FP_PREV, sizeof(*prev));
 }
 
-bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	return !copy_from_uspace((void *) ra, (uint64_t *) fp + FRAME_OFFSET_RA,
-	    sizeof(*ra));
+	return !copy_from_uspace((void *) ra,
+	    (uint64_t *) ctx->fp + FRAME_OFFSET_RA, sizeof(*ra));
 }
 
Index: kernel/arch/amd64/src/pm.c
===================================================================
--- kernel/arch/amd64/src/pm.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/pm.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -171,5 +171,5 @@
 
 		d->unused = 0;
-		d->selector = gdtselector(KTEXT_DES);
+		d->selector = GDT_SELECTOR(KTEXT_DES);
 
 		d->present = 1;
@@ -291,5 +291,5 @@
 	 * to its own TSS. We just need to load the TR register.
 	 */
-	tr_load(gdtselector(TSS_DES));
+	tr_load(GDT_SELECTOR(TSS_DES));
 }
 
Index: kernel/arch/amd64/src/smp/ap.S
===================================================================
--- kernel/arch/amd64/src/smp/ap.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/smp/ap.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -61,13 +61,13 @@
 	orl $1, %eax
 	movl %eax, %cr0     # switch to protected mode
-	jmpl $gdtselector(KTEXT32_DES), $jump_to_kernel - BOOT_OFFSET + AP_BOOT_OFFSET
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $jump_to_kernel - BOOT_OFFSET + AP_BOOT_OFFSET
 
 jump_to_kernel:
 .code32
-	movw $gdtselector(KDATA_DES), %ax
+	movw $GDT_SELECTOR(KDATA_DES), %ax
 	movw %ax, %ds
 	movw %ax, %es
 	movw %ax, %ss
-	movw $gdtselector(UDATA_DES), %ax
+	movw $GDT_SELECTOR(UDATA_DES), %ax
 	movw %ax, %gs
 	
@@ -94,5 +94,5 @@
 	
 	# At this point we are in compatibility mode
-	jmpl $gdtselector(KTEXT_DES), $start64 - BOOT_OFFSET + AP_BOOT_OFFSET
+	jmpl $GDT_SELECTOR(KTEXT_DES), $start64 - BOOT_OFFSET + AP_BOOT_OFFSET
 
 .code64
Index: kernel/arch/amd64/src/syscall.c
===================================================================
--- kernel/arch/amd64/src/syscall.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/syscall.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -58,6 +58,6 @@
 	 */
 	write_msr(AMD_MSR_STAR,
-	    ((uint64_t)(gdtselector(KDATA_DES) | PL_USER) << 48) |
-	    ((uint64_t)(gdtselector(KTEXT_DES) | PL_KERNEL) << 32));
+	    ((uint64_t) (GDT_SELECTOR(KDATA_DES) | PL_USER) << 48) |
+	    ((uint64_t) (GDT_SELECTOR(KTEXT_DES) | PL_KERNEL) << 32));
 	write_msr(AMD_MSR_LSTAR, (uint64_t)syscall_entry);
 	/* Mask RFLAGS on syscall 
Index: kernel/arch/amd64/src/userspace.c
===================================================================
--- kernel/arch/amd64/src/userspace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/amd64/src/userspace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -65,8 +65,8 @@
 		"xorq %%rdi, %%rdi\n"
 		"iretq\n"
-		:: [udata_des] "i" (gdtselector(UDATA_DES) | PL_USER),
+		:: [udata_des] "i" (GDT_SELECTOR(UDATA_DES) | PL_USER),
 		   [stack_size] "r" (kernel_uarg->uspace_stack + THREAD_STACK_SIZE),
 		   [ipl] "r" (ipl),
-		   [utext_des] "i" (gdtselector(UTEXT_DES) | PL_USER),
+		   [utext_des] "i" (GDT_SELECTOR(UTEXT_DES) | PL_USER),
 		   [entry] "r" (kernel_uarg->uspace_entry),
 		   [uarg] "r" (kernel_uarg->uspace_uarg)
Index: kernel/arch/arm32/src/debug/stacktrace.c
===================================================================
--- kernel/arch/arm32/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/arm32/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -40,12 +40,12 @@
 #define FRAME_OFFSET_RA		-1
 
-bool kernel_frame_pointer_validate(uintptr_t fp)
+bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
-	uint32_t *stack = (void *) fp;
+	uint32_t *stack = (void *) ctx->fp;
 
 	*prev = stack[FRAME_OFFSET_FP_PREV];
@@ -53,7 +53,7 @@
 }
 
-bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	uint32_t *stack = (void *) fp;
+	uint32_t *stack = (void *) ctx->fp;
 
 	*ra = stack[FRAME_OFFSET_RA];
@@ -61,19 +61,19 @@
 }
 
-bool uspace_frame_pointer_validate(uintptr_t fp)
+bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return !copy_from_uspace((void *) prev,
-	    (uint32_t *) fp + FRAME_OFFSET_FP_PREV, sizeof(*prev));
+	    (uint32_t *) ctx->fp + FRAME_OFFSET_FP_PREV, sizeof(*prev));
 }
 
-bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	return !copy_from_uspace((void *) ra, (uint32_t *) fp + FRAME_OFFSET_RA,
-	    sizeof(*ra));
+	return !copy_from_uspace((void *) ra,
+	    (uint32_t *) ctx->fp + FRAME_OFFSET_RA, sizeof(*ra));
 }
 
Index: kernel/arch/ia32/include/bios/bios.h
===================================================================
--- kernel/arch/ia32/include/bios/bios.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/include/bios/bios.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -38,6 +38,4 @@
 #include <typedefs.h>
 
-#define BIOS_EBDA_PTR  0x40e
-
 extern uintptr_t ebda;
 
Index: kernel/arch/ia32/include/mm/as.h
===================================================================
--- kernel/arch/ia32/include/mm/as.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/include/mm/as.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup ia32mm	
+/** @addtogroup ia32mm
  * @{
  */
Index: kernel/arch/ia32/include/mm/page.h
===================================================================
--- kernel/arch/ia32/include/mm/page.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/include/mm/page.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup ia32mm	
+/** @addtogroup ia32mm
  * @{
  */
@@ -106,5 +106,5 @@
 
 /* Set PTE flags accessors for each level. */
-#define SET_PTL1_FLAGS_ARCH(ptl0, i, x)	\
+#define SET_PTL1_FLAGS_ARCH(ptl0, i, x) \
 	set_pt_flags((pte_t *) (ptl0), (size_t) (i), (x))
 #define SET_PTL2_FLAGS_ARCH(ptl1, i, x)
Index: kernel/arch/ia32/include/pm.h
===================================================================
--- kernel/arch/ia32/include/pm.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/include/pm.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -58,5 +58,5 @@
 #endif /* CONFIG_FB */
 
-#define gdtselector(des)  ((des) << 3)
+#define GDT_SELECTOR(des)  ((des) << 3)
 
 #define PL_KERNEL  0
@@ -153,5 +153,4 @@
 
 extern ptr_16_32_t gdtr;
-extern ptr_16_32_t bootstrap_gdtr;
 extern ptr_16_32_t protected_ap_gdtr;
 extern tss_t *tss_p;
Index: kernel/arch/ia32/src/asm.S
===================================================================
--- kernel/arch/ia32/src/asm.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/asm.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -225,5 +225,5 @@
 	 * Switch to kernel selectors.
 	 */
-	movw $(gdtselector(KDATA_DES)), %ax
+	movw $(GDT_SELECTOR(KDATA_DES)), %ax
 	movw %ax, %ds
 	movw %ax, %es
@@ -304,5 +304,5 @@
 	 * Switch to kernel selectors.
 	 */
-	movl $(gdtselector(KDATA_DES)), %eax
+	movl $(GDT_SELECTOR(KDATA_DES)), %eax
 	movl %eax, %ds
 	movl %eax, %es
@@ -407,5 +407,5 @@
 	 * Switch to kernel selectors.
 	 */
-	movl $(gdtselector(KDATA_DES)), %eax
+	movl $(GDT_SELECTOR(KDATA_DES)), %eax
 	movl %eax, %ds
 	movl %eax, %es
@@ -416,5 +416,5 @@
 	 */
 	xorl %eax, %eax
-	cmpl $(gdtselector(KTEXT_DES)), ISTATE_OFFSET_CS(%esp)
+	cmpl $(GDT_SELECTOR(KTEXT_DES)), ISTATE_OFFSET_CS(%esp)
 	cmovnzl %eax, %ebp
 
Index: kernel/arch/ia32/src/bios/bios.c
===================================================================
--- kernel/arch/ia32/src/bios/bios.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/bios/bios.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -36,4 +36,6 @@
 #include <typedefs.h>
 
+#define BIOS_EBDA_PTR  0x40e
+
 uintptr_t ebda = 0;
 
Index: kernel/arch/ia32/src/boot/boot.S
===================================================================
--- kernel/arch/ia32/src/boot/boot.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/boot/boot.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -78,8 +78,8 @@
 	
 	/* Initialize Global Descriptor Table register */
-	lgdtl KA2PA(bootstrap_gdtr)
+	lgdtl bootstrap_gdtr
 	
 	/* Kernel data + stack */
-	movw $gdtselector(KDATA_DES), %cx
+	movw $GDT_SELECTOR(KDATA_DES), %cx
 	movw %cx, %es
 	movw %cx, %fs
@@ -88,5 +88,5 @@
 	movw %cx, %ss
 	
-	jmpl $gdtselector(KTEXT_DES), $multiboot_meeting_point
+	jmpl $GDT_SELECTOR(KTEXT_DES), $multiboot_meeting_point
 	multiboot_meeting_point:
 	
@@ -514,4 +514,8 @@
 page_directory:
 	.space 4096, 0
+
+bootstrap_gdtr:
+	.word GDT_SELECTOR(GDT_ITEMS)
+	.long KA2PA(gdt)
 
 grub_eax:
Index: kernel/arch/ia32/src/boot/vesa_real.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_real.inc	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/boot/vesa_real.inc	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -30,5 +30,5 @@
 .code32
 vesa_init:
-	jmp $gdtselector(VESA_INIT_DES), $vesa_init_real - vesa_init
+	jmp $GDT_SELECTOR(VESA_INIT_DES), $vesa_init_real - vesa_init
 
 .code16
@@ -335,5 +335,5 @@
 		vesa_leave_real2:
 		
-			ljmpl $gdtselector(KTEXT32_DES), $(vesa_init_protected - vesa_init + VESA_INIT_SEGMENT << 4)
+			ljmpl $GDT_SELECTOR(KTEXT32_DES), $(vesa_init_protected - vesa_init + VESA_INIT_SEGMENT << 4)
 	
 	no_mode:
Index: kernel/arch/ia32/src/boot/vesa_ret.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_ret.inc	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/boot/vesa_ret.inc	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -7,5 +7,5 @@
 	
 	/* Kernel data + stack */
-	movw $gdtselector(KDATA_DES), %cx
+	movw $GDT_SELECTOR(KDATA_DES), %cx
 	movw %cx, %es
 	movw %cx, %fs
@@ -14,3 +14,3 @@
 	movw %cx, %ss
 	
-	jmpl $gdtselector(KTEXT_DES), $vesa_meeting_point
+	jmpl $GDT_SELECTOR(KTEXT_DES), $vesa_meeting_point
Index: kernel/arch/ia32/src/ddi/ddi.c
===================================================================
--- kernel/arch/ia32/src/ddi/ddi.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/ddi/ddi.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -153,5 +153,5 @@
 	 */
 	gdt_p[TSS_DES].access = AR_PRESENT | AR_TSS | DPL_KERNEL;
-	tr_load(gdtselector(TSS_DES));
+	tr_load(GDT_SELECTOR(TSS_DES));
 	
 	/*
Index: kernel/arch/ia32/src/debug/stacktrace.c
===================================================================
--- kernel/arch/ia32/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -40,38 +40,38 @@
 #define FRAME_OFFSET_RA		1
 
-bool kernel_frame_pointer_validate(uintptr_t fp)
+bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
-	uint32_t *stack = (void *) fp;
+	uint32_t *stack = (void *) ctx->fp;
 	*prev = stack[FRAME_OFFSET_FP_PREV];
 	return true;
 }
 
-bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	uint32_t *stack = (void *) fp;
+	uint32_t *stack = (void *) ctx->fp;
 	*ra = stack[FRAME_OFFSET_RA];
 	return true;
 }
 
-bool uspace_frame_pointer_validate(uintptr_t fp)
+bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return !copy_from_uspace((void *) prev,
-	    (uint32_t *) fp + FRAME_OFFSET_FP_PREV, sizeof(*prev));
+	    (uint32_t *) ctx->fp + FRAME_OFFSET_FP_PREV, sizeof(*prev));
 }
 
-bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	return !copy_from_uspace((void *) ra, (uint32_t *) fp + FRAME_OFFSET_RA,
-	    sizeof(*ra));
+	return !copy_from_uspace((void *) ra,
+	    (uint32_t *) ctx->fp + FRAME_OFFSET_RA, sizeof(*ra));
 }
 
Index: kernel/arch/ia32/src/mm/frame.c
===================================================================
--- kernel/arch/ia32/src/mm/frame.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/mm/frame.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -131,7 +131,14 @@
 			if (last_frame < ALIGN_UP(new_base + new_size, FRAME_SIZE))
 				last_frame = ALIGN_UP(new_base + new_size, FRAME_SIZE);
-		}
-		
-		if (e820table[i].type == MEMMAP_MEMORY_RESERVED) {
+		} else if ((e820table[i].type == MEMMAP_MEMORY_ACPI) ||
+		    (e820table[i].type == MEMMAP_MEMORY_NVS)) {
+			/* To be safe, make the firmware zone possibly larger */
+			uint64_t new_base = ALIGN_DOWN(base, FRAME_SIZE);
+			uint64_t new_size = ALIGN_UP(size + (base - new_base),
+			    FRAME_SIZE);
+			
+			zone_create(ADDR2PFN(new_base), SIZE2FRAMES(new_size), 0,
+			    ZONE_FIRMWARE);
+		} else {
 			/* To be safe, make the reserved zone possibly larger */
 			uint64_t new_base = ALIGN_DOWN(base, FRAME_SIZE);
@@ -141,14 +148,4 @@
 			zone_create(ADDR2PFN(new_base), SIZE2FRAMES(new_size), 0,
 			    ZONE_RESERVED);
-		}
-		
-		if (e820table[i].type == MEMMAP_MEMORY_ACPI) {
-			/* To be safe, make the firmware zone possibly larger */
-			uint64_t new_base = ALIGN_DOWN(base, FRAME_SIZE);
-			uint64_t new_size = ALIGN_UP(size + (base - new_base),
-			    FRAME_SIZE);
-			
-			zone_create(ADDR2PFN(new_base), SIZE2FRAMES(new_size), 0,
-			    ZONE_FIRMWARE);
 		}
 	}
@@ -203,5 +200,5 @@
 #ifdef CONFIG_SMP
 		/* Reserve AP real mode bootstrap memory */
-		frame_mark_unavailable(AP_BOOT_OFFSET >> FRAME_WIDTH, 
+		frame_mark_unavailable(AP_BOOT_OFFSET >> FRAME_WIDTH,
 		    (hardcoded_unmapped_ktext_size +
 		    hardcoded_unmapped_kdata_size) >> FRAME_WIDTH);
Index: kernel/arch/ia32/src/pm.c
===================================================================
--- kernel/arch/ia32/src/pm.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/pm.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -75,6 +75,6 @@
 	/* VESA Init descriptor */
 #ifdef CONFIG_FB
-	{ 0xffff, 0, VESA_INIT_SEGMENT>>12, AR_PRESENT | AR_CODE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 }
-#endif	
+	{ 0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_CODE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 }
+#endif
 };
 
@@ -86,6 +86,8 @@
 
 /* gdtr is changed by kmp before next CPU is initialized */
-ptr_16_32_t bootstrap_gdtr = { .limit = sizeof(gdt), .base = KA2PA((uintptr_t) gdt) };
-ptr_16_32_t gdtr = { .limit = sizeof(gdt), .base = (uintptr_t) gdt };
+ptr_16_32_t gdtr = {
+	.limit = sizeof(gdt),
+	.base = (uintptr_t) gdt
+};
 
 void gdt_setbase(descriptor_t *d, uintptr_t base)
@@ -128,5 +130,5 @@
 
 		d->unused = 0;
-		d->selector = gdtselector(KTEXT_DES);
+		d->selector = GDT_SELECTOR(KTEXT_DES);
 
 		if (i == VECTOR_SYSCALL) {
@@ -283,5 +285,5 @@
 	 * to its own TSS. We just need to load the TR register.
 	 */
-	tr_load(gdtselector(TSS_DES));
+	tr_load(GDT_SELECTOR(TSS_DES));
 	
 	clean_IOPL_NT_flags();    /* Disable I/O on nonprivileged levels and clear NT flag. */
Index: kernel/arch/ia32/src/proc/scheduler.c
===================================================================
--- kernel/arch/ia32/src/proc/scheduler.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/proc/scheduler.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -67,5 +67,5 @@
 	/* Set kernel stack for CPL3 -> CPL0 switch via interrupt */
 	CPU->arch.tss->esp0 = kstk;
-	CPU->arch.tss->ss0 = gdtselector(KDATA_DES);
+	CPU->arch.tss->ss0 = GDT_SELECTOR(KDATA_DES);
 	
 	/* Set up TLS in GS register */
Index: kernel/arch/ia32/src/syscall.c
===================================================================
--- kernel/arch/ia32/src/syscall.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/syscall.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -45,5 +45,5 @@
 
 	/* set kernel mode CS selector */
-	write_msr(IA32_MSR_SYSENTER_CS, gdtselector(KTEXT_DES));
+	write_msr(IA32_MSR_SYSENTER_CS, GDT_SELECTOR(KTEXT_DES));
 	/* set kernel mode entry point */
 	write_msr(IA32_MSR_SYSENTER_EIP, (uint32_t) sysenter_handler);
Index: kernel/arch/ia32/src/userspace.c
===================================================================
--- kernel/arch/ia32/src/userspace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia32/src/userspace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -75,11 +75,11 @@
 		"iret\n"
 		:
-		: [udata_des] "i" (gdtselector(UDATA_DES) | PL_USER),
+		: [udata_des] "i" (GDT_SELECTOR(UDATA_DES) | PL_USER),
 		  [stack_size] "r" ((uint8_t *) kernel_uarg->uspace_stack + THREAD_STACK_SIZE),
 		  [ipl] "r" (ipl),
-		  [utext_des] "i" (gdtselector(UTEXT_DES) | PL_USER),
+		  [utext_des] "i" (GDT_SELECTOR(UTEXT_DES) | PL_USER),
 		  [entry] "r" (kernel_uarg->uspace_entry),
 		  [uarg] "r" (kernel_uarg->uspace_uarg),
-		  [tls_des] "r" (gdtselector(TLS_DES))
+		  [tls_des] "r" (GDT_SELECTOR(TLS_DES))
 		: "eax");
 	
Index: kernel/arch/ia64/src/debug/stacktrace.c
===================================================================
--- kernel/arch/ia64/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ia64/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -37,30 +37,30 @@
 #include <typedefs.h>
 
-bool kernel_frame_pointer_validate(uintptr_t fp)
+bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
 	return false;
 }
 
-bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return false;
 }
 
-bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
 	return false;
 }
 
-bool uspace_frame_pointer_validate(uintptr_t fp)
+bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
 	return false;
 }
 
-bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return false;
 }
 
-bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
 	return false;
Index: kernel/arch/mips32/include/debugger.h
===================================================================
--- kernel/arch/mips32/include/debugger.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/mips32/include/debugger.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -68,4 +68,6 @@
 extern bpinfo_t breakpoints[BKPOINTS_MAX];
 
+extern bool is_jump(unative_t);
+
 extern void debugger_init(void);
 extern void debugger_bpoint(istate_t *);
Index: kernel/arch/mips32/src/debug/stacktrace.c
===================================================================
--- kernel/arch/mips32/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/mips32/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -36,35 +36,204 @@
 #include <syscall/copy.h>
 #include <typedefs.h>
-
-bool kernel_frame_pointer_validate(uintptr_t fp)
+#include <arch/debugger.h>
+#include <print.h>
+
+#define R0	0U
+#define SP	29U
+#define RA	31U
+
+#define OP_SHIFT	26
+#define RS_SHIFT	21
+#define RT_SHIFT	16
+#define RD_SHIFT	11
+
+#define HINT_SHIFT	6
+#define BASE_SHIFT	RS_SHIFT
+#define IMM_SHIFT	0
+#define OFFSET_SHIFT	IMM_SHIFT
+
+#define RS_MASK		(0x1f << RS_SHIFT)
+#define RT_MASK		(0x1f << RT_SHIFT)
+#define RD_MASK		(0x1f << RD_SHIFT)
+#define HINT_MASK	(0x1f << HINT_SHIFT)
+#define BASE_MASK	RS_MASK
+#define IMM_MASK	(0xffff << IMM_SHIFT)
+#define OFFSET_MASK	IMM_MASK	
+
+#define RS_GET(inst)		(((inst) & RS_MASK) >> RS_SHIFT)
+#define RD_GET(inst)		(((inst) & RD_MASK) >> RD_SHIFT)
+#define IMM_GET(inst)		(int16_t)(((inst) & IMM_MASK) >> IMM_SHIFT)
+#define BASE_GET(inst)		RS_GET(inst)
+#define OFFSET_GET(inst)	IMM_GET(inst)	
+
+#define ADDU_R_SP_R0_TEMPL \
+	((0x0 << OP_SHIFT) | (SP << RS_SHIFT) | (R0 << RT_SHIFT) | 0x21)
+#define ADDU_SP_R_R0_TEMPL \
+	((0x0 << OP_SHIFT) | (SP << RD_SHIFT) | (R0 << RT_SHIFT) | 0x21)
+#define ADDI_SP_SP_IMM_TEMPL \
+	((0x8 << OP_SHIFT) | (SP << RS_SHIFT) | (SP << RT_SHIFT))
+#define ADDIU_SP_SP_IMM_TEMPL \
+	((0x9 << OP_SHIFT) | (SP << RS_SHIFT) | (SP << RT_SHIFT))
+#define JR_RA_TEMPL \
+	((0x0 << OP_SHIFT) | (RA << RS_SHIFT) | (0x0 << HINT_SHIFT) | 0x8)
+#define SW_RA_TEMPL \
+	((0x2b << OP_SHIFT) | (RA << RT_SHIFT))
+
+#define IS_ADDU_R_SP_R0(inst) \
+	(((inst) & ~RD_MASK) == ADDU_R_SP_R0_TEMPL)
+#define IS_ADDU_SP_R_R0(inst) \
+	(((inst) & ~RS_MASK) == ADDU_SP_R_R0_TEMPL)
+#define IS_ADDI_SP_SP_IMM(inst) \
+	(((inst) & ~IMM_MASK) == ADDI_SP_SP_IMM_TEMPL)
+#define IS_ADDIU_SP_SP_IMM(inst) \
+	(((inst) & ~IMM_MASK) == ADDIU_SP_SP_IMM_TEMPL)
+#define IS_JR_RA(inst) \
+	(((inst) & ~HINT_MASK) == JR_RA_TEMPL)
+#define IS_SW_RA(inst) \
+	(((inst) & ~(BASE_MASK | OFFSET_MASK)) == SW_RA_TEMPL)
+
+extern char ktext_start;
+extern char ktext_end;
+
+static bool
+scan(stack_trace_context_t *ctx, uintptr_t *prev_fp, uintptr_t *prev_ra)
+{
+	uint32_t *inst = (void *) ctx->pc;
+	bool has_fp = false;
+	size_t frame_size;
+	unsigned int fp = SP;
+
+	do {
+		inst--;
+#if 0
+		/*
+		 * This is one of the situations in which the theory (ABI) does
+		 * not meet the practice (GCC). GCC simply does not place the
+		 * JR $ra instruction as dictated by the ABI, rendering the
+		 * official stack tracing algorithm somewhat unapplicable.
+		 */
+
+		if (IS_ADDU_R_SP_R0(*inst)) {
+			uint32_t *cur;
+			fp = RD_GET(*inst);
+			/*
+			 * We have a candidate for frame pointer.
+			 */
+			
+			/* Seek to the end of this function. */
+			for (cur = inst + 1; !IS_JR_RA(*cur); cur++)
+				;
+			/* Scan the last basic block */
+			for (cur--; !is_jump(*(cur - 1)); cur--) {
+				if (IS_ADDU_SP_R_R0(*cur) &&
+				    (fp == RS_GET(*cur))) {
+					has_fp = true;
+				}
+			}
+			continue;
+		}
+		
+		if (IS_JR_RA(*inst)) {
+			if (!ctx->istate)
+				return false;
+			/*
+			 * No stack frame has been allocated yet.
+			 * Use the values stored in istate.
+			 */
+			if (prev_fp)
+				*prev_fp = ctx->istate->sp;
+			if (prev_ra)
+				*prev_ra = ctx->istate->ra - 8;
+			ctx->istate = NULL;
+			return true;
+		}
+#endif
+
+	} while ((!IS_ADDIU_SP_SP_IMM(*inst) && !IS_ADDI_SP_SP_IMM(*inst)) ||
+	    (IMM_GET(*inst) >= 0));
+	
+	/*
+	 * We are at the instruction which allocates the space for the current
+	 * stack frame.
+	 */
+	frame_size = -IMM_GET(*inst);
+	if (prev_fp)
+		*prev_fp = ctx->fp + frame_size;
+
+	/*
+	 * Scan the first basic block for the occurrence of
+	 * SW $ra, OFFSET($base).
+	 */
+	for (inst++; !is_jump(*(inst - 1)) && (uintptr_t) inst < ctx->pc;
+	    inst++) {
+		if (IS_SW_RA(*inst)) {
+			unsigned int base = BASE_GET(*inst);
+			int16_t offset = OFFSET_GET(*inst);
+
+			if (base == SP || (has_fp && base == fp)) {
+				uint32_t *addr = (void *) (ctx->fp + offset);
+				
+				if (offset % 4 != 0)
+					return false;
+				/* cannot store below current stack pointer */
+				if (offset < 0)
+					return false;
+				/* too big offsets are suspicious */
+				if (offset > 32 * 4)
+					return false;
+
+				if (prev_ra)
+					*prev_ra = *addr;
+				return true;
+			}
+		}
+	}
+
+	/*
+	 * The first basic block does not save the return address or saves it
+	 * after ctx->pc, which means that the correct value is in istate.
+	 */
+	if (prev_ra) {
+		if (!ctx->istate)
+			return false;
+		*prev_ra = ctx->istate->ra - 8;
+		ctx->istate = NULL;
+	}
+	return true;
+}
+
+
+bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
+{
+	return !((ctx->fp == 0) || ((ctx->fp % 8) != 0) ||
+	    (ctx->pc % 4 != 0) || (ctx->pc < (uintptr_t) &ktext_start) ||
+	    (ctx->pc >= (uintptr_t) &ktext_end));
+}
+
+bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
+{
+	return scan(ctx, prev, NULL);
+}
+
+bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
+{
+	return scan(ctx, NULL, ra);
+}
+
+bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
 	return false;
 }
 
-bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return false;
 }
 
-bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
 	return false;
 }
 
-bool uspace_frame_pointer_validate(uintptr_t fp)
-{
-	return false;
-}
-
-bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
-{
-	return false;
-}
-
-bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
-{
-	return false;
-}
-
 /** @}
  */
Index: kernel/arch/mips32/src/debug/stacktrace_asm.S
===================================================================
--- kernel/arch/mips32/src/debug/stacktrace_asm.S	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/mips32/src/debug/stacktrace_asm.S	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -37,7 +37,7 @@
 frame_pointer_get:
 	j $ra
-	xor $v0, $v0
+	move $v0, $sp
 
 program_counter_get:
 	j $ra
-	xor $v0, $v0
+	move $v0, $ra
Index: kernel/arch/mips32/src/debugger.c
===================================================================
--- kernel/arch/mips32/src/debugger.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/mips32/src/debugger.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -134,5 +134,5 @@
  *
  */
-static bool is_jump(unative_t instr)
+bool is_jump(unative_t instr)
 {
 	unsigned int i;
Index: kernel/arch/ppc32/src/debug/stacktrace.c
===================================================================
--- kernel/arch/ppc32/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/ppc32/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -40,38 +40,38 @@
 #define FRAME_OFFSET_RA       1
 
-bool kernel_frame_pointer_validate(uintptr_t fp)
+bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
-	uint32_t *stack = (void *) fp;
+	uint32_t *stack = (void *) ctx->fp;
 	*prev = stack[FRAME_OFFSET_FP_PREV];
 	return true;
 }
 
-bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	uint32_t *stack = (void *) fp;
+	uint32_t *stack = (void *) ctx->fp;
 	*ra = stack[FRAME_OFFSET_RA];
 	return true;
 }
 
-bool uspace_frame_pointer_validate(uintptr_t fp)
+bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return !copy_from_uspace((void *) prev,
-	    (uint32_t *) fp + FRAME_OFFSET_FP_PREV, sizeof(*prev));
+	    (uint32_t *) ctx->fp + FRAME_OFFSET_FP_PREV, sizeof(*prev));
 }
 
-bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	return !copy_from_uspace((void *) ra, (uint32_t *) fp + FRAME_OFFSET_RA,
-	    sizeof(*ra));
+	return !copy_from_uspace((void *) ra,
+	    (uint32_t *) ctx->fp + FRAME_OFFSET_RA, sizeof(*ra));
 }
 
Index: kernel/arch/sparc64/src/debug/stacktrace.c
===================================================================
--- kernel/arch/sparc64/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/arch/sparc64/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -50,5 +50,5 @@
 extern void alloc_window_and_flush(void);
 
-bool kernel_frame_pointer_validate(uintptr_t fp)
+bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
 	uintptr_t kstack;
@@ -63,12 +63,12 @@
 	kstack -= PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE;
 
-	if (THREAD && (fp == kstack))
+	if (THREAD && (ctx->fp == kstack))
 		return false;
-	return fp != 0;
+	return ctx->fp != 0;
 }
 
-bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
-	uint64_t *stack = (void *) fp;
+	uint64_t *stack = (void *) ctx->fp;
 	alloc_window_and_flush();
 	*prev = stack[FRAME_OFFSET_FP_PREV] + STACK_BIAS;
@@ -76,7 +76,7 @@
 }
 
-bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
 {
-	uint64_t *stack = (void *) fp;
+	uint64_t *stack = (void *) ctx->fp;
 	alloc_window_and_flush();
 	*ra = stack[FRAME_OFFSET_RA];
@@ -84,15 +84,15 @@
 }
 
-bool uspace_frame_pointer_validate(uintptr_t fp)
+bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
 {
 	return false;
 }
 
-bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
+bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
 {
 	return false;
 }
 
-bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
+bool uspace_return_address_get(stack_trace_context_t *ctx , uintptr_t *ra)
 {
 	return false;
Index: kernel/generic/include/macros.h
===================================================================
--- kernel/generic/include/macros.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/generic/include/macros.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -47,12 +47,30 @@
  * @param s2  Start address of the second interval.
  * @param sz2 Size of the second interval.
+ *
  */
-NO_TRACE static inline int overlaps(uintptr_t s1, size_t sz1, uintptr_t s2,
-    size_t sz2)
+NO_TRACE static inline int overlaps(uint64_t s1, uint64_t sz1, uint64_t s2,
+    uint64_t sz2)
 {
-	uintptr_t e1 = s1 + sz1;
-	uintptr_t e2 = s2 + sz2;
+	uint64_t e1 = s1 + sz1;
+	uint64_t e2 = s2 + sz2;
 	
 	return ((s1 < e2) && (s2 < e1));
+}
+
+/** Return true if the second interval is within the first interval.
+ *
+ * @param s1  Start address of the first interval.
+ * @param sz1 Size of the first interval.
+ * @param s2  Start address of the second interval.
+ * @param sz2 Size of the second interval.
+ *
+ */
+NO_TRACE static inline int iswithin(uint64_t s1, uint64_t sz1, uint64_t s2,
+    uint64_t sz2)
+{
+	uint64_t e1 = s1 + sz1;
+	uint64_t e2 = s2 + sz2;
+	
+	return ((s1 <= s2) && (e1 >= e2));
 }
 
@@ -74,5 +92,5 @@
 
 /* Compute overlapping of physical addresses */
-#define PA_overlaps(x, szx, y, szy) \
+#define PA_OVERLAPS(x, szx, y, szy) \
 	overlaps(KA2PA((x)), (szx), KA2PA((y)), (szy))
 
Index: kernel/generic/include/stacktrace.h
===================================================================
--- kernel/generic/include/stacktrace.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/generic/include/stacktrace.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -42,7 +42,13 @@
 
 typedef struct {
-	bool (* frame_pointer_validate)(uintptr_t);
-	bool (* frame_pointer_prev)(uintptr_t, uintptr_t *);
-	bool (* return_address_get)(uintptr_t, uintptr_t *);
+	uintptr_t fp;
+	uintptr_t pc;
+	struct istate *istate;
+} stack_trace_context_t;
+
+typedef struct {
+	bool (* stack_trace_context_validate)(stack_trace_context_t *);
+	bool (* frame_pointer_prev)(stack_trace_context_t *, uintptr_t *);
+	bool (* return_address_get)(stack_trace_context_t *, uintptr_t *);
 	bool (* symbol_resolve)(uintptr_t, const char **, uintptr_t *);
 } stack_trace_ops_t;
@@ -53,5 +59,5 @@
 extern void stack_trace(void);
 extern void stack_trace_istate(struct istate *);
-extern void stack_trace_fp_pc(stack_trace_ops_t *, uintptr_t, uintptr_t);
+extern void stack_trace_ctx(stack_trace_ops_t *, stack_trace_context_t *);
 
 /*
@@ -61,11 +67,11 @@
 extern uintptr_t program_counter_get(void);
 
-extern bool kernel_frame_pointer_validate(uintptr_t);
-extern bool kernel_frame_pointer_prev(uintptr_t, uintptr_t *);
-extern bool kernel_return_address_get(uintptr_t, uintptr_t *);
+extern bool kernel_stack_trace_context_validate(stack_trace_context_t *);
+extern bool kernel_frame_pointer_prev(stack_trace_context_t *, uintptr_t *);
+extern bool kernel_return_address_get(stack_trace_context_t *, uintptr_t *);
 
-extern bool uspace_frame_pointer_validate(uintptr_t);
-extern bool uspace_frame_pointer_prev(uintptr_t, uintptr_t *);
-extern bool uspace_return_address_get(uintptr_t, uintptr_t *);
+extern bool uspace_stack_trace_context_validate(stack_trace_context_t *);
+extern bool uspace_frame_pointer_prev(stack_trace_context_t *, uintptr_t *);
+extern bool uspace_return_address_get(stack_trace_context_t *, uintptr_t *);
 
 #endif
Index: kernel/generic/src/debug/stacktrace.c
===================================================================
--- kernel/generic/src/debug/stacktrace.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/generic/src/debug/stacktrace.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup genericdebug 
+/** @addtogroup genericdebug
  * @{
  */
@@ -42,24 +42,31 @@
 
 void
-stack_trace_fp_pc(stack_trace_ops_t *ops, uintptr_t fp, uintptr_t pc)
+stack_trace_ctx(stack_trace_ops_t *ops, stack_trace_context_t *ctx)
 {
 	int cnt = 0;
 	const char *symbol;
 	uintptr_t offset;
+	uintptr_t fp;
+	uintptr_t pc;
 	
-	while (cnt++ < STACK_FRAMES_MAX && ops->frame_pointer_validate(fp)) {
+	while (cnt++ < STACK_FRAMES_MAX &&
+	    ops->stack_trace_context_validate(ctx)) {
 		if (ops->symbol_resolve &&
-		    ops->symbol_resolve(pc, &symbol, &offset)) {
+		    ops->symbol_resolve(ctx->pc, &symbol, &offset)) {
 		    	if (offset)
-				printf("%p: %s+%" PRIp "()\n", fp, symbol, offset);
+				printf("%p: %s+%" PRIp "()\n",
+				    ctx->fp, symbol, offset);
 			else
-				printf("%p: %s()\n", fp, symbol);
+				printf("%p: %s()\n",
+				    ctx->fp, symbol);
 		} else {
-			printf("%p: %p()\n", fp, pc);
+			printf("%p: %p()\n", ctx->fp, ctx->pc);
 		}
-		if (!ops->return_address_get(fp, &pc))
+		if (!ops->return_address_get(ctx, &pc))
 			break;
-		if (!ops->frame_pointer_prev(fp, &fp))
+		if (!ops->frame_pointer_prev(ctx, &fp))
 			break;
+		ctx->fp = fp;
+		ctx->pc = pc;
 	}
 }
@@ -67,5 +74,11 @@
 void stack_trace(void)
 {
-	stack_trace_fp_pc(&kst_ops, frame_pointer_get(), program_counter_get());
+	stack_trace_context_t ctx = {
+		.fp = frame_pointer_get(),
+		.pc = program_counter_get(),
+		.istate = NULL
+	};
+
+	stack_trace_ctx(&kst_ops, &ctx);
 
 	/*
@@ -78,13 +91,18 @@
 void stack_trace_istate(istate_t *istate)
 {
+	stack_trace_context_t ctx = {
+		.fp = istate_get_fp(istate),
+		.pc = istate_get_pc(istate),
+		.istate = istate
+	};
+	
 	if (istate_from_uspace(istate))
-		stack_trace_fp_pc(&ust_ops, istate_get_fp(istate),
-		    istate_get_pc(istate));
+		stack_trace_ctx(&ust_ops, &ctx);
 	else
-		stack_trace_fp_pc(&kst_ops, istate_get_fp(istate),
-		    istate_get_pc(istate));
+		stack_trace_ctx(&kst_ops, &ctx);
 }
 
-static bool kernel_symbol_resolve(uintptr_t addr, const char **sp, uintptr_t *op)
+static bool
+kernel_symbol_resolve(uintptr_t addr, const char **sp, uintptr_t *op)
 {
 	return (symtab_name_lookup(addr, sp, op) == 0);
@@ -92,5 +110,5 @@
 
 stack_trace_ops_t kst_ops = {
-	.frame_pointer_validate = kernel_frame_pointer_validate,
+	.stack_trace_context_validate = kernel_stack_trace_context_validate,
 	.frame_pointer_prev = kernel_frame_pointer_prev,
 	.return_address_get = kernel_return_address_get,
@@ -99,5 +117,5 @@
 
 stack_trace_ops_t ust_ops = {
-	.frame_pointer_validate = uspace_frame_pointer_validate,
+	.stack_trace_context_validate = uspace_stack_trace_context_validate,
 	.frame_pointer_prev = uspace_frame_pointer_prev,
 	.return_address_get = uspace_return_address_get,
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/generic/src/main/main.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -147,5 +147,5 @@
 	size_t i;
 	for (i = 0; i < init.cnt; i++) {
-		if (PA_overlaps(config.stack_base, config.stack_size,
+		if (PA_OVERLAPS(config.stack_base, config.stack_size,
 		    init.tasks[i].addr, init.tasks[i].size))
 			config.stack_base = ALIGN_UP(init.tasks[i].addr +
@@ -155,5 +155,5 @@
 	/* Avoid placing stack on top of boot allocations. */
 	if (ballocs.size) {
-		if (PA_overlaps(config.stack_base, config.stack_size,
+		if (PA_OVERLAPS(config.stack_base, config.stack_size,
 		    ballocs.base, ballocs.size))
 			config.stack_base = ALIGN_UP(ballocs.base +
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ kernel/generic/src/mm/frame.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -121,5 +121,6 @@
  *
  */
-NO_TRACE static size_t zones_insert_zone(pfn_t base, size_t count)
+NO_TRACE static size_t zones_insert_zone(pfn_t base, size_t count,
+    zone_flags_t flags)
 {
 	if (zones.count + 1 == ZONES_MAX) {
@@ -131,10 +132,23 @@
 	for (i = 0; i < zones.count; i++) {
 		/* Check for overlap */
-		if (overlaps(base, count,
-		    zones.info[i].base, zones.info[i].count)) {
-			printf("Zone (%p, %p) overlaps with zone (%p, %p)!\n",
-			    PFN2ADDR(base), PFN2ADDR(base + count),
-			    PFN2ADDR(zones.info[i].base),
-			    PFN2ADDR(zones.info[i].base + zones.info[i].count));
+		if (overlaps(zones.info[i].base, zones.info[i].count,
+		    base, count)) {
+			
+			/*
+			 * If the overlaping zones are of the same type
+			 * and the new zone is completely within the previous
+			 * one, then quietly ignore the new zone.
+			 *
+			 */
+			
+			if ((zones.info[i].flags != flags) ||
+			    (!iswithin(zones.info[i].base, zones.info[i].count,
+			    base, count))) {
+				printf("Zone (%p, %p) overlaps with previous zone (%p, %p)!\n",
+				    PFN2ADDR(base), PFN2ADDR(count),
+				    PFN2ADDR(zones.info[i].base),
+				    PFN2ADDR(zones.info[i].count));
+			}
+			
 			return (size_t) -1;
 		}
@@ -147,6 +161,7 @@
 	for (j = zones.count; j > i; j--) {
 		zones.info[j] = zones.info[j - 1];
-		zones.info[j].buddy_system->data =
-		    (void *) &zones.info[j - 1];
+		if (zones.info[j].buddy_system != NULL)
+			zones.info[j].buddy_system->data =
+			    (void *) &zones.info[j];
 	}
 	
@@ -748,6 +763,7 @@
 	for (i = z2 + 1; i < zones.count; i++) {
 		zones.info[i - 1] = zones.info[i];
-		zones.info[i - 1].buddy_system->data =
-		    (void *) &zones.info[i - 1];
+		if (zones.info[i - 1].buddy_system != NULL)
+			zones.info[i - 1].buddy_system->data =
+			    (void *) &zones.info[i - 1];
 	}
 	
@@ -898,5 +914,5 @@
 		}
 		
-		size_t znum = zones_insert_zone(start, count);
+		size_t znum = zones_insert_zone(start, count, flags);
 		if (znum == (size_t) -1) {
 			irq_spinlock_unlock(&zones.lock, true);
@@ -921,5 +937,5 @@
 	
 	/* Non-available zone */
-	size_t znum = zones_insert_zone(start, count);
+	size_t znum = zones_insert_zone(start, count, flags);
 	if (znum == (size_t) -1) {
 		irq_spinlock_unlock(&zones.lock, true);
Index: tools/mkfat.py
===================================================================
--- tools/mkfat.py	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ tools/mkfat.py	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -343,12 +343,18 @@
 def usage(prname):
 	"Print usage syntax"
-	print prname + " <PATH> <IMAGE>"
+	print prname + " <EXTRA_BYTES> <PATH> <IMAGE>"
 
 def main():
-	if (len(sys.argv) < 3):
+	if (len(sys.argv) < 4):
 		usage(sys.argv[0])
 		return
 	
-	path = os.path.abspath(sys.argv[1])
+	if (not sys.argv[1].isdigit()):
+		print "<EXTRA_BYTES> must be a number"
+		return
+	
+	extra_bytes = int(sys.argv[1])
+	
+	path = os.path.abspath(sys.argv[2])
 	if (not os.path.isdir(path)):
 		print "<PATH> must be a directory"
@@ -365,9 +371,9 @@
 	
 	# Make sure the filesystem is large enought for FAT16
-	size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
+	size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size + extra_bytes
 	while (size / cluster_size < fat16_clusters):
 		if (cluster_size > sector_size):
 			cluster_size /= 2
-			size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
+			size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size + extra_bytes
 		else:
 			size = fat16_clusters * cluster_size + reserved_clusters * cluster_size
@@ -381,5 +387,5 @@
 	data_start = root_start + root_size
 	
-	outf = file(sys.argv[2], "w")
+	outf = file(sys.argv[3], "w")
 	
 	boot_sector = xstruct.create(BOOT_SECTOR)
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/Makefile.common	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -172,5 +172,9 @@
 ifneq ($(BINARY),)
 %.disasm: $(BINARY)
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	$(OBJDUMP) -d -S $< > $@
+else
 	$(OBJDUMP) -d $< > $@
+endif
 
 $(BINARY): $(LINKER_SCRIPT) $(OBJECTS) $(LIBS) $(BASE_LIBS)
Index: uspace/app/klog/klog.c
===================================================================
--- uspace/app/klog/klog.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/app/klog/klog.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -43,11 +43,15 @@
 #include <event.h>
 #include <errno.h>
+#include <str_error.h>
 #include <io/klog.h>
 
-#define NAME  "klog"
+#define NAME       "klog"
+#define LOG_FNAME  "/log/klog"
 
 /* Pointer to klog area */
 static wchar_t *klog;
 static size_t klog_length;
+
+static FILE *log;
 
 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
@@ -58,6 +62,17 @@
 	size_t i;
 	
-	for (i = klog_len - klog_stored; i < klog_len; i++)
-		putchar(klog[(klog_start + i) % klog_length]);
+	for (i = klog_len - klog_stored; i < klog_len; i++) {
+		wchar_t ch = klog[(klog_start + i) % klog_length];
+		
+		putchar(ch);
+		
+		if (log != NULL)
+			fputc(ch, log);
+	}
+	
+	if (log != NULL) {
+		fflush(log);
+		fsync(fileno(log));
+	}
 }
 
@@ -91,4 +106,14 @@
 	}
 	
+	/*
+	 * Mode "a" would be definitively much better here, but it is
+	 * not well supported by the FAT driver.
+	 *
+	 */
+	log = fopen(LOG_FNAME, "w");
+	if (log == NULL)
+		printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
+		    str_error(errno));
+	
 	async_set_interrupt_received(interrupt_received);
 	klog_update();
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/lib/c/generic/io/io.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -757,4 +757,14 @@
 }
 
+int fileno(FILE *stream)
+{
+	if (stream->klog) {
+		errno = EBADF;
+		return -1;
+	}
+	
+	return stream->fd;
+}
+
 int fphone(FILE *stream)
 {
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/lib/c/include/stdio.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -171,4 +171,5 @@
 extern off64_t ftell(FILE *);
 extern int feof(FILE *);
+extern int fileno(FILE *);
 
 extern int fflush(FILE *);
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/srv/fs/fat/fat.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -48,4 +48,17 @@
 
 #define min(a, b)		((a) < (b) ? (a) : (b))
+
+/*
+ * Convenience macros for accessing some frequently used boot sector members.
+ */
+#define BPS(bs)		uint16_t_le2host((bs)->bps)
+#define SPC(bs)		(bs)->spc
+#define RSCNT(bs)	uint16_t_le2host((bs)->rscnt)
+#define FATCNT(bs)	(bs)->fatcnt
+#define SF(bs)		uint16_t_le2host((bs)->sec_per_fat)
+#define RDE(bs)		uint16_t_le2host((bs)->root_ent_max)
+#define TS(bs)		(uint16_t_le2host((bs)->totsec16) != 0 ? \
+			uint16_t_le2host((bs)->totsec16) : \
+			uint32_t_le2host(bs->totsec32))
 
 #define BS_BLOCK		0
@@ -198,4 +211,16 @@
 	unsigned		refcnt;
 	bool			dirty;
+
+	/*
+	 * Cache of the node's last and "current" cluster to avoid some
+	 * unnecessary FAT walks.
+	 */
+	/* Node's last cluster in FAT. */
+	bool		lastc_cached_valid;
+	fat_cluster_t	lastc_cached_value;
+	/* Node's "current" cluster, i.e. where the last I/O took place. */
+	bool		currc_cached_valid;
+	aoff64_t	currc_cached_bn;
+	fat_cluster_t	currc_cached_value;
 } fat_node_t;
 
Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -49,4 +49,15 @@
 #include <mem.h>
 
+/*
+ * Convenience macros for computing some frequently used values from the
+ * primitive boot sector members.
+ */
+#define RDS(bs)		((sizeof(fat_dentry_t) * RDE((bs))) / BPS((bs))) + \
+			(((sizeof(fat_dentry_t) * RDE((bs))) % BPS((bs))) != 0)
+#define SSA(bs)		(RSCNT((bs)) + FATCNT((bs)) * SF((bs)) + RDS(bs))
+
+#define CLBN2PBN(bs, cl, bn) \
+	(SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
+
 /**
  * The fat_alloc_lock mutex protects all copies of the File Allocation Table
@@ -74,12 +85,7 @@
 {
 	block_t *b;
-	unsigned bps;
-	unsigned rscnt;		/* block address of the first FAT */
 	uint16_t clusters = 0;
 	fat_cluster_t clst = firstc;
 	int rc;
-
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
 
 	if (firstc == FAT_CLST_RES0) {
@@ -99,8 +105,9 @@
 		if (lastc)
 			*lastc = clst;	/* remember the last cluster number */
-		fsec = (clst * sizeof(fat_cluster_t)) / bps;
-		fidx = clst % (bps / sizeof(fat_cluster_t));
+		fsec = (clst * sizeof(fat_cluster_t)) / BPS(bs);
+		fidx = clst % (BPS(bs) / sizeof(fat_cluster_t));
 		/* read FAT1 */
-		rc = block_get(&b, dev_handle, rscnt + fsec, BLOCK_FLAGS_NONE);
+		rc = block_get(&b, dev_handle, RSCNT(bs) + fsec,
+		    BLOCK_FLAGS_NONE);
 		if (rc != EOK)
 			return rc;
@@ -125,7 +132,5 @@
  * @param block		Pointer to a block pointer for storing result.
  * @param bs		Buffer holding the boot sector of the file system.
- * @param dev_handle	Device handle of the file system.
- * @param firstc	First cluster used by the file. Can be zero if the file
- *			is empty.
+ * @param nodep		FAT node.
  * @param bn		Block number.
  * @param flags		Flags passed to libblock.
@@ -134,16 +139,75 @@
  */
 int
+fat_block_get(block_t **block, struct fat_bs *bs, fat_node_t *nodep,
+    aoff64_t bn, int flags)
+{
+	fat_cluster_t firstc = nodep->firstc;
+	fat_cluster_t currc;
+	aoff64_t relbn = bn;
+	int rc;
+
+	if (!nodep->size)
+		return ELIMIT;
+
+	if (nodep->firstc == FAT_CLST_ROOT) 
+		goto fall_through;
+
+	if (((((nodep->size - 1) / BPS(bs)) / SPC(bs)) == bn / SPC(bs)) &&
+	    nodep->lastc_cached_valid) {
+	    	/*
+		 * This is a request to read a block within the last cluster
+		 * when fortunately we have the last cluster number cached.
+		 */
+		return block_get(block, nodep->idx->dev_handle,
+		    CLBN2PBN(bs, nodep->lastc_cached_value, bn), flags);
+	}
+
+	if (nodep->currc_cached_valid && bn >= nodep->currc_cached_bn) {
+		/*
+		 * We can start with the cluster cached by the previous call to
+		 * fat_block_get().
+		 */
+		firstc = nodep->currc_cached_value;
+		relbn -= (nodep->currc_cached_bn / SPC(bs)) * SPC(bs);
+	}
+
+fall_through:
+	rc = _fat_block_get(block, bs, nodep->idx->dev_handle, firstc,
+	    &currc, relbn, flags);
+	if (rc != EOK)
+		return rc;
+	
+	/*
+	 * Update the "current" cluster cache.
+	 */
+	nodep->currc_cached_valid = true;
+	nodep->currc_cached_bn = bn;
+	nodep->currc_cached_value = currc;
+
+	return rc;
+}
+
+/** Read block from file located on a FAT file system.
+ *
+ * @param block		Pointer to a block pointer for storing result.
+ * @param bs		Buffer holding the boot sector of the file system.
+ * @param dev_handle	Device handle of the file system.
+ * @param fcl		First cluster used by the file. Can be zero if the file
+ *			is empty.
+ * @param clp		If not NULL, address where the cluster containing bn
+ *			will be stored.
+ *			stored 
+ * @param bn		Block number.
+ * @param flags		Flags passed to libblock.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
 _fat_block_get(block_t **block, fat_bs_t *bs, dev_handle_t dev_handle,
-    fat_cluster_t firstc, aoff64_t bn, int flags)
-{
-	unsigned bps;
-	unsigned rscnt;		/* block address of the first FAT */
-	unsigned rde;
-	unsigned rds;		/* root directory size */
-	unsigned sf;
-	unsigned ssa;		/* size of the system area */
+    fat_cluster_t fcl, fat_cluster_t *clp, aoff64_t bn, int flags)
+{
 	uint16_t clusters;
 	unsigned max_clusters;
-	fat_cluster_t lastc;
+	fat_cluster_t c;
 	int rc;
 
@@ -151,33 +215,25 @@
 	 * This function can only operate on non-zero length files.
 	 */
-	if (firstc == FAT_CLST_RES0)
+	if (fcl == FAT_CLST_RES0)
 		return ELIMIT;
 
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
-	rde = uint16_t_le2host(bs->root_ent_max);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-
-	rds = (sizeof(fat_dentry_t) * rde) / bps;
-	rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
-	ssa = rscnt + bs->fatcnt * sf + rds;
-
-	if (firstc == FAT_CLST_ROOT) {
+	if (fcl == FAT_CLST_ROOT) {
 		/* root directory special case */
-		assert(bn < rds);
-		rc = block_get(block, dev_handle, rscnt + bs->fatcnt * sf + bn,
-		    flags);
+		assert(bn < RDS(bs));
+		rc = block_get(block, dev_handle,
+		    RSCNT(bs) + FATCNT(bs) * SF(bs) + bn, flags);
 		return rc;
 	}
 
-	max_clusters = bn / bs->spc;
-	rc = fat_cluster_walk(bs, dev_handle, firstc, &lastc, &clusters,
-	    max_clusters);
+	max_clusters = bn / SPC(bs);
+	rc = fat_cluster_walk(bs, dev_handle, fcl, &c, &clusters, max_clusters);
 	if (rc != EOK)
 		return rc;
 	assert(clusters == max_clusters);
 
-	rc = block_get(block, dev_handle,
-	    ssa + (lastc - FAT_CLST_FIRST) * bs->spc + bn % bs->spc, flags);
+	rc = block_get(block, dev_handle, CLBN2PBN(bs, c, bn), flags);
+
+	if (clp)
+		*clp = c;
 
 	return rc;
@@ -198,24 +254,19 @@
 int fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, aoff64_t pos)
 {
-	uint16_t bps;
-	unsigned spc;
 	block_t *b;
 	aoff64_t o, boundary;
 	int rc;
 
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	
-	boundary = ROUND_UP(nodep->size, bps * spc);
+	boundary = ROUND_UP(nodep->size, BPS(bs) * SPC(bs));
 
 	/* zero out already allocated space */
 	for (o = nodep->size; o < pos && o < boundary;
-	    o = ALIGN_DOWN(o + bps, bps)) {
-	    	int flags = (o % bps == 0) ?
+	    o = ALIGN_DOWN(o + BPS(bs), BPS(bs))) {
+	    	int flags = (o % BPS(bs) == 0) ?
 		    BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE;
-		rc = fat_block_get(&b, bs, nodep, o / bps, flags);
-		if (rc != EOK)
-			return rc;
-		memset(b->data + o % bps, 0, bps - o % bps);
+		rc = fat_block_get(&b, bs, nodep, o / BPS(bs), flags);
+		if (rc != EOK)
+			return rc;
+		memset(b->data + o % BPS(bs), 0, BPS(bs) - o % BPS(bs));
 		b->dirty = true;		/* need to sync node */
 		rc = block_put(b);
@@ -228,10 +279,10 @@
 	
 	/* zero out the initial part of the new cluster chain */
-	for (o = boundary; o < pos; o += bps) {
+	for (o = boundary; o < pos; o += BPS(bs)) {
 		rc = _fat_block_get(&b, bs, nodep->idx->dev_handle, mcl,
-		    (o - boundary) / bps, BLOCK_FLAGS_NOREAD);
-		if (rc != EOK)
-			return rc;
-		memset(b->data, 0, min(bps, pos - o));
+		    NULL, (o - boundary) / BPS(bs), BLOCK_FLAGS_NOREAD);
+		if (rc != EOK)
+			return rc;
+		memset(b->data, 0, min(BPS(bs), pos - o));
 		b->dirty = true;		/* need to sync node */
 		rc = block_put(b);
@@ -257,19 +308,13 @@
 {
 	block_t *b;
-	uint16_t bps;
-	uint16_t rscnt;
-	uint16_t sf;
 	fat_cluster_t *cp;
 	int rc;
 
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-
-	rc = block_get(&b, dev_handle, rscnt + sf * fatno +
-	    (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
+	rc = block_get(&b, dev_handle, RSCNT(bs) + SF(bs) * fatno +
+	    (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK)
 		return rc;
-	cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
+	cp = (fat_cluster_t *)b->data +
+	    clst % (BPS(bs) / sizeof(fat_cluster_t));
 	*value = uint16_t_le2host(*cp);
 	rc = block_put(b);
@@ -293,20 +338,14 @@
 {
 	block_t *b;
-	uint16_t bps;
-	uint16_t rscnt;
-	uint16_t sf;
 	fat_cluster_t *cp;
 	int rc;
 
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-
-	assert(fatno < bs->fatcnt);
-	rc = block_get(&b, dev_handle, rscnt + sf * fatno +
-	    (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
+	assert(fatno < FATCNT(bs));
+	rc = block_get(&b, dev_handle, RSCNT(bs) + SF(bs) * fatno +
+	    (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK)
 		return rc;
-	cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
+	cp = (fat_cluster_t *)b->data +
+	    clst % (BPS(bs) / sizeof(fat_cluster_t));
 	*cp = host2uint16_t_le(value);
 	b->dirty = true;		/* need to sync block */
@@ -364,11 +403,4 @@
     fat_cluster_t *mcl, fat_cluster_t *lcl)
 {
-	uint16_t bps;
-	uint16_t rscnt;
-	uint16_t sf;
-	uint32_t ts;
-	unsigned rde;
-	unsigned rds;
-	unsigned ssa;
 	block_t *blk;
 	fat_cluster_t *lifo;	/* stack for storing free cluster numbers */ 
@@ -380,16 +412,4 @@
 	if (!lifo)
 		return ENOMEM;
-	
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-	rde = uint16_t_le2host(bs->root_ent_max);
-	ts = (uint32_t) uint16_t_le2host(bs->totsec16);
-	if (ts == 0)
-		ts = uint32_t_le2host(bs->totsec32);
-
-	rds = (sizeof(fat_dentry_t) * rde) / bps;
-	rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
-	ssa = rscnt + bs->fatcnt * sf + rds;
 	
 	/*
@@ -397,16 +417,20 @@
 	 */
 	fibril_mutex_lock(&fat_alloc_lock);
-	for (b = 0, cl = 0; b < sf; b++) {
-		rc = block_get(&blk, dev_handle, rscnt + b, BLOCK_FLAGS_NONE);
+	for (b = 0, cl = 0; b < SF(bs); b++) {
+		rc = block_get(&blk, dev_handle, RSCNT(bs) + b,
+		    BLOCK_FLAGS_NONE);
 		if (rc != EOK)
 			goto error;
-		for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) {
+		for (c = 0; c < BPS(bs) / sizeof(fat_cluster_t); c++, cl++) {
 			/*
-			 * Check if the cluster is physically there. This check
-			 * becomes necessary when the file system is created
-			 * with fewer total sectors than how many is inferred
-			 * from the size of the file allocation table.
+			 * Check if the entire cluster is physically there.
+			 * This check becomes necessary when the file system is
+			 * created with fewer total sectors than how many is
+			 * inferred from the size of the file allocation table
+			 * or when the last cluster ends beyond the end of the
+			 * device.
 			 */
-			if ((cl >= 2) && ((cl - 2) * bs->spc + ssa >= ts)) {
+			if ((cl >= FAT_CLST_FIRST) &&
+			    CLBN2PBN(bs, cl, SPC(bs) - 1) >= TS(bs)) {
 				rc = block_put(blk);
 				if (rc != EOK)
@@ -511,33 +535,44 @@
  * @param nodep		Node representing the file.
  * @param mcl		First cluster of the cluster chain to append.
+ * @param lcl		Last cluster of the cluster chain to append.
  *
  * @return		EOK on success or a negative error code.
  */
-int fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl)
+int
+fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl,
+    fat_cluster_t lcl)
 {
 	dev_handle_t dev_handle = nodep->idx->dev_handle;
-	fat_cluster_t lcl;
+	fat_cluster_t lastc;
 	uint16_t numc;
 	uint8_t fatno;
 	int rc;
 
-	rc = fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl, &numc,
-	    (uint16_t) -1);
-	if (rc != EOK)
-		return rc;
-
-	if (numc == 0) {
-		/* No clusters allocated to the node yet. */
-		nodep->firstc = mcl;
-		nodep->dirty = true;		/* need to sync node */
-		return EOK;
+	if (nodep->lastc_cached_valid) {
+		lastc = nodep->lastc_cached_value;
+		nodep->lastc_cached_valid = false;
+	} else {
+		rc = fat_cluster_walk(bs, dev_handle, nodep->firstc, &lastc,
+		    &numc, (uint16_t) -1);
+		if (rc != EOK)
+			return rc;
+
+		if (numc == 0) {
+			/* No clusters allocated to the node yet. */
+			nodep->firstc = mcl;
+			nodep->dirty = true;	/* need to sync node */
+			return EOK;
+		}
 	}
 
 	for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
-		rc = fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lcl,
+		rc = fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lastc,
 		    mcl);
 		if (rc != EOK)
 			return rc;
 	}
+
+	nodep->lastc_cached_valid = true;
+	nodep->lastc_cached_value = lcl;
 
 	return EOK;
@@ -548,5 +583,5 @@
  * @param bs		Buffer holding the boot sector of the file system.
  * @param nodep		FAT node where the chopping will take place.
- * @param lastc		Last cluster which will remain in the node. If this
+ * @param lcl		Last cluster which will remain in the node. If this
  *			argument is FAT_CLST_RES0, then all clusters will
  *			be chopped off.
@@ -554,10 +589,17 @@
  * @return		EOK on success or a negative return code.
  */
-int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lastc)
-{
-	int rc;
-
+int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lcl)
+{
+	int rc;
 	dev_handle_t dev_handle = nodep->idx->dev_handle;
-	if (lastc == FAT_CLST_RES0) {
+
+	/*
+	 * Invalidate cached cluster numbers.
+	 */
+	nodep->lastc_cached_valid = false;
+	if (nodep->currc_cached_value != lcl)
+		nodep->currc_cached_valid = false;
+
+	if (lcl == FAT_CLST_RES0) {
 		/* The node will have zero size and no clusters allocated. */
 		rc = fat_free_clusters(bs, dev_handle, nodep->firstc);
@@ -570,5 +612,5 @@
 		unsigned fatno;
 
-		rc = fat_get_cluster(bs, dev_handle, FAT1, lastc, &nextc);
+		rc = fat_get_cluster(bs, dev_handle, FAT1, lcl, &nextc);
 		if (rc != EOK)
 			return rc;
@@ -576,5 +618,5 @@
 		/* Terminate the cluster chain in all copies of FAT. */
 		for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
-			rc = fat_set_cluster(bs, dev_handle, fatno, lastc,
+			rc = fat_set_cluster(bs, dev_handle, fatno, lcl,
 			    FAT_CLST_LAST1);
 			if (rc != EOK)
@@ -588,4 +630,10 @@
 	}
 
+	/*
+	 * Update and re-enable the last cluster cache.
+	 */
+	nodep->lastc_cached_valid = true;
+	nodep->lastc_cached_value = lcl;
+
 	return EOK;
 }
@@ -596,15 +644,12 @@
 	int i;
 	block_t *b;
-	unsigned bps;
-	int rc;
-
-	bps = uint16_t_le2host(bs->bps);
-	
-	for (i = 0; i < bs->spc; i++) {
-		rc = _fat_block_get(&b, bs, dev_handle, c, i,
+	int rc;
+
+	for (i = 0; i < SPC(bs); i++) {
+		rc = _fat_block_get(&b, bs, dev_handle, c, NULL, i,
 		    BLOCK_FLAGS_NOREAD);
 		if (rc != EOK)
 			return rc;
-		memset(b->data, 0, bps);
+		memset(b->data, 0, BPS(bs));
 		b->dirty = true;
 		rc = block_put(b);
Index: uspace/srv/fs/fat/fat_fat.h
===================================================================
--- uspace/srv/fs/fat/fat_fat.h	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/srv/fs/fat/fat_fat.h	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -64,13 +64,11 @@
     fat_cluster_t *, uint16_t *, uint16_t);
 
-#define fat_block_get(b, bs, np, bn, flags) \
-    _fat_block_get((b), (bs), (np)->idx->dev_handle, (np)->firstc, (bn), \
-    (flags))
-
+extern int fat_block_get(block_t **, struct fat_bs *, struct fat_node *,
+    aoff64_t, int);
 extern int _fat_block_get(block_t **, struct fat_bs *, dev_handle_t,
-    fat_cluster_t, aoff64_t, int);
+    fat_cluster_t, fat_cluster_t *, aoff64_t, int);
 
 extern int fat_append_clusters(struct fat_bs *, struct fat_node *,
-    fat_cluster_t);
+    fat_cluster_t, fat_cluster_t);
 extern int fat_chop_clusters(struct fat_bs *, struct fat_node *,
     fat_cluster_t);
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -60,4 +60,7 @@
 #define FS_NODE(node)	((node) ? (node)->bp : NULL)
 
+#define DPS(bs)		(BPS((bs)) / sizeof(fat_dentry_t))
+#define BPC(bs)		(BPS((bs)) * SPC((bs)))
+
 /** Mutex protecting the list of cached free FAT nodes. */
 static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
@@ -101,4 +104,9 @@
 	node->refcnt = 0;
 	node->dirty = false;
+	node->lastc_cached_valid = false;
+	node->lastc_cached_value = FAT_CLST_LAST1;
+	node->currc_cached_valid = false;
+	node->currc_cached_bn = 0;
+	node->currc_cached_value = FAT_CLST_LAST1;
 }
 
@@ -108,6 +116,4 @@
 	fat_bs_t *bs;
 	fat_dentry_t *d;
-	uint16_t bps;
-	unsigned dps;
 	int rc;
 	
@@ -115,14 +121,13 @@
 
 	bs = block_bb_get(node->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
 	
 	/* Read the block that contains the dentry of interest. */
 	rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,
-	    (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
+	    NULL, (node->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
+	    BLOCK_FLAGS_NONE);
 	if (rc != EOK)
 		return rc;
 
-	d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
+	d = ((fat_dentry_t *)b->data) + (node->idx->pdi % DPS(bs));
 
 	d->firstc = host2uint16_t_le(node->firstc);
@@ -266,7 +271,4 @@
 	fat_dentry_t *d;
 	fat_node_t *nodep = NULL;
-	unsigned bps;
-	unsigned spc;
-	unsigned dps;
 	int rc;
 
@@ -298,11 +300,8 @@
 
 	bs = block_bb_get(idxp->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	dps = bps / sizeof(fat_dentry_t);
 
 	/* Read the block that contains the dentry of interest. */
-	rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,
-	    (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
+	rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc, NULL,
+	    (idxp->pdi * sizeof(fat_dentry_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK) {
 		(void) fat_node_put(FS_NODE(nodep));
@@ -310,5 +309,5 @@
 	}
 
-	d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
+	d = ((fat_dentry_t *)b->data) + (idxp->pdi % DPS(bs));
 	if (d->attr & FAT_ATTR_SUBDIR) {
 		/* 
@@ -330,5 +329,5 @@
 			return rc;
 		}
-		nodep->size = bps * spc * clusters;
+		nodep->size = BPS(bs) * SPC(bs) * clusters;
 	} else {
 		nodep->type = FAT_FILE;
@@ -368,6 +367,4 @@
 	char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
 	unsigned i, j;
-	unsigned bps;		/* bytes per sector */
-	unsigned dps;		/* dentries per sector */
 	unsigned blocks;
 	fat_dentry_t *d;
@@ -377,7 +374,5 @@
 	fibril_mutex_lock(&parentp->idx->lock);
 	bs = block_bb_get(parentp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-	blocks = parentp->size / bps;
+	blocks = parentp->size / BPS(bs);
 	for (i = 0; i < blocks; i++) {
 		rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
@@ -386,5 +381,5 @@
 			return rc;
 		}
-		for (j = 0; j < dps; j++) { 
+		for (j = 0; j < DPS(bs); j++) { 
 			d = ((fat_dentry_t *)b->data) + j;
 			switch (fat_classify_dentry(d)) {
@@ -414,5 +409,5 @@
 				fat_idx_t *idx = fat_idx_get_by_pos(
 				    parentp->idx->dev_handle, parentp->firstc,
-				    i * dps + j);
+				    i * DPS(bs) + j);
 				fibril_mutex_unlock(&parentp->idx->lock);
 				if (!idx) {
@@ -513,9 +508,7 @@
 	fat_bs_t *bs;
 	fat_cluster_t mcl, lcl;
-	uint16_t bps;
 	int rc;
 
 	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
 	if (flags & L_DIRECTORY) {
 		/* allocate a cluster */
@@ -546,5 +539,5 @@
 		nodep->type = FAT_DIRECTORY;
 		nodep->firstc = mcl;
-		nodep->size = bps * bs->spc;
+		nodep->size = BPS(bs) * SPC(bs);
 	} else {
 		nodep->type = FAT_FILE;
@@ -609,6 +602,4 @@
 	block_t *b;
 	unsigned i, j;
-	uint16_t bps;
-	unsigned dps;
 	unsigned blocks;
 	fat_cluster_t mcl, lcl;
@@ -640,8 +631,6 @@
 	fibril_mutex_lock(&parentp->idx->lock);
 	bs = block_bb_get(parentp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-
-	blocks = parentp->size / bps;
+
+	blocks = parentp->size / BPS(bs);
 
 	for (i = 0; i < blocks; i++) {
@@ -651,5 +640,5 @@
 			return rc;
 		}
-		for (j = 0; j < dps; j++) {
+		for (j = 0; j < DPS(bs); j++) {
 			d = ((fat_dentry_t *)b->data) + j;
 			switch (fat_classify_dentry(d)) {
@@ -691,5 +680,5 @@
 		return rc;
 	}
-	rc = fat_append_clusters(bs, parentp, mcl);
+	rc = fat_append_clusters(bs, parentp, mcl, lcl);
 	if (rc != EOK) {
 		(void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
@@ -697,5 +686,5 @@
 		return rc;
 	}
-	parentp->size += bps * bs->spc;
+	parentp->size += BPS(bs) * SPC(bs);
 	parentp->dirty = true;		/* need to sync node */
 	rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
@@ -771,5 +760,5 @@
 
 	childp->idx->pfc = parentp->firstc;
-	childp->idx->pdi = i * dps + j;
+	childp->idx->pdi = i * DPS(bs) + j;
 	fibril_mutex_unlock(&childp->idx->lock);
 
@@ -793,5 +782,4 @@
 	fat_bs_t *bs;
 	fat_dentry_t *d;
-	uint16_t bps;
 	block_t *b;
 	bool has_children;
@@ -812,13 +800,12 @@
 	fibril_mutex_lock(&childp->idx->lock);
 	bs = block_bb_get(childp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
 
 	rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
-	    (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
+	    NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
 	    BLOCK_FLAGS_NONE);
 	if (rc != EOK) 
 		goto error;
 	d = (fat_dentry_t *)b->data +
-	    (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
+	    (childp->idx->pdi % (BPS(bs) / sizeof(fat_dentry_t)));
 	/* mark the dentry as not-currently-used */
 	d->name[0] = FAT_DENTRY_ERASED;
@@ -852,6 +839,4 @@
 	fat_bs_t *bs;
 	fat_node_t *nodep = FAT_NODE(fn);
-	unsigned bps;
-	unsigned dps;
 	unsigned blocks;
 	block_t *b;
@@ -866,8 +851,6 @@
 	fibril_mutex_lock(&nodep->idx->lock);
 	bs = block_bb_get(nodep->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-
-	blocks = nodep->size / bps;
+
+	blocks = nodep->size / BPS(bs);
 
 	for (i = 0; i < blocks; i++) {
@@ -879,5 +862,5 @@
 			return rc;
 		}
-		for (j = 0; j < dps; j++) {
+		for (j = 0; j < DPS(bs); j++) {
 			d = ((fat_dentry_t *)b->data) + j;
 			switch (fat_classify_dentry(d)) {
@@ -976,6 +959,4 @@
 	enum cache_mode cmode;
 	fat_bs_t *bs;
-	uint16_t bps;
-	uint16_t rde;
 	
 	/* Accept the mount options */
@@ -1014,9 +995,5 @@
 	bs = block_bb_get(dev_handle);
 	
-	/* Read the number of root directory entries. */
-	bps = uint16_t_le2host(bs->bps);
-	rde = uint16_t_le2host(bs->root_ent_max);
-
-	if (bps != BS_SIZE) {
+	if (BPS(bs) != BS_SIZE) {
 		block_fini(dev_handle);
 		ipc_answer_0(rid, ENOTSUP);
@@ -1025,5 +1002,5 @@
 
 	/* Initialize the block cache */
-	rc = block_cache_init(dev_handle, bps, 0 /* XXX */, cmode);
+	rc = block_cache_init(dev_handle, BPS(bs), 0 /* XXX */, cmode);
 	if (rc != EOK) {
 		block_fini(dev_handle);
@@ -1087,5 +1064,5 @@
 	rootp->refcnt = 1;
 	rootp->lnkcnt = 0;	/* FS root is not linked */
-	rootp->size = rde * sizeof(fat_dentry_t);
+	rootp->size = RDE(bs) * sizeof(fat_dentry_t);
 	rootp->idx = ridxp;
 	ridxp->nodep = rootp;
@@ -1165,5 +1142,4 @@
 	fat_node_t *nodep;
 	fat_bs_t *bs;
-	uint16_t bps;
 	size_t bytes;
 	block_t *b;
@@ -1191,5 +1167,4 @@
 
 	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
 
 	if (nodep->type == FAT_FILE) {
@@ -1204,7 +1179,7 @@
 			(void) async_data_read_finalize(callid, NULL, 0);
 		} else {
-			bytes = min(len, bps - pos % bps);
+			bytes = min(len, BPS(bs) - pos % BPS(bs));
 			bytes = min(bytes, nodep->size - pos);
-			rc = fat_block_get(&b, bs, nodep, pos / bps,
+			rc = fat_block_get(&b, bs, nodep, pos / BPS(bs),
 			    BLOCK_FLAGS_NONE);
 			if (rc != EOK) {
@@ -1214,6 +1189,6 @@
 				return;
 			}
-			(void) async_data_read_finalize(callid, b->data + pos % bps,
-			    bytes);
+			(void) async_data_read_finalize(callid,
+			    b->data + pos % BPS(bs), bytes);
 			rc = block_put(b);
 			if (rc != EOK) {
@@ -1230,6 +1205,6 @@
 
 		assert(nodep->type == FAT_DIRECTORY);
-		assert(nodep->size % bps == 0);
-		assert(bps % sizeof(fat_dentry_t) == 0);
+		assert(nodep->size % BPS(bs) == 0);
+		assert(BPS(bs) % sizeof(fat_dentry_t) == 0);
 
 		/*
@@ -1239,6 +1214,6 @@
 		 * the position pointer accordingly.
 		 */
-		bnum = (pos * sizeof(fat_dentry_t)) / bps;
-		while (bnum < nodep->size / bps) {
+		bnum = (pos * sizeof(fat_dentry_t)) / BPS(bs);
+		while (bnum < nodep->size / BPS(bs)) {
 			aoff64_t o;
 
@@ -1247,6 +1222,6 @@
 			if (rc != EOK)
 				goto err;
-			for (o = pos % (bps / sizeof(fat_dentry_t));
-			    o < bps / sizeof(fat_dentry_t);
+			for (o = pos % (BPS(bs) / sizeof(fat_dentry_t));
+			    o < BPS(bs) / sizeof(fat_dentry_t);
 			    o++, pos++) {
 				d = ((fat_dentry_t *)b->data) + o;
@@ -1306,7 +1281,4 @@
 	size_t bytes, size;
 	block_t *b;
-	uint16_t bps;
-	unsigned spc;
-	unsigned bpc;		/* bytes per cluster */
 	aoff64_t boundary;
 	int flags = BLOCK_FLAGS_NONE;
@@ -1334,7 +1306,4 @@
 
 	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	bpc = bps * spc;
 
 	/*
@@ -1345,9 +1314,9 @@
 	 * value signalizing a smaller number of bytes written. 
 	 */ 
-	bytes = min(len, bps - pos % bps);
-	if (bytes == bps)
+	bytes = min(len, BPS(bs) - pos % BPS(bs));
+	if (bytes == BPS(bs))
 		flags |= BLOCK_FLAGS_NOREAD;
 	
-	boundary = ROUND_UP(nodep->size, bpc);
+	boundary = ROUND_UP(nodep->size, BPC(bs));
 	if (pos < boundary) {
 		/*
@@ -1364,5 +1333,5 @@
 			return;
 		}
-		rc = fat_block_get(&b, bs, nodep, pos / bps, flags);
+		rc = fat_block_get(&b, bs, nodep, pos / BPS(bs), flags);
 		if (rc != EOK) {
 			(void) fat_node_put(fn);
@@ -1371,6 +1340,6 @@
 			return;
 		}
-		(void) async_data_write_finalize(callid, b->data + pos % bps,
-		    bytes);
+		(void) async_data_write_finalize(callid,
+		    b->data + pos % BPS(bs), bytes);
 		b->dirty = true;		/* need to sync block */
 		rc = block_put(b);
@@ -1396,5 +1365,5 @@
 		fat_cluster_t mcl, lcl; 
  
-		nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
+		nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
 		/* create an independent chain of nclsts clusters in all FATs */
 		rc = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
@@ -1415,6 +1384,6 @@
 			return;
 		}
-		rc = _fat_block_get(&b, bs, dev_handle, lcl, (pos / bps) % spc,
-		    flags);
+		rc = _fat_block_get(&b, bs, dev_handle, lcl, NULL,
+		    (pos / BPS(bs)) % SPC(bs), flags);
 		if (rc != EOK) {
 			(void) fat_free_clusters(bs, dev_handle, mcl);
@@ -1424,6 +1393,6 @@
 			return;
 		}
-		(void) async_data_write_finalize(callid, b->data + pos % bps,
-		    bytes);
+		(void) async_data_write_finalize(callid,
+		    b->data + pos % BPS(bs), bytes);
 		b->dirty = true;		/* need to sync block */
 		rc = block_put(b);
@@ -1438,5 +1407,5 @@
 		 * node's cluster chain.
 		 */
-		rc = fat_append_clusters(bs, nodep, mcl);
+		rc = fat_append_clusters(bs, nodep, mcl, lcl);
 		if (rc != EOK) {
 			(void) fat_free_clusters(bs, dev_handle, mcl);
@@ -1462,7 +1431,4 @@
 	fat_node_t *nodep;
 	fat_bs_t *bs;
-	uint16_t bps;
-	uint8_t spc;
-	unsigned bpc;	/* bytes per cluster */
 	int rc;
 
@@ -1479,7 +1445,4 @@
 
 	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	bpc = bps * spc;
 
 	if (nodep->size == size) {
@@ -1491,5 +1454,5 @@
 		 */
 		rc = EINVAL;
-	} else if (ROUND_UP(nodep->size, bpc) == ROUND_UP(size, bpc)) {
+	} else if (ROUND_UP(nodep->size, BPC(bs)) == ROUND_UP(size, BPC(bs))) {
 		/*
 		 * The node will be shrunk, but no clusters will be deallocated.
@@ -1509,5 +1472,5 @@
 			fat_cluster_t lastc;
 			rc = fat_cluster_walk(bs, dev_handle, nodep->firstc,
-			    &lastc, NULL, (size - 1) / bpc);
+			    &lastc, NULL, (size - 1) / BPC(bs));
 			if (rc != EOK)
 				goto out;
@@ -1564,6 +1527,25 @@
 void fat_sync(ipc_callid_t rid, ipc_call_t *request)
 {
-	/* Dummy implementation */
-	ipc_answer_0(rid, EOK);
+	dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
+	fs_node_t *fn;
+	int rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
+	if (!fn) {
+		ipc_answer_0(rid, ENOENT);
+		return;
+	}
+	
+	fat_node_t *nodep = FAT_NODE(fn);
+	
+	nodep->dirty = true;
+	rc = fat_node_sync(nodep);
+	
+	fat_node_put(fn);
+	ipc_answer_0(rid, rc);
 }
 
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 527298a2333d7b6963d6547e3f3c42f0bea1e8af)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 2d0c3a666e5f1f5195ff4c489e3e90fa9cf7e215)
@@ -736,5 +736,8 @@
 void tmpfs_sync(ipc_callid_t rid, ipc_call_t *request)
 {
-	/* Dummy implementation */
+	/*
+	 * TMPFS keeps its data structures always consistent,
+	 * thus the sync operation is a no-op.
+	 */
 	ipc_answer_0(rid, EOK);
 }
