Index: kernel/arch/amd64/src/ddi/ddi.c
===================================================================
--- kernel/arch/amd64/src/ddi/ddi.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/amd64/src/ddi/ddi.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -42,4 +42,5 @@
 #include <errno.h>
 #include <arch/cpu.h>
+#include <cpu.h>
 #include <arch.h>
 #include <align.h>
@@ -58,27 +59,28 @@
 int ddi_iospace_enable_arch(task_t *task, uintptr_t ioaddr, size_t size)
 {
-	size_t bits = ioaddr + size;
-	if (bits > IO_PORTS)
+	size_t elements = ioaddr + size;
+	if (elements > IO_PORTS)
 		return ENOENT;
 	
-	if (task->arch.iomap.bits < bits) {
+	if (task->arch.iomap.elements < elements) {
 		/*
 		 * The I/O permission bitmap is too small and needs to be grown.
 		 */
 		
-		uint8_t *newmap = (uint8_t *) malloc(BITS2BYTES(bits), FRAME_ATOMIC);
-		if (!newmap)
+		void *store = malloc(bitmap_size(elements, 0), FRAME_ATOMIC);
+		if (!store)
 			return ENOMEM;
 		
 		bitmap_t oldiomap;
-		bitmap_initialize(&oldiomap, task->arch.iomap.map,
+		bitmap_initialize(&oldiomap, task->arch.iomap.elements, 0,
 		    task->arch.iomap.bits);
-		bitmap_initialize(&task->arch.iomap, newmap, bits);
+		
+		bitmap_initialize(&task->arch.iomap, elements, 0, store);
 		
 		/*
 		 * Mark the new range inaccessible.
 		 */
-		bitmap_set_range(&task->arch.iomap, oldiomap.bits,
-		    bits - oldiomap.bits);
+		bitmap_set_range(&task->arch.iomap, oldiomap.elements,
+		    elements - oldiomap.elements);
 		
 		/*
@@ -88,6 +90,7 @@
 		if (oldiomap.bits) {
 			bitmap_copy(&task->arch.iomap, &oldiomap,
-			    oldiomap.bits);
-			free(oldiomap.map);
+			    oldiomap.elements);
+			
+			free(oldiomap.bits);
 		}
 	}
@@ -96,5 +99,5 @@
 	 * Enable the range and we are done.
 	 */
-	bitmap_clear_range(&task->arch.iomap, (size_t) ioaddr, (size_t) size);
+	bitmap_clear_range(&task->arch.iomap, (size_t) ioaddr, size);
 	
 	/*
@@ -118,13 +121,15 @@
 	/* First, copy the I/O Permission Bitmap. */
 	irq_spinlock_lock(&TASK->lock, false);
+	
 	size_t ver = TASK->arch.iomapver;
-	size_t bits = TASK->arch.iomap.bits;
-	if (bits) {
-		ASSERT(TASK->arch.iomap.map);
+	size_t elements = TASK->arch.iomap.elements;
+	
+	if (elements > 0) {
+		ASSERT(TASK->arch.iomap.bits);
 		
 		bitmap_t iomap;
-		bitmap_initialize(&iomap, CPU->arch.tss->iomap,
-		    TSS_IOMAP_SIZE * 8);
-		bitmap_copy(&iomap, &TASK->arch.iomap, bits);
+		bitmap_initialize(&iomap, TSS_IOMAP_SIZE * 8, 0,
+		    CPU->arch.tss->iomap);
+		bitmap_copy(&iomap, &TASK->arch.iomap, elements);
 		
 		/*
@@ -132,16 +137,19 @@
 		 * I/O access.
 		 */
-		bitmap_set_range(&iomap, bits, ALIGN_UP(bits, 8) - bits);
+		bitmap_set_range(&iomap, elements,
+		    ALIGN_UP(elements, 8) - elements);
+		
 		/*
 		 * It is safe to set the trailing eight bits because of the
 		 * extra convenience byte in TSS_IOMAP_SIZE.
 		 */
-		bitmap_set_range(&iomap, ALIGN_UP(bits, 8), 8);
+		bitmap_set_range(&iomap, ALIGN_UP(elements, 8), 8);
 	}
+	
 	irq_spinlock_unlock(&TASK->lock, false);
 	
 	/*
 	 * Second, adjust TSS segment limit.
-	 * Take the extra ending byte will all bits set into account. 
+	 * Take the extra ending byte with all bits set into account.
 	 */
 	ptr_16_64_t cpugdtr;
@@ -149,5 +157,6 @@
 	
 	descriptor_t *gdt_p = (descriptor_t *) cpugdtr.base;
-	gdt_tss_setlimit(&gdt_p[TSS_DES], TSS_BASIC_SIZE + BITS2BYTES(bits));
+	size_t size = bitmap_size(elements, 0);
+	gdt_tss_setlimit(&gdt_p[TSS_DES], TSS_BASIC_SIZE + size);
 	gdtr_load(&cpugdtr);
 	
Index: kernel/arch/amd64/src/proc/task.c
===================================================================
--- kernel/arch/amd64/src/proc/task.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/amd64/src/proc/task.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -34,6 +34,7 @@
 
 #include <proc/task.h>
+#include <typedefs.h>
+#include <adt/bitmap.h>
 #include <mm/slab.h>
-#include <typedefs.h>
 
 /** Perform amd64 specific task initialization.
@@ -45,5 +46,5 @@
 {
 	task->arch.iomapver = 0;
-	bitmap_initialize(&task->arch.iomap, NULL, 0);
+	bitmap_initialize(&task->arch.iomap, 0, 0, NULL);
 }
 
@@ -55,6 +56,6 @@
 void task_destroy_arch(task_t *task)
 {
-	if (task->arch.iomap.map)
-		free(task->arch.iomap.map);
+	if (task->arch.iomap.bits != NULL)
+		free(task->arch.iomap.bits);
 }
 
Index: kernel/arch/arm32/include/arch/asm.h
===================================================================
--- kernel/arch/arm32/include/arch/asm.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/arm32/include/arch/asm.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -38,4 +38,5 @@
 
 #include <typedefs.h>
+#include <arch/cp15.h>
 #include <arch/stack.h>
 #include <config.h>
@@ -51,7 +52,7 @@
  * chapter 2.3.8 p.2-22 (52 in the PDF)
  *
- * @note Although mcr p15, 0, R0, c7, c0, 4 is defined in ARM Architecture
- * reference manual for armv4/5 CP15 implementation is mandatory only for
- * armv6+.
+ * @note Although CP15WFI (mcr p15, 0, R0, c7, c0, 4) is defined in ARM
+ * Architecture reference manual for armv4/5, CP15 implementation is mandatory
+ * only for armv6+.
  */
 NO_TRACE static inline void cpu_sleep(void)
@@ -60,5 +61,5 @@
 	asm volatile ( "wfe" );
 #elif defined(PROCESSOR_ARCH_armv6) | defined(PROCESSOR_arm926ej_s) | defined(PROCESSOR_arm920t)
-	asm volatile ( "mcr p15, 0, R0, c7, c0, 4" );
+	WFI_write(0);
 #endif
 }
Index: kernel/arch/arm32/include/arch/cp15.h
===================================================================
--- kernel/arch/arm32/include/arch/cp15.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/arm32/include/arch/cp15.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -171,4 +171,11 @@
 	CCSIDR_LINESIZE_MASK = 0x7,
 	CCSIDR_LINESIZE_SHIFT = 0,
+#define CCSIDR_SETS(val) \
+	(((val >> CCSIDR_NUMSETS_SHIFT) & CCSIDR_NUMSETS_MASK) + 1)
+#define CCSIDR_WAYS(val) \
+	(((val >> CCSIDR_ASSOC_SHIFT) & CCSIDR_ASSOC_MASK) + 1)
+/* The register value is log(linesize_in_words) - 2 */
+#define CCSIDR_LINESIZE_LOG(val) \
+	(((val >> CCSIDR_LINESIZE_SHIFT) & CCSIDR_LINESIZE_MASK) + 2 + 2)
 };
 CONTROL_REG_GEN_READ(CCSIDR, c0, 1, c0, 0);
@@ -187,5 +194,6 @@
 	CLIDR_UNI_CACHE = 0x4,
 	CLIDR_CACHE_MASK = 0x7,
-#define CLIDR_CACHE(level, val)   ((val >> (level - 1) * 3) & CLIDR_CACHE_MASK)
+/** levels counted from 0 */
+#define CLIDR_CACHE(level, val)   ((val >> (level * 3)) & CLIDR_CACHE_MASK)
 };
 CONTROL_REG_GEN_READ(CLIDR, c0, 1, c0, 1);
@@ -293,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);
@@ -363,5 +382,5 @@
 
 CONTROL_REG_GEN_WRITE(DCIMVAC, c7, 0, c6, 1);
-CONTROL_REG_GEN_WRITE(DCIMSW, c7, 0, c6, 2);
+CONTROL_REG_GEN_WRITE(DCISW, c7, 0, c6, 2);
 
 CONTROL_REG_GEN_WRITE(ATS1CPR, c7, 0, c8, 0);
@@ -369,8 +388,8 @@
 CONTROL_REG_GEN_WRITE(ATS1CUR, c7, 0, c8, 2);
 CONTROL_REG_GEN_WRITE(ATS1CUW, c7, 0, c8, 3);
-CONTROL_REG_GEN_WRITE(ATS1NSOPR, c7, 0, c8, 4);
-CONTROL_REG_GEN_WRITE(ATS1NSOPW, c7, 0, c8, 5);
-CONTROL_REG_GEN_WRITE(ATS1NSOUR, c7, 0, c8, 6);
-CONTROL_REG_GEN_WRITE(ATS1NSOUW, c7, 0, c8, 7);
+CONTROL_REG_GEN_WRITE(ATS12NSOPR, c7, 0, c8, 4);
+CONTROL_REG_GEN_WRITE(ATS12NSOPW, c7, 0, c8, 5);
+CONTROL_REG_GEN_WRITE(ATS12NSOUR, c7, 0, c8, 6);
+CONTROL_REG_GEN_WRITE(ATS12NSOUW, c7, 0, c8, 7);
 
 
Index: kernel/arch/arm32/include/arch/mm/page.h
===================================================================
--- kernel/arch/arm32/include/arch/mm/page.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/arm32/include/arch/mm/page.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -41,4 +41,5 @@
 #include <arch/exception.h>
 #include <arch/barrier.h>
+#include <arch/cp15.h>
 #include <trace.h>
 
@@ -95,11 +96,11 @@
 /* Set PTE address accessors for each level. */
 #define SET_PTL0_ADDRESS_ARCH(ptl0) \
-        (set_ptl0_addr((pte_t *) (ptl0)))
+	set_ptl0_addr((pte_t *) (ptl0))
 #define SET_PTL1_ADDRESS_ARCH(ptl0, i, a) \
-        (((pte_t *) (ptl0))[(i)].l0.coarse_table_addr = (a) >> 10)
+	set_ptl1_addr((pte_t*) (ptl0), i, a)
 #define SET_PTL2_ADDRESS_ARCH(ptl1, i, a)
 #define SET_PTL3_ADDRESS_ARCH(ptl2, i, a)
 #define SET_FRAME_ADDRESS_ARCH(ptl3, i, a) \
-        (((pte_t *) (ptl3))[(i)].l1.frame_base_addr = (a) >> 12)
+	set_ptl3_addr((pte_t*) (ptl3), i, a)
 
 /* Get PTE flags accessors for each level. */
@@ -129,4 +130,7 @@
 	set_pt_level1_present((pte_t *) (ptl3), (size_t) (i))
 
+
+#define pt_coherence(page) pt_coherence_m(page, 1)
+
 #if defined(PROCESSOR_ARCH_armv6) | defined(PROCESSOR_ARCH_armv7_a)
 #include "page_armv6.h"
@@ -137,4 +141,33 @@
 #endif
 
+/** Sets the address of level 0 page table.
+ *
+ * @param pt Pointer to the page table to set.
+ *
+ * Page tables are always in cacheable memory.
+ * Make sure the memory type is correct, and in sync with:
+ * init_boot_pt (boot/arch/arm32/src/mm.c)
+ * init_ptl0_section (boot/arch/arm32/src/mm.c)
+ * set_pt_level1_flags (kernel/arch/arm32/include/arch/mm/page_armv6.h)
+ */
+NO_TRACE static inline void set_ptl0_addr(pte_t *pt)
+{
+	uint32_t val = (uint32_t)pt & TTBR_ADDR_MASK;
+	val |= TTBR_RGN_WBWA_CACHE | TTBR_C_FLAG;
+	TTBR0_write(val);
+}
+
+NO_TRACE static inline void set_ptl1_addr(pte_t *pt, size_t i, uintptr_t address)
+{
+	pt[i].l0.coarse_table_addr = address >> 10;
+	pt_coherence(&pt[i].l0);
+}
+
+NO_TRACE static inline void set_ptl3_addr(pte_t *pt, size_t i, uintptr_t address)
+{
+	pt[i].l1.frame_base_addr = address >> 12;
+	pt_coherence(&pt[i].l1);
+}
+
 #endif
 
Index: kernel/arch/arm32/include/arch/mm/page_armv4.h
===================================================================
--- kernel/arch/arm32/include/arch/mm/page_armv4.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/arm32/include/arch/mm/page_armv4.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -120,18 +120,10 @@
 #define PTE_DESCRIPTOR_SMALL_PAGE	2
 
-
-/** Sets the address of level 0 page table.
- *
- * @param pt Pointer to the page table to set.
- *
- */
-NO_TRACE static inline void set_ptl0_addr(pte_t *pt)
-{
-	asm volatile (
-		"mcr p15, 0, %[pt], c2, c0, 0\n"
-		:: [pt] "r" (pt)
-	);
-}
-
+#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.
@@ -223,5 +215,5 @@
 	
 	/* default access permission */
-	p->access_permission_0 = p->access_permission_1 = 
+	p->access_permission_0 = p->access_permission_1 =
 	    p->access_permission_2 = p->access_permission_3 =
 	    PTE_AP_USER_NO_KERNEL_RW;
@@ -229,12 +221,12 @@
 	if (flags & PAGE_USER)  {
 		if (flags & PAGE_READ) {
-			p->access_permission_0 = p->access_permission_1 = 
-			    p->access_permission_2 = p->access_permission_3 = 
+			p->access_permission_0 = p->access_permission_1 =
+			    p->access_permission_2 = p->access_permission_3 =
 			    PTE_AP_USER_RO_KERNEL_RW;
 		}
 		if (flags & PAGE_WRITE) {
-			p->access_permission_0 = p->access_permission_1 = 
-			    p->access_permission_2 = p->access_permission_3 = 
-			    PTE_AP_USER_RW_KERNEL_RW; 
+			p->access_permission_0 = p->access_permission_1 =
+			    p->access_permission_2 = p->access_permission_3 =
+			    PTE_AP_USER_RW_KERNEL_RW;
 		}
 	}
Index: kernel/arch/arm32/include/arch/mm/page_armv6.h
===================================================================
--- kernel/arch/arm32/include/arch/mm/page_armv6.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/arm32/include/arch/mm/page_armv6.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -40,4 +40,5 @@
 #error "Do not include arch specific page.h directly use generic page.h instead"
 #endif
+
 
 /* Macros for querying the last-level PTE entries. */
@@ -125,16 +126,37 @@
 #define PTE_DESCRIPTOR_SMALL_PAGE_NX	3
 
-/** Sets the address of level 0 page table.
- *
- * @param pt Pointer to the page table to set.
- *
- */
-NO_TRACE static inline void set_ptl0_addr(pte_t *pt)
-{
-	asm volatile (
-		"mcr p15, 0, %[pt], c2, c0, 0\n"
-		:: [pt] "r" (pt)
-	);
-}
+
+/**
+ * For an ARMv7 implementation that does not include the Large Physical Address Extension,
+ * and in implementations of architecture versions before ARMv7, if the translation tables
+ * are held in Write-Back Cacheable memory, the caches must be cleaned to the point of
+ * unification after writing to the translation tables and before the DSB instruction. This
+ * ensures that the updated translation table are visible to a hardware translation table walk.
+ *
+ * Therefore, an example instruction sequence for writing a translation table entry,
+ * covering changes to the instruction
+ * or data mappings in a uniprocessor system is:
+ * STR rx, [Translation table entry]
+ * ; write new entry to the translation table
+ * Clean cache line [Translation table entry] : This operation is not required with the
+ * ; Multiprocessing Extensions.
+ * DSB
+ * ; ensures visibility of the data cleaned from the D Cache
+ * Invalidate TLB entry by MVA (and ASID if non-global) [page address]
+ * Invalidate BTC
+ * DSB
+ * ; ensure completion of the Invalidate TLB operation
+ * ISB
+ * ; ensure table changes visible to instruction fetch
+ *
+ * ARM Architecture reference chp. B3.10.1 p. B3-1375
+ * @note: see TTRB0/1 for pt memory type
+ */
+#define pt_coherence_m(pt, count) \
+do { \
+	for (unsigned i = 0; i < count; ++i) \
+		DCCMVAU_write((uintptr_t)(pt + i)); \
+	read_barrier(); \
+} while (0)
 
 
@@ -206,4 +228,5 @@
 		p->ns = 0;
 	}
+	pt_coherence(p);
 }
 
@@ -232,15 +255,30 @@
 			p->descriptor_type = PTE_DESCRIPTOR_SMALL_PAGE_NX;
 	}
-	
-	/* tex=0 buf=1 and cache=1 => normal memory
-	 * tex=0 buf=1 and cache=0 => shareable device mmio
-	 */
-	p->cacheable = (flags & PAGE_CACHEABLE);
-	p->bufferable = 1;
-	p->tex = 0;
+
+	if (flags & PAGE_CACHEABLE) {
+		/*
+		 * Write-through, no write-allocate memory, see ch. B3.8.2
+		 * (p. B3-1358) of ARM Architecture reference manual.
+		 * Make sure the memory type is correct, and in sync with:
+		 * init_boot_pt (boot/arch/arm32/src/mm.c)
+		 * init_ptl0_section (boot/arch/arm32/src/mm.c)
+		 * set_ptl0_addr (kernel/arch/arm32/include/arch/mm/page.h)
+		 */
+		p->tex = 5;
+		p->cacheable = 0;
+		p->bufferable = 1;
+	} else {
+		/*
+		 * Shareable device memory, see ch. B3.8.2 (p. B3-1358) of
+		 * ARM Architecture reference manual.
+		 */
+		p->tex = 0;
+		p->cacheable = 0;
+		p->bufferable = 1;
+	}
 	
 	/* Shareable is ignored for devices (non-cacheable),
-	 * turn it on for normal memory. */
-	p->shareable = 1;
+	 * turn it off for normal memory. */
+	p->shareable = 0;
 	
 	p->non_global = !(flags & PAGE_GLOBAL);
@@ -256,4 +294,5 @@
 			p->access_permission_1 = PTE_AP1_RO;
 	}
+	pt_coherence(p);
 }
 
@@ -264,6 +303,6 @@
 	p->should_be_zero_0 = 0;
 	p->should_be_zero_1 = 0;
-	write_barrier();
 	p->descriptor_type = PTE_DESCRIPTOR_COARSE_TABLE;
+	pt_coherence(p);
 }
 
@@ -273,4 +312,5 @@
 
 	p->descriptor_type = PTE_DESCRIPTOR_SMALL_PAGE;
+	pt_coherence(p);
 }
 
Index: kernel/arch/arm32/src/cpu/cpu.c
===================================================================
--- kernel/arch/arm32/src/cpu/cpu.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/arm32/src/cpu/cpu.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -157,5 +157,5 @@
 #endif
 #ifdef PROCESSOR_ARCH_armv7_a
-	 /* ICache coherency is elaborate on in barrier.h.
+	 /* ICache coherency is elaborated on in barrier.h.
 	  * VIPT and PIPT caches need maintenance only on code modify,
 	  * so it should be safe for general use.
@@ -166,4 +166,7 @@
 		control_reg |=
 		    SCTLR_INST_CACHE_EN_FLAG | SCTLR_BRANCH_PREDICT_EN_FLAG;
+	} else {
+		control_reg &=
+		    ~(SCTLR_INST_CACHE_EN_FLAG | SCTLR_BRANCH_PREDICT_EN_FLAG);
 	}
 #endif
@@ -204,7 +207,6 @@
 #ifdef PROCESSOR_ARCH_armv7_a
 	CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT);
-	const unsigned ls_log = 2 +
-	    ((CCSIDR_read() >> CCSIDR_LINESIZE_SHIFT) & CCSIDR_LINESIZE_MASK);
-	return ls_log + 2; //return log2(bytes)
+	const uint32_t ccsidr = CCSIDR_read();
+	return CCSIDR_LINESIZE_LOG(ccsidr);
 #endif
 	return 0;
@@ -217,7 +219,6 @@
 #ifdef PROCESSOR_ARCH_armv7_a
 	CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT);
-	const unsigned ways = 1 +
-	    ((CCSIDR_read() >> CCSIDR_ASSOC_SHIFT) & CCSIDR_ASSOC_MASK);
-	return ways;
+	const uint32_t ccsidr = CCSIDR_read();
+	return CCSIDR_WAYS(ccsidr);
 #endif
 	return 0;
@@ -229,7 +230,6 @@
 #ifdef PROCESSOR_ARCH_armv7_a
 	CSSELR_write((level & CCSELR_LEVEL_MASK) << CCSELR_LEVEL_SHIFT);
-	const unsigned sets = 1 +
-	    ((CCSIDR_read() >> CCSIDR_NUMSETS_SHIFT) & CCSIDR_NUMSETS_MASK);
-	return sets;
+	const uint32_t ccsidr = CCSIDR_read();
+	return CCSIDR_SETS(ccsidr);
 #endif
 	return 0;
@@ -241,5 +241,5 @@
 #ifdef PROCESSOR_ARCH_armv7_a
 	const uint32_t val = CLIDR_read();
-	for (unsigned i = 1; i <= 7; ++i) {
+	for (unsigned i = 0; i < 8; ++i) {
 		const unsigned ctype = CLIDR_CACHE(i, val);
 		switch (ctype) {
@@ -280,5 +280,5 @@
 		const unsigned ways = dcache_ways(i);
 		const unsigned sets = dcache_sets(i);
-		const unsigned way_shift =  31 - log2(ways);
+		const unsigned way_shift = 32 - log2(ways);
 		const unsigned set_shift = dcache_linesize_log(i);
 		dcache_clean_manual(i, false, ways, sets, way_shift, set_shift);
@@ -293,5 +293,5 @@
 		const unsigned ways = dcache_ways(i);
 		const unsigned sets = dcache_sets(i);
-		const unsigned way_shift =  31 - log2(ways);
+		const unsigned way_shift = 32 - log2(ways);
 		const unsigned set_shift = dcache_linesize_log(i);
 		dcache_clean_manual(i, true, ways, sets, way_shift, set_shift);
Index: kernel/arch/arm32/src/mach/beagleboardxm/beagleboardxm.c
===================================================================
--- kernel/arch/arm32/src/mach/beagleboardxm/beagleboardxm.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/arm32/src/mach/beagleboardxm/beagleboardxm.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -85,9 +85,10 @@
 static void bb_timer_irq_handler(irq_t *irq)
 {
+	amdm37x_gpt_irq_ack(&beagleboard.timer);
+
         /*
          * We are holding a lock which prevents preemption.
          * Release the lock, call clock() and reacquire the lock again.
          */
-	amdm37x_gpt_irq_ack(&beagleboard.timer);
 	spinlock_unlock(&irq->lock);
 	clock();
@@ -147,5 +148,4 @@
 {
 	const unsigned inum = amdm37x_irc_inum_get(beagleboard.irc_addr);
-	amdm37x_irc_irq_ack(beagleboard.irc_addr);
 
 	irq_t *irq = irq_dispatch_and_lock(inum);
@@ -159,4 +159,7 @@
 		    CPU->id, inum);
 	}
+	/** amdm37x manual ch. 12.5.2 (p. 2428) places irc ack at the end
+	 * of ISR. DO this to avoid strange behavior. */
+	amdm37x_irc_irq_ack(beagleboard.irc_addr);
 }
 
Index: kernel/arch/arm32/src/mm/tlb.c
===================================================================
--- kernel/arch/arm32/src/mm/tlb.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/arm32/src/mm/tlb.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -37,6 +37,8 @@
 #include <arch/mm/asid.h>
 #include <arch/asm.h>
+#include <arch/cp15.h>
 #include <typedefs.h>
 #include <arch/mm/page.h>
+#include <arch/cache.h>
 
 /** Invalidate all entries in TLB.
@@ -46,9 +48,17 @@
 void tlb_invalidate_all(void)
 {
-	asm volatile (
-		"eor r1, r1\n"
-		"mcr p15, 0, r1, c8, c7, 0\n"
-		::: "r1"
-	);
+	TLBIALL_write(0);
+	/*
+	 * "A TLB maintenance operation is only guaranteed to be complete after
+	 * the execution of a DSB instruction."
+	 * "An ISB instruction, or a return from an exception, causes the
+	 * effect of all completed TLB maintenance operations that appear in
+	 * program order before the ISB or return from exception to be visible
+	 * to all subsequent instructions, including the instruction fetches
+	 * for those instructions."
+	 * ARM Architecture reference Manual ch. B3.10.1 p. B3-1374 B3-1375
+	 */
+	read_barrier();
+	inst_barrier();
 }
 
@@ -60,4 +70,5 @@
 {
 	tlb_invalidate_all();
+	// TODO: why not TLBIASID_write(asid) ?
 }
 
@@ -65,11 +76,21 @@
  *
  * @param page Virtual adress of the page
- */ 
+ */
 static inline void invalidate_page(uintptr_t page)
 {
-	asm volatile (
-		"mcr p15, 0, %[page], c8, c7, 1\n"
-		:: [page] "r" (page)
-	);
+	//TODO: What about TLBIMVAA?
+	TLBIMVA_write(page);
+	/*
+	 * "A TLB maintenance operation is only guaranteed to be complete after
+	 * the execution of a DSB instruction."
+	 * "An ISB instruction, or a return from an exception, causes the
+	 * effect of all completed TLB maintenance operations that appear in
+	 * program order before the ISB or return from exception to be visible
+	 * to all subsequent instructions, including the instruction fetches
+	 * for those instructions."
+	 * ARM Architecture reference Manual ch. B3.10.1 p. B3-1374 B3-1375
+	 */
+	read_barrier();
+	inst_barrier();
 }
 
@@ -83,7 +104,5 @@
 void tlb_invalidate_pages(asid_t asid __attribute__((unused)), uintptr_t page, size_t cnt)
 {
-	unsigned int i;
-
-	for (i = 0; i < cnt; i++)
+	for (unsigned i = 0; i < cnt; i++)
 		invalidate_page(page + i * PAGE_SIZE);
 }
Index: kernel/arch/ia32/src/ddi/ddi.c
===================================================================
--- kernel/arch/ia32/src/ddi/ddi.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/ia32/src/ddi/ddi.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -59,27 +59,28 @@
 int ddi_iospace_enable_arch(task_t *task, uintptr_t ioaddr, size_t size)
 {
-	size_t bits = ioaddr + size;
-	if (bits > IO_PORTS)
+	size_t elements = ioaddr + size;
+	if (elements > IO_PORTS)
 		return ENOENT;
 	
-	if (task->arch.iomap.bits < bits) {
+	if (task->arch.iomap.elements < elements) {
 		/*
 		 * The I/O permission bitmap is too small and needs to be grown.
 		 */
 		
-		uint8_t *newmap = (uint8_t *) malloc(BITS2BYTES(bits), FRAME_ATOMIC);
-		if (!newmap)
+		void *store = malloc(bitmap_size(elements, 0), FRAME_ATOMIC);
+		if (!store)
 			return ENOMEM;
 		
 		bitmap_t oldiomap;
-		bitmap_initialize(&oldiomap, task->arch.iomap.map,
+		bitmap_initialize(&oldiomap, task->arch.iomap.elements, 0,
 		    task->arch.iomap.bits);
-		bitmap_initialize(&task->arch.iomap, newmap, bits);
+		
+		bitmap_initialize(&task->arch.iomap, elements, 0, store);
 		
 		/*
 		 * Mark the new range inaccessible.
 		 */
-		bitmap_set_range(&task->arch.iomap, oldiomap.bits,
-		    bits - oldiomap.bits);
+		bitmap_set_range(&task->arch.iomap, oldiomap.elements,
+		    elements - oldiomap.elements);
 		
 		/*
@@ -89,6 +90,7 @@
 		if (oldiomap.bits) {
 			bitmap_copy(&task->arch.iomap, &oldiomap,
-			    oldiomap.bits);
-			free(oldiomap.map);
+			    oldiomap.elements);
+			
+			free(oldiomap.bits);
 		}
 	}
@@ -97,5 +99,5 @@
 	 * Enable the range and we are done.
 	 */
-	bitmap_clear_range(&task->arch.iomap, (size_t) ioaddr, (size_t) size);
+	bitmap_clear_range(&task->arch.iomap, (size_t) ioaddr, size);
 	
 	/*
@@ -119,13 +121,15 @@
 	/* First, copy the I/O Permission Bitmap. */
 	irq_spinlock_lock(&TASK->lock, false);
+	
 	size_t ver = TASK->arch.iomapver;
-	size_t bits = TASK->arch.iomap.bits;
-	if (bits) {
-		ASSERT(TASK->arch.iomap.map);
+	size_t elements = TASK->arch.iomap.elements;
+	
+	if (elements > 0) {
+		ASSERT(TASK->arch.iomap.bits);
 		
 		bitmap_t iomap;
-		bitmap_initialize(&iomap, CPU->arch.tss->iomap,
-		    TSS_IOMAP_SIZE * 8);
-		bitmap_copy(&iomap, &TASK->arch.iomap, bits);
+		bitmap_initialize(&iomap, TSS_IOMAP_SIZE * 8, 0,
+		    CPU->arch.tss->iomap);
+		bitmap_copy(&iomap, &TASK->arch.iomap, elements);
 		
 		/*
@@ -133,11 +137,14 @@
 		 * I/O access.
 		 */
-		bitmap_set_range(&iomap, bits, ALIGN_UP(bits, 8) - bits);
+		bitmap_set_range(&iomap, elements,
+		    ALIGN_UP(elements, 8) - elements);
+		
 		/*
 		 * It is safe to set the trailing eight bits because of the
 		 * extra convenience byte in TSS_IOMAP_SIZE.
 		 */
-		bitmap_set_range(&iomap, ALIGN_UP(bits, 8), 8);
+		bitmap_set_range(&iomap, ALIGN_UP(elements, 8), 8);
 	}
+	
 	irq_spinlock_unlock(&TASK->lock, false);
 	
@@ -150,5 +157,6 @@
 	
 	descriptor_t *gdt_p = (descriptor_t *) cpugdtr.base;
-	gdt_setlimit(&gdt_p[TSS_DES], TSS_BASIC_SIZE + BITS2BYTES(bits));
+	size_t size = bitmap_size(elements, 0);
+	gdt_setlimit(&gdt_p[TSS_DES], TSS_BASIC_SIZE + size);
 	gdtr_load(&cpugdtr);
 	
Index: kernel/arch/ia32/src/mm/frame.c
===================================================================
--- kernel/arch/ia32/src/mm/frame.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/ia32/src/mm/frame.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -47,4 +47,5 @@
 
 #define PHYSMEM_LIMIT32  UINT64_C(0x100000000)
+#define PHYSMEM_LIMIT_DMA   UINT64_C(0x1000000)
 
 size_t hardcoded_unmapped_ktext_size = 0;
@@ -91,11 +92,26 @@
 				else
 					conf = minconf;
-				zone_create(pfn, count, conf,
-				    ZONE_AVAILABLE | ZONE_LOWMEM);
+
+				if ((pfn * PAGE_SIZE) < PHYSMEM_LIMIT_DMA) {
+					size_t dma_count = min(
+					    PHYSMEM_LIMIT_DMA / PAGE_SIZE - pfn,
+					    count);
+					zone_create(pfn, dma_count, conf,
+					    ZONE_AVAILABLE | ZONE_DMA);
+					count -= dma_count;
+					pfn += dma_count;
+				}
+
+				conf = pfn;
+				if (count) {
+					zone_create(pfn, count, conf,
+					    ZONE_AVAILABLE | ZONE_LOWMEM);
+				}
 			} else {
 				conf = zone_external_conf_alloc(count);
-				if (conf != 0)
+				if (conf != 0) {
 					zone_create(pfn, count, conf,
 					    ZONE_AVAILABLE | ZONE_HIGHMEM);
+				}
 			}
 		} else if ((e820table[i].type == MEMMAP_MEMORY_ACPI) ||
Index: kernel/arch/ia32/src/proc/task.c
===================================================================
--- kernel/arch/ia32/src/proc/task.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/ia32/src/proc/task.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -40,20 +40,22 @@
 /** Perform ia32 specific task initialization.
  *
- * @param t Task to be initialized.
+ * @param task Task to be initialized.
+ *
  */
-void task_create_arch(task_t *t)
+void task_create_arch(task_t *task)
 {
-	t->arch.iomapver = 0;
-	bitmap_initialize(&t->arch.iomap, NULL, 0);
+	task->arch.iomapver = 0;
+	bitmap_initialize(&task->arch.iomap, 0, 0, NULL);
 }
 
 /** Perform ia32 specific task destruction.
  *
- * @param t Task to be initialized.
+ * @param task Task to be initialized.
+ *
  */
-void task_destroy_arch(task_t *t)
+void task_destroy_arch(task_t *task)
 {
-	if (t->arch.iomap.map)
-		free(t->arch.iomap.map);
+	if (task->arch.iomap.bits != NULL)
+		free(task->arch.iomap.bits);
 }
 
Index: kernel/arch/ia64/src/ddi/ddi.c
===================================================================
--- kernel/arch/ia64/src/ddi/ddi.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/ia64/src/ddi/ddi.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -56,11 +56,13 @@
 {
 	if (!task->arch.iomap) {
-		uint8_t *map;
-
 		task->arch.iomap = malloc(sizeof(bitmap_t), 0);
-		map = malloc(BITS2BYTES(IO_MEMMAP_PAGES), 0);
-		if(!map)
+		if (task->arch.iomap == NULL)
 			return ENOMEM;
-		bitmap_initialize(task->arch.iomap, map, IO_MEMMAP_PAGES);
+		
+		void *store = malloc(bitmap_size(IO_MEMMAP_PAGES, 0), 0);
+		if (store == NULL)
+			return ENOMEM;
+		
+		bitmap_initialize(task->arch.iomap, IO_MEMMAP_PAGES, 0, store);
 		bitmap_clear_range(task->arch.iomap, 0, IO_MEMMAP_PAGES);
 	}
@@ -69,5 +71,5 @@
 	size = ALIGN_UP(size + ioaddr - 4 * iopage, PORTS_PER_PAGE);
 	bitmap_set_range(task->arch.iomap, iopage, size / 4);
-
+	
 	return 0;
 }
Index: kernel/arch/sparc64/include/arch/mm/frame.h
===================================================================
--- kernel/arch/sparc64/include/arch/mm/frame.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc64/include/arch/mm/frame.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -46,4 +46,16 @@
 #endif
 
+#ifndef __ASM__
+
+#include <typedefs.h>
+
+extern uintptr_t end_of_identity;
+
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
+#define physmem_print()
+
+#endif
+
 #endif
 
Index: kernel/arch/sparc64/include/arch/mm/sun4u/frame.h
===================================================================
--- kernel/arch/sparc64/include/arch/mm/sun4u/frame.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc64/include/arch/mm/sun4u/frame.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -72,10 +72,4 @@
 typedef union frame_address frame_address_t;
 
-extern uintptr_t end_of_identity;
-
-extern void frame_low_arch_init(void);
-extern void frame_high_arch_init(void);
-#define physmem_print()
-
 #endif
 
Index: kernel/arch/sparc64/include/arch/mm/sun4v/frame.h
===================================================================
--- kernel/arch/sparc64/include/arch/mm/sun4v/frame.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc64/include/arch/mm/sun4v/frame.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -42,14 +42,4 @@
 #define FRAME_SIZE		(1 << FRAME_WIDTH)
 
-#ifndef __ASM__
-
-#include <typedefs.h>
-
-extern void frame_low_arch_init(void);
-extern void frame_high_arch_init(void);
-#define physmem_print()
-
-#endif
-
 #endif
 
Index: kernel/arch/sparc64/include/arch/trap/sun4v/mmu.h
===================================================================
--- kernel/arch/sparc64/include/arch/trap/sun4v/mmu.h	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc64/include/arch/trap/sun4v/mmu.h	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -102,4 +102,11 @@
 	nop
 
+	/* exclude pages beyond the end of memory from the identity mapping */
+	sethi %hi(end_of_identity), %g4
+	ldx [%g4 + %lo(end_of_identity)], %g4
+	cmp %g1, %g4
+	bgeu %xcc, 0f
+	nop
+
 	/*
 	 * Installing the identity does not fit into 32 instructions, call
Index: kernel/arch/sparc64/src/mm/sun4v/frame.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4v/frame.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc64/src/mm/sun4v/frame.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -101,4 +101,7 @@
 	 */
 	frame_mark_unavailable(ADDR2PFN(KA2PA(PFN2ADDR(0))), 1);
+
+	/* PA2KA will work only on low-memory. */
+	end_of_identity = PA2KA(config.physmem_end - FRAME_SIZE) + PAGE_SIZE;
 }
 
Index: kernel/arch/sparc64/src/mm/sun4v/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4v/tlb.c	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc64/src/mm/sun4v/tlb.c	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -251,4 +251,5 @@
 	uintptr_t va = DMISS_ADDRESS(page_and_ctx);
 	uint16_t ctx = DMISS_CONTEXT(page_and_ctx);
+	as_t *as = AS;
 
 	if (ctx == ASID_KERNEL) {
@@ -256,9 +257,13 @@
 			/* NULL access in kernel */
 			panic("NULL pointer dereference.");
+		} else if (va >= end_of_identity) {
+			/* Kernel non-identity */
+			as = AS_KERNEL;
+		} else {
+			panic("Unexpected kernel page fault.");
 		}
-		panic("Unexpected kernel page fault.");
-	}
-
-	t = page_mapping_find(AS, va, true);
+	}
+
+	t = page_mapping_find(as, va, true);
 	if (t) {
 		/*
@@ -295,6 +300,10 @@
 	uintptr_t va = DMISS_ADDRESS(page_and_ctx);
 	uint16_t ctx = DMISS_CONTEXT(page_and_ctx);
-
-	t = page_mapping_find(AS, va, true);
+	as_t *as = AS;
+
+	if (ctx == ASID_KERNEL)
+		as = AS_KERNEL;
+
+	t = page_mapping_find(as, va, true);
 	if (t && PTE_WRITABLE(t)) {
 		/*
Index: kernel/arch/sparc64/src/sun4v/start.S
===================================================================
--- kernel/arch/sparc64/src/sun4v/start.S	(revision 3efc35affa36b99c7857e37488bf6acf248901c6)
+++ kernel/arch/sparc64/src/sun4v/start.S	(revision 6ac3d27eb625f68dbcec00d5d56ddbd6ca72b413)
@@ -345,4 +345,13 @@
 	.quad 0
 
+/*
+ * This variable is used by the fast_data_access_MMU_miss trap handler.
+ * In runtime, it is modified to contain the address of the end of physical
+ * memory.
+ */
+.global end_of_identity
+end_of_identity:
+	.quad -1
+
 .global kernel_8k_tlb_data_template
 kernel_8k_tlb_data_template:
