Construct page table in Rust.

Bug: 223166344
Test: atest vmbase_example.integration_test
Change-Id: I023fd99395fcd795c608f78568945341c8354127
diff --git a/vmbase/example/Android.bp b/vmbase/example/Android.bp
index a0d84b4..d540f4d 100644
--- a/vmbase/example/Android.bp
+++ b/vmbase/example/Android.bp
@@ -13,6 +13,7 @@
         "libcore.rust_sysroot",
     ],
     rustlibs: [
+        "libaarch64_paging",
         "libbuddy_system_allocator",
         "libvmbase",
     ],
diff --git a/vmbase/example/idmap.S b/vmbase/example/idmap.S
index f1df6cc..7fc5d5e 100644
--- a/vmbase/example/idmap.S
+++ b/vmbase/example/idmap.S
@@ -38,13 +38,13 @@
 .align 12
 idmap:
 	/* level 1 */
-	.quad		.L_BLOCK_DEV | 0x0		// 1 GB of device mappings
-	.quad		.L_BLOCK_DEV | 0x40000000	// Another 1 GB of device mapppings
-	.quad		.L_TT_TYPE_TABLE + 0f		// up to 1 GB of DRAM
-	.fill		509, 8, 0x0			// 509 GB of remaining VA space
+	.quad		.L_BLOCK_DEV | 0x0		// 1 GiB of device mappings
+	.quad		0x0				// 1 GiB unmapped
+	.quad		.L_TT_TYPE_TABLE + 0f		// up to 1 GiB of DRAM
+	.fill		509, 8, 0x0			// 509 GiB of remaining VA space
 
 	/* level 2 */
 0:	.quad		.L_BLOCK_RO  | 0x80000000	// DT provided by VMM
-	.quad		.L_BLOCK_MEM_XIP | 0x80200000	// 2 MB of DRAM containing image
-	.quad		.L_BLOCK_MEM | 0x80400000	// 2 MB of writable DRAM
+	.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/vmbase/example/src/main.rs b/vmbase/example/src/main.rs
index 3b1786c..99aca1d 100644
--- a/vmbase/example/src/main.rs
+++ b/vmbase/example/src/main.rs
@@ -22,6 +22,10 @@
 
 extern crate alloc;
 
+use aarch64_paging::{
+    idmap::IdMap,
+    paging::{Attributes, MemoryRegion},
+};
 use alloc::{vec, vec::Vec};
 use buddy_system_allocator::LockedHeap;
 use vmbase::{main, println};
@@ -30,11 +34,17 @@
 static mut ZEROED_DATA: [u32; 10] = [0; 10];
 static mut MUTABLE_DATA: [u32; 4] = [1, 2, 3, 4];
 
+const ASID: usize = 1;
+const ROOT_LEVEL: usize = 1;
+
 #[global_allocator]
 static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();
 
 static mut HEAP: [u8; 65536] = [0; 65536];
 
+/// The first 1 GiB of memory are used for MMIO.
+const DEVICE_REGION: MemoryRegion = MemoryRegion::new(0, 0x40000000);
+
 main!(main);
 
 /// Entry point for VM bootloader.
@@ -49,6 +59,56 @@
     }
 
     check_alloc();
+
+    let mut idmap = IdMap::new(ASID, ROOT_LEVEL);
+    idmap.map_range(&DEVICE_REGION, Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER).unwrap();
+    idmap
+        .map_range(
+            &text_region(),
+            Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::READ_ONLY,
+        )
+        .unwrap();
+    idmap
+        .map_range(
+            &rodata_region(),
+            Attributes::NORMAL
+                | Attributes::NON_GLOBAL
+                | Attributes::READ_ONLY
+                | Attributes::EXECUTE_NEVER,
+        )
+        .unwrap();
+    idmap
+        .map_range(
+            &writable_region(),
+            Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::EXECUTE_NEVER,
+        )
+        .unwrap();
+
+    println!("Activating IdMap...");
+    println!("{:?}", idmap);
+    idmap.activate();
+    println!("Activated.");
+
+    check_data();
+}
+
+/// Executable code.
+fn text_region() -> MemoryRegion {
+    unsafe { MemoryRegion::new(&text_begin as *const u8 as usize, &text_end as *const u8 as usize) }
+}
+
+/// Read-only data.
+fn rodata_region() -> MemoryRegion {
+    unsafe {
+        MemoryRegion::new(&rodata_begin as *const u8 as usize, &rodata_end as *const u8 as usize)
+    }
+}
+
+/// Writable data, including the stack.
+fn writable_region() -> MemoryRegion {
+    unsafe {
+        MemoryRegion::new(&data_begin as *const u8 as usize, &boot_stack_end as *const u8 as usize)
+    }
 }
 
 fn print_addresses() {
@@ -121,6 +181,8 @@
         assert_eq!(MUTABLE_DATA[3], 4);
         MUTABLE_DATA[0] += 41;
         assert_eq!(MUTABLE_DATA[0], 42);
+        MUTABLE_DATA[0] -= 41;
+        assert_eq!(MUTABLE_DATA[0], 1);
     }
     println!("Data looks good");
 }