Add data and instruction cache maintenance functions

Add Xlat::clean_data_cache and Xlat::invalidate_instruction_cache
functions, that clean/invalidate the data/instruction caches of a given
virtual address range.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I60deeedcaeed88a4487f3e08243541ea213deec6
diff --git a/src/lib.rs b/src/lib.rs
index 63d24cc..4ffc12a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1040,12 +1040,7 @@
                     )
                 };
 
-                Self::walk_descriptors(
-                    va,
-                    level + 1,
-                    next_level_table,
-                    granule,
-                )
+                Self::walk_descriptors(va, level + 1, next_level_table, granule)
             }
         }
     }
@@ -1088,6 +1083,81 @@
         }
     }
 
+    /// Clean data cache by address to Point of Coherency.
+    ///
+    /// # Safety
+    /// The clean operation is done on a virtual address of the currently active mapping. The caller
+    /// must ensure that the VA to PA translation does not cause a translation fault as described in
+    /// section 'D7.5.9.2 The data cache maintenance instruction (DC)' of 'ARM DDI 0487L'. Since the
+    /// cache clean operation might alter the visible contents of the affected memory area for other
+    /// cores as well, the code must be designed to account for these changes.
+    #[cfg(target_arch = "aarch64")]
+    pub unsafe fn clean_data_cache(va: VirtualAddress, length: usize) {
+        let line_size = Self::dcache_line_size();
+        let address_mask = !(line_size - 1);
+
+        for address in (va.0 & address_mask..va.0 + length).step_by(line_size) {
+            // SAFETY: If the functions safety conditions are met, the 'dc' instruction cannot
+            // violate Rust's safety guarantees.
+            unsafe { core::arch::asm!("dc cvac, {}", in(reg) address) }
+        }
+
+        // SAFETY: Memory barrier.
+        unsafe {
+            core::arch::asm!("dsb ish");
+        }
+    }
+
+    /// Invalidate instruction cache by address to Point of Unification.
+    ///
+    /// # Safety
+    /// The invalidate operation is done on a virtual address of the currently active mapping. The
+    /// caller must ensure that the VA to PA translation does not cause a translation fault as
+    /// described in section 'D7.5.9.2 The data cache maintenance instruction (DC)' of
+    /// 'ARM DDI 0487L'. Since the cache clean operation might alter the visible contents of the
+    /// affected memory area for other cores as well, the code must be designed to account for these
+    /// changes.
+    #[cfg(target_arch = "aarch64")]
+    pub unsafe fn invalidate_instruction_cache(va: VirtualAddress, length: usize) {
+        let line_size = Self::icache_line_size();
+        let address_mask = !(line_size - 1);
+
+        for address in (va.0 & address_mask..va.0 + length).step_by(line_size) {
+            // SAFETY: If the functions safety conditions are met, the 'ic' instruction cannot
+            // violate Rust's safety guarantees.
+            unsafe { core::arch::asm!("ic ivau, {}", in(reg) address) }
+        }
+
+        // SAFETY: Memory barrier.
+        unsafe {
+            core::arch::asm!("dsb ish");
+        }
+    }
+
+    /// Returns the data cache line size in bytes.
+    #[cfg(target_arch = "aarch64")]
+    fn dcache_line_size() -> usize {
+        const WORD_SIZE: usize = 4;
+        let ctr_el0: u64;
+
+        unsafe { core::arch::asm!("mrs {0}, ctr_el0", out(reg) ctr_el0) };
+
+        let dminline = (ctr_el0 >> 16) & 0xf;
+        WORD_SIZE << dminline
+    }
+
+    /// Returns the instruction cache line size in bytes.
+    #[cfg(target_arch = "aarch64")]
+    fn icache_line_size() -> usize {
+        const WORD_SIZE: usize = 4;
+        let ctr_el0: u64;
+
+        unsafe { core::arch::asm!("mrs {0}, ctr_el0", out(reg) ctr_el0) };
+
+        let iminline = ctr_el0 & 0xf;
+        WORD_SIZE << iminline
+    }
+
     #[cfg(target_arch = "aarch64")]
     fn invalidate(regime: &TranslationRegime, va: Option<VirtualAddress>) {
         // SAFETY: The assembly code invalidates the translation table entry of