From ce6446501d48fe3396903f9add09a338a96ffa9c Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Wed, 26 Jan 2022 11:35:48 +0100 Subject: [PATCH] virtio-devices: Handle queue addresses translation Upon the enablement of the queue by the guest, we perform a translation of the descriptor table, the available ring and used ring addresses prior to enabling the device itself. This only applies to the case where the device is placed behind a vIOMMU, which is the reason why the translation is needed. Indeed, the addresses allocated by the guest are IOVAs which must be translated into GPAs before we can access the queue. Signed-off-by: Sebastien Boeuf --- .../src/transport/pci_common_config.rs | 31 +++++++++++++++++-- virtio-devices/src/transport/pci_device.rs | 1 + 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/virtio-devices/src/transport/pci_common_config.rs b/virtio-devices/src/transport/pci_common_config.rs index 67290a6b8..0f37ecb44 100644 --- a/virtio-devices/src/transport/pci_common_config.rs +++ b/virtio-devices/src/transport/pci_common_config.rs @@ -12,7 +12,7 @@ use std::sync::atomic::{AtomicU16, Ordering}; use std::sync::{Arc, Mutex}; use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize_derive::Versionize; -use virtio_queue::Queue; +use virtio_queue::{AccessPlatform, Queue}; use vm_memory::{GuestAddress, GuestMemoryAtomic}; use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped}; @@ -52,6 +52,7 @@ impl VersionMapped for VirtioPciCommonConfigState {} /// le64 queue_avail; // 0x28 // read-write /// le64 queue_used; // 0x30 // read-write pub struct VirtioPciCommonConfig { + pub access_platform: Option>, pub driver_status: u8, pub config_generation: u8, pub device_feature_select: u32, @@ -196,7 +197,32 @@ impl VirtioPciCommonConfig { 0x16 => self.queue_select = value, 0x18 => self.with_queue_mut(queues, |q| q.state.size = value), 0x1a => self.msix_queues.lock().unwrap()[self.queue_select as usize] = value, - 0x1c => self.with_queue_mut(queues, |q| q.enable(value == 1)), + 0x1c => self.with_queue_mut(queues, |q| { + let ready = value == 1; + q.set_ready(ready); + // Translate address of descriptor table and vrings. + if let Some(access_platform) = &self.access_platform { + if ready { + let desc_table = + access_platform.translate(q.state.desc_table.0, 0).unwrap(); + let avail_ring = + access_platform.translate(q.state.avail_ring.0, 0).unwrap(); + let used_ring = access_platform.translate(q.state.used_ring.0, 0).unwrap(); + q.set_desc_table_address( + Some((desc_table & 0xffff_ffff) as u32), + Some((desc_table >> 32) as u32), + ); + q.set_avail_ring_address( + Some((avail_ring & 0xffff_ffff) as u32), + Some((avail_ring >> 32) as u32), + ); + q.set_used_ring_address( + Some((used_ring & 0xffff_ffff) as u32), + Some((used_ring >> 32) as u32), + ); + } + } + }), _ => { warn!("invalid virtio register word write: 0x{:x}", offset); } @@ -374,6 +400,7 @@ mod tests { #[test] fn write_base_regs() { let mut regs = VirtioPciCommonConfig { + access_platform: None, driver_status: 0xaa, config_generation: 0x55, device_feature_select: 0x0, diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs index b684496aa..2854a966c 100644 --- a/virtio-devices/src/transport/pci_device.rs +++ b/virtio-devices/src/transport/pci_device.rs @@ -423,6 +423,7 @@ impl VirtioPciDevice { id, configuration, common_config: VirtioPciCommonConfig { + access_platform, driver_status: 0, config_generation: 0, device_feature_select: 0,