Index: kernel/arch/arm32/include/arch/cp15.h
===================================================================
--- kernel/arch/arm32/include/arch/cp15.h	(revision 8ff767bf9deeb6028783af67da985d5d5301172c)
+++ kernel/arch/arm32/include/arch/cp15.h	(revision 0c40fd50243688f325f369871c3ae638910d5aec)
@@ -301,4 +301,15 @@
 
 /* Memory protection and control registers */
+enum {
+	TTBR_ADDR_MASK = 0xffffff80,
+	TTBR_NOS_FLAG = 1 << 5,
+	TTBR_RGN_MASK = 0x3 << 3,
+	TTBR_RGN_NO_CACHE = 0x0 << 3,
+	TTBR_RGN_WBWA_CACHE = 0x1 << 3,
+	TTBR_RGN_WT_CACHE = 0x2 << 3,
+	TTBR_RGN_WB_CACHE = 0x3 << 3,
+	TTBR_S_FLAG = 1 << 1,
+	TTBR_C_FLAG = 1 << 0,
+};
 CONTROL_REG_GEN_READ(TTBR0, c2, 0, c0, 0);
 CONTROL_REG_GEN_WRITE(TTBR0, c2, 0, c0, 0);
Index: kernel/arch/arm32/include/arch/mm/page.h
===================================================================
--- kernel/arch/arm32/include/arch/mm/page.h	(revision 8ff767bf9deeb6028783af67da985d5d5301172c)
+++ kernel/arch/arm32/include/arch/mm/page.h	(revision 0c40fd50243688f325f369871c3ae638910d5aec)
@@ -145,8 +145,12 @@
  * @param pt Pointer to the page table to set.
  *
+ * Page tables are always in cacheable memory.
+ * Make sure the memory type is correct.
  */
 NO_TRACE static inline void set_ptl0_addr(pte_t *pt)
 {
-	TTBR0_write((uint32_t)pt);
+	uint32_t val = (uint32_t)pt & TTBR_ADDR_MASK;
+	val |= TTBR_RGN_WT_CACHE | TTBR_C_FLAG;
+	TTBR0_write(val);
 }
 
Index: kernel/arch/arm32/include/arch/mm/page_armv4.h
===================================================================
--- kernel/arch/arm32/include/arch/mm/page_armv4.h	(revision 8ff767bf9deeb6028783af67da985d5d5301172c)
+++ kernel/arch/arm32/include/arch/mm/page_armv4.h	(revision 0c40fd50243688f325f369871c3ae638910d5aec)
@@ -120,5 +120,10 @@
 #define PTE_DESCRIPTOR_SMALL_PAGE	2
 
-#define pt_coherence_m(page, count)
+#define pt_coherence_m(pt, count) \
+do { \
+	for (unsigned i = 0; i < count; ++i) \
+		DCCMVAU_write((uintptr_t)(pt + i)); \
+	read_barrier(); \
+} while (0)
 
 /** Returns level 0 page table entry flags.
Index: kernel/arch/arm32/include/arch/mm/page_armv6.h
===================================================================
--- kernel/arch/arm32/include/arch/mm/page_armv6.h	(revision 8ff767bf9deeb6028783af67da985d5d5301172c)
+++ kernel/arch/arm32/include/arch/mm/page_armv6.h	(revision 0c40fd50243688f325f369871c3ae638910d5aec)
@@ -151,10 +151,10 @@
  *
  * ARM Architecture reference chp. B3.10.1 p. B3-1375
- */
-//TODO: DCCMVAU does not work.
+ * @note: see TTRB0/1 for pt memory type
+ */
 #define pt_coherence_m(pt, count) \
 do { \
 	for (unsigned i = 0; i < count; ++i) \
-		DCCMVAC_write((uintptr_t)(pt + i)); \
+		DCCMVAU_write((uintptr_t)(pt + i)); \
 	read_barrier(); \
 } while (0)
@@ -300,5 +300,4 @@
 	p->should_be_zero_0 = 0;
 	p->should_be_zero_1 = 0;
-	write_barrier();
 	p->descriptor_type = PTE_DESCRIPTOR_COARSE_TABLE;
 	pt_coherence(p);
