pvmfw: Add MemoryTracker & MemorySlices

Add support for dynamically validating, mapping, and allocating
non-overlapping slices of main RAM in a safe manner in MemoryTracker and
use it in MemorySlices for the regions of interest, located through the
inputs.

Bug: 256148034
Bug: 249054080
Bug: 256827715
Test: atest MicrodroidTestApp
Change-Id: I25f8db10df763c0473c281bf96f30e6b5fbe1619
diff --git a/pvmfw/src/helpers.rs b/pvmfw/src/helpers.rs
index 59cf9f3..9062957 100644
--- a/pvmfw/src/helpers.rs
+++ b/pvmfw/src/helpers.rs
@@ -14,6 +14,8 @@
 
 //! Miscellaneous helper functions.
 
+use core::arch::asm;
+
 pub const SIZE_4KB: usize = 4 << 10;
 pub const SIZE_2MB: usize = 2 << 20;
 
@@ -39,3 +41,30 @@
 pub const fn page_4kb_of(addr: usize) -> usize {
     unchecked_align_down(addr, SIZE_4KB)
 }
+
+#[inline]
+fn min_dcache_line_size() -> usize {
+    const DMINLINE_SHIFT: usize = 16;
+    const DMINLINE_MASK: usize = 0xf;
+    let ctr_el0: usize;
+
+    unsafe { asm!("mrs {x}, ctr_el0", x = out(reg) ctr_el0) }
+
+    // DminLine: log2 of the number of words in the smallest cache line of all the data caches.
+    let dminline = (ctr_el0 >> DMINLINE_SHIFT) & DMINLINE_MASK;
+
+    1 << dminline
+}
+
+#[inline]
+/// Flush data cache over the entire slice.
+pub fn flush_region(start: usize, size: usize) {
+    let line_size = min_dcache_line_size();
+    let end = start + size;
+    let start = unchecked_align_down(start, line_size);
+
+    for line in (start..end).step_by(line_size) {
+        // SAFETY - Clearing cache lines shouldn't have Rust-visible side effects.
+        unsafe { asm!("dc cvau, {x}", x = in(reg) line) }
+    }
+}