Эх сурвалжийг харах

Test reading and writing block device.

Andrew Walbran 2 жил өмнө
parent
commit
63b964c1aa
1 өөрчлөгдсөн 203 нэмэгдсэн , 0 устгасан
  1. 203 0
      src/device/blk.rs

+ 203 - 0
src/device/blk.rs

@@ -460,3 +460,206 @@ bitflags! {
         const NOTIFICATION_DATA     = 1 << 38;
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{
+        hal::fake::FakeHal,
+        transport::{
+            fake::{FakeTransport, QueueStatus, State},
+            DeviceStatus, DeviceType,
+        },
+    };
+    use alloc::{sync::Arc, vec};
+    use core::{mem::size_of, ptr::NonNull};
+    use std::{sync::Mutex, thread, time::Duration};
+
+    #[test]
+    fn config() {
+        let mut config_space = BlkConfig {
+            capacity_low: Volatile::new(0x42),
+            capacity_high: Volatile::new(0x02),
+            size_max: Volatile::new(0),
+            seg_max: Volatile::new(0),
+            cylinders: Volatile::new(0),
+            heads: Volatile::new(0),
+            sectors: Volatile::new(0),
+            blk_size: Volatile::new(0),
+            physical_block_exp: Volatile::new(0),
+            alignment_offset: Volatile::new(0),
+            min_io_size: Volatile::new(0),
+            opt_io_size: Volatile::new(0),
+        };
+        let state = Arc::new(Mutex::new(State {
+            status: DeviceStatus::empty(),
+            driver_features: 0,
+            guest_page_size: 0,
+            interrupt_pending: false,
+            queues: vec![QueueStatus::default(); 1],
+        }));
+        let transport = FakeTransport {
+            device_type: DeviceType::Console,
+            max_queue_size: QUEUE_SIZE.into(),
+            device_features: BlkFeature::RO.bits(),
+            config_space: NonNull::from(&mut config_space),
+            state: state.clone(),
+        };
+        let blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
+
+        assert_eq!(blk.capacity(), 0x02_0000_0042);
+        assert_eq!(blk.readonly(), true);
+    }
+
+    #[test]
+    fn read() {
+        let mut config_space = BlkConfig {
+            capacity_low: Volatile::new(66),
+            capacity_high: Volatile::new(0),
+            size_max: Volatile::new(0),
+            seg_max: Volatile::new(0),
+            cylinders: Volatile::new(0),
+            heads: Volatile::new(0),
+            sectors: Volatile::new(0),
+            blk_size: Volatile::new(0),
+            physical_block_exp: Volatile::new(0),
+            alignment_offset: Volatile::new(0),
+            min_io_size: Volatile::new(0),
+            opt_io_size: Volatile::new(0),
+        };
+        let state = Arc::new(Mutex::new(State {
+            status: DeviceStatus::empty(),
+            driver_features: 0,
+            guest_page_size: 0,
+            interrupt_pending: false,
+            queues: vec![QueueStatus::default(); 1],
+        }));
+        let transport = FakeTransport {
+            device_type: DeviceType::Console,
+            max_queue_size: QUEUE_SIZE.into(),
+            device_features: 0,
+            config_space: NonNull::from(&mut config_space),
+            state: state.clone(),
+        };
+        let mut blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
+
+        // Start a thread to simulate the device waiting for a read request.
+        let handle = thread::spawn(move || {
+            println!("Device waiting for a request.");
+            while !state.lock().unwrap().queues[usize::from(QUEUE)].notified {
+                thread::sleep(Duration::from_millis(10));
+            }
+            println!("Transmit queue was notified.");
+
+            state
+                .lock()
+                .unwrap()
+                .read_write_queue::<{ QUEUE_SIZE as usize }>(QUEUE, |request| {
+                    assert_eq!(
+                        request,
+                        BlkReq {
+                            type_: ReqType::In,
+                            reserved: 0,
+                            sector: 42
+                        }
+                        .as_bytes()
+                    );
+
+                    let mut response = vec![0; SECTOR_SIZE];
+                    response[0..9].copy_from_slice(b"Test data");
+                    response.extend_from_slice(
+                        BlkResp {
+                            status: RespStatus::OK,
+                        }
+                        .as_bytes(),
+                    );
+
+                    response
+                });
+        });
+
+        // Read a block from the device.
+        let mut buffer = [0; 512];
+        blk.read_block(42, &mut buffer).unwrap();
+        assert_eq!(&buffer[0..9], b"Test data");
+
+        handle.join().unwrap();
+    }
+
+    #[test]
+    fn write() {
+        let mut config_space = BlkConfig {
+            capacity_low: Volatile::new(66),
+            capacity_high: Volatile::new(0),
+            size_max: Volatile::new(0),
+            seg_max: Volatile::new(0),
+            cylinders: Volatile::new(0),
+            heads: Volatile::new(0),
+            sectors: Volatile::new(0),
+            blk_size: Volatile::new(0),
+            physical_block_exp: Volatile::new(0),
+            alignment_offset: Volatile::new(0),
+            min_io_size: Volatile::new(0),
+            opt_io_size: Volatile::new(0),
+        };
+        let state = Arc::new(Mutex::new(State {
+            status: DeviceStatus::empty(),
+            driver_features: 0,
+            guest_page_size: 0,
+            interrupt_pending: false,
+            queues: vec![QueueStatus::default(); 1],
+        }));
+        let transport = FakeTransport {
+            device_type: DeviceType::Console,
+            max_queue_size: QUEUE_SIZE.into(),
+            device_features: 0,
+            config_space: NonNull::from(&mut config_space),
+            state: state.clone(),
+        };
+        let mut blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
+
+        // Start a thread to simulate the device waiting for a write request.
+        let handle = thread::spawn(move || {
+            println!("Device waiting for a request.");
+            while !state.lock().unwrap().queues[usize::from(QUEUE)].notified {
+                thread::sleep(Duration::from_millis(10));
+            }
+            println!("Transmit queue was notified.");
+
+            state
+                .lock()
+                .unwrap()
+                .read_write_queue::<{ QUEUE_SIZE as usize }>(QUEUE, |request| {
+                    assert_eq!(
+                        &request[0..size_of::<BlkReq>()],
+                        BlkReq {
+                            type_: ReqType::Out,
+                            reserved: 0,
+                            sector: 42
+                        }
+                        .as_bytes()
+                    );
+                    let data = &request[size_of::<BlkReq>()..];
+                    assert_eq!(data.len(), SECTOR_SIZE);
+                    assert_eq!(&data[0..9], b"Test data");
+
+                    let mut response = Vec::new();
+                    response.extend_from_slice(
+                        BlkResp {
+                            status: RespStatus::OK,
+                        }
+                        .as_bytes(),
+                    );
+
+                    response
+                });
+        });
+
+        // Write a block to the device.
+        let mut buffer = [0; 512];
+        buffer[0..9].copy_from_slice(b"Test data");
+        blk.write_block(42, &mut buffer).unwrap();
+
+        handle.join().unwrap();
+    }
+}