Index: arch/ia64/include/asm.h
===================================================================
--- arch/ia64/include/asm.h	(revision 4a2f4bb11f3b7c88eee45262b755ff5f2f153dc1)
+++ arch/ia64/include/asm.h	(revision 2a003d5b70d5a4307a6cbdff215872746300cb53)
@@ -240,4 +240,10 @@
 }
 
+/** Disable protection key checking. */
+static inline void pk_disable(void)
+{
+	__asm__ volatile ("rsm %0\n" : : "i" (PSR_PK_MASK));
+}
+
 extern void cpu_halt(void);
 extern void cpu_sleep(void);
Index: arch/ia64/include/mm/page.h
===================================================================
--- arch/ia64/include/mm/page.h	(revision 4a2f4bb11f3b7c88eee45262b755ff5f2f153dc1)
+++ arch/ia64/include/mm/page.h	(revision 2a003d5b70d5a4307a6cbdff215872746300cb53)
@@ -43,7 +43,9 @@
 
 /** Implementation of page hash table interface. */
+#define HT_ENTRIES_ARCH			0
 #define HT_HASH_ARCH(page, asid)	0
 #define HT_COMPARE_ARCH(page, asid, t)	0
 #define HT_SLOT_EMPTY_ARCH(t)		1
+#define HT_INVALIDATE_SLOT_ARCH(t)
 #define HT_GET_NEXT_ARCH(t)		0
 #define HT_SET_NEXT_ARCH(t, s)
Index: arch/ia64/include/register.h
===================================================================
--- arch/ia64/include/register.h	(revision 4a2f4bb11f3b7c88eee45262b755ff5f2f153dc1)
+++ arch/ia64/include/register.h	(revision 2a003d5b70d5a4307a6cbdff215872746300cb53)
@@ -35,6 +35,7 @@
 
 #define CR_IVR_MASK	0xf
+#define PSR_IC_MASK	0x2000
 #define PSR_I_MASK	0x4000
-#define PSR_IC_MASK	0x2000
+#define PSR_PK_MASK	0x8000
 
 /** Application registers. */
Index: arch/ia64/src/mm/page.c
===================================================================
--- arch/ia64/src/mm/page.c	(revision 4a2f4bb11f3b7c88eee45262b755ff5f2f153dc1)
+++ arch/ia64/src/mm/page.c	(revision 2a003d5b70d5a4307a6cbdff215872746300cb53)
@@ -34,4 +34,5 @@
 #include <config.h>
 #include <panic.h>
+#include <arch/asm.h>
 
 __u64 thash(__u64 va);
@@ -141,4 +142,5 @@
 {
 	page_operations = &page_ht_operations;
+	pk_disable();
 	set_VHPT_environment();
 }
Index: arch/sparc64/include/mm/page.h
===================================================================
--- arch/sparc64/include/mm/page.h	(revision 4a2f4bb11f3b7c88eee45262b755ff5f2f153dc1)
+++ arch/sparc64/include/mm/page.h	(revision 2a003d5b70d5a4307a6cbdff215872746300cb53)
@@ -43,7 +43,9 @@
 
 /** Implementation of page hash table interface. */
+#define HT_ENTRIES_ARCH			0
 #define HT_HASH_ARCH(page, asid)	0
 #define HT_COMPARE_ARCH(page, asid, t)	0
 #define HT_SLOT_EMPTY_ARCH(t)		1
+#define HT_INVALIDATE_SLOT_ARCH(t)
 #define HT_GET_NEXT_ARCH(t)		0
 #define HT_SET_NEXT_ARCH(t, s)
Index: genarch/include/mm/page_ht.h
===================================================================
--- genarch/include/mm/page_ht.h	(revision 4a2f4bb11f3b7c88eee45262b755ff5f2f153dc1)
+++ genarch/include/mm/page_ht.h	(revision 2a003d5b70d5a4307a6cbdff215872746300cb53)
@@ -37,4 +37,8 @@
 
 #include <mm/page.h>
+#include <typedefs.h>
+
+/** Number of slots in page hash table. */
+#define HT_ENTRIES			HT_ENTRIES_ARCH
 
 /** Hash function.
@@ -57,5 +61,5 @@
 #define HT_COMPARE(page, asid, t)	HT_COMPARE_ARCH(page, asid, t)
 
-/** Identify empty hash table slots.
+/** Identify empty page hash table slots.
  *
  * @param t Pointer ro hash table typed pte_t *.
@@ -64,4 +68,10 @@
  */
 #define HT_SLOT_EMPTY(t)		HT_SLOT_EMPTY_ARCH(t)
+
+/** Invalidate/empty page hash table slot.
+ *
+ * @param t Address of the slot to be invalidated.
+ */
+#define HT_INVALIDATE_SLOT(t)		HT_INVALIDATE_SLOT_ARCH(t)
 
 /** Return next record in collision chain.
@@ -90,5 +100,11 @@
 #define HT_SET_RECORD(t, page, asid, frame, flags)	HT_SET_RECORD_ARCH(t, page, asid, frame, flags)
 
+
 extern page_operations_t page_ht_operations;
+extern spinlock_t page_ht_lock;
+
+extern pte_t *page_ht;
+
+extern void ht_invalidate_all(void);
 
 #endif
Index: genarch/src/mm/page_ht.c
===================================================================
--- genarch/src/mm/page_ht.c	(revision 4a2f4bb11f3b7c88eee45262b755ff5f2f153dc1)
+++ genarch/src/mm/page_ht.c	(revision 2a003d5b70d5a4307a6cbdff215872746300cb53)
@@ -35,5 +35,21 @@
 #include <typedefs.h>
 #include <arch/asm.h>
+#include <synch/spinlock.h>
+#include <arch.h>
 #include <debug.h>
+
+/**
+ * This lock protects the page hash table. Note that software must
+ * be still careful about ordering of writes to ensure consistent
+ * view of the page hash table for hardware helpers such as VHPT
+ * walker on ia64.
+ */
+SPINLOCK_INITIALIZE(page_ht_lock);
+
+/**
+ * Page hash table pointer.
+ * The page hash table may be accessed only when page_ht_lock is held.
+ */
+pte_t *page_ht = NULL;
 
 static void ht_mapping_insert(__address page, asid_t asid, __address frame, int flags, __address root);
@@ -48,5 +64,7 @@
  *
  * Map virtual address 'page' to physical address 'frame'
- * using 'flags'.
+ * using 'flags'. In order not to disturb hardware searching,
+ * new mappings are appended to the end of the collision
+ * chain.
  *
  * @param page Virtual address of the page to be mapped.
@@ -58,15 +76,43 @@
 void ht_mapping_insert(__address page, asid_t asid, __address frame, int flags, __address root)
 {
-	pte_t *t, *u = NULL;
+	pte_t *t, *u;
+	ipl_t ipl;
+	
+	ipl = interrupts_disable();
+	spinlock_lock(&page_ht_lock);
 	
 	t = HT_HASH(page, asid);
 	if (!HT_SLOT_EMPTY(t)) {
-		u = (pte_t *) malloc(sizeof(pte_t));	/* FIXME: use slab allocator for this */
-		if (!u)
-			panic("could not allocate memory for hash table\n");
-		*u = *t;
+	
+		/*
+		 * The slot is occupied.
+		 * Walk through the collision chain and append the mapping to its end.
+		 */
+		 
+		do {
+			u = t;
+			if (HT_COMPARE(page, asid, t)) {
+				/*
+				 * Nothing to do,
+				 * the record is already there.
+				 */
+				spinlock_unlock(&page_ht_lock);
+				interrupts_restore(ipl);
+				return;
+			}
+		} while ((t = HT_GET_NEXT(t)));
+	
+		t = (pte_t *) malloc(sizeof(pte_t));	/* FIXME: use slab allocator for this */
+		if (!t)
+			panic("could not allocate memory\n");
+
+		HT_SET_NEXT(u, t);
 	}
-	HT_SET_NEXT(t, u);
+	
 	HT_SET_RECORD(t, page, asid, frame, flags);
+	HT_SET_NEXT(t, NULL);
+	
+	spinlock_unlock(&page_ht_lock);
+	interrupts_restore(ipl);
 }
 
@@ -74,4 +120,6 @@
  *
  * Find mapping for virtual page.
+ *
+ * Interrupts must be disabled.
  *
  * @param page Virtual page.
@@ -85,8 +133,38 @@
 	pte_t *t;
 	
+	spinlock_lock(&page_ht_lock);
 	t = HT_HASH(page, asid);
-	while (!HT_COMPARE(page, asid, t) && HT_GET_NEXT(t))
-		t = HT_GET_NEXT(t);
+	if (!HT_SLOT_EMPTY(t)) {
+		while (!HT_COMPARE(page, asid, t) && HT_GET_NEXT(t))
+			t = HT_GET_NEXT(t);
+		t = HT_COMPARE(page, asid, t) ? t : NULL;
+	} else {
+		t = NULL;
+	}
+	spinlock_unlock(&page_ht_lock);
+	return t;
+}
+
+/** Invalidate page hash table.
+ *
+ * Interrupts must be disabled.
+ */
+void ht_invalidate_all(void)
+{
+	pte_t *t, *u;
+	int i;
 	
-	return HT_COMPARE(page, asid, t) ? t : NULL;
+	spinlock_lock(&page_ht_lock);
+	for (i = 0; i < HT_ENTRIES; i++) {
+		if (!HT_SLOT_EMPTY(&page_ht[i])) {
+			t = HT_GET_NEXT(&page_ht[i]);
+			while (t) {
+				u = t;
+				t = HT_GET_NEXT(t);
+				free(u);		/* FIXME: use slab allocator for this */
+			}
+			HT_INVALIDATE_SLOT(&page_ht[i]);
+		}
+	}
+	spinlock_unlock(&page_ht_lock);
 }
