1use core::ops::Range;
30
31use vstd::prelude::*;
32use vstd_extra::ownership::*;
33
34use crate::mm::frame::UFrame;
35use crate::mm::io::VmIoOwner;
36use crate::mm::page_prop::PageProperty;
37use crate::mm::vm_space::vm_space_specs::VmSpaceOwner;
38use crate::mm::vm_space::UserPtConfig;
39use crate::mm::Vaddr;
40use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
41use crate::specs::mm::page_table::cursor::owners::CursorOwner;
42
43verus! {
44
45pub type VmSpaceId = int;
47
48pub type CursorId = int;
50
51pub type VmIoId = int;
53
54pub enum VmIoKind {
56 Reader,
57 Writer,
58}
59
60pub tracked struct VmIoEntry {
62 pub vm_space: VmSpaceId,
63 pub kind: VmIoKind,
64 pub owner: VmIoOwner,
65}
66
67pub enum CursorKind {
72 ReadOnly,
73 Mutable,
74}
75
76pub tracked struct CursorEntry<'rcu> {
83 pub vm_space: VmSpaceId,
84 pub kind: CursorKind,
85 pub owner: CursorOwner<'rcu, UserPtConfig>,
86}
87
88pub tracked struct VmStore<'rcu> {
94 pub regions: MetaRegionOwners,
95 pub vm_spaces: Map<VmSpaceId, VmSpaceOwner>,
96 pub cursors: Map<CursorId, CursorEntry<'rcu>>,
97 pub vm_ios: Map<VmIoId, VmIoEntry>,
98}
99
100impl<'a, 'rcu> VmStore<'rcu> {
101 pub open spec fn inv(self) -> bool {
105 &&& self.regions.inv()
106 &&& forall|id: VmSpaceId|
107 #[trigger] self.vm_spaces.dom().contains(id)
108 ==> self.vm_spaces[id].inv()
109 &&& forall|id: CursorId|
110 #[trigger] self.cursors.dom().contains(id)
111 ==> self.cursors[id].owner.inv()
112 &&& forall|id: CursorId|
113 #[trigger] self.cursors.dom().contains(id)
114 ==> self.vm_spaces.dom().contains(self.cursors[id].vm_space)
115 &&& forall|id: VmIoId|
116 #[trigger] self.vm_ios.dom().contains(id)
117 ==> self.vm_ios[id].owner.inv()
118 &&& forall|id: VmIoId|
119 #[trigger] self.vm_ios.dom().contains(id)
120 ==> self.vm_spaces.dom().contains(self.vm_ios[id].vm_space)
121 }
122}
123
124pub enum Op {
126 NewVmSpace,
129 DropVmSpace { vs: VmSpaceId },
131 OpenCursor { vs: VmSpaceId, va: Range<Vaddr> },
135 OpenCursorMut { vs: VmSpaceId, va: Range<Vaddr> },
137 DropCursor { c: CursorId },
140 Query { c: CursorId },
143 FindNext { c: CursorId, len: usize },
145 Jump { c: CursorId, va: Vaddr },
147 VirtAddr { c: CursorId },
150 Map { c: CursorId, frame: UFrame, prop: PageProperty },
154 Unmap { c: CursorId, len: usize },
157 ProtectNext { c: CursorId, len: usize },
161 NewReader { vs: VmSpaceId, vaddr: Vaddr, len: usize },
163 NewWriter { vs: VmSpaceId, vaddr: Vaddr, len: usize },
165 DropReader { vio: VmIoId },
167 DropWriter { vio: VmIoId },
169}
170
171pub axiom fn vm_space_new_embedded<'a>(tracked regions: &mut MetaRegionOwners)
182 -> (tracked res: VmSpaceOwner)
183 requires
184 old(regions).inv(),
185 ensures
186 final(regions).inv(),
187 res.inv(),
188;
189
190pub axiom fn vm_space_cursor_embedded<'a, 'rcu>(
201 tracked vm_space: &VmSpaceOwner,
202 va: Range<Vaddr>,
203) -> (tracked res: Option<CursorOwner<'rcu, UserPtConfig>>)
204 requires
205 vm_space.inv(),
206 ensures
207 res matches Some(c) ==> c.inv(),
208;
209
210pub axiom fn vm_space_cursor_mut_embedded<'a, 'rcu>(
214 tracked vm_space: &VmSpaceOwner,
215 va: Range<Vaddr>,
216) -> (tracked res: Option<CursorOwner<'rcu, UserPtConfig>>)
217 requires
218 vm_space.inv(),
219 ensures
220 res matches Some(c) ==> c.inv(),
221;
222
223pub axiom fn cursor_query_embedded<'rcu>(
227 tracked owner: &mut CursorOwner<'rcu, UserPtConfig>,
228)
229 requires
230 old(owner).inv(),
231 ensures
232 final(owner).inv(),
233;
234
235pub axiom fn cursor_find_next_embedded<'rcu>(
238 tracked owner: &mut CursorOwner<'rcu, UserPtConfig>,
239 len: usize,
240)
241 requires
242 old(owner).inv(),
243 ensures
244 final(owner).inv(),
245;
246
247pub axiom fn cursor_jump_embedded<'rcu>(
250 tracked owner: &mut CursorOwner<'rcu, UserPtConfig>,
251 va: Vaddr,
252)
253 requires
254 old(owner).inv(),
255 ensures
256 final(owner).inv(),
257;
258
259pub axiom fn cursor_mut_map_embedded<'rcu>(
265 tracked owner: &mut CursorOwner<'rcu, UserPtConfig>,
266 tracked regions: &mut MetaRegionOwners,
267 frame: UFrame,
268 prop: PageProperty,
269)
270 requires
271 old(owner).inv(),
272 old(regions).inv(),
273 ensures
274 final(owner).inv(),
275 final(regions).inv(),
276;
277
278pub axiom fn cursor_mut_unmap_embedded<'rcu>(
282 tracked owner: &mut CursorOwner<'rcu, UserPtConfig>,
283 tracked regions: &mut MetaRegionOwners,
284 len: usize,
285)
286 requires
287 old(owner).inv(),
288 old(regions).inv(),
289 ensures
290 final(owner).inv(),
291 final(regions).inv(),
292;
293
294pub axiom fn cursor_mut_protect_next_embedded<'rcu>(
296 tracked owner: &mut CursorOwner<'rcu, UserPtConfig>,
297 len: usize,
298)
299 requires
300 old(owner).inv(),
301 ensures
302 final(owner).inv(),
303;
304
305pub axiom fn vm_space_reader_embedded<'a>(
312 tracked vm_space: &VmSpaceOwner,
313 vaddr: Vaddr,
314 len: usize,
315) -> (tracked res: Option<VmIoOwner>)
316 requires
317 vm_space.inv(),
318 ensures
319 res matches Some(o) ==> o.inv(),
320;
321
322pub axiom fn vm_space_writer_embedded<'a>(
324 tracked vm_space: &VmSpaceOwner,
325 vaddr: Vaddr,
326 len: usize,
327) -> (tracked res: Option<VmIoOwner>)
328 requires
329 vm_space.inv(),
330 ensures
331 res matches Some(o) ==> o.inv(),
332;
333
334pub proof fn step<'a, 'rcu>(tracked s: &mut VmStore<'rcu>, op: Op)
340 requires
341 old(s).inv(),
342 ensures
343 final(s).inv(),
344{
345 match op {
346 Op::NewVmSpace => new_vm_space_step(s),
347 Op::DropVmSpace { vs } => drop_vm_space_step(s, vs),
348 Op::OpenCursor { vs, va } => open_cursor_step(s, vs, va, CursorKind::ReadOnly),
349 Op::OpenCursorMut { vs, va } => open_cursor_step(s, vs, va, CursorKind::Mutable),
350 Op::DropCursor { c } => drop_cursor_step(s, c),
351 Op::Query { c } => cursor_method_step(s, c, CursorMethod::Query),
352 Op::FindNext { c, len } => cursor_method_step(s, c, CursorMethod::FindNext(len)),
353 Op::Jump { c, va } => cursor_method_step(s, c, CursorMethod::Jump(va)),
354 Op::VirtAddr { c: _ } => {} Op::Map { c, frame, prop } => map_step(s, c, frame, prop),
356 Op::Unmap { c, len } => cursor_mut_regions_step(s, c, CursorMutRegionsMethod::Unmap(len)),
357 Op::ProtectNext { c, len } => cursor_method_step(s, c, CursorMethod::ProtectNext(len)),
358 Op::NewReader { vs, vaddr, len } => new_vm_io_step(s, vs, vaddr, len, VmIoKind::Reader),
359 Op::NewWriter { vs, vaddr, len } => new_vm_io_step(s, vs, vaddr, len, VmIoKind::Writer),
360 Op::DropReader { vio } => drop_vm_io_step(s, vio),
361 Op::DropWriter { vio } => drop_vm_io_step(s, vio),
362 }
363}
364
365pub enum CursorMethod {
367 Query,
368 FindNext(usize),
369 Jump(Vaddr),
370 ProtectNext(usize),
371}
372
373pub enum CursorMutRegionsMethod {
377 Unmap(usize),
378}
379
380pub open spec fn fresh_vm_space_id<'a>(m: Map<VmSpaceId, VmSpaceOwner>) -> VmSpaceId {
383 choose|id: VmSpaceId| !m.dom().contains(id)
384}
385
386pub open spec fn fresh_cursor_id<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>) -> CursorId {
388 choose|id: CursorId| !m.dom().contains(id)
389}
390
391pub axiom fn axiom_fresh_vm_space_id_not_in_dom<'a>(
394 m: Map<VmSpaceId, VmSpaceOwner>,
395)
396 ensures
397 !m.dom().contains(fresh_vm_space_id(m)),
398;
399
400pub axiom fn axiom_fresh_cursor_id_not_in_dom<'rcu>(
403 m: Map<CursorId, CursorEntry<'rcu>>,
404)
405 ensures
406 !m.dom().contains(fresh_cursor_id(m)),
407;
408
409pub axiom fn axiom_cursor_entry_new<'rcu>(
416 vm_space: VmSpaceId,
417 kind: CursorKind,
418 tracked owner: CursorOwner<'rcu, UserPtConfig>,
419) -> (tracked res: CursorEntry<'rcu>)
420 ensures
421 res.vm_space == vm_space,
422 res.kind == kind,
423 res.owner == owner,
424;
425
426pub open spec fn fresh_vm_io_id<'a>(m: Map<VmIoId, VmIoEntry>) -> VmIoId {
428 choose|id: VmIoId| !m.dom().contains(id)
429}
430
431pub axiom fn axiom_fresh_vm_io_id_not_in_dom<'a>(m: Map<VmIoId, VmIoEntry>)
434 ensures
435 !m.dom().contains(fresh_vm_io_id(m)),
436;
437
438pub axiom fn axiom_vm_io_entry_new<'a>(
440 vm_space: VmSpaceId,
441 kind: VmIoKind,
442 tracked owner: VmIoOwner,
443) -> (tracked res: VmIoEntry)
444 ensures
445 res.vm_space == vm_space,
446 res.kind == kind,
447 res.owner == owner,
448;
449
450proof fn new_vm_space_step<'a, 'rcu>(tracked s: &mut VmStore<'rcu>)
451 requires
452 old(s).inv(),
453 ensures
454 final(s).inv(),
455{
456 let tracked owner = vm_space_new_embedded(&mut s.regions);
457 let ghost id = fresh_vm_space_id(s.vm_spaces);
458 axiom_fresh_vm_space_id_not_in_dom(s.vm_spaces);
459 s.vm_spaces.tracked_insert(id, owner);
460 assert(final(s).inv()) by {
461 assert forall|j: VmSpaceId|
462 #[trigger] final(s).vm_spaces.dom().contains(j)
463 implies final(s).vm_spaces[j].inv()
464 by {
465 if j == id {
466 assert(final(s).vm_spaces[j] == owner);
467 } else {
468 assert(old(s).vm_spaces.dom().contains(j));
469 }
470 };
471 assert forall|j: CursorId|
474 #[trigger] final(s).cursors.dom().contains(j)
475 implies final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
476 by {
477 assert(old(s).cursors.dom().contains(j));
478 assert(old(s).vm_spaces.dom().contains(old(s).cursors[j].vm_space));
479 };
480 assert forall|j: VmIoId|
481 #[trigger] final(s).vm_ios.dom().contains(j)
482 implies final(s).vm_ios[j].owner.inv()
483 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
484 by {
485 assert(old(s).vm_ios.dom().contains(j));
486 assert(final(s).vm_ios[j] == old(s).vm_ios[j]);
487 };
488 };
489}
490
491proof fn drop_vm_space_step<'a, 'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId)
492 requires
493 old(s).inv(),
494 ensures
495 final(s).inv(),
496{
497 if s.vm_spaces.dom().contains(vs)
501 && (forall|c: CursorId|
502 #[trigger] s.cursors.dom().contains(c)
503 ==> s.cursors[c].vm_space != vs)
504 && (forall|v: VmIoId|
505 #[trigger] s.vm_ios.dom().contains(v)
506 ==> s.vm_ios[v].vm_space != vs)
507 {
508 let _ = s.vm_spaces.tracked_remove(vs);
509 }
510 assert(final(s).inv()) by {
511 assert forall|j: VmSpaceId|
512 #[trigger] final(s).vm_spaces.dom().contains(j)
513 implies final(s).vm_spaces[j].inv()
514 by {
515 assert(old(s).vm_spaces.dom().contains(j));
516 };
517 assert forall|j: CursorId|
518 #[trigger] final(s).cursors.dom().contains(j)
519 implies final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
520 by {
521 assert(old(s).cursors.dom().contains(j));
522 assert(final(s).cursors[j] == old(s).cursors[j]);
523 };
524 assert forall|j: VmIoId|
525 #[trigger] final(s).vm_ios.dom().contains(j)
526 implies final(s).vm_ios[j].owner.inv()
527 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
528 by {
529 assert(old(s).vm_ios.dom().contains(j));
530 assert(final(s).vm_ios[j] == old(s).vm_ios[j]);
531 };
532 };
533}
534
535proof fn open_cursor_step<'a, 'rcu>(
536 tracked s: &mut VmStore<'rcu>,
537 vs: VmSpaceId,
538 va: Range<Vaddr>,
539 kind: CursorKind,
540)
541 requires
542 old(s).inv(),
543 ensures
544 final(s).inv(),
545{
546 if s.vm_spaces.dom().contains(vs) {
547 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
548 let tracked res = match kind {
549 CursorKind::ReadOnly => vm_space_cursor_embedded(vm_space_ref, va),
550 CursorKind::Mutable => vm_space_cursor_mut_embedded(vm_space_ref, va),
551 };
552 match res {
553 Option::Some(owner) => {
554 let ghost id = fresh_cursor_id(s.cursors);
555 axiom_fresh_cursor_id_not_in_dom(s.cursors);
556 let tracked entry = axiom_cursor_entry_new(vs, kind, owner);
557 s.cursors.tracked_insert(id, entry);
558 assert(final(s).inv()) by {
559 assert forall|j: CursorId|
560 #[trigger] final(s).cursors.dom().contains(j)
561 implies final(s).cursors[j].owner.inv()
562 && final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
563 by {
564 if j == id {
565 assert(final(s).cursors[j] == entry);
566 } else {
567 assert(old(s).cursors.dom().contains(j));
568 }
569 };
570 assert forall|j: VmIoId|
571 #[trigger] final(s).vm_ios.dom().contains(j)
572 implies final(s).vm_ios[j].owner.inv()
573 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
574 by {
575 assert(old(s).vm_ios.dom().contains(j));
576 assert(final(s).vm_ios[j] == old(s).vm_ios[j]);
577 };
578 };
579 },
580 Option::None => {
581 },
583 }
584 }
585}
586
587proof fn drop_cursor_step<'a, 'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
588 requires
589 old(s).inv(),
590 ensures
591 final(s).inv(),
592{
593 if s.cursors.dom().contains(c) {
594 let _ = s.cursors.tracked_remove(c);
595 }
596 assert(final(s).inv()) by {
597 assert forall|j: CursorId|
598 #[trigger] final(s).cursors.dom().contains(j)
599 implies final(s).cursors[j].owner.inv()
600 && final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
601 by {
602 assert(old(s).cursors.dom().contains(j));
603 assert(final(s).cursors[j] == old(s).cursors[j]);
604 };
605 assert forall|j: VmIoId|
606 #[trigger] final(s).vm_ios.dom().contains(j)
607 implies final(s).vm_ios[j].owner.inv()
608 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
609 by {
610 assert(old(s).vm_ios.dom().contains(j));
611 assert(final(s).vm_ios[j] == old(s).vm_ios[j]);
612 };
613 };
614}
615
616proof fn cursor_method_step<'a, 'rcu>(
617 tracked s: &mut VmStore<'rcu>,
618 c: CursorId,
619 method: CursorMethod,
620)
621 requires
622 old(s).inv(),
623 ensures
624 final(s).inv(),
625{
626 if s.cursors.dom().contains(c) {
627 let tracked mut entry = s.cursors.tracked_remove(c);
628 let ghost old_vm_space = entry.vm_space;
629 let ghost old_kind = entry.kind;
630 match method {
631 CursorMethod::Query => cursor_query_embedded(&mut entry.owner),
632 CursorMethod::FindNext(len) => cursor_find_next_embedded(&mut entry.owner, len),
633 CursorMethod::Jump(va) => cursor_jump_embedded(&mut entry.owner, va),
634 CursorMethod::ProtectNext(len) => cursor_mut_protect_next_embedded(&mut entry.owner, len),
635 }
636 assert(entry.vm_space == old_vm_space);
637 assert(entry.kind == old_kind);
638 s.cursors.tracked_insert(c, entry);
639 }
640 assert(final(s).inv()) by {
641 assert forall|j: CursorId|
642 #[trigger] final(s).cursors.dom().contains(j)
643 implies final(s).cursors[j].owner.inv()
644 && final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
645 by {
646 assert(old(s).cursors.dom().contains(j));
647 if j == c {
648 } else {
650 assert(final(s).cursors[j] == old(s).cursors[j]);
651 }
652 };
653 assert forall|j: VmIoId|
654 #[trigger] final(s).vm_ios.dom().contains(j)
655 implies final(s).vm_ios[j].owner.inv()
656 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
657 by {
658 assert(old(s).vm_ios.dom().contains(j));
659 assert(final(s).vm_ios[j] == old(s).vm_ios[j]);
660 };
661 };
662}
663
664proof fn cursor_mut_regions_step<'a, 'rcu>(
665 tracked s: &mut VmStore<'rcu>,
666 c: CursorId,
667 method: CursorMutRegionsMethod,
668)
669 requires
670 old(s).inv(),
671 ensures
672 final(s).inv(),
673{
674 if s.cursors.dom().contains(c) {
675 let tracked mut entry = s.cursors.tracked_remove(c);
676 let ghost old_vm_space = entry.vm_space;
677 match method {
678 CursorMutRegionsMethod::Unmap(len) => {
679 cursor_mut_unmap_embedded(&mut entry.owner, &mut s.regions, len);
680 },
681 }
682 assert(entry.vm_space == old_vm_space);
683 s.cursors.tracked_insert(c, entry);
684 }
685 assert(final(s).inv()) by {
686 assert forall|j: VmSpaceId|
688 #[trigger] final(s).vm_spaces.dom().contains(j)
689 implies final(s).vm_spaces[j].inv()
690 by {
691 assert(old(s).vm_spaces.dom().contains(j));
692 assert(final(s).vm_spaces[j] == old(s).vm_spaces[j]);
693 };
694 assert forall|j: CursorId|
695 #[trigger] final(s).cursors.dom().contains(j)
696 implies final(s).cursors[j].owner.inv()
697 && final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
698 by {
699 assert(old(s).cursors.dom().contains(j));
700 if j == c {
701 } else {
703 assert(final(s).cursors[j] == old(s).cursors[j]);
704 }
705 };
706 assert forall|j: VmIoId|
707 #[trigger] final(s).vm_ios.dom().contains(j)
708 implies final(s).vm_ios[j].owner.inv()
709 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
710 by {
711 assert(old(s).vm_ios.dom().contains(j));
712 assert(final(s).vm_ios[j] == old(s).vm_ios[j]);
713 };
714 };
715}
716
717proof fn map_step<'a, 'rcu>(
718 tracked s: &mut VmStore<'rcu>,
719 c: CursorId,
720 frame: UFrame,
721 prop: PageProperty,
722)
723 requires
724 old(s).inv(),
725 ensures
726 final(s).inv(),
727{
728 if s.cursors.dom().contains(c) {
729 let tracked mut entry = s.cursors.tracked_remove(c);
730 let ghost old_vm_space = entry.vm_space;
731 cursor_mut_map_embedded(&mut entry.owner, &mut s.regions, frame, prop);
732 assert(entry.vm_space == old_vm_space);
733 s.cursors.tracked_insert(c, entry);
734 }
735 assert(final(s).inv()) by {
736 assert forall|j: VmSpaceId|
737 #[trigger] final(s).vm_spaces.dom().contains(j)
738 implies final(s).vm_spaces[j].inv()
739 by {
740 assert(old(s).vm_spaces.dom().contains(j));
741 assert(final(s).vm_spaces[j] == old(s).vm_spaces[j]);
742 };
743 assert forall|j: CursorId|
744 #[trigger] final(s).cursors.dom().contains(j)
745 implies final(s).cursors[j].owner.inv()
746 && final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
747 by {
748 assert(old(s).cursors.dom().contains(j));
749 if j == c {
750 } else {
752 assert(final(s).cursors[j] == old(s).cursors[j]);
753 }
754 };
755 assert forall|j: VmIoId|
756 #[trigger] final(s).vm_ios.dom().contains(j)
757 implies final(s).vm_ios[j].owner.inv()
758 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
759 by {
760 assert(old(s).vm_ios.dom().contains(j));
761 assert(final(s).vm_ios[j] == old(s).vm_ios[j]);
762 };
763 };
764}
765
766proof fn new_vm_io_step<'a, 'rcu>(
767 tracked s: &mut VmStore<'rcu>,
768 vs: VmSpaceId,
769 vaddr: Vaddr,
770 len: usize,
771 kind: VmIoKind,
772)
773 requires
774 old(s).inv(),
775 ensures
776 final(s).inv(),
777{
778 if s.vm_spaces.dom().contains(vs) {
779 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
780 let tracked res = match kind {
781 VmIoKind::Reader => vm_space_reader_embedded(vm_space_ref, vaddr, len),
782 VmIoKind::Writer => vm_space_writer_embedded(vm_space_ref, vaddr, len),
783 };
784 match res {
785 Option::Some(owner) => {
786 let ghost id = fresh_vm_io_id(s.vm_ios);
787 axiom_fresh_vm_io_id_not_in_dom(s.vm_ios);
788 let tracked entry = axiom_vm_io_entry_new(vs, kind, owner);
789 s.vm_ios.tracked_insert(id, entry);
790 assert(final(s).inv()) by {
791 assert forall|j: VmSpaceId|
792 #[trigger] final(s).vm_spaces.dom().contains(j)
793 implies final(s).vm_spaces[j].inv()
794 by {
795 assert(old(s).vm_spaces.dom().contains(j));
796 assert(final(s).vm_spaces[j] == old(s).vm_spaces[j]);
797 };
798 assert forall|j: CursorId|
799 #[trigger] final(s).cursors.dom().contains(j)
800 implies final(s).cursors[j].owner.inv()
801 && final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
802 by {
803 assert(old(s).cursors.dom().contains(j));
804 assert(final(s).cursors[j] == old(s).cursors[j]);
805 };
806 assert forall|j: VmIoId|
807 #[trigger] final(s).vm_ios.dom().contains(j)
808 implies final(s).vm_ios[j].owner.inv()
809 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
810 by {
811 if j == id {
812 assert(final(s).vm_ios[j] == entry);
813 } else {
814 assert(old(s).vm_ios.dom().contains(j));
815 }
816 };
817 };
818 },
819 Option::None => {
820 },
822 }
823 }
824}
825
826pub proof fn smoke_test<'a, 'rcu>(tracked s: &mut VmStore<'rcu>)
836 requires
837 old(s).inv(),
838 ensures
839 final(s).inv(),
840{
841 step(s, Op::NewVmSpace);
842 step(s, Op::OpenCursorMut { vs: 0int, va: 0..0 });
843 step(s, Op::Query { c: 0int });
844 step(s, Op::FindNext { c: 0int, len: 0 });
845 step(s, Op::DropCursor { c: 0int });
846 step(s, Op::NewReader { vs: 0int, vaddr: 0, len: 0 });
847 step(s, Op::DropReader { vio: 0int });
848 step(s, Op::DropVmSpace { vs: 0int });
849}
850
851proof fn drop_vm_io_step<'a, 'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId)
852 requires
853 old(s).inv(),
854 ensures
855 final(s).inv(),
856{
857 if s.vm_ios.dom().contains(vio) {
858 let _ = s.vm_ios.tracked_remove(vio);
859 }
860 assert(final(s).inv()) by {
861 assert forall|j: VmSpaceId|
862 #[trigger] final(s).vm_spaces.dom().contains(j)
863 implies final(s).vm_spaces[j].inv()
864 by {
865 assert(old(s).vm_spaces.dom().contains(j));
866 assert(final(s).vm_spaces[j] == old(s).vm_spaces[j]);
867 };
868 assert forall|j: CursorId|
869 #[trigger] final(s).cursors.dom().contains(j)
870 implies final(s).cursors[j].owner.inv()
871 && final(s).vm_spaces.dom().contains(final(s).cursors[j].vm_space)
872 by {
873 assert(old(s).cursors.dom().contains(j));
874 assert(final(s).cursors[j] == old(s).cursors[j]);
875 };
876 assert forall|j: VmIoId|
877 #[trigger] final(s).vm_ios.dom().contains(j)
878 implies final(s).vm_ios[j].owner.inv()
879 && final(s).vm_spaces.dom().contains(final(s).vm_ios[j].vm_space)
880 by {
881 assert(old(s).vm_ios.dom().contains(j));
882 assert(final(s).vm_ios[j] == old(s).vm_ios[j]);
883 };
884 };
885}
886
887}