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 for i in 0..num_pages
117 invariant
118 start_paddr + num_pages * crate::mm::PAGE_SIZE <= usize::MAX,
119 {
120 let paddr = start_paddr + (i * crate::mm::PAGE_SIZE);
121 if mapping_set.contains(&paddr) {
122 return false;
123 }
124 }
125
126 for i in 0..num_pages
127 invariant
128 start_paddr + num_pages * crate::mm::PAGE_SIZE <= usize::MAX,
129 {
130 let paddr = start_paddr + (i * crate::mm::PAGE_SIZE);
131 // Failure: complex arguments to $mut parameters are currently unsupported
132 // mapping_set.insert(paddr);
133 }
134
135 true
136 },
137 }
138}
139
140#[verifier::external_body]
141pub fn dma_type() -> DmaType {
142 unimplemented!()
143}
144
145} // verus!
146/*
147use alloc::collections::BTreeSet;
148
149pub use dma_coherent::DmaCoherent;
150pub use dma_stream::{DmaDirection, DmaStream, DmaStreamSlice};
151use inherit_methods_macro::inherit_methods;
152use spin::Once;
153
154use super::Paddr;
155use crate::{arch::iommu::has_dma_remapping, mm::PAGE_SIZE, sync::SpinLock};
156
157
158
159
160#[inherit_methods(from = "(**self)")]
161impl<T: HasDaddr> HasDaddr for &T {
162 fn daddr(&self) -> Daddr;
163}
164
165/// Set of all physical addresses with dma mapping.
166static DMA_MAPPING_SET: Once<SpinLock<BTreeSet<Paddr>>> = Once::new();
167
168pub fn dma_type() -> DmaType {
169 if has_dma_remapping() {
170 DmaType::Iommu
171 } else {
172 DmaType::Direct
173 }
174}
175
176pub fn init() {
177 DMA_MAPPING_SET.call_once(|| SpinLock::new(BTreeSet::new(), Ghost(()), Tracked(())));
178}
179
180/// Checks whether the physical addresses has dma mapping.
181/// Fail if they have been mapped, otherwise insert them.
182fn check_and_insert_dma_mapping(start_paddr: Paddr, num_pages: usize) -> bool {
183 let mut mapping_set = DMA_MAPPING_SET.get().unwrap().disable_irq().lock();
184 // Ensure that the addresses used later will not overflow
185 start_paddr.checked_add(num_pages * PAGE_SIZE).unwrap();
186 for i in 0..num_pages {
187 let paddr = start_paddr + (i * PAGE_SIZE);
188 if mapping_set.contains(&paddr) {
189 return false;
190 }
191 }
192 for i in 0..num_pages {
193 let paddr = start_paddr + (i * PAGE_SIZE);
194 mapping_set.insert(paddr);
195 }
196 true
197}
198
199/// Removes a physical address from the dma mapping set.
200fn remove_dma_mapping(start_paddr: Paddr, num_pages: usize) {
201 let mut mapping_set = DMA_MAPPING_SET.get().unwrap().disable_irq().lock();
202 // Ensure that the addresses used later will not overflow
203 start_paddr.checked_add(num_pages * PAGE_SIZE).unwrap();
204 for i in 0..num_pages {
205 let paddr = start_paddr + (i * PAGE_SIZE);
206 mapping_set.remove(&paddr);
207 }
208}
209*/