vmbase_example: Run most tests using dynamic PTs

Instead of enabling the dynamic page tables for a short duration and
switching back to idmap.S, enable them early and keep them (almost)
until main() returns.

Map the DT before it is accessed by the tests. As a result, the
assertion that the DT must be at a hard-coded location can be lifted and
we can remove the mapping from idmap.S. Note that the PT test was
previously using .map_rodata() for the DT but, given modify_fdt(), we
must actually use .map_data().

For the PCI BAR, avoid a BBM violation but detecting if the region is
already mapped. To do so, implement RangeExt for MemoryRegion.

Test: atest vmbase_example.integration_test
Change-Id: I1abbf1566c579282742f5a0936e0934e69c38797
diff --git a/guest/vmbase_example/idmap.S b/guest/vmbase_example/idmap.S
index 268de5f..2e62085 100644
--- a/guest/vmbase_example/idmap.S
+++ b/guest/vmbase_example/idmap.S
@@ -45,7 +45,7 @@
 
 0:	/* level 2 */
 #if defined(VMBASE_EXAMPLE_IS_BIOS)
-	.quad		.L_BLOCK_MEM | 0x80000000	// DT provided by VMM
+	.quad		0				// 2 MiB not mapped (DT)
 	.quad		.L_BLOCK_MEM_XIP | 0x80200000	// 2 MiB of DRAM containing image
 	.quad		.L_BLOCK_MEM | 0x80400000	// 2 MiB of writable DRAM
 	.fill		509, 8, 0x0
diff --git a/guest/vmbase_example/src/main.rs b/guest/vmbase_example/src/main.rs
index 02c9429..7a3f427 100644
--- a/guest/vmbase_example/src/main.rs
+++ b/guest/vmbase_example/src/main.rs
@@ -36,12 +36,10 @@
 use log::{debug, error, info, trace, warn, LevelFilter};
 use vmbase::{
     bionic, configure_heap, generate_image_header,
-    layout::{
-        crosvm::{FDT_MAX_SIZE, MEM_START},
-        rodata_range, scratch_range, text_range,
-    },
+    layout::{crosvm::FDT_MAX_SIZE, rodata_range, scratch_range, text_range},
     linker, logger, main,
     memory::{PageTable, SIZE_64KB},
+    util::RangeExt as _,
 };
 
 static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
@@ -80,13 +78,15 @@
     check_data();
     check_stack_guard();
 
+    let mut page_table = PageTable::default();
+    init_page_table(&mut page_table).unwrap();
+
     info!("Checking FDT...");
     let fdt_addr = usize::try_from(arg0).unwrap();
-    // We are about to access the region so check that it matches our page tables in idmap.S.
-    assert_eq!(fdt_addr, MEM_START);
     // SAFETY: The DTB range is valid, writable memory, and we don't construct any aliases to it.
     let fdt = unsafe { core::slice::from_raw_parts_mut(fdt_addr as *mut u8, FDT_MAX_SIZE) };
     let fdt_region = (VirtualAddress(fdt_addr)..VirtualAddress(fdt_addr + fdt.len())).into();
+    page_table.map_data(&fdt_region).unwrap();
     let fdt = Fdt::from_mut_slice(fdt).unwrap();
     info!("FDT passed verification.");
     check_fdt(fdt);
@@ -98,11 +98,13 @@
 
     check_alloc();
 
-    let mut page_table = PageTable::default();
-    page_table.map_rodata(&fdt_region).unwrap();
-    page_table.map_device(&get_bar_region(&pci_info)).unwrap();
-    init_page_table(&mut page_table).unwrap();
-    mem::drop(page_table); // Release PageTable and switch back to idmap.S
+    let bar_region = get_bar_region(&pci_info);
+    if bar_region.is_within(&DEVICE_REGION) {
+        // Avoid a MapError::BreakBeforeMakeViolation.
+        info!("BAR region is within already mapped device region: skipping page table ops.");
+    } else {
+        page_table.map_device(&bar_region).unwrap();
+    }
 
     check_data();
     check_dice();
@@ -112,6 +114,10 @@
     check_pci(&mut pci_root);
 
     emit_suppressed_log();
+
+    info!("De-activating IdMap...");
+    mem::drop(page_table); // Release PageTable and switch back to idmap.S
+    info!("De-activated.");
 }
 
 fn check_stack_guard() {
diff --git a/libs/libvmbase/src/util.rs b/libs/libvmbase/src/util.rs
index 8c230a1..e52ac8e 100644
--- a/libs/libvmbase/src/util.rs
+++ b/libs/libvmbase/src/util.rs
@@ -14,6 +14,7 @@
 
 //! Utility functions.
 
+use aarch64_paging::paging::MemoryRegion;
 use core::ops::Range;
 
 /// Flatten [[T; N]] into &[T]
@@ -91,3 +92,13 @@
         self.start < other.end && other.start < self.end
     }
 }
+
+impl RangeExt for MemoryRegion {
+    fn is_within(&self, other: &Self) -> bool {
+        self.start() >= other.start() && self.end() <= other.end()
+    }
+
+    fn overlaps(&self, other: &Self) -> bool {
+        self.start() < other.end() && other.start() < self.end()
+    }
+}