Index: kernel/genarch/src/mm/page_ht.c
===================================================================
--- kernel/genarch/src/mm/page_ht.c	(revision 38dc82d20695b43a799be28d4fd2b2cd2c5bb785)
+++ kernel/genarch/src/mm/page_ht.c	(revision 346b12a2767bb66df8633e469fd871fea8c43b5c)
@@ -60,4 +60,5 @@
 static void ht_mapping_remove(as_t *, uintptr_t);
 static bool ht_mapping_find(as_t *, uintptr_t, bool, pte_t *);
+static void ht_mapping_update(as_t *, uintptr_t, bool, pte_t *);
 static void ht_mapping_make_global(uintptr_t, size_t);
 
@@ -91,4 +92,5 @@
 	.mapping_remove = ht_mapping_remove,
 	.mapping_find = ht_mapping_find,
+	.mapping_update = ht_mapping_update,
 	.mapping_make_global = ht_mapping_make_global
 };
@@ -245,4 +247,19 @@
 }
 
+static pte_t *ht_mapping_find_internal(as_t *as, uintptr_t page, bool nolock)
+{
+	sysarg_t key[2] = {
+		(uintptr_t) as,
+		page = ALIGN_DOWN(page, PAGE_SIZE)
+	};
+
+	ASSERT(nolock || page_table_locked(as));
+	
+	link_t *cur = hash_table_find(&page_ht, key);
+	if (cur)
+		return hash_table_get_instance(cur, pte_t, link);
+	
+	return NULL;
+}
 
 /** Find mapping for virtual page in page hash table.
@@ -257,16 +274,36 @@
 bool ht_mapping_find(as_t *as, uintptr_t page, bool nolock, pte_t *pte)
 {
-	sysarg_t key[2] = {
-		(uintptr_t) as,
-		page = ALIGN_DOWN(page, PAGE_SIZE)
-	};
-
-	ASSERT(nolock || page_table_locked(as));
-	
-	link_t *cur = hash_table_find(&page_ht, key);
-	if (cur)
-		*pte = *hash_table_get_instance(cur, pte_t, link);
-	
-	return cur != NULL;
+	pte_t *t = ht_mapping_find_internal(as, page, nolock);
+	if (t)
+		*pte = *t;
+	
+	return t != NULL;
+}
+
+/** Update mapping for virtual page in page hash table.
+ *
+ * @param as       Address space to which page belongs.
+ * @param page     Virtual page.
+ * @param nolock   True if the page tables need not be locked.
+ * @param pte      New PTE.
+ */
+void ht_mapping_update(as_t *as, uintptr_t page, bool nolock, pte_t *pte)
+{
+	pte_t *t = ht_mapping_find_internal(as, page, nolock);
+	if (!t)
+		panic("Updating non-existent PTE");
+	
+	ASSERT(pte->as == t->as);
+	ASSERT(pte->page == t->page);
+	ASSERT(pte->frame == t->frame);
+	ASSERT(pte->g == t->g);
+	ASSERT(pte->x == t->x);
+	ASSERT(pte->w == t->w);
+	ASSERT(pte->k == t->k);
+	ASSERT(pte->c == t->c);
+	ASSERT(pte->p == t->p);
+
+	t->a = pte->a;
+	t->d = pte->d;
 }
 
Index: kernel/genarch/src/mm/page_pt.c
===================================================================
--- kernel/genarch/src/mm/page_pt.c	(revision 38dc82d20695b43a799be28d4fd2b2cd2c5bb785)
+++ kernel/genarch/src/mm/page_pt.c	(revision 346b12a2767bb66df8633e469fd871fea8c43b5c)
@@ -54,4 +54,5 @@
 static void pt_mapping_remove(as_t *, uintptr_t);
 static bool pt_mapping_find(as_t *, uintptr_t, bool, pte_t *pte);
+static void pt_mapping_update(as_t *, uintptr_t, bool, pte_t *pte);
 static void pt_mapping_make_global(uintptr_t, size_t);
 
@@ -60,4 +61,5 @@
 	.mapping_remove = pt_mapping_remove,
 	.mapping_find = pt_mapping_find,
+	.mapping_update = pt_mapping_update,
 	.mapping_make_global = pt_mapping_make_global
 };
@@ -289,4 +291,41 @@
 }
 
+static pte_t *pt_mapping_find_internal(as_t *as, uintptr_t page, bool nolock)
+{
+	ASSERT(nolock || page_table_locked(as));
+
+	pte_t *ptl0 = (pte_t *) PA2KA((uintptr_t) as->genarch.page_table);
+	if (GET_PTL1_FLAGS(ptl0, PTL0_INDEX(page)) & PAGE_NOT_PRESENT)
+		return NULL;
+
+	read_barrier();
+	
+	pte_t *ptl1 = (pte_t *) PA2KA(GET_PTL1_ADDRESS(ptl0, PTL0_INDEX(page)));
+	if (GET_PTL2_FLAGS(ptl1, PTL1_INDEX(page)) & PAGE_NOT_PRESENT)
+		return NULL;
+
+#if (PTL1_ENTRIES != 0)
+	/*
+	 * Always read ptl2 only after we are sure it is present.
+	 */
+	read_barrier();
+#endif
+	
+	pte_t *ptl2 = (pte_t *) PA2KA(GET_PTL2_ADDRESS(ptl1, PTL1_INDEX(page)));
+	if (GET_PTL3_FLAGS(ptl2, PTL2_INDEX(page)) & PAGE_NOT_PRESENT)
+		return NULL;
+
+#if (PTL2_ENTRIES != 0)
+	/*
+	 * Always read ptl3 only after we are sure it is present.
+	 */
+	read_barrier();
+#endif
+	
+	pte_t *ptl3 = (pte_t *) PA2KA(GET_PTL3_ADDRESS(ptl2, PTL2_INDEX(page)));
+	
+	return &ptl3[PTL3_INDEX(page)];
+}
+
 /** Find mapping for virtual page in hierarchical page tables.
  *
@@ -300,38 +339,30 @@
 bool pt_mapping_find(as_t *as, uintptr_t page, bool nolock, pte_t *pte)
 {
-	ASSERT(nolock || page_table_locked(as));
-
-	pte_t *ptl0 = (pte_t *) PA2KA((uintptr_t) as->genarch.page_table);
-	if (GET_PTL1_FLAGS(ptl0, PTL0_INDEX(page)) & PAGE_NOT_PRESENT)
-		return false;
-
-	read_barrier();
-	
-	pte_t *ptl1 = (pte_t *) PA2KA(GET_PTL1_ADDRESS(ptl0, PTL0_INDEX(page)));
-	if (GET_PTL2_FLAGS(ptl1, PTL1_INDEX(page)) & PAGE_NOT_PRESENT)
-		return false;
-
-#if (PTL1_ENTRIES != 0)
-	/*
-	 * Always read ptl2 only after we are sure it is present.
-	 */
-	read_barrier();
-#endif
-	
-	pte_t *ptl2 = (pte_t *) PA2KA(GET_PTL2_ADDRESS(ptl1, PTL1_INDEX(page)));
-	if (GET_PTL3_FLAGS(ptl2, PTL2_INDEX(page)) & PAGE_NOT_PRESENT)
-		return false;
-
-#if (PTL2_ENTRIES != 0)
-	/*
-	 * Always read ptl3 only after we are sure it is present.
-	 */
-	read_barrier();
-#endif
-	
-	pte_t *ptl3 = (pte_t *) PA2KA(GET_PTL3_ADDRESS(ptl2, PTL2_INDEX(page)));
-	
-	*pte = ptl3[PTL3_INDEX(page)];
-	return true;
+	pte_t *t = pt_mapping_find_internal(as, page, nolock);
+	if (t)
+		*pte = *t;
+	return t != NULL;
+}
+
+/** Update mapping for virtual page in hierarchical page tables.
+ *
+ * @param as       Address space to which page belongs.
+ * @param page     Virtual page.
+ * @param nolock   True if the page tables need not be locked.
+ * @param[in] pte  New PTE.
+ */
+void pt_mapping_update(as_t *as, uintptr_t page, bool nolock, pte_t *pte)
+{
+	pte_t *t = pt_mapping_find_internal(as, page, nolock);
+	if (!t)
+		panic("Updating non-existent PTE");	
+
+	ASSERT(PTE_VALID(t) == PTE_VALID(pte));
+	ASSERT(PTE_PRESENT(t) == PTE_PRESENT(pte));
+	ASSERT(PTE_GET_FRAME(t) == PTE_GET_FRAME(pte));
+	ASSERT(PTE_WRITABLE(t) == PTE_WRITABLE(pte));
+	ASSERT(PTE_EXECUTABLE(t) == PTE_EXECUTABLE(pte));
+
+	*t = *pte;
 }
 
