mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio: Port codebase to the latest virtio-queue version
The new virtio-queue version introduced some breaking changes which need to be addressed so that Cloud Hypervisor can still work with this version. The most important change is about removing a handle to the guest memory from the Queue, meaning the caller has to provide the guest memory handle for multiple methods from the QueueT trait. One interesting aspect is that QueueT has been widely extended to provide every getter and setter we need to access and update the Queue structure without having direct access to its internal fields. This patch ports all the virtio and vhost-user devices to this new crate definition. It also updates both vhost-user-block and vhost-user-net backends based on the updated vhost-user-backend crate. It also updates the fuzz directory. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
committed by
Rob Bradford
parent
7199119bb2
commit
a423bf13ad
@@ -6,14 +6,13 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use crate::{GuestMemoryMmap, VirtioDevice};
|
||||
use crate::VirtioDevice;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
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 vm_memory::{GuestAddress, GuestMemoryAtomic};
|
||||
use virtio_queue::{Queue, QueueT};
|
||||
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
|
||||
use vm_virtio::AccessPlatform;
|
||||
|
||||
@@ -90,7 +89,7 @@ impl VirtioPciCommonConfig {
|
||||
&mut self,
|
||||
offset: u64,
|
||||
data: &mut [u8],
|
||||
queues: &mut [Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
queues: &mut [Queue],
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
assert!(data.len() <= 8);
|
||||
@@ -120,7 +119,7 @@ impl VirtioPciCommonConfig {
|
||||
&mut self,
|
||||
offset: u64,
|
||||
data: &[u8],
|
||||
queues: &mut [Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
queues: &mut [Queue],
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
assert!(data.len() <= 8);
|
||||
@@ -159,20 +158,16 @@ impl VirtioPciCommonConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_common_config_word(
|
||||
&self,
|
||||
offset: u64,
|
||||
queues: &[Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
) -> u16 {
|
||||
fn read_common_config_word(&self, offset: u64, queues: &[Queue]) -> u16 {
|
||||
debug!("read_common_config_word: offset 0x{:x}", offset);
|
||||
match offset {
|
||||
0x10 => self.msix_config.load(Ordering::Acquire),
|
||||
0x12 => queues.len() as u16, // num_queues
|
||||
0x16 => self.queue_select,
|
||||
0x18 => self.with_queue(queues, |q| q.state.size).unwrap_or(0),
|
||||
0x18 => self.with_queue(queues, |q| q.size()).unwrap_or(0),
|
||||
0x1a => self.msix_queues.lock().unwrap()[self.queue_select as usize],
|
||||
0x1c => {
|
||||
if self.with_queue(queues, |q| q.state.ready).unwrap_or(false) {
|
||||
if self.with_queue(queues, |q| q.ready()).unwrap_or(false) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
@@ -186,17 +181,12 @@ impl VirtioPciCommonConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_common_config_word(
|
||||
&mut self,
|
||||
offset: u64,
|
||||
value: u16,
|
||||
queues: &mut [Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
) {
|
||||
fn write_common_config_word(&mut self, offset: u64, value: u16, queues: &mut [Queue]) {
|
||||
debug!("write_common_config_word: offset 0x{:x}", offset);
|
||||
match offset {
|
||||
0x10 => self.msix_config.store(value, Ordering::Release),
|
||||
0x16 => self.queue_select = value,
|
||||
0x18 => self.with_queue_mut(queues, |q| q.state.size = value),
|
||||
0x18 => self.with_queue_mut(queues, |q| q.set_size(value)),
|
||||
0x1a => self.msix_queues.lock().unwrap()[self.queue_select as usize] = value,
|
||||
0x1c => self.with_queue_mut(queues, |q| {
|
||||
let ready = value == 1;
|
||||
@@ -204,15 +194,9 @@ impl VirtioPciCommonConfig {
|
||||
// Translate address of descriptor table and vrings.
|
||||
if let Some(access_platform) = &self.access_platform {
|
||||
if ready {
|
||||
let desc_table = access_platform
|
||||
.translate_gva(q.state.desc_table.0, 0)
|
||||
.unwrap();
|
||||
let avail_ring = access_platform
|
||||
.translate_gva(q.state.avail_ring.0, 0)
|
||||
.unwrap();
|
||||
let used_ring = access_platform
|
||||
.translate_gva(q.state.used_ring.0, 0)
|
||||
.unwrap();
|
||||
let desc_table = access_platform.translate_gva(q.desc_table(), 0).unwrap();
|
||||
let avail_ring = access_platform.translate_gva(q.avail_ring(), 0).unwrap();
|
||||
let used_ring = access_platform.translate_gva(q.used_ring(), 0).unwrap();
|
||||
q.set_desc_table_address(
|
||||
Some((desc_table & 0xffff_ffff) as u32),
|
||||
Some((desc_table >> 32) as u32),
|
||||
@@ -260,17 +244,10 @@ impl VirtioPciCommonConfig {
|
||||
&mut self,
|
||||
offset: u64,
|
||||
value: u32,
|
||||
queues: &mut [Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
queues: &mut [Queue],
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
debug!("write_common_config_dword: offset 0x{:x}", offset);
|
||||
fn hi(v: &mut GuestAddress, x: u32) {
|
||||
*v = (*v & 0xffff_ffff) | ((u64::from(x)) << 32)
|
||||
}
|
||||
|
||||
fn lo(v: &mut GuestAddress, x: u32) {
|
||||
*v = (*v & !0xffff_ffff) | (u64::from(x))
|
||||
}
|
||||
|
||||
match offset {
|
||||
0x00 => self.device_feature_select = value,
|
||||
@@ -287,12 +264,12 @@ impl VirtioPciCommonConfig {
|
||||
);
|
||||
}
|
||||
}
|
||||
0x20 => self.with_queue_mut(queues, |q| lo(&mut q.state.desc_table, value)),
|
||||
0x24 => self.with_queue_mut(queues, |q| hi(&mut q.state.desc_table, value)),
|
||||
0x28 => self.with_queue_mut(queues, |q| lo(&mut q.state.avail_ring, value)),
|
||||
0x2c => self.with_queue_mut(queues, |q| hi(&mut q.state.avail_ring, value)),
|
||||
0x30 => self.with_queue_mut(queues, |q| lo(&mut q.state.used_ring, value)),
|
||||
0x34 => self.with_queue_mut(queues, |q| hi(&mut q.state.used_ring, value)),
|
||||
0x20 => self.with_queue_mut(queues, |q| q.set_desc_table_address(Some(value), None)),
|
||||
0x24 => self.with_queue_mut(queues, |q| q.set_desc_table_address(None, Some(value))),
|
||||
0x28 => self.with_queue_mut(queues, |q| q.set_avail_ring_address(Some(value), None)),
|
||||
0x2c => self.with_queue_mut(queues, |q| q.set_avail_ring_address(None, Some(value))),
|
||||
0x30 => self.with_queue_mut(queues, |q| q.set_used_ring_address(Some(value), None)),
|
||||
0x34 => self.with_queue_mut(queues, |q| q.set_used_ring_address(None, Some(value))),
|
||||
_ => {
|
||||
warn!("invalid virtio register dword write: 0x{:x}", offset);
|
||||
}
|
||||
@@ -304,39 +281,30 @@ impl VirtioPciCommonConfig {
|
||||
0 // Assume the guest has no reason to read write-only registers.
|
||||
}
|
||||
|
||||
fn write_common_config_qword(
|
||||
&mut self,
|
||||
offset: u64,
|
||||
value: u64,
|
||||
queues: &mut [Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
) {
|
||||
fn write_common_config_qword(&mut self, offset: u64, value: u64, queues: &mut [Queue]) {
|
||||
debug!("write_common_config_qword: offset 0x{:x}", offset);
|
||||
|
||||
let low = Some((value & 0xffff_ffff) as u32);
|
||||
let high = Some((value >> 32) as u32);
|
||||
|
||||
match offset {
|
||||
0x20 => self.with_queue_mut(queues, |q| q.state.desc_table = GuestAddress(value)),
|
||||
0x28 => self.with_queue_mut(queues, |q| q.state.avail_ring = GuestAddress(value)),
|
||||
0x30 => self.with_queue_mut(queues, |q| q.state.used_ring = GuestAddress(value)),
|
||||
0x20 => self.with_queue_mut(queues, |q| q.set_desc_table_address(low, high)),
|
||||
0x28 => self.with_queue_mut(queues, |q| q.set_avail_ring_address(low, high)),
|
||||
0x30 => self.with_queue_mut(queues, |q| q.set_used_ring_address(low, high)),
|
||||
_ => {
|
||||
warn!("invalid virtio register qword write: 0x{:x}", offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_queue<U, F>(
|
||||
&self,
|
||||
queues: &[Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
f: F,
|
||||
) -> Option<U>
|
||||
fn with_queue<U, F>(&self, queues: &[Queue], f: F) -> Option<U>
|
||||
where
|
||||
F: FnOnce(&Queue<GuestMemoryAtomic<GuestMemoryMmap>>) -> U,
|
||||
F: FnOnce(&Queue) -> U,
|
||||
{
|
||||
queues.get(self.queue_select as usize).map(f)
|
||||
}
|
||||
|
||||
fn with_queue_mut<F: FnOnce(&mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>)>(
|
||||
&self,
|
||||
queues: &mut [Queue<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
f: F,
|
||||
) {
|
||||
fn with_queue_mut<F: FnOnce(&mut Queue)>(&self, queues: &mut [Queue], f: F) {
|
||||
if let Some(queue) = queues.get_mut(self.queue_select as usize) {
|
||||
f(queue);
|
||||
}
|
||||
@@ -385,7 +353,7 @@ mod tests {
|
||||
&mut self,
|
||||
_mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
_interrupt_evt: Arc<dyn VirtioInterrupt>,
|
||||
_queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
|
||||
_queues: Vec<(usize, Queue, EventFd)>,
|
||||
) -> ActivateResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -24,19 +24,20 @@ use pci::{
|
||||
use std::any::Any;
|
||||
use std::cmp;
|
||||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
use std::result;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU16, AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_queue::{Error as QueueError, Queue};
|
||||
use virtio_queue::{Error as QueueError, Queue, QueueT};
|
||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||
use vm_device::interrupt::{
|
||||
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
|
||||
};
|
||||
use vm_device::{BusDevice, Resource};
|
||||
use vm_memory::{Address, ByteValued, GuestAddress, GuestMemoryAtomic, Le32};
|
||||
use vm_memory::{Address, ByteValued, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, Le32};
|
||||
use vm_migration::{
|
||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
||||
};
|
||||
@@ -292,8 +293,7 @@ pub struct VirtioPciDeviceActivator {
|
||||
memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
device_activated: Arc<AtomicBool>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
queues: Option<Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>>,
|
||||
queues: Option<Vec<(usize, Queue, EventFd)>>,
|
||||
barrier: Option<Arc<Barrier>>,
|
||||
id: String,
|
||||
}
|
||||
@@ -342,11 +342,11 @@ pub struct VirtioPciDevice {
|
||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||
|
||||
// virtio queues
|
||||
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
||||
queues: Vec<Queue>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
|
||||
// Guest memory
|
||||
memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
memory: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
|
||||
// Settings PCI BAR
|
||||
settings_bar: u8,
|
||||
@@ -406,12 +406,7 @@ impl VirtioPciDevice {
|
||||
let queues = locked_device
|
||||
.queue_max_sizes()
|
||||
.iter()
|
||||
.map(|&s| {
|
||||
Queue::<GuestMemoryAtomic<GuestMemoryMmap>, virtio_queue::QueueState>::new(
|
||||
memory.clone(),
|
||||
s,
|
||||
)
|
||||
})
|
||||
.map(|&s| Queue::new(s).unwrap())
|
||||
.collect();
|
||||
|
||||
let pci_device_id = VIRTIO_PCI_DEVICE_ID_BASE + locked_device.device_type() as u16;
|
||||
@@ -482,7 +477,7 @@ impl VirtioPciDevice {
|
||||
virtio_interrupt: None,
|
||||
queues,
|
||||
queue_evts,
|
||||
memory: Some(memory),
|
||||
memory,
|
||||
settings_bar: 0,
|
||||
use_64bit_bar,
|
||||
interrupt_source_group,
|
||||
@@ -514,11 +509,11 @@ impl VirtioPciDevice {
|
||||
.iter()
|
||||
.map(|q| QueueState {
|
||||
max_size: q.max_size(),
|
||||
size: q.state.size,
|
||||
ready: q.state.ready,
|
||||
desc_table: q.state.desc_table.0,
|
||||
avail_ring: q.state.avail_ring.0,
|
||||
used_ring: q.state.used_ring.0,
|
||||
size: q.size(),
|
||||
ready: q.ready(),
|
||||
desc_table: q.desc_table(),
|
||||
avail_ring: q.avail_ring(),
|
||||
used_ring: q.used_ring(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
@@ -532,20 +527,26 @@ impl VirtioPciDevice {
|
||||
|
||||
// Update virtqueues indexes for both available and used rings.
|
||||
for (i, queue) in self.queues.iter_mut().enumerate() {
|
||||
queue.state.size = state.queues[i].size;
|
||||
queue.state.ready = state.queues[i].ready;
|
||||
queue.state.desc_table = GuestAddress(state.queues[i].desc_table);
|
||||
queue.state.avail_ring = GuestAddress(state.queues[i].avail_ring);
|
||||
queue.state.used_ring = GuestAddress(state.queues[i].used_ring);
|
||||
queue.set_size(state.queues[i].size);
|
||||
queue.set_ready(state.queues[i].ready);
|
||||
queue
|
||||
.try_set_desc_table_address(GuestAddress(state.queues[i].desc_table))
|
||||
.unwrap();
|
||||
queue
|
||||
.try_set_avail_ring_address(GuestAddress(state.queues[i].avail_ring))
|
||||
.unwrap();
|
||||
queue
|
||||
.try_set_used_ring_address(GuestAddress(state.queues[i].used_ring))
|
||||
.unwrap();
|
||||
queue.set_next_avail(
|
||||
queue
|
||||
.used_idx(Ordering::Acquire)
|
||||
.used_idx(self.memory.memory().deref(), Ordering::Acquire)
|
||||
.map_err(Error::QueueRingIndex)?
|
||||
.0,
|
||||
);
|
||||
queue.set_next_used(
|
||||
queue
|
||||
.used_idx(Ordering::Acquire)
|
||||
.used_idx(self.memory.memory().deref(), Ordering::Acquire)
|
||||
.map_err(Error::QueueRingIndex)?
|
||||
.0,
|
||||
);
|
||||
@@ -701,11 +702,11 @@ impl VirtioPciDevice {
|
||||
let mut queues = Vec::new();
|
||||
|
||||
for (queue_index, queue) in self.queues.iter().enumerate() {
|
||||
if !queue.state.ready {
|
||||
if !queue.ready() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !queue.is_valid() {
|
||||
if !queue.is_valid(self.memory.memory().deref()) {
|
||||
error!("Queue {} is not valid", queue_index);
|
||||
}
|
||||
|
||||
@@ -718,7 +719,7 @@ impl VirtioPciDevice {
|
||||
|
||||
VirtioPciDeviceActivator {
|
||||
interrupt: self.virtio_interrupt.take(),
|
||||
memory: self.memory.clone(),
|
||||
memory: Some(self.memory.clone()),
|
||||
device: self.device.clone(),
|
||||
queues: Some(queues),
|
||||
device_activated: self.device_activated.clone(),
|
||||
|
||||
Reference in New Issue
Block a user