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