Skip to main content

ostd/mm/dma/
mod.rs

1// SPDX-License-Identifier: MPL-2.0
2use vstd::prelude::*;
3#[cfg(feature = "irc11")]
4use vstd::thread_view::Objective;
5use vstd_extra::{
6    atomic_data::AtomicDataWithOwner,
7    once::Once,
8    resource_invariant::{SimpleResourceInvariant, TrivialResourceInvariant},
9};
10
11mod dma_coherent;
12pub use dma_coherent::DmaCoherent;
13mod dma_stream;
14#[cfg(ktest)]
15mod test;
16
17use crate::sync::{PreemptDisabled, SpinLock, SpinLockGuard};
18use alloc::collections::BTreeSet;
19
20use super::Paddr;
21
22verus! {
23
24pub tracked struct DmaMappingSetOwner {}
25
26// This empty owner carries no subjective weak-memory observations.
27#[cfg(feature = "irc11")]
28unsafe impl Objective for DmaMappingSetOwner {
29
30}
31
32pub ghost struct DmaMappingSetInvariant;
33
34impl SimpleResourceInvariant<
35    SpinLock<BTreeSet<Paddr>, PreemptDisabled>,
36> for DmaMappingSetInvariant {
37    type Resource = DmaMappingSetOwner;
38
39    open spec fn inv(
40        v: SpinLock<BTreeSet<Paddr>, PreemptDisabled>,
41        _resource: DmaMappingSetOwner,
42    ) -> bool {
43        v.type_inv()
44    }
45}
46
47/// Set of all physical addresses with dma mapping.
48exec static DMA_MAPPING_SET: Once<
49    SpinLock<BTreeSet<Paddr>, PreemptDisabled>,
50    DmaMappingSetInvariant,
51    TrivialResourceInvariant,
52>
53    ensures
54        DMA_MAPPING_SET.wf(),
55{
56    Once::new(Ghost(TrivialResourceInvariant))
57}
58
59#[inline(always)]
60pub fn init() {
61    let lock = SpinLock::new(BTreeSet::new(), Ghost(()), Tracked(()));
62
63    proof {
64        use_type_invariant(&lock);
65    }
66
67    let tracked owner = DmaMappingSetOwner {  };
68    let data = AtomicDataWithOwner::new(lock, Tracked(owner), Ghost(DmaMappingSetInvariant));
69
70    DMA_MAPPING_SET.init(data);
71}
72
73/// The device address.
74///
75/// If a device performs DMA to read or write system
76/// memory, the addresses used by the device are device addresses.
77/// Daddr can distinguish the address space used by cpu side and
78/// the address space used by device side.
79pub type Daddr = usize;
80
81#[derive(PartialEq)]
82pub enum DmaType {
83    Direct,
84    Iommu,
85}
86
87#[derive(Debug, PartialEq)]
88pub enum DmaError {
89    InvalidArgs,
90    AlreadyMapped,
91}
92
93/// A trait for types that have mapped address in the device address space.
94pub trait HasDaddr {
95    /// Gets the base address of the mapping in the
96    /// device address space.
97    fn daddr(&self) -> Daddr;
98}
99
100#[verifier::inline]
101pub open spec fn is_valid_daddr(d: Daddr) -> bool {
102    true
103}
104
105/// Checks whether the physical addresses has dma mapping.
106/// Fail if they have been mapped, otherwise insert them.
107#[verus_spec(
108    requires
109        start_paddr + num_pages * crate::mm::PAGE_SIZE <= usize::MAX,
110)]
111fn check_and_insert_dma_mapping(start_paddr: Paddr, num_pages: usize) -> bool {
112    match DMA_MAPPING_SET.get() {
113        None => false,
114        Some(mapping_set) => {
115            let mut mapping_set = mapping_set.lock();
116            let mut i = 0;
117
118            #[verus_spec(
119                invariant
120                    i <= num_pages,
121                    start_paddr + num_pages * crate::mm::PAGE_SIZE <= usize::MAX,
122                decreases
123                    num_pages - i,
124            )]
125            while i < num_pages {
126                let paddr = start_paddr + (i * crate::mm::PAGE_SIZE);
127                if mapping_set.contains(&paddr) {
128                    return false;
129                }
130                i += 1;
131            }
132
133            i = 0;
134            #[verus_spec(
135                invariant
136                    i <= num_pages,
137                    start_paddr + num_pages * crate::mm::PAGE_SIZE <= usize::MAX,
138                decreases
139                    num_pages - i,
140            )]
141            while i < num_pages {
142                let paddr = start_paddr + (i * crate::mm::PAGE_SIZE);
143                // Failure: complex arguments to $mut parameters are currently unsupported
144                // mapping_set.insert(paddr);
145                i += 1;
146            }
147
148            true
149        },
150    }
151}
152
153#[verifier::external_body]
154pub fn dma_type() -> DmaType {
155    unimplemented!()
156}
157
158} // verus!
159/*
160use alloc::collections::BTreeSet;
161
162pub use dma_coherent::DmaCoherent;
163pub use dma_stream::{DmaDirection, DmaStream, DmaStreamSlice};
164use inherit_methods_macro::inherit_methods;
165use spin::Once;
166
167use super::Paddr;
168use crate::{arch::iommu::has_dma_remapping, mm::PAGE_SIZE, sync::SpinLock};
169
170
171
172
173#[inherit_methods(from = "(**self)")]
174impl<T: HasDaddr> HasDaddr for &T {
175    fn daddr(&self) -> Daddr;
176}
177
178/// Set of all physical addresses with dma mapping.
179static DMA_MAPPING_SET: Once<SpinLock<BTreeSet<Paddr>>> = Once::new();
180
181pub fn dma_type() -> DmaType {
182    if has_dma_remapping() {
183        DmaType::Iommu
184    } else {
185        DmaType::Direct
186    }
187}
188
189pub fn init() {
190    DMA_MAPPING_SET.call_once(|| SpinLock::new(BTreeSet::new(), Ghost(()), Tracked(())));
191}
192
193/// Checks whether the physical addresses has dma mapping.
194/// Fail if they have been mapped, otherwise insert them.
195fn check_and_insert_dma_mapping(start_paddr: Paddr, num_pages: usize) -> bool {
196    let mut mapping_set = DMA_MAPPING_SET.get().unwrap().disable_irq().lock();
197    // Ensure that the addresses used later will not overflow
198    start_paddr.checked_add(num_pages * PAGE_SIZE).unwrap();
199    for i in 0..num_pages {
200        let paddr = start_paddr + (i * PAGE_SIZE);
201        if mapping_set.contains(&paddr) {
202            return false;
203        }
204    }
205    for i in 0..num_pages {
206        let paddr = start_paddr + (i * PAGE_SIZE);
207        mapping_set.insert(paddr);
208    }
209    true
210}
211
212/// Removes a physical address from the dma mapping set.
213fn remove_dma_mapping(start_paddr: Paddr, num_pages: usize) {
214    let mut mapping_set = DMA_MAPPING_SET.get().unwrap().disable_irq().lock();
215    // Ensure that the addresses used later will not overflow
216    start_paddr.checked_add(num_pages * PAGE_SIZE).unwrap();
217    for i in 0..num_pages {
218        let paddr = start_paddr + (i * PAGE_SIZE);
219        mapping_set.remove(&paddr);
220    }
221}
222*/