xref: /aosp_15_r20/external/crosvm/devices/src/pci/coiommu.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! This is the CoIOMMU backend implementation. CoIOMMU is a virtual device
6*bb4ee6a4SAndroid Build Coastguard Worker //! which provide fine-grained pinning for the VFIO pci-passthrough device
7*bb4ee6a4SAndroid Build Coastguard Worker //! so that hypervisor doesn't need to pin the enter VM's memory to improve
8*bb4ee6a4SAndroid Build Coastguard Worker //! the memory utilization. CoIOMMU doesn't provide the intra-guest protection
9*bb4ee6a4SAndroid Build Coastguard Worker //! so it can only be used for the TRUSTED passthrough devices.
10*bb4ee6a4SAndroid Build Coastguard Worker //!
11*bb4ee6a4SAndroid Build Coastguard Worker //! CoIOMMU is presented at KVM forum 2020:
12*bb4ee6a4SAndroid Build Coastguard Worker //! <https://kvmforum2020.sched.com/event/eE2z/a-virtual-iommu-with-cooperative-dma-buffer-tracking-yu-zhang-intel>
13*bb4ee6a4SAndroid Build Coastguard Worker //!
14*bb4ee6a4SAndroid Build Coastguard Worker //! Also presented at usenix ATC20:
15*bb4ee6a4SAndroid Build Coastguard Worker //! <https://www.usenix.org/conference/atc20/presentation/tian>
16*bb4ee6a4SAndroid Build Coastguard Worker 
17*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::VecDeque;
18*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto;
19*bb4ee6a4SAndroid Build Coastguard Worker use std::default::Default;
20*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt;
21*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
22*bb4ee6a4SAndroid Build Coastguard Worker use std::panic;
23*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::fence;
24*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicU32;
25*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering;
26*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
27*bb4ee6a4SAndroid Build Coastguard Worker use std::thread;
28*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail;
31*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::ensure;
32*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
33*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
34*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
35*bb4ee6a4SAndroid Build Coastguard Worker use base::info;
36*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
37*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
38*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken;
39*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMapping;
40*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingBuilder;
41*bb4ee6a4SAndroid Build Coastguard Worker use base::Protection;
42*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
43*bb4ee6a4SAndroid Build Coastguard Worker use base::SafeDescriptor;
44*bb4ee6a4SAndroid Build Coastguard Worker use base::SharedMemory;
45*bb4ee6a4SAndroid Build Coastguard Worker use base::Timer;
46*bb4ee6a4SAndroid Build Coastguard Worker use base::TimerTrait;
47*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
48*bb4ee6a4SAndroid Build Coastguard Worker use base::TubeError;
49*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
50*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
51*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Datamatch;
52*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MemCacheType;
53*bb4ee6a4SAndroid Build Coastguard Worker use resources::Alloc;
54*bb4ee6a4SAndroid Build Coastguard Worker use resources::AllocOptions;
55*bb4ee6a4SAndroid Build Coastguard Worker use resources::SystemAllocator;
56*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
57*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserializer;
58*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
59*bb4ee6a4SAndroid Build Coastguard Worker use serde_keyvalue::FromKeyValues;
60*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
61*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
62*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::api::VmMemoryClient;
63*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmMemoryDestination;
64*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmMemorySource;
65*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
66*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
67*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
68*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
69*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciBarConfiguration;
72*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciBarPrefetchable;
73*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciBarRegionType;
74*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciClassCode;
75*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciConfiguration;
76*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciHeaderType;
77*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciOtherSubclass;
78*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::COMMAND_REG;
79*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::COMMAND_REG_MEMORY_SPACE_MASK;
80*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_device::BarRange;
81*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_device::PciDevice;
82*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_device::Result as PciResult;
83*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciAddress;
84*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciBarIndex;
85*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciDeviceError;
86*bb4ee6a4SAndroid Build Coastguard Worker use crate::vfio::VfioContainer;
87*bb4ee6a4SAndroid Build Coastguard Worker use crate::Suspendable;
88*bb4ee6a4SAndroid Build Coastguard Worker use crate::UnpinRequest;
89*bb4ee6a4SAndroid Build Coastguard Worker use crate::UnpinResponse;
90*bb4ee6a4SAndroid Build Coastguard Worker 
91*bb4ee6a4SAndroid Build Coastguard Worker const PCI_VENDOR_ID_COIOMMU: u16 = 0x1234;
92*bb4ee6a4SAndroid Build Coastguard Worker const PCI_DEVICE_ID_COIOMMU: u16 = 0xabcd;
93*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_CMD_DEACTIVATE: u64 = 0;
94*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_CMD_ACTIVATE: u64 = 1;
95*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_CMD_PARK_UNPIN: u64 = 2;
96*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_CMD_UNPARK_UNPIN: u64 = 3;
97*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_REVISION_ID: u8 = 0x10;
98*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_MMIO_BAR: PciBarIndex = 0;
99*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_MMIO_BAR_SIZE: u64 = 0x2000;
100*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_NOTIFYMAP_BAR: PciBarIndex = 2;
101*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_NOTIFYMAP_SIZE: usize = 0x2000;
102*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_TOPOLOGYMAP_BAR: u8 = 4;
103*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_TOPOLOGYMAP_SIZE: usize = 0x2000;
104*bb4ee6a4SAndroid Build Coastguard Worker const PAGE_SIZE_4K: u64 = 4096;
105*bb4ee6a4SAndroid Build Coastguard Worker const PAGE_SHIFT_4K: u64 = 12;
106*bb4ee6a4SAndroid Build Coastguard Worker const PIN_PAGES_IN_BATCH: u64 = 1 << 63;
107*bb4ee6a4SAndroid Build Coastguard Worker 
108*bb4ee6a4SAndroid Build Coastguard Worker const DTTE_PINNED_FLAG: u32 = 1 << 31;
109*bb4ee6a4SAndroid Build Coastguard Worker const DTTE_ACCESSED_FLAG: u32 = 1 << 30;
110*bb4ee6a4SAndroid Build Coastguard Worker const DTT_ENTRY_PRESENT: u64 = 1;
111*bb4ee6a4SAndroid Build Coastguard Worker const DTT_ENTRY_PFN_SHIFT: u64 = 12;
112*bb4ee6a4SAndroid Build Coastguard Worker 
113*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
114*bb4ee6a4SAndroid Build Coastguard Worker enum Error {
115*bb4ee6a4SAndroid Build Coastguard Worker     #[error("CoIommu failed to create shared memory")]
116*bb4ee6a4SAndroid Build Coastguard Worker     CreateSharedMemory,
117*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Failed to get DTT entry")]
118*bb4ee6a4SAndroid Build Coastguard Worker     GetDTTEntry,
119*bb4ee6a4SAndroid Build Coastguard Worker }
120*bb4ee6a4SAndroid Build Coastguard Worker 
121*bb4ee6a4SAndroid Build Coastguard Worker //default interval is 60s
122*bb4ee6a4SAndroid Build Coastguard Worker const UNPIN_DEFAULT_INTERVAL: Duration = Duration::from_secs(60);
123*bb4ee6a4SAndroid Build Coastguard Worker const UNPIN_GEN_DEFAULT_THRES: u64 = 10;
124*bb4ee6a4SAndroid Build Coastguard Worker /// Holds the coiommu unpin policy
125*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
126*bb4ee6a4SAndroid Build Coastguard Worker #[serde(rename_all = "kebab-case")]
127*bb4ee6a4SAndroid Build Coastguard Worker pub enum CoIommuUnpinPolicy {
128*bb4ee6a4SAndroid Build Coastguard Worker     #[default]
129*bb4ee6a4SAndroid Build Coastguard Worker     Off,
130*bb4ee6a4SAndroid Build Coastguard Worker     Lru,
131*bb4ee6a4SAndroid Build Coastguard Worker }
132*bb4ee6a4SAndroid Build Coastguard Worker 
133*bb4ee6a4SAndroid Build Coastguard Worker impl fmt::Display for CoIommuUnpinPolicy {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result134*bb4ee6a4SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135*bb4ee6a4SAndroid Build Coastguard Worker         use self::CoIommuUnpinPolicy::*;
136*bb4ee6a4SAndroid Build Coastguard Worker 
137*bb4ee6a4SAndroid Build Coastguard Worker         match self {
138*bb4ee6a4SAndroid Build Coastguard Worker             Off => write!(f, "off"),
139*bb4ee6a4SAndroid Build Coastguard Worker             Lru => write!(f, "lru"),
140*bb4ee6a4SAndroid Build Coastguard Worker         }
141*bb4ee6a4SAndroid Build Coastguard Worker     }
142*bb4ee6a4SAndroid Build Coastguard Worker }
143*bb4ee6a4SAndroid Build Coastguard Worker 
deserialize_unpin_interval<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result<Duration, D::Error>144*bb4ee6a4SAndroid Build Coastguard Worker fn deserialize_unpin_interval<'de, D: Deserializer<'de>>(
145*bb4ee6a4SAndroid Build Coastguard Worker     deserializer: D,
146*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Duration, D::Error> {
147*bb4ee6a4SAndroid Build Coastguard Worker     let secs = u64::deserialize(deserializer)?;
148*bb4ee6a4SAndroid Build Coastguard Worker 
149*bb4ee6a4SAndroid Build Coastguard Worker     Ok(Duration::from_secs(secs))
150*bb4ee6a4SAndroid Build Coastguard Worker }
151*bb4ee6a4SAndroid Build Coastguard Worker 
deserialize_unpin_limit<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result<Option<u64>, D::Error>152*bb4ee6a4SAndroid Build Coastguard Worker fn deserialize_unpin_limit<'de, D: Deserializer<'de>>(
153*bb4ee6a4SAndroid Build Coastguard Worker     deserializer: D,
154*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Option<u64>, D::Error> {
155*bb4ee6a4SAndroid Build Coastguard Worker     let limit = u64::deserialize(deserializer)?;
156*bb4ee6a4SAndroid Build Coastguard Worker 
157*bb4ee6a4SAndroid Build Coastguard Worker     match limit {
158*bb4ee6a4SAndroid Build Coastguard Worker         0 => Err(serde::de::Error::custom(
159*bb4ee6a4SAndroid Build Coastguard Worker             "Please use non-zero unpin_limit value",
160*bb4ee6a4SAndroid Build Coastguard Worker         )),
161*bb4ee6a4SAndroid Build Coastguard Worker         limit => Ok(Some(limit)),
162*bb4ee6a4SAndroid Build Coastguard Worker     }
163*bb4ee6a4SAndroid Build Coastguard Worker }
164*bb4ee6a4SAndroid Build Coastguard Worker 
unpin_interval_default() -> Duration165*bb4ee6a4SAndroid Build Coastguard Worker fn unpin_interval_default() -> Duration {
166*bb4ee6a4SAndroid Build Coastguard Worker     UNPIN_DEFAULT_INTERVAL
167*bb4ee6a4SAndroid Build Coastguard Worker }
168*bb4ee6a4SAndroid Build Coastguard Worker 
unpin_gen_threshold_default() -> u64169*bb4ee6a4SAndroid Build Coastguard Worker fn unpin_gen_threshold_default() -> u64 {
170*bb4ee6a4SAndroid Build Coastguard Worker     UNPIN_GEN_DEFAULT_THRES
171*bb4ee6a4SAndroid Build Coastguard Worker }
172*bb4ee6a4SAndroid Build Coastguard Worker 
173*bb4ee6a4SAndroid Build Coastguard Worker /// Holds the parameters for a coiommu device
174*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, FromKeyValues)]
175*bb4ee6a4SAndroid Build Coastguard Worker #[serde(deny_unknown_fields)]
176*bb4ee6a4SAndroid Build Coastguard Worker pub struct CoIommuParameters {
177*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default)]
178*bb4ee6a4SAndroid Build Coastguard Worker     pub unpin_policy: CoIommuUnpinPolicy,
179*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(
180*bb4ee6a4SAndroid Build Coastguard Worker         deserialize_with = "deserialize_unpin_interval",
181*bb4ee6a4SAndroid Build Coastguard Worker         default = "unpin_interval_default"
182*bb4ee6a4SAndroid Build Coastguard Worker     )]
183*bb4ee6a4SAndroid Build Coastguard Worker     pub unpin_interval: Duration,
184*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(deserialize_with = "deserialize_unpin_limit", default)]
185*bb4ee6a4SAndroid Build Coastguard Worker     pub unpin_limit: Option<u64>,
186*bb4ee6a4SAndroid Build Coastguard Worker     // Number of unpin intervals a pinned page must be busy for to be aged into the
187*bb4ee6a4SAndroid Build Coastguard Worker     // older, less frequently checked generation.
188*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default = "unpin_gen_threshold_default")]
189*bb4ee6a4SAndroid Build Coastguard Worker     pub unpin_gen_threshold: u64,
190*bb4ee6a4SAndroid Build Coastguard Worker }
191*bb4ee6a4SAndroid Build Coastguard Worker 
192*bb4ee6a4SAndroid Build Coastguard Worker impl Default for CoIommuParameters {
default() -> Self193*bb4ee6a4SAndroid Build Coastguard Worker     fn default() -> Self {
194*bb4ee6a4SAndroid Build Coastguard Worker         Self {
195*bb4ee6a4SAndroid Build Coastguard Worker             unpin_policy: CoIommuUnpinPolicy::Off,
196*bb4ee6a4SAndroid Build Coastguard Worker             unpin_interval: UNPIN_DEFAULT_INTERVAL,
197*bb4ee6a4SAndroid Build Coastguard Worker             unpin_limit: None,
198*bb4ee6a4SAndroid Build Coastguard Worker             unpin_gen_threshold: UNPIN_GEN_DEFAULT_THRES,
199*bb4ee6a4SAndroid Build Coastguard Worker         }
200*bb4ee6a4SAndroid Build Coastguard Worker     }
201*bb4ee6a4SAndroid Build Coastguard Worker }
202*bb4ee6a4SAndroid Build Coastguard Worker 
203*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default, Debug, Copy, Clone)]
204*bb4ee6a4SAndroid Build Coastguard Worker struct CoIommuReg {
205*bb4ee6a4SAndroid Build Coastguard Worker     dtt_root: u64,
206*bb4ee6a4SAndroid Build Coastguard Worker     cmd: u64,
207*bb4ee6a4SAndroid Build Coastguard Worker     dtt_level: u64,
208*bb4ee6a4SAndroid Build Coastguard Worker }
209*bb4ee6a4SAndroid Build Coastguard Worker 
210*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
211*bb4ee6a4SAndroid Build Coastguard Worker struct PinnedPageInfo {
212*bb4ee6a4SAndroid Build Coastguard Worker     gfn: u64,
213*bb4ee6a4SAndroid Build Coastguard Worker     unpin_busy_cnt: u64,
214*bb4ee6a4SAndroid Build Coastguard Worker }
215*bb4ee6a4SAndroid Build Coastguard Worker 
216*bb4ee6a4SAndroid Build Coastguard Worker impl PinnedPageInfo {
new(gfn: u64, unpin_busy_cnt: u64) -> Self217*bb4ee6a4SAndroid Build Coastguard Worker     fn new(gfn: u64, unpin_busy_cnt: u64) -> Self {
218*bb4ee6a4SAndroid Build Coastguard Worker         PinnedPageInfo {
219*bb4ee6a4SAndroid Build Coastguard Worker             gfn,
220*bb4ee6a4SAndroid Build Coastguard Worker             unpin_busy_cnt,
221*bb4ee6a4SAndroid Build Coastguard Worker         }
222*bb4ee6a4SAndroid Build Coastguard Worker     }
223*bb4ee6a4SAndroid Build Coastguard Worker }
224*bb4ee6a4SAndroid Build Coastguard Worker 
225*bb4ee6a4SAndroid Build Coastguard Worker #[derive(PartialEq, Debug, Eq)]
226*bb4ee6a4SAndroid Build Coastguard Worker enum UnpinThreadState {
227*bb4ee6a4SAndroid Build Coastguard Worker     Unparked,
228*bb4ee6a4SAndroid Build Coastguard Worker     Parked,
229*bb4ee6a4SAndroid Build Coastguard Worker }
230*bb4ee6a4SAndroid Build Coastguard Worker 
231*bb4ee6a4SAndroid Build Coastguard Worker struct CoIommuPinState {
232*bb4ee6a4SAndroid Build Coastguard Worker     new_gen_pinned_pages: VecDeque<PinnedPageInfo>,
233*bb4ee6a4SAndroid Build Coastguard Worker     old_gen_pinned_pages: VecDeque<u64>,
234*bb4ee6a4SAndroid Build Coastguard Worker     unpin_thread_state: UnpinThreadState,
235*bb4ee6a4SAndroid Build Coastguard Worker     unpin_park_count: u64,
236*bb4ee6a4SAndroid Build Coastguard Worker }
237*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_map( vfio_container: &Arc<Mutex<VfioContainer>>, iova: u64, size: u64, user_addr: u64, ) -> bool238*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn vfio_map(
239*bb4ee6a4SAndroid Build Coastguard Worker     vfio_container: &Arc<Mutex<VfioContainer>>,
240*bb4ee6a4SAndroid Build Coastguard Worker     iova: u64,
241*bb4ee6a4SAndroid Build Coastguard Worker     size: u64,
242*bb4ee6a4SAndroid Build Coastguard Worker     user_addr: u64,
243*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
244*bb4ee6a4SAndroid Build Coastguard Worker     match vfio_container
245*bb4ee6a4SAndroid Build Coastguard Worker         .lock()
246*bb4ee6a4SAndroid Build Coastguard Worker         .vfio_dma_map(iova, size, user_addr, true)
247*bb4ee6a4SAndroid Build Coastguard Worker     {
248*bb4ee6a4SAndroid Build Coastguard Worker         Ok(_) => true,
249*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
250*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(errno) = std::io::Error::last_os_error().raw_os_error() {
251*bb4ee6a4SAndroid Build Coastguard Worker                 if errno == libc::EEXIST {
252*bb4ee6a4SAndroid Build Coastguard Worker                     // Already pinned. set PINNED flag
253*bb4ee6a4SAndroid Build Coastguard Worker                     error!("CoIommu: iova 0x{:x} already pinned", iova);
254*bb4ee6a4SAndroid Build Coastguard Worker                     return true;
255*bb4ee6a4SAndroid Build Coastguard Worker                 }
256*bb4ee6a4SAndroid Build Coastguard Worker             }
257*bb4ee6a4SAndroid Build Coastguard Worker             error!("CoIommu: failed to map iova 0x{:x}: {}", iova, e);
258*bb4ee6a4SAndroid Build Coastguard Worker             false
259*bb4ee6a4SAndroid Build Coastguard Worker         }
260*bb4ee6a4SAndroid Build Coastguard Worker     }
261*bb4ee6a4SAndroid Build Coastguard Worker }
262*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_unmap(vfio_container: &Arc<Mutex<VfioContainer>>, iova: u64, size: u64) -> bool263*bb4ee6a4SAndroid Build Coastguard Worker fn vfio_unmap(vfio_container: &Arc<Mutex<VfioContainer>>, iova: u64, size: u64) -> bool {
264*bb4ee6a4SAndroid Build Coastguard Worker     match vfio_container.lock().vfio_dma_unmap(iova, size) {
265*bb4ee6a4SAndroid Build Coastguard Worker         Ok(_) => true,
266*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
267*bb4ee6a4SAndroid Build Coastguard Worker             error!("CoIommu: failed to unmap iova 0x{:x}: {}", iova, e);
268*bb4ee6a4SAndroid Build Coastguard Worker             false
269*bb4ee6a4SAndroid Build Coastguard Worker         }
270*bb4ee6a4SAndroid Build Coastguard Worker     }
271*bb4ee6a4SAndroid Build Coastguard Worker }
272*bb4ee6a4SAndroid Build Coastguard Worker 
273*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default, Debug, Copy, Clone, FromZeroes, FromBytes, AsBytes)]
274*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
275*bb4ee6a4SAndroid Build Coastguard Worker struct PinPageInfo {
276*bb4ee6a4SAndroid Build Coastguard Worker     bdf: u16,
277*bb4ee6a4SAndroid Build Coastguard Worker     pad: [u16; 3],
278*bb4ee6a4SAndroid Build Coastguard Worker     nr_pages: u64,
279*bb4ee6a4SAndroid Build Coastguard Worker }
280*bb4ee6a4SAndroid Build Coastguard Worker 
281*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_UPPER_LEVEL_STRIDE: u64 = 9;
282*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_UPPER_LEVEL_MASK: u64 = (1 << COIOMMU_UPPER_LEVEL_STRIDE) - 1;
283*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_PT_LEVEL_STRIDE: u64 = 10;
284*bb4ee6a4SAndroid Build Coastguard Worker const COIOMMU_PT_LEVEL_MASK: u64 = (1 << COIOMMU_PT_LEVEL_STRIDE) - 1;
285*bb4ee6a4SAndroid Build Coastguard Worker 
level_to_offset(gfn: u64, level: u64) -> Result<u64>286*bb4ee6a4SAndroid Build Coastguard Worker fn level_to_offset(gfn: u64, level: u64) -> Result<u64> {
287*bb4ee6a4SAndroid Build Coastguard Worker     if level == 1 {
288*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(gfn & COIOMMU_PT_LEVEL_MASK);
289*bb4ee6a4SAndroid Build Coastguard Worker     }
290*bb4ee6a4SAndroid Build Coastguard Worker 
291*bb4ee6a4SAndroid Build Coastguard Worker     if level == 0 {
292*bb4ee6a4SAndroid Build Coastguard Worker         bail!("Invalid level for gfn 0x{:x}", gfn);
293*bb4ee6a4SAndroid Build Coastguard Worker     }
294*bb4ee6a4SAndroid Build Coastguard Worker 
295*bb4ee6a4SAndroid Build Coastguard Worker     let offset = COIOMMU_PT_LEVEL_STRIDE + (level - 2) * COIOMMU_UPPER_LEVEL_STRIDE;
296*bb4ee6a4SAndroid Build Coastguard Worker 
297*bb4ee6a4SAndroid Build Coastguard Worker     Ok((gfn >> offset) & COIOMMU_UPPER_LEVEL_MASK)
298*bb4ee6a4SAndroid Build Coastguard Worker }
299*bb4ee6a4SAndroid Build Coastguard Worker 
300*bb4ee6a4SAndroid Build Coastguard Worker struct DTTIter {
301*bb4ee6a4SAndroid Build Coastguard Worker     ptr: *const u8,
302*bb4ee6a4SAndroid Build Coastguard Worker     gfn: u64,
303*bb4ee6a4SAndroid Build Coastguard Worker }
304*bb4ee6a4SAndroid Build Coastguard Worker 
305*bb4ee6a4SAndroid Build Coastguard Worker impl Default for DTTIter {
default() -> Self306*bb4ee6a4SAndroid Build Coastguard Worker     fn default() -> Self {
307*bb4ee6a4SAndroid Build Coastguard Worker         DTTIter {
308*bb4ee6a4SAndroid Build Coastguard Worker             ptr: std::ptr::null(),
309*bb4ee6a4SAndroid Build Coastguard Worker             gfn: 0,
310*bb4ee6a4SAndroid Build Coastguard Worker         }
311*bb4ee6a4SAndroid Build Coastguard Worker     }
312*bb4ee6a4SAndroid Build Coastguard Worker }
313*bb4ee6a4SAndroid Build Coastguard Worker 
314*bb4ee6a4SAndroid Build Coastguard Worker // Get a DMA Tracking Table(DTT) entry associated with the gfn.
315*bb4ee6a4SAndroid Build Coastguard Worker //
316*bb4ee6a4SAndroid Build Coastguard Worker // There are two ways to get the entry:
317*bb4ee6a4SAndroid Build Coastguard Worker // #1. Walking the DMA Tracking Table(DTT) by the GFN to get the
318*bb4ee6a4SAndroid Build Coastguard Worker // corresponding entry. The DTT is shared between frontend and
319*bb4ee6a4SAndroid Build Coastguard Worker // backend. It is page-table-like strctures and the entry is indexed
320*bb4ee6a4SAndroid Build Coastguard Worker // by GFN. The argument dtt_root represents the root page
321*bb4ee6a4SAndroid Build Coastguard Worker // pga and dtt_level represents the maximum page table level.
322*bb4ee6a4SAndroid Build Coastguard Worker //
323*bb4ee6a4SAndroid Build Coastguard Worker // #2. Calculate the entry address via the argument dtt_iter. dtt_iter
324*bb4ee6a4SAndroid Build Coastguard Worker // stores an entry address and the associated gfn. If the target gfn is
325*bb4ee6a4SAndroid Build Coastguard Worker // in the same page table page with the gfn in dtt_iter, then can
326*bb4ee6a4SAndroid Build Coastguard Worker // calculate the target entry address based on the entry address in
327*bb4ee6a4SAndroid Build Coastguard Worker // dtt_iter.
328*bb4ee6a4SAndroid Build Coastguard Worker //
329*bb4ee6a4SAndroid Build Coastguard Worker // As the DTT entry is shared between frontend and backend, the accessing
330*bb4ee6a4SAndroid Build Coastguard Worker // should be atomic. So the returned value is converted to an AtomicU32
331*bb4ee6a4SAndroid Build Coastguard Worker // pointer.
gfn_to_dtt_pte( mem: &GuestMemory, dtt_level: u64, dtt_root: u64, dtt_iter: &mut DTTIter, gfn: u64, ) -> Result<*const AtomicU32>332*bb4ee6a4SAndroid Build Coastguard Worker fn gfn_to_dtt_pte(
333*bb4ee6a4SAndroid Build Coastguard Worker     mem: &GuestMemory,
334*bb4ee6a4SAndroid Build Coastguard Worker     dtt_level: u64,
335*bb4ee6a4SAndroid Build Coastguard Worker     dtt_root: u64,
336*bb4ee6a4SAndroid Build Coastguard Worker     dtt_iter: &mut DTTIter,
337*bb4ee6a4SAndroid Build Coastguard Worker     gfn: u64,
338*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<*const AtomicU32> {
339*bb4ee6a4SAndroid Build Coastguard Worker     let ptr = if dtt_iter.ptr.is_null()
340*bb4ee6a4SAndroid Build Coastguard Worker         || dtt_iter.gfn >> COIOMMU_PT_LEVEL_STRIDE != gfn >> COIOMMU_PT_LEVEL_STRIDE
341*bb4ee6a4SAndroid Build Coastguard Worker     {
342*bb4ee6a4SAndroid Build Coastguard Worker         // Slow path to walk the DTT to get the pte entry
343*bb4ee6a4SAndroid Build Coastguard Worker         let mut level = dtt_level;
344*bb4ee6a4SAndroid Build Coastguard Worker         let mut pt_gpa = dtt_root;
345*bb4ee6a4SAndroid Build Coastguard Worker         let dtt_nonleaf_entry_size = mem::size_of::<u64>() as u64;
346*bb4ee6a4SAndroid Build Coastguard Worker 
347*bb4ee6a4SAndroid Build Coastguard Worker         while level != 1 {
348*bb4ee6a4SAndroid Build Coastguard Worker             let index = level_to_offset(gfn, level)? * dtt_nonleaf_entry_size;
349*bb4ee6a4SAndroid Build Coastguard Worker             let parent_pt = mem
350*bb4ee6a4SAndroid Build Coastguard Worker                 .read_obj_from_addr::<u64>(GuestAddress(pt_gpa + index))
351*bb4ee6a4SAndroid Build Coastguard Worker                 .context(Error::GetDTTEntry)?;
352*bb4ee6a4SAndroid Build Coastguard Worker 
353*bb4ee6a4SAndroid Build Coastguard Worker             if (parent_pt & DTT_ENTRY_PRESENT) == 0 {
354*bb4ee6a4SAndroid Build Coastguard Worker                 bail!("DTT absent at level {} for gfn 0x{:x}", level, gfn);
355*bb4ee6a4SAndroid Build Coastguard Worker             }
356*bb4ee6a4SAndroid Build Coastguard Worker 
357*bb4ee6a4SAndroid Build Coastguard Worker             pt_gpa = (parent_pt >> DTT_ENTRY_PFN_SHIFT) << PAGE_SHIFT_4K;
358*bb4ee6a4SAndroid Build Coastguard Worker             level -= 1;
359*bb4ee6a4SAndroid Build Coastguard Worker         }
360*bb4ee6a4SAndroid Build Coastguard Worker 
361*bb4ee6a4SAndroid Build Coastguard Worker         let index = level_to_offset(gfn, level)? * mem::size_of::<u32>() as u64;
362*bb4ee6a4SAndroid Build Coastguard Worker 
363*bb4ee6a4SAndroid Build Coastguard Worker         mem.get_host_address(GuestAddress(pt_gpa + index))
364*bb4ee6a4SAndroid Build Coastguard Worker             .context(Error::GetDTTEntry)?
365*bb4ee6a4SAndroid Build Coastguard Worker     } else if gfn > dtt_iter.gfn {
366*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
367*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we checked that dtt_iter.ptr is valid and that the dtt_pte
368*bb4ee6a4SAndroid Build Coastguard Worker         // for gfn lies on the same dtt page as the dtt_pte for dtt_iter.gfn, which
369*bb4ee6a4SAndroid Build Coastguard Worker         // means the calculated ptr will point to the same page as dtt_iter.ptr
370*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
371*bb4ee6a4SAndroid Build Coastguard Worker             dtt_iter
372*bb4ee6a4SAndroid Build Coastguard Worker                 .ptr
373*bb4ee6a4SAndroid Build Coastguard Worker                 .add(mem::size_of::<AtomicU32>() * (gfn - dtt_iter.gfn) as usize)
374*bb4ee6a4SAndroid Build Coastguard Worker         }
375*bb4ee6a4SAndroid Build Coastguard Worker     } else {
376*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
377*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we checked that dtt_iter.ptr is valid and that the dtt_pte
378*bb4ee6a4SAndroid Build Coastguard Worker         // for gfn lies on the same dtt page as the dtt_pte for dtt_iter.gfn, which
379*bb4ee6a4SAndroid Build Coastguard Worker         // means the calculated ptr will point to the same page as dtt_iter.ptr
380*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
381*bb4ee6a4SAndroid Build Coastguard Worker             dtt_iter
382*bb4ee6a4SAndroid Build Coastguard Worker                 .ptr
383*bb4ee6a4SAndroid Build Coastguard Worker                 .sub(mem::size_of::<AtomicU32>() * (dtt_iter.gfn - gfn) as usize)
384*bb4ee6a4SAndroid Build Coastguard Worker         }
385*bb4ee6a4SAndroid Build Coastguard Worker     };
386*bb4ee6a4SAndroid Build Coastguard Worker 
387*bb4ee6a4SAndroid Build Coastguard Worker     dtt_iter.ptr = ptr;
388*bb4ee6a4SAndroid Build Coastguard Worker     dtt_iter.gfn = gfn;
389*bb4ee6a4SAndroid Build Coastguard Worker 
390*bb4ee6a4SAndroid Build Coastguard Worker     Ok(ptr as *const AtomicU32)
391*bb4ee6a4SAndroid Build Coastguard Worker }
392*bb4ee6a4SAndroid Build Coastguard Worker 
pin_page( pinstate: &mut CoIommuPinState, policy: CoIommuUnpinPolicy, vfio_container: &Arc<Mutex<VfioContainer>>, mem: &GuestMemory, dtt_level: u64, dtt_root: u64, dtt_iter: &mut DTTIter, gfn: u64, ) -> Result<()>393*bb4ee6a4SAndroid Build Coastguard Worker fn pin_page(
394*bb4ee6a4SAndroid Build Coastguard Worker     pinstate: &mut CoIommuPinState,
395*bb4ee6a4SAndroid Build Coastguard Worker     policy: CoIommuUnpinPolicy,
396*bb4ee6a4SAndroid Build Coastguard Worker     vfio_container: &Arc<Mutex<VfioContainer>>,
397*bb4ee6a4SAndroid Build Coastguard Worker     mem: &GuestMemory,
398*bb4ee6a4SAndroid Build Coastguard Worker     dtt_level: u64,
399*bb4ee6a4SAndroid Build Coastguard Worker     dtt_root: u64,
400*bb4ee6a4SAndroid Build Coastguard Worker     dtt_iter: &mut DTTIter,
401*bb4ee6a4SAndroid Build Coastguard Worker     gfn: u64,
402*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
403*bb4ee6a4SAndroid Build Coastguard Worker     let leaf_entry = gfn_to_dtt_pte(mem, dtt_level, dtt_root, dtt_iter, gfn)?;
404*bb4ee6a4SAndroid Build Coastguard Worker 
405*bb4ee6a4SAndroid Build Coastguard Worker     let gpa = gfn << PAGE_SHIFT_4K;
406*bb4ee6a4SAndroid Build Coastguard Worker     let host_addr = mem
407*bb4ee6a4SAndroid Build Coastguard Worker         .get_host_address_range(GuestAddress(gpa), PAGE_SIZE_4K as usize)
408*bb4ee6a4SAndroid Build Coastguard Worker         .context("failed to get host address")? as u64;
409*bb4ee6a4SAndroid Build Coastguard Worker 
410*bb4ee6a4SAndroid Build Coastguard Worker     // SAFETY:
411*bb4ee6a4SAndroid Build Coastguard Worker     // Safe because ptr is valid and guaranteed by the gfn_to_dtt_pte.
412*bb4ee6a4SAndroid Build Coastguard Worker     // Test PINNED flag
413*bb4ee6a4SAndroid Build Coastguard Worker     if (unsafe { (*leaf_entry).load(Ordering::Relaxed) } & DTTE_PINNED_FLAG) != 0 {
414*bb4ee6a4SAndroid Build Coastguard Worker         info!("CoIommu: gfn 0x{:x} already pinned", gfn);
415*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(());
416*bb4ee6a4SAndroid Build Coastguard Worker     }
417*bb4ee6a4SAndroid Build Coastguard Worker 
418*bb4ee6a4SAndroid Build Coastguard Worker     // SAFETY:
419*bb4ee6a4SAndroid Build Coastguard Worker     // Safe because the gpa is valid from the gfn_to_dtt_pte and the host_addr
420*bb4ee6a4SAndroid Build Coastguard Worker     // is guaranteed by MemoryMapping interface.
421*bb4ee6a4SAndroid Build Coastguard Worker     if unsafe { vfio_map(vfio_container, gpa, PAGE_SIZE_4K, host_addr) } {
422*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
423*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because ptr is valid and guaranteed by the gfn_to_dtt_pte.
424*bb4ee6a4SAndroid Build Coastguard Worker         // set PINNED flag
425*bb4ee6a4SAndroid Build Coastguard Worker         unsafe { (*leaf_entry).fetch_or(DTTE_PINNED_FLAG, Ordering::SeqCst) };
426*bb4ee6a4SAndroid Build Coastguard Worker         if policy == CoIommuUnpinPolicy::Lru {
427*bb4ee6a4SAndroid Build Coastguard Worker             pinstate
428*bb4ee6a4SAndroid Build Coastguard Worker                 .new_gen_pinned_pages
429*bb4ee6a4SAndroid Build Coastguard Worker                 .push_back(PinnedPageInfo::new(gfn, 0));
430*bb4ee6a4SAndroid Build Coastguard Worker         }
431*bb4ee6a4SAndroid Build Coastguard Worker     }
432*bb4ee6a4SAndroid Build Coastguard Worker 
433*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
434*bb4ee6a4SAndroid Build Coastguard Worker }
435*bb4ee6a4SAndroid Build Coastguard Worker 
436*bb4ee6a4SAndroid Build Coastguard Worker #[derive(PartialEq, Debug, Eq)]
437*bb4ee6a4SAndroid Build Coastguard Worker enum UnpinResult {
438*bb4ee6a4SAndroid Build Coastguard Worker     UnpinlistEmpty,
439*bb4ee6a4SAndroid Build Coastguard Worker     Unpinned,
440*bb4ee6a4SAndroid Build Coastguard Worker     NotPinned,
441*bb4ee6a4SAndroid Build Coastguard Worker     NotUnpinned,
442*bb4ee6a4SAndroid Build Coastguard Worker     FailedUnpin,
443*bb4ee6a4SAndroid Build Coastguard Worker     UnpinParked,
444*bb4ee6a4SAndroid Build Coastguard Worker }
445*bb4ee6a4SAndroid Build Coastguard Worker 
unpin_page( pinstate: &mut CoIommuPinState, vfio_container: &Arc<Mutex<VfioContainer>>, mem: &GuestMemory, dtt_level: u64, dtt_root: u64, dtt_iter: &mut DTTIter, gfn: u64, force: bool, ) -> UnpinResult446*bb4ee6a4SAndroid Build Coastguard Worker fn unpin_page(
447*bb4ee6a4SAndroid Build Coastguard Worker     pinstate: &mut CoIommuPinState,
448*bb4ee6a4SAndroid Build Coastguard Worker     vfio_container: &Arc<Mutex<VfioContainer>>,
449*bb4ee6a4SAndroid Build Coastguard Worker     mem: &GuestMemory,
450*bb4ee6a4SAndroid Build Coastguard Worker     dtt_level: u64,
451*bb4ee6a4SAndroid Build Coastguard Worker     dtt_root: u64,
452*bb4ee6a4SAndroid Build Coastguard Worker     dtt_iter: &mut DTTIter,
453*bb4ee6a4SAndroid Build Coastguard Worker     gfn: u64,
454*bb4ee6a4SAndroid Build Coastguard Worker     force: bool,
455*bb4ee6a4SAndroid Build Coastguard Worker ) -> UnpinResult {
456*bb4ee6a4SAndroid Build Coastguard Worker     if pinstate.unpin_thread_state == UnpinThreadState::Parked {
457*bb4ee6a4SAndroid Build Coastguard Worker         return UnpinResult::UnpinParked;
458*bb4ee6a4SAndroid Build Coastguard Worker     }
459*bb4ee6a4SAndroid Build Coastguard Worker 
460*bb4ee6a4SAndroid Build Coastguard Worker     let leaf_entry = match gfn_to_dtt_pte(mem, dtt_level, dtt_root, dtt_iter, gfn) {
461*bb4ee6a4SAndroid Build Coastguard Worker         Ok(v) => v,
462*bb4ee6a4SAndroid Build Coastguard Worker         Err(_) => {
463*bb4ee6a4SAndroid Build Coastguard Worker             // The case force == true may try to unpin a page which is not
464*bb4ee6a4SAndroid Build Coastguard Worker             // mapped in the dtt. For such page, the pte doesn't exist yet
465*bb4ee6a4SAndroid Build Coastguard Worker             // thus don't need to report any error log.
466*bb4ee6a4SAndroid Build Coastguard Worker             // The case force == false is used by coiommu to periodically
467*bb4ee6a4SAndroid Build Coastguard Worker             // unpin the pages which have been mapped in dtt, thus the pte
468*bb4ee6a4SAndroid Build Coastguard Worker             // for such page does exist. However with the unpin request from
469*bb4ee6a4SAndroid Build Coastguard Worker             // virtio balloon, such pages can be unpinned already and the DTT
470*bb4ee6a4SAndroid Build Coastguard Worker             // pages might be reclaimed by the Guest OS kernel as well, thus
471*bb4ee6a4SAndroid Build Coastguard Worker             // it is also possible to be here. Not to report an error log.
472*bb4ee6a4SAndroid Build Coastguard Worker             return UnpinResult::NotPinned;
473*bb4ee6a4SAndroid Build Coastguard Worker         }
474*bb4ee6a4SAndroid Build Coastguard Worker     };
475*bb4ee6a4SAndroid Build Coastguard Worker 
476*bb4ee6a4SAndroid Build Coastguard Worker     if force {
477*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
478*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because leaf_entry is valid and guaranteed by the gfn_to_dtt_pte.
479*bb4ee6a4SAndroid Build Coastguard Worker         // This case is for balloon to evict pages so these pages should
480*bb4ee6a4SAndroid Build Coastguard Worker         // already been locked by balloon and no device driver in VM is
481*bb4ee6a4SAndroid Build Coastguard Worker         // able to access these pages, so just clear ACCESSED flag first
482*bb4ee6a4SAndroid Build Coastguard Worker         // to make sure the following unpin can be success.
483*bb4ee6a4SAndroid Build Coastguard Worker         unsafe { (*leaf_entry).fetch_and(!DTTE_ACCESSED_FLAG, Ordering::SeqCst) };
484*bb4ee6a4SAndroid Build Coastguard Worker     }
485*bb4ee6a4SAndroid Build Coastguard Worker 
486*bb4ee6a4SAndroid Build Coastguard Worker     // SAFETY:
487*bb4ee6a4SAndroid Build Coastguard Worker     // Safe because leaf_entry is valid and guaranteed by the gfn_to_dtt_pte.
488*bb4ee6a4SAndroid Build Coastguard Worker     if let Err(entry) = unsafe {
489*bb4ee6a4SAndroid Build Coastguard Worker         (*leaf_entry).compare_exchange(DTTE_PINNED_FLAG, 0, Ordering::SeqCst, Ordering::SeqCst)
490*bb4ee6a4SAndroid Build Coastguard Worker     } {
491*bb4ee6a4SAndroid Build Coastguard Worker         // The compare_exchange failed as the original leaf entry is
492*bb4ee6a4SAndroid Build Coastguard Worker         // not DTTE_PINNED_FLAG so cannot do the unpin.
493*bb4ee6a4SAndroid Build Coastguard Worker         if entry == 0 {
494*bb4ee6a4SAndroid Build Coastguard Worker             // The GFN is already unpinned. This is very similar to the
495*bb4ee6a4SAndroid Build Coastguard Worker             // gfn_to_dtt_pte error case, with the only difference being
496*bb4ee6a4SAndroid Build Coastguard Worker             // that the dtt_pte happens to be on a present page table.
497*bb4ee6a4SAndroid Build Coastguard Worker             UnpinResult::NotPinned
498*bb4ee6a4SAndroid Build Coastguard Worker         } else {
499*bb4ee6a4SAndroid Build Coastguard Worker             if !force {
500*bb4ee6a4SAndroid Build Coastguard Worker                 // SAFETY:
501*bb4ee6a4SAndroid Build Coastguard Worker                 // Safe because leaf_entry is valid and guaranteed by the gfn_to_dtt_pte.
502*bb4ee6a4SAndroid Build Coastguard Worker                 // The ACCESSED_FLAG is set by the guest if guest requires DMA map for
503*bb4ee6a4SAndroid Build Coastguard Worker                 // this page. It represents whether or not this page is touched by the
504*bb4ee6a4SAndroid Build Coastguard Worker                 // guest. By clearing this flag after an unpin work, we can detect if
505*bb4ee6a4SAndroid Build Coastguard Worker                 // this page has been touched by the guest in the next round of unpin
506*bb4ee6a4SAndroid Build Coastguard Worker                 // work. If the ACCESSED_FLAG is set at the next round, unpin this page
507*bb4ee6a4SAndroid Build Coastguard Worker                 // will be failed and we will be here again to clear this flag. If this
508*bb4ee6a4SAndroid Build Coastguard Worker                 // flag is not set at the next round, unpin this page will be probably
509*bb4ee6a4SAndroid Build Coastguard Worker                 // success.
510*bb4ee6a4SAndroid Build Coastguard Worker                 unsafe { (*leaf_entry).fetch_and(!DTTE_ACCESSED_FLAG, Ordering::SeqCst) };
511*bb4ee6a4SAndroid Build Coastguard Worker             } else {
512*bb4ee6a4SAndroid Build Coastguard Worker                 // If we're here, then the guest is trying to release a page via the
513*bb4ee6a4SAndroid Build Coastguard Worker                 // balloon that it still has pinned. This most likely that something is
514*bb4ee6a4SAndroid Build Coastguard Worker                 // wrong in the guest kernel. Just leave the page pinned and log
515*bb4ee6a4SAndroid Build Coastguard Worker                 // an error.
516*bb4ee6a4SAndroid Build Coastguard Worker                 // This failure blocks the balloon from removing the page, which ensures
517*bb4ee6a4SAndroid Build Coastguard Worker                 // that the guest's view of memory will remain consistent with device
518*bb4ee6a4SAndroid Build Coastguard Worker                 // DMA's view of memory. Also note that the host kernel maintains an
519*bb4ee6a4SAndroid Build Coastguard Worker                 // elevated refcount for pinned pages, which is a second guarantee the
520*bb4ee6a4SAndroid Build Coastguard Worker                 // pages accessible by device DMA won't be freed until after they are
521*bb4ee6a4SAndroid Build Coastguard Worker                 // unpinned.
522*bb4ee6a4SAndroid Build Coastguard Worker                 error!(
523*bb4ee6a4SAndroid Build Coastguard Worker                     "CoIommu: force case cannot pin gfn 0x{:x} entry 0x{:x}",
524*bb4ee6a4SAndroid Build Coastguard Worker                     gfn, entry
525*bb4ee6a4SAndroid Build Coastguard Worker                 );
526*bb4ee6a4SAndroid Build Coastguard Worker             }
527*bb4ee6a4SAndroid Build Coastguard Worker             // GFN cannot be unpinned either because the unmap count
528*bb4ee6a4SAndroid Build Coastguard Worker             // is non-zero or the it has accessed flag set.
529*bb4ee6a4SAndroid Build Coastguard Worker             UnpinResult::NotUnpinned
530*bb4ee6a4SAndroid Build Coastguard Worker         }
531*bb4ee6a4SAndroid Build Coastguard Worker     } else {
532*bb4ee6a4SAndroid Build Coastguard Worker         // The compare_exchange success as the original leaf entry is
533*bb4ee6a4SAndroid Build Coastguard Worker         // DTTE_PINNED_FLAG and the new leaf entry is 0 now. Unpin the
534*bb4ee6a4SAndroid Build Coastguard Worker         // page.
535*bb4ee6a4SAndroid Build Coastguard Worker         let gpa = gfn << PAGE_SHIFT_4K;
536*bb4ee6a4SAndroid Build Coastguard Worker         if vfio_unmap(vfio_container, gpa, PAGE_SIZE_4K) {
537*bb4ee6a4SAndroid Build Coastguard Worker             UnpinResult::Unpinned
538*bb4ee6a4SAndroid Build Coastguard Worker         } else {
539*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
540*bb4ee6a4SAndroid Build Coastguard Worker             // Safe because leaf_entry is valid and guaranteed by the gfn_to_dtt_pte.
541*bb4ee6a4SAndroid Build Coastguard Worker             // make sure the pinned flag is set
542*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { (*leaf_entry).fetch_or(DTTE_PINNED_FLAG, Ordering::SeqCst) };
543*bb4ee6a4SAndroid Build Coastguard Worker             // need to put this gfn back to pinned vector
544*bb4ee6a4SAndroid Build Coastguard Worker             UnpinResult::FailedUnpin
545*bb4ee6a4SAndroid Build Coastguard Worker         }
546*bb4ee6a4SAndroid Build Coastguard Worker     }
547*bb4ee6a4SAndroid Build Coastguard Worker }
548*bb4ee6a4SAndroid Build Coastguard Worker 
549*bb4ee6a4SAndroid Build Coastguard Worker struct PinWorker {
550*bb4ee6a4SAndroid Build Coastguard Worker     mem: GuestMemory,
551*bb4ee6a4SAndroid Build Coastguard Worker     endpoints: Vec<u16>,
552*bb4ee6a4SAndroid Build Coastguard Worker     notifymap_mmap: Arc<MemoryMapping>,
553*bb4ee6a4SAndroid Build Coastguard Worker     dtt_level: u64,
554*bb4ee6a4SAndroid Build Coastguard Worker     dtt_root: u64,
555*bb4ee6a4SAndroid Build Coastguard Worker     ioevents: Vec<Event>,
556*bb4ee6a4SAndroid Build Coastguard Worker     vfio_container: Arc<Mutex<VfioContainer>>,
557*bb4ee6a4SAndroid Build Coastguard Worker     pinstate: Arc<Mutex<CoIommuPinState>>,
558*bb4ee6a4SAndroid Build Coastguard Worker     params: CoIommuParameters,
559*bb4ee6a4SAndroid Build Coastguard Worker }
560*bb4ee6a4SAndroid Build Coastguard Worker 
561*bb4ee6a4SAndroid Build Coastguard Worker impl PinWorker {
debug_label(&self) -> &'static str562*bb4ee6a4SAndroid Build Coastguard Worker     fn debug_label(&self) -> &'static str {
563*bb4ee6a4SAndroid Build Coastguard Worker         "CoIommuPinWorker"
564*bb4ee6a4SAndroid Build Coastguard Worker     }
565*bb4ee6a4SAndroid Build Coastguard Worker 
run(&mut self, kill_evt: Event)566*bb4ee6a4SAndroid Build Coastguard Worker     fn run(&mut self, kill_evt: Event) {
567*bb4ee6a4SAndroid Build Coastguard Worker         #[derive(EventToken)]
568*bb4ee6a4SAndroid Build Coastguard Worker         enum Token {
569*bb4ee6a4SAndroid Build Coastguard Worker             Kill,
570*bb4ee6a4SAndroid Build Coastguard Worker             Pin { index: usize },
571*bb4ee6a4SAndroid Build Coastguard Worker         }
572*bb4ee6a4SAndroid Build Coastguard Worker 
573*bb4ee6a4SAndroid Build Coastguard Worker         let wait_ctx: WaitContext<Token> =
574*bb4ee6a4SAndroid Build Coastguard Worker             match WaitContext::build_with(&[(&kill_evt, Token::Kill)]) {
575*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(pc) => pc,
576*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
577*bb4ee6a4SAndroid Build Coastguard Worker                     error!("{}: failed creating WaitContext: {}", self.debug_label(), e);
578*bb4ee6a4SAndroid Build Coastguard Worker                     return;
579*bb4ee6a4SAndroid Build Coastguard Worker                 }
580*bb4ee6a4SAndroid Build Coastguard Worker             };
581*bb4ee6a4SAndroid Build Coastguard Worker 
582*bb4ee6a4SAndroid Build Coastguard Worker         for (index, event) in self.ioevents.iter().enumerate() {
583*bb4ee6a4SAndroid Build Coastguard Worker             match wait_ctx.add(event, Token::Pin { index }) {
584*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(_) => {}
585*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
586*bb4ee6a4SAndroid Build Coastguard Worker                     error!(
587*bb4ee6a4SAndroid Build Coastguard Worker                         "{}: failed to add ioevent for index {}: {}",
588*bb4ee6a4SAndroid Build Coastguard Worker                         self.debug_label(),
589*bb4ee6a4SAndroid Build Coastguard Worker                         index,
590*bb4ee6a4SAndroid Build Coastguard Worker                         e
591*bb4ee6a4SAndroid Build Coastguard Worker                     );
592*bb4ee6a4SAndroid Build Coastguard Worker                     return;
593*bb4ee6a4SAndroid Build Coastguard Worker                 }
594*bb4ee6a4SAndroid Build Coastguard Worker             }
595*bb4ee6a4SAndroid Build Coastguard Worker         }
596*bb4ee6a4SAndroid Build Coastguard Worker 
597*bb4ee6a4SAndroid Build Coastguard Worker         'wait: loop {
598*bb4ee6a4SAndroid Build Coastguard Worker             let events = match wait_ctx.wait() {
599*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(v) => v,
600*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
601*bb4ee6a4SAndroid Build Coastguard Worker                     error!("{}: failed polling for events: {}", self.debug_label(), e);
602*bb4ee6a4SAndroid Build Coastguard Worker                     break;
603*bb4ee6a4SAndroid Build Coastguard Worker                 }
604*bb4ee6a4SAndroid Build Coastguard Worker             };
605*bb4ee6a4SAndroid Build Coastguard Worker 
606*bb4ee6a4SAndroid Build Coastguard Worker             for event in events.iter().filter(|e| e.is_readable) {
607*bb4ee6a4SAndroid Build Coastguard Worker                 match event.token {
608*bb4ee6a4SAndroid Build Coastguard Worker                     Token::Kill => break 'wait,
609*bb4ee6a4SAndroid Build Coastguard Worker                     Token::Pin { index } => {
610*bb4ee6a4SAndroid Build Coastguard Worker                         let offset = index * mem::size_of::<u64>();
611*bb4ee6a4SAndroid Build Coastguard Worker                         if let Some(event) = self.ioevents.get(index) {
612*bb4ee6a4SAndroid Build Coastguard Worker                             if let Err(e) = event.wait() {
613*bb4ee6a4SAndroid Build Coastguard Worker                                 error!(
614*bb4ee6a4SAndroid Build Coastguard Worker                                     "{}: failed reading event {}: {}",
615*bb4ee6a4SAndroid Build Coastguard Worker                                     self.debug_label(),
616*bb4ee6a4SAndroid Build Coastguard Worker                                     index,
617*bb4ee6a4SAndroid Build Coastguard Worker                                     e
618*bb4ee6a4SAndroid Build Coastguard Worker                                 );
619*bb4ee6a4SAndroid Build Coastguard Worker                                 self.notifymap_mmap.write_obj::<u64>(0, offset).unwrap();
620*bb4ee6a4SAndroid Build Coastguard Worker                                 break 'wait;
621*bb4ee6a4SAndroid Build Coastguard Worker                             }
622*bb4ee6a4SAndroid Build Coastguard Worker                         }
623*bb4ee6a4SAndroid Build Coastguard Worker                         if let Ok(data) = self.notifymap_mmap.read_obj::<u64>(offset) {
624*bb4ee6a4SAndroid Build Coastguard Worker                             if let Err(e) = self.pin_pages(data) {
625*bb4ee6a4SAndroid Build Coastguard Worker                                 error!("{}: {}", self.debug_label(), e);
626*bb4ee6a4SAndroid Build Coastguard Worker                             }
627*bb4ee6a4SAndroid Build Coastguard Worker                         }
628*bb4ee6a4SAndroid Build Coastguard Worker                         fence(Ordering::SeqCst);
629*bb4ee6a4SAndroid Build Coastguard Worker                         self.notifymap_mmap.write_obj::<u64>(0, offset).unwrap();
630*bb4ee6a4SAndroid Build Coastguard Worker                     }
631*bb4ee6a4SAndroid Build Coastguard Worker                 }
632*bb4ee6a4SAndroid Build Coastguard Worker             }
633*bb4ee6a4SAndroid Build Coastguard Worker         }
634*bb4ee6a4SAndroid Build Coastguard Worker     }
635*bb4ee6a4SAndroid Build Coastguard Worker 
pin_pages_in_batch(&mut self, gpa: u64) -> Result<()>636*bb4ee6a4SAndroid Build Coastguard Worker     fn pin_pages_in_batch(&mut self, gpa: u64) -> Result<()> {
637*bb4ee6a4SAndroid Build Coastguard Worker         let pin_page_info = self
638*bb4ee6a4SAndroid Build Coastguard Worker             .mem
639*bb4ee6a4SAndroid Build Coastguard Worker             .read_obj_from_addr::<PinPageInfo>(GuestAddress(gpa))
640*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to get pin page info")?;
641*bb4ee6a4SAndroid Build Coastguard Worker 
642*bb4ee6a4SAndroid Build Coastguard Worker         let bdf = pin_page_info.bdf;
643*bb4ee6a4SAndroid Build Coastguard Worker         ensure!(
644*bb4ee6a4SAndroid Build Coastguard Worker             self.endpoints.iter().any(|&x| x == bdf),
645*bb4ee6a4SAndroid Build Coastguard Worker             "pin page for unexpected bdf 0x{:x}",
646*bb4ee6a4SAndroid Build Coastguard Worker             bdf
647*bb4ee6a4SAndroid Build Coastguard Worker         );
648*bb4ee6a4SAndroid Build Coastguard Worker 
649*bb4ee6a4SAndroid Build Coastguard Worker         let mut nr_pages = pin_page_info.nr_pages;
650*bb4ee6a4SAndroid Build Coastguard Worker         let mut offset = mem::size_of::<PinPageInfo>() as u64;
651*bb4ee6a4SAndroid Build Coastguard Worker         let mut dtt_iter: DTTIter = Default::default();
652*bb4ee6a4SAndroid Build Coastguard Worker         let mut pinstate = self.pinstate.lock();
653*bb4ee6a4SAndroid Build Coastguard Worker         while nr_pages > 0 {
654*bb4ee6a4SAndroid Build Coastguard Worker             let gfn = self
655*bb4ee6a4SAndroid Build Coastguard Worker                 .mem
656*bb4ee6a4SAndroid Build Coastguard Worker                 .read_obj_from_addr::<u64>(GuestAddress(gpa + offset))
657*bb4ee6a4SAndroid Build Coastguard Worker                 .context("failed to get pin page gfn")?;
658*bb4ee6a4SAndroid Build Coastguard Worker 
659*bb4ee6a4SAndroid Build Coastguard Worker             pin_page(
660*bb4ee6a4SAndroid Build Coastguard Worker                 &mut pinstate,
661*bb4ee6a4SAndroid Build Coastguard Worker                 self.params.unpin_policy,
662*bb4ee6a4SAndroid Build Coastguard Worker                 &self.vfio_container,
663*bb4ee6a4SAndroid Build Coastguard Worker                 &self.mem,
664*bb4ee6a4SAndroid Build Coastguard Worker                 self.dtt_level,
665*bb4ee6a4SAndroid Build Coastguard Worker                 self.dtt_root,
666*bb4ee6a4SAndroid Build Coastguard Worker                 &mut dtt_iter,
667*bb4ee6a4SAndroid Build Coastguard Worker                 gfn,
668*bb4ee6a4SAndroid Build Coastguard Worker             )?;
669*bb4ee6a4SAndroid Build Coastguard Worker 
670*bb4ee6a4SAndroid Build Coastguard Worker             offset += mem::size_of::<u64>() as u64;
671*bb4ee6a4SAndroid Build Coastguard Worker             nr_pages -= 1;
672*bb4ee6a4SAndroid Build Coastguard Worker         }
673*bb4ee6a4SAndroid Build Coastguard Worker 
674*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
675*bb4ee6a4SAndroid Build Coastguard Worker     }
676*bb4ee6a4SAndroid Build Coastguard Worker 
pin_pages(&mut self, gfn_bdf: u64) -> Result<()>677*bb4ee6a4SAndroid Build Coastguard Worker     fn pin_pages(&mut self, gfn_bdf: u64) -> Result<()> {
678*bb4ee6a4SAndroid Build Coastguard Worker         if gfn_bdf & PIN_PAGES_IN_BATCH != 0 {
679*bb4ee6a4SAndroid Build Coastguard Worker             let gpa = gfn_bdf & !PIN_PAGES_IN_BATCH;
680*bb4ee6a4SAndroid Build Coastguard Worker             self.pin_pages_in_batch(gpa)
681*bb4ee6a4SAndroid Build Coastguard Worker         } else {
682*bb4ee6a4SAndroid Build Coastguard Worker             let bdf = (gfn_bdf & 0xffff) as u16;
683*bb4ee6a4SAndroid Build Coastguard Worker             let gfn = gfn_bdf >> 16;
684*bb4ee6a4SAndroid Build Coastguard Worker             let mut dtt_iter: DTTIter = Default::default();
685*bb4ee6a4SAndroid Build Coastguard Worker             ensure!(
686*bb4ee6a4SAndroid Build Coastguard Worker                 self.endpoints.iter().any(|&x| x == bdf),
687*bb4ee6a4SAndroid Build Coastguard Worker                 "pin page for unexpected bdf 0x{:x}",
688*bb4ee6a4SAndroid Build Coastguard Worker                 bdf
689*bb4ee6a4SAndroid Build Coastguard Worker             );
690*bb4ee6a4SAndroid Build Coastguard Worker 
691*bb4ee6a4SAndroid Build Coastguard Worker             let mut pinstate = self.pinstate.lock();
692*bb4ee6a4SAndroid Build Coastguard Worker             pin_page(
693*bb4ee6a4SAndroid Build Coastguard Worker                 &mut pinstate,
694*bb4ee6a4SAndroid Build Coastguard Worker                 self.params.unpin_policy,
695*bb4ee6a4SAndroid Build Coastguard Worker                 &self.vfio_container,
696*bb4ee6a4SAndroid Build Coastguard Worker                 &self.mem,
697*bb4ee6a4SAndroid Build Coastguard Worker                 self.dtt_level,
698*bb4ee6a4SAndroid Build Coastguard Worker                 self.dtt_root,
699*bb4ee6a4SAndroid Build Coastguard Worker                 &mut dtt_iter,
700*bb4ee6a4SAndroid Build Coastguard Worker                 gfn,
701*bb4ee6a4SAndroid Build Coastguard Worker             )
702*bb4ee6a4SAndroid Build Coastguard Worker         }
703*bb4ee6a4SAndroid Build Coastguard Worker     }
704*bb4ee6a4SAndroid Build Coastguard Worker }
705*bb4ee6a4SAndroid Build Coastguard Worker 
706*bb4ee6a4SAndroid Build Coastguard Worker struct UnpinWorker {
707*bb4ee6a4SAndroid Build Coastguard Worker     mem: GuestMemory,
708*bb4ee6a4SAndroid Build Coastguard Worker     dtt_level: u64,
709*bb4ee6a4SAndroid Build Coastguard Worker     dtt_root: u64,
710*bb4ee6a4SAndroid Build Coastguard Worker     vfio_container: Arc<Mutex<VfioContainer>>,
711*bb4ee6a4SAndroid Build Coastguard Worker     unpin_tube: Option<Tube>,
712*bb4ee6a4SAndroid Build Coastguard Worker     pinstate: Arc<Mutex<CoIommuPinState>>,
713*bb4ee6a4SAndroid Build Coastguard Worker     params: CoIommuParameters,
714*bb4ee6a4SAndroid Build Coastguard Worker     unpin_gen_threshold: u64,
715*bb4ee6a4SAndroid Build Coastguard Worker }
716*bb4ee6a4SAndroid Build Coastguard Worker 
717*bb4ee6a4SAndroid Build Coastguard Worker impl UnpinWorker {
debug_label(&self) -> &'static str718*bb4ee6a4SAndroid Build Coastguard Worker     fn debug_label(&self) -> &'static str {
719*bb4ee6a4SAndroid Build Coastguard Worker         "CoIommuUnpinWorker"
720*bb4ee6a4SAndroid Build Coastguard Worker     }
721*bb4ee6a4SAndroid Build Coastguard Worker 
run(&mut self, kill_evt: Event)722*bb4ee6a4SAndroid Build Coastguard Worker     fn run(&mut self, kill_evt: Event) {
723*bb4ee6a4SAndroid Build Coastguard Worker         #[derive(EventToken)]
724*bb4ee6a4SAndroid Build Coastguard Worker         enum Token {
725*bb4ee6a4SAndroid Build Coastguard Worker             UnpinTimer,
726*bb4ee6a4SAndroid Build Coastguard Worker             UnpinReq,
727*bb4ee6a4SAndroid Build Coastguard Worker             Kill,
728*bb4ee6a4SAndroid Build Coastguard Worker         }
729*bb4ee6a4SAndroid Build Coastguard Worker 
730*bb4ee6a4SAndroid Build Coastguard Worker         let wait_ctx: WaitContext<Token> =
731*bb4ee6a4SAndroid Build Coastguard Worker             match WaitContext::build_with(&[(&kill_evt, Token::Kill)]) {
732*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(pc) => pc,
733*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
734*bb4ee6a4SAndroid Build Coastguard Worker                     error!("{}: failed creating WaitContext: {}", self.debug_label(), e);
735*bb4ee6a4SAndroid Build Coastguard Worker                     return;
736*bb4ee6a4SAndroid Build Coastguard Worker                 }
737*bb4ee6a4SAndroid Build Coastguard Worker             };
738*bb4ee6a4SAndroid Build Coastguard Worker 
739*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(tube) = &self.unpin_tube {
740*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = wait_ctx.add(tube, Token::UnpinReq) {
741*bb4ee6a4SAndroid Build Coastguard Worker                 error!("{}: failed creating WaitContext: {}", self.debug_label(), e);
742*bb4ee6a4SAndroid Build Coastguard Worker                 return;
743*bb4ee6a4SAndroid Build Coastguard Worker             }
744*bb4ee6a4SAndroid Build Coastguard Worker         }
745*bb4ee6a4SAndroid Build Coastguard Worker 
746*bb4ee6a4SAndroid Build Coastguard Worker         let mut unpin_timer = if self.params.unpin_policy != CoIommuUnpinPolicy::Off
747*bb4ee6a4SAndroid Build Coastguard Worker             && !self.params.unpin_interval.is_zero()
748*bb4ee6a4SAndroid Build Coastguard Worker         {
749*bb4ee6a4SAndroid Build Coastguard Worker             let mut timer = match Timer::new() {
750*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(t) => t,
751*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
752*bb4ee6a4SAndroid Build Coastguard Worker                     error!(
753*bb4ee6a4SAndroid Build Coastguard Worker                         "{}: failed to create the unpin timer: {}",
754*bb4ee6a4SAndroid Build Coastguard Worker                         self.debug_label(),
755*bb4ee6a4SAndroid Build Coastguard Worker                         e
756*bb4ee6a4SAndroid Build Coastguard Worker                     );
757*bb4ee6a4SAndroid Build Coastguard Worker                     return;
758*bb4ee6a4SAndroid Build Coastguard Worker                 }
759*bb4ee6a4SAndroid Build Coastguard Worker             };
760*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = timer.reset_repeating(self.params.unpin_interval) {
761*bb4ee6a4SAndroid Build Coastguard Worker                 error!(
762*bb4ee6a4SAndroid Build Coastguard Worker                     "{}: failed to start the unpin timer: {}",
763*bb4ee6a4SAndroid Build Coastguard Worker                     self.debug_label(),
764*bb4ee6a4SAndroid Build Coastguard Worker                     e
765*bb4ee6a4SAndroid Build Coastguard Worker                 );
766*bb4ee6a4SAndroid Build Coastguard Worker                 return;
767*bb4ee6a4SAndroid Build Coastguard Worker             }
768*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = wait_ctx.add(&timer, Token::UnpinTimer) {
769*bb4ee6a4SAndroid Build Coastguard Worker                 error!("{}: failed creating WaitContext: {}", self.debug_label(), e);
770*bb4ee6a4SAndroid Build Coastguard Worker                 return;
771*bb4ee6a4SAndroid Build Coastguard Worker             }
772*bb4ee6a4SAndroid Build Coastguard Worker             Some(timer)
773*bb4ee6a4SAndroid Build Coastguard Worker         } else {
774*bb4ee6a4SAndroid Build Coastguard Worker             None
775*bb4ee6a4SAndroid Build Coastguard Worker         };
776*bb4ee6a4SAndroid Build Coastguard Worker 
777*bb4ee6a4SAndroid Build Coastguard Worker         let unpin_tube = self.unpin_tube.take();
778*bb4ee6a4SAndroid Build Coastguard Worker         'wait: loop {
779*bb4ee6a4SAndroid Build Coastguard Worker             let events = match wait_ctx.wait() {
780*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(v) => v,
781*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
782*bb4ee6a4SAndroid Build Coastguard Worker                     error!("{}: failed polling for events: {}", self.debug_label(), e);
783*bb4ee6a4SAndroid Build Coastguard Worker                     break;
784*bb4ee6a4SAndroid Build Coastguard Worker                 }
785*bb4ee6a4SAndroid Build Coastguard Worker             };
786*bb4ee6a4SAndroid Build Coastguard Worker 
787*bb4ee6a4SAndroid Build Coastguard Worker             for event in events.iter().filter(|e| e.is_readable) {
788*bb4ee6a4SAndroid Build Coastguard Worker                 match event.token {
789*bb4ee6a4SAndroid Build Coastguard Worker                     Token::UnpinTimer => {
790*bb4ee6a4SAndroid Build Coastguard Worker                         self.unpin_pages();
791*bb4ee6a4SAndroid Build Coastguard Worker                         if let Some(timer) = &mut unpin_timer {
792*bb4ee6a4SAndroid Build Coastguard Worker                             if let Err(e) = timer.mark_waited() {
793*bb4ee6a4SAndroid Build Coastguard Worker                                 error!(
794*bb4ee6a4SAndroid Build Coastguard Worker                                     "{}: failed to clear unpin timer: {}",
795*bb4ee6a4SAndroid Build Coastguard Worker                                     self.debug_label(),
796*bb4ee6a4SAndroid Build Coastguard Worker                                     e
797*bb4ee6a4SAndroid Build Coastguard Worker                                 );
798*bb4ee6a4SAndroid Build Coastguard Worker                                 break 'wait;
799*bb4ee6a4SAndroid Build Coastguard Worker                             }
800*bb4ee6a4SAndroid Build Coastguard Worker                         }
801*bb4ee6a4SAndroid Build Coastguard Worker                     }
802*bb4ee6a4SAndroid Build Coastguard Worker                     Token::UnpinReq => {
803*bb4ee6a4SAndroid Build Coastguard Worker                         if let Some(tube) = &unpin_tube {
804*bb4ee6a4SAndroid Build Coastguard Worker                             match tube.recv::<UnpinRequest>() {
805*bb4ee6a4SAndroid Build Coastguard Worker                                 Ok(req) => {
806*bb4ee6a4SAndroid Build Coastguard Worker                                     let mut unpin_done = true;
807*bb4ee6a4SAndroid Build Coastguard Worker                                     for range in req.ranges {
808*bb4ee6a4SAndroid Build Coastguard Worker                                         // Locking with respect to pin_pages isn't necessary
809*bb4ee6a4SAndroid Build Coastguard Worker                                         // for this case because the unpinned pages in the range
810*bb4ee6a4SAndroid Build Coastguard Worker                                         // should all be in the balloon and so nothing will attempt
811*bb4ee6a4SAndroid Build Coastguard Worker                                         // to pin them.
812*bb4ee6a4SAndroid Build Coastguard Worker                                         if !self.unpin_pages_in_range(range.0, range.1) {
813*bb4ee6a4SAndroid Build Coastguard Worker                                             unpin_done = false;
814*bb4ee6a4SAndroid Build Coastguard Worker                                             break;
815*bb4ee6a4SAndroid Build Coastguard Worker                                         }
816*bb4ee6a4SAndroid Build Coastguard Worker                                     }
817*bb4ee6a4SAndroid Build Coastguard Worker                                     let resp = if unpin_done {
818*bb4ee6a4SAndroid Build Coastguard Worker                                         UnpinResponse::Success
819*bb4ee6a4SAndroid Build Coastguard Worker                                     } else {
820*bb4ee6a4SAndroid Build Coastguard Worker                                         UnpinResponse::Failed
821*bb4ee6a4SAndroid Build Coastguard Worker                                     };
822*bb4ee6a4SAndroid Build Coastguard Worker                                     if let Err(e) = tube.send(&resp) {
823*bb4ee6a4SAndroid Build Coastguard Worker                                         error!(
824*bb4ee6a4SAndroid Build Coastguard Worker                                             "{}: failed to send unpin response {}",
825*bb4ee6a4SAndroid Build Coastguard Worker                                             self.debug_label(),
826*bb4ee6a4SAndroid Build Coastguard Worker                                             e
827*bb4ee6a4SAndroid Build Coastguard Worker                                         );
828*bb4ee6a4SAndroid Build Coastguard Worker                                     }
829*bb4ee6a4SAndroid Build Coastguard Worker                                 }
830*bb4ee6a4SAndroid Build Coastguard Worker                                 Err(e) => {
831*bb4ee6a4SAndroid Build Coastguard Worker                                     if let TubeError::Disconnected = e {
832*bb4ee6a4SAndroid Build Coastguard Worker                                         if let Err(e) = wait_ctx.delete(tube) {
833*bb4ee6a4SAndroid Build Coastguard Worker                                             error!(
834*bb4ee6a4SAndroid Build Coastguard Worker                                                 "{}: failed to remove unpin_tube: {}",
835*bb4ee6a4SAndroid Build Coastguard Worker                                                 self.debug_label(),
836*bb4ee6a4SAndroid Build Coastguard Worker                                                 e
837*bb4ee6a4SAndroid Build Coastguard Worker                                             );
838*bb4ee6a4SAndroid Build Coastguard Worker                                         }
839*bb4ee6a4SAndroid Build Coastguard Worker                                     } else {
840*bb4ee6a4SAndroid Build Coastguard Worker                                         error!(
841*bb4ee6a4SAndroid Build Coastguard Worker                                             "{}: failed to recv Unpin Request: {}",
842*bb4ee6a4SAndroid Build Coastguard Worker                                             self.debug_label(),
843*bb4ee6a4SAndroid Build Coastguard Worker                                             e
844*bb4ee6a4SAndroid Build Coastguard Worker                                         );
845*bb4ee6a4SAndroid Build Coastguard Worker                                     }
846*bb4ee6a4SAndroid Build Coastguard Worker                                 }
847*bb4ee6a4SAndroid Build Coastguard Worker                             }
848*bb4ee6a4SAndroid Build Coastguard Worker                         }
849*bb4ee6a4SAndroid Build Coastguard Worker                     }
850*bb4ee6a4SAndroid Build Coastguard Worker                     Token::Kill => break 'wait,
851*bb4ee6a4SAndroid Build Coastguard Worker                 }
852*bb4ee6a4SAndroid Build Coastguard Worker             }
853*bb4ee6a4SAndroid Build Coastguard Worker         }
854*bb4ee6a4SAndroid Build Coastguard Worker         self.unpin_tube = unpin_tube;
855*bb4ee6a4SAndroid Build Coastguard Worker     }
856*bb4ee6a4SAndroid Build Coastguard Worker 
unpin_pages(&mut self)857*bb4ee6a4SAndroid Build Coastguard Worker     fn unpin_pages(&mut self) {
858*bb4ee6a4SAndroid Build Coastguard Worker         if self.params.unpin_policy == CoIommuUnpinPolicy::Lru {
859*bb4ee6a4SAndroid Build Coastguard Worker             self.lru_unpin_pages();
860*bb4ee6a4SAndroid Build Coastguard Worker         }
861*bb4ee6a4SAndroid Build Coastguard Worker     }
862*bb4ee6a4SAndroid Build Coastguard Worker 
lru_unpin_page( &mut self, dtt_iter: &mut DTTIter, new_gen: bool, ) -> (UnpinResult, Option<PinnedPageInfo>)863*bb4ee6a4SAndroid Build Coastguard Worker     fn lru_unpin_page(
864*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
865*bb4ee6a4SAndroid Build Coastguard Worker         dtt_iter: &mut DTTIter,
866*bb4ee6a4SAndroid Build Coastguard Worker         new_gen: bool,
867*bb4ee6a4SAndroid Build Coastguard Worker     ) -> (UnpinResult, Option<PinnedPageInfo>) {
868*bb4ee6a4SAndroid Build Coastguard Worker         let mut pinstate = self.pinstate.lock();
869*bb4ee6a4SAndroid Build Coastguard Worker         let pageinfo = if new_gen {
870*bb4ee6a4SAndroid Build Coastguard Worker             pinstate.new_gen_pinned_pages.pop_front()
871*bb4ee6a4SAndroid Build Coastguard Worker         } else {
872*bb4ee6a4SAndroid Build Coastguard Worker             pinstate
873*bb4ee6a4SAndroid Build Coastguard Worker                 .old_gen_pinned_pages
874*bb4ee6a4SAndroid Build Coastguard Worker                 .pop_front()
875*bb4ee6a4SAndroid Build Coastguard Worker                 .map(|gfn| PinnedPageInfo::new(gfn, 0))
876*bb4ee6a4SAndroid Build Coastguard Worker         };
877*bb4ee6a4SAndroid Build Coastguard Worker 
878*bb4ee6a4SAndroid Build Coastguard Worker         pageinfo.map_or((UnpinResult::UnpinlistEmpty, None), |pageinfo| {
879*bb4ee6a4SAndroid Build Coastguard Worker             (
880*bb4ee6a4SAndroid Build Coastguard Worker                 unpin_page(
881*bb4ee6a4SAndroid Build Coastguard Worker                     &mut pinstate,
882*bb4ee6a4SAndroid Build Coastguard Worker                     &self.vfio_container,
883*bb4ee6a4SAndroid Build Coastguard Worker                     &self.mem,
884*bb4ee6a4SAndroid Build Coastguard Worker                     self.dtt_level,
885*bb4ee6a4SAndroid Build Coastguard Worker                     self.dtt_root,
886*bb4ee6a4SAndroid Build Coastguard Worker                     dtt_iter,
887*bb4ee6a4SAndroid Build Coastguard Worker                     pageinfo.gfn,
888*bb4ee6a4SAndroid Build Coastguard Worker                     false,
889*bb4ee6a4SAndroid Build Coastguard Worker                 ),
890*bb4ee6a4SAndroid Build Coastguard Worker                 Some(pageinfo),
891*bb4ee6a4SAndroid Build Coastguard Worker             )
892*bb4ee6a4SAndroid Build Coastguard Worker         })
893*bb4ee6a4SAndroid Build Coastguard Worker     }
894*bb4ee6a4SAndroid Build Coastguard Worker 
lru_unpin_pages_in_loop(&mut self, unpin_limit: Option<u64>, new_gen: bool) -> u64895*bb4ee6a4SAndroid Build Coastguard Worker     fn lru_unpin_pages_in_loop(&mut self, unpin_limit: Option<u64>, new_gen: bool) -> u64 {
896*bb4ee6a4SAndroid Build Coastguard Worker         let mut not_unpinned_new_gen_pages = VecDeque::new();
897*bb4ee6a4SAndroid Build Coastguard Worker         let mut not_unpinned_old_gen_pages = VecDeque::new();
898*bb4ee6a4SAndroid Build Coastguard Worker         let mut unpinned_count = 0;
899*bb4ee6a4SAndroid Build Coastguard Worker         let has_limit = unpin_limit.is_some();
900*bb4ee6a4SAndroid Build Coastguard Worker         let limit_count = unpin_limit.unwrap_or(0);
901*bb4ee6a4SAndroid Build Coastguard Worker         let mut dtt_iter: DTTIter = Default::default();
902*bb4ee6a4SAndroid Build Coastguard Worker 
903*bb4ee6a4SAndroid Build Coastguard Worker         // If has_limit is true but limit_count is 0, will not do the unpin
904*bb4ee6a4SAndroid Build Coastguard Worker         while !has_limit || unpinned_count != limit_count {
905*bb4ee6a4SAndroid Build Coastguard Worker             let (result, pinned_page) = self.lru_unpin_page(&mut dtt_iter, new_gen);
906*bb4ee6a4SAndroid Build Coastguard Worker             match result {
907*bb4ee6a4SAndroid Build Coastguard Worker                 UnpinResult::UnpinlistEmpty => break,
908*bb4ee6a4SAndroid Build Coastguard Worker                 UnpinResult::Unpinned => unpinned_count += 1,
909*bb4ee6a4SAndroid Build Coastguard Worker                 UnpinResult::NotPinned => {}
910*bb4ee6a4SAndroid Build Coastguard Worker                 UnpinResult::NotUnpinned => {
911*bb4ee6a4SAndroid Build Coastguard Worker                     if let Some(mut page) = pinned_page {
912*bb4ee6a4SAndroid Build Coastguard Worker                         if self.params.unpin_gen_threshold != 0 {
913*bb4ee6a4SAndroid Build Coastguard Worker                             page.unpin_busy_cnt += 1;
914*bb4ee6a4SAndroid Build Coastguard Worker                             // Unpin from new_gen queue but not
915*bb4ee6a4SAndroid Build Coastguard Worker                             // successfully unpinned. Need to check
916*bb4ee6a4SAndroid Build Coastguard Worker                             // the unpin_gen threshold. If reach, put
917*bb4ee6a4SAndroid Build Coastguard Worker                             // it to old_gen queue.
918*bb4ee6a4SAndroid Build Coastguard Worker                             // And if it is not from new_gen, directly
919*bb4ee6a4SAndroid Build Coastguard Worker                             // put into old_gen queue.
920*bb4ee6a4SAndroid Build Coastguard Worker                             if !new_gen || page.unpin_busy_cnt >= self.params.unpin_gen_threshold {
921*bb4ee6a4SAndroid Build Coastguard Worker                                 not_unpinned_old_gen_pages.push_back(page.gfn);
922*bb4ee6a4SAndroid Build Coastguard Worker                             } else {
923*bb4ee6a4SAndroid Build Coastguard Worker                                 not_unpinned_new_gen_pages.push_back(page);
924*bb4ee6a4SAndroid Build Coastguard Worker                             }
925*bb4ee6a4SAndroid Build Coastguard Worker                         }
926*bb4ee6a4SAndroid Build Coastguard Worker                     }
927*bb4ee6a4SAndroid Build Coastguard Worker                 }
928*bb4ee6a4SAndroid Build Coastguard Worker                 UnpinResult::FailedUnpin | UnpinResult::UnpinParked => {
929*bb4ee6a4SAndroid Build Coastguard Worker                     // Although UnpinParked means we didn't actually try to unpin
930*bb4ee6a4SAndroid Build Coastguard Worker                     // gfn, it's not worth specifically handing since parking is
931*bb4ee6a4SAndroid Build Coastguard Worker                     // expected to be relatively rare.
932*bb4ee6a4SAndroid Build Coastguard Worker                     if let Some(page) = pinned_page {
933*bb4ee6a4SAndroid Build Coastguard Worker                         if new_gen {
934*bb4ee6a4SAndroid Build Coastguard Worker                             not_unpinned_new_gen_pages.push_back(page);
935*bb4ee6a4SAndroid Build Coastguard Worker                         } else {
936*bb4ee6a4SAndroid Build Coastguard Worker                             not_unpinned_old_gen_pages.push_back(page.gfn);
937*bb4ee6a4SAndroid Build Coastguard Worker                         }
938*bb4ee6a4SAndroid Build Coastguard Worker                     }
939*bb4ee6a4SAndroid Build Coastguard Worker                     if result == UnpinResult::UnpinParked {
940*bb4ee6a4SAndroid Build Coastguard Worker                         thread::park();
941*bb4ee6a4SAndroid Build Coastguard Worker                     }
942*bb4ee6a4SAndroid Build Coastguard Worker                 }
943*bb4ee6a4SAndroid Build Coastguard Worker             }
944*bb4ee6a4SAndroid Build Coastguard Worker         }
945*bb4ee6a4SAndroid Build Coastguard Worker 
946*bb4ee6a4SAndroid Build Coastguard Worker         if !not_unpinned_new_gen_pages.is_empty() {
947*bb4ee6a4SAndroid Build Coastguard Worker             let mut pinstate = self.pinstate.lock();
948*bb4ee6a4SAndroid Build Coastguard Worker             pinstate
949*bb4ee6a4SAndroid Build Coastguard Worker                 .new_gen_pinned_pages
950*bb4ee6a4SAndroid Build Coastguard Worker                 .append(&mut not_unpinned_new_gen_pages);
951*bb4ee6a4SAndroid Build Coastguard Worker         }
952*bb4ee6a4SAndroid Build Coastguard Worker 
953*bb4ee6a4SAndroid Build Coastguard Worker         if !not_unpinned_old_gen_pages.is_empty() {
954*bb4ee6a4SAndroid Build Coastguard Worker             let mut pinstate = self.pinstate.lock();
955*bb4ee6a4SAndroid Build Coastguard Worker             pinstate
956*bb4ee6a4SAndroid Build Coastguard Worker                 .old_gen_pinned_pages
957*bb4ee6a4SAndroid Build Coastguard Worker                 .append(&mut not_unpinned_old_gen_pages);
958*bb4ee6a4SAndroid Build Coastguard Worker         }
959*bb4ee6a4SAndroid Build Coastguard Worker 
960*bb4ee6a4SAndroid Build Coastguard Worker         unpinned_count
961*bb4ee6a4SAndroid Build Coastguard Worker     }
962*bb4ee6a4SAndroid Build Coastguard Worker 
lru_unpin_pages(&mut self)963*bb4ee6a4SAndroid Build Coastguard Worker     fn lru_unpin_pages(&mut self) {
964*bb4ee6a4SAndroid Build Coastguard Worker         let mut unpin_count = 0;
965*bb4ee6a4SAndroid Build Coastguard Worker         if self.params.unpin_gen_threshold != 0 {
966*bb4ee6a4SAndroid Build Coastguard Worker             self.unpin_gen_threshold += 1;
967*bb4ee6a4SAndroid Build Coastguard Worker             if self.unpin_gen_threshold == self.params.unpin_gen_threshold {
968*bb4ee6a4SAndroid Build Coastguard Worker                 self.unpin_gen_threshold = 0;
969*bb4ee6a4SAndroid Build Coastguard Worker                 // Try to unpin inactive queue first if reaches the thres hold
970*bb4ee6a4SAndroid Build Coastguard Worker                 unpin_count = self.lru_unpin_pages_in_loop(self.params.unpin_limit, false);
971*bb4ee6a4SAndroid Build Coastguard Worker             }
972*bb4ee6a4SAndroid Build Coastguard Worker         }
973*bb4ee6a4SAndroid Build Coastguard Worker         // Unpin the new_gen queue with the updated unpin_limit after unpin old_gen queue
974*bb4ee6a4SAndroid Build Coastguard Worker         self.lru_unpin_pages_in_loop(
975*bb4ee6a4SAndroid Build Coastguard Worker             self.params
976*bb4ee6a4SAndroid Build Coastguard Worker                 .unpin_limit
977*bb4ee6a4SAndroid Build Coastguard Worker                 .map(|limit| limit.saturating_sub(unpin_count)),
978*bb4ee6a4SAndroid Build Coastguard Worker             true,
979*bb4ee6a4SAndroid Build Coastguard Worker         );
980*bb4ee6a4SAndroid Build Coastguard Worker     }
981*bb4ee6a4SAndroid Build Coastguard Worker 
unpin_pages_in_range(&self, gfn: u64, count: u64) -> bool982*bb4ee6a4SAndroid Build Coastguard Worker     fn unpin_pages_in_range(&self, gfn: u64, count: u64) -> bool {
983*bb4ee6a4SAndroid Build Coastguard Worker         let mut dtt_iter: DTTIter = Default::default();
984*bb4ee6a4SAndroid Build Coastguard Worker         let mut index = 0;
985*bb4ee6a4SAndroid Build Coastguard Worker         while index != count {
986*bb4ee6a4SAndroid Build Coastguard Worker             let mut pinstate = self.pinstate.lock();
987*bb4ee6a4SAndroid Build Coastguard Worker             let result = unpin_page(
988*bb4ee6a4SAndroid Build Coastguard Worker                 &mut pinstate,
989*bb4ee6a4SAndroid Build Coastguard Worker                 &self.vfio_container,
990*bb4ee6a4SAndroid Build Coastguard Worker                 &self.mem,
991*bb4ee6a4SAndroid Build Coastguard Worker                 self.dtt_level,
992*bb4ee6a4SAndroid Build Coastguard Worker                 self.dtt_root,
993*bb4ee6a4SAndroid Build Coastguard Worker                 &mut dtt_iter,
994*bb4ee6a4SAndroid Build Coastguard Worker                 gfn + index,
995*bb4ee6a4SAndroid Build Coastguard Worker                 true,
996*bb4ee6a4SAndroid Build Coastguard Worker             );
997*bb4ee6a4SAndroid Build Coastguard Worker             drop(pinstate);
998*bb4ee6a4SAndroid Build Coastguard Worker 
999*bb4ee6a4SAndroid Build Coastguard Worker             match result {
1000*bb4ee6a4SAndroid Build Coastguard Worker                 UnpinResult::Unpinned | UnpinResult::NotPinned => {}
1001*bb4ee6a4SAndroid Build Coastguard Worker                 UnpinResult::UnpinParked => {
1002*bb4ee6a4SAndroid Build Coastguard Worker                     thread::park();
1003*bb4ee6a4SAndroid Build Coastguard Worker                     continue;
1004*bb4ee6a4SAndroid Build Coastguard Worker                 }
1005*bb4ee6a4SAndroid Build Coastguard Worker                 _ => {
1006*bb4ee6a4SAndroid Build Coastguard Worker                     error!("coiommu: force unpin failed by {:?}", result);
1007*bb4ee6a4SAndroid Build Coastguard Worker                     return false;
1008*bb4ee6a4SAndroid Build Coastguard Worker                 }
1009*bb4ee6a4SAndroid Build Coastguard Worker             }
1010*bb4ee6a4SAndroid Build Coastguard Worker             index += 1;
1011*bb4ee6a4SAndroid Build Coastguard Worker         }
1012*bb4ee6a4SAndroid Build Coastguard Worker         true
1013*bb4ee6a4SAndroid Build Coastguard Worker     }
1014*bb4ee6a4SAndroid Build Coastguard Worker }
1015*bb4ee6a4SAndroid Build Coastguard Worker 
1016*bb4ee6a4SAndroid Build Coastguard Worker pub struct CoIommuDev {
1017*bb4ee6a4SAndroid Build Coastguard Worker     config_regs: PciConfiguration,
1018*bb4ee6a4SAndroid Build Coastguard Worker     pci_address: Option<PciAddress>,
1019*bb4ee6a4SAndroid Build Coastguard Worker     mem: GuestMemory,
1020*bb4ee6a4SAndroid Build Coastguard Worker     coiommu_reg: CoIommuReg,
1021*bb4ee6a4SAndroid Build Coastguard Worker     endpoints: Vec<u16>,
1022*bb4ee6a4SAndroid Build Coastguard Worker     notifymap_mem: SafeDescriptor,
1023*bb4ee6a4SAndroid Build Coastguard Worker     notifymap_mmap: Arc<MemoryMapping>,
1024*bb4ee6a4SAndroid Build Coastguard Worker     notifymap_addr: Option<u64>,
1025*bb4ee6a4SAndroid Build Coastguard Worker     topologymap_mem: SafeDescriptor,
1026*bb4ee6a4SAndroid Build Coastguard Worker     topologymap_addr: Option<u64>,
1027*bb4ee6a4SAndroid Build Coastguard Worker     mmapped: bool,
1028*bb4ee6a4SAndroid Build Coastguard Worker     vm_memory_client: VmMemoryClient,
1029*bb4ee6a4SAndroid Build Coastguard Worker     pin_thread: Option<WorkerThread<PinWorker>>,
1030*bb4ee6a4SAndroid Build Coastguard Worker     unpin_thread: Option<WorkerThread<UnpinWorker>>,
1031*bb4ee6a4SAndroid Build Coastguard Worker     unpin_tube: Option<Tube>,
1032*bb4ee6a4SAndroid Build Coastguard Worker     ioevents: Vec<Event>,
1033*bb4ee6a4SAndroid Build Coastguard Worker     vfio_container: Arc<Mutex<VfioContainer>>,
1034*bb4ee6a4SAndroid Build Coastguard Worker     pinstate: Arc<Mutex<CoIommuPinState>>,
1035*bb4ee6a4SAndroid Build Coastguard Worker     params: CoIommuParameters,
1036*bb4ee6a4SAndroid Build Coastguard Worker }
1037*bb4ee6a4SAndroid Build Coastguard Worker 
1038*bb4ee6a4SAndroid Build Coastguard Worker impl CoIommuDev {
new( mem: GuestMemory, vfio_container: Arc<Mutex<VfioContainer>>, vm_memory_client: VmMemoryClient, unpin_tube: Option<Tube>, endpoints: Vec<u16>, vcpu_count: u64, params: CoIommuParameters, ) -> Result<Self>1039*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
1040*bb4ee6a4SAndroid Build Coastguard Worker         mem: GuestMemory,
1041*bb4ee6a4SAndroid Build Coastguard Worker         vfio_container: Arc<Mutex<VfioContainer>>,
1042*bb4ee6a4SAndroid Build Coastguard Worker         vm_memory_client: VmMemoryClient,
1043*bb4ee6a4SAndroid Build Coastguard Worker         unpin_tube: Option<Tube>,
1044*bb4ee6a4SAndroid Build Coastguard Worker         endpoints: Vec<u16>,
1045*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_count: u64,
1046*bb4ee6a4SAndroid Build Coastguard Worker         params: CoIommuParameters,
1047*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Self> {
1048*bb4ee6a4SAndroid Build Coastguard Worker         let config_regs = PciConfiguration::new(
1049*bb4ee6a4SAndroid Build Coastguard Worker             PCI_VENDOR_ID_COIOMMU,
1050*bb4ee6a4SAndroid Build Coastguard Worker             PCI_DEVICE_ID_COIOMMU,
1051*bb4ee6a4SAndroid Build Coastguard Worker             PciClassCode::Other,
1052*bb4ee6a4SAndroid Build Coastguard Worker             &PciOtherSubclass::Other,
1053*bb4ee6a4SAndroid Build Coastguard Worker             None, // No Programming interface.
1054*bb4ee6a4SAndroid Build Coastguard Worker             PciHeaderType::Device,
1055*bb4ee6a4SAndroid Build Coastguard Worker             PCI_VENDOR_ID_COIOMMU,
1056*bb4ee6a4SAndroid Build Coastguard Worker             PCI_DEVICE_ID_COIOMMU,
1057*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_REVISION_ID,
1058*bb4ee6a4SAndroid Build Coastguard Worker         );
1059*bb4ee6a4SAndroid Build Coastguard Worker 
1060*bb4ee6a4SAndroid Build Coastguard Worker         // notifymap_mem is used as Bar2 for Guest to check if request is completed by coIOMMU.
1061*bb4ee6a4SAndroid Build Coastguard Worker         let notifymap_mem = SharedMemory::new("coiommu_notifymap", COIOMMU_NOTIFYMAP_SIZE as u64)
1062*bb4ee6a4SAndroid Build Coastguard Worker             .context(Error::CreateSharedMemory)?;
1063*bb4ee6a4SAndroid Build Coastguard Worker         let notifymap_mmap = Arc::new(
1064*bb4ee6a4SAndroid Build Coastguard Worker             MemoryMappingBuilder::new(COIOMMU_NOTIFYMAP_SIZE)
1065*bb4ee6a4SAndroid Build Coastguard Worker                 .from_shared_memory(&notifymap_mem)
1066*bb4ee6a4SAndroid Build Coastguard Worker                 .offset(0)
1067*bb4ee6a4SAndroid Build Coastguard Worker                 .build()?,
1068*bb4ee6a4SAndroid Build Coastguard Worker         );
1069*bb4ee6a4SAndroid Build Coastguard Worker 
1070*bb4ee6a4SAndroid Build Coastguard Worker         // topologymap_mem is used as Bar4 for Guest to check which device is on top of coIOMMU.
1071*bb4ee6a4SAndroid Build Coastguard Worker         let topologymap_mem =
1072*bb4ee6a4SAndroid Build Coastguard Worker             SharedMemory::new("coiommu_topologymap", COIOMMU_TOPOLOGYMAP_SIZE as u64)
1073*bb4ee6a4SAndroid Build Coastguard Worker                 .context(Error::CreateSharedMemory)?;
1074*bb4ee6a4SAndroid Build Coastguard Worker         let topologymap_mmap = Arc::new(
1075*bb4ee6a4SAndroid Build Coastguard Worker             MemoryMappingBuilder::new(COIOMMU_TOPOLOGYMAP_SIZE)
1076*bb4ee6a4SAndroid Build Coastguard Worker                 .from_shared_memory(&topologymap_mem)
1077*bb4ee6a4SAndroid Build Coastguard Worker                 .offset(0)
1078*bb4ee6a4SAndroid Build Coastguard Worker                 .build()?,
1079*bb4ee6a4SAndroid Build Coastguard Worker         );
1080*bb4ee6a4SAndroid Build Coastguard Worker 
1081*bb4ee6a4SAndroid Build Coastguard Worker         ensure!(
1082*bb4ee6a4SAndroid Build Coastguard Worker             (endpoints.len() + 1) * mem::size_of::<u16>() <= COIOMMU_TOPOLOGYMAP_SIZE,
1083*bb4ee6a4SAndroid Build Coastguard Worker             "Coiommu: too many endpoints"
1084*bb4ee6a4SAndroid Build Coastguard Worker         );
1085*bb4ee6a4SAndroid Build Coastguard Worker         topologymap_mmap.write_obj::<u16>(endpoints.len() as u16, 0)?;
1086*bb4ee6a4SAndroid Build Coastguard Worker         for (index, endpoint) in endpoints.iter().enumerate() {
1087*bb4ee6a4SAndroid Build Coastguard Worker             topologymap_mmap.write_obj::<u16>(*endpoint, (index + 1) * mem::size_of::<u16>())?;
1088*bb4ee6a4SAndroid Build Coastguard Worker         }
1089*bb4ee6a4SAndroid Build Coastguard Worker 
1090*bb4ee6a4SAndroid Build Coastguard Worker         let mut ioevents = Vec::new();
1091*bb4ee6a4SAndroid Build Coastguard Worker         for _ in 0..vcpu_count {
1092*bb4ee6a4SAndroid Build Coastguard Worker             ioevents.push(Event::new().context("CoIommu failed to create event fd")?);
1093*bb4ee6a4SAndroid Build Coastguard Worker         }
1094*bb4ee6a4SAndroid Build Coastguard Worker 
1095*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Self {
1096*bb4ee6a4SAndroid Build Coastguard Worker             config_regs,
1097*bb4ee6a4SAndroid Build Coastguard Worker             pci_address: None,
1098*bb4ee6a4SAndroid Build Coastguard Worker             mem,
1099*bb4ee6a4SAndroid Build Coastguard Worker             coiommu_reg: Default::default(),
1100*bb4ee6a4SAndroid Build Coastguard Worker             endpoints,
1101*bb4ee6a4SAndroid Build Coastguard Worker             notifymap_mem: notifymap_mem.into(),
1102*bb4ee6a4SAndroid Build Coastguard Worker             notifymap_mmap,
1103*bb4ee6a4SAndroid Build Coastguard Worker             notifymap_addr: None,
1104*bb4ee6a4SAndroid Build Coastguard Worker             topologymap_mem: topologymap_mem.into(),
1105*bb4ee6a4SAndroid Build Coastguard Worker             topologymap_addr: None,
1106*bb4ee6a4SAndroid Build Coastguard Worker             mmapped: false,
1107*bb4ee6a4SAndroid Build Coastguard Worker             vm_memory_client,
1108*bb4ee6a4SAndroid Build Coastguard Worker             pin_thread: None,
1109*bb4ee6a4SAndroid Build Coastguard Worker             unpin_thread: None,
1110*bb4ee6a4SAndroid Build Coastguard Worker             unpin_tube,
1111*bb4ee6a4SAndroid Build Coastguard Worker             ioevents,
1112*bb4ee6a4SAndroid Build Coastguard Worker             vfio_container,
1113*bb4ee6a4SAndroid Build Coastguard Worker             pinstate: Arc::new(Mutex::new(CoIommuPinState {
1114*bb4ee6a4SAndroid Build Coastguard Worker                 new_gen_pinned_pages: VecDeque::new(),
1115*bb4ee6a4SAndroid Build Coastguard Worker                 old_gen_pinned_pages: VecDeque::new(),
1116*bb4ee6a4SAndroid Build Coastguard Worker                 unpin_thread_state: UnpinThreadState::Unparked,
1117*bb4ee6a4SAndroid Build Coastguard Worker                 unpin_park_count: 0,
1118*bb4ee6a4SAndroid Build Coastguard Worker             })),
1119*bb4ee6a4SAndroid Build Coastguard Worker             params,
1120*bb4ee6a4SAndroid Build Coastguard Worker         })
1121*bb4ee6a4SAndroid Build Coastguard Worker     }
1122*bb4ee6a4SAndroid Build Coastguard Worker 
register_mmap( &self, descriptor: SafeDescriptor, size: usize, offset: u64, gpa: u64, prot: Protection, ) -> Result<()>1123*bb4ee6a4SAndroid Build Coastguard Worker     fn register_mmap(
1124*bb4ee6a4SAndroid Build Coastguard Worker         &self,
1125*bb4ee6a4SAndroid Build Coastguard Worker         descriptor: SafeDescriptor,
1126*bb4ee6a4SAndroid Build Coastguard Worker         size: usize,
1127*bb4ee6a4SAndroid Build Coastguard Worker         offset: u64,
1128*bb4ee6a4SAndroid Build Coastguard Worker         gpa: u64,
1129*bb4ee6a4SAndroid Build Coastguard Worker         prot: Protection,
1130*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
1131*bb4ee6a4SAndroid Build Coastguard Worker         let _region = self
1132*bb4ee6a4SAndroid Build Coastguard Worker             .vm_memory_client
1133*bb4ee6a4SAndroid Build Coastguard Worker             .register_memory(
1134*bb4ee6a4SAndroid Build Coastguard Worker                 VmMemorySource::Descriptor {
1135*bb4ee6a4SAndroid Build Coastguard Worker                     descriptor,
1136*bb4ee6a4SAndroid Build Coastguard Worker                     offset,
1137*bb4ee6a4SAndroid Build Coastguard Worker                     size: size as u64,
1138*bb4ee6a4SAndroid Build Coastguard Worker                 },
1139*bb4ee6a4SAndroid Build Coastguard Worker                 VmMemoryDestination::GuestPhysicalAddress(gpa),
1140*bb4ee6a4SAndroid Build Coastguard Worker                 prot,
1141*bb4ee6a4SAndroid Build Coastguard Worker                 MemCacheType::CacheCoherent,
1142*bb4ee6a4SAndroid Build Coastguard Worker             )
1143*bb4ee6a4SAndroid Build Coastguard Worker             .context("register_mmap register_memory failed")?;
1144*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
1145*bb4ee6a4SAndroid Build Coastguard Worker     }
1146*bb4ee6a4SAndroid Build Coastguard Worker 
mmap(&mut self)1147*bb4ee6a4SAndroid Build Coastguard Worker     fn mmap(&mut self) {
1148*bb4ee6a4SAndroid Build Coastguard Worker         if self.mmapped {
1149*bb4ee6a4SAndroid Build Coastguard Worker             return;
1150*bb4ee6a4SAndroid Build Coastguard Worker         }
1151*bb4ee6a4SAndroid Build Coastguard Worker 
1152*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(gpa) = self.notifymap_addr {
1153*bb4ee6a4SAndroid Build Coastguard Worker             match self.register_mmap(
1154*bb4ee6a4SAndroid Build Coastguard Worker                 self.notifymap_mem.try_clone().unwrap(),
1155*bb4ee6a4SAndroid Build Coastguard Worker                 COIOMMU_NOTIFYMAP_SIZE,
1156*bb4ee6a4SAndroid Build Coastguard Worker                 0,
1157*bb4ee6a4SAndroid Build Coastguard Worker                 gpa,
1158*bb4ee6a4SAndroid Build Coastguard Worker                 Protection::read_write(),
1159*bb4ee6a4SAndroid Build Coastguard Worker             ) {
1160*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(_) => {}
1161*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
1162*bb4ee6a4SAndroid Build Coastguard Worker                     panic!("{}: map notifymap failed: {}", self.debug_label(), e);
1163*bb4ee6a4SAndroid Build Coastguard Worker                 }
1164*bb4ee6a4SAndroid Build Coastguard Worker             }
1165*bb4ee6a4SAndroid Build Coastguard Worker         }
1166*bb4ee6a4SAndroid Build Coastguard Worker 
1167*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(gpa) = self.topologymap_addr {
1168*bb4ee6a4SAndroid Build Coastguard Worker             match self.register_mmap(
1169*bb4ee6a4SAndroid Build Coastguard Worker                 self.topologymap_mem.try_clone().unwrap(),
1170*bb4ee6a4SAndroid Build Coastguard Worker                 COIOMMU_TOPOLOGYMAP_SIZE,
1171*bb4ee6a4SAndroid Build Coastguard Worker                 0,
1172*bb4ee6a4SAndroid Build Coastguard Worker                 gpa,
1173*bb4ee6a4SAndroid Build Coastguard Worker                 Protection::read(),
1174*bb4ee6a4SAndroid Build Coastguard Worker             ) {
1175*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(_) => {}
1176*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
1177*bb4ee6a4SAndroid Build Coastguard Worker                     panic!("{}: map topologymap failed: {}", self.debug_label(), e);
1178*bb4ee6a4SAndroid Build Coastguard Worker                 }
1179*bb4ee6a4SAndroid Build Coastguard Worker             }
1180*bb4ee6a4SAndroid Build Coastguard Worker         }
1181*bb4ee6a4SAndroid Build Coastguard Worker 
1182*bb4ee6a4SAndroid Build Coastguard Worker         self.mmapped = true;
1183*bb4ee6a4SAndroid Build Coastguard Worker     }
1184*bb4ee6a4SAndroid Build Coastguard Worker 
start_workers(&mut self)1185*bb4ee6a4SAndroid Build Coastguard Worker     fn start_workers(&mut self) {
1186*bb4ee6a4SAndroid Build Coastguard Worker         if self.pin_thread.is_none() {
1187*bb4ee6a4SAndroid Build Coastguard Worker             self.start_pin_thread();
1188*bb4ee6a4SAndroid Build Coastguard Worker         }
1189*bb4ee6a4SAndroid Build Coastguard Worker 
1190*bb4ee6a4SAndroid Build Coastguard Worker         if self.unpin_thread.is_none() {
1191*bb4ee6a4SAndroid Build Coastguard Worker             self.start_unpin_thread();
1192*bb4ee6a4SAndroid Build Coastguard Worker         }
1193*bb4ee6a4SAndroid Build Coastguard Worker     }
1194*bb4ee6a4SAndroid Build Coastguard Worker 
start_pin_thread(&mut self)1195*bb4ee6a4SAndroid Build Coastguard Worker     fn start_pin_thread(&mut self) {
1196*bb4ee6a4SAndroid Build Coastguard Worker         let mem = self.mem.clone();
1197*bb4ee6a4SAndroid Build Coastguard Worker         let endpoints = self.endpoints.to_vec();
1198*bb4ee6a4SAndroid Build Coastguard Worker         let notifymap_mmap = self.notifymap_mmap.clone();
1199*bb4ee6a4SAndroid Build Coastguard Worker         let dtt_root = self.coiommu_reg.dtt_root;
1200*bb4ee6a4SAndroid Build Coastguard Worker         let dtt_level = self.coiommu_reg.dtt_level;
1201*bb4ee6a4SAndroid Build Coastguard Worker         let ioevents: Vec<Event> = self
1202*bb4ee6a4SAndroid Build Coastguard Worker             .ioevents
1203*bb4ee6a4SAndroid Build Coastguard Worker             .iter()
1204*bb4ee6a4SAndroid Build Coastguard Worker             .map(|e| e.try_clone().unwrap())
1205*bb4ee6a4SAndroid Build Coastguard Worker             .collect();
1206*bb4ee6a4SAndroid Build Coastguard Worker 
1207*bb4ee6a4SAndroid Build Coastguard Worker         let bar0 = self.config_regs.get_bar_addr(COIOMMU_MMIO_BAR);
1208*bb4ee6a4SAndroid Build Coastguard Worker         let notify_base = bar0 + mem::size_of::<CoIommuReg>() as u64;
1209*bb4ee6a4SAndroid Build Coastguard Worker         for (i, evt) in self.ioevents.iter().enumerate() {
1210*bb4ee6a4SAndroid Build Coastguard Worker             self.vm_memory_client
1211*bb4ee6a4SAndroid Build Coastguard Worker                 .register_io_event(
1212*bb4ee6a4SAndroid Build Coastguard Worker                     evt.try_clone().expect("failed to clone event"),
1213*bb4ee6a4SAndroid Build Coastguard Worker                     notify_base + i as u64,
1214*bb4ee6a4SAndroid Build Coastguard Worker                     Datamatch::AnyLength,
1215*bb4ee6a4SAndroid Build Coastguard Worker                 )
1216*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to register ioevent");
1217*bb4ee6a4SAndroid Build Coastguard Worker         }
1218*bb4ee6a4SAndroid Build Coastguard Worker 
1219*bb4ee6a4SAndroid Build Coastguard Worker         let vfio_container = self.vfio_container.clone();
1220*bb4ee6a4SAndroid Build Coastguard Worker         let pinstate = self.pinstate.clone();
1221*bb4ee6a4SAndroid Build Coastguard Worker         let params = self.params;
1222*bb4ee6a4SAndroid Build Coastguard Worker 
1223*bb4ee6a4SAndroid Build Coastguard Worker         self.pin_thread = Some(WorkerThread::start("coiommu_pin", move |kill_evt| {
1224*bb4ee6a4SAndroid Build Coastguard Worker             let mut worker = PinWorker {
1225*bb4ee6a4SAndroid Build Coastguard Worker                 mem,
1226*bb4ee6a4SAndroid Build Coastguard Worker                 endpoints,
1227*bb4ee6a4SAndroid Build Coastguard Worker                 notifymap_mmap,
1228*bb4ee6a4SAndroid Build Coastguard Worker                 dtt_root,
1229*bb4ee6a4SAndroid Build Coastguard Worker                 dtt_level,
1230*bb4ee6a4SAndroid Build Coastguard Worker                 ioevents,
1231*bb4ee6a4SAndroid Build Coastguard Worker                 vfio_container,
1232*bb4ee6a4SAndroid Build Coastguard Worker                 pinstate,
1233*bb4ee6a4SAndroid Build Coastguard Worker                 params,
1234*bb4ee6a4SAndroid Build Coastguard Worker             };
1235*bb4ee6a4SAndroid Build Coastguard Worker             worker.run(kill_evt);
1236*bb4ee6a4SAndroid Build Coastguard Worker             worker
1237*bb4ee6a4SAndroid Build Coastguard Worker         }));
1238*bb4ee6a4SAndroid Build Coastguard Worker     }
1239*bb4ee6a4SAndroid Build Coastguard Worker 
start_unpin_thread(&mut self)1240*bb4ee6a4SAndroid Build Coastguard Worker     fn start_unpin_thread(&mut self) {
1241*bb4ee6a4SAndroid Build Coastguard Worker         let mem = self.mem.clone();
1242*bb4ee6a4SAndroid Build Coastguard Worker         let dtt_root = self.coiommu_reg.dtt_root;
1243*bb4ee6a4SAndroid Build Coastguard Worker         let dtt_level = self.coiommu_reg.dtt_level;
1244*bb4ee6a4SAndroid Build Coastguard Worker         let vfio_container = self.vfio_container.clone();
1245*bb4ee6a4SAndroid Build Coastguard Worker         let unpin_tube = self.unpin_tube.take();
1246*bb4ee6a4SAndroid Build Coastguard Worker         let pinstate = self.pinstate.clone();
1247*bb4ee6a4SAndroid Build Coastguard Worker         let params = self.params;
1248*bb4ee6a4SAndroid Build Coastguard Worker         self.unpin_thread = Some(WorkerThread::start("coiommu_unpin", move |kill_evt| {
1249*bb4ee6a4SAndroid Build Coastguard Worker             let mut worker = UnpinWorker {
1250*bb4ee6a4SAndroid Build Coastguard Worker                 mem,
1251*bb4ee6a4SAndroid Build Coastguard Worker                 dtt_level,
1252*bb4ee6a4SAndroid Build Coastguard Worker                 dtt_root,
1253*bb4ee6a4SAndroid Build Coastguard Worker                 vfio_container,
1254*bb4ee6a4SAndroid Build Coastguard Worker                 unpin_tube,
1255*bb4ee6a4SAndroid Build Coastguard Worker                 pinstate,
1256*bb4ee6a4SAndroid Build Coastguard Worker                 params,
1257*bb4ee6a4SAndroid Build Coastguard Worker                 unpin_gen_threshold: 0,
1258*bb4ee6a4SAndroid Build Coastguard Worker             };
1259*bb4ee6a4SAndroid Build Coastguard Worker             worker.run(kill_evt);
1260*bb4ee6a4SAndroid Build Coastguard Worker             worker
1261*bb4ee6a4SAndroid Build Coastguard Worker         }));
1262*bb4ee6a4SAndroid Build Coastguard Worker     }
1263*bb4ee6a4SAndroid Build Coastguard Worker 
allocate_bar_address( &mut self, resources: &mut SystemAllocator, address: PciAddress, size: u64, bar_num: u8, name: &str, ) -> PciResult<u64>1264*bb4ee6a4SAndroid Build Coastguard Worker     fn allocate_bar_address(
1265*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
1266*bb4ee6a4SAndroid Build Coastguard Worker         resources: &mut SystemAllocator,
1267*bb4ee6a4SAndroid Build Coastguard Worker         address: PciAddress,
1268*bb4ee6a4SAndroid Build Coastguard Worker         size: u64,
1269*bb4ee6a4SAndroid Build Coastguard Worker         bar_num: u8,
1270*bb4ee6a4SAndroid Build Coastguard Worker         name: &str,
1271*bb4ee6a4SAndroid Build Coastguard Worker     ) -> PciResult<u64> {
1272*bb4ee6a4SAndroid Build Coastguard Worker         let addr = resources
1273*bb4ee6a4SAndroid Build Coastguard Worker             .allocate_mmio(
1274*bb4ee6a4SAndroid Build Coastguard Worker                 size,
1275*bb4ee6a4SAndroid Build Coastguard Worker                 Alloc::PciBar {
1276*bb4ee6a4SAndroid Build Coastguard Worker                     bus: address.bus,
1277*bb4ee6a4SAndroid Build Coastguard Worker                     dev: address.dev,
1278*bb4ee6a4SAndroid Build Coastguard Worker                     func: address.func,
1279*bb4ee6a4SAndroid Build Coastguard Worker                     bar: bar_num,
1280*bb4ee6a4SAndroid Build Coastguard Worker                 },
1281*bb4ee6a4SAndroid Build Coastguard Worker                 name.to_string(),
1282*bb4ee6a4SAndroid Build Coastguard Worker                 AllocOptions::new().prefetchable(true).align(size),
1283*bb4ee6a4SAndroid Build Coastguard Worker             )
1284*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|e| PciDeviceError::IoAllocationFailed(size, e))?;
1285*bb4ee6a4SAndroid Build Coastguard Worker 
1286*bb4ee6a4SAndroid Build Coastguard Worker         let bar = PciBarConfiguration::new(
1287*bb4ee6a4SAndroid Build Coastguard Worker             bar_num as usize,
1288*bb4ee6a4SAndroid Build Coastguard Worker             size,
1289*bb4ee6a4SAndroid Build Coastguard Worker             PciBarRegionType::Memory64BitRegion,
1290*bb4ee6a4SAndroid Build Coastguard Worker             PciBarPrefetchable::Prefetchable,
1291*bb4ee6a4SAndroid Build Coastguard Worker         )
1292*bb4ee6a4SAndroid Build Coastguard Worker         .set_address(addr);
1293*bb4ee6a4SAndroid Build Coastguard Worker 
1294*bb4ee6a4SAndroid Build Coastguard Worker         self.config_regs
1295*bb4ee6a4SAndroid Build Coastguard Worker             .add_pci_bar(bar)
1296*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|e| PciDeviceError::IoRegistrationFailed(addr, e))?;
1297*bb4ee6a4SAndroid Build Coastguard Worker 
1298*bb4ee6a4SAndroid Build Coastguard Worker         Ok(addr)
1299*bb4ee6a4SAndroid Build Coastguard Worker     }
1300*bb4ee6a4SAndroid Build Coastguard Worker 
read_mmio(&mut self, offset: u64, data: &mut [u8])1301*bb4ee6a4SAndroid Build Coastguard Worker     fn read_mmio(&mut self, offset: u64, data: &mut [u8]) {
1302*bb4ee6a4SAndroid Build Coastguard Worker         if offset >= mem::size_of::<CoIommuReg>() as u64 {
1303*bb4ee6a4SAndroid Build Coastguard Worker             error!(
1304*bb4ee6a4SAndroid Build Coastguard Worker                 "{}: read_mmio: invalid offset 0x{:x}",
1305*bb4ee6a4SAndroid Build Coastguard Worker                 self.debug_label(),
1306*bb4ee6a4SAndroid Build Coastguard Worker                 offset
1307*bb4ee6a4SAndroid Build Coastguard Worker             );
1308*bb4ee6a4SAndroid Build Coastguard Worker             return;
1309*bb4ee6a4SAndroid Build Coastguard Worker         }
1310*bb4ee6a4SAndroid Build Coastguard Worker 
1311*bb4ee6a4SAndroid Build Coastguard Worker         // Sanity check, must be 64bit aligned accessing
1312*bb4ee6a4SAndroid Build Coastguard Worker         if offset % 8 != 0 || data.len() != 8 {
1313*bb4ee6a4SAndroid Build Coastguard Worker             error!(
1314*bb4ee6a4SAndroid Build Coastguard Worker                 "{}: read_mmio: unaligned accessing: offset 0x{:x} actual len {} expect len 8",
1315*bb4ee6a4SAndroid Build Coastguard Worker                 self.debug_label(),
1316*bb4ee6a4SAndroid Build Coastguard Worker                 offset,
1317*bb4ee6a4SAndroid Build Coastguard Worker                 data.len()
1318*bb4ee6a4SAndroid Build Coastguard Worker             );
1319*bb4ee6a4SAndroid Build Coastguard Worker             return;
1320*bb4ee6a4SAndroid Build Coastguard Worker         }
1321*bb4ee6a4SAndroid Build Coastguard Worker 
1322*bb4ee6a4SAndroid Build Coastguard Worker         let v = match offset / 8 {
1323*bb4ee6a4SAndroid Build Coastguard Worker             0 => self.coiommu_reg.dtt_root,
1324*bb4ee6a4SAndroid Build Coastguard Worker             1 => self.coiommu_reg.cmd,
1325*bb4ee6a4SAndroid Build Coastguard Worker             2 => self.coiommu_reg.dtt_level,
1326*bb4ee6a4SAndroid Build Coastguard Worker             _ => return,
1327*bb4ee6a4SAndroid Build Coastguard Worker         };
1328*bb4ee6a4SAndroid Build Coastguard Worker 
1329*bb4ee6a4SAndroid Build Coastguard Worker         data.copy_from_slice(&v.to_ne_bytes());
1330*bb4ee6a4SAndroid Build Coastguard Worker     }
1331*bb4ee6a4SAndroid Build Coastguard Worker 
write_mmio(&mut self, offset: u64, data: &[u8])1332*bb4ee6a4SAndroid Build Coastguard Worker     fn write_mmio(&mut self, offset: u64, data: &[u8]) {
1333*bb4ee6a4SAndroid Build Coastguard Worker         let mmio_len = mem::size_of::<CoIommuReg>() as u64;
1334*bb4ee6a4SAndroid Build Coastguard Worker         if offset >= mmio_len {
1335*bb4ee6a4SAndroid Build Coastguard Worker             if data.len() != 1 {
1336*bb4ee6a4SAndroid Build Coastguard Worker                 error!(
1337*bb4ee6a4SAndroid Build Coastguard Worker                     "{}: write_mmio: unaligned accessing: offset 0x{:x} actual len {} expect len 1",
1338*bb4ee6a4SAndroid Build Coastguard Worker                     self.debug_label(),
1339*bb4ee6a4SAndroid Build Coastguard Worker                     offset,
1340*bb4ee6a4SAndroid Build Coastguard Worker                     data.len()
1341*bb4ee6a4SAndroid Build Coastguard Worker                 );
1342*bb4ee6a4SAndroid Build Coastguard Worker                 return;
1343*bb4ee6a4SAndroid Build Coastguard Worker             }
1344*bb4ee6a4SAndroid Build Coastguard Worker 
1345*bb4ee6a4SAndroid Build Coastguard Worker             // Usually will not be here as this is for the per-vcpu notify
1346*bb4ee6a4SAndroid Build Coastguard Worker             // register which is monitored by the ioevents. For the notify
1347*bb4ee6a4SAndroid Build Coastguard Worker             // register which is not covered by the ioevents, they are not
1348*bb4ee6a4SAndroid Build Coastguard Worker             // be used by the frontend driver. In case the frontend driver
1349*bb4ee6a4SAndroid Build Coastguard Worker             // went here, do a simple handle to make sure the frontend driver
1350*bb4ee6a4SAndroid Build Coastguard Worker             // will not be blocked, and through an error log.
1351*bb4ee6a4SAndroid Build Coastguard Worker             let index = (offset - mmio_len) as usize;
1352*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(event) = self.ioevents.get(index) {
1353*bb4ee6a4SAndroid Build Coastguard Worker                 let _ = event.signal();
1354*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1355*bb4ee6a4SAndroid Build Coastguard Worker                 self.notifymap_mmap
1356*bb4ee6a4SAndroid Build Coastguard Worker                     .write_obj::<u64>(0, index * mem::size_of::<u64>())
1357*bb4ee6a4SAndroid Build Coastguard Worker                     .unwrap();
1358*bb4ee6a4SAndroid Build Coastguard Worker                 error!(
1359*bb4ee6a4SAndroid Build Coastguard Worker                     "{}: No page will be pinned as driver is accessing unused trigger register: offset 0x{:x}",
1360*bb4ee6a4SAndroid Build Coastguard Worker                     self.debug_label(),
1361*bb4ee6a4SAndroid Build Coastguard Worker                     offset
1362*bb4ee6a4SAndroid Build Coastguard Worker                 );
1363*bb4ee6a4SAndroid Build Coastguard Worker             }
1364*bb4ee6a4SAndroid Build Coastguard Worker             return;
1365*bb4ee6a4SAndroid Build Coastguard Worker         }
1366*bb4ee6a4SAndroid Build Coastguard Worker 
1367*bb4ee6a4SAndroid Build Coastguard Worker         // Sanity check, must be 64bit aligned accessing for CoIommuReg
1368*bb4ee6a4SAndroid Build Coastguard Worker         if offset % 8 != 0 || data.len() != 8 {
1369*bb4ee6a4SAndroid Build Coastguard Worker             error!(
1370*bb4ee6a4SAndroid Build Coastguard Worker                 "{}: write_mmio: unaligned accessing: offset 0x{:x} actual len {} expect len 8",
1371*bb4ee6a4SAndroid Build Coastguard Worker                 self.debug_label(),
1372*bb4ee6a4SAndroid Build Coastguard Worker                 offset,
1373*bb4ee6a4SAndroid Build Coastguard Worker                 data.len()
1374*bb4ee6a4SAndroid Build Coastguard Worker             );
1375*bb4ee6a4SAndroid Build Coastguard Worker             return;
1376*bb4ee6a4SAndroid Build Coastguard Worker         }
1377*bb4ee6a4SAndroid Build Coastguard Worker 
1378*bb4ee6a4SAndroid Build Coastguard Worker         let index = offset / 8;
1379*bb4ee6a4SAndroid Build Coastguard Worker         let v = u64::from_ne_bytes(data.try_into().unwrap());
1380*bb4ee6a4SAndroid Build Coastguard Worker         match index {
1381*bb4ee6a4SAndroid Build Coastguard Worker             0 => {
1382*bb4ee6a4SAndroid Build Coastguard Worker                 if self.coiommu_reg.dtt_root == 0 {
1383*bb4ee6a4SAndroid Build Coastguard Worker                     self.coiommu_reg.dtt_root = v;
1384*bb4ee6a4SAndroid Build Coastguard Worker                 }
1385*bb4ee6a4SAndroid Build Coastguard Worker             }
1386*bb4ee6a4SAndroid Build Coastguard Worker             1 => match v {
1387*bb4ee6a4SAndroid Build Coastguard Worker                 // Deactivate can happen if the frontend driver in the guest
1388*bb4ee6a4SAndroid Build Coastguard Worker                 // fails during probing or if the CoIommu device is removed
1389*bb4ee6a4SAndroid Build Coastguard Worker                 // by the guest. Neither of these cases is expected, and if
1390*bb4ee6a4SAndroid Build Coastguard Worker                 // either happens the guest will be non-functional due to
1391*bb4ee6a4SAndroid Build Coastguard Worker                 // pass-through devices which rely on CoIommu not working.
1392*bb4ee6a4SAndroid Build Coastguard Worker                 // So just fail hard and panic.
1393*bb4ee6a4SAndroid Build Coastguard Worker                 COIOMMU_CMD_DEACTIVATE => {
1394*bb4ee6a4SAndroid Build Coastguard Worker                     panic!("{}: Deactivate is not supported", self.debug_label())
1395*bb4ee6a4SAndroid Build Coastguard Worker                 }
1396*bb4ee6a4SAndroid Build Coastguard Worker                 COIOMMU_CMD_ACTIVATE => {
1397*bb4ee6a4SAndroid Build Coastguard Worker                     if self.coiommu_reg.dtt_root != 0 && self.coiommu_reg.dtt_level != 0 {
1398*bb4ee6a4SAndroid Build Coastguard Worker                         self.start_workers();
1399*bb4ee6a4SAndroid Build Coastguard Worker                     }
1400*bb4ee6a4SAndroid Build Coastguard Worker                 }
1401*bb4ee6a4SAndroid Build Coastguard Worker                 COIOMMU_CMD_PARK_UNPIN => {
1402*bb4ee6a4SAndroid Build Coastguard Worker                     let mut pinstate = self.pinstate.lock();
1403*bb4ee6a4SAndroid Build Coastguard Worker                     pinstate.unpin_thread_state = UnpinThreadState::Parked;
1404*bb4ee6a4SAndroid Build Coastguard Worker                     if let Some(v) = pinstate.unpin_park_count.checked_add(1) {
1405*bb4ee6a4SAndroid Build Coastguard Worker                         pinstate.unpin_park_count = v;
1406*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
1407*bb4ee6a4SAndroid Build Coastguard Worker                         panic!("{}: Park request overflowing", self.debug_label());
1408*bb4ee6a4SAndroid Build Coastguard Worker                     }
1409*bb4ee6a4SAndroid Build Coastguard Worker                 }
1410*bb4ee6a4SAndroid Build Coastguard Worker                 COIOMMU_CMD_UNPARK_UNPIN => {
1411*bb4ee6a4SAndroid Build Coastguard Worker                     let mut pinstate = self.pinstate.lock();
1412*bb4ee6a4SAndroid Build Coastguard Worker                     if pinstate.unpin_thread_state == UnpinThreadState::Parked {
1413*bb4ee6a4SAndroid Build Coastguard Worker                         if let Some(v) = pinstate.unpin_park_count.checked_sub(1) {
1414*bb4ee6a4SAndroid Build Coastguard Worker                             pinstate.unpin_park_count = v;
1415*bb4ee6a4SAndroid Build Coastguard Worker                             if pinstate.unpin_park_count == 0 {
1416*bb4ee6a4SAndroid Build Coastguard Worker                                 if let Some(worker_thread) = &self.unpin_thread {
1417*bb4ee6a4SAndroid Build Coastguard Worker                                     worker_thread.thread().unpark();
1418*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1419*bb4ee6a4SAndroid Build Coastguard Worker                                 pinstate.unpin_thread_state = UnpinThreadState::Unparked;
1420*bb4ee6a4SAndroid Build Coastguard Worker                             }
1421*bb4ee6a4SAndroid Build Coastguard Worker                         } else {
1422*bb4ee6a4SAndroid Build Coastguard Worker                             error!("{}: Park count is already reached to 0", self.debug_label());
1423*bb4ee6a4SAndroid Build Coastguard Worker                         }
1424*bb4ee6a4SAndroid Build Coastguard Worker                     }
1425*bb4ee6a4SAndroid Build Coastguard Worker                 }
1426*bb4ee6a4SAndroid Build Coastguard Worker                 _ => {}
1427*bb4ee6a4SAndroid Build Coastguard Worker             },
1428*bb4ee6a4SAndroid Build Coastguard Worker             2 => {
1429*bb4ee6a4SAndroid Build Coastguard Worker                 if self.coiommu_reg.dtt_level == 0 {
1430*bb4ee6a4SAndroid Build Coastguard Worker                     self.coiommu_reg.dtt_level = v;
1431*bb4ee6a4SAndroid Build Coastguard Worker                 }
1432*bb4ee6a4SAndroid Build Coastguard Worker             }
1433*bb4ee6a4SAndroid Build Coastguard Worker             _ => {}
1434*bb4ee6a4SAndroid Build Coastguard Worker         }
1435*bb4ee6a4SAndroid Build Coastguard Worker     }
1436*bb4ee6a4SAndroid Build Coastguard Worker }
1437*bb4ee6a4SAndroid Build Coastguard Worker 
1438*bb4ee6a4SAndroid Build Coastguard Worker impl PciDevice for CoIommuDev {
debug_label(&self) -> String1439*bb4ee6a4SAndroid Build Coastguard Worker     fn debug_label(&self) -> String {
1440*bb4ee6a4SAndroid Build Coastguard Worker         "CoIommu".to_owned()
1441*bb4ee6a4SAndroid Build Coastguard Worker     }
1442*bb4ee6a4SAndroid Build Coastguard Worker 
allocate_address(&mut self, resources: &mut SystemAllocator) -> PciResult<PciAddress>1443*bb4ee6a4SAndroid Build Coastguard Worker     fn allocate_address(&mut self, resources: &mut SystemAllocator) -> PciResult<PciAddress> {
1444*bb4ee6a4SAndroid Build Coastguard Worker         if self.pci_address.is_none() {
1445*bb4ee6a4SAndroid Build Coastguard Worker             self.pci_address = match resources.allocate_pci(0, self.debug_label()) {
1446*bb4ee6a4SAndroid Build Coastguard Worker                 Some(Alloc::PciBar {
1447*bb4ee6a4SAndroid Build Coastguard Worker                     bus,
1448*bb4ee6a4SAndroid Build Coastguard Worker                     dev,
1449*bb4ee6a4SAndroid Build Coastguard Worker                     func,
1450*bb4ee6a4SAndroid Build Coastguard Worker                     bar: _,
1451*bb4ee6a4SAndroid Build Coastguard Worker                 }) => Some(PciAddress { bus, dev, func }),
1452*bb4ee6a4SAndroid Build Coastguard Worker                 _ => None,
1453*bb4ee6a4SAndroid Build Coastguard Worker             }
1454*bb4ee6a4SAndroid Build Coastguard Worker         }
1455*bb4ee6a4SAndroid Build Coastguard Worker         self.pci_address.ok_or(PciDeviceError::PciAllocationFailed)
1456*bb4ee6a4SAndroid Build Coastguard Worker     }
1457*bb4ee6a4SAndroid Build Coastguard Worker 
allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> PciResult<Vec<BarRange>>1458*bb4ee6a4SAndroid Build Coastguard Worker     fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> PciResult<Vec<BarRange>> {
1459*bb4ee6a4SAndroid Build Coastguard Worker         let address = self
1460*bb4ee6a4SAndroid Build Coastguard Worker             .pci_address
1461*bb4ee6a4SAndroid Build Coastguard Worker             .expect("allocate_address must be called prior to allocate_io_bars");
1462*bb4ee6a4SAndroid Build Coastguard Worker 
1463*bb4ee6a4SAndroid Build Coastguard Worker         // Allocate one bar for the structures pointed to by the capability structures.
1464*bb4ee6a4SAndroid Build Coastguard Worker         let mut ranges: Vec<BarRange> = Vec::new();
1465*bb4ee6a4SAndroid Build Coastguard Worker 
1466*bb4ee6a4SAndroid Build Coastguard Worker         let mmio_addr = self.allocate_bar_address(
1467*bb4ee6a4SAndroid Build Coastguard Worker             resources,
1468*bb4ee6a4SAndroid Build Coastguard Worker             address,
1469*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_MMIO_BAR_SIZE,
1470*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_MMIO_BAR as u8,
1471*bb4ee6a4SAndroid Build Coastguard Worker             "coiommu-mmiobar",
1472*bb4ee6a4SAndroid Build Coastguard Worker         )?;
1473*bb4ee6a4SAndroid Build Coastguard Worker 
1474*bb4ee6a4SAndroid Build Coastguard Worker         ranges.push(BarRange {
1475*bb4ee6a4SAndroid Build Coastguard Worker             addr: mmio_addr,
1476*bb4ee6a4SAndroid Build Coastguard Worker             size: COIOMMU_MMIO_BAR_SIZE,
1477*bb4ee6a4SAndroid Build Coastguard Worker             prefetchable: false,
1478*bb4ee6a4SAndroid Build Coastguard Worker         });
1479*bb4ee6a4SAndroid Build Coastguard Worker 
1480*bb4ee6a4SAndroid Build Coastguard Worker         Ok(ranges)
1481*bb4ee6a4SAndroid Build Coastguard Worker     }
1482*bb4ee6a4SAndroid Build Coastguard Worker 
allocate_device_bars( &mut self, resources: &mut SystemAllocator, ) -> PciResult<Vec<BarRange>>1483*bb4ee6a4SAndroid Build Coastguard Worker     fn allocate_device_bars(
1484*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
1485*bb4ee6a4SAndroid Build Coastguard Worker         resources: &mut SystemAllocator,
1486*bb4ee6a4SAndroid Build Coastguard Worker     ) -> PciResult<Vec<BarRange>> {
1487*bb4ee6a4SAndroid Build Coastguard Worker         let address = self
1488*bb4ee6a4SAndroid Build Coastguard Worker             .pci_address
1489*bb4ee6a4SAndroid Build Coastguard Worker             .expect("allocate_address must be called prior to allocate_device_bars");
1490*bb4ee6a4SAndroid Build Coastguard Worker 
1491*bb4ee6a4SAndroid Build Coastguard Worker         let mut ranges: Vec<BarRange> = Vec::new();
1492*bb4ee6a4SAndroid Build Coastguard Worker 
1493*bb4ee6a4SAndroid Build Coastguard Worker         let topologymap_addr = self.allocate_bar_address(
1494*bb4ee6a4SAndroid Build Coastguard Worker             resources,
1495*bb4ee6a4SAndroid Build Coastguard Worker             address,
1496*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_TOPOLOGYMAP_SIZE as u64,
1497*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_TOPOLOGYMAP_BAR,
1498*bb4ee6a4SAndroid Build Coastguard Worker             "coiommu-topology",
1499*bb4ee6a4SAndroid Build Coastguard Worker         )?;
1500*bb4ee6a4SAndroid Build Coastguard Worker         self.topologymap_addr = Some(topologymap_addr);
1501*bb4ee6a4SAndroid Build Coastguard Worker         ranges.push(BarRange {
1502*bb4ee6a4SAndroid Build Coastguard Worker             addr: topologymap_addr,
1503*bb4ee6a4SAndroid Build Coastguard Worker             size: COIOMMU_TOPOLOGYMAP_SIZE as u64,
1504*bb4ee6a4SAndroid Build Coastguard Worker             prefetchable: false,
1505*bb4ee6a4SAndroid Build Coastguard Worker         });
1506*bb4ee6a4SAndroid Build Coastguard Worker 
1507*bb4ee6a4SAndroid Build Coastguard Worker         let notifymap_addr = self.allocate_bar_address(
1508*bb4ee6a4SAndroid Build Coastguard Worker             resources,
1509*bb4ee6a4SAndroid Build Coastguard Worker             address,
1510*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_NOTIFYMAP_SIZE as u64,
1511*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_NOTIFYMAP_BAR as u8,
1512*bb4ee6a4SAndroid Build Coastguard Worker             "coiommu-notifymap",
1513*bb4ee6a4SAndroid Build Coastguard Worker         )?;
1514*bb4ee6a4SAndroid Build Coastguard Worker         self.notifymap_addr = Some(notifymap_addr);
1515*bb4ee6a4SAndroid Build Coastguard Worker         ranges.push(BarRange {
1516*bb4ee6a4SAndroid Build Coastguard Worker             addr: notifymap_addr,
1517*bb4ee6a4SAndroid Build Coastguard Worker             size: COIOMMU_NOTIFYMAP_SIZE as u64,
1518*bb4ee6a4SAndroid Build Coastguard Worker             prefetchable: false,
1519*bb4ee6a4SAndroid Build Coastguard Worker         });
1520*bb4ee6a4SAndroid Build Coastguard Worker 
1521*bb4ee6a4SAndroid Build Coastguard Worker         Ok(ranges)
1522*bb4ee6a4SAndroid Build Coastguard Worker     }
1523*bb4ee6a4SAndroid Build Coastguard Worker 
read_config_register(&self, reg_idx: usize) -> u321524*bb4ee6a4SAndroid Build Coastguard Worker     fn read_config_register(&self, reg_idx: usize) -> u32 {
1525*bb4ee6a4SAndroid Build Coastguard Worker         self.config_regs.read_reg(reg_idx)
1526*bb4ee6a4SAndroid Build Coastguard Worker     }
1527*bb4ee6a4SAndroid Build Coastguard Worker 
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])1528*bb4ee6a4SAndroid Build Coastguard Worker     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
1529*bb4ee6a4SAndroid Build Coastguard Worker         if reg_idx == COMMAND_REG
1530*bb4ee6a4SAndroid Build Coastguard Worker             && data.len() == 2
1531*bb4ee6a4SAndroid Build Coastguard Worker             && data[0] & COMMAND_REG_MEMORY_SPACE_MASK as u8 != 0
1532*bb4ee6a4SAndroid Build Coastguard Worker             && !self.mmapped
1533*bb4ee6a4SAndroid Build Coastguard Worker         {
1534*bb4ee6a4SAndroid Build Coastguard Worker             self.mmap();
1535*bb4ee6a4SAndroid Build Coastguard Worker         }
1536*bb4ee6a4SAndroid Build Coastguard Worker 
1537*bb4ee6a4SAndroid Build Coastguard Worker         self.config_regs.write_reg(reg_idx, offset, data);
1538*bb4ee6a4SAndroid Build Coastguard Worker     }
1539*bb4ee6a4SAndroid Build Coastguard Worker 
keep_rds(&self) -> Vec<RawDescriptor>1540*bb4ee6a4SAndroid Build Coastguard Worker     fn keep_rds(&self) -> Vec<RawDescriptor> {
1541*bb4ee6a4SAndroid Build Coastguard Worker         let mut rds = vec![
1542*bb4ee6a4SAndroid Build Coastguard Worker             self.vfio_container.lock().as_raw_descriptor(),
1543*bb4ee6a4SAndroid Build Coastguard Worker             self.vm_memory_client.as_raw_descriptor(),
1544*bb4ee6a4SAndroid Build Coastguard Worker             self.notifymap_mem.as_raw_descriptor(),
1545*bb4ee6a4SAndroid Build Coastguard Worker             self.topologymap_mem.as_raw_descriptor(),
1546*bb4ee6a4SAndroid Build Coastguard Worker         ];
1547*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(unpin_tube) = &self.unpin_tube {
1548*bb4ee6a4SAndroid Build Coastguard Worker             rds.push(unpin_tube.as_raw_descriptor());
1549*bb4ee6a4SAndroid Build Coastguard Worker         }
1550*bb4ee6a4SAndroid Build Coastguard Worker         rds.extend(self.ioevents.iter().map(Event::as_raw_descriptor));
1551*bb4ee6a4SAndroid Build Coastguard Worker         rds
1552*bb4ee6a4SAndroid Build Coastguard Worker     }
1553*bb4ee6a4SAndroid Build Coastguard Worker 
read_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &mut [u8])1554*bb4ee6a4SAndroid Build Coastguard Worker     fn read_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &mut [u8]) {
1555*bb4ee6a4SAndroid Build Coastguard Worker         match bar_index {
1556*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_MMIO_BAR => self.read_mmio(offset, data),
1557*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_NOTIFYMAP_BAR => {
1558*bb4ee6a4SAndroid Build Coastguard Worker                 // With coiommu device activated, the accessing the notifymap bar
1559*bb4ee6a4SAndroid Build Coastguard Worker                 // won't cause vmexit. If goes here, means the coiommu device is
1560*bb4ee6a4SAndroid Build Coastguard Worker                 // deactivated, and will not do the pin/unpin work. Thus no need
1561*bb4ee6a4SAndroid Build Coastguard Worker                 // to handle this notifymap read.
1562*bb4ee6a4SAndroid Build Coastguard Worker             }
1563*bb4ee6a4SAndroid Build Coastguard Worker             _ => {}
1564*bb4ee6a4SAndroid Build Coastguard Worker         }
1565*bb4ee6a4SAndroid Build Coastguard Worker     }
1566*bb4ee6a4SAndroid Build Coastguard Worker 
write_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &[u8])1567*bb4ee6a4SAndroid Build Coastguard Worker     fn write_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &[u8]) {
1568*bb4ee6a4SAndroid Build Coastguard Worker         match bar_index {
1569*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_MMIO_BAR => self.write_mmio(offset, data),
1570*bb4ee6a4SAndroid Build Coastguard Worker             COIOMMU_NOTIFYMAP_BAR => {
1571*bb4ee6a4SAndroid Build Coastguard Worker                 // With coiommu device activated, the accessing the notifymap bar
1572*bb4ee6a4SAndroid Build Coastguard Worker                 // won't cause vmexit. If goes here, means the coiommu device is
1573*bb4ee6a4SAndroid Build Coastguard Worker                 // deactivated, and will not do the pin/unpin work. Thus no need
1574*bb4ee6a4SAndroid Build Coastguard Worker                 // to handle this notifymap write.
1575*bb4ee6a4SAndroid Build Coastguard Worker             }
1576*bb4ee6a4SAndroid Build Coastguard Worker             _ => {}
1577*bb4ee6a4SAndroid Build Coastguard Worker         }
1578*bb4ee6a4SAndroid Build Coastguard Worker     }
1579*bb4ee6a4SAndroid Build Coastguard Worker 
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>1580*bb4ee6a4SAndroid Build Coastguard Worker     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
1581*bb4ee6a4SAndroid Build Coastguard Worker         self.config_regs.get_bar_configuration(bar_num)
1582*bb4ee6a4SAndroid Build Coastguard Worker     }
1583*bb4ee6a4SAndroid Build Coastguard Worker }
1584*bb4ee6a4SAndroid Build Coastguard Worker 
1585*bb4ee6a4SAndroid Build Coastguard Worker impl Suspendable for CoIommuDev {}
1586