Index: kernel/arch/sparc64/src/asm.S
===================================================================
--- kernel/arch/sparc64/src/asm.S	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/asm.S	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -29,4 +29,5 @@
 #include <arch/stack.h>
 #include <arch/regdef.h>
+#include <arch/mm/mmu.h>
 
 .text
@@ -144,2 +145,38 @@
 read_from_ag_g7:
 	READ_ALTERNATE_REGISTER %g7, PSTATE_AG_BIT
+
+
+/** Switch to userspace.
+ *
+ * %o0	Userspace entry address.
+ * %o1	Userspace stack pointer address.
+ */
+.global switch_to_userspace
+switch_to_userspace:
+	flushw
+	wrpr %g0, 0, %cleanwin		! avoid information leak
+	save %o1, -STACK_WINDOW_SAVE_AREA_SIZE, %sp
+
+	clr %i2
+	clr %i3
+	clr %i4
+	clr %i5
+	clr %i6
+
+	wrpr %g0, 1, %tl		! enforce mapping via nucleus
+
+	rdpr %cwp, %g1
+	wrpr %g1, TSTATE_IE_BIT, %tstate
+	wrpr %i0, 0, %tnpc
+	
+	/*
+	 * Set primary context according to secondary context.
+	 * Secondary context has been already installed by
+	 * higher-level functions.
+	 */
+	wr %g0, ASI_DMMU, %asi
+	ldxa [VA_SECONDARY_CONTEXT_REG] %asi, %g1
+	stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi
+	flush %i7
+	
+	done				! jump to userspace
Index: kernel/arch/sparc64/src/ddi/ddi.c
===================================================================
--- kernel/arch/sparc64/src/ddi/ddi.c	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/ddi/ddi.c	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -27,5 +27,5 @@
  */
 
- /** @addtogroup sparc64ddi
+/** @addtogroup sparc64ddi
  * @{
  */
@@ -53,5 +53,4 @@
 }
 
- /** @}
+/** @}
  */
-
Index: kernel/arch/sparc64/src/dummy.s
===================================================================
--- kernel/arch/sparc64/src/dummy.s	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/dummy.s	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -40,5 +40,4 @@
 .global fpu_enable
 .global fpu_init
-.global userspace
 .global sys_tls_set
 
@@ -56,5 +55,4 @@
 fpu_enable:
 fpu_init:
-userspace:
 sys_tls_set:
 
Index: kernel/arch/sparc64/src/mm/as.c
===================================================================
--- kernel/arch/sparc64/src/mm/as.c	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/mm/as.c	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -27,5 +27,5 @@
  */
 
- /** @addtogroup sparc64mm
+/** @addtogroup sparc64mm
  * @{
  */
@@ -34,4 +34,5 @@
 
 #include <arch/mm/as.h>
+#include <arch/mm/tlb.h>
 #include <genarch/mm/as_ht.h>
 #include <genarch/mm/asid_fifo.h>
@@ -44,5 +45,21 @@
 }
 
- /** @}
+void as_install_arch(as_t *as)
+{
+	tlb_context_reg_t ctx;
+	
+	/*
+	 * Write ASID to secondary context register.
+	 * The primary context register has to be set
+	 * from TL>0 so it will be filled from the
+	 * secondary context register from the TL=1
+	 * code just before switch to userspace.
+	 */
+	ctx.v = 0;
+	ctx.context = as->asid;
+	mmu_secondary_context_write(ctx.v);
+}
+
+/** @}
  */
 
Index: kernel/arch/sparc64/src/mm/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/tlb.c	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/mm/tlb.c	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -375,7 +375,14 @@
 void tlb_invalidate_asid(asid_t asid)
 {
-	/* TODO: write asid to some Context register and encode the register in second parameter below. */
-	itlb_demap(TLB_DEMAP_CONTEXT, TLB_DEMAP_NUCLEUS, 0);
-	dtlb_demap(TLB_DEMAP_CONTEXT, TLB_DEMAP_NUCLEUS, 0);
+	tlb_context_reg_t sc_save, ctx;
+	
+	ctx.v = sc_save.v = mmu_secondary_context_read();
+	ctx.context = asid;
+	mmu_secondary_context_write(ctx.v);
+	
+	itlb_demap(TLB_DEMAP_CONTEXT, TLB_DEMAP_SECONDARY, 0);
+	dtlb_demap(TLB_DEMAP_CONTEXT, TLB_DEMAP_SECONDARY, 0);
+	
+	mmu_secondary_context_write(sc_save.v);
 }
 
@@ -389,10 +396,16 @@
 {
 	int i;
+	tlb_context_reg_t sc_save, ctx;
+	
+	ctx.v = sc_save.v = mmu_secondary_context_read();
+	ctx.context = asid;
+	mmu_secondary_context_write(ctx.v);
 	
 	for (i = 0; i < cnt; i++) {
-		/* TODO: write asid to some Context register and encode the register in second parameter below. */
-		itlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_NUCLEUS, page + i * PAGE_SIZE);
-		dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_NUCLEUS, page + i * PAGE_SIZE);
-	}
+		itlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_SECONDARY, page + i * PAGE_SIZE);
+		dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_SECONDARY, page + i * PAGE_SIZE);
+	}
+	
+	mmu_secondary_context_write(sc_save.v);
 }
 
Index: kernel/arch/sparc64/src/proc/scheduler.c
===================================================================
--- kernel/arch/sparc64/src/proc/scheduler.c	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/proc/scheduler.c	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -92,6 +92,8 @@
 		 * in the userspace window buffer to %g7 in the alternate and interrupt sets.
 		 */
-		write_to_ig_g6((uintptr_t) THREAD->kstack + STACK_SIZE - STACK_BIAS);
-		write_to_ag_g6((uintptr_t) THREAD->kstack + STACK_SIZE - STACK_BIAS);
+		uint64_t sp = (uintptr_t) THREAD->kstack + STACK_SIZE
+			- (STACK_BIAS + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT));
+		write_to_ig_g6(sp);
+		write_to_ag_g6(sp);
 		write_to_ag_g7((uintptr_t) THREAD->arch.uspace_window_buffer);
 	}
Index: kernel/arch/sparc64/src/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sparc64.c	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/sparc64.c	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -35,4 +35,5 @@
 #include <arch.h>
 #include <debug.h>
+#include <config.h>
 #include <arch/trap/trap.h>
 #include <arch/console.h>
@@ -42,6 +43,7 @@
 #include <arch/boot/boot.h>
 #include <arch/arch.h>
-#include <arch/mm/tlb.h>
-#include <mm/asid.h>
+#include <arch/mm/page.h>
+#include <arch/stack.h>
+#include <userspace.h>
 
 bootinfo_t bootinfo;
@@ -92,4 +94,16 @@
 }
 
+/** Switch to userspace. */
+void userspace(uspace_arg_t *kernel_uarg)
+{
+	switch_to_userspace((uintptr_t) kernel_uarg->uspace_entry,
+		((uintptr_t) kernel_uarg->uspace_stack) + STACK_SIZE
+		- (ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT) + STACK_BIAS));
+
+	for (;;)
+		;
+	/* not reached */
+}
+
 /** @}
  */
Index: kernel/arch/sparc64/src/start.S
===================================================================
--- kernel/arch/sparc64/src/start.S	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/start.S	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -69,5 +69,5 @@
 	wrpr %g1, 0, %pstate
 
-	wrpr %r0, 0, %pil		! intialize %pil
+	wrpr %g0, 0, %pil		! intialize %pil
 
 	/*
Index: kernel/arch/sparc64/src/trap/trap_table.S
===================================================================
--- kernel/arch/sparc64/src/trap/trap_table.S	(revision e0b241fd74402f055e3581549efeaa597b289645)
+++ kernel/arch/sparc64/src/trap/trap_table.S	(revision ed166f71740001c3b594706d223312aeb0e52fb0)
@@ -41,4 +41,5 @@
 #include <arch/trap/exception.h>
 #include <arch/trap/mmu.h>
+#include <arch/mm/mmu.h>
 #include <arch/mm/page.h>
 #include <arch/stack.h>
@@ -349,5 +350,5 @@
 	wrpr %l0, %otherwin
 	wrpr %g0, %cansave
-	wrpr %g0, NWINDOW-1, %cleanwin
+	wrpr %g0, NWINDOW - 1, %cleanwin
 
 	/*
@@ -355,7 +356,7 @@
 	 */
 	mov VA_PRIMARY_CONTEXT_REG, %l0
-        stxa %g0, [%l0] ASI_DMMU
-	set kernel_image_start, %l0
-        flush %l0
+	stxa %g0, [%l0] ASI_DMMU
+	rd %pc, %l0
+	flush %l0
 
 	ba 1f
@@ -498,4 +499,12 @@
 	 */
 	wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(1), %wstate
+
+	/*
+	 * Set primary context according to secondary context.
+	 */
+	wr %g0, ASI_DMMU, %asi
+	ldxa [VA_SECONDARY_CONTEXT_REG] %asi, %g1
+	stxa %g1, [VA_PRIMARY_CONTEXT_REG] %asi
+	flush %o7
 	
 	rdpr %cwp, %g1
