Handle top bits in upper VA ranges

Set and enforce top bits in virtual address if Upper VA range is
selected for EL1/0 or EL2/0 (VHE). This means that the top bits must
match the selected VA range and Xlat will also return matching virtual
addresses.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I44c2a326a9d3fdd4d82ec01e8f95d1c8f7d305b1
diff --git a/src/lib.rs b/src/lib.rs
index b5f95d6..c8abbdd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -114,13 +114,13 @@
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub enum RegimeVaRange {
     Lower,
     Upper,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub enum TranslationRegime {
     EL1_0(RegimeVaRange, u8), // EL1 and EL0 stage 1, TTBRx_EL1
     #[cfg(target_feature = "vh")]
@@ -129,6 +129,17 @@
     EL3,                      // EL3, TTBR0_EL3
 }
 
+impl TranslationRegime {
+    fn is_upper_va_range(&self) -> bool {
+        match self {
+            TranslationRegime::EL1_0(RegimeVaRange::Upper, _) => true,
+            #[cfg(target_feature = "vh")]
+            EL2_0(RegimeVaRange::Upper, _) => true,
+            _ => false,
+        }
+    }
+}
+
 pub type TranslationGranule<const VA_BITS: usize> = granule::TranslationGranule<VA_BITS>;
 
 pub struct Xlat<const VA_BITS: usize> {
@@ -173,6 +184,15 @@
     ) -> Self {
         let initial_lookup_level = granule.initial_lookup_level();
 
+        if !address.start.is_valid_in_regime::<VA_BITS>(regime)
+            || !address.end.is_valid_in_regime::<VA_BITS>(regime)
+        {
+            panic!(
+                "Invalid address range {:?} for regime {:?}",
+                address, regime
+            );
+        }
+
         let base_table = page_pool
             .allocate_pages(
                 granule.table_size::<Descriptor>(initial_lookup_level),
@@ -547,7 +567,7 @@
     ) -> Result<VirtualAddress, XlatError> {
         let blocks = BlockIterator::new(
             region.get_pa(),
-            region.base(),
+            region.base().remove_upper_bits::<VA_BITS>(),
             region.length(),
             self.granule,
         )?;
@@ -565,7 +585,7 @@
     fn unmap_region(&mut self, region: &VirtualRegion) -> Result<(), XlatError> {
         let blocks = BlockIterator::new(
             region.get_pa(),
-            region.base(),
+            region.base().remove_upper_bits::<VA_BITS>(),
             region.length(),
             self.granule,
         )?;