devices/virtio/iommu/sys/linux/
vfio_wrapper.rs1use std::sync::Arc;
8
9use anyhow::Context;
10use base::AsRawDescriptor;
11use base::AsRawDescriptors;
12use base::Protection;
13use base::RawDescriptor;
14use sync::Mutex;
15use vm_memory::GuestAddress;
16use vm_memory::GuestMemory;
17
18use crate::vfio::VfioError;
19use crate::virtio::iommu::memory_mapper::AddMapResult;
20use crate::virtio::iommu::memory_mapper::MappingInfo;
21use crate::virtio::iommu::memory_mapper::MemoryMapper;
22use crate::virtio::iommu::memory_mapper::RemoveMapResult;
23use crate::VfioContainer;
24
25pub struct VfioWrapper {
26 container: Arc<Mutex<VfioContainer>>,
27 id: u32,
30 mem: GuestMemory,
31}
32
33impl VfioWrapper {
34 pub fn new(container: Arc<Mutex<VfioContainer>>, mem: GuestMemory) -> Self {
35 let c = container.lock();
36 let groups = c.group_ids();
37 assert!(groups.len() == 1);
39 let id = *groups[0];
40 drop(c);
41 Self { container, id, mem }
42 }
43
44 pub fn new_with_id(container: VfioContainer, id: u32, mem: GuestMemory) -> Self {
45 Self {
46 container: Arc::new(Mutex::new(container)),
47 id,
48 mem,
49 }
50 }
51
52 pub fn clone_as_raw_descriptor(&self) -> Result<RawDescriptor, VfioError> {
53 self.container.lock().clone_as_raw_descriptor()
54 }
55
56 unsafe fn do_map(&self, map: MappingInfo) -> anyhow::Result<AddMapResult> {
57 let res = self.container.lock().vfio_dma_map(
58 map.iova,
59 map.size,
60 map.gpa.offset(),
61 map.prot.allows(&Protection::write()),
62 );
63 if let Err(VfioError::IommuDmaMap(err)) = res {
64 if err.errno() == libc::EEXIST {
65 return Ok(AddMapResult::OverlapFailure);
67 }
68 }
69 res.context("vfio mapping error").map(|_| AddMapResult::Ok)
70 }
71}
72
73impl MemoryMapper for VfioWrapper {
74 fn add_map(&mut self, mut map: MappingInfo) -> anyhow::Result<AddMapResult> {
75 map.gpa = GuestAddress(
76 self.mem
77 .get_host_address_range(map.gpa, map.size as usize)
78 .context("failed to find host address")? as u64,
79 );
80
81 unsafe { self.do_map(map) }
85 }
86
87 unsafe fn vfio_dma_map(
88 &mut self,
89 iova: u64,
90 hva: u64,
91 size: u64,
92 prot: Protection,
93 ) -> anyhow::Result<AddMapResult> {
94 self.do_map(MappingInfo {
95 iova,
96 gpa: GuestAddress(hva),
97 size,
98 prot,
99 })
100 }
101
102 fn remove_map(&mut self, iova_start: u64, size: u64) -> anyhow::Result<RemoveMapResult> {
103 iova_start.checked_add(size).context("iova overflow")?;
104 self.container
105 .lock()
106 .vfio_dma_unmap(iova_start, size)
107 .context("vfio unmapping error")
108 .map(|_| RemoveMapResult::Success(None))
109 }
110
111 fn get_mask(&self) -> anyhow::Result<u64> {
112 self.container
113 .lock()
114 .vfio_get_iommu_page_size_mask()
115 .context("vfio get mask error")
116 }
117
118 fn supports_detach(&self) -> bool {
119 false
132 }
133
134 fn id(&self) -> u32 {
135 self.id
136 }
137}
138
139impl AsRawDescriptors for VfioWrapper {
140 fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
141 vec![self.container.lock().as_raw_descriptor()]
142 }
143}