Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/Makefile	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -71,4 +71,5 @@
 	generic/device/nic.c \
 	generic/device/pci.c \
+	generic/device/ahci.c \
 	generic/elf/elf_load.c \
 	generic/event.c \
Index: uspace/lib/c/arch/abs32le/_link.ld.in
===================================================================
--- uspace/lib/c/arch/abs32le/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/abs32le/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -14,12 +14,16 @@
 SECTIONS {
 #ifdef LOADER
+	. = 0x70001000 + SIZEOF_HEADERS;
+	
 	.interp : {
 		*(.interp);
-	} :interp
-	
-	. = 0x70001000 + SIZEOF_HEADERS;
+	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
+	
+	/* Make sure the code is aligned reasonably */
+	. = ALIGN(., 16);
+	
 	.text : {
 		*(.text .text.*);
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -15,12 +15,16 @@
 SECTIONS {
 #ifdef LOADER
+	. = 0x70001000 + SIZEOF_HEADERS;
+	
 	.interp : {
 		*(.interp);
-	} :interp
-	
-	. = 0x70001000 + SIZEOF_HEADERS;
+	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
+	
+	/* Make sure the code is aligned reasonably */
+	. = ALIGN(., 16);
+	
 	.init : {
 		*(.init);
Index: uspace/lib/c/arch/amd64/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/amd64/include/elf_linux.h	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/amd64/include/elf_linux.h	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -66,4 +66,16 @@
 	uint64_t rsp;
 	uint64_t ss;
+
+	/*
+	 * The following registers need to be part of elf_regs_t.
+	 * Unfortunately, we don't have any information about them in our
+	 * istate_t.
+	 */
+	uint64_t unused_fs_base;
+	uint64_t unused_gs_base;
+	uint64_t unused_ds;
+	uint64_t unused_es;
+	uint64_t unused_fs;
+	uint64_t unused_gs;
 } elf_regs_t;
 
@@ -91,4 +103,14 @@
 	elf_regs->rsp = istate->rsp;
 	elf_regs->ss = istate->ss;
+
+	/*
+	 * Reset the registers for which there is not enough info in istate_t.
+	 */
+	elf_regs->unused_fs_base = 0;
+	elf_regs->unused_gs_base = 0;
+	elf_regs->unused_ds = 0;
+	elf_regs->unused_es = 0;
+	elf_regs->unused_fs = 0;
+	elf_regs->unused_gs = 0;
 }
 
Index: uspace/lib/c/arch/arm32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/arm32/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/arm32/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -14,12 +14,16 @@
 SECTIONS {
 #ifdef LOADER
+	. = 0x70001000 + SIZEOF_HEADERS;
+	
 	.interp : {
 		*(.interp);
-	} :interp
-	
-	. = 0x70001000 + SIZEOF_HEADERS;
+	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
+	
+	/* Make sure the code is aligned reasonably */
+	. = ALIGN(., 8);
+	
 	.init : {
 		*(.init);
Index: uspace/lib/c/arch/arm32/src/fibril.S
===================================================================
--- uspace/lib/c/arch/arm32/src/fibril.S	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/arm32/src/fibril.S	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -35,5 +35,5 @@
 	stmia r0!, {sp, lr}
 	stmia r0!, {r4-r11}
-
+	
 	# return 1
 	mov r0, #1
@@ -43,6 +43,6 @@
 	ldmia r0!, {sp, lr}
 	ldmia r0!, {r4-r11}
-
-	#return 0
+	
+	# return 0
 	mov r0, #0
 	mov pc, lr
Index: uspace/lib/c/arch/arm32/src/stacktrace_asm.S
===================================================================
--- uspace/lib/c/arch/arm32/src/stacktrace_asm.S	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/arm32/src/stacktrace_asm.S	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -41,4 +41,4 @@
 
 stacktrace_pc_get:
-	mov r0, lr 
+	mov r0, lr
 	mov pc, lr
Index: uspace/lib/c/arch/arm32/src/thread_entry.s
===================================================================
--- uspace/lib/c/arch/arm32/src/thread_entry.s	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/arm32/src/thread_entry.s	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -42,4 +42,4 @@
 	push {fp, ip, lr, pc}
 	sub fp, ip, #4
-
-        b __thread_main
+	
+	b __thread_main
Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -19,9 +19,4 @@
 
 SECTIONS {
-#if defined(LOADER) || defined(DLEXE)
-	.interp : {
-		*(.interp);
-	} :interp
-#endif
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
@@ -29,4 +24,14 @@
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
+	
+#if defined(LOADER) || defined(DLEXE)
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
+	
+	/* Make sure the code is aligned reasonably */
+	. = ALIGN(., 16);
+	
 	.init : {
 		*(.init);
@@ -37,5 +42,5 @@
 		*(.rodata .rodata.*);
 	} :text
-
+	
 #if defined(SHLIB) || defined(DLEXE)
 	.rel.plt : {
@@ -80,12 +85,13 @@
 #if defined(SHLIB) || defined(DLEXE)
 	.data.rel : {
-                *(.data.rel .data.rel.*);
+		*(.data.rel .data.rel.*);
 	} :data
-
+	
 	.got : {
-                *(.got);
+		*(.got);
 	} :data
+	
 	.got.plt : {
-                *(.got.plt);
+		*(.got.plt);
 	} :data
 #endif
Index: uspace/lib/c/arch/ia64/Makefile.common
===================================================================
--- uspace/lib/c/arch/ia64/Makefile.common	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/ia64/Makefile.common	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -27,5 +27,15 @@
 #
 
-GCC_CFLAGS += -fno-unwind-tables
+#
+# FIXME:
+#
+# The -fno-selective-scheduling and -fno-selective-scheduling2 options
+# should be removed as soon as a bug in GCC concerning unchecked
+# speculative loads is fixed.
+#
+# See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53975 for reference.
+#
+
+GCC_CFLAGS += -fno-unwind-tables -fno-selective-scheduling -fno-selective-scheduling2
 
 ENDIANESS = LE
Index: uspace/lib/c/arch/ia64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia64/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/ia64/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -14,18 +14,16 @@
 SECTIONS {
 #ifdef LOADER
+	. = 0x800000000 + SIZEOF_HEADERS;
+	
 	.interp : {
 		*(.interp);
-	} :interp
-	
-	. = 0x800000000 + SIZEOF_HEADERS;
+	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	/*
-	 * XXX This is just a work around. Problem: .init section does not
-	 * have the proper alignment.
-	 */
+	
+	/* Make sure the code is aligned reasonably */
 	. = ALIGN(., 16);
-
+	
 	.init : {
 		*(.init);
Index: uspace/lib/c/arch/mips32/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips32/Makefile.common	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/mips32/Makefile.common	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -27,5 +27,5 @@
 #
 
-GCC_CFLAGS += -mips3 -mabi=32
+GCC_CFLAGS += -msoft-float -mips3 -mabi=32
 
 ENDIANESS = LE
Index: uspace/lib/c/arch/mips32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/mips32/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -14,12 +14,16 @@
 SECTIONS {
 #ifdef LOADER
+	. = 0x70004000 + SIZEOF_HEADERS;
+	
 	.interp : {
 		*(.interp);
-	} :interp
-	
-	. = 0x70004000 + SIZEOF_HEADERS;
+	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
+	
+	/* Make sure the code is aligned reasonably */
+	. = ALIGN(., 16);
+	
 	.init : {
 		*(.init);
Index: uspace/lib/c/arch/mips32eb/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips32eb/Makefile.common	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/mips32eb/Makefile.common	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -27,5 +27,5 @@
 #
 
-GCC_CFLAGS += -mips3 -mabi=32
+GCC_CFLAGS += -msoft-float -mips3 -mabi=32
 
 ENDIANESS = BE
Index: uspace/lib/c/arch/mips64/Makefile.common
===================================================================
--- uspace/lib/c/arch/mips64/Makefile.common	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/mips64/Makefile.common	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -27,5 +27,5 @@
 #
 
-GCC_CFLAGS += -mips3 -mabi=64
+GCC_CFLAGS += -msoft-float -mips3 -mabi=64
 AFLAGS = -64
 
Index: uspace/lib/c/arch/mips64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips64/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/mips64/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -15,12 +15,16 @@
 SECTIONS {
 #ifdef LOADER
+	. = 0x70004000 + SIZEOF_HEADERS;
+	
 	.interp : {
 		*(.interp);
-	} :interp
-	
-	. = 0x70004000 + SIZEOF_HEADERS;
+	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
+	
+	/* Make sure the code is aligned reasonably */
+	. = ALIGN(., 16);
+	
 	.init : {
 		*(.init);
Index: uspace/lib/c/arch/ppc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ppc32/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/ppc32/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -15,12 +15,16 @@
 SECTIONS {
 #ifdef LOADER
+	. = 0x70001000 + SIZEOF_HEADERS;
+	
 	.interp : {
 		*(.interp);
-	} :interp
-	
-	. = 0x70001000 + SIZEOF_HEADERS;
+	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
+	
+	/* Make sure the code is aligned reasonably */
+	. = ALIGN(., 4);
+	
 	.init : {
 		*(.init);
Index: uspace/lib/c/arch/sparc64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc64/_link.ld.in	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/arch/sparc64/_link.ld.in	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -14,12 +14,16 @@
 SECTIONS {
 #ifdef LOADER
+	. = 0x70004000 + SIZEOF_HEADERS;
+	
 	.interp : {
 		*(.interp);
-	} :interp
-	
-	. = 0x70004000 + SIZEOF_HEADERS;
+	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
+	
+	/* Make sure the code is aligned reasonably */
+	. = ALIGN(., 16);
+	
 	.init : {
 		*(.init);
Index: uspace/lib/c/generic/device/ahci.c
===================================================================
--- uspace/lib/c/generic/device/ahci.c	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
+++ uspace/lib/c/generic/device/ahci.c	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/dev_iface.h>
+#include <assert.h>
+#include <device/ahci.h>
+#include <errno.h>
+#include <async.h>
+#include <ipc/services.h>
+#include <stdio.h>
+#include <as.h>
+
+typedef enum {
+	IPC_M_AHCI_GET_SATA_DEVICE_NAME,
+	IPC_M_AHCI_GET_NUM_BLOCKS,
+	IPC_M_AHCI_GET_BLOCK_SIZE,
+	IPC_M_AHCI_READ_BLOCKS,
+	IPC_M_AHCI_WRITE_BLOCKS,
+} ahci_iface_funcs_t;
+
+#define MAX_NAME_LENGTH  1024
+
+#define LO(ptr) \
+	((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff))
+
+#define HI(ptr) \
+	((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) >> 32))
+
+async_sess_t* ahci_get_sess(devman_handle_t funh, char **name)
+{
+	// FIXME: Use a better way than substring match
+	
+	*name = NULL;
+	
+	char devn[MAX_NAME_LENGTH];
+	int rc = devman_fun_get_name(funh, devn, MAX_NAME_LENGTH);
+	if (rc != EOK)
+		return NULL;
+	
+	size_t devn_size = str_size(devn);
+	
+	if ((devn_size > 5) && (str_lcmp(devn, "ahci_", 5) == 0)) {
+		async_sess_t *sess = devman_device_connect(EXCHANGE_PARALLEL,
+		    funh, IPC_FLAG_BLOCKING);
+		
+		if (sess) {
+			*name = str_dup(devn);
+			return sess;
+		}
+	}
+	
+	return NULL;
+}
+
+int ahci_get_sata_device_name(async_sess_t *sess, size_t sata_dev_name_length,
+    char *sata_dev_name)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	aid_t req = async_send_2(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_GET_SATA_DEVICE_NAME, sata_dev_name_length, NULL);
+	
+	async_data_read_start(exch, sata_dev_name, sata_dev_name_length);
+	
+	sysarg_t rc;
+	async_wait_for(req, &rc);
+	
+	return rc;
+}
+
+int ahci_get_num_blocks(async_sess_t *sess, uint64_t *blocks)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	sysarg_t blocks_hi;
+	sysarg_t blocks_lo;
+	int rc = async_req_1_2(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_GET_NUM_BLOCKS, &blocks_hi, &blocks_lo);
+	
+	async_exchange_end(exch);
+	
+	if (rc == EOK) {
+		*blocks = (((uint64_t) blocks_hi) << 32)
+		    | (((uint64_t) blocks_lo) & 0xffffffff);
+	}
+	
+	return rc;
+}
+
+int ahci_get_block_size(async_sess_t *sess, size_t *blocks_size)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	sysarg_t bs;
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_GET_BLOCK_SIZE, &bs);
+	
+	async_exchange_end(exch);
+	
+	if (rc == EOK)
+		*blocks_size = (size_t) bs;
+	
+	return rc;
+}
+
+int ahci_read_blocks(async_sess_t *sess, uint64_t blocknum, size_t count,
+    void *buf)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	aid_t req;
+	req = async_send_4(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_READ_BLOCKS, HI(blocknum),  LO(blocknum), count, NULL);
+	
+	async_share_out_start(exch, buf, AS_AREA_READ | AS_AREA_WRITE);
+	
+	async_exchange_end(exch);
+	
+	sysarg_t rc;
+	async_wait_for(req, &rc);
+	
+	return rc;
+}
+
+int ahci_write_blocks(async_sess_t *sess, uint64_t blocknum, size_t count,
+    void* buf)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (!exch)
+		return EINVAL;
+	
+	aid_t req = async_send_4(exch, DEV_IFACE_ID(AHCI_DEV_IFACE),
+	    IPC_M_AHCI_WRITE_BLOCKS, HI(blocknum),  LO(blocknum), count, NULL);
+	
+	async_share_out_start(exch, buf, AS_AREA_READ | AS_AREA_WRITE);
+	
+	async_exchange_end(exch);
+	
+	sysarg_t rc;
+	async_wait_for(req, &rc);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/generic/malloc.c	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -109,4 +109,7 @@
 	(((uintptr_t) (area)->end) - sizeof(heap_block_foot_t))
 
+#define AREA_LAST_BLOCK_HEAD(area) \
+	((uintptr_t) BLOCK_HEAD(((heap_block_foot_t *) AREA_LAST_BLOCK_FOOT(area))))
+
 /** Get header in heap block.
  *
@@ -346,8 +349,18 @@
 		return false;
 	
-	/* Add new free block */
-	size_t net_size = (size_t) (end - area->end);
-	if (net_size > 0)
-		block_init(area->end, net_size, true, area);
+	heap_block_head_t *last_head =
+	    (heap_block_head_t *) AREA_LAST_BLOCK_HEAD(area);
+	
+	if (last_head->free) {
+		/* Add the new space to the last block. */
+		size_t net_size = (size_t) (end - area->end) + last_head->size;
+		malloc_assert(net_size > 0);
+		block_init(last_head, net_size, true, area);
+	} else {
+		/* Add new free block */
+		size_t net_size = (size_t) (end - area->end);
+		if (net_size > 0)
+			block_init(area->end, net_size, true, area);
+	}
 	
 	/* Update heap area parameters */
@@ -355,27 +368,4 @@
 	
 	return true;
-}
-
-/** Try to enlarge any of the heap areas
- *
- * Should be called only inside the critical section.
- *
- * @param size Gross size of item to allocate (bytes).
- *
- */
-static bool heap_grow(size_t size)
-{
-	if (size == 0)
-		return true;
-	
-	/* First try to enlarge some existing area */
-	for (heap_area_t *area = first_heap_area; area != NULL;
-	    area = area->next) {
-		if (area_grow(area, size))
-			return true;
-	}
-	
-	/* Eventually try to create a new area */
-	return area_create(AREA_OVERHEAD(size));
 }
 
@@ -661,4 +651,50 @@
 }
 
+/** Try to enlarge any of the heap areas.
+ *
+ * If successful, allocate block of the given size in the area.
+ * Should be called only inside the critical section.
+ *
+ * @param size  Gross size of item to allocate (bytes).
+ * @param align Memory address alignment.
+ *
+ * @return Allocated block.
+ * @return NULL on failure.
+ *
+ */
+static void *heap_grow_and_alloc(size_t size, size_t align)
+{
+	if (size == 0)
+		return NULL;
+	
+	/* First try to enlarge some existing area */
+	for (heap_area_t *area = first_heap_area; area != NULL;
+	    area = area->next) {
+		
+		if (area_grow(area, size + align)) {
+			heap_block_head_t *first =
+			    (heap_block_head_t *) AREA_LAST_BLOCK_HEAD(area);
+			
+			void *addr =
+			    malloc_area(area, first, NULL, size, align);
+			malloc_assert(addr != NULL);
+			return addr;
+		}
+	}
+	
+	/* Eventually try to create a new area */
+	if (area_create(AREA_OVERHEAD(size + align))) {
+		heap_block_head_t *first =
+		    (heap_block_head_t *) AREA_FIRST_BLOCK_HEAD(last_heap_area);
+		
+		void *addr =
+		    malloc_area(last_heap_area, first, NULL, size, align);
+		malloc_assert(addr != NULL);
+		return addr;
+	}
+	
+	return NULL;
+}
+
 /** Allocate a memory block
  *
@@ -679,16 +715,22 @@
 	
 	size_t falign = lcm(align, BASE_ALIGN);
-	size_t real_size = GROSS_SIZE(ALIGN_UP(size, falign));
-	
-	bool retry = false;
-	heap_block_head_t *split;
-	
-loop:
+	
+	/* Check for integer overflow. */
+	if (falign < align)
+		return NULL;
+	
+	/*
+	 * The size of the allocated block needs to be naturally
+	 * aligned, because the footer structure also needs to reside
+	 * on a naturally aligned address in order to avoid unaligned
+	 * memory accesses.
+	 */
+	size_t gross_size = GROSS_SIZE(ALIGN_UP(size, BASE_ALIGN));
 	
 	/* Try the next fit approach */
-	split = next_fit;
+	heap_block_head_t *split = next_fit;
 	
 	if (split != NULL) {
-		void *addr = malloc_area(split->area, split, NULL, real_size,
+		void *addr = malloc_area(split->area, split, NULL, gross_size,
 		    falign);
 		
@@ -703,5 +745,5 @@
 		    AREA_FIRST_BLOCK_HEAD(area);
 		
-		void *addr = malloc_area(area, first, split, real_size,
+		void *addr = malloc_area(area, first, split, gross_size,
 		    falign);
 		
@@ -710,13 +752,6 @@
 	}
 	
-	if (!retry) {
-		/* Try to grow the heap space */
-		if (heap_grow(real_size)) {
-			retry = true;
-			goto loop;
-		}
-	}
-	
-	return NULL;
+	/* Finally, try to grow heap space and allocate in the new area. */
+	return heap_grow_and_alloc(gross_size, falign);
 }
 
@@ -731,4 +766,6 @@
 void *calloc(const size_t nmemb, const size_t size)
 {
+	// FIXME: Check for overflow
+	
 	void *block = malloc(nmemb * size);
 	if (block == NULL)
@@ -870,5 +907,5 @@
 	if (addr == NULL)
 		return;
-
+	
 	futex_down(&malloc_futex);
 	
Index: uspace/lib/c/generic/str.c
===================================================================
--- uspace/lib/c/generic/str.c	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/generic/str.c	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -428,12 +428,17 @@
  *
  * Do a char-by-char comparison of two NULL-terminated strings.
- * The strings are considered equal iff they consist of the same
- * characters on the minimum of their lengths.
+ * The strings are considered equal iff their length is equal
+ * and both strings consist of the same sequence of characters.
+ *
+ * A string S1 is less than another string S2 if it has a character with
+ * lower value at the first character position where the strings differ.
+ * If the strings differ in length, the shorter one is treated as if
+ * padded by characters with a value of zero.
  *
  * @param s1 First string to compare.
  * @param s2 Second string to compare.
  *
- * @return 0 if the strings are equal, -1 if first is smaller,
- *         1 if second smaller.
+ * @return 0 if the strings are equal, -1 if the first is less than the second,
+ *         1 if the second is less than the first.
  *
  */
@@ -466,6 +471,14 @@
  *
  * Do a char-by-char comparison of two NULL-terminated strings.
- * The strings are considered equal iff they consist of the same
- * characters on the minimum of their lengths and the length limit.
+ * The strings are considered equal iff
+ * min(str_length(s1), max_len) == min(str_length(s2), max_len)
+ * and both strings consist of the same sequence of characters,
+ * up to max_len characters.
+ *
+ * A string S1 is less than another string S2 if it has a character with
+ * lower value at the first character position where the strings differ.
+ * If the strings differ in length, the shorter one is treated as if
+ * padded by characters with a value of zero. Only the first max_len
+ * characters are considered.
  *
  * @param s1      First string to compare.
@@ -473,6 +486,6 @@
  * @param max_len Maximum number of characters to consider.
  *
- * @return 0 if the strings are equal, -1 if first is smaller,
- *         1 if second smaller.
+ * @return 0 if the strings are equal, -1 if the first is less than the second,
+ *         1 if the second is less than the first.
  *
  */
@@ -508,4 +521,40 @@
 	return 0;
 
+}
+
+/** Test whether p is a prefix of s.
+ *
+ * Do a char-by-char comparison of two NULL-terminated strings
+ * and determine if p is a prefix of s.
+ *
+ * @param s The string in which to look
+ * @param p The string to check if it is a prefix of s
+ *
+ * @return true iff p is prefix of s else false
+ *
+ */
+bool str_test_prefix(const char *s, const char *p)
+{
+	wchar_t c1 = 0;
+	wchar_t c2 = 0;
+	
+	size_t off1 = 0;
+	size_t off2 = 0;
+
+	while (true) {
+		c1 = str_decode(s, &off1, STR_NO_LIMIT);
+		c2 = str_decode(p, &off2, STR_NO_LIMIT);
+		
+		if (c2 == 0)
+			return true;
+
+		if (c1 != c2)
+			return false;
+		
+		if (c1 == 0)
+			break;
+	}
+
+	return false;
 }
 
@@ -1085,5 +1134,5 @@
 		c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
 		    (c <= '9' ? c - '0' : 0xff)));
-		if (c > base) {
+		if (c >= base) {
 			break;
 		}
Index: uspace/lib/c/include/device/ahci.h
===================================================================
--- uspace/lib/c/include/device/ahci.h	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
+++ uspace/lib/c/include/device/ahci.h	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 Petr Jerman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ * @brief AHCI interface definition.
+ */
+
+#ifndef LIBC_DEVICE_AHCI_H_
+#define LIBC_DEVICE_AHCI_H_
+
+#include <async.h>
+#include <devman.h>
+
+extern async_sess_t* ahci_get_sess(devman_handle_t, char **);
+
+extern int ahci_get_sata_device_name(async_sess_t *, size_t, char *);
+extern int ahci_get_num_blocks(async_sess_t *, uint64_t *);
+extern int ahci_get_block_size(async_sess_t *, size_t *);
+extern int ahci_read_blocks(async_sess_t *, uint64_t, size_t, void *);
+extern int ahci_write_blocks(async_sess_t *, uint64_t, size_t, void *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -51,4 +51,6 @@
 	/** Interface provided by USB HID devices. */
 	USBHID_DEV_IFACE,
+	/** Interface provided by AHCI devices. */
+	AHCI_DEV_IFACE,
 
 	DEV_IFACE_MAX
Index: uspace/lib/c/include/str.h
===================================================================
--- uspace/lib/c/include/str.h	(revision bc216a07a86e40d74455b7f4d6fb8f65e195443d)
+++ uspace/lib/c/include/str.h	(revision 85d31de9fb7e4a793a91abe63f006b2fd2e81ece)
@@ -79,4 +79,6 @@
 extern int str_lcmp(const char *s1, const char *s2, size_t max_len);
 
+extern bool str_test_prefix(const char *s, const char *p);
+
 extern void str_cpy(char *dest, size_t size, const char *src);
 extern void str_ncpy(char *dest, size_t size, const char *src, size_t n);
