Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/Makefile	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -233,4 +233,5 @@
 	generic/src/main/version.c \
 	generic/src/main/shutdown.c \
+	generic/src/proc/program.c \
 	generic/src/proc/scheduler.c \
 	generic/src/proc/thread.c \
@@ -271,4 +272,5 @@
 	generic/src/synch/mutex.c \
 	generic/src/synch/semaphore.c \
+	generic/src/synch/smc.c \
 	generic/src/synch/waitq.c \
 	generic/src/synch/futex.c \
Index: kernel/arch/amd64/src/userspace.c
===================================================================
--- kernel/arch/amd64/src/userspace.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/amd64/src/userspace.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -62,4 +62,6 @@
 			  "pushq %4\n"
 			  "movq %5, %%rax\n"
+			  /* %rdi is defined to hold pcb_ptr - set it to 0 */
+			  "xorq %%rdi, %%rdi\n"
 			  "iretq\n"
 			  : : 
Index: kernel/arch/arm32/src/userspace.c
===================================================================
--- kernel/arch/arm32/src/userspace.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/arm32/src/userspace.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -71,6 +71,9 @@
 	ustate.r0 = (uintptr_t) kernel_uarg->uspace_uarg;
 
+	/* %r1 is defined to hold pcb_ptr - set it to 0 */
+	ustate.r1 = 0;
+
 	/* clear other registers */
-	ustate.r1 = ustate.r2  = ustate.r3  = ustate.r4  = ustate.r5 =
+	ustate.r2 = ustate.r3  = ustate.r4  = ustate.r5 =
 	    ustate.r6  = ustate.r7  = ustate.r8  = ustate.r9 = ustate.r10 = 
 	    ustate.r11 = ustate.r12 = ustate.lr = 0;
Index: kernel/arch/ia32/src/userspace.c
===================================================================
--- kernel/arch/ia32/src/userspace.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/ia32/src/userspace.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -71,4 +71,8 @@
 		"pushl %4\n"
 		"movl %5, %%eax\n"
+
+		/* %ebx is defined to hold pcb_ptr - set it to 0 */
+		"xorl %%ebx, %%ebx\n"	
+
 		"iret\n"
 		: 
Index: kernel/arch/ia32xen/src/userspace.c
===================================================================
--- kernel/arch/ia32xen/src/userspace.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/ia32xen/src/userspace.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -69,4 +69,8 @@
 		"pushl %4\n"
 		"movl %5, %%eax\n"
+
+		/* %ebx is defined to hold pcb_ptr - set it to 0 */
+		"xorl %%ebx, %%ebx\n"
+
 		"iret\n"
 		: 
Index: kernel/arch/ia64/src/asm.S
===================================================================
--- kernel/arch/ia64/src/asm.S	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/ia64/src/asm.S	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -164,4 +164,7 @@
 	xor r1 = r1, r1
 	
+	/* r2 is defined to hold pcb_ptr - set it to 0 */
+	xor r2 = r2, r2
+	
 	mov loc1 = cr.ifs
 	movl loc2 = PFM_MASK ;;
Index: kernel/arch/mips32/src/start.S
===================================================================
--- kernel/arch/mips32/src/start.S	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/mips32/src/start.S	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -350,4 +350,6 @@
 	add $sp, $a0, 0
 	add $v0, $a1, 0 
-	add $t9, $a2, 0			# Set up correct entry into PIC code 
-	eret
+	add $t9, $a2, 0			# Set up correct entry into PIC code
+	xor $a0, $a0, $a0		# $a0 is defined to hold pcb_ptr
+					# set it to 0
+	eret
Index: kernel/arch/ppc32/src/asm.S
===================================================================
--- kernel/arch/ppc32/src/asm.S	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/ppc32/src/asm.S	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -66,4 +66,8 @@
 	
 	mr sp, r4
+
+	# %r3 is defined to hold pcb_ptr - set it to 0
+
+	xor r3, r3, r3
 	
 	# jump to userspace
Index: kernel/arch/ppc64/src/asm.S
===================================================================
--- kernel/arch/ppc64/src/asm.S	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/ppc64/src/asm.S	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -67,4 +67,8 @@
 	mr sp, r4
 	
+	# %r3 is defined to hold pcb_ptr - set it to 0
+
+	xor r3, r3, r3
+
 	# jump to userspace
 	
Index: kernel/arch/sparc64/src/asm.S
===================================================================
--- kernel/arch/sparc64/src/asm.S	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/arch/sparc64/src/asm.S	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -275,4 +275,6 @@
 
 	mov %i2, %o0			! uarg
+	xor %o1, %o1, %o1		! %o1 is defined to hold pcb_ptr
+					! set it to 0
 
 	clr %i2
Index: kernel/generic/include/lib/elf.h
===================================================================
--- kernel/generic/include/lib/elf.h	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/include/lib/elf.h	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -115,5 +115,6 @@
 #define EE_INCOMPATIBLE		3	/* ELF image is not compatible with current architecture */
 #define EE_UNSUPPORTED		4	/* Non-supported ELF (e.g. dynamic ELFs) */
-#define EE_IRRECOVERABLE	5
+#define EE_LOADER		5	/* The image is actually a program loader */
+#define EE_IRRECOVERABLE	6
 
 /**
@@ -339,4 +340,8 @@
 extern char *elf_error(unsigned int rc);
 
+/* Interpreter string used to recognize the program loader */
+#define ELF_INTERP_ZSTR "kernel"
+#define ELF_INTERP_ZLEN  sizeof(ELF_INTERP_ZSTR)
+
 #endif
 
Index: kernel/generic/include/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/include/mm/as.h	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -270,4 +270,5 @@
 int as_area_share(as_t *src_as, uintptr_t src_base, size_t acc_size,
     as_t *dst_as, uintptr_t dst_base, int dst_flags_mask);
+extern int as_area_change_flags(as_t *as, int flags, uintptr_t address);
 
 extern int as_area_get_flags(as_area_t *area);
@@ -300,9 +301,17 @@
 extern mem_backend_t phys_backend;
 
-extern unsigned int elf_load(elf_header_t *header, as_t *as);
+/** 
+ * This flags is passed when running the loader, otherwise elf_load()
+ * would return with a EE_LOADER error code.
+ */
+#define ELD_F_NONE	0
+#define ELD_F_LOADER	1
+
+extern unsigned int elf_load(elf_header_t *header, as_t *as, int flags);
 
 /* Address space area related syscalls. */
 extern unative_t sys_as_area_create(uintptr_t address, size_t size, int flags);
 extern unative_t sys_as_area_resize(uintptr_t address, size_t size, int flags);
+extern unative_t sys_as_area_change_flags(uintptr_t address, int flags);
 extern unative_t sys_as_area_destroy(uintptr_t address);
 
Index: kernel/generic/include/proc/program.h
===================================================================
--- kernel/generic/include/proc/program.h	(revision f93f1689b424f33048541ffe5740a07867076862)
+++ kernel/generic/include/proc/program.h	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008 Jiri Svoboda
+ * 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 genericproc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_PROGRAM_H_
+#define KERN_PROGRAM_H_
+
+#include <arch/types.h>
+
+struct task;
+struct thread;
+
+/** Program info structure.
+ *
+ * A program is an abstraction of a freshly created (not yet running)
+ * userspace task containing a main thread along with its userspace stack.
+ */
+typedef struct program {
+	struct task *task;		/**< Program task */
+	struct thread *main_thread;	/**< Program main thread */
+} program_t;
+
+extern void *program_loader;
+
+extern void program_create(as_t *as, uintptr_t entry_addr, program_t *p);
+extern int program_create_from_image(void *image_addr, program_t *p);
+extern int program_create_loader(program_t *p);
+extern void program_ready(program_t *p);
+
+extern unative_t sys_program_spawn_loader(int *uspace_phone_id);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/include/proc/task.h	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -133,5 +133,4 @@
 
 extern unative_t sys_task_get_id(task_id_t *uspace_task_id);
-extern unative_t sys_task_spawn(void *image, size_t size);
 
 #endif
Index: kernel/generic/include/proc/thread.h
===================================================================
--- kernel/generic/include/proc/thread.h	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/include/proc/thread.h	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -249,6 +249,4 @@
 extern bool thread_exists(thread_t *t);
 
-extern thread_t *thread_create_program(void *program_addr, char *name);
-
 /** Fpu context slab cache. */
 extern slab_cache_t *fpu_context_slab;
Index: kernel/generic/include/synch/smc.h
===================================================================
--- kernel/generic/include/synch/smc.h	(revision f93f1689b424f33048541ffe5740a07867076862)
+++ kernel/generic/include/synch/smc.h	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2008 Jiri Svoboda
+ * 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 sync
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_SMC_H_
+#define KERN_SMC_H_
+
+extern unative_t sys_smc_coherence(uintptr_t va, size_t size);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/syscall/syscall.h
===================================================================
--- kernel/generic/include/syscall/syscall.h	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/include/syscall/syscall.h	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -45,11 +45,13 @@
 	
 	SYS_TASK_GET_ID,
-	SYS_TASK_SPAWN,
+	SYS_PROGRAM_SPAWN_LOADER,
 	
 	SYS_FUTEX_SLEEP,
 	SYS_FUTEX_WAKEUP,
+	SYS_SMC_COHERENCE,
 	
 	SYS_AS_AREA_CREATE,
 	SYS_AS_AREA_RESIZE,
+	SYS_AS_AREA_CHANGE_FLAGS,
 	SYS_AS_AREA_DESTROY,
 	
Index: kernel/generic/src/lib/elf.c
===================================================================
--- kernel/generic/src/lib/elf.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/src/lib/elf.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -58,5 +58,5 @@
 
 static int segment_header(elf_segment_header_t *entry, elf_header_t *elf,
-    as_t *as);
+    as_t *as, int flags);
 static int section_header(elf_section_header_t *entry, elf_header_t *elf,
     as_t *as);
@@ -68,7 +68,8 @@
  * @param header Pointer to ELF header in memory
  * @param as Created and properly mapped address space
+ * @param flags A combination of ELD_F_*
  * @return EE_OK on success
  */
-unsigned int elf_load(elf_header_t *header, as_t * as)
+unsigned int elf_load(elf_header_t *header, as_t * as, int flags)
 {
 	int i, rc;
@@ -111,5 +112,5 @@
 		seghdr = &((elf_segment_header_t *)(((uint8_t *) header) +
 		    header->e_phoff))[i];
-		rc = segment_header(seghdr, header, as);
+		rc = segment_header(seghdr, header, as, flags);
 		if (rc != EE_OK)
 			return rc;
@@ -152,6 +153,8 @@
  */
 static int segment_header(elf_segment_header_t *entry, elf_header_t *elf,
-    as_t *as)
-{
+    as_t *as, int flags)
+{
+	char *interp;
+
 	switch (entry->p_type) {
 	case PT_NULL:
@@ -163,4 +166,14 @@
 	case PT_DYNAMIC:
 	case PT_INTERP:
+		interp = (char *)elf + entry->p_offset;
+		/* FIXME */
+		/*if (memcmp((uintptr_t)interp, (uintptr_t)ELF_INTERP_ZSTR,
+		    ELF_INTERP_ZLEN) != 0) {
+			return EE_UNSUPPORTED;
+		}*/
+		if ((flags & ELD_F_LOADER) == 0) {
+			return EE_LOADER;
+		}
+		break;
 	case PT_SHLIB:
 	case PT_NOTE:
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/src/main/kinit.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -48,4 +48,5 @@
 #include <proc/task.h>
 #include <proc/thread.h>
+#include <proc/program.h>
 #include <panic.h>
 #include <func.h>
@@ -160,5 +161,5 @@
 	 */
 	count_t i;
-	thread_t *threads[CONFIG_INIT_TASKS];
+	program_t programs[CONFIG_INIT_TASKS];
 	
 	for (i = 0; i < init.cnt; i++) {
@@ -168,17 +169,21 @@
 		}
 
-		threads[i] = thread_create_program((void *) init.tasks[i].addr,
-		    "uspace");
-		
-		if (threads[i] != NULL) {
+		int rc = program_create_from_image((void *) init.tasks[i].addr,
+		    &programs[i]);
+
+		if (rc == 0 && programs[i].task != NULL) {
 			/*
 			 * Set capabilities to init userspace tasks.
 			 */
-			cap_set(threads[i]->task, CAP_CAP | CAP_MEM_MANAGER |
+			cap_set(programs[i].task, CAP_CAP | CAP_MEM_MANAGER |
 			    CAP_IO_MANAGER | CAP_PREEMPT_CONTROL | CAP_IRQ_REG);
+
 			
 			if (!ipc_phone_0)
-				ipc_phone_0 = &threads[i]->task->answerbox;
+				ipc_phone_0 = &programs[i].task->answerbox;
+		} else if (rc == 0) {
+			/* It was the program loader and was registered */
 		} else {
+			/* RAM disk image */
 			int rd = init_rd((rd_header_t *) init.tasks[i].addr,
 			    init.tasks[i].size);
@@ -194,7 +199,7 @@
 	 */
 	for (i = 0; i < init.cnt; i++) {
-		if (threads[i] != NULL) {
+		if (programs[i].task != NULL) {
 			thread_usleep(50000);
-			thread_ready(threads[i]);
+			program_ready(&programs[i]);
 		}
 	}
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/src/mm/as.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -772,4 +772,158 @@
 }
 
+/** Change adress area flags.
+ *
+ * The idea is to have the same data, but with a different access mode.
+ * This is needed e.g. for writing code into memory and then executing it.
+ * In order for this to work properly, this may copy the data
+ * into private anonymous memory (unless it's already there).
+ *
+ * @param as Address space.
+ * @param flags Flags of the area memory.
+ * @param address Address withing the area to be changed.
+ *
+ * @return Zero on success or a value from @ref errno.h on failure. 
+ */
+int as_area_change_flags(as_t *as, int flags, uintptr_t address)
+{
+	as_area_t *area;
+	uintptr_t base;
+	link_t *cur;
+	ipl_t ipl;
+	int page_flags;
+	uintptr_t *old_frame;
+	index_t frame_idx;
+	count_t used_pages;
+
+	/* Flags for the new memory mapping */
+	page_flags = area_flags_to_page_flags(flags);
+
+	ipl = interrupts_disable();
+	mutex_lock(&as->lock);
+
+	area = find_area_and_lock(as, address);
+	if (!area) {
+		mutex_unlock(&as->lock);
+		interrupts_restore(ipl);
+		return ENOENT;
+	}
+
+	if (area->sh_info || area->backend != &anon_backend) {
+		/* Copying shared areas not supported yet */
+		/* Copying non-anonymous memory not supported yet */
+		mutex_unlock(&area->lock);
+		mutex_unlock(&as->lock);
+		interrupts_restore(ipl);
+		return ENOTSUP;
+	}
+
+	base = area->base;
+
+	/*
+	 * Compute total number of used pages in the used_space B+tree
+	 */
+	used_pages = 0;
+
+	for (cur = area->used_space.leaf_head.next;
+	    cur != &area->used_space.leaf_head; cur = cur->next) {
+		btree_node_t *node;
+		unsigned int i;
+		
+		node = list_get_instance(cur, btree_node_t, leaf_link);
+		for (i = 0; i < node->keys; i++) {
+			used_pages += (count_t) node->value[i];
+		}
+	}
+
+	/* An array for storing frame numbers */
+	old_frame = malloc(used_pages * sizeof(uintptr_t), 0);
+
+	/*
+	 * Start TLB shootdown sequence.
+	 */
+	tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, area->pages);
+
+	/*
+	 * Remove used pages from page tables and remember their frame
+	 * numbers.
+	 */
+	frame_idx = 0;
+
+	for (cur = area->used_space.leaf_head.next;
+	    cur != &area->used_space.leaf_head; cur = cur->next) {
+		btree_node_t *node;
+		unsigned int i;
+		
+		node = list_get_instance(cur, btree_node_t, leaf_link);
+		for (i = 0; i < node->keys; i++) {
+			uintptr_t b = node->key[i];
+			count_t j;
+			pte_t *pte;
+			
+			for (j = 0; j < (count_t) node->value[i]; j++) {
+				page_table_lock(as, false);
+				pte = page_mapping_find(as, b + j * PAGE_SIZE);
+				ASSERT(pte && PTE_VALID(pte) &&
+				    PTE_PRESENT(pte));
+				old_frame[frame_idx++] = PTE_GET_FRAME(pte);
+
+				/* Remove old mapping */
+				page_mapping_remove(as, b + j * PAGE_SIZE);
+				page_table_unlock(as, false);
+			}
+		}
+	}
+
+	/*
+	 * Finish TLB shootdown sequence.
+	 */
+
+	tlb_invalidate_pages(as->asid, area->base, area->pages);
+	/*
+	 * Invalidate potential software translation caches (e.g. TSB on
+	 * sparc64).
+	 */
+	as_invalidate_translation_cache(as, area->base, area->pages);
+	tlb_shootdown_finalize();
+
+	/*
+	 * Map pages back in with new flags. This step is kept separate
+	 * so that there's no instant when the memory area could be
+	 * accesed with both the old and the new flags at once.
+	 */
+	frame_idx = 0;
+
+	for (cur = area->used_space.leaf_head.next;
+	    cur != &area->used_space.leaf_head; cur = cur->next) {
+		btree_node_t *node;
+		unsigned int i;
+		
+		node = list_get_instance(cur, btree_node_t, leaf_link);
+		for (i = 0; i < node->keys; i++) {
+			uintptr_t b = node->key[i];
+			count_t j;
+			
+			for (j = 0; j < (count_t) node->value[i]; j++) {
+				page_table_lock(as, false);
+
+				/* Insert the new mapping */
+				page_mapping_insert(as, b + j * PAGE_SIZE,
+				    old_frame[frame_idx++], page_flags);
+
+				page_table_unlock(as, false);
+			}
+		}
+	}
+
+	free(old_frame);
+
+	mutex_unlock(&area->lock);
+	mutex_unlock(&as->lock);
+	interrupts_restore(ipl);
+
+	return 0;
+}
+
+
 /** Handle page fault within the current address space.
  *
@@ -1767,4 +1921,10 @@
 }
 
+/** Wrapper for as_area_change_flags(). */
+unative_t sys_as_area_change_flags(uintptr_t address, int flags)
+{
+	return (unative_t) as_area_change_flags(AS, flags, address);
+}
+
 /** Wrapper for as_area_destroy(). */
 unative_t sys_as_area_destroy(uintptr_t address)
Index: kernel/generic/src/proc/program.c
===================================================================
--- kernel/generic/src/proc/program.c	(revision f93f1689b424f33048541ffe5740a07867076862)
+++ kernel/generic/src/proc/program.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2001-2004 Jakub Jermar
+ * Copyright (c) 2008 Jiri Svoboda
+ * 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 genericproc
+ * @{
+ */
+
+/**
+ * @file
+ * @brief	Running userspace programs.
+ */
+
+#include <main/uinit.h>
+#include <proc/thread.h>
+#include <proc/task.h>
+#include <proc/uarg.h>
+#include <mm/as.h>
+#include <mm/slab.h>
+#include <arch.h>
+#include <adt/list.h>
+#include <ipc/ipc.h>
+#include <ipc/ipcrsc.h>
+#include <security/cap.h>
+#include <lib/elf.h>
+#include <errno.h>
+#include <print.h>
+#include <syscall/copy.h>
+#include <proc/program.h>
+
+#ifndef LOADED_PROG_STACK_PAGES_NO
+#define LOADED_PROG_STACK_PAGES_NO 1
+#endif
+
+/**
+ * Points to the binary image used as the program loader. All non-initial
+ * tasks are created from this executable image.
+ */
+void *program_loader = NULL;
+
+/** Create a program using an existing address space.
+ *
+ * @param as		Address space containing a binary program image.
+ * @param entry_addr	Program entry-point address in program address space.
+ * @param p		Buffer for storing program information.
+ */
+void program_create(as_t *as, uintptr_t entry_addr, program_t *p)
+{
+	as_area_t *a;
+	uspace_arg_t *kernel_uarg;
+
+	kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
+	kernel_uarg->uspace_entry = (void *) entry_addr;
+	kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS;
+	kernel_uarg->uspace_thread_function = NULL;
+	kernel_uarg->uspace_thread_arg = NULL;
+	kernel_uarg->uspace_uarg = NULL;
+	
+	p->task = task_create(as, "app");
+	ASSERT(p->task);
+
+	/*
+	 * Create the data as_area.
+	 */
+	a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
+	    LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS,
+	    AS_AREA_ATTR_NONE, &anon_backend, NULL);
+
+	/*
+	 * Create the main thread.
+	 */
+	p->main_thread = thread_create(uinit, kernel_uarg, p->task,
+	    THREAD_FLAG_USPACE, "uinit", false);
+	ASSERT(p->main_thread);
+}
+
+/** Parse an executable image in the kernel memory.
+ *
+ * If the image belongs to a program loader, it is registered as such,
+ * (and *task is set to NULL). Otherwise a task is created from the
+ * executable image. The task is returned in *task.
+ *
+ * @param image_addr	Address of an executable program image.
+ * @param p		Buffer for storing program info. If image_addr
+ *			points to a loader image, p->task will be set to
+ *			NULL and EOK will be returned.
+ *
+ * @return EOK on success or negative error code.
+ */
+int program_create_from_image(void *image_addr, program_t *p)
+{
+	as_t *as;
+	unsigned int rc;
+
+	as = as_create(0);
+	ASSERT(as);
+
+	rc = elf_load((elf_header_t *) image_addr, as, 0);
+	if (rc != EE_OK) {
+		as_destroy(as);
+		p->task = NULL;
+		p->main_thread = NULL;
+		if (rc != EE_LOADER)
+			return ENOTSUP;
+		
+		/* Register image as the program loader */
+		ASSERT(program_loader == NULL);
+		program_loader = image_addr;
+		printf("Registered program loader at 0x%" PRIp "\n",
+		    image_addr);
+		return EOK;
+	}
+
+	program_create(as, ((elf_header_t *) image_addr)->e_entry, p);
+
+	return EOK;
+}
+
+/** Create a task from the program loader image.
+ *
+ * @param p Buffer for storing program info.
+ * @return EOK on success or negative error code.
+ */
+int program_create_loader(program_t *p)
+{
+	as_t *as;
+	unsigned int rc;
+	void *loader;
+
+	as = as_create(0);
+	ASSERT(as);
+
+	loader = program_loader;
+	if (!loader) {
+		printf("Cannot spawn loader as none was registered\n");
+		return ENOENT;
+	}
+
+	rc = elf_load((elf_header_t *) program_loader, as, ELD_F_LOADER);
+	if (rc != EE_OK) {
+		as_destroy(as);
+		return ENOENT;
+	}
+
+	program_create(as, ((elf_header_t *) program_loader)->e_entry, p);
+
+	return EOK;
+}
+
+/** Make program ready.
+ *
+ * Switch program's main thread to the ready state.
+ *
+ * @param p Program to make ready.
+ */
+void program_ready(program_t *p)
+{
+	thread_ready(p->main_thread);
+}
+
+/** Syscall for creating a new loader instance from userspace.
+ *
+ * Creates a new task from the program loader image, connects a phone
+ * to it and stores the phone id into the provided buffer.
+ *
+ * @param uspace_phone_id Userspace address where to store the phone id.
+ *
+ * @return 0 on success or an error code from @ref errno.h.
+ */
+unative_t sys_program_spawn_loader(int *uspace_phone_id)
+{
+	program_t p;
+	int fake_id;
+	int rc;
+	int phone_id;
+
+	fake_id = 0;
+
+	/* Before we even try creating the task, see if we can write the id */
+	rc = (unative_t) copy_to_uspace(uspace_phone_id, &fake_id,
+	    sizeof(fake_id));
+	if (rc != 0)
+		return rc;
+
+	phone_id = phone_alloc();
+	if (phone_id < 0)
+		return ELIMIT;
+
+	rc = program_create_loader(&p);
+	if (rc != 0)
+		return rc;
+
+	phone_connect(phone_id, &p.task->answerbox);
+
+	/* No need to aquire lock before task_ready() */
+	rc = (unative_t) copy_to_uspace(uspace_phone_id, &phone_id,
+	    sizeof(phone_id));
+	if (rc != 0) {
+		/* Ooops */
+		ipc_phone_hangup(&TASK->phones[phone_id]);
+		task_kill(p.task->taskid);
+		return rc;
+	}
+
+	// FIXME: control the capabilities
+	cap_set(p.task, cap_get(TASK));
+
+	program_ready(&p);
+
+	return EOK;
+}
+
+/** @}
+ */
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/src/proc/task.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -36,8 +36,6 @@
  */
 
-#include <main/uinit.h>
 #include <proc/thread.h>
 #include <proc/task.h>
-#include <proc/uarg.h>
 #include <mm/as.h>
 #include <mm/slab.h>
@@ -47,20 +45,13 @@
 #include <arch.h>
 #include <arch/barrier.h>
-#include <panic.h>
 #include <adt/avl.h>
 #include <adt/btree.h>
 #include <adt/list.h>
 #include <ipc/ipc.h>
-#include <security/cap.h>
-#include <memstr.h>
+#include <ipc/ipcrsc.h>
 #include <print.h>
-#include <lib/elf.h>
 #include <errno.h>
 #include <func.h>
 #include <syscall/copy.h>
-
-#ifndef LOADED_PROG_STACK_PAGES_NO
-#define LOADED_PROG_STACK_PAGES_NO 1
-#endif
 
 /** Spinlock protecting the tasks_tree AVL tree. */
@@ -252,87 +243,4 @@
 }
 
-unative_t sys_task_spawn(void *image, size_t size)
-{
-	void *kimage = malloc(size, 0);
-	if (kimage == NULL)
-		return ENOMEM;
-	
-	int rc = copy_from_uspace(kimage, image, size);
-	if (rc != EOK)
-		return rc;
-
-	/*
-	 * Not very efficient and it would be better to call it on code only,
-	 * but this whole function is a temporary hack anyway and one day it
-	 * will go in favor of the userspace dynamic loader.
-	 */
-	smc_coherence_block(kimage, size);
-	
-	uspace_arg_t *kernel_uarg;
-	kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
-	if (kernel_uarg == NULL) {
-		free(kimage);
-		return ENOMEM;
-	}
-	
-	kernel_uarg->uspace_entry =
-	    (void *) ((elf_header_t *) kimage)->e_entry;
-	kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS;
-	kernel_uarg->uspace_thread_function = NULL;
-	kernel_uarg->uspace_thread_arg = NULL;
-	kernel_uarg->uspace_uarg = NULL;
-	
-	as_t *as = as_create(0);
-	if (as == NULL) {
-		free(kernel_uarg);
-		free(kimage);
-		return ENOMEM;
-	}
-	
-	unsigned int erc = elf_load((elf_header_t *) kimage, as);
-	if (erc != EE_OK) {
-		as_destroy(as);
-		free(kernel_uarg);
-		free(kimage);
-		return ENOENT;
-	}
-	
-	as_area_t *area = as_area_create(as,
-	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
-	    LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS,
-	    AS_AREA_ATTR_NONE, &anon_backend, NULL);
-	if (area == NULL) {
-		as_destroy(as);
-		free(kernel_uarg);
-		free(kimage);
-		return ENOMEM;
-	}
-	
-	task_t *task = task_create(as, "app");
-	if (task == NULL) {
-		as_destroy(as);
-		free(kernel_uarg);
-		free(kimage);
-		return ENOENT;
-	}
-	
-	// FIXME: control the capabilities
-	cap_set(task, cap_get(TASK));
-	
-	thread_t *thread = thread_create(uinit, kernel_uarg, task,
-	    THREAD_FLAG_USPACE, "user", false);
-	if (thread == NULL) {
-		task_destroy(task);
-		as_destroy(as);
-		free(kernel_uarg);
-		free(kimage);
-		return ENOENT;
-	}
-	
-	thread_ready(thread);
-	
-	return EOK;
-}
-
 /** Find task structure corresponding to task ID.
  *
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/src/proc/thread.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -673,72 +673,4 @@
 }
 
-
-/** Create new user task with 1 thread from image
- *
- * @param program_addr Address of program executable image.
- * @param name Program name.
- *
- * @return Initialized main thread of the task or NULL on error.
- */
-thread_t *thread_create_program(void *program_addr, char *name)
-{
-	as_t *as;
-	as_area_t *area;
-	unsigned int rc;
-	task_t *task;
-	uspace_arg_t *kernel_uarg;
-	
-	kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
-	if (kernel_uarg == NULL)
-		return NULL;
-	
-	kernel_uarg->uspace_entry =
-	    (void *) ((elf_header_t *) program_addr)->e_entry;
-	kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS;
-	kernel_uarg->uspace_thread_function = NULL;
-	kernel_uarg->uspace_thread_arg = NULL;
-	kernel_uarg->uspace_uarg = NULL;
-
-	as = as_create(0);
-	if (as == NULL) {
-		free(kernel_uarg);
-		return NULL;
-	}
-
-	rc = elf_load((elf_header_t *) program_addr, as);
-	if (rc != EE_OK) {
-		free(kernel_uarg);
-		as_destroy(as);
-		return NULL;
-	}
-	
-	/*
-	 * Create the data as_area.
-	 */
-	area = as_area_create(as,
-		AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
-		LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS,
-		AS_AREA_ATTR_NONE, &anon_backend, NULL);
-	if (area == NULL) {
-		free(kernel_uarg);
-		as_destroy(as);
-		return NULL;
-	} 
-	
-	task = task_create(as, name);
-	if (task == NULL) {
-		free(kernel_uarg);
-		as_destroy(as);
-		return NULL;
-	}
-	
-	/*
-	 * Create the main thread.
-	 */
-	return thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,
-	    "uinit", false);
-}
-
-
 /** Update accounting of current thread.
  *
Index: kernel/generic/src/synch/smc.c
===================================================================
--- kernel/generic/src/synch/smc.c	(revision f93f1689b424f33048541ffe5740a07867076862)
+++ kernel/generic/src/synch/smc.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008 Jiri Svoboda
+ * 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 sync
+ * @{
+ */
+
+/**
+ * @file
+ * @brief	Self-modifying code barriers.
+ */
+
+#include <arch.h>
+#include <macros.h>
+#include <errno.h>
+#include <arch/barrier.h>
+#include <synch/smc.h>
+
+unative_t sys_smc_coherence(uintptr_t va, size_t size)
+{
+	if (overlaps(va, size, NULL, PAGE_SIZE))
+		return EINVAL;
+
+	if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
+		if (overlaps(va, size, KERNEL_ADDRESS_SPACE_START,
+		    KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START))
+			return EINVAL;
+	}
+
+	smc_coherence_block((void *) va, size);
+	return 0;
+}
+
+/** @}
+ */
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision b5a1730ff354c85c5705e67a0537b3a6768217ac)
+++ kernel/generic/src/syscall/syscall.c	(revision f93f1689b424f33048541ffe5740a07867076862)
@@ -39,4 +39,5 @@
 #include <proc/thread.h>
 #include <proc/task.h>
+#include <proc/program.h>
 #include <mm/as.h>
 #include <print.h>
@@ -47,4 +48,5 @@
 #include <ipc/sysipc.h>
 #include <synch/futex.h>
+#include <synch/smc.h>
 #include <ddi/ddi.h>
 #include <security/cap.h>
@@ -124,13 +126,15 @@
 	
 	(syshandler_t) sys_task_get_id,
-	(syshandler_t) sys_task_spawn,
+	(syshandler_t) sys_program_spawn_loader,
 	
 	/* Synchronization related syscalls. */
 	(syshandler_t) sys_futex_sleep_timeout,
 	(syshandler_t) sys_futex_wakeup,
+	(syshandler_t) sys_smc_coherence,
 	
 	/* Address space related syscalls. */
 	(syshandler_t) sys_as_area_create,
 	(syshandler_t) sys_as_area_resize,
+	(syshandler_t) sys_as_area_change_flags,
 	(syshandler_t) sys_as_area_destroy,
 	
