Index: uspace/lib/c/generic/device/ahci.c
===================================================================
--- uspace/lib/c/generic/device/ahci.c	(revision 30c08260b42b92e158e687ba64c4b4cc6561218e)
+++ uspace/lib/c/generic/device/ahci.c	(revision 30c08260b42b92e158e687ba64c4b4cc6561218e)
@@ -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 30c08260b42b92e158e687ba64c4b4cc6561218e)
@@ -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 30c08260b42b92e158e687ba64c4b4cc6561218e)
@@ -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;
 		}
