diff --git a/devices/src/virtio/mod.rs b/devices/src/virtio/mod.rs index c0b84fe66d..a1701f5894 100644 --- a/devices/src/virtio/mod.rs +++ b/devices/src/virtio/mod.rs @@ -49,6 +49,7 @@ pub use self::wl::*; use std::cmp; use std::convert::TryFrom; +const DEVICE_RESET: u32 = 0x0; const DEVICE_ACKNOWLEDGE: u32 = 0x01; const DEVICE_DRIVER: u32 = 0x02; const DEVICE_DRIVER_OK: u32 = 0x04; diff --git a/devices/src/virtio/queue.rs b/devices/src/virtio/queue.rs index 78a9cc377d..153449a657 100644 --- a/devices/src/virtio/queue.rs +++ b/devices/src/virtio/queue.rs @@ -245,6 +245,18 @@ impl Queue { min(self.size, self.max_size) } + /// Reset queue to a clean state + pub fn reset(&mut self) { + self.ready = false; + self.size = self.max_size; + self.vector = VIRTIO_MSI_NO_VECTOR; + self.desc_table = GuestAddress(0); + self.avail_ring = GuestAddress(0); + self.used_ring = GuestAddress(0); + self.next_avail = Wrapping(0); + self.next_used = Wrapping(0); + } + pub fn is_valid(&self, mem: &GuestMemory) -> bool { let queue_size = self.actual_size() as usize; let desc_table = self.desc_table; diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs index dbfaa699af..2be272c284 100644 --- a/devices/src/virtio/virtio_pci_device.rs +++ b/devices/src/virtio/virtio_pci_device.rs @@ -297,6 +297,11 @@ impl VirtioPciDevice { && self.common_config.driver_status & DEVICE_FAILED as u8 == 0 } + /// Determines if the driver has requested the device reset itself + fn is_reset_requested(&self) -> bool { + self.common_config.driver_status == DEVICE_RESET as u8 + } + fn are_queues_valid(&self) -> bool { if let Some(mem) = self.mem.as_ref() { self.queues.iter().all(|q| q.is_valid(mem)) @@ -688,5 +693,16 @@ impl PciDevice for VirtioPciDevice { } } } + + // Device has been reset by the driver + if self.device_activated && self.is_reset_requested() { + if self.device.reset() { + self.device_activated = false; + // reset queues + self.queues.iter_mut().for_each(Queue::reset); + // select queue 0 by default + self.common_config.queue_select = 0; + } + } } }