Index: uspace/lib/c/generic/ddi.c
===================================================================
--- uspace/lib/c/generic/ddi.c	(revision e7267a2a04e93e48e35fdd68fe61f148d4e5094f)
+++ uspace/lib/c/generic/ddi.c	(revision 04cb6957dc283940ca49fb7fa71d84ccfcd446bd)
@@ -34,5 +34,7 @@
 
 #include <assert.h>
+#include <atomic.h>
 #include <unistd.h>
+#include <stdio.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -47,4 +49,5 @@
 #include "private/libc.h"
 
+
 /** Return unique device number.
  *
@@ -120,11 +123,11 @@
  *
  */
-int iospace_enable(task_id_t id, void *ioaddr, unsigned long size)
-{
-	ddi_ioarg_t arg;
-	
-	arg.task_id = id;
-	arg.ioaddr = ioaddr;
-	arg.size = size;
+static int iospace_enable(task_id_t id, void *ioaddr, size_t size)
+{
+	const ddi_ioarg_t arg = {
+		.task_id = id,
+		.ioaddr = ioaddr,
+		.size = size
+	};
 	
 	return __SYSCALL1(SYS_IOSPACE_ENABLE, (sysarg_t) &arg);
@@ -136,5 +139,5 @@
  * @param size     Size of the I/O region.
  * @param virt     Virtual address for application's
- *                 PIO operations.
+ *                 PIO operations. Can be NULL for PMIO.
  *
  * @return EOK on success.
@@ -146,9 +149,14 @@
 #ifdef IO_SPACE_BOUNDARY
 	if (pio_addr < IO_SPACE_BOUNDARY) {
-		*virt = pio_addr;
+		if (virt)
+			*virt = pio_addr;
 		return iospace_enable(task_get_id(), pio_addr, size);
 	}
+#else
+	(void) iospace_enable;
 #endif
-	
+	if (!virt)
+		return EINVAL;
+
 	void *phys_frame =
 	    (void *) ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE);
@@ -166,4 +174,43 @@
 }
 
+void pio_write_8(ioport8_t *reg, uint8_t val)
+{
+	pio_trace_log(reg, val, true);
+	arch_pio_write_8(reg, val);
+}
+
+void pio_write_16(ioport16_t *reg, uint16_t val)
+{
+	pio_trace_log(reg, val, true);
+	arch_pio_write_16(reg, val);
+}
+
+void pio_write_32(ioport32_t *reg, uint32_t val)
+{
+	pio_trace_log(reg, val, true);
+	arch_pio_write_32(reg, val);
+}
+
+uint8_t pio_read_8(const ioport8_t *reg)
+{
+	const uint8_t val = arch_pio_read_8(reg);
+	pio_trace_log(reg, val, false);
+	return val;
+}
+
+uint16_t pio_read_16(const ioport16_t *reg)
+{
+	const uint16_t val = arch_pio_read_16(reg);
+	pio_trace_log(reg, val, false);
+	return val;
+}
+
+uint32_t pio_read_32(const ioport32_t *reg)
+{
+	const uint32_t val = arch_pio_read_32(reg);
+	pio_trace_log(reg, val, false);
+	return val;
+}
+
 /** Register IRQ notification.
  *
Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision e7267a2a04e93e48e35fdd68fe61f148d4e5094f)
+++ uspace/lib/c/generic/malloc.c	(revision 04cb6957dc283940ca49fb7fa71d84ccfcd446bd)
@@ -289,5 +289,5 @@
 	size_t asize = ALIGN_UP(size, PAGE_SIZE);
 	void *astart = as_area_create(AS_AREA_ANY, asize,
-	    AS_AREA_WRITE | AS_AREA_READ);
+	    AS_AREA_WRITE | AS_AREA_READ | AS_AREA_CACHEABLE);
 	if (astart == AS_MAP_FAILED)
 		return false;
Index: uspace/lib/c/generic/pio_trace.c
===================================================================
--- uspace/lib/c/generic/pio_trace.c	(revision 04cb6957dc283940ca49fb7fa71d84ccfcd446bd)
+++ uspace/lib/c/generic/pio_trace.c	(revision 04cb6957dc283940ca49fb7fa71d84ccfcd446bd)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <adt/list.h>
+#include <fibril_synch.h>
+#include <ddi.h>
+#include <str.h>
+
+
+typedef struct {
+	link_t link;
+	volatile void *base;
+	size_t size;
+	void *data;
+	trace_fnc log;
+} region_t;
+
+static inline region_t * region_instance(link_t *l)
+{
+	return list_get_instance(l, region_t, link);
+}
+
+static inline region_t * region_create(volatile void* base, size_t size,
+    trace_fnc log, void* data)
+{
+	region_t *new_reg = malloc(sizeof(region_t));
+	if (new_reg) {
+		link_initialize(&new_reg->link);
+		new_reg->base = base;
+		new_reg->data = data;
+		new_reg->size = size;
+		new_reg->log = log;
+	}
+	return new_reg;
+}
+
+static inline void region_destroy(region_t *r)
+{
+	free(r);
+}
+
+typedef struct {
+	list_t list;
+	fibril_rwlock_t guard;
+} pio_regions_t;
+
+static pio_regions_t * get_regions(void)
+{
+	static pio_regions_t regions = {
+		.list = {
+			.head = { &regions.list.head, &regions.list.head },
+		},
+		.guard = FIBRIL_RWLOCK_INITIALIZER(regions.guard),
+	};
+	return &regions;
+}
+
+
+void pio_trace_log(const volatile void *r, uint32_t val, bool write)
+{
+	pio_regions_t *regions = get_regions();
+	fibril_rwlock_read_lock(&regions->guard);
+	list_foreach(regions->list, it) {
+		assert(it);
+		region_t *reg = region_instance(it);
+		assert(reg);
+		if ((r >= reg->base) && (r < reg->base + reg->size)) {
+			if (reg->log)
+				reg->log(r, val, reg->base,
+				    reg->size, reg->data, write);
+			break;
+		}
+	}
+	fibril_rwlock_read_unlock(&regions->guard);
+}
+
+int pio_trace_enable(void *base, size_t size, trace_fnc log, void *data)
+{
+	pio_regions_t *regions = get_regions();
+	assert(regions);
+
+	region_t *region = region_create(base, size, log, data);
+	if (!region)
+		return ENOMEM;
+
+	fibril_rwlock_write_lock(&regions->guard);
+	list_append(&region->link, &regions->list);
+	fibril_rwlock_write_unlock(&regions->guard);
+	return EOK;
+}
+
+void pio_trace_disable(void *r)
+{
+	pio_regions_t *regions = get_regions();
+	assert(regions);
+
+	fibril_rwlock_write_lock(&regions->guard);
+	list_foreach_safe(regions->list, it, next) {
+		assert(it);
+		region_t *reg = region_instance(it);
+		assert(reg);
+		if (r >= reg->base && (r < reg->base + reg->size)) {
+				list_remove(&reg->link);
+				region_destroy(reg);
+		}
+	}
+	fibril_rwlock_write_unlock(&regions->guard);
+}
+
+/** @}
+ */
