1use core::ops::Range;
9use vstd::pervasive::{arbitrary, proof_from_false};
10use vstd::prelude::*;
11use vstd_extra::ownership::Inv;
12
13use crate::mm::io::{Infallible, VmReader, VmWriter};
14use crate::mm::kspace::{KERNEL_BASE_VADDR, KERNEL_END_VADDR};
15use crate::specs::mm::virt_mem::MemView;
16
17verus! {
18
19pub axiom fn axiom_slice_in_kernel(slice: &[u8])
32 ensures
33 ::vstd_extra::external::slice::as_ptr_spec(slice) as usize >= KERNEL_BASE_VADDR,
34 ::vstd_extra::external::slice::as_ptr_spec(slice) as usize + slice.len()
35 <= KERNEL_END_VADDR,
36;
37
38pub axiom fn axiom_kernel_mem_view(range: Range<usize>) -> (tracked mv: MemView)
48 ensures
49 mv.mappings_are_disjoint(),
50 forall|va: usize|
51 #![trigger mv.addr_transl(va)]
52 range.start <= va < range.end ==> {
53 &&& mv.addr_transl(va) is Some
54 &&& mv.memory.contains_key((mv.addr_transl(va)->0).0)
55 &&& mv.memory[(mv.addr_transl(va)->0).0].contents[(mv.addr_transl(
56 va,
57 )->0).1 as int] is Init
58 },
59;
60
61pub tracked enum VmIoMemView {
76 WriteView(MemView),
78 ReadView(MemView),
80}
81
82pub tracked struct VmIoOwner {
89 pub ghost id: nat,
91 pub ghost range: Range<usize>,
93 pub ghost is_fallible: bool,
95 pub ghost is_kernel: bool,
97 pub mem_view: Option<VmIoMemView>,
99}
100
101impl VmIoOwner {
102 pub open spec fn inv_wf(self) -> bool {
105 self.range.start <= self.range.end
106 }
107}
108
109impl Inv for VmIoOwner {
110 open spec fn inv(self) -> bool {
112 &&& self.inv_wf()
113 &&& match self.mem_view {
114 Some(VmIoMemView::WriteView(mv)) => {
115 &&& mv.mappings_are_disjoint()
116 &&& forall|va: usize|
117 self.range.start <= va < self.range.end ==> {
118 &&& #[trigger] mv.addr_transl(va) is Some
119 }
120 },
121 Some(VmIoMemView::ReadView(mv)) => {
122 &&& mv.mappings_are_disjoint()
123 &&& forall|va: usize|
124 self.range.start <= va < self.range.end ==> {
125 &&& #[trigger] mv.addr_transl(va) is Some
126 }
127 },
128 None => true,
129 }
130 }
131}
132
133impl VmIoOwner {
134 #[verifier::inline]
136 pub open spec fn has_read_view(self) -> bool {
137 self.mem_view matches Some(VmIoMemView::ReadView(_))
138 }
139
140 #[verifier::inline]
142 pub open spec fn has_write_view(self) -> bool {
143 self.mem_view matches Some(VmIoMemView::WriteView(_))
144 }
145
146 #[verifier::inline]
148 pub open spec fn can_read(self) -> bool {
149 self.has_read_view()
150 }
151
152 #[verifier::inline]
154 pub open spec fn can_write(self) -> bool {
155 self.has_write_view()
156 }
157
158 #[verifier::inline]
160 pub open spec fn read_view_initialized(self) -> bool {
161 match self.mem_view {
162 Some(VmIoMemView::ReadView(mem_src)) => {
163 forall|i: usize|
164 #![trigger mem_src.addr_transl(i)]
165 self.range.start <= i < self.range.end ==> {
166 &&& mem_src.addr_transl(i) is Some
167 &&& mem_src.memory.contains_key((mem_src.addr_transl(i)->0).0)
168 &&& mem_src.memory[(mem_src.addr_transl(i)->0).0].contents[(
169 mem_src.addr_transl(i)->0).1 as int] is Init
170 }
171 },
172 _ => false,
173 }
174 }
175
176 #[verifier::inline]
178 pub open spec fn overlaps(self, other: VmIoOwner) -> bool {
179 !self.disjoint(other)
180 }
181
182 #[verifier::inline]
183 pub open spec fn overlaps_with_range(self, range: Range<usize>) -> bool {
184 &&& self.range.start <= range.end
185 &&& range.start <= self.range.end
186 }
187
188 #[verifier::inline]
190 pub open spec fn disjoint(self, other: VmIoOwner) -> bool {
191 &&& !self.overlaps_with_range(other.range)
192 &&& match (self.mem_view, other.mem_view) {
193 (Some(lhs), Some(rhs)) => match (lhs, rhs) {
194 (VmIoMemView::WriteView(lmv), VmIoMemView::WriteView(rmv)) => {
195 lmv.mappings.disjoint(rmv.mappings)
196 },
197 (VmIoMemView::WriteView(lmv), VmIoMemView::ReadView(rmv)) => {
198 lmv.mappings.disjoint(rmv.mappings)
199 },
200 (VmIoMemView::ReadView(lmv), VmIoMemView::WriteView(rmv)) => {
201 lmv.mappings.disjoint(rmv.mappings)
202 },
203 (VmIoMemView::ReadView(lmv), VmIoMemView::ReadView(rmv)) => {
204 lmv.mappings.disjoint(rmv.mappings)
205 },
206 },
207 _ => true,
208 }
209 }
210
211 #[verifier::inline]
212 pub open spec fn params_eq(self, other: VmIoOwner) -> bool {
213 &&& self.range == other.range
214 &&& self.is_fallible == other.is_fallible
215 }
216
217 pub proof fn change_fallible(tracked &mut self, tracked fallible: bool)
227 requires
228 old(self).inv(),
229 old(self).is_fallible != fallible,
230 ensures
231 final(self).inv(),
232 final(self).is_fallible == fallible,
233 {
234 self.is_fallible = fallible;
235 }
236
237 pub proof fn advance(tracked &mut self, nbytes: usize) -> (tracked res: VmIoMemView)
253 requires
254 old(self).inv(),
255 old(self).mem_view is Some,
256 nbytes <= old(self).range.end - old(self).range.start,
257 ensures
258 final(self).inv(),
259 final(self).range.start == old(self).range.start + nbytes,
260 final(self).range.end == old(self).range.end,
261 final(self).is_fallible == old(self).is_fallible,
262 final(self).id == old(self).id,
263 final(self).is_kernel == old(self).is_kernel,
264 old(self).mem_view matches Some(VmIoMemView::ReadView(_))
265 ==> final(self).mem_view matches Some(VmIoMemView::ReadView(_)),
266 old(self).mem_view matches Some(VmIoMemView::WriteView(_))
267 ==> final(self).mem_view matches Some(VmIoMemView::WriteView(_)),
268 old(self).read_view_initialized() ==> final(self).read_view_initialized(),
269 old(self).mem_view matches Some(VmIoMemView::ReadView(_)) ==> forall|va: usize|
272 #![trigger final(self).read_view_of().read(va)]
273 old(self).range.start + nbytes <= va < old(self).range.end && old(
274 self,
275 ).read_view_of().addr_transl(va) is Some && old(
276 self,
277 ).read_view_of().memory.contains_key(
278 (old(self).read_view_of().addr_transl(va)->0).0,
279 ) ==> {
280 &&& old(self).read_view_of().addr_transl(va)
281 == final(self).read_view_of().addr_transl(va)
282 &&& old(self).read_view_of().read(va) == final(self).read_view_of().read(va)
283 },
284 {
285 let ghost old_start = self.range.start;
286 let ghost old_end = self.range.end;
287 let ghost old_view_g = self.mem_view;
288 let ghost split_end = old_start + nbytes;
289
290 let tracked old_view = self.mem_view.tracked_take();
291 let tracked res = match old_view {
292 VmIoMemView::WriteView(view) => {
293 let ghost view_g = view;
294 let tracked (left, right) = view.tracked_split(old_start, nbytes);
295 MemView::lemma_split_preserves_transl(view_g, old_start, nbytes, left, right);
296 assert(right.mappings_are_disjoint()) by {
297 assert(right.mappings <= view_g.mappings);
298 };
299 assert forall|va: usize|
300 split_end <= va < old_end implies #[trigger] right.addr_transl(va) is Some by {
301 assert(view_g.addr_transl(va) is Some);
302 assert(view_g.addr_transl(va) == right.addr_transl(va));
303 };
304 self.mem_view = Some(VmIoMemView::WriteView(right));
305 VmIoMemView::WriteView(left)
306 },
307 VmIoMemView::ReadView(view) => {
308 let ghost view_g = view;
309 let tracked (left, right) = view.tracked_split(old_start, nbytes);
310 MemView::lemma_split_preserves_transl(view_g, old_start, nbytes, left, right);
311 MemView::lemma_split_preserves_read(view_g, old_start, nbytes, left, right);
312 assert(right.mappings_are_disjoint()) by {
313 assert(right.mappings <= view_g.mappings);
314 };
315 assert forall|va: usize|
316 split_end <= va < old_end implies #[trigger] right.addr_transl(va) is Some by {
317 assert(view_g.addr_transl(va) is Some);
318 assert(view_g.addr_transl(va) == right.addr_transl(va));
319 };
320 if old_view_g matches Some(VmIoMemView::ReadView(mv0)) && (forall|i: usize|
322 #![trigger mv0.addr_transl(i)]
323 old_start <= i < old_end ==> {
324 &&& mv0.addr_transl(i) is Some
325 &&& mv0.memory.contains_key(mv0.addr_transl(i).unwrap().0)
326 &&& mv0.memory[mv0.addr_transl(i).unwrap().0].contents[mv0.addr_transl(
327 i,
328 ).unwrap().1 as int] is Init
329 }) {
330 assert forall|i: usize|
331 #![trigger right.addr_transl(i)]
332 split_end <= i < old_end implies {
333 &&& right.addr_transl(i) is Some
334 &&& right.memory.contains_key(right.addr_transl(i).unwrap().0)
335 &&& right.memory[right.addr_transl(
336 i,
337 ).unwrap().0].contents[right.addr_transl(i).unwrap().1 as int] is Init
338 } by {
339 assert(view_g.addr_transl(i) == right.addr_transl(i));
340 let pa = right.addr_transl(i).unwrap().0;
341 assert(view_g.memory.contains_key(pa));
342 assert(view_g.is_mapped(i, pa));
343 assert(right.memory.dom().contains(pa));
344 assert(right.memory[pa] == view_g.memory[pa]);
345 };
346 }
347 self.mem_view = Some(VmIoMemView::ReadView(right));
348 VmIoMemView::ReadView(left)
349 },
350 };
351 self.range = Range { start: split_end as usize, end: old_end };
352 res
353 }
354
355 pub proof fn split(tracked &mut self, nbytes: usize) -> (tracked r: VmIoOwner)
371 requires
372 old(self).inv(),
373 old(self).mem_view is Some,
374 nbytes <= old(self).range.end - old(self).range.start,
375 ensures
376 r.inv(),
377 r.range.start == old(self).range.start,
378 r.range.end == old(self).range.start + nbytes,
379 r.is_fallible == old(self).is_fallible,
380 r.is_kernel == old(self).is_kernel,
381 r.mem_view is Some,
382 final(self).inv(),
383 final(self).range.start == old(self).range.start + nbytes,
384 final(self).range.end == old(self).range.end,
385 final(self).is_fallible == old(self).is_fallible,
386 final(self).id == old(self).id,
387 final(self).is_kernel == old(self).is_kernel,
388 final(self).mem_view is Some,
389 old(self).mem_view matches Some(VmIoMemView::ReadView(_)) ==> {
390 &&& r.mem_view matches Some(VmIoMemView::ReadView(_))
391 &&& final(self).mem_view matches Some(VmIoMemView::ReadView(_))
392 },
393 old(self).mem_view matches Some(VmIoMemView::WriteView(_)) ==> {
394 &&& r.mem_view matches Some(VmIoMemView::WriteView(_))
395 &&& final(self).mem_view matches Some(VmIoMemView::WriteView(_))
396 },
397 old(self).read_view_initialized() ==> {
398 &&& r.read_view_initialized()
399 &&& final(self).read_view_initialized()
400 },
401 {
402 let ghost old_start = self.range.start;
403 let ghost old_end = self.range.end;
404 let ghost old_view_g = self.mem_view;
405 let ghost split_end = old_start + nbytes;
406
407 let tracked old_view = self.mem_view.tracked_take();
408 let tracked left_view = match old_view {
409 VmIoMemView::WriteView(view) => {
410 let ghost view_g = view;
411 let tracked (left, right) = view.tracked_split(old_start, nbytes);
412 MemView::lemma_split_preserves_transl(view_g, old_start, nbytes, left, right);
413 assert(left.mappings_are_disjoint()) by {
415 assert(left.mappings <= view_g.mappings);
416 };
417 assert forall|va: usize|
418 old_start <= va < split_end implies #[trigger] left.addr_transl(va) is Some by {
419 assert(view_g.addr_transl(va) is Some);
420 assert(view_g.addr_transl(va) == left.addr_transl(va));
421 };
422 assert(right.mappings_are_disjoint()) by {
423 assert(right.mappings <= view_g.mappings);
424 };
425 assert forall|va: usize|
426 split_end <= va < old_end implies #[trigger] right.addr_transl(va) is Some by {
427 assert(view_g.addr_transl(va) is Some);
428 assert(view_g.addr_transl(va) == right.addr_transl(va));
429 };
430 self.mem_view = Some(VmIoMemView::WriteView(right));
431 VmIoMemView::WriteView(left)
432 },
433 VmIoMemView::ReadView(view) => {
434 let ghost view_g = view;
435 let tracked (left, right) = view.tracked_split(old_start, nbytes);
436 MemView::lemma_split_preserves_transl(view_g, old_start, nbytes, left, right);
437 assert(left.mappings_are_disjoint()) by {
438 assert(left.mappings <= view_g.mappings);
439 };
440 assert forall|va: usize|
441 old_start <= va < split_end implies #[trigger] left.addr_transl(va) is Some by {
442 assert(view_g.addr_transl(va) is Some);
443 assert(view_g.addr_transl(va) == left.addr_transl(va));
444 };
445 assert(right.mappings_are_disjoint()) by {
446 assert(right.mappings <= view_g.mappings);
447 };
448 assert forall|va: usize|
449 split_end <= va < old_end implies #[trigger] right.addr_transl(va) is Some by {
450 assert(view_g.addr_transl(va) is Some);
451 assert(view_g.addr_transl(va) == right.addr_transl(va));
452 };
453 if old_view_g matches Some(VmIoMemView::ReadView(mv0)) && (forall|i: usize|
456 #![trigger mv0.addr_transl(i)]
457 old_start <= i < old_end ==> {
458 &&& mv0.addr_transl(i) is Some
459 &&& mv0.memory.contains_key(mv0.addr_transl(i).unwrap().0)
460 &&& mv0.memory[mv0.addr_transl(i).unwrap().0].contents[mv0.addr_transl(
461 i,
462 ).unwrap().1 as int] is Init
463 }) {
464 assert forall|i: usize|
465 #![trigger left.addr_transl(i)]
466 old_start <= i < split_end implies {
467 &&& left.addr_transl(i) is Some
468 &&& left.memory.contains_key(left.addr_transl(i).unwrap().0)
469 &&& left.memory[left.addr_transl(i).unwrap().0].contents[left.addr_transl(
470 i,
471 ).unwrap().1 as int] is Init
472 } by {
473 assert(view_g.addr_transl(i) == left.addr_transl(i));
474 let pa = left.addr_transl(i).unwrap().0;
475 assert(view_g.memory.contains_key(pa));
476 assert(view_g.is_mapped(i, pa));
477 assert(left.memory.dom().contains(pa));
478 assert(left.memory[pa] == view_g.memory[pa]);
479 };
480 assert forall|i: usize|
481 #![trigger right.addr_transl(i)]
482 split_end <= i < old_end implies {
483 &&& right.addr_transl(i) is Some
484 &&& right.memory.contains_key(right.addr_transl(i).unwrap().0)
485 &&& right.memory[right.addr_transl(
486 i,
487 ).unwrap().0].contents[right.addr_transl(i).unwrap().1 as int] is Init
488 } by {
489 assert(view_g.addr_transl(i) == right.addr_transl(i));
490 let pa = right.addr_transl(i).unwrap().0;
491 assert(view_g.memory.contains_key(pa));
492 assert(view_g.is_mapped(i, pa));
493 assert(right.memory.dom().contains(pa));
494 assert(right.memory[pa] == view_g.memory[pa]);
495 };
496 }
497 self.mem_view = Some(VmIoMemView::ReadView(right));
498 VmIoMemView::ReadView(left)
499 },
500 };
501 self.range = Range { start: split_end as usize, end: old_end };
502
503 let tracked left_owner = VmIoOwner {
504 id: arbitrary(),
505 range: Range { start: old_start, end: split_end as usize },
506 is_fallible: self.is_fallible,
507 is_kernel: self.is_kernel,
508 mem_view: Some(left_view),
509 };
510 left_owner
511 }
512
513 pub proof fn tracked_read_view_unwrap(tracked &self) -> (tracked r: &MemView)
522 requires
523 self.inv(),
524 self.mem_view matches Some(VmIoMemView::ReadView(_)),
525 ensures
526 VmIoMemView::ReadView(*r) == self.mem_view->0,
527 *r == Self::read_view_of(*self),
528 {
529 match &self.mem_view {
530 Some(VmIoMemView::ReadView(r)) => r,
531 _ => { proof_from_false() },
532 }
533 }
534
535 pub open spec fn read_view_of(self) -> MemView {
541 match self.mem_view {
542 Some(VmIoMemView::ReadView(mv)) => mv,
543 _ => arbitrary(),
544 }
545 }
546
547 pub proof fn write_to_read(tracked &mut self)
562 requires
563 old(self).inv(),
564 old(self).mem_view matches Some(VmIoMemView::WriteView(_)),
565 ensures
566 final(self).inv(),
567 final(self).range == old(self).range,
568 final(self).is_fallible == old(self).is_fallible,
569 final(self).is_kernel == old(self).is_kernel,
570 final(self).id == old(self).id,
571 final(self).mem_view matches Some(VmIoMemView::ReadView(_)),
572 old(self).mem_view matches Some(VmIoMemView::WriteView(mv))
573 ==> final(self).mem_view matches Some(VmIoMemView::ReadView(rv)) && rv == mv,
574 {
575 let tracked old_view = self.mem_view.tracked_take();
576 let tracked mv = match old_view {
577 VmIoMemView::WriteView(m) => m,
578 _ => { proof_from_false() },
579 };
580 self.mem_view = Some(VmIoMemView::ReadView(mv));
581 }
582}
583
584impl<Fallibility> VmWriter<'_, Fallibility> {
588 pub open spec fn inv_wf(self) -> bool {
590 &&& self.cursor.range@ == self.end.range@
591 }
592
593 pub open spec fn wf(self, owner: VmIoOwner) -> bool {
595 &&& owner.inv()
596 &&& owner.range.start == self.cursor.vaddr
597 &&& owner.range.end == self.end.vaddr
598 &&& owner.id == self.ghost_id@
599 &&& owner.mem_view matches Some(VmIoMemView::WriteView(mv)) ==> {
600 forall|va: usize|
601 owner.range.start <= va < owner.range.end ==> {
602 &&& #[trigger] mv.addr_transl(va) is Some
603 }
604 }
605 }
606}
607
608impl<Fallibility> Inv for VmWriter<'_, Fallibility> {
609 open spec fn inv(self) -> bool {
610 &&& self.inv_wf()
611 &&& self.cursor.inv()
612 &&& self.end.inv()
613 &&& self.cursor.vaddr <= self.end.vaddr
614 }
615}
616
617impl<Fallibility> VmReader<'_, Fallibility> {
618 pub open spec fn inv_wf(self) -> bool {
620 &&& self.cursor.range@ == self.end.range@
621 }
622
623 pub open spec fn wf(self, owner: VmIoOwner) -> bool {
625 &&& owner.inv()
626 &&& owner.range.start == self.cursor.vaddr
627 &&& owner.range.end == self.end.vaddr
628 &&& owner.id == self.ghost_id@
629 &&& owner.mem_view matches Some(VmIoMemView::ReadView(mv)) ==> {
630 forall|va: usize|
631 owner.range.start <= va < owner.range.end ==> {
632 &&& #[trigger] mv.addr_transl(va) is Some
633 }
634 }
635 }
636}
637
638impl<Fallibility> Inv for VmReader<'_, Fallibility> {
639 open spec fn inv(self) -> bool {
640 &&& self.inv_wf()
641 &&& self.cursor.inv()
642 &&& self.end.inv()
643 &&& self.cursor.vaddr <= self.end.vaddr
644 }
645}
646
647}