1use vstd::pervasive::arbitrary;
49use vstd::prelude::*;
50
51use vstd_extra::ownership::*;
52
53use crate::specs::mm::io::{VmIoMemView, VmIoOwner, axiom_kernel_mem_view};
54
55use crate::mm::{MAX_USERSPACE_VADDR, Vaddr, vm_space::vm_space_specs::VmSpaceOwner};
56
57use super::{VmIoEntry, VmIoKind, VmSpaceId, tracked_vm_io_entry_new};
58
59verus! {
60
61pub proof fn tracked_vm_space_reader_embedded<'a>(
68 tracked vm_space: &VmSpaceOwner,
69 vaddr: Vaddr,
70 len: usize,
71) -> (tracked res: Option<VmIoOwner>)
72 requires
73 vm_space.inv(),
74 ensures
75 res matches Some(o) ==> o.inv(),
76 res matches Some(o) ==> o.mem_view is None,
77 res is Some ==> (vaddr as nat) + (len as nat) <= MAX_USERSPACE_VADDR as nat,
78{
79 if (vaddr as nat) + (len as nat) <= MAX_USERSPACE_VADDR as nat {
80 let tracked owner = VmIoOwner {
81 id: arbitrary(),
82 range: vaddr..(vaddr + len) as usize,
83 is_fallible: true,
84 is_kernel: false,
85 mem_view: None,
86 };
87 Some(owner)
88 } else {
89 None
90 }
91}
92
93pub proof fn tracked_vm_space_writer_embedded<'a>(
95 tracked vm_space: &VmSpaceOwner,
96 vaddr: Vaddr,
97 len: usize,
98) -> (tracked res: Option<VmIoOwner>)
99 requires
100 vm_space.inv(),
101 ensures
102 res matches Some(o) ==> o.inv(),
103 res matches Some(o) ==> o.mem_view is None,
104 res is Some ==> (vaddr as nat) + (len as nat) <= MAX_USERSPACE_VADDR as nat,
105{
106 if (vaddr as nat) + (len as nat) <= MAX_USERSPACE_VADDR as nat {
107 let tracked owner = VmIoOwner {
108 id: arbitrary(),
109 range: vaddr..(vaddr + len) as usize,
110 is_fallible: true,
111 is_kernel: false,
112 mem_view: None,
113 };
114 Some(owner)
115 } else {
116 None
117 }
118}
119
120pub proof fn tracked_vm_reader_from_kernel_space_embedded(vaddr: Vaddr, len: usize) -> (tracked res:
127 VmIoOwner)
128 ensures
129 res.inv(),
130 res.read_view_initialized(),
131{
132 let ghost range = if (vaddr as nat) + (len as nat) <= usize::MAX as nat {
133 vaddr..(vaddr + len) as usize
134 } else {
135 vaddr..vaddr
136 };
137 let tracked mem_view = axiom_kernel_mem_view(range);
138 VmIoOwner {
139 id: arbitrary(),
140 range,
141 is_fallible: false,
142 is_kernel: true,
143 mem_view: Some(VmIoMemView::ReadView(mem_view)),
144 }
145}
146
147pub proof fn tracked_vm_writer_from_kernel_space_embedded(vaddr: Vaddr, len: usize) -> (tracked res:
153 VmIoOwner)
154 ensures
155 res.inv(),
156 res.has_write_view(),
157{
158 let ghost range = if (vaddr as nat) + (len as nat) <= usize::MAX as nat {
159 vaddr..(vaddr + len) as usize
160 } else {
161 vaddr..vaddr
162 };
163 let tracked mem_view = axiom_kernel_mem_view(range);
164 VmIoOwner {
165 id: arbitrary(),
166 range,
167 is_fallible: false,
168 is_kernel: true,
169 mem_view: Some(VmIoMemView::WriteView(mem_view)),
170 }
171}
172
173pub proof fn tracked_vm_reader_read_embedded(
181 tracked source_owner: &mut VmIoOwner,
182 tracked dest_owner: &mut VmIoOwner,
183) -> (tracked consumed_w: VmIoOwner)
184 requires
185 old(source_owner).inv(),
186 old(dest_owner).inv(),
187 old(source_owner).read_view_initialized(),
188 old(dest_owner).has_write_view(),
189 ensures
190 final(source_owner).inv(),
191 final(dest_owner).inv(),
192 final(source_owner).read_view_initialized(),
193 final(dest_owner).has_write_view(),
194 final(source_owner).range.start >= old(source_owner).range.start,
196 final(source_owner).range.end == old(source_owner).range.end,
197 final(dest_owner).range.start >= old(dest_owner).range.start,
198 final(dest_owner).range.end == old(dest_owner).range.end,
199 consumed_w.inv(),
200 consumed_w.has_write_view(),
201 consumed_w.range.start >= old(dest_owner).range.start,
203 consumed_w.range.end <= final(dest_owner).range.start,
204{
205 dest_owner.split(0)
206}
207
208pub proof fn lemma_vm_writer_limit_embedded(tracked owner: &mut VmIoOwner, max_avail: usize)
210 requires
211 old(owner).inv(),
212 ensures
213 final(owner).inv(),
214 *final(owner) == *old(owner),
215{
216}
217
218pub proof fn lemma_vm_writer_skip_embedded(tracked owner: &mut VmIoOwner, nbytes: usize)
220 requires
221 old(owner).inv(),
222 ensures
223 final(owner).inv(),
224 *final(owner) == *old(owner),
225{
226}
227
228pub enum VmIoMethod {
233 ReaderLimit(usize),
234 ReaderSkip(usize),
235 WriterFillZeros(usize),
236 WriterLimit(usize),
237 WriterSkip(usize),
238}
239
240pub(super) proof fn new_vm_io_step<'a>(
244 tracked vm_space: &VmSpaceOwner,
245 vs: Option<VmSpaceId>,
246 vaddr: Vaddr,
247 len: usize,
248 kind: VmIoKind,
249) -> (tracked res: Option<VmIoEntry>)
250 requires
251 vm_space.inv(),
252 vs is Some, ensures
255 res matches Some(e) ==> e.inv(),
256 res matches Some(e) ==> e.kind == kind,
257 res matches Some(e) ==> e.vaddr == vaddr,
258 res matches Some(e) ==> e.len == len,
259 res matches Some(e) ==> e.vm_space == vs,
260 res matches Some(_) ==> (vaddr as nat) + (len as nat) <= MAX_USERSPACE_VADDR as nat,
261{
262 let tracked owner_opt = match kind {
263 VmIoKind::Reader => tracked_vm_space_reader_embedded(vm_space, vaddr, len),
264 VmIoKind::Writer => tracked_vm_space_writer_embedded(vm_space, vaddr, len),
265 };
266 match owner_opt {
267 Option::Some(owner) => {
268 let tracked entry = tracked_vm_io_entry_new(vs, kind, vaddr, len, owner);
269 Option::Some(entry)
270 },
271 Option::None => Option::None,
272 }
273}
274
275pub(super) proof fn new_kernel_vm_io_step(vaddr: Vaddr, len: usize, kind: VmIoKind) -> (tracked res:
280 VmIoEntry)
281 ensures
282 res.inv(),
283 res.kind == kind,
284 res.vaddr == vaddr,
285 res.len == len,
286 res.vm_space is None,
287{
288 let tracked owner = match kind {
289 VmIoKind::Reader => tracked_vm_reader_from_kernel_space_embedded(vaddr, len),
290 VmIoKind::Writer => tracked_vm_writer_from_kernel_space_embedded(vaddr, len),
291 };
292 tracked_vm_io_entry_new(Option::<VmSpaceId>::None, kind, vaddr, len, owner)
293}
294
295pub(super) proof fn drop_vm_io_step(tracked _entry: VmIoEntry) {
298}
299
300pub(super) proof fn vm_io_method_step(tracked entry: &mut VmIoEntry, method: VmIoMethod)
306 requires
307 old(entry).inv(),
308 ensures
309 final(entry).vm_space == old(entry).vm_space,
310 final(entry).kind == old(entry).kind,
311 final(entry).vaddr == old(entry).vaddr,
312 final(entry).len == old(entry).len,
313 final(entry).inv(),
314{
315 match method {
316 VmIoMethod::ReaderLimit(_) => {},
317 VmIoMethod::ReaderSkip(_) => {},
318 VmIoMethod::WriterFillZeros(_) => {},
319 VmIoMethod::WriterLimit(max) => lemma_vm_writer_limit_embedded(&mut entry.owner, max),
320 VmIoMethod::WriterSkip(n) => lemma_vm_writer_skip_embedded(&mut entry.owner, n),
321 }
322}
323
324pub(super) proof fn read_step(
330 tracked source: &mut VmIoEntry,
331 tracked dest: &mut VmIoEntry,
332) -> (tracked res: VmIoEntry)
333 requires
334 old(source).inv(),
335 old(dest).inv(),
336 old(source).is_kernel_reader(),
337 old(dest).is_kernel_writer(),
338 ensures
339 final(source).vm_space == old(source).vm_space,
340 final(source).kind == old(source).kind,
341 final(source).vaddr == old(source).vaddr,
342 final(source).len == old(source).len,
343 final(source).inv(),
344 final(dest).vm_space == old(dest).vm_space,
345 final(dest).kind == old(dest).kind,
346 final(dest).vaddr == old(dest).vaddr,
347 final(dest).len == old(dest).len,
348 final(dest).inv(),
349 res.inv(),
351 res.kind == VmIoKind::Writer,
352 res.vm_space is None,
353{
354 let tracked val_owner = tracked_vm_reader_read_embedded(&mut source.owner, &mut dest.owner);
355 tracked_vm_io_entry_new(Option::<VmSpaceId>::None, VmIoKind::Writer, 0usize, 0usize, val_owner)
356}
357
358}