Index: kernel/arch/amd64/include/context.h
===================================================================
--- kernel/arch/amd64/include/context.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/amd64/include/context.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -38,5 +38,6 @@
 #include <typedefs.h>
 
-/* According to ABI the stack MUST be aligned on 
+/*
+ * According to ABI the stack MUST be aligned on
  * 16-byte boundary. If it is not, the va_arg calling will
  * panic sooner or later
Index: kernel/arch/arm32/include/context.h
===================================================================
--- kernel/arch/arm32/include/context.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/arm32/include/context.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup arm32	
+/** @addtogroup arm32
  * @{
  */
Index: kernel/arch/ia64/include/context.h
===================================================================
--- kernel/arch/ia64/include/context.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/ia64/include/context.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup ia64	
+/** @addtogroup ia64
  * @{
  */
@@ -47,14 +47,14 @@
  * One item is put onto the stack to support get_stack_base().
  */
-#define SP_DELTA	(0 + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT))
+#define SP_DELTA  (0 + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT))
 
 /* RSE stack starts at the bottom of memory stack, hence the division by 2. */
-#define context_set(c, _pc, stack, size)								\
-	do {												\
-		(c)->pc = (uintptr_t) _pc;								\
-		(c)->bsp = ((uintptr_t) stack) + ALIGN_UP((size / 2), REGISTER_STACK_ALIGNMENT);	\
-		(c)->ar_pfs &= PFM_MASK; 								\
-		(c)->sp = ((uintptr_t) stack) + ALIGN_UP((size / 2), STACK_ALIGNMENT) - SP_DELTA;	\
-	} while (0);
+#define context_set(c, _pc, stack, size) \
+	do { \
+		(c)->pc = (uintptr_t) _pc; \
+		(c)->bsp = ((uintptr_t) stack) + ALIGN_UP((size / 2), REGISTER_STACK_ALIGNMENT); \
+		(c)->ar_pfs &= PFM_MASK; \
+		(c)->sp = ((uintptr_t) stack) + ALIGN_UP((size / 2), STACK_ALIGNMENT) - SP_DELTA; \
+	} while (0)
 
 /*
Index: kernel/arch/mips32/include/context.h
===================================================================
--- kernel/arch/mips32/include/context.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/mips32/include/context.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -42,5 +42,5 @@
  * Put one item onto the stack to support get_stack_base() and align it up.
  */
-#define SP_DELTA  (0 + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT))
+#define SP_DELTA  (ABI_STACK_FRAME + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT))
 
 #ifndef __ASM__
Index: kernel/arch/mips32/include/stack.h
===================================================================
--- kernel/arch/mips32/include/stack.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/mips32/include/stack.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup mips32	
+/** @addtogroup mips32
  * @{
  */
@@ -36,6 +36,7 @@
 #define KERN_mips32_STACK_H_
 
-#define STACK_ITEM_SIZE		4
-#define STACK_ALIGNMENT		8
+#define STACK_ITEM_SIZE  4
+#define STACK_ALIGNMENT  8
+#define ABI_STACK_FRAME  32
 
 #endif
Index: kernel/arch/mips32/src/start.S
===================================================================
--- kernel/arch/mips32/src/start.S	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/mips32/src/start.S	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -241,5 +241,5 @@
 	/* $a1 contains physical address of bootinfo_t */
 	jal arch_pre_main
-	nop
+	addiu $sp, -ABI_STACK_FRAME
 	
 	j main_bsp
@@ -281,6 +281,8 @@
 	
 	move $a1, $sp
+	move $a0, $k0
 	jal exc_dispatch     /* exc_dispatch(excno, register_space) */
-	move $a0, $k0
+	addiu $sp, -ABI_STACK_FRAME
+	addiu $sp, ABI_STACK_FRAME
 	
 	REGISTERS_LOAD $sp
@@ -323,4 +325,5 @@
 	sw $t0, ISTATE_OFFSET_T0($sp)  /* save the 5th argument on the stack */
 	sw $t1, ISTATE_OFFSET_T1($sp)  /* save the 6th argument on the stack */
+	
 	jal syscall_handler
 	sw $v0, ISTATE_OFFSET_V0($sp)  /* save the syscall number on the stack */
@@ -357,6 +360,8 @@
 	move $sp, $k0
 	
+	move $a0, $sp
 	jal tlb_refill
-	move $a0, $sp 
+	addiu $sp, -ABI_STACK_FRAME
+	addiu $sp, ABI_STACK_FRAME
 	
 	REGISTERS_LOAD $sp
@@ -366,11 +371,13 @@
 cache_error_handler:
 	KERNEL_STACK_TO_K0
-	sub $k0, ISTATE_SOFT_SIZE 
+	sub $k0, ISTATE_SOFT_SIZE
 	REGISTERS_STORE_AND_EXC_RESET $k0
 	sw $sp, ISTATE_OFFSET_SP($k0)
 	move $sp, $k0
 	
+	move $a0, $sp
 	jal cache_error
-	move $a0, $sp
+	addiu $sp, -ABI_STACK_FRAME
+	addiu $sp, ABI_STACK_FRAME
 	
 	REGISTERS_LOAD $sp
Index: kernel/arch/mips64/include/context.h
===================================================================
--- kernel/arch/mips64/include/context.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/mips64/include/context.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -42,5 +42,5 @@
  * Put one item onto the stack to support get_stack_base() and align it up.
  */
-#define SP_DELTA  (0 + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT))
+#define SP_DELTA  (ABI_STACK_FRAME + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT))
 
 #ifndef __ASM__
Index: kernel/arch/mips64/include/stack.h
===================================================================
--- kernel/arch/mips64/include/stack.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/mips64/include/stack.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -38,4 +38,5 @@
 #define STACK_ITEM_SIZE  8
 #define STACK_ALIGNMENT  8
+#define ABI_STACK_FRAME  64
 
 #endif
Index: kernel/arch/mips64/src/start.S
===================================================================
--- kernel/arch/mips64/src/start.S	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/mips64/src/start.S	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -241,5 +241,5 @@
 	/* $a1 contains physical address of bootinfo_t */
 	jal arch_pre_main
-	nop
+	addiu $sp, -ABI_STACK_FRAME
 	
 	j main_bsp
@@ -281,6 +281,8 @@
 	
 	move $a1, $sp
+	move $a0, $k0
 	jal exc_dispatch     /* exc_dispatch(excno, register_space) */
-	move $a0, $k0
+	addiu $sp, -ABI_STACK_FRAME
+	addiu $sp, ABI_STACK_FRAME
 	
 	REGISTERS_LOAD $sp
@@ -323,4 +325,5 @@
 	sw $t0, ISTATE_OFFSET_T0($sp)  /* save the 5th argument on the stack */
 	sw $t1, ISTATE_OFFSET_T1($sp)  /* save the 6th argument on the stack */
+	
 	jal syscall_handler
 	sw $v0, ISTATE_OFFSET_V0($sp)  /* save the syscall number on the stack */
@@ -357,6 +360,8 @@
 	move $sp, $k0
 	
+	move $a0, $sp
 	jal tlb_refill
-	move $a0, $sp 
+	addiu $sp, -ABI_STACK_FRAME
+	addiu $sp, ABI_STACK_FRAME
 	
 	REGISTERS_LOAD $sp
@@ -366,11 +371,13 @@
 cache_error_handler:
 	KERNEL_STACK_TO_K0
-	sub $k0, ISTATE_SOFT_SIZE 
+	sub $k0, ISTATE_SOFT_SIZE
 	REGISTERS_STORE_AND_EXC_RESET $k0
 	sw $sp, ISTATE_OFFSET_SP($k0)
 	move $sp, $k0
 	
+	move $a0, $sp
 	jal cache_error
-	move $a0, $sp
+	addiu $sp, -ABI_STACK_FRAME
+	addiu $sp, ABI_STACK_FRAME
 	
 	REGISTERS_LOAD $sp
Index: kernel/arch/ppc32/src/ppc32.c
===================================================================
--- kernel/arch/ppc32/src/ppc32.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/ppc32/src/ppc32.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -173,4 +173,6 @@
 		ofw_tree_walk_by_device_type("display", display_register, NULL);
 #endif
+		/* Map OFW information into sysinfo */
+		ofw_sysinfo_map();
 		
 		/* Initialize IRQ routing */
Index: kernel/arch/sparc64/include/context.h
===================================================================
--- kernel/arch/sparc64/include/context.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/sparc64/include/context.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup sparc64	
+/** @addtogroup sparc64
  * @{
  */
@@ -40,12 +40,13 @@
 #include <align.h>
 
-#define SP_DELTA	(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE)
+#define SP_DELTA  (STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE)
 
-#define context_set(c, _pc, stack, size)			\
-	(c)->pc = ((uintptr_t) _pc) - 8;			\
-	(c)->sp = ((uintptr_t) stack) + ALIGN_UP((size), 	\
-		STACK_ALIGNMENT) - (STACK_BIAS + SP_DELTA);	\
-	(c)->fp = -STACK_BIAS
-	
+#define context_set(c, _pc, stack, size) \
+	do { \
+		(c)->pc = ((uintptr_t) _pc) - 8; \
+		(c)->sp = ((uintptr_t) stack) + ALIGN_UP((size), \
+		    STACK_ALIGNMENT) - (STACK_BIAS + SP_DELTA); \
+		(c)->fp = -STACK_BIAS; \
+	} while (0)
 
 /*
Index: kernel/arch/sparc64/src/sun4u/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sun4u/sparc64.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/sparc64/src/sun4u/sparc64.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -94,4 +94,7 @@
 {
 	if (config.cpu_active == 1) {
+		/* Map OFW information into sysinfo */
+		ofw_sysinfo_map();
+		
 		/*
 		 * We have 2^11 different interrupt vectors.
Index: kernel/arch/sparc64/src/sun4v/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sun4v/sparc64.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/arch/sparc64/src/sun4v/sparc64.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -92,4 +92,7 @@
 {
 	if (config.cpu_active == 1) {
+		/* Map OFW information into sysinfo */
+		ofw_sysinfo_map();
+		
 		/*
 		 * We have 2^11 different interrupt vectors.
Index: kernel/genarch/include/ofw/ofw_tree.h
===================================================================
--- kernel/genarch/include/ofw/ofw_tree.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/genarch/include/ofw/ofw_tree.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -67,5 +67,5 @@
 
 extern void ofw_tree_init(ofw_tree_node_t *);
-extern void ofw_tree_print(void);
+extern void ofw_sysinfo_map(void);
 
 extern const char *ofw_tree_node_name(const ofw_tree_node_t *);
Index: kernel/genarch/src/ofw/ofw_tree.c
===================================================================
--- kernel/genarch/src/ofw/ofw_tree.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/genarch/src/ofw/ofw_tree.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -38,4 +38,5 @@
 #include <genarch/ofw/ofw_tree.h>
 #include <mm/slab.h>
+#include <sysinfo/sysinfo.h>
 #include <memstr.h>
 #include <str.h>
@@ -65,7 +66,5 @@
     const char *name)
 {
-	size_t i;
-	
-	for (i = 0; i < node->properties; i++) {
+	for (size_t i = 0; i < node->properties; i++) {
 		if (str_cmp(node->property[i].name, name) == 0)
 			return &node->property[i];
@@ -104,10 +103,8 @@
     const char *name)
 {
-	ofw_tree_node_t *cur;
-	
 	/*
 	 * Try to find the disambigued name.
 	 */
-	for (cur = node->child; cur; cur = cur->peer) {
+	for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
 		if (str_cmp(cur->da_name, name) == 0)
 			return cur;
@@ -121,5 +118,5 @@
 	 * are not always fully-qualified.
 	 */
-	for (cur = node->child; cur; cur = cur->peer) {
+	for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
 		if (str_cmp(ofw_tree_node_name(cur), name) == 0)
 			return cur;
@@ -141,7 +138,5 @@
     const char *dtype)
 {
-	ofw_tree_node_t *cur;
-	
-	for (cur = node->child; cur; cur = cur->peer) {
+	for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
 		ofw_tree_property_t *prop =
 		    ofw_tree_getprop(cur, "device_type");
@@ -172,13 +167,11 @@
     phandle handle)
 {
-	ofw_tree_node_t *cur;
-	
-	for (cur = root; cur; cur = cur->peer) {
+	for (ofw_tree_node_t *cur = root; cur; cur = cur->peer) {
 		if (cur->node_handle == handle)
 			return cur;
 		
 		if (cur->child) {
-			ofw_tree_node_t *node
-			    = ofw_tree_find_node_by_handle(cur->child, handle);
+			ofw_tree_node_t *node =
+			    ofw_tree_find_node_by_handle(cur->child, handle);
 			if (node)
 				return node;
@@ -201,7 +194,5 @@
     const char *dtype)
 {
-	ofw_tree_node_t *cur;
-	
-	for (cur = node->peer; cur; cur = cur->peer) {
+	for (ofw_tree_node_t *cur = node->peer; cur; cur = cur->peer) {
 		ofw_tree_property_t *prop =
 		    ofw_tree_getprop(cur, "device_type");
@@ -229,9 +220,7 @@
     const char *name)
 {
-	ofw_tree_node_t *cur;
-	
-	for (cur = node->peer; cur; cur = cur->peer) {
-		ofw_tree_property_t *prop
-		    = ofw_tree_getprop(cur, "name");
+	for (ofw_tree_node_t *cur = node->peer; cur; cur = cur->peer) {
+		ofw_tree_property_t *prop =
+		    ofw_tree_getprop(cur, "name");
 		
 		if ((!prop) || (!prop->value))
@@ -259,8 +248,7 @@
 	
 	ofw_tree_node_t *node = ofw_root;
-	size_t i;
 	size_t j;
 	
-	for (i = 1; (i < str_size(path)) && (node); i = j + 1) {
+	for (size_t i = 1; (i < str_size(path)) && (node); i = j + 1) {
 		for (j = i; (j < str_size(path)) && (path[j] != '/'); j++);
 		
@@ -294,7 +282,5 @@
     const char *dtype, ofw_tree_walker_t walker, void *arg)
 {
-	ofw_tree_node_t *cur;
-	
-	for (cur = node; cur; cur = cur->peer) {
+	for (ofw_tree_node_t *cur = node; cur; cur = cur->peer) {
 		ofw_tree_property_t *prop =
 		    ofw_tree_getprop(cur, "device_type");
@@ -334,5 +320,58 @@
 }
 
-/** Print OpenFirmware device subtree rooted in a node.
+/** Get OpenFirmware node properties.
+ *
+ * @param item    Sysinfo item (unused).
+ * @param size    Size of the returned data.
+ * @param dry_run Do not get the data, just calculate the size.
+ * @param data    OpenFirmware node.
+ *
+ * @return Data containing a serialized dump of all node
+ *         properties. If the return value is not NULL, it
+ *         should be freed in the context of the sysinfo request.
+ *
+ */
+static void *ofw_sysinfo_properties(struct sysinfo_item *item, size_t *size,
+    bool dry_run, void *data)
+{
+	ofw_tree_node_t *node = (ofw_tree_node_t *) data;
+	
+	/* Compute serialized data size */
+	*size = 0;
+	for (size_t i = 0; i < node->properties; i++)
+		*size += str_size(node->property[i].name) + 1 +
+		    sizeof(node->property[i].size) + node->property[i].size;
+	
+	if (dry_run)
+		return NULL;
+	
+	void *dump = malloc(*size, FRAME_ATOMIC);
+	if (dump == NULL) {
+		*size = 0;
+		return NULL;
+	}
+	
+	/* Serialize the data */
+	size_t pos = 0;
+	for (size_t i = 0; i < node->properties; i++) {
+		/* Property name */
+		str_cpy(dump + pos, *size - pos, node->property[i].name);
+		pos += str_size(node->property[i].name) + 1;
+		
+		/* Value size */
+		memcpy(dump + pos, &node->property[i].size,
+		    sizeof(node->property[i].size));
+		pos += sizeof(node->property[i].size);
+		
+		/* Value */
+		memcpy(dump + pos, node->property[i].value,
+		    node->property[i].size);
+		pos += node->property[i].size;
+	}
+	
+	return ((void *) dump);
+}
+
+/** Map OpenFirmware device subtree rooted in a node into sysinfo.
  *
  * Child nodes are processed recursively and peer nodes are processed
@@ -343,20 +382,19 @@
  *
  */
-static void ofw_tree_node_print(ofw_tree_node_t *node, const char *path)
+static void ofw_tree_node_sysinfo(ofw_tree_node_t *node, const char *path)
 {
 	char *cur_path = (char *) malloc(PATH_MAX_LEN, 0);
-	ofw_tree_node_t *cur;
-	
-	for (cur = node; cur; cur = cur->peer) {
-		if ((cur->parent) && (path)) {
-			snprintf(cur_path, PATH_MAX_LEN, "%s/%s", path, cur->da_name);
-			printf("%s\n", cur_path);
-		} else {
-			snprintf(cur_path, PATH_MAX_LEN, "%s", cur->da_name);
-			printf("/\n");
-		}
+	
+	for (ofw_tree_node_t *cur = node; cur; cur = cur->peer) {
+		if ((cur->parent) && (path))
+			snprintf(cur_path, PATH_MAX_LEN, "%s.%s", path, cur->da_name);
+		else
+			snprintf(cur_path, PATH_MAX_LEN, "firmware.%s", cur->da_name);
+		
+		sysinfo_set_item_gen_data(cur_path, NULL, ofw_sysinfo_properties,
+		    (void *) cur);
 		
 		if (cur->child)
-			ofw_tree_node_print(cur->child, cur_path);
+			ofw_tree_node_sysinfo(cur->child, cur_path);
 	}
 	
@@ -364,8 +402,8 @@
 }
 
-/** Print the structure of the OpenFirmware device tree. */
-void ofw_tree_print(void)
-{
-	ofw_tree_node_print(ofw_root, NULL);
+/** Map the OpenFirmware device tree into sysinfo. */
+void ofw_sysinfo_map(void)
+{
+	ofw_tree_node_sysinfo(ofw_root, NULL);
 }
 
Index: kernel/generic/include/context.h
===================================================================
--- kernel/generic/include/context.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/generic/include/context.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -41,6 +41,8 @@
 
 #define context_set_generic(ctx, _pc, stack, size) \
-	(ctx)->pc = (uintptr_t) (_pc); \
-	(ctx)->sp = ((uintptr_t) (stack)) + (size) - SP_DELTA;
+	do { \
+		(ctx)->pc = (uintptr_t) (_pc); \
+		(ctx)->sp = ((uintptr_t) (stack)) + (size) - SP_DELTA; \
+	} while (0)
 
 extern int context_save_arch(context_t *ctx) __attribute__((returns_twice));
Index: kernel/generic/include/sysinfo/sysinfo.h
===================================================================
--- kernel/generic/include/sysinfo/sysinfo.h	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/generic/include/sysinfo/sysinfo.h	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2006 Jakub Vana
+ * Copyright (c) 2012 Martin Decky
  * All rights reserved.
  *
@@ -54,9 +55,26 @@
 struct sysinfo_item;
 
-/** Gerated numeric value function */
-typedef sysarg_t (*sysinfo_fn_val_t)(struct sysinfo_item *);
+/** Generated numeric value function */
+typedef sysarg_t (*sysinfo_fn_val_t)(struct sysinfo_item *, void *);
+
+/** Sysinfo generated numberic value data
+ *
+ */
+typedef struct {
+	sysinfo_fn_val_t fn;  /**< Generated value function */
+	void *data;           /**< Private data */
+} sysinfo_gen_val_data_t;
 
 /** Generated binary data function */
-typedef void *(*sysinfo_fn_data_t)(struct sysinfo_item *, size_t *, bool);
+typedef void *(*sysinfo_fn_data_t)(struct sysinfo_item *, size_t *, bool,
+    void *);
+
+/** Sysinfo generated binary data data
+ *
+ */
+typedef struct {
+	sysinfo_fn_data_t fn;  /**< Generated binary data function */
+	void *data;            /**< Private data */
+} sysinfo_gen_data_data_t;
 
 /** Sysinfo item binary data
@@ -72,8 +90,8 @@
  */
 typedef union {
-	sysarg_t val;               /**< Constant numberic value */
-	sysinfo_fn_val_t fn_val;    /**< Generated numeric value function */
-	sysinfo_fn_data_t fn_data;  /**< Generated binary data function */
-	sysinfo_data_t data;        /**< Constant binary data */
+	sysarg_t val;                      /**< Constant numberic value */
+	sysinfo_data_t data;               /**< Constant binary data */
+	sysinfo_gen_val_data_t gen_val;    /**< Generated numeric value function */
+	sysinfo_gen_data_data_t gen_data;  /**< Generated binary data function */
 } sysinfo_item_val_t;
 
@@ -95,5 +113,13 @@
 
 /** Generated subtree function */
-typedef sysinfo_return_t (*sysinfo_fn_subtree_t)(const char *, bool);
+typedef sysinfo_return_t (*sysinfo_fn_subtree_t)(const char *, bool, void *);
+
+/** Sysinfo generated subtree data
+ *
+ */
+typedef struct {
+	sysinfo_fn_subtree_t fn;  /**< Generated subtree function */
+	void *data;               /**< Private data */
+} sysinfo_gen_subtree_data_t;
 
 /** Sysinfo subtree (union)
@@ -101,6 +127,6 @@
  */
 typedef union {
-	struct sysinfo_item *table;     /**< Fixed subtree (list of subitems) */
-	sysinfo_fn_subtree_t get_data;  /**< Generated subtree function */
+	struct sysinfo_item *table;            /**< Fixed subtree (list of subitems) */
+	sysinfo_gen_subtree_data_t generator;  /**< Generated subtree */
 } sysinfo_subtree_t;
 
@@ -123,16 +149,18 @@
 extern void sysinfo_set_item_data(const char *, sysinfo_item_t **, void *,
     size_t);
-extern void sysinfo_set_item_fn_val(const char *, sysinfo_item_t **,
-    sysinfo_fn_val_t);
-extern void sysinfo_set_item_fn_data(const char *, sysinfo_item_t **,
-    sysinfo_fn_data_t);
+extern void sysinfo_set_item_gen_val(const char *, sysinfo_item_t **,
+    sysinfo_fn_val_t, void *);
+extern void sysinfo_set_item_gen_data(const char *, sysinfo_item_t **,
+    sysinfo_fn_data_t, void *);
 extern void sysinfo_set_item_undefined(const char *, sysinfo_item_t **);
 
 extern void sysinfo_set_subtree_fn(const char *, sysinfo_item_t **,
-    sysinfo_fn_subtree_t);
+    sysinfo_fn_subtree_t, void *);
 
 extern void sysinfo_init(void);
 extern void sysinfo_dump(sysinfo_item_t *);
 
+extern sysarg_t sys_sysinfo_get_keys_size(void *, size_t, void *);
+extern sysarg_t sys_sysinfo_get_keys(void *, size_t, void *, size_t, size_t *);
 extern sysarg_t sys_sysinfo_get_val_type(void *, size_t);
 extern sysarg_t sys_sysinfo_get_value(void *, size_t, void *);
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/generic/src/main/main.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -221,5 +221,5 @@
 	frame_init();
 	slab_cache_init();
-	ra_init();	
+	ra_init();
 	sysinfo_init();
 	btree_init();
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/generic/src/mm/frame.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -1270,5 +1270,5 @@
 /** Adjust bounds of physical memory region according to low/high memory split.
  *
- * @param low[in]	If true, the adujstment is performed to make the region
+ * @param low[in]	If true, the adjustment is performed to make the region
  *			fit in the low memory. Otherwise the adjustment is
  *			performed to make the region fit in the high memory.
@@ -1282,8 +1282,5 @@
 bool frame_adjust_zone_bounds(bool low, uintptr_t *basep, size_t *sizep)
 {
-	// FIXME: This might lead to overflow if the identity_size is too big
-	// but it is necessary if the PA identity_base > identity_size
-	const uintptr_t limit =
-	    KA2PA(config.identity_base) + config.identity_size;
+	uintptr_t limit = KA2PA(config.identity_base) + config.identity_size;
 
 	if (low) {
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/generic/src/syscall/syscall.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -184,4 +184,6 @@
 	
 	/* Sysinfo syscalls. */
+	(syshandler_t) sys_sysinfo_get_keys_size,
+	(syshandler_t) sys_sysinfo_get_keys,
 	(syshandler_t) sys_sysinfo_get_val_type,
 	(syshandler_t) sys_sysinfo_get_value,
Index: kernel/generic/src/sysinfo/stats.c
===================================================================
--- kernel/generic/src/sysinfo/stats.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/generic/src/sysinfo/stats.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -83,9 +83,10 @@
  *
  * @param item Sysinfo item (unused).
+ * @param data Unused.
  *
  * @return System uptime (in secords).
  *
  */
-static sysarg_t get_stats_uptime(struct sysinfo_item *item)
+static sysarg_t get_stats_uptime(struct sysinfo_item *item, void *data)
 {
 	/* This doesn't have to be very accurate */
@@ -98,4 +99,5 @@
  * @param size    Size of the returned data.
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Data containing several stats_cpu_t structures.
@@ -104,5 +106,5 @@
  */
 static void *get_stats_cpus(struct sysinfo_item *item, size_t *size,
-    bool dry_run)
+    bool dry_run, void *data)
 {
 	*size = sizeof(stats_cpu_t) * config.cpu_count;
@@ -249,5 +251,5 @@
 	ASSERT(interrupts_disabled());
 	ASSERT(irq_spinlock_locked(&task->lock));
-
+	
 	stats_task->task_id = task->taskid;
 	str_cpy(stats_task->name, TASK_NAME_BUFLEN, task->name);
@@ -293,4 +295,5 @@
  * @param size    Size of the returned data.
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Data containing several stats_task_t structures.
@@ -299,5 +302,5 @@
  */
 static void *get_stats_tasks(struct sysinfo_item *item, size_t *size,
-    bool dry_run)
+    bool dry_run, void *data)
 {
 	/* Messing with task structures, avoid deadlock */
@@ -350,5 +353,5 @@
 	ASSERT(interrupts_disabled());
 	ASSERT(irq_spinlock_locked(&thread->lock));
-
+	
 	stats_thread->thread_id = thread->tid;
 	stats_thread->task_id = thread->task->taskid;
@@ -398,4 +401,5 @@
  * @param size    Size of the returned data.
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Data containing several stats_task_t structures.
@@ -404,5 +408,5 @@
  */
 static void *get_stats_threads(struct sysinfo_item *item, size_t *size,
-    bool dry_run)
+    bool dry_run, void *data)
 {
 	/* Messing with threads structures, avoid deadlock */
@@ -451,4 +455,5 @@
  * @param name    Task ID (string-encoded number).
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Sysinfo return holder. The type of the returned
@@ -460,5 +465,6 @@
  *
  */
-static sysinfo_return_t get_stats_task(const char *name, bool dry_run)
+static sysinfo_return_t get_stats_task(const char *name, bool dry_run,
+    void *data)
 {
 	/* Initially no return value */
@@ -520,4 +526,5 @@
  * @param name    Thread ID (string-encoded number).
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Sysinfo return holder. The type of the returned
@@ -529,5 +536,6 @@
  *
  */
-static sysinfo_return_t get_stats_thread(const char *name, bool dry_run)
+static sysinfo_return_t get_stats_thread(const char *name, bool dry_run,
+    void *data)
 {
 	/* Initially no return value */
@@ -586,4 +594,5 @@
  * @param size    Size of the returned data.
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Data containing several stats_exc_t structures.
@@ -592,5 +601,5 @@
  */
 static void *get_stats_exceptions(struct sysinfo_item *item, size_t *size,
-    bool dry_run)
+    bool dry_run, void *data)
 {
 	*size = sizeof(stats_exc_t) * IVT_ITEMS;
@@ -634,4 +643,5 @@
  * @param name    Exception number (string-encoded number).
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Sysinfo return holder. The type of the returned
@@ -643,5 +653,6 @@
  *
  */
-static sysinfo_return_t get_stats_exception(const char *name, bool dry_run)
+static sysinfo_return_t get_stats_exception(const char *name, bool dry_run,
+    void *data)
 {
 	/* Initially no return value */
@@ -705,4 +716,5 @@
  * @param size    Size of the returned data.
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Data containing stats_physmem_t.
@@ -711,5 +723,5 @@
  */
 static void *get_stats_physmem(struct sysinfo_item *item, size_t *size,
-    bool dry_run)
+    bool dry_run, void *data)
 {
 	*size = sizeof(stats_physmem_t);
@@ -735,4 +747,5 @@
  * @param size    Size of the returned data.
  * @param dry_run Do not get the data, just calculate the size.
+ * @param data    Unused.
  *
  * @return Data several load_t values.
@@ -741,5 +754,5 @@
  */
 static void *get_stats_load(struct sysinfo_item *item, size_t *size,
-    bool dry_run)
+    bool dry_run, void *data)
 {
 	*size = sizeof(load_t) * LOAD_STEPS;
@@ -810,14 +823,14 @@
 	mutex_initialize(&load_lock, MUTEX_PASSIVE);
 	
-	sysinfo_set_item_fn_val("system.uptime", NULL, get_stats_uptime);
-	sysinfo_set_item_fn_data("system.cpus", NULL, get_stats_cpus);
-	sysinfo_set_item_fn_data("system.physmem", NULL, get_stats_physmem);
-	sysinfo_set_item_fn_data("system.load", NULL, get_stats_load);
-	sysinfo_set_item_fn_data("system.tasks", NULL, get_stats_tasks);
-	sysinfo_set_item_fn_data("system.threads", NULL, get_stats_threads);
-	sysinfo_set_item_fn_data("system.exceptions", NULL, get_stats_exceptions);
-	sysinfo_set_subtree_fn("system.tasks", NULL, get_stats_task);
-	sysinfo_set_subtree_fn("system.threads", NULL, get_stats_thread);
-	sysinfo_set_subtree_fn("system.exceptions", NULL, get_stats_exception);
+	sysinfo_set_item_gen_val("system.uptime", NULL, get_stats_uptime, NULL);
+	sysinfo_set_item_gen_data("system.cpus", NULL, get_stats_cpus, NULL);
+	sysinfo_set_item_gen_data("system.physmem", NULL, get_stats_physmem, NULL);
+	sysinfo_set_item_gen_data("system.load", NULL, get_stats_load, NULL);
+	sysinfo_set_item_gen_data("system.tasks", NULL, get_stats_tasks, NULL);
+	sysinfo_set_item_gen_data("system.threads", NULL, get_stats_threads, NULL);
+	sysinfo_set_item_gen_data("system.exceptions", NULL, get_stats_exceptions, NULL);
+	sysinfo_set_subtree_fn("system.tasks", NULL, get_stats_task, NULL);
+	sysinfo_set_subtree_fn("system.threads", NULL, get_stats_thread, NULL);
+	sysinfo_set_subtree_fn("system.exceptions", NULL, get_stats_exception, NULL);
 }
 
Index: kernel/generic/src/sysinfo/sysinfo.c
===================================================================
--- kernel/generic/src/sysinfo/sysinfo.c	(revision 43cd4995323e5ad59552104e19f2a501c05c51d4)
+++ kernel/generic/src/sysinfo/sysinfo.c	(revision bfb3d60871e2c31cc9372922fbe8c58234fb97a4)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2006 Jakub Vana
+ * Copyright (c) 2012 Martin Decky
  * All rights reserved.
  *
@@ -99,5 +100,5 @@
 	    sizeof(sysinfo_item_t), 0, sysinfo_item_constructor,
 	    sysinfo_item_destructor, SLAB_CACHE_MAGDEFERRED);
-
+	
 	mutex_initialize(&sysinfo_lock, MUTEX_ACTIVE);
 }
@@ -110,5 +111,5 @@
  * @param subtree Current sysinfo (sub)tree root item.
  * @param ret     If the return value is NULL, this argument
- *                can be either also NULL (i.e. no item was
+ *                can be set either to NULL (i.e. no item was
  *                found and no data was generated) or the
  *                original pointer is used to store the value
@@ -125,5 +126,4 @@
 {
 	ASSERT(subtree != NULL);
-	ASSERT(ret != NULL);
 	
 	sysinfo_item_t *cur = subtree;
@@ -151,9 +151,14 @@
 			case SYSINFO_SUBTREE_FUNCTION:
 				/* Get generated data */
-				**ret = cur->subtree.get_data(name + i + 1, dry_run);
+				if (ret != NULL)
+					**ret = cur->subtree.generator.fn(name + i + 1,
+					    dry_run, cur->subtree.generator.data);
+				
 				return NULL;
 			default:
 				/* Not found, no data generated */
-				*ret = NULL;
+				if (ret != NULL)
+					*ret = NULL;
+				
 				return NULL;
 			}
@@ -164,5 +169,7 @@
 	
 	/* Not found, no data generated */
-	*ret = NULL;
+	if (ret != NULL)
+		*ret = NULL;
+	
 	return NULL;
 }
@@ -352,8 +359,9 @@
  *             a new root item (NULL for global sysinfo root).
  * @param fn   Numeric value generator function.
- *
- */
-void sysinfo_set_item_fn_val(const char *name, sysinfo_item_t **root,
-    sysinfo_fn_val_t fn)
+ * @param data Private data.
+ *
+ */
+void sysinfo_set_item_gen_val(const char *name, sysinfo_item_t **root,
+    sysinfo_fn_val_t fn, void *data)
 {
 	/* Protect sysinfo tree consistency */
@@ -366,5 +374,6 @@
 	if (item != NULL) {
 		item->val_type = SYSINFO_VAL_FUNCTION_VAL;
-		item->val.fn_val = fn;
+		item->val.gen_val.fn = fn;
+		item->val.gen_val.data = data;
 	}
 	
@@ -383,8 +392,9 @@
  *             a new root item (NULL for global sysinfo root).
  * @param fn   Binary data generator function.
- *
- */
-void sysinfo_set_item_fn_data(const char *name, sysinfo_item_t **root,
-    sysinfo_fn_data_t fn)
+ * @param data Private data.
+ *
+ */
+void sysinfo_set_item_gen_data(const char *name, sysinfo_item_t **root,
+    sysinfo_fn_data_t fn, void *data)
 {
 	/* Protect sysinfo tree consistency */
@@ -397,5 +407,6 @@
 	if (item != NULL) {
 		item->val_type = SYSINFO_VAL_FUNCTION_DATA;
-		item->val.fn_data = fn;
+		item->val.gen_data.fn = fn;
+		item->val.gen_data.data = data;
 	}
 	
@@ -431,8 +442,9 @@
  *             a new root item (NULL for global sysinfo root).
  * @param fn   Subtree generator function.
+ * @param data Private data to be passed to the generator.
  *
  */
 void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
-    sysinfo_fn_subtree_t fn)
+    sysinfo_fn_subtree_t fn, void *data)
 {
 	/* Protect sysinfo tree consistency */
@@ -448,5 +460,6 @@
 	if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
 		item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
-		item->subtree.get_data = fn;
+		item->subtree.generator.fn = fn;
+		item->subtree.generator.data = data;
 	}
 	
@@ -456,12 +469,11 @@
 /** Sysinfo dump indentation helper routine
  *
- * @param depth Number of indentation characters to print.
- *
- */
-NO_TRACE static void sysinfo_indent(unsigned int depth)
-{
-	unsigned int i;
-	for (i = 0; i < depth; i++)
-		printf("  ");
+ * @param depth Number of spaces to print.
+ *
+ */
+NO_TRACE static void sysinfo_indent(size_t spaces)
+{
+	for (size_t i = 0; i < spaces; i++)
+		printf(" ");
 }
 
@@ -470,15 +482,22 @@
  * Should be called with sysinfo_lock held.
  *
- * @param root  Root item of the current (sub)tree.
- * @param depth Current depth in the sysinfo tree.
- *
- */
-NO_TRACE static void sysinfo_dump_internal(sysinfo_item_t *root, unsigned int depth)
-{
-	sysinfo_item_t *cur = root;
-	
+ * @param root   Root item of the current (sub)tree.
+ * @param spaces Current indentation level.
+ *
+ */
+NO_TRACE static void sysinfo_dump_internal(sysinfo_item_t *root, size_t spaces)
+{
 	/* Walk all siblings */
-	while (cur != NULL) {
-		sysinfo_indent(depth);
+	for (sysinfo_item_t *cur = root; cur; cur = cur->next) {
+		size_t length;
+		
+		if (spaces == 0) {
+			printf("%s", cur->name);
+			length = str_length(cur->name);
+		} else {
+			sysinfo_indent(spaces);
+			printf(".%s", cur->name);
+			length = str_length(cur->name) + 1;
+		}
 		
 		sysarg_t val;
@@ -488,24 +507,23 @@
 		switch (cur->val_type) {
 		case SYSINFO_VAL_UNDEFINED:
-			printf("+ %s\n", cur->name);
+			printf(" [undefined]\n");
 			break;
 		case SYSINFO_VAL_VAL:
-			printf("+ %s -> %" PRIun" (%#" PRIxn ")\n", cur->name,
-			    cur->val.val, cur->val.val);
+			printf(" -> %" PRIun" (%#" PRIxn ")\n", cur->val.val,
+			    cur->val.val);
 			break;
 		case SYSINFO_VAL_DATA:
-			printf("+ %s (%zu bytes)\n", cur->name,
-			    cur->val.data.size);
+			printf(" (%zu bytes)\n", cur->val.data.size);
 			break;
 		case SYSINFO_VAL_FUNCTION_VAL:
-			val = cur->val.fn_val(cur);
-			printf("+ %s -> %" PRIun" (%#" PRIxn ") [generated]\n",
-			    cur->name, val, val);
+			val = cur->val.gen_val.fn(cur, cur->val.gen_val.data);
+			printf(" -> %" PRIun" (%#" PRIxn ") [generated]\n", val,
+			    val);
 			break;
 		case SYSINFO_VAL_FUNCTION_DATA:
 			/* N.B.: No data was actually returned (only a dry run) */
-			(void) cur->val.fn_data(cur, &size, true);
-			printf("+ %s (%zu bytes) [generated]\n", cur->name,
-			    size);
+			(void) cur->val.gen_data.fn(cur, &size, true,
+			    cur->val.gen_data.data);
+			printf(" (%zu bytes) [generated]\n", size);
 			break;
 		default:
@@ -518,16 +536,14 @@
 			break;
 		case SYSINFO_SUBTREE_TABLE:
-			sysinfo_dump_internal(cur->subtree.table, depth + 1);
+			sysinfo_dump_internal(cur->subtree.table, spaces + length);
 			break;
 		case SYSINFO_SUBTREE_FUNCTION:
-			sysinfo_indent(depth + 1);
-			printf("+ [generated subtree]\n");
+			sysinfo_indent(spaces + length);
+			printf("<generated subtree>\n");
 			break;
 		default:
-			sysinfo_indent(depth + 1);
-			printf("+ [unknown subtree]\n");
+			sysinfo_indent(spaces + length);
+			printf("<unknown subtree>\n");
 		}
-		
-		cur = cur->next;
 	}
 }
@@ -594,9 +610,9 @@
 			break;
 		case SYSINFO_VAL_FUNCTION_VAL:
-			ret.val = item->val.fn_val(item);
+			ret.val = item->val.gen_val.fn(item, item->val.gen_val.data);
 			break;
 		case SYSINFO_VAL_FUNCTION_DATA:
-			ret.data.data = item->val.fn_data(item, &ret.data.size,
-			    dry_run);
+			ret.data.data = item->val.gen_data.fn(item, &ret.data.size,
+			    dry_run, item->val.gen_data.data);
 			break;
 		}
@@ -635,6 +651,6 @@
 	ASSERT(path);
 	
-	if ((copy_from_uspace(path, ptr, size + 1) == 0)
-	    && (path[size] == 0)) {
+	if ((copy_from_uspace(path, ptr, size + 1) == 0) &&
+	    (path[size] == 0)) {
 		/*
 		 * Prevent other functions from messing with sysinfo while we
@@ -645,6 +661,201 @@
 		mutex_unlock(&sysinfo_lock);
 	}
+	
 	free(path);
 	return ret;
+}
+
+/** Return sysinfo keys determined by name
+ *
+ * Should be called with sysinfo_lock held.
+ *
+ * @param name    Sysinfo path.
+ * @param root    Root item of the sysinfo (sub)tree.
+ *                If it is NULL then consider the global
+ *                sysinfo tree.
+ * @param dry_run Do not actually get any generated
+ *                binary data, just calculate the size.
+ *
+ * @return Item value (constant or generated).
+ *
+ */
+NO_TRACE static sysinfo_return_t sysinfo_get_keys(const char *name,
+    sysinfo_item_t **root, bool dry_run)
+{
+	if (root == NULL)
+		root = &global_root;
+	
+	sysinfo_item_t *subtree = NULL;
+	
+	if (name[0] != 0) {
+		/* Try to find the item */
+		sysinfo_item_t *item =
+		    sysinfo_find_item(name, *root, NULL, dry_run);
+		if ((item != NULL) &&
+		    (item->subtree_type == SYSINFO_SUBTREE_TABLE))
+			subtree = item->subtree.table;
+	} else
+		subtree = *root;
+	
+	sysinfo_return_t ret;
+	
+	if (subtree != NULL) {
+		/*
+		 * Calculate the size of subkeys.
+		 */
+		size_t size = 0;
+		for (sysinfo_item_t *cur = subtree; cur; cur = cur->next)
+			size += str_size(cur->name) + 1;
+		
+		if (dry_run) {
+			ret.tag = SYSINFO_VAL_DATA;
+			ret.data.data = NULL;
+			ret.data.size = size;
+		} else {
+			/* Allocate buffer for subkeys */
+			char *names = (char *) malloc(size, FRAME_ATOMIC);
+			if (names == NULL)
+				return ret;
+			
+			size_t pos = 0;
+			for (sysinfo_item_t *cur = subtree; cur; cur = cur->next) {
+				str_cpy(names + pos, size - pos, cur->name);
+				pos += str_size(cur->name) + 1;
+			}
+			
+			/* Correct return value */
+			ret.tag = SYSINFO_VAL_DATA;
+			ret.data.data = (void *) names;
+			ret.data.size = size;
+		}
+	} else {
+		/* No item in the fixed sysinfo tree */
+		ret.tag = SYSINFO_VAL_UNDEFINED;
+	}
+	
+	return ret;
+}
+
+/** Return sysinfo keys determined by name from user space
+ *
+ * The path string passed from the user space has to be properly
+ * null-terminated (the last passed character must be null).
+ *
+ * @param ptr     Sysinfo path in the user address space.
+ * @param size    Size of the path string.
+ * @param dry_run Do not actually get any generated
+ *                binary data, just calculate the size.
+ *
+ */
+NO_TRACE static sysinfo_return_t sysinfo_get_keys_uspace(void *ptr, size_t size,
+    bool dry_run)
+{
+	sysinfo_return_t ret;
+	ret.tag = SYSINFO_VAL_UNDEFINED;
+	
+	if (size > SYSINFO_MAX_PATH)
+		return ret;
+	
+	char *path = (char *) malloc(size + 1, 0);
+	ASSERT(path);
+	
+	if ((copy_from_uspace(path, ptr, size + 1) == 0) &&
+	    (path[size] == 0)) {
+		/*
+		 * Prevent other functions from messing with sysinfo while we
+		 * are reading it.
+		 */
+		mutex_lock(&sysinfo_lock);
+		ret = sysinfo_get_keys(path, NULL, dry_run);
+		mutex_unlock(&sysinfo_lock);
+	}
+	
+	free(path);
+	return ret;
+}
+
+/** Get the sysinfo keys size (syscall)
+ *
+ * The path string passed from the user space has
+ * to be properly null-terminated (the last passed
+ * character must be null).
+ *
+ * @param path_ptr  Sysinfo path in the user address space.
+ * @param path_size Size of the path string.
+ * @param size_ptr  User space pointer where to store the
+ *                  keys size.
+ *
+ * @return Error code (EOK in case of no error).
+ *
+ */
+sysarg_t sys_sysinfo_get_keys_size(void *path_ptr, size_t path_size,
+    void *size_ptr)
+{
+	int rc;
+	
+	/*
+	 * Get the keys.
+	 *
+	 * N.B.: There is no need to free any potential keys
+	 * since we request a dry run.
+	 */
+	sysinfo_return_t ret =
+	    sysinfo_get_keys_uspace(path_ptr, path_size, true);
+	
+	/* Check return data tag */
+	if (ret.tag == SYSINFO_VAL_DATA)
+		rc = copy_to_uspace(size_ptr, &ret.data.size,
+		    sizeof(ret.data.size));
+	else
+		rc = EINVAL;
+	
+	return (sysarg_t) rc;
+}
+
+/** Get the sysinfo keys (syscall)
+ *
+ * The path string passed from the user space has
+ * to be properly null-terminated (the last passed
+ * character must be null).
+ *
+ * If the user space buffer size does not equal
+ * the actual size of the returned data, the data
+ * is truncated.
+ *
+ * The actual size of data returned is stored to
+ * size_ptr.
+ *
+ * @param path_ptr    Sysinfo path in the user address space.
+ * @param path_size   Size of the path string.
+ * @param buffer_ptr  User space pointer to the buffer where
+ *                    to store the binary data.
+ * @param buffer_size User space buffer size.
+ * @param size_ptr    User space pointer where to store the
+ *                    binary data size.
+ *
+ * @return Error code (EOK in case of no error).
+ *
+ */
+sysarg_t sys_sysinfo_get_keys(void *path_ptr, size_t path_size,
+    void *buffer_ptr, size_t buffer_size, size_t *size_ptr)
+{
+	int rc;
+	
+	/* Get the keys */
+	sysinfo_return_t ret = sysinfo_get_keys_uspace(path_ptr, path_size,
+	    false);
+	
+	/* Check return data tag */
+	if (ret.tag == SYSINFO_VAL_DATA) {
+		size_t size = min(ret.data.size, buffer_size);
+		rc = copy_to_uspace(buffer_ptr, ret.data.data, size);
+		if (rc == EOK)
+			rc = copy_to_uspace(size_ptr, &size, sizeof(size));
+		
+		free(ret.data.data);
+	} else
+		rc = EINVAL;
+	
+	return (sysarg_t) rc;
 }
 
@@ -672,6 +883,6 @@
 	
 	/*
-	 * Map generated value types to constant types (user space does not care
-	 * whether the value is constant or generated).
+	 * Map generated value types to constant types (user space does
+	 * not care whether the value is constant or generated).
 	 */
 	if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
@@ -701,10 +912,10 @@
 {
 	int rc;
-
+	
 	/*
 	 * Get the item.
 	 *
-	 * N.B.: There is no need to free any potential generated binary data
-	 * since we request a dry run.
+	 * N.B.: There is no need to free any potential generated binary
+	 * data since we request a dry run.
 	 */
 	sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
@@ -741,6 +952,6 @@
 	 * Get the item.
 	 *
-	 * N.B.: There is no need to free any potential generated binary data
-	 * since we request a dry run.
+	 * N.B.: There is no need to free any potential generated binary
+	 * data since we request a dry run.
 	 */
 	sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
