-
Notifications
You must be signed in to change notification settings - Fork 107
Refine the VirtioDevice trait #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,12 +4,86 @@ | |
| // | ||
| // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause | ||
|
|
||
| use super::queue::Queue; | ||
| use super::*; | ||
| use std::sync::atomic::AtomicUsize; | ||
| use std::sync::Arc; | ||
| use vm_device::interrupt::{InterruptIndex, InterruptSourceGroup, InterruptSourceType}; | ||
| use vm_device::resources::DeviceResourceRequest; | ||
| use vm_memory::GuestMemory; | ||
| use vmm_sys_util::eventfd::EventFd; | ||
|
|
||
| /// Data struct to manage an virtio queue. | ||
| pub struct VirtioQueueConfig<'a, M: GuestMemory> { | ||
| /// A virtque. | ||
| pub queue: Queue<'a, M>, | ||
|
|
||
| /// And associated event notification fd. | ||
| pub queue_evt: EventFd, | ||
| } | ||
|
|
||
| /// Configuration information for an virtio device. | ||
| /// | ||
| /// The ownership of an virtio device configuration object will be moved into the VirtioDevice | ||
| /// object when VirtioDevice::activate() method gets called, and it should be returned back | ||
| /// if VirtioDevice::activate() fails or when VirtioDevice::reset() gets called. | ||
| pub struct VirtioDeviceConfig<'a, M: GuestMemory> { | ||
| /// Memory object to access the guest memory. | ||
| pub mem: M, | ||
|
|
||
| /// Virtqueues of the virtio device. | ||
| pub queues: Vec<VirtioQueueConfig<'a, M>>, | ||
|
|
||
| /// A group of interrupts to notify the guest for queue events. | ||
| pub intr_group: Arc<Box<dyn InterruptSourceGroup>>, | ||
| } | ||
|
|
||
| impl<'a, M> VirtioDeviceConfig<'a, M> | ||
| where | ||
| M: GuestMemory, | ||
| { | ||
| /// Constructs an virtio device configuration object. | ||
| pub fn new( | ||
| mem: M, | ||
| queues: Vec<VirtioQueueConfig<'a, M>>, | ||
| intr_group: Arc<Box<dyn InterruptSourceGroup>>, | ||
| ) -> Self { | ||
| VirtioDeviceConfig { | ||
| mem, | ||
| queues, | ||
| intr_group, | ||
| } | ||
| } | ||
|
|
||
| /// Trigger an interrupt for a specific event source. | ||
| pub fn trigger(&self, index: u32, flags: u32) -> Result<(), std::io::Error> { | ||
| match self.intr_group.get_type() { | ||
| InterruptSourceType::LegacyIrq => self.intr_group.trigger(0, flags), | ||
| InterruptSourceType::MsiIrq | InterruptSourceType::VfioMsiIrq(_, _) => { | ||
| self.intr_group.trigger(index, 0) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Get all irqfds associated with vritio queues. | ||
| pub fn get_vring_irqfds(&self) -> Vec<&EventFd> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a usecase where both LegacyIrq and MsiIrq are supported at the same time? It looks like the implementation of the DeviceConfig is wildly different depending on the interrupt system. Each function here is converted in a match on the type of interrupt.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per PCI spec, a device will work in Legacy mode after reset, and may switch to/from PCI MSI/MSI-x mode when OS programs the interrupt configuration registers. So it's a must for a PCI device to support both legacy and MSI/MSIx interrupts.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case, can we have |
||
| match self.intr_group.get_type() { | ||
| InterruptSourceType::LegacyIrq => { | ||
| let irqfd = self.intr_group.get_irqfd(0).unwrap(); | ||
| vec![irqfd; 1] | ||
| } | ||
| InterruptSourceType::MsiIrq | InterruptSourceType::VfioMsiIrq(_, _) => { | ||
| //Skip the first irqfd which is for device configuration change events. | ||
| let intr_len = self.intr_group.len() as usize; | ||
| let mut irqfds = Vec::with_capacity(intr_len - 1); | ||
| for index in 1..intr_len { | ||
| irqfds.push(self.intr_group.get_irqfd(index as InterruptIndex).unwrap()); | ||
| } | ||
| irqfds | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Trait for virtio devices to be driven by a virtio transport. | ||
| /// | ||
| /// The lifecycle of a virtio device is to be moved to a virtio transport, which will then query | ||
|
|
@@ -18,7 +92,7 @@ use vmm_sys_util::eventfd::EventFd; | |
| /// called and all the events, memory, and queues for device operation will be moved into the | ||
| /// device. Optionally, a virtio device can implement device reset in which it returns said | ||
| /// resources and resets its internal state. | ||
| pub trait VirtioDevice: Send { | ||
| pub trait VirtioDevice<M: GuestMemory>: Send { | ||
| /// Associated guest memory | ||
| type M: GuestMemory; | ||
|
|
||
|
|
@@ -43,19 +117,17 @@ pub trait VirtioDevice: Send { | |
| /// Writes to this device configuration space at `offset`. | ||
| fn write_config(&mut self, offset: u64, data: &[u8]); | ||
|
|
||
| /// Returns the resource requirements of the virtio device. | ||
| fn get_resource_requirements(&self, requests: &mut Vec<DeviceResourceRequest>); | ||
|
|
||
| /// Activates this device for real usage. | ||
| fn activate<M: GuestMemory>( | ||
| &mut self, | ||
| mem: Self::M, | ||
| interrupt_evt: EventFd, | ||
| status: Arc<AtomicUsize>, | ||
| queues: Vec<Queue<M>>, | ||
| queue_evts: Vec<EventFd>, | ||
| ) -> ActivateResult; | ||
|
|
||
| /// Optionally deactivates this device and returns ownership of the guest memory map, interrupt | ||
| /// event, and queue events. | ||
| fn reset(&mut self) -> Option<(EventFd, Vec<EventFd>)> { | ||
| /// The ownership of the VirtioDeviceConfig object moves into the VirtioDevice object if | ||
| /// activate succeeds, otherwise it should return the ownership back. | ||
| fn activate(&mut self, config: VirtioDeviceConfig<M>) -> ActivateResult<VirtioDeviceConfig<M>>; | ||
|
|
||
| /// Optional method to deactivate the device and return ownership of the VirtioDeviceConfig | ||
| /// object. | ||
| fn reset(&mut self) -> Option<VirtioDeviceConfig<M>> { | ||
| None | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.