Index: kernel/arch/arm32/include/cache.h
===================================================================
--- kernel/arch/arm32/include/cache.h	(revision bad1f5376943a72bce1b976c2fe106c6545cd679)
+++ kernel/arch/arm32/include/cache.h	(revision bad1f5376943a72bce1b976c2fe106c6545cd679)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup arm32
+ * @{
+ */
+/** @file
+ *  @brief Security Extensions Routines
+ */
+
+#ifndef KERN_arm32_CACHE_H_
+#define KERN_arm32_CACHE_H_
+
+unsigned dcache_levels(void);
+
+void dcache_flush(void);
+void dcache_flush_invalidate(void);
+void cpu_dcache_flush(void);
+void cpu_dcache_flush_invalidate(void);
+void icache_invalidate(void);
+
+#endif
+/** @}
+ */
+
Index: kernel/arch/arm32/include/cp15.h
===================================================================
--- kernel/arch/arm32/include/cp15.h	(revision 5fcd5372fa4cc52bb3d6d189df950427675f6acd)
+++ kernel/arch/arm32/include/cp15.h	(revision bad1f5376943a72bce1b976c2fe106c6545cd679)
@@ -104,8 +104,41 @@
 CONTROL_REG_GEN_READ(ID_ISAR5, c0, 0, c2, 5);
 
+enum {
+	CCSIDR_WT_FLAG = 1 << 31,
+	CCSIDR_WB_FLAG = 1 << 30,
+	CCSIDR_RA_FLAG = 1 << 29,
+	CCSIDR_WA_FLAG = 1 << 28,
+	CCSIDR_NUMSETS_MASK = 0x7fff,
+	CCSIDR_NUMSETS_SHIFT = 13,
+	CCSIDR_ASSOC_MASK = 0x3ff,
+	CCSIDR_ASSOC_SHIFT = 3,
+	CCSIDR_LINESIZE_MASK = 0x7,
+	CCSIDR_LINESIZE_SHIFT = 0,
+};
 CONTROL_REG_GEN_READ(CCSIDR, c0, 1, c0, 0);
+
+enum {
+	CLIDR_LOUU_MASK = 0x7,
+	CLIDR_LOUU_SHIFT = 27,
+	CLIDR_LOC_MASK = 0x7,
+	CLIDR_LOC_SHIFT = 24,
+	CLIDR_LOUIS_MASK = 0x7,
+	CLIDR_LOUIS_SHIFT = 21,
+	CLIDR_NOCACHE = 0x0,
+	CLIDR_ICACHE_ONLY = 0x1,
+	CLIDR_DCACHE_ONLY = 0x2,
+	CLIDR_SEP_CACHE = 0x3,
+	CLIDR_UNI_CACHE = 0x4,
+	CLIDR_CACHE_MASK = 0x7,
+#define CLIDR_CACHE(level, val)   ((val >> (level - 1) * 3) & CLIDR_CACHE_MASK)
+};
 CONTROL_REG_GEN_READ(CLIDR, c0, 1, c0, 1);
 CONTROL_REG_GEN_READ(AIDR, c0, 1, c0, 7); /* Implementation defined or MIDR */
 
+enum {
+	CCSELR_LEVEL_MASK = 0x7,
+	CCSELR_LEVEL_SHIFT = 1,
+	CCSELR_INSTRUCTION_FLAG = 1 << 0,
+};
 CONTROL_REG_GEN_READ(CSSELR, c0, 2, c0, 0);
 CONTROL_REG_GEN_WRITE(CSSELR, c0, 2, c0, 0);
Index: kernel/arch/arm32/include/cpu.h
===================================================================
--- kernel/arch/arm32/include/cpu.h	(revision 5fcd5372fa4cc52bb3d6d189df950427675f6acd)
+++ kernel/arch/arm32/include/cpu.h	(revision bad1f5376943a72bce1b976c2fe106c6545cd679)
@@ -40,4 +40,7 @@
 #include <arch/asm.h>
 
+enum {
+	ARM_MAX_CACHE_LEVELS = 7,
+};
 
 /** Struct representing ARM CPU identification. */
@@ -57,4 +60,13 @@
 	/** Revision number. */
 	uint32_t rev_num;
+
+	struct {
+		unsigned ways;
+		unsigned sets;
+		unsigned line_size;
+		unsigned way_shift;
+		unsigned set_shift;
+	} dcache[ARM_MAX_CACHE_LEVELS];
+	unsigned dcache_levels;
 } cpu_arch_t;
 
Index: kernel/arch/arm32/src/cpu/cpu.c
===================================================================
--- kernel/arch/arm32/src/cpu/cpu.c	(revision 5fcd5372fa4cc52bb3d6d189df950427675f6acd)
+++ kernel/arch/arm32/src/cpu/cpu.c	(revision bad1f5376943a72bce1b976c2fe106c6545cd679)
@@ -34,8 +34,26 @@
  */
 
+#include <arch/cache.h>
 #include <arch/cpu.h>
+#include <arch/cp15.h>
 #include <cpu.h>
 #include <arch.h>
 #include <print.h>
+
+static inline unsigned log2(unsigned val)
+{
+	unsigned log = 0;
+	--val;
+	while (val) {
+		++log;
+		val >>= 1;
+	}
+	return log;
+}
+
+static unsigned dcache_ways(unsigned level);
+static unsigned dcache_sets(unsigned level);
+static unsigned dcache_linesize_log(unsigned level);
+
 
 /** Implementers (vendor) names */
@@ -93,4 +111,17 @@
 	cpu->rev_num = (ident << 28) >> 28;
 	// TODO CPUs with arch_num == 0xf use CPUID scheme for identification
+	cpu->dcache_levels = dcache_levels();
+
+	for (unsigned i = 0; i < cpu->dcache_levels; ++i) {
+		cpu->dcache[i].ways = dcache_ways(i);
+		cpu->dcache[i].sets = dcache_sets(i);
+		cpu->dcache[i].way_shift = 31 - log2(cpu->dcache[i].ways);
+		cpu->dcache[i].set_shift = dcache_linesize_log(i);
+		cpu->dcache[i].line_size = 1 << dcache_linesize_log(i);
+		printf("Found DCache L%u: %u-way, %u sets, %u byte lines "
+		    "(shifts: w%u, s%u)\n", i + 1, cpu->dcache[i].ways,
+		    cpu->dcache[i].sets, cpu->dcache[i].line_size,
+		    cpu->dcache[i].way_shift, cpu->dcache[i].set_shift);
+	}
 }
 
@@ -170,4 +201,125 @@
 }
 
+/** See chapter B4.1.19 of ARM Architecture Reference Manual */
+static unsigned dcache_linesize_log(unsigned level)
+{
+#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)
+#endif
+	return 0;
+
+}
+
+/** See chapter B4.1.19 of ARM Architecture Reference Manual */
+static unsigned dcache_ways(unsigned level)
+{
+#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;
+#endif
+	return 0;
+}
+
+/** See chapter B4.1.19 of ARM Architecture Reference Manual */
+static unsigned dcache_sets(unsigned level)
+{
+#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;
+#endif
+	return 0;
+}
+
+unsigned dcache_levels(void)
+{
+	const uint32_t val = CLIDR_read();
+	unsigned levels = 0;
+	for (unsigned i = 1; i <= 7; ++i) {
+		const unsigned ctype = CLIDR_CACHE(i, val);
+		switch (ctype) {
+		case CLIDR_DCACHE_ONLY:
+		case CLIDR_SEP_CACHE:
+		case CLIDR_UNI_CACHE:
+			++levels;
+		default:
+			(void)0;
+		}
+	}
+	return levels;
+}
+
+static void dcache_clean_manual(unsigned level, bool invalidate,
+    unsigned ways, unsigned sets, unsigned way_shift, unsigned set_shift)
+{
+
+	for (unsigned i = 0; i < ways; ++i) {
+		for (unsigned j = 0; j < sets; ++j) {
+			const uint32_t val =
+			    ((level & 0x7) << 1) |
+			    (j << set_shift) | (i << way_shift);
+			if (invalidate)
+				DCCISW_write(val);
+			else
+				DCCSW_write(val);
+		}
+	}
+}
+
+void dcache_flush(void)
+{
+	/* See ARM Architecture Reference Manual ch. B4.2.1 p. B4-1724 */
+	const unsigned levels = dcache_levels();
+	for (unsigned i = 0; i < levels; ++i) {
+		const unsigned ways = dcache_ways(i);
+		const unsigned sets = dcache_sets(i);
+		const unsigned way_shift =  31 - log2(ways);
+		const unsigned set_shift = dcache_linesize_log(i);
+		dcache_clean_manual(i, false, ways, sets, way_shift, set_shift);
+	}
+}
+
+void dcache_flush_invalidate(void)
+{
+	/* See ARM Architecture Reference Manual ch. B4.2.1 p. B4-1724 */
+	const unsigned levels = dcache_levels();
+	for (unsigned i = 0; i < levels; ++i) {
+		const unsigned ways = dcache_ways(i);
+		const unsigned sets = dcache_sets(i);
+		const unsigned way_shift =  31 - log2(ways);
+		const unsigned set_shift = dcache_linesize_log(i);
+		dcache_clean_manual(i, true, ways, sets, way_shift, set_shift);
+	}
+}
+
+
+void cpu_dcache_flush(void)
+{
+	for (unsigned i = 0; i < CPU->arch.dcache_levels; ++i)
+		dcache_clean_manual(i, false,
+		    CPU->arch.dcache[i].ways, CPU->arch.dcache[i].sets,
+		    CPU->arch.dcache[i].way_shift, CPU->arch.dcache[i].set_shift);
+}
+
+void cpu_dcache_flush_invalidate(void)
+{
+	const unsigned levels =  dcache_levels();
+	for (unsigned i = 0; i < levels; ++i)
+		dcache_clean_manual(i, true,
+		    CPU->arch.dcache[i].ways, CPU->arch.dcache[i].sets,
+		    CPU->arch.dcache[i].way_shift, CPU->arch.dcache[i].set_shift);
+}
+
+void icache_invalidate(void)
+{
+	ICIALLU_write(0);
+}
+
 /** @}
  */
