Index: kernel/arch/sparc32/src/exception.c
===================================================================
--- kernel/arch/sparc32/src/exception.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/exception.c	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -48,6 +48,7 @@
 void instruction_access_exception(int n, istate_t *istate)
 {
-	fault_if_from_uspace(istate, "%s.", __func__);
-	panic_badtrap(istate, n, "%s.", __func__);
+	page_fault(n, istate);
+//	fault_if_from_uspace(istate, "%s.", __func__);
+//	panic_badtrap(istate, n, "%s.", __func__);
 }
 
@@ -104,6 +105,7 @@
 void data_access_exception(int n, istate_t *istate)
 {
-	fault_if_from_uspace(istate, "%s.", __func__);
-	panic_badtrap(istate, n, "%s.", __func__);
+	page_fault(n, istate);
+//	fault_if_from_uspace(istate, "%s.", __func__);
+//	panic_badtrap(istate, n, "%s.", __func__);
 }
 
@@ -111,6 +113,7 @@
 void data_access_error(int n, istate_t *istate)
 {
-	fault_if_from_uspace(istate, "%s.", __func__);
-	panic_badtrap(istate, n, "%s.", __func__);
+	page_fault(n, istate);
+//	fault_if_from_uspace(istate, "%s.", __func__);
+//	panic_badtrap(istate, n, "%s.", __func__);
 }
 
@@ -118,6 +121,7 @@
 void data_store_error(int n, istate_t *istate)
 {
-	fault_if_from_uspace(istate, "%s.", __func__);
-	panic_badtrap(istate, n, "%s.", __func__);
+	page_fault(n, istate);
+//	fault_if_from_uspace(istate, "%s.", __func__);
+//	panic_badtrap(istate, n, "%s.", __func__);
 }
 /** Handle data_access_error. (0x2c) */
Index: kernel/arch/sparc32/src/mm/frame.c
===================================================================
--- kernel/arch/sparc32/src/mm/frame.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/mm/frame.c	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -60,4 +60,6 @@
 		    BOOT_PT_START_FRAME + BOOT_PT_SIZE_FRAMES,
 		    ZONE_AVAILABLE | ZONE_LOWMEM);
+
+		printf("low_zone: %d frames\n", SIZE2FRAMES(size));
 	} else {
 		pfn_t conf = zone_external_conf_alloc(SIZE2FRAMES(size));
@@ -65,6 +67,9 @@
 			zone_create(ADDR2PFN(base), SIZE2FRAMES(size), conf,
 			    ZONE_AVAILABLE | ZONE_HIGHMEM);
+
+		printf("high zone: %d frames\n", SIZE2FRAMES(size));
 	}
-	
+
+	printf("free: %d\n", frame_total_free_get());
 }
 
@@ -81,4 +86,5 @@
 	/* blacklist boot page table */
 	frame_mark_unavailable(BOOT_PT_START_FRAME, BOOT_PT_SIZE_FRAMES);
+	printf("free: %d\n", frame_total_free_get());
 	//machine_frame_init();
 }
Index: kernel/arch/sparc32/src/mm/page.c
===================================================================
--- kernel/arch/sparc32/src/mm/page.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/mm/page.c	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -34,4 +34,6 @@
 
 #include <arch/mm/page.h>
+#include <arch/mm/page_fault.h>
+#include <arch/mm/tlb.h>
 #include <genarch/mm/page_pt.h>
 #include <arch/mm/frame.h>
@@ -75,5 +77,5 @@
 
 	/* Switch MMU to new context table */
-	asi_u32_write(ASI_MMUREGS, 0x100, KA2PA(as_context_table) >> 4);
+	asi_u32_write(ASI_MMUREGS, MMU_CONTEXT_TABLE, KA2PA(as_context_table) >> 4);
 
 	//boot_page_table_free();
@@ -82,4 +84,19 @@
 void page_fault(unsigned int n __attribute__((unused)), istate_t *istate)
 {
+	uint32_t fault_status = asi_u32_read(ASI_MMUREGS, MMU_FAULT_STATUS);
+	uintptr_t fault_address = asi_u32_read(ASI_MMUREGS, MMU_FAULT_ADDRESS);
+	mmu_fault_status_t *fault = (mmu_fault_status_t *)&fault_status;
+	mmu_fault_type_t type = (mmu_fault_type_t)fault->ft;
+
+	printf("page fault on address 0x%08x, status 0x%08x\n", fault_address, fault_status);
+
+	if (type == FAULT_TYPE_LOAD_USER_DATA)	
+		as_page_fault(fault_address, PF_ACCESS_READ, istate);
+
+	if (type == FAULT_TYPE_EXECUTE_USER)
+		as_page_fault(fault_address, PF_ACCESS_EXEC, istate);
+
+	if (type == FAULT_TYPE_STORE_USER_DATA || type == FAULT_TYPE_STORE_USER_INSTRUCTION)
+		as_page_fault(fault_address, PF_ACCESS_WRITE, istate);
 }
 
Index: kernel/arch/sparc32/src/proc/scheduler.c
===================================================================
--- kernel/arch/sparc32/src/proc/scheduler.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/proc/scheduler.c	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Martin Decky
+ * Copyright (c) 2013 Jakub Klama
  * All rights reserved.
  *
@@ -34,4 +34,7 @@
 
 #include <proc/scheduler.h>
+#include <proc/thread.h>
+#include <arch.h>
+#include <arch/arch.h>
 
 void before_task_runs_arch(void)
@@ -41,4 +44,6 @@
 void before_thread_runs_arch(void)
 {
+	kernel_sp = (uintptr_t) THREAD->kstack + STACK_SIZE;
+	uspace_wbuf = (uintptr_t) THREAD->arch.uspace_window_buffer;
 }
 
Index: kernel/arch/sparc32/src/proc/thread.c
===================================================================
--- kernel/arch/sparc32/src/proc/thread.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/proc/thread.c	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -33,8 +33,43 @@
  */
 
+#include <arch/regwin.h>
 #include <proc/thread.h>
+
+void thr_constructor_arch(thread_t *t)
+{
+	t->arch.uspace_window_buffer = NULL;
+}
+
+void thr_destructor_arch(thread_t *t)
+{
+	if (t->arch.uspace_window_buffer) {
+		uintptr_t uw_buf = (uintptr_t) t->arch.uspace_window_buffer;
+		/*
+		 * Mind the possible alignment of the userspace window buffer
+		 * belonging to a killed thread.
+		 */
+		free((uint8_t *) ALIGN_DOWN(uw_buf, UWB_ALIGNMENT));
+	}
+}
 
 void thread_create_arch(thread_t *t)
 {
+	if ((t->uspace) && (!t->arch.uspace_window_buffer))
+		{
+		/*
+		 * The thread needs userspace window buffer and the object
+		 * returned from the slab allocator doesn't have any.
+		 */
+		t->arch.uspace_window_buffer = malloc(UWB_ASIZE, 0);
+	} else {
+		uintptr_t uw_buf = (uintptr_t) t->arch.uspace_window_buffer;
+
+		/*
+		 * Mind the possible alignment of the userspace window buffer
+		 * belonging to a killed thread.
+		 */
+		t->arch.uspace_window_buffer = (uint8_t *) ALIGN_DOWN(uw_buf,
+		    UWB_ASIZE);
+	}
 }
 
Index: kernel/arch/sparc32/src/sparc32.c
===================================================================
--- kernel/arch/sparc32/src/sparc32.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/sparc32.c	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -56,5 +56,5 @@
 char memcpy_to_uspace_failover_address;
 
-void arch_pre_main(bootinfo_t *bootinfo)
+void arch_pre_main(void *unused, bootinfo_t *bootinfo)
 {
 	init.cnt = min3(bootinfo->cnt, TASKMAP_MAX_RECORDS, CONFIG_INIT_TASKS);
Index: kernel/arch/sparc32/src/start.S
===================================================================
--- kernel/arch/sparc32/src/start.S	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/start.S	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -31,4 +31,6 @@
 .global kernel_image_start
 .global early_putchar
+.global kernel_sp
+.global uspace_wbuf
 
 kernel_image_start:
@@ -68,4 +70,10 @@
 	nop
 
+kernel_sp:
+.space 4
+
+uspace_wbuf:
+.space 4
+
 .align 16
 .space 4096
Index: kernel/arch/sparc32/src/trap_table.S
===================================================================
--- kernel/arch/sparc32/src/trap_table.S	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/trap_table.S	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -33,4 +33,5 @@
 .global trap_table
 .global reset_trap
+.global preemptible_trap
 .global window_overflow_trap
 .global window_underflow_trap
@@ -116,10 +117,50 @@
         rett %l2
 
-#define	TRAP(_vector, _handler) \
+preemptible_trap:
+	/* Enable traps */
+	mov %psr, %l0
+	or %l0, (1 << 5), %l0
+	mov %l0, %psr
+
+	/* Check whether previous mode was usermode */
+	and %l0, (1 << 6), %l0
+	cmp %l0, 0
+	bne 1f
+	nop
+
+	/* Set up stack */
+	set kernel_sp, %l4
+	ld [%l4], %sp
+	mov %sp, %fp
+1:	sub %sp, 112, %sp
+
+	/* Save trap data on stack */
+	st %l1, [%fp - 4]
+	st %l2, [%fp - 8]
+	st %l0, [%fp - 12]
+
+	/* Jump to actual subroutine */
+	mov 1, %o0
+	jmp %g1
+	sub %fp, 12, %o1
+
+	/* Return from handler */
+	ld [%fp - 4], %l1
+	ld [%fp - 8], %l2
+	jmp %l1
+	rett %l2
+
+#define	STRAP(_vector, _handler) \
 	.org trap_table + _vector * TRAP_ENTRY_SIZE; \
 	mov %psr, %l0 ; \
 	sethi %hi(_handler), %l4 ; \
-	jmp %l4 + %lo(_handler); \
-	mov _vector, %l3 ;
+	jmp %lo(_handler) + %l4 ; \
+	nop
+
+#define	TRAP(_vector, _handler) \
+	.org trap_table + _vector * TRAP_ENTRY_SIZE; \
+	sethi %hi(_handler), %g1 ; \
+	b preemptible_trap ; \
+	or %g1, %lo(_handler), %g1 ;
 
 #define	INTERRUPT(_vector, _priority) \
@@ -141,6 +182,6 @@
 	TRAP(0x3, privileged_instruction)
 	TRAP(0x4, fp_disabled)
-	TRAP(0x5, window_overflow_trap)
-	TRAP(0x6, window_underflow_trap)
+	STRAP(0x5, window_overflow_trap)
+	STRAP(0x6, window_underflow_trap)
 	TRAP(0x7, mem_address_not_aligned)
 	TRAP(0x8, fp_exception)
Index: kernel/arch/sparc32/src/userspace.c
===================================================================
--- kernel/arch/sparc32/src/userspace.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc32/src/userspace.c	(revision 4d2dba7fbc2d5f64befb5898859b0ed4ea88adf4)
@@ -36,4 +36,5 @@
 #include <typedefs.h>
 #include <arch.h>
+#include <arch/asm.h>
 #include <abi/proc/uarg.h>
 #include <mm/as.h>
@@ -41,7 +42,22 @@
 void userspace(uspace_arg_t *kernel_uarg)
 {
+	printf("userspace(): entry=%p, stack=%p, stacksize=%d\n", kernel_uarg->uspace_entry, kernel_uarg->uspace_stack, kernel_uarg->uspace_stack_size);
 	/* On real hardware this switches the CPU to user
 	   space mode and jumps to kernel_uarg->uspace_entry. */
-	
+
+	uint32_t psr = psr_read();
+
+	psr &= ~(1 << 7);
+	psr &= ~(1 << 6);
+
+	asm volatile (
+		"mov %[stack], %%sp\n"
+		"mov %[psr], %%psr\n"
+		"nop\n"
+		"jmp %[entry]\n"
+		"nop\n" :: [entry] "r" (kernel_uarg->uspace_entry),
+			   [psr] "r" (psr),
+			   [stack] "r" (kernel_uarg->uspace_stack + kernel_uarg->uspace_stack_size));
+
 	while (true);
 }
