Test reading from a VirtIO block device.

Bug: 237250092
Test: atest vmbase_example.integration_test
Change-Id: I42b57d5b07f397becf954ef949c1a2c5c4067b19
diff --git a/vmbase/example/src/pci.rs b/vmbase/example/src/pci.rs
index e4a4b04..10a67b9 100644
--- a/vmbase/example/src/pci.rs
+++ b/vmbase/example/src/pci.rs
@@ -16,7 +16,7 @@
 
 use aarch64_paging::paging::MemoryRegion;
 use alloc::alloc::{alloc, dealloc, Layout};
-use core::ffi::CStr;
+use core::{ffi::CStr, mem::size_of};
 use libfdt::{Fdt, FdtNode, Reg};
 use log::{debug, info};
 use virtio_drivers::{
@@ -28,7 +28,10 @@
 };
 
 /// The standard sector size of a VirtIO block device, in bytes.
-const SECTOR_SIZE_BYTES: u64 = 512;
+const SECTOR_SIZE_BYTES: usize = 512;
+
+/// The size in sectors of the test block device we expect.
+const EXPECTED_SECTOR_COUNT: usize = 4;
 
 /// Finds an FDT node with compatible=pci-host-cam-generic.
 pub fn pci_node(fdt: &Fdt) -> FdtNode {
@@ -40,6 +43,7 @@
 
 pub fn check_pci(reg: Reg<u64>, allocator: &mut PciMemory32Allocator) {
     let mut pci_root = unsafe { PciRoot::new(reg.addr as *mut u8, Cam::MmioCam) };
+    let mut checked_virtio_device_count = 0;
     for (device_function, info) in pci_root.enumerate_bus(0) {
         let (status, command) = pci_root.get_status_command(device_function);
         info!("Found {} at {}, status {:?} command {:?}", info, device_function, status, command);
@@ -53,15 +57,35 @@
                 transport.device_type(),
                 transport.read_device_features(),
             );
-            instantiate_virtio_driver(transport, virtio_type);
+            if check_virtio_device(transport, virtio_type) {
+                checked_virtio_device_count += 1;
+            }
         }
     }
+
+    assert_eq!(checked_virtio_device_count, 1);
 }
 
-fn instantiate_virtio_driver(transport: impl Transport, device_type: DeviceType) {
+/// Checks the given VirtIO device, if we know how to.
+///
+/// Returns true if the device was checked, or false if it was ignored.
+fn check_virtio_device(transport: impl Transport, device_type: DeviceType) -> bool {
     if device_type == DeviceType::Block {
-        let blk = VirtIOBlk::<HalImpl, _>::new(transport).expect("failed to create blk driver");
-        info!("Found {} KiB block device.", blk.capacity() * SECTOR_SIZE_BYTES / 1024);
+        let mut blk = VirtIOBlk::<HalImpl, _>::new(transport).expect("failed to create blk driver");
+        info!("Found {} KiB block device.", blk.capacity() * SECTOR_SIZE_BYTES as u64 / 1024);
+        assert_eq!(blk.capacity(), EXPECTED_SECTOR_COUNT as u64);
+        let mut data = [0; SECTOR_SIZE_BYTES * EXPECTED_SECTOR_COUNT];
+        for i in 0..EXPECTED_SECTOR_COUNT {
+            blk.read_block(i, &mut data[i * SECTOR_SIZE_BYTES..(i + 1) * SECTOR_SIZE_BYTES])
+                .expect("Failed to read block device.");
+        }
+        for (i, chunk) in data.chunks(size_of::<u32>()).enumerate() {
+            assert_eq!(chunk, &(i as u32).to_le_bytes());
+        }
+        info!("Read expected data from block device.");
+        true
+    } else {
+        false
     }
 }
 
diff --git a/vmbase/example/tests/test.rs b/vmbase/example/tests/test.rs
index 57b68ed..d58c8e6 100644
--- a/vmbase/example/tests/test.rs
+++ b/vmbase/example/tests/test.rs
@@ -16,7 +16,7 @@
 
 use android_system_virtualizationservice::{
     aidl::android::system::virtualizationservice::{
-        VirtualMachineConfig::VirtualMachineConfig,
+        DiskImage::DiskImage, VirtualMachineConfig::VirtualMachineConfig,
         VirtualMachineRawConfig::VirtualMachineRawConfig,
     },
     binder::{ParcelFileDescriptor, ProcessState},
@@ -25,7 +25,7 @@
 use log::info;
 use std::{
     fs::File,
-    io::{self, BufRead, BufReader},
+    io::{self, BufRead, BufReader, Write},
     os::unix::io::FromRawFd,
     panic, thread,
 };
@@ -33,6 +33,7 @@
 
 const VMBASE_EXAMPLE_PATH: &str =
     "/data/local/tmp/vmbase_example.integration_test/arm64/vmbase_example.bin";
+const TEST_DISK_IMAGE_PATH: &str = "/data/local/tmp/vmbase_example.integration_test/test_disk.img";
 
 /// Runs the vmbase_example VM as an unprotected VM via VirtualizationService.
 #[test]
@@ -57,13 +58,28 @@
             .with_context(|| format!("Failed to open VM image {}", VMBASE_EXAMPLE_PATH))?,
     );
 
+    // Make file for test disk image.
+    let mut test_image = File::options()
+        .create(true)
+        .read(true)
+        .write(true)
+        .truncate(true)
+        .open(TEST_DISK_IMAGE_PATH)
+        .with_context(|| format!("Failed to open test disk image {}", TEST_DISK_IMAGE_PATH))?;
+    // Write 4 sectors worth of 4-byte numbers counting up.
+    for i in 0u32..512 {
+        test_image.write_all(&i.to_le_bytes())?;
+    }
+    let test_image = ParcelFileDescriptor::new(test_image);
+    let disk_image = DiskImage { image: Some(test_image), writable: false, partitions: vec![] };
+
     let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
         name: String::from("VmBaseTest"),
         kernel: None,
         initrd: None,
         params: None,
         bootloader: Some(bootloader),
-        disks: vec![],
+        disks: vec![disk_image],
         protectedVm: false,
         memoryMib: 300,
         numCpus: 1,