Index: arch/amd64/src/proc/scheduler.c
===================================================================
--- arch/amd64/src/proc/scheduler.c	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/amd64/src/proc/scheduler.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -44,2 +44,6 @@
 	swapgs();
 }
+
+void after_thread_ran_arch(void)
+{
+}
Index: arch/ia32/src/proc/scheduler.c
===================================================================
--- arch/ia32/src/proc/scheduler.c	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/ia32/src/proc/scheduler.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -38,2 +38,6 @@
 	CPU->arch.tss->ss0 = selector(KDATA_DES);
 }
+
+void after_thread_ran_arch(void)
+{
+}
Index: arch/ia64/src/dummy.s
===================================================================
--- arch/ia64/src/dummy.s	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/ia64/src/dummy.s	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -33,4 +33,5 @@
 .global userspace
 .global before_thread_runs_arch
+.global after_thread_ran_arch
 .global cpu_sleep
 .global dummy
@@ -40,4 +41,5 @@
 
 before_thread_runs_arch:
+after_thread_ran_arch:
 userspace:
 calibrate_delay_loop:
Index: arch/mips32/src/mips32.c
===================================================================
--- arch/mips32/src/mips32.c	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/mips32/src/mips32.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -135,2 +135,6 @@
 	supervisor_sp = (__address) &THREAD->kstack[THREAD_STACK_SIZE-SP_DELTA];
 }
+
+void after_thread_ran_arch(void)
+{
+}
Index: arch/ppc32/src/dummy.s
===================================================================
--- arch/ppc32/src/dummy.s	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/ppc32/src/dummy.s	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -32,4 +32,5 @@
 .global userspace
 .global before_thread_runs_arch
+.global after_thread_ran_arch
 .global dummy
 .global fpu_init
@@ -38,4 +39,5 @@
 
 before_thread_runs_arch:
+after_thread_ran_arch:
 userspace:
 asm_delay_loop:
Index: arch/sparc64/Makefile.inc
===================================================================
--- arch/sparc64/Makefile.inc	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/Makefile.inc	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -82,4 +82,5 @@
 	arch/$(ARCH)/src/sparc64.c \
 	arch/$(ARCH)/src/start.S \
+	arch/$(ARCH)/src/proc/scheduler.c \
 	arch/$(ARCH)/src/trap/trap_table.S \
 	arch/$(ARCH)/src/trap/trap.c \
Index: arch/sparc64/include/drivers/i8042.h
===================================================================
--- arch/sparc64/include/drivers/i8042.h	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/include/drivers/i8042.h	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -33,5 +33,5 @@
 
 #define KBD_PHYS_ADDRESS	0x1fff8904000ULL
-#define KBD_VIRT_ADDRESS	0x00000d00000ULL
+#define KBD_VIRT_ADDRESS	0x000d0000000ULL
 
 #define STATUS_REG	4
@@ -41,5 +41,5 @@
 static inline void i8042_data_write(__u8 data)
 {
-	((__u8 *)(KBD_VIRT_ADDRESS))[DATA_REG] = data;
+	((volatile __u8 *)(KBD_VIRT_ADDRESS))[DATA_REG] = data;
 }
 
@@ -56,5 +56,5 @@
 static inline void i8042_command_write(__u8 command)
 {
-	((__u8 *)(KBD_VIRT_ADDRESS))[COMMAND_REG] = command;
+	((volatile __u8 *)(KBD_VIRT_ADDRESS))[COMMAND_REG] = command;
 }
 
Index: arch/sparc64/include/mm/tlb.h
===================================================================
--- arch/sparc64/include/mm/tlb.h	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/include/mm/tlb.h	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -406,3 +406,5 @@
 extern void fast_data_access_protection(void);
 
+extern void dtlb_insert_mapping(__address page, __address frame, int pagesize, bool locked, bool cacheable);
+
 #endif
Index: arch/sparc64/include/trap/exception.h
===================================================================
--- arch/sparc64/include/trap/exception.h	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/include/trap/exception.h	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -32,4 +32,5 @@
 #define TT_INSTRUCTION_ACCESS_EXCEPTION		0x08
 #define TT_ILLEGAL_INSTRUCTION			0x10
+#define TT_DATA_ACCESS_ERROR			0x32
 #define TT_MEM_ADDRESS_NOT_ALIGNED		0x34
 
@@ -37,4 +38,5 @@
 extern void do_instruction_access_exc(void);
 extern void do_mem_address_not_aligned(void);
+extern void do_data_access_error(void);
 extern void do_illegal_instruction(void);
 #endif /* !__ASM__ */
Index: arch/sparc64/src/console.c
===================================================================
--- arch/sparc64/src/console.c	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/src/console.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -41,4 +41,5 @@
 #include <proc/thread.h>
 #include <synch/mutex.h>
+#include <arch/mm/tlb.h>
 
 #define KEYBOARD_POLL_PAUSE	50000	/* 50ms */
@@ -76,4 +77,8 @@
 	ofw_console_active = 0;
 	stdin = NULL;
+
+	dtlb_insert_mapping(FB_VIRT_ADDRESS, FB_PHYS_ADDRESS, PAGESIZE_4M, true, false);
+	dtlb_insert_mapping(KBD_VIRT_ADDRESS, KBD_PHYS_ADDRESS, PAGESIZE_8K, true, false);
+
 	fb_init(FB_VIRT_ADDRESS, FB_X_RES, FB_Y_RES, FB_COLOR_DEPTH/8);
 	i8042_init();
Index: arch/sparc64/src/mm/tlb.c
===================================================================
--- arch/sparc64/src/mm/tlb.c	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/src/mm/tlb.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -110,10 +110,23 @@
 	dmmu_enable();
 	immu_enable();
-	
-	/*
-	 * Quick hack: map frame buffer
-	 */
-	fr.address = FB_PHYS_ADDRESS;
-	pg.address = FB_VIRT_ADDRESS;
+}
+
+/** Insert privileged mapping into DMMU TLB.
+ *
+ * @param page Virtual page address.
+ * @param frame Physical frame address.
+ * @param pagesize Page size.
+ * @param locked True for permanent mappings, false otherwise.
+ * @param cacheable True if the mapping is cacheable, false otherwise.
+ */
+void dtlb_insert_mapping(__address page, __address frame, int pagesize, bool locked, bool cacheable)
+{
+	tlb_tag_access_reg_t tag;
+	tlb_data_t data;
+	page_address_t pg;
+	frame_address_t fr;
+
+	pg.address = page;
+	fr.address = frame;
 
 	tag.value = ASID_KERNEL;
@@ -124,9 +137,9 @@
 	data.value = 0;
 	data.v = true;
-	data.size = PAGESIZE_4M;
+	data.size = pagesize;
 	data.pfn = fr.pfn;
-	data.l = true;
-	data.cp = 0;
-	data.cv = 0;
+	data.l = locked;
+	data.cp = cacheable;
+	data.cv = cacheable;
 	data.p = true;
 	data.w = true;
@@ -134,28 +147,4 @@
 
 	dtlb_data_in_write(data.value);
-	
-	/*
-	 * Quick hack: map keyboard
-	 */
-	fr.address = KBD_PHYS_ADDRESS;
-	pg.address = KBD_VIRT_ADDRESS;
-
-	tag.value = ASID_KERNEL;
-	tag.vpn = pg.vpn;
-
-	dtlb_tag_access_write(tag.value);
-
-	data.value = 0;
-	data.v = true;
-	data.size = PAGESIZE_8K;
-	data.pfn = fr.pfn;
-	data.l = true;
-	data.cp = 0;
-	data.cv = 0;
-	data.p = true;
-	data.w = true;
-	data.g = true;
-
-	dtlb_data_in_write(data.value);
 }
 
@@ -170,5 +159,4 @@
 {
 	tlb_tag_access_reg_t tag;
-	tlb_data_t data;
 	__address tpc;
 	char *tpc_str;
@@ -187,16 +175,5 @@
 	 * Identity map piece of faulting kernel address space.
 	 */
-	data.value = 0;
-	data.v = true;
-	data.size = PAGESIZE_8K;
-	data.pfn = tag.vpn;
-	data.l = false;
-	data.cp = 1;
-	data.cv = 1;
-	data.p = true;
-	data.w = true;
-	data.g = true;
-
-	dtlb_data_in_write(data.value);
+	dtlb_insert_mapping(tag.vpn * PAGE_SIZE, tag.vpn * FRAME_SIZE, PAGESIZE_8K, false, true);
 }
 
Index: arch/sparc64/src/proc/scheduler.c
===================================================================
--- arch/sparc64/src/proc/scheduler.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
+++ arch/sparc64/src/proc/scheduler.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2006 Jakub Jermar
+ * 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.
+ */
+
+#include <proc/scheduler.h>
+#include <proc/thread.h>
+#include <arch.h>
+#include <arch/mm/tlb.h>
+#include <config.h>
+#include <align.h>
+
+/** Ensure that thread's kernel stack is locked in TLB. */
+void before_thread_runs_arch(void)
+{
+	__address base;
+	
+	base = ALIGN_DOWN(config.base, 4*1024*1024);
+
+	if ((__address) THREAD->kstack < base || (__address) THREAD->kstack > base + 4*1024*1024) {
+		/*
+		 * Kernel stack of this thread is not locked in DTLB.
+		 * First, make sure it is not mapped already.
+		 * If not, create a locked mapping for it.
+		 */
+		 dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_NUCLEUS, (__address) THREAD->kstack);
+		 dtlb_insert_mapping((__address) THREAD->kstack, (__address) THREAD->kstack, PAGESIZE_8K, true, true);
+	}	
+}
+
+/** Unlock thread's stack from TLB, if necessary. */
+void after_thread_ran_arch(void)
+{
+	__address base;
+
+	base = ALIGN_DOWN(config.base, 4*1024*1024);
+
+	if ((__address) THREAD->kstack < base || (__address) THREAD->kstack > base + 4*1024*1024) {
+		/*
+		 * Kernel stack of this thread is locked in DTLB.
+		 * Destroy the mapping.
+		 */
+		dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_NUCLEUS, (__address) THREAD->kstack);
+	}
+}
Index: arch/sparc64/src/sparc64.c
===================================================================
--- arch/sparc64/src/sparc64.c	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/src/sparc64.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -75,6 +75,2 @@
 {
 }
-
-void before_thread_runs_arch(void)
-{
-}
Index: arch/sparc64/src/trap/exception.c
===================================================================
--- arch/sparc64/src/trap/exception.c	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/src/trap/exception.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -43,4 +43,10 @@
 }
 
+/** Handle data_access_error. */
+void do_data_access_error(void)
+{
+	panic("Data Access Error: %P\n", tpc_read());
+}
+
 /** Handle mem_address_not_aligned. */
 void do_illegal_instruction(void)
Index: arch/sparc64/src/trap/trap_table.S
===================================================================
--- arch/sparc64/src/trap/trap_table.S	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ arch/sparc64/src/trap/trap_table.S	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -73,4 +73,10 @@
 	CLEAN_WINDOW_HANDLER
 
+/* TT = 0x32, TL = 0, data_access_error */
+.org trap_table + TT_DATA_ACCESS_ERROR*ENTRY_SIZE
+.global data_access_error
+data_access_error:
+	SIMPLE_HANDLER do_data_access_error
+
 /* TT = 0x34, TL = 0, mem_address_not_aligned */
 .org trap_table + TT_MEM_ADDRESS_NOT_ALIGNED*ENTRY_SIZE
@@ -226,4 +232,10 @@
 clean_window_handler_high:
 	CLEAN_WINDOW_HANDLER
+
+/* TT = 0x32, TL > 0, data_access_error */
+.org trap_table + (TT_DATA_ACCESS_ERROR+512)*ENTRY_SIZE
+.global data_access_error_high
+data_access_error_high:
+	SIMPLE_HANDLER do_data_access_error
 
 /* TT = 0x34, TL > 0, mem_address_not_aligned */
Index: generic/include/proc/scheduler.h
===================================================================
--- generic/include/proc/scheduler.h	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ generic/include/proc/scheduler.h	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -54,11 +54,13 @@
 
 extern void before_thread_runs(void);
+extern void after_thread_ran(void);
 
 extern void sched_print_list(void);
+
 /*
  * To be defined by architectures:
  */
- 
 extern void before_thread_runs_arch(void);
+extern void after_thread_ran_arch(void);
 
 #endif
Index: generic/src/proc/scheduler.c
===================================================================
--- generic/src/proc/scheduler.c	(revision d87c3f3d6ecce3cef508faa5142aa822aa7ad387)
+++ generic/src/proc/scheduler.c	(revision 97f1691963436356ca38316e0966ffeb57cd5639)
@@ -50,5 +50,5 @@
 atomic_t nrdy;
 
-/** Take actions before new thread runs
+/** Take actions before new thread runs.
  *
  * Perform actions that need to be
@@ -76,4 +76,18 @@
 	}
 #endif
+}
+
+/** Take actions after old thread ran.
+ *
+ * Perform actions that need to be
+ * taken after the running thread
+ * was preempted by the scheduler.
+ *
+ * THREAD->lock is locked on entry
+ *
+ */
+void after_thread_ran(void)
+{
+	after_thread_ran_arch();
 }
 
@@ -258,4 +272,7 @@
 
 	if (THREAD) {
+		/* must be run after switch to scheduler stack */
+		after_thread_ran();
+
 		switch (THREAD->state) {
 		    case Running:
@@ -301,4 +318,5 @@
 			break;
 		}
+
 		THREAD = NULL;
 	}
@@ -350,4 +368,14 @@
 	printf("cpu%d: tid %d (priority=%d,ticks=%d,nrdy=%d)\n", CPU->id, THREAD->tid, THREAD->priority, THREAD->ticks, atomic_get(&CPU->nrdy));
 	#endif	
+
+	/*
+	 * Some architectures provide late kernel PA2KA(identity)
+	 * mapping in a page fault handler. However, the page fault
+	 * handler uses the kernel stack of the running thread and
+	 * therefore cannot be used to map it. The kernel stack, if
+	 * necessary, is to be mapped in before_thread_runs(). This
+	 * function must be executed before the switch to the new stack.
+	 */
+	before_thread_runs();
 
 	/*
@@ -388,5 +416,4 @@
 			 * This is the place where threads leave scheduler();
 			 */
-			before_thread_runs();
 			spinlock_unlock(&THREAD->lock);
 			interrupts_restore(THREAD->saved_context.ipl);
