Index: kernel/generic/src/ddi/ddi.c
===================================================================
--- kernel/generic/src/ddi/ddi.c	(revision 2cc7f1601bf37a38c6fbe566c6f941f3ffef337e)
+++ kernel/generic/src/ddi/ddi.c	(revision c87562caea0f9d8e04a513ef2ec01d9f1c9077c2)
@@ -166,7 +166,7 @@
 	}
 	
-	if (zones.info[znum].flags & ZONE_FIRMWARE) {
-		/*
-		 * Frames are part of firmware
+	if (zones.info[znum].flags & (ZONE_FIRMWARE | ZONE_RESERVED)) {
+		/*
+		 * Frames are part of firmware or reserved zone
 		 * -> allow mapping for privileged tasks.
 		 */
Index: kernel/generic/src/lib/func.c
===================================================================
--- kernel/generic/src/lib/func.c	(revision 2cc7f1601bf37a38c6fbe566c6f941f3ffef337e)
+++ kernel/generic/src/lib/func.c	(revision c87562caea0f9d8e04a513ef2ec01d9f1c9077c2)
@@ -53,5 +53,5 @@
 void halt()
 {
-#ifdef CONFIG_DEBUG
+#if (defined(CONFIG_DEBUG)) && (defined(CONFIG_KCONSOLE))
 	bool rundebugger = false;
 	
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 2cc7f1601bf37a38c6fbe566c6f941f3ffef337e)
+++ kernel/generic/src/main/main.c	(revision c87562caea0f9d8e04a513ef2ec01d9f1c9077c2)
@@ -221,5 +221,5 @@
 	frame_init();
 	slab_cache_init();
-	ra_init();	
+	ra_init();
 	sysinfo_init();
 	btree_init();
@@ -257,5 +257,5 @@
 		for (i = 0; i < init.cnt; i++)
 			LOG("init[%zu].addr=%p, init[%zu].size=%zu",
-			    i, (void *) init.tasks[i].addr, i, init.tasks[i].size);
+			    i, (void *) init.tasks[i].paddr, i, init.tasks[i].size);
 	} else
 		printf("No init binaries found.\n");
Index: kernel/generic/src/mm/page.c
===================================================================
--- kernel/generic/src/mm/page.c	(revision 2cc7f1601bf37a38c6fbe566c6f941f3ffef337e)
+++ kernel/generic/src/mm/page.c	(revision c87562caea0f9d8e04a513ef2ec01d9f1c9077c2)
@@ -168,9 +168,9 @@
 int page_find_mapping(uintptr_t virt, void **phys)
 {
-	mutex_lock(&AS->lock);
+	page_table_lock(AS, true);
 	
 	pte_t *pte = page_mapping_find(AS, virt, false);
 	if ((!PTE_VALID(pte)) || (!PTE_PRESENT(pte))) {
-		mutex_unlock(&AS->lock);
+		page_table_unlock(AS, true);
 		return ENOENT;
 	}
@@ -179,5 +179,5 @@
 	    (virt - ALIGN_DOWN(virt, PAGE_SIZE));
 	
-	mutex_unlock(&AS->lock);
+	page_table_unlock(AS, true);
 	
 	return EOK;
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 2cc7f1601bf37a38c6fbe566c6f941f3ffef337e)
+++ kernel/generic/src/syscall/syscall.c	(revision c87562caea0f9d8e04a513ef2ec01d9f1c9077c2)
@@ -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 2cc7f1601bf37a38c6fbe566c6f941f3ffef337e)
+++ kernel/generic/src/sysinfo/stats.c	(revision c87562caea0f9d8e04a513ef2ec01d9f1c9077c2)
@@ -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 2cc7f1601bf37a38c6fbe566c6f941f3ffef337e)
+++ kernel/generic/src/sysinfo/sysinfo.c	(revision c87562caea0f9d8e04a513ef2ec01d9f1c9077c2)
@@ -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);
