Index: arch/ia64/include/mm/asid.h
===================================================================
--- arch/ia64/include/mm/asid.h	(revision 849386a07eb8c9ccdf6283b866a86ee0c59052bc)
+++ arch/ia64/include/mm/asid.h	(revision 457d18ab5e0f7c0463835d670622bae2fc50be71)
@@ -43,4 +43,9 @@
 #define RID_OVERFLOW		16777216	/* 2^24 */
 
+#define ASID2RID(asid, vrn)	(((asid)*RIDS_PER_ASID)+(vrn))
+#define RID2ASID(rid)		((rid)/RIDS_PER_ASID)
+
+typedef __u32 rid_t;
+
 /**
  * This macro is needed only to compile the kernel.
Index: arch/ia64/include/mm/page.h
===================================================================
--- arch/ia64/include/mm/page.h	(revision 849386a07eb8c9ccdf6283b866a86ee0c59052bc)
+++ arch/ia64/include/mm/page.h	(revision 457d18ab5e0f7c0463835d670622bae2fc50be71)
@@ -33,4 +33,5 @@
 #include <arch/mm/frame.h>
 #include <genarch/mm/page_ht.h>
+#include <arch/mm/asid.h>
 #include <arch/types.h>
 #include <typedefs.h>
@@ -47,12 +48,14 @@
 
 /** Implementation of page hash table interface. */
-#define HT_ENTRIES_ARCH			(VHPT_SIZE/sizeof(pte_t))
-#define HT_HASH_ARCH(page, asid)	vhpt_hash((page), (asid))
-#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)
-#define HT_SET_RECORD_ARCH(t, page, asid, frame, flags)
+#define HT_ENTRIES_ARCH					(VHPT_SIZE/sizeof(pte_t))
+#define HT_HASH_ARCH(page, asid)			vhpt_hash((page), (asid))
+#define HT_COMPARE_ARCH(page, asid, t)			vhpt_compare((page), (asid), (t))
+#define HT_SLOT_EMPTY_ARCH(t)				((t)->present.tag.tag_info.ti)
+#define HT_INVALIDATE_SLOT_ARCH(t)			(t)->present.tag.tag_info.ti = true
+#define HT_GET_NEXT_ARCH(t)				(t)->present.next
+#define HT_SET_NEXT_ARCH(t, s)				(t)->present.next = (s)
+#define HT_SET_RECORD_ARCH(t, page, asid, frame, flags)	vhpt_set_record(t, page, asid, frame, flags)
+
+#define PPN_SHIFT			12
 
 #define VRN_SHIFT			61
@@ -60,5 +63,4 @@
 
 #define VRN_KERNEL	 		0
-#define VRN_WORK			1LL
 #define REGION_REGISTERS 		8
 
@@ -67,4 +69,17 @@
 
 #define VHPT_BASE 			page_ht		/* Must be aligned to VHPT_SIZE */
+
+/** Memory Attributes. */
+#define MA_WRITEBACK	0x0
+#define MA_UNCACHEABLE	0x4
+
+/** Privilege Levels. Only the most and the least privileged ones are ever used. */
+#define PL_KERNEL	0x0
+#define PL_USER		0x3
+
+/* Access Rigths. Only certain combinations are used by the kernel. */
+#define AR_READ		0x0
+#define AR_EXECUTE	0x1
+#define AR_WRITE	0x2
 
 struct vhpt_tag_info {
@@ -102,5 +117,5 @@
 	
 	/* Word 3 */													
-	unsigned long long next : 64;	/**< Collision chain next pointer. */
+	pte_t *next;			/**< Collision chain next pointer. */
 } __attribute__ ((packed));
 
@@ -120,5 +135,5 @@
 	
 	/* Word 3 */													
-	unsigned long long next : 64;	/**< Collision chain next pointer. */
+	pte_t *next;			/**< Collision chain next pointer. */
 	
 } __attribute__ ((packed));
@@ -127,4 +142,5 @@
 	struct vhpt_entry_present present;
 	struct vhpt_entry_not_present not_present;
+	__u64 word[4];
 } vhpt_entry;
 
@@ -244,4 +260,6 @@
 extern void page_arch_init(void);
 extern pte_t *vhpt_hash(__address page, asid_t asid);
+extern bool vhpt_compare(__address page, asid_t asid, pte_t *t);
+extern void vhpt_set_record(pte_t *t, __address page, asid_t asid, __address frame, int flags);
 
 #endif
Index: arch/ia64/src/mm/asid.c
===================================================================
--- arch/ia64/src/mm/asid.c	(revision 849386a07eb8c9ccdf6283b866a86ee0c59052bc)
+++ arch/ia64/src/mm/asid.c	(revision 457d18ab5e0f7c0463835d670622bae2fc50be71)
@@ -50,4 +50,5 @@
 #include <mm/asid.h>
 #include <mm/as.h>
+#include <genarch/mm/page_ht.h>
 #include <mm/tlb.h>
 #include <list.h>
@@ -105,4 +106,15 @@
 			spinlock_unlock(&as->lock);
 		}
+		
+		/*
+		 * The page hash table uses VHPT long format PTE's.
+		 * Unfortunatelly, this format has no space to
+		 * store as_t pointer, so it is necessary to
+		 * invalidate the whole structure after all ASIDs
+		 * have been reassigned. The information swept out
+		 * from the page hash table can be later reconstructed
+		 * from as_t structures on demand.
+		 */
+		ht_invalidate_all();
 
 		/*
Index: arch/ia64/src/mm/page.c
===================================================================
--- arch/ia64/src/mm/page.c	(revision 849386a07eb8c9ccdf6283b866a86ee0c59052bc)
+++ arch/ia64/src/mm/page.c	(revision 457d18ab5e0f7c0463835d670622bae2fc50be71)
@@ -31,5 +31,7 @@
 #include <genarch/mm/page_ht.h>
 #include <mm/asid.h>
+#include <arch/mm/asid.h>
 #include <arch/types.h>
+#include <typedefs.h>
 #include <print.h>
 #include <mm/page.h>
@@ -41,6 +43,16 @@
 #include <memstr.h>
 
+static void set_vhpt_environment(void);
+
+/** Initialize ia64 virtual address translation subsystem. */
+void page_arch_init(void)
+{
+	page_operations = &page_ht_operations;
+	pk_disable();
+	set_vhpt_environment();
+}
+
 /** Initialize VHPT and region registers. */
-static void set_vhpt_environment(void)
+void set_vhpt_environment(void)
 {
 	region_register rr;
@@ -95,20 +107,7 @@
 }
 
-/** Initialize ia64 virtual address translation subsystem. */
-void page_arch_init(void)
-{
-	page_operations = &page_ht_operations;
-	pk_disable();
-	set_vhpt_environment();
-}
-
 /** Calculate address of collision chain from VPN and ASID.
  *
- * This is rather non-trivial function.
- * First, it has to translate ASID to RID.
- * This is achieved by taking VRN bits of
- * page into account.
- * Second, it must preserve the region register
- * it writes the RID to.
+ * Interrupts must be disabled.
  *
  * @param page Address of virtual page including VRN bits.
@@ -120,16 +119,30 @@
 {
 	region_register rr_save, rr;
+	index_t vrn;
+	rid_t rid;
 	pte_t *t;
 
-	rr_save.word = rr_read(VRN_WORK);
+	vrn = page >> VRN_SHIFT;
+	rid = ASID2RID(asid, vrn);
+	
+	rr_save.word = rr_read(vrn);
+	if (rr_save.map.rid == rid) {
+		/*
+		 * The RID is already in place, compute thash and return.
+		 */
+		t = (pte_t *) thash(page);
+		return t;
+	}
+	
+	/*
+	 * The RID must be written to some region register.
+	 * To speed things up, register indexed by vrn is used.
+	 */
 	rr.word = rr_save.word;
-	if ((page >> VRN_SHIFT) != VRN_KERNEL)
-		rr.map.rid = (asid * RIDS_PER_ASID) + (page >> VRN_SHIFT);
-	else
-		rr.map.rid = ASID_KERNEL;
-	rr_write(VRN_WORK, rr.word);
-	srlz_i();
-	t = (pte_t *) thash((VRN_WORK << VRN_SHIFT) | (~(VRN_MASK) & page));
-	rr_write(VRN_WORK, rr_save.word);
+	rr.map.rid = rid;
+	rr_write(vrn, rr.word);
+	srlz_i();
+	t = (pte_t *) thash(page);
+	rr_write(vrn, rr_save.word);
 	srlz_i();
 	srlz_d();
@@ -137,2 +150,103 @@
 	return t;
 }
+
+/** Compare ASID and VPN against PTE.
+ *
+ * Interrupts must be disabled.
+ *
+ * @param page Address of virtual page including VRN bits.
+ * @param asid Address space identifier.
+ *
+ * @return True if page and asid match the page and asid of t, false otherwise.
+ */
+bool vhpt_compare(__address page, asid_t asid, pte_t *t)
+{
+	region_register rr_save, rr;	
+	index_t vrn;
+	rid_t rid;
+	bool match;
+
+	ASSERT(t);
+
+	vrn = page >> VRN_SHIFT;
+	rid = ASID2RID(asid, vrn);
+	
+	rr_save.word = rr_read(vrn);
+	if (rr_save.map.rid == rid) {
+		/*
+		 * The RID is already in place, compare ttag with t and return.
+		 */
+		return ttag(page) == t->present.tag.tag_word;
+	}
+	
+	/*
+	 * The RID must be written to some region register.
+	 * To speed things up, register indexed by vrn is used.
+	 */
+	rr.word = rr_save.word;
+	rr.map.rid = rid;
+	rr_write(vrn, rr.word);
+	srlz_i();
+	match = (ttag(page) == t->present.tag.tag_word);
+	rr_write(vrn, rr_save.word);
+	srlz_i();
+	srlz_d();
+
+	return match;		
+}
+
+/** Set up one VHPT entry.
+ *
+ * @param t VHPT entry to be set up.
+ * @param page Virtual address of the page mapped by the entry.
+ * @param asid Address space identifier of the address space to which page belongs.
+ * @param frame Physical address of the frame to wich page is mapped.
+ * @param flags Different flags for the mapping.
+ */
+void vhpt_set_record(pte_t *t, __address page, asid_t asid, __address frame, int flags)
+{
+	region_register rr_save, rr;	
+	index_t vrn;
+	rid_t rid;
+	__u64 tag;
+
+	ASSERT(t);
+
+	vrn = page >> VRN_SHIFT;
+	rid = ASID2RID(asid, vrn);
+	
+	/*
+	 * Compute ttag.
+	 */
+	rr_save.word = rr_read(vrn);
+	rr.word = rr_save.word;
+	rr.map.rid = rid;
+	rr_write(vrn, rr.word);
+	srlz_i();
+	tag = ttag(page);
+	rr_write(vrn, rr_save.word);
+	srlz_i();
+	srlz_d();
+	
+	/*
+	 * Clear the entry.
+	 */
+	t->word[0] = 0;
+	t->word[1] = 0;
+	t->word[2] = 0;
+	t->word[3] = 0;
+	
+	t->present.p = true;
+	t->present.ma = (flags & PAGE_CACHEABLE) ? MA_WRITEBACK : MA_UNCACHEABLE;
+	t->present.a = false;	/* not accessed */
+	t->present.d = false;	/* not dirty */
+	t->present.pl = (flags & PAGE_USER) ? PL_USER : PL_KERNEL;
+	t->present.ar = (flags & PAGE_WRITE) ? AR_WRITE : AR_READ;
+	t->present.ar |= (flags & PAGE_EXEC) ? AR_EXECUTE : 0; 
+	t->present.ppn = frame >> PPN_SHIFT;
+	t->present.ed = false;	/* exception not deffered */
+	t->present.ps = PAGE_WIDTH;
+	t->present.key = 0;
+	t->present.tag.tag_word = tag;
+	t->present.next = NULL;
+}
