Index: kernel/arch/sparc64/include/mm/frame.h
===================================================================
--- kernel/arch/sparc64/include/mm/frame.h	(revision e11ae91fc3a4227bcea74717abb36d585ceb5627)
+++ kernel/arch/sparc64/include/mm/frame.h	(revision ee454eb5d8b6afbdf2584335a5838d1980e66cb9)
@@ -33,6 +33,6 @@
  */
 
-#ifndef __sparc64_FRAME_H__
-#define __sparc64_FRAME_H__
+#ifndef KERN_sparc64_FRAME_H_
+#define KERN_sparc64_FRAME_H_
 
 #define FRAME_WIDTH		13	/* 8K */
Index: kernel/arch/sparc64/include/mm/page.h
===================================================================
--- kernel/arch/sparc64/include/mm/page.h	(revision e11ae91fc3a4227bcea74717abb36d585ceb5627)
+++ kernel/arch/sparc64/include/mm/page.h	(revision ee454eb5d8b6afbdf2584335a5838d1980e66cb9)
@@ -33,6 +33,6 @@
  */
 
-#ifndef __sparc64_PAGE_H__
-#define __sparc64_PAGE_H__
+#ifndef KERN_sparc64_PAGE_H_
+#define KERN_sparc64_PAGE_H_
 
 #include <arch/mm/frame.h>
@@ -42,4 +42,6 @@
 
 #ifdef KERNEL
+
+#ifndef __ASM__
 
 #include <mm/page.h>
@@ -54,5 +56,5 @@
 	struct {
 		uint64_t vpn : 51;		/**< Virtual Page Number. */
-		unsigned offset : 13;	/**< Offset. */
+		unsigned offset : 13;		/**< Offset. */
 	} __attribute__ ((packed));
 };
@@ -62,4 +64,6 @@
 extern void page_arch_init(void);
 
+#endif /* !def __ASM__ */
+
 #endif /* KERNEL */
 
Index: kernel/arch/sparc64/include/regdef.h
===================================================================
--- kernel/arch/sparc64/include/regdef.h	(revision e11ae91fc3a4227bcea74717abb36d585ceb5627)
+++ kernel/arch/sparc64/include/regdef.h	(revision ee454eb5d8b6afbdf2584335a5838d1980e66cb9)
@@ -50,4 +50,7 @@
 #define TSTATE_CWP_MASK		0x1f
 
+#define WSTATE_NORMAL(n)	(n)
+#define WSTATE_OTHER(n)		((n)<<3)
+
 #endif
 
Index: kernel/arch/sparc64/src/proc/scheduler.c
===================================================================
--- kernel/arch/sparc64/src/proc/scheduler.c	(revision e11ae91fc3a4227bcea74717abb36d585ceb5627)
+++ kernel/arch/sparc64/src/proc/scheduler.c	(revision ee454eb5d8b6afbdf2584335a5838d1980e66cb9)
@@ -79,10 +79,10 @@
 		 */
 		ASSERT(THREAD->arch.uspace_window_buffer);
-		uintptr_t uw_buf = (uintptr_t) THREAD->arch.uspace_window_buffer;
+		uintptr_t uw_buf = ALIGN_DOWN((uintptr_t) THREAD->arch.uspace_window_buffer, PAGE_SIZE);
 		if (!overlaps(uw_buf, PAGE_SIZE, base, 1<<KERNEL_PAGE_WIDTH)) {
 			/*
 			 * The buffer is not covered by the 4M locked kernel DTLB entry.
 			 */
-			dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_NUCLEUS, (uintptr_t) uw_buf);
+			dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_NUCLEUS, uw_buf);
 			dtlb_insert_mapping(uw_buf, KA2PA(uw_buf), PAGESIZE_8K, true, true);
 		}
@@ -127,5 +127,5 @@
 		flushw();	/* force all userspace windows into memory */
 		
-		uintptr_t uw_buf = (uintptr_t) THREAD->arch.uspace_window_buffer;
+		uintptr_t uw_buf = ALIGN_DOWN((uintptr_t) THREAD->arch.uspace_window_buffer, PAGE_SIZE);
 		if (!overlaps(uw_buf, PAGE_SIZE, base, 1<<KERNEL_PAGE_WIDTH)) {
 			/*
@@ -134,5 +134,5 @@
 			 * Demap it.
 			 */
-			dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_NUCLEUS, (uintptr_t) uw_buf);
+			dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_NUCLEUS, uw_buf);
 		}
 	
Index: kernel/arch/sparc64/src/proc/thread.c
===================================================================
--- kernel/arch/sparc64/src/proc/thread.c	(revision e11ae91fc3a4227bcea74717abb36d585ceb5627)
+++ kernel/arch/sparc64/src/proc/thread.c	(revision ee454eb5d8b6afbdf2584335a5838d1980e66cb9)
@@ -36,4 +36,7 @@
 #include <arch/proc/thread.h>
 #include <mm/frame.h>
+#include <mm/page.h>
+#include <arch/mm/page.h>
+#include <align.h>
 
 void thr_constructor_arch(thread_t *t)
@@ -47,6 +50,11 @@
 void thr_destructor_arch(thread_t *t)
 {
-	if (t->arch.uspace_window_buffer)
-		frame_free((uintptr_t) t->arch.uspace_window_buffer);
+	if (t->arch.uspace_window_buffer) {
+		/*
+		 * Mind the possible alignment of the userspace window buffer
+		 * belonging to a killed thread.
+		 */
+		frame_free(ALIGN_DOWN((uintptr_t) t->arch.uspace_window_buffer, PAGE_SIZE));
+	}
 }
 
@@ -59,4 +67,12 @@
 		 */
 		t->arch.uspace_window_buffer = frame_alloc(ONE_FRAME, 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, PAGE_SIZE);
 	}
 }
Index: kernel/arch/sparc64/src/trap/trap_table.S
===================================================================
--- kernel/arch/sparc64/src/trap/trap_table.S	(revision e11ae91fc3a4227bcea74717abb36d585ceb5627)
+++ kernel/arch/sparc64/src/trap/trap_table.S	(revision ee454eb5d8b6afbdf2584335a5838d1980e66cb9)
@@ -41,4 +41,5 @@
 #include <arch/trap/exception.h>
 #include <arch/trap/mmu.h>
+#include <arch/mm/page.h>
 #include <arch/stack.h>
 #include <arch/regdef.h>
@@ -330,4 +331,9 @@
 
 	/*
+	 * Normal window spills will go to the userspace window buffer.
+	 */
+	wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(2), %wstate
+
+	/*
 	 * Switch to kernel stack. The old stack is
 	 * automatically saved in the old window's %sp
@@ -364,5 +370,11 @@
 	 */
 1:
-
+	
+	/*
+	 * Other window spills will go to the userspace window buffer
+	 * and normal spills will go to the kernel stack.
+	 */
+	wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(0), %wstate
+	
 	/*
 	 * Copy arguments.
@@ -450,5 +462,5 @@
 	 */
 	flushw
-	mov %sp, %g1
+	mov %sp, %g2
 	stx %i0, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I0]
 	stx %i1, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I1]
@@ -460,5 +472,5 @@
 	stx %i7, [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I7]
 	wrpr %l0, 0, %cwp
-	mov %g1, %sp
+	mov %g2, %sp
 	ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I0], %i0
 	ldx [%sp + PREEMPTIBLE_HANDLER_STACK_FRAME_SIZE + STACK_BIAS + SAVED_I1], %i1
@@ -472,8 +484,81 @@
 	/*
 	 * OTHERWIN != 0 or fall-through from the OTHERWIN == 0 case.
+	 * The CWP has already been restored to the value it had prior to the SAVE
+	 * at the beginning of this function.
 	 */
 0:
-	! TODO: restore register windows from register window memory buffer
-
+	rdpr %tstate, %g1
+	andcc %g1, TSTATE_PRIV_BIT, %g0		! if we are not returning to userspace...,
+	bnz 1f					! ...skip restoring userspace windows
+	nop
+	
+	rdpr %cwp, %g1
+	rdpr %otherwin, %g2
+
+	/*
+	 * Skip all OTHERWIN windows and descend to the first window
+	 * in the userspace window buffer.
+	 */
+	sub %g1, %g2, %g3
+	dec %g3
+	and %g3, NWINDOW - 1, %g3
+	wrpr %g3, 0, %cwp
+
+	/*
+	 * CWP is now in the window last saved in the userspace window buffer.
+	 * Fill all windows stored in the buffer.
+	 */
+	clr %g4
+0:	andcc %g7, PAGE_WIDTH - 1, %g0		! PAGE_SIZE alignment check
+	bz 0f					! %g7 is page-aligned, no more windows to refill
+	nop
+
+	add %g7, -STACK_WINDOW_SAVE_AREA_SIZE, %g7
+	ldx [%g7 + L0_OFFSET], %l0
+	ldx [%g7 + L1_OFFSET], %l1
+	ldx [%g7 + L2_OFFSET], %l2
+	ldx [%g7 + L3_OFFSET], %l3
+	ldx [%g7 + L4_OFFSET], %l4
+	ldx [%g7 + L5_OFFSET], %l5
+	ldx [%g7 + L6_OFFSET], %l6
+	ldx [%g7 + L7_OFFSET], %l7
+	ldx [%g7 + I0_OFFSET], %i0
+	ldx [%g7 + I1_OFFSET], %i1
+	ldx [%g7 + I2_OFFSET], %i2
+	ldx [%g7 + I3_OFFSET], %i3
+	ldx [%g7 + I4_OFFSET], %i4
+	ldx [%g7 + I5_OFFSET], %i5
+	ldx [%g7 + I6_OFFSET], %i6
+	ldx [%g7 + I7_OFFSET], %i7
+
+	dec %g3
+	and %g3, NWINDOW - 1, %g3
+	wrpr %g3, 0, %cwp			! switch to the preceeding window
+
+	ba 0b
+	inc %g4
+
+0:
+	/*
+	 * Switch back to the proper current window and adjust
+	 * OTHERWIN, CANRESTORE, CANSAVE and CLEANWIN.
+	 */
+	wrpr %g1, 0, %cwp
+	add %g4, %g2, %g2
+	mov NWINDOW - 2, %g1
+	sub %g1, %g2, %g1
+	
+	wrpr %g0, 0, %otherwin
+	wrpr %g1, 0, %cansave			! NWINDOW - 2 - CANRESTORE
+	wrpr %g2, 0, %canrestore		! OTHERWIN + windows in the buffer
+	wrpr %g2, 0, %cleanwin			! avoid information leak
+
+	/*
+	 * Spills and fills will be processed by the {spill,fill}_1_normal
+	 * handlers.
+	 */
+	wrpr %g0, WSTATE_OTHER(0) | WSTATE_NORMAL(1), %wstate
+
+1:
 	restore
 	retry
