1pub mod cursor;
152pub mod frame;
153pub mod io;
154pub mod kvirt_store;
155pub mod list_store;
156pub mod segment;
157pub mod trace;
158pub mod unique;
159pub mod vm_space;
160
161use core::ops::Range;
162
163use vstd::prelude::*;
164use vstd_extra::ownership::*;
165use vstd_extra::set_extra::*;
166
167use crate::mm::frame::{
168 MetaSlot, UFrame,
169 meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
170};
171use crate::mm::page_prop::PageProperty;
172use crate::mm::vm_space::UserPtConfig;
173use crate::mm::vm_space::vm_space_specs::VmSpaceOwner;
174use crate::mm::{MAX_USERSPACE_VADDR, Paddr, Vaddr};
175use crate::specs::arch::*;
176use crate::specs::mm::frame::mapping::{frame_to_index, index_to_frame, max_meta_slots};
177use crate::specs::mm::frame::meta_owners::PageUsage;
178use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
179use crate::specs::mm::io::VmIoOwner;
180use crate::specs::mm::page_table::cursor::owners::CursorOwner;
181use crate::specs::mm::page_table::node::Guards;
182use crate::specs::mm::tlb::TlbModel;
183
184verus! {
185
186pub type VmSpaceId = int;
191
192pub type CursorId = int;
194
195pub type VmIoId = int;
197
198pub type FrameId = int;
200
201pub type SegmentId = int;
204
205pub type UniqueId = int;
208
209pub tracked struct FrameEntry {
216 pub paddr: Paddr,
217}
218
219pub tracked struct SegmentEntry {
237 pub range: Range<Paddr>,
238}
239
240pub tracked struct UniqueEntry {
248 pub paddr: Paddr,
249}
250
251pub open spec fn segment_cover_count(segments: Map<SegmentId, SegmentEntry>, paddr: Paddr) -> nat {
261 segments.dom().filter(
262 |sid: SegmentId| segments[sid].range.start <= paddr && paddr < segments[sid].range.end,
263 ).len()
264}
265
266pub proof fn lemma_segment_cover_witness(
271 segments: Map<SegmentId, SegmentEntry>,
272 paddr: Paddr,
273) -> (sid: SegmentId)
274 requires
275 segment_cover_count(segments, paddr) > 0,
276 ensures
277 segments.dom().contains(sid),
278 segments[sid].range.start <= paddr < segments[sid].range.end,
279{
280 let covering = segments.dom().filter(
281 |sid: SegmentId| segments[sid].range.start <= paddr && paddr < segments[sid].range.end,
282 );
283 assert(covering.len() > 0);
284 let sid = covering.choose();
285 assert(covering.contains(sid));
286 sid
287}
288
289pub open spec fn handle_count(frames: Map<FrameId, FrameEntry>, idx: usize) -> nat {
294 frames.dom().filter(|fid: FrameId| frame_to_index(frames[fid].paddr) == idx).len()
295}
296
297pub proof fn lemma_handle_count_insert_fresh(
302 frames: Map<FrameId, FrameEntry>,
303 id: FrameId,
304 entry: FrameEntry,
305 idx: usize,
306)
307 requires
308 !frames.dom().contains(id),
309 ensures
310 handle_count(frames.insert(id, entry), idx) == handle_count(frames, idx) + (
311 if frame_to_index(entry.paddr) == idx {
312 1nat
313 } else {
314 0nat
315 }),
316{
317 let frames2 = frames.insert(id, entry);
318 let new_filt = frames2.dom().filter(|fid: FrameId| frame_to_index(frames2[fid].paddr) == idx);
319 let old_filt = frames.dom().filter(|fid: FrameId| frame_to_index(frames[fid].paddr) == idx);
320 assert(frames2.dom() == frames.dom().insert(id));
321 if frame_to_index(entry.paddr) == idx {
322 assert(new_filt == old_filt.insert(id)) by {
323 assert forall|fid: FrameId| #[trigger] new_filt.contains(fid) implies old_filt.insert(
324 id,
325 ).contains(fid) by {
326 if fid != id {
327 assert(frames2[fid] == frames[fid]);
328 }
329 };
330 assert forall|fid: FrameId| #[trigger]
331 old_filt.insert(id).contains(fid) implies new_filt.contains(fid) by {
332 if fid != id {
333 assert(frames2[fid] == frames[fid]);
334 } else {
335 assert(frames2[id] == entry);
336 }
337 };
338 };
339 assert(!old_filt.contains(id));
340 assert(new_filt.len() == old_filt.len() + 1);
341 } else {
342 assert(new_filt == old_filt) by {
343 assert forall|fid: FrameId| #[trigger] new_filt.contains(fid) implies old_filt.contains(
344 fid,
345 ) by {
346 if fid != id {
347 assert(frames2[fid] == frames[fid]);
348 } else {
349 assert(frames2[id] == entry);
350 }
351 };
352 assert forall|fid: FrameId| #[trigger] old_filt.contains(fid) implies new_filt.contains(
353 fid,
354 ) by {
355 assert(fid != id);
356 assert(frames2[fid] == frames[fid]);
357 };
358 };
359 }
360}
361
362pub proof fn lemma_handle_count_remove(frames: Map<FrameId, FrameEntry>, fid: FrameId, idx: usize)
366 requires
367 frames.dom().contains(fid),
368 ensures
369 handle_count(frames.remove(fid), idx) == handle_count(frames, idx) - (if frame_to_index(
370 frames[fid].paddr,
371 ) == idx {
372 1nat
373 } else {
374 0nat
375 }),
376{
377 let frames2 = frames.remove(fid);
378 let new_filt = frames2.dom().filter(|gid: FrameId| frame_to_index(frames2[gid].paddr) == idx);
379 let old_filt = frames.dom().filter(|gid: FrameId| frame_to_index(frames[gid].paddr) == idx);
380 assert(frames2.dom() == frames.dom().remove(fid));
381 if frame_to_index(frames[fid].paddr) == idx {
382 assert(old_filt.contains(fid));
383 assert(new_filt == old_filt.remove(fid)) by {
384 assert forall|gid: FrameId| #[trigger] new_filt.contains(gid) implies old_filt.remove(
385 fid,
386 ).contains(gid) by {
387 assert(gid != fid);
388 assert(frames2[gid] == frames[gid]);
389 };
390 assert forall|gid: FrameId| #[trigger]
391 old_filt.remove(fid).contains(gid) implies new_filt.contains(gid) by {
392 assert(gid != fid);
393 assert(frames2[gid] == frames[gid]);
394 };
395 };
396 assert(new_filt.len() == (old_filt.len() - 1) as nat);
397 } else {
398 assert(!old_filt.contains(fid));
399 assert(new_filt == old_filt) by {
400 assert forall|gid: FrameId| #[trigger] new_filt.contains(gid) implies old_filt.contains(
401 gid,
402 ) by {
403 assert(gid != fid);
404 assert(frames2[gid] == frames[gid]);
405 };
406 assert forall|gid: FrameId| #[trigger] old_filt.contains(gid) implies new_filt.contains(
407 gid,
408 ) by {
409 assert(gid != fid);
410 assert(frames2[gid] == frames[gid]);
411 };
412 };
413 }
414}
415
416pub proof fn lemma_frame_drop_pre_derivable<'rcu>(s: VmStore<'rcu>, fid: FrameId)
446 requires
447 s.inv(),
448 s.frames.dom().contains(fid),
449 segment_cover_count(s.segments, s.frames[fid].paddr) == 0,
450 ensures
451 frame::drop_pre(s.regions, s.frames[fid].paddr),
452 s.regions.slot_owners[frame_to_index(s.frames[fid].paddr)].inner_perms.ref_count.value()
453 == 1 ==> handle_count(s.frames, frame_to_index(s.frames[fid].paddr)) == 1,
454{
455 let paddr = s.frames[fid].paddr;
456 let idx = frame_to_index(paddr);
457 assert(has_safe_slot(paddr));
459 s.regions.inv_implies_correct_addr(paddr);
460 assert(s.frames.dom().filter(
462 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
463 ).contains(fid));
464 assert(handle_count(s.frames, idx) >= 1);
465 assert(s.regions.slot_owners[idx].usage == PageUsage::Frame);
467 let so = s.regions.slot_owners[idx];
469 let rc = so.inner_perms.ref_count.value();
470 assert(rc != REF_COUNT_UNUSED);
471 assert(rc != REF_COUNT_UNIQUE);
472 assert(rc == handle_count(s.frames, idx) + so.paths_in_pt.len());
473 assert(so.inner_perms.storage.is_init());
474 assert(s.regions.slot_owners.contains_key(idx));
479 assert(so.inner_perms.in_list.value() == 0);
482 if rc == 1 {
484 assert(handle_count(s.frames, idx) + so.paths_in_pt.len() == 1);
485 assert(so.paths_in_pt.len() == 0);
486 assert(so.paths_in_pt == Set::empty());
487 assert(handle_count(s.frames, idx) == 1);
488 }
489}
490
491pub enum VmIoKind {
493 Reader,
494 Writer,
495}
496
497pub tracked struct VmIoEntry {
516 pub vm_space: Option<VmSpaceId>,
517 pub kind: VmIoKind,
518 pub vaddr: Vaddr,
519 pub len: usize,
520 pub owner: VmIoOwner,
521}
522
523impl VmIoEntry {
524 pub open spec fn inv(self) -> bool {
526 &&& self.owner.inv()
527 &&& match self.vm_space {
528 Some(_) => self.owner.mem_view is None,
529 None => match self.kind {
530 VmIoKind::Reader => self.owner.read_view_initialized(),
531 VmIoKind::Writer => self.owner.has_write_view(),
532 },
533 }
534 }
535
536 pub open spec fn is_kernel_reader(self) -> bool {
547 &&& self.vm_space is None
548 &&& self.kind == VmIoKind::Reader
549 }
550
551 pub open spec fn is_kernel_writer(self) -> bool {
552 &&& self.vm_space is None
553 &&& self.kind == VmIoKind::Writer
554 }
555}
556
557pub enum CursorKind {
562 ReadOnly,
563 Mutable,
564}
565
566pub tracked struct CursorEntry<'rcu> {
572 pub vm_space: VmSpaceId,
573 pub kind: CursorKind,
574 pub va: Range<Vaddr>,
575 pub owner: CursorOwner<'rcu, UserPtConfig>,
576 pub guards: Guards<'rcu>,
577}
578
579impl<'rcu> CursorEntry<'rcu> {
580 pub open spec fn inv(self) -> bool {
588 &&& self.owner.inv()
589 &&& self.owner.children_not_locked(self.guards)
590 &&& self.owner.nodes_locked(self.guards)
591 &&& !self.owner.popped_too_high
592 }
593}
594
595pub tracked struct VmStore<'rcu> {
603 pub regions: MetaRegionOwners,
604 pub tlb_model: TlbModel,
605 pub vm_spaces: Map<VmSpaceId, VmSpaceOwner>,
606 pub cursors: Map<CursorId, CursorEntry<'rcu>>,
607 pub vm_ios: Map<VmIoId, VmIoEntry>,
608 pub frames: Map<FrameId, FrameEntry>,
609 pub segments: Map<SegmentId, SegmentEntry>,
610 pub unique_frames: Map<UniqueId, UniqueEntry>,
611}
612
613impl<'a, 'rcu> VmStore<'rcu> {
614 pub open spec fn inv(self) -> bool {
625 self.structural_inv() && self.accounting_inv()
626 }
627
628 pub open spec fn structural_inv(self) -> bool {
634 &&& self.regions.inv()
635 &&& forall|idx: usize|
668 idx < max_meta_slots() ==> #[trigger] self.regions.slots.contains_key(idx) || (
669 self.regions.slot_owners[idx].usage == PageUsage::PageTable
670 && self.regions.slot_owners[idx].inner_perms.ref_count.value()
671 != REF_COUNT_UNUSED)
672 &&& forall|idx: usize|
677 idx < max_meta_slots()
678 ==> #[trigger] self.regions.slot_owners[idx].inner_perms.in_list.value() == 0
679 &&& self.tlb_model.inv()
680 &&& forall|id: VmSpaceId| #[trigger]
681 self.vm_spaces.dom().contains(id) ==> self.vm_spaces[id].inv()
682 &&& forall|id: CursorId| #[trigger]
683 self.cursors.dom().contains(id) ==> self.cursors[id].inv()
684 &&& forall|id: CursorId| #[trigger]
685 self.cursors.dom().contains(id) ==> self.cursors[id].owner.metaregion_sound(
686 self.regions,
687 )
688 &&& forall|id: CursorId| #[trigger]
689 self.cursors.dom().contains(id) ==> self.vm_spaces.dom().contains(
690 self.cursors[id].vm_space,
691 )
692 &&& forall|id: VmIoId| #[trigger] self.vm_ios.dom().contains(id) ==> self.vm_ios[id].inv()
693 &&& forall|id: VmIoId| #[trigger]
694 self.vm_ios.dom().contains(id) ==> (self.vm_ios[id].vm_space matches Some(vs)
695 ==> self.vm_spaces.dom().contains(vs))
696 &&& forall|id: VmIoId| #[trigger]
697 self.vm_ios.dom().contains(id) ==> self.vm_ios[id].vm_space is Some ==> (
698 self.vm_ios[id].vaddr as nat) + (self.vm_ios[id].len as nat)
699 <= MAX_USERSPACE_VADDR as nat
700 &&& forall|fid: FrameId| #[trigger]
710 self.frames.dom().contains(fid) ==> has_safe_slot(
711 self.frames[fid].paddr,
712 )
713 &&& forall|fid: FrameId| #[trigger]
722 self.frames.dom().contains(fid) ==> self.regions.slot_owners[frame_to_index(
723 self.frames[fid].paddr,
724 )].usage
725 == PageUsage::Frame
726 &&& forall|sid: SegmentId| #[trigger]
732 self.segments.dom().contains(sid) ==> {
733 let r = self.segments[sid].range;
734 &&& r.start % PAGE_SIZE == 0
735 &&& r.end % PAGE_SIZE == 0
736 &&& r.start < r.end
737 &&& r.end <= MAX_PADDR
738 }
739 &&& forall|sid: SegmentId, paddr: Paddr|
747 #![trigger
748 self.segments.dom().contains(sid),
749 frame_to_index(paddr)]
750 self.segments.dom().contains(sid) && self.segments[sid].range.start <= paddr
751 < self.segments[sid].range.end && paddr % PAGE_SIZE == 0
752 ==> self.regions.slot_owners[frame_to_index(paddr)].usage
753 == PageUsage::Frame
754 &&& forall|uid: UniqueId| #[trigger]
759 self.unique_frames.dom().contains(uid) ==> has_safe_slot(
760 self.unique_frames[uid].paddr,
761 )
762 &&& forall|uid: UniqueId| #[trigger]
767 self.unique_frames.dom().contains(uid) ==> {
768 let so = self.regions.slot_owners[frame_to_index(self.unique_frames[uid].paddr)];
769 &&& so.usage == PageUsage::Frame
770 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
771 &&& so.inner_perms.in_list.value() == 0
772 &&& so.paths_in_pt.is_empty()
773 }
774 &&& forall|uid1: UniqueId, uid2: UniqueId|
778 #![trigger
779 self.unique_frames.dom().contains(uid1),
780 self.unique_frames.dom().contains(uid2)]
781 self.unique_frames.dom().contains(uid1) && self.unique_frames.dom().contains(uid2)
782 && self.unique_frames[uid1].paddr == self.unique_frames[uid2].paddr ==> uid1 == uid2
783 }
784
785 pub open spec fn accounting_inv(self) -> bool {
815 &&& forall|idx: usize|
854 #![trigger self.regions.slot_owners[idx]]
855 idx < max_meta_slots() && self.regions.slot_owners[idx].inner_perms.ref_count.value()
856 == REF_COUNT_UNUSED ==> handle_count(self.frames, idx) == 0
857 && self.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
858 self.segments,
859 index_to_frame(idx),
860 )
861 == 0
862 &&& forall|idx: usize|
867 #![trigger self.regions.slot_owners[idx]]
868 idx < max_meta_slots() && self.regions.slot_owners[idx].usage == PageUsage::Frame
869 && self.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
870 && self.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE
871 ==> handle_count(self.frames, idx) > 0
872 || self.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
873 self.segments,
874 index_to_frame(idx),
875 )
876 > 0
877 &&& forall|idx: usize|
885 #![trigger self.regions.slot_owners[idx]]
886 idx < max_meta_slots() && self.regions.slot_owners[idx].usage == PageUsage::Frame && (
887 handle_count(self.frames, idx) > 0 || self.regions.slot_owners[idx].paths_in_pt.len()
888 > 0 || segment_cover_count(self.segments, index_to_frame(idx)) > 0) ==> {
889 let so = self.regions.slot_owners[idx];
890 let rc = so.inner_perms.ref_count.value();
891 &&& rc != REF_COUNT_UNUSED
892 &&& rc != REF_COUNT_UNIQUE
893 &&& rc == handle_count(self.frames, idx) + so.paths_in_pt.len()
894 + segment_cover_count(self.segments, index_to_frame(idx))
895 &&& so.inner_perms.storage.is_init()
896 }
897 }
898}
899
900pub enum Op {
906 NewVmSpace,
907 DropVmSpace { vs: VmSpaceId },
908 OpenCursor { vs: VmSpaceId, va: Range<Vaddr> },
909 OpenCursorMut { vs: VmSpaceId, va: Range<Vaddr> },
910 DropCursor { c: CursorId },
911 Query { c: CursorId },
912 FindNext { c: CursorId, len: usize },
913 Jump { c: CursorId, va: Vaddr },
914 VirtAddr { c: CursorId },
915 Map { c: CursorId, fid: FrameId, prop: PageProperty },
916 Unmap { c: CursorId, len: usize },
917 ProtectNext { c: CursorId, len: usize },
918 NewReader { vs: VmSpaceId, vaddr: Vaddr, len: usize },
919 NewWriter { vs: VmSpaceId, vaddr: Vaddr, len: usize },
920 NewKernelReader { vaddr: Vaddr, len: usize },
921 NewKernelWriter { vaddr: Vaddr, len: usize },
922 DropReader { vio: VmIoId },
923 DropWriter { vio: VmIoId },
924 ReaderReadVal { source: VmIoId },
928 ReaderCollect { source: VmIoId },
930 ReaderLimit { vio: VmIoId, max: usize },
931 ReaderSkip { vio: VmIoId, n: usize },
932 ReaderQuery { vio: VmIoId },
933 WriterWriteVal { writer: VmIoId },
935 WriterFillZeros { vio: VmIoId, len: usize },
936 WriterLimit { vio: VmIoId, max: usize },
937 WriterSkip { vio: VmIoId, n: usize },
938 WriterQuery { vio: VmIoId },
939 Read { source: VmIoId, dest: VmIoId },
942 Write { source: VmIoId, dest: VmIoId },
945 FrameFromUnused { paddr: Paddr },
948 FrameFromInUse { paddr: Paddr },
952 FrameDrop { fid: FrameId },
958 SegmentFromUnused { range: Range<Paddr> },
963 SegmentDrop { sid: SegmentId },
967 SegmentSplit { sid: SegmentId, offset: usize },
974 SegmentNext { sid: SegmentId },
983 SegmentClone { sid: SegmentId },
989 SegmentSlice { sid: SegmentId, sub_range: Range<Paddr> },
996 UniqueFromUnused { paddr: Paddr },
1001 UniqueDrop { uid: UniqueId },
1005 FromUnique { uid: UniqueId },
1010 TryFromShared { fid: FrameId },
1016}
1017
1018pub open spec fn op_pre<'rcu>(s: VmStore<'rcu>, op: Op) -> bool {
1036 match op {
1037 Op::NewVmSpace => true,
1038 Op::DropVmSpace { vs } => s.vm_spaces.dom().contains(vs) && (forall|c: CursorId| #[trigger]
1039 s.cursors.dom().contains(c) ==> s.cursors[c].vm_space != vs) && (forall|v: VmIoId|
1040 #[trigger]
1041 s.vm_ios.dom().contains(v) ==> s.vm_ios[v].vm_space != Some(vs)),
1042 Op::OpenCursor { vs, va: _ } => s.vm_spaces.dom().contains(vs),
1043 Op::OpenCursorMut { vs, va: _ } => s.vm_spaces.dom().contains(vs),
1044 Op::DropCursor { c } => s.cursors.dom().contains(c),
1045 Op::Query { c } => s.cursors.dom().contains(c),
1046 Op::FindNext { c, len: _ } => s.cursors.dom().contains(c),
1047 Op::Jump { c, va: _ } => s.cursors.dom().contains(c),
1048 Op::VirtAddr { c } => s.cursors.dom().contains(c),
1049 Op::Map { c, fid, prop: _ } => s.cursors.dom().contains(c) && s.frames.dom().contains(fid),
1062 Op::Unmap { c, len: _ } => s.cursors.dom().contains(c),
1063 Op::ProtectNext { c, len: _ } => s.cursors.dom().contains(c),
1064 Op::NewReader { vs, vaddr: _, len: _ } => s.vm_spaces.dom().contains(vs),
1065 Op::NewWriter { vs, vaddr: _, len: _ } => s.vm_spaces.dom().contains(vs),
1066 Op::NewKernelReader { vaddr: _, len: _ } => true,
1067 Op::NewKernelWriter { vaddr: _, len: _ } => true,
1068 Op::DropReader { vio } => s.vm_ios.dom().contains(vio),
1069 Op::DropWriter { vio } => s.vm_ios.dom().contains(vio),
1070 Op::ReaderReadVal { source } => s.vm_ios.dom().contains(source),
1071 Op::ReaderCollect { source } => s.vm_ios.dom().contains(source),
1072 Op::ReaderLimit { vio, max: _ } => s.vm_ios.dom().contains(vio),
1073 Op::ReaderSkip { vio, n: _ } => s.vm_ios.dom().contains(vio),
1074 Op::ReaderQuery { vio } => s.vm_ios.dom().contains(vio),
1075 Op::WriterWriteVal { writer } => s.vm_ios.dom().contains(writer),
1076 Op::WriterFillZeros { vio, len: _ } => s.vm_ios.dom().contains(vio),
1077 Op::WriterLimit { vio, max: _ } => s.vm_ios.dom().contains(vio),
1078 Op::WriterSkip { vio, n: _ } => s.vm_ios.dom().contains(vio),
1079 Op::WriterQuery { vio } => s.vm_ios.dom().contains(vio),
1080 Op::Read { source, dest } => s.vm_ios.dom().contains(source) && s.vm_ios.dom().contains(
1086 dest,
1087 ) && source != dest && s.vm_ios[source].is_kernel_reader()
1088 && s.vm_ios[dest].is_kernel_writer(),
1089 Op::Write { source, dest } => s.vm_ios.dom().contains(source) && s.vm_ios.dom().contains(
1091 dest,
1092 ) && source != dest && s.vm_ios[source].is_kernel_reader()
1093 && s.vm_ios[dest].is_kernel_writer(),
1094 Op::FrameFromUnused { paddr: _ } => true,
1095 Op::FrameFromInUse { paddr: _ } => true,
1096 Op::FrameDrop { fid } => s.frames.dom().contains(fid) && segment_cover_count(
1113 s.segments,
1114 s.frames[fid].paddr,
1115 ) == 0,
1116 Op::SegmentFromUnused { range: _ } => true,
1123 Op::SegmentDrop { sid } => s.segments.dom().contains(sid),
1129 Op::SegmentSplit { sid, offset } => s.segments.dom().contains(sid) && offset % PAGE_SIZE
1134 == 0 && 0 < offset && offset < (s.segments[sid].range.end
1135 - s.segments[sid].range.start),
1136 Op::SegmentNext { sid } => s.segments.dom().contains(sid),
1139 Op::SegmentClone { sid } => s.segments.dom().contains(sid) && forall|paddr: Paddr|
1140 #![trigger frame_to_index(paddr)]
1141 (s.segments[sid].range.start <= paddr < s.segments[sid].range.end && paddr % PAGE_SIZE
1142 == 0) ==> s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value()
1143 + 1 <= REF_COUNT_MAX,
1144 Op::SegmentSlice { sid, sub_range } => s.segments.dom().contains(sid) && sub_range.start
1150 % PAGE_SIZE == 0 && sub_range.end % PAGE_SIZE == 0 && s.segments[sid].range.start
1151 <= sub_range.start && sub_range.start < sub_range.end && sub_range.end
1152 <= s.segments[sid].range.end && forall|paddr: Paddr|
1153 #![trigger frame_to_index(paddr)]
1154 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0)
1155 ==> s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1
1156 <= REF_COUNT_MAX,
1157 Op::UniqueFromUnused { paddr: _ } => true,
1164 Op::UniqueDrop { uid } => s.unique_frames.dom().contains(uid),
1169 Op::FromUnique { uid } => s.unique_frames.dom().contains(uid),
1172 Op::TryFromShared { fid } => s.frames.dom().contains(fid),
1176 }
1177}
1178
1179impl<'rcu> VmStore<'rcu> {
1184 pub proof fn extract_vm_space(tracked &mut self, vs: VmSpaceId) -> (tracked res: VmSpaceOwner)
1189 requires
1190 old(self).inv(),
1191 old(self).vm_spaces.dom().contains(vs),
1192 forall|c: CursorId| #[trigger]
1193 old(self).cursors.dom().contains(c) ==> old(self).cursors[c].vm_space != vs,
1194 forall|v: VmIoId| #[trigger]
1195 old(self).vm_ios.dom().contains(v) ==> old(self).vm_ios[v].vm_space != Some(vs),
1196 ensures
1197 final(self).regions == old(self).regions,
1198 final(self).tlb_model == old(self).tlb_model,
1199 final(self).vm_spaces == old(self).vm_spaces.remove(vs),
1200 final(self).cursors == old(self).cursors,
1201 final(self).vm_ios == old(self).vm_ios,
1202 final(self).frames == old(self).frames,
1203 final(self).segments == old(self).segments,
1204 final(self).unique_frames == old(self).unique_frames,
1205 res == old(self).vm_spaces[vs],
1206 final(self).inv(),
1207 {
1208 self.vm_spaces.tracked_remove(vs)
1209 }
1210
1211 pub proof fn insert_vm_space(tracked &mut self, vs: VmSpaceId, tracked owner: VmSpaceOwner)
1214 requires
1215 old(self).inv(),
1216 !old(self).vm_spaces.dom().contains(vs),
1217 owner.inv(),
1218 ensures
1219 final(self).regions == old(self).regions,
1220 final(self).tlb_model == old(self).tlb_model,
1221 final(self).vm_spaces == old(self).vm_spaces.insert(vs, owner),
1222 final(self).cursors == old(self).cursors,
1223 final(self).vm_ios == old(self).vm_ios,
1224 final(self).frames == old(self).frames,
1225 final(self).segments == old(self).segments,
1226 final(self).unique_frames == old(self).unique_frames,
1227 final(self).inv(),
1228 {
1229 self.vm_spaces.tracked_insert(vs, owner);
1230 }
1231
1232 pub proof fn extract_cursor(tracked &mut self, c: CursorId) -> (tracked res: CursorEntry<'rcu>)
1234 requires
1235 old(self).inv(),
1236 old(self).cursors.dom().contains(c),
1237 ensures
1238 final(self).regions == old(self).regions,
1239 final(self).tlb_model == old(self).tlb_model,
1240 final(self).vm_spaces == old(self).vm_spaces,
1241 final(self).cursors == old(self).cursors.remove(c),
1242 final(self).vm_ios == old(self).vm_ios,
1243 final(self).frames == old(self).frames,
1244 final(self).segments == old(self).segments,
1245 final(self).unique_frames == old(self).unique_frames,
1246 res == old(self).cursors[c],
1247 final(self).inv(),
1248 {
1249 self.cursors.tracked_remove(c)
1250 }
1251
1252 pub proof fn insert_cursor(tracked &mut self, c: CursorId, tracked entry: CursorEntry<'rcu>)
1257 requires
1258 old(self).inv(),
1259 !old(self).cursors.dom().contains(c),
1260 entry.inv(),
1261 entry.owner.metaregion_sound(old(self).regions),
1262 old(self).vm_spaces.dom().contains(entry.vm_space),
1263 ensures
1264 final(self).regions == old(self).regions,
1265 final(self).tlb_model == old(self).tlb_model,
1266 final(self).vm_spaces == old(self).vm_spaces,
1267 final(self).cursors == old(self).cursors.insert(c, entry),
1268 final(self).vm_ios == old(self).vm_ios,
1269 final(self).frames == old(self).frames,
1270 final(self).segments == old(self).segments,
1271 final(self).unique_frames == old(self).unique_frames,
1272 final(self).inv(),
1273 {
1274 self.cursors.tracked_insert(c, entry);
1275 }
1276
1277 pub proof fn extract_vm_io(tracked &mut self, vio: VmIoId) -> (tracked res: VmIoEntry)
1279 requires
1280 old(self).inv(),
1281 old(self).vm_ios.dom().contains(vio),
1282 ensures
1283 final(self).regions == old(self).regions,
1284 final(self).tlb_model == old(self).tlb_model,
1285 final(self).vm_spaces == old(self).vm_spaces,
1286 final(self).cursors == old(self).cursors,
1287 final(self).vm_ios == old(self).vm_ios.remove(vio),
1288 final(self).frames == old(self).frames,
1289 final(self).segments == old(self).segments,
1290 final(self).unique_frames == old(self).unique_frames,
1291 res == old(self).vm_ios[vio],
1292 final(self).inv(),
1293 {
1294 self.vm_ios.tracked_remove(vio)
1295 }
1296
1297 pub proof fn insert_vm_io(tracked &mut self, vio: VmIoId, tracked entry: VmIoEntry)
1305 requires
1306 old(self).inv(),
1307 !old(self).vm_ios.dom().contains(vio),
1308 entry.inv(),
1309 entry.vm_space matches Some(vs) ==> old(self).vm_spaces.dom().contains(vs),
1310 entry.vm_space is Some ==> (entry.vaddr as nat) + (entry.len as nat)
1311 <= MAX_USERSPACE_VADDR as nat,
1312 ensures
1313 final(self).regions == old(self).regions,
1314 final(self).tlb_model == old(self).tlb_model,
1315 final(self).vm_spaces == old(self).vm_spaces,
1316 final(self).cursors == old(self).cursors,
1317 final(self).vm_ios == old(self).vm_ios.insert(vio, entry),
1318 final(self).frames == old(self).frames,
1319 final(self).segments == old(self).segments,
1320 final(self).unique_frames == old(self).unique_frames,
1321 final(self).inv(),
1322 {
1323 self.vm_ios.tracked_insert(vio, entry);
1324 }
1325
1326 pub proof fn extract_frame(tracked &mut self, fid: FrameId) -> (tracked res: FrameEntry)
1335 requires
1336 old(self).structural_inv(),
1337 old(self).frames.dom().contains(fid),
1338 ensures
1339 final(self).regions == old(self).regions,
1340 final(self).tlb_model == old(self).tlb_model,
1341 final(self).vm_spaces == old(self).vm_spaces,
1342 final(self).cursors == old(self).cursors,
1343 final(self).vm_ios == old(self).vm_ios,
1344 final(self).frames == old(self).frames.remove(fid),
1345 final(self).segments == old(self).segments,
1346 final(self).unique_frames == old(self).unique_frames,
1347 res == old(self).frames[fid],
1348 final(self).structural_inv(),
1349 {
1350 self.frames.tracked_remove(fid)
1351 }
1352
1353 pub proof fn insert_frame(tracked &mut self, fid: FrameId, tracked entry: FrameEntry)
1362 requires
1363 old(self).structural_inv(),
1364 !old(self).frames.dom().contains(fid),
1365 has_safe_slot(entry.paddr),
1366 old(self).regions.slot_owners[frame_to_index(entry.paddr)].usage == PageUsage::Frame,
1371 ensures
1372 final(self).regions == old(self).regions,
1373 final(self).tlb_model == old(self).tlb_model,
1374 final(self).vm_spaces == old(self).vm_spaces,
1375 final(self).cursors == old(self).cursors,
1376 final(self).vm_ios == old(self).vm_ios,
1377 final(self).frames == old(self).frames.insert(fid, entry),
1378 final(self).segments == old(self).segments,
1379 final(self).unique_frames == old(self).unique_frames,
1380 final(self).structural_inv(),
1381 {
1382 self.frames.tracked_insert(fid, entry);
1383 }
1384
1385 pub proof fn extract_unique(tracked &mut self, uid: UniqueId) -> (tracked res: UniqueEntry)
1389 requires
1390 old(self).unique_frames.dom().contains(uid),
1391 ensures
1392 final(self).regions == old(self).regions,
1393 final(self).tlb_model == old(self).tlb_model,
1394 final(self).vm_spaces == old(self).vm_spaces,
1395 final(self).cursors == old(self).cursors,
1396 final(self).vm_ios == old(self).vm_ios,
1397 final(self).frames == old(self).frames,
1398 final(self).segments == old(self).segments,
1399 final(self).unique_frames == old(self).unique_frames.remove(uid),
1400 res == old(self).unique_frames[uid],
1401 {
1402 self.unique_frames.tracked_remove(uid)
1403 }
1404
1405 pub proof fn insert_unique(tracked &mut self, uid: UniqueId, tracked entry: UniqueEntry)
1411 requires
1412 !old(self).unique_frames.dom().contains(uid),
1413 ensures
1414 final(self).regions == old(self).regions,
1415 final(self).tlb_model == old(self).tlb_model,
1416 final(self).vm_spaces == old(self).vm_spaces,
1417 final(self).cursors == old(self).cursors,
1418 final(self).vm_ios == old(self).vm_ios,
1419 final(self).frames == old(self).frames,
1420 final(self).segments == old(self).segments,
1421 final(self).unique_frames == old(self).unique_frames.insert(uid, entry),
1422 {
1423 self.unique_frames.tracked_insert(uid, entry);
1424 }
1425
1426 pub proof fn extract_segment(tracked &mut self, sid: SegmentId) -> (tracked res: SegmentEntry)
1433 requires
1434 old(self).segments.dom().contains(sid),
1435 ensures
1436 final(self).regions == old(self).regions,
1437 final(self).tlb_model == old(self).tlb_model,
1438 final(self).vm_spaces == old(self).vm_spaces,
1439 final(self).cursors == old(self).cursors,
1440 final(self).vm_ios == old(self).vm_ios,
1441 final(self).frames == old(self).frames,
1442 final(self).segments == old(self).segments.remove(sid),
1443 final(self).unique_frames == old(self).unique_frames,
1444 res == old(self).segments[sid],
1445 {
1446 self.segments.tracked_remove(sid)
1447 }
1448
1449 pub proof fn insert_segment(tracked &mut self, sid: SegmentId, tracked entry: SegmentEntry)
1454 requires
1455 !old(self).segments.dom().contains(sid),
1456 ensures
1457 final(self).regions == old(self).regions,
1458 final(self).tlb_model == old(self).tlb_model,
1459 final(self).vm_spaces == old(self).vm_spaces,
1460 final(self).cursors == old(self).cursors,
1461 final(self).vm_ios == old(self).vm_ios,
1462 final(self).frames == old(self).frames,
1463 final(self).segments == old(self).segments.insert(sid, entry),
1464 final(self).unique_frames == old(self).unique_frames,
1465 {
1466 self.segments.tracked_insert(sid, entry);
1467 }
1468}
1469
1470pub proof fn step<'rcu>(tracked s: &mut VmStore<'rcu>, op: Op)
1480 requires
1481 old(s).inv(),
1482 op_pre(*old(s), op),
1483 ensures
1484 final(s).inv(),
1485{
1486 match op {
1487 Op::NewVmSpace => step_new_vm_space(s),
1488 Op::DropVmSpace { vs } => step_drop_vm_space(s, vs),
1489 Op::OpenCursor { vs, va } => step_open_cursor(s, vs, va),
1490 Op::OpenCursorMut { vs, va } => step_open_cursor_mut(s, vs, va),
1491 Op::DropCursor { c } => step_drop_cursor(s, c),
1492 Op::Query { c } => step_query(s, c),
1493 Op::FindNext { c, len } => step_find_next(s, c, len),
1494 Op::Jump { c, va } => step_jump(s, c, va),
1495 Op::VirtAddr { c: _ } => {},
1496 Op::Map { c, fid, prop } => step_map(s, c, fid, prop),
1497 Op::Unmap { c, len } => step_unmap(s, c, len),
1498 Op::ProtectNext { c, len } => step_protect_next(s, c, len),
1499 Op::NewReader { vs, vaddr, len } => step_new_vm_io(s, vs, vaddr, len, VmIoKind::Reader),
1500 Op::NewWriter { vs, vaddr, len } => step_new_vm_io(s, vs, vaddr, len, VmIoKind::Writer),
1501 Op::NewKernelReader { vaddr, len } => step_new_kernel_vm_io(
1502 s,
1503 vaddr,
1504 len,
1505 VmIoKind::Reader,
1506 ),
1507 Op::NewKernelWriter { vaddr, len } => step_new_kernel_vm_io(
1508 s,
1509 vaddr,
1510 len,
1511 VmIoKind::Writer,
1512 ),
1513 Op::DropReader { vio } => step_drop_vm_io(s, vio),
1514 Op::DropWriter { vio } => step_drop_vm_io(s, vio),
1515 Op::ReaderReadVal { source: _ } => {},
1517 Op::ReaderCollect { source: _ } => {},
1518 Op::WriterWriteVal { writer: _ } => {},
1519 Op::ReaderLimit { vio, max } => step_vm_io_method(s, vio, io::VmIoMethod::ReaderLimit(max)),
1520 Op::ReaderSkip { vio, n } => step_vm_io_method(s, vio, io::VmIoMethod::ReaderSkip(n)),
1521 Op::ReaderQuery { vio: _ } => {},
1522 Op::WriterFillZeros { vio, len } => step_vm_io_method(
1523 s,
1524 vio,
1525 io::VmIoMethod::WriterFillZeros(len),
1526 ),
1527 Op::WriterLimit { vio, max } => step_vm_io_method(s, vio, io::VmIoMethod::WriterLimit(max)),
1528 Op::WriterSkip { vio, n } => step_vm_io_method(s, vio, io::VmIoMethod::WriterSkip(n)),
1529 Op::WriterQuery { vio: _ } => {},
1530 Op::Read { source, dest } => step_read(s, source, dest),
1532 Op::Write { source, dest } => step_write(s, source, dest),
1535 Op::FrameFromUnused { paddr } => step_frame_from_unused(s, paddr),
1536 Op::FrameFromInUse { paddr } => step_frame_from_in_use(s, paddr),
1537 Op::FrameDrop { fid } => step_frame_drop(s, fid),
1538 Op::SegmentFromUnused { range } => step_segment_from_unused(s, range),
1539 Op::SegmentDrop { sid } => step_segment_drop(s, sid),
1540 Op::SegmentSplit { sid, offset } => step_segment_split(s, sid, offset),
1541 Op::SegmentNext { sid } => step_segment_next(s, sid),
1542 Op::SegmentClone { sid } => step_segment_clone(s, sid),
1543 Op::SegmentSlice { sid, sub_range } => step_segment_slice(s, sid, sub_range),
1544 Op::UniqueFromUnused { paddr } => step_unique_from_unused(s, paddr),
1545 Op::UniqueDrop { uid } => step_unique_drop(s, uid),
1546 Op::FromUnique { uid } => step_from_unique(s, uid),
1547 Op::TryFromShared { fid } => step_try_from_shared(s, fid),
1548 }
1549}
1550
1551proof fn lemma_accounting_preserved_by_pt_alloc<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1567 requires
1568 s_old.inv(),
1569 s_new.frames == s_old.frames,
1570 s_new.segments == s_old.segments,
1572 forall|i: usize|
1573 #![trigger s_new.regions.slot_owners[i]]
1574 s_new.regions.slot_owners[i] != s_old.regions.slot_owners[i] ==> {
1575 &&& s_old.regions.slot_owners[i].inner_perms.ref_count.value() == REF_COUNT_UNUSED
1576 &&& s_new.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1577 &&& s_new.regions.slot_owners[i].usage != PageUsage::Frame
1578 },
1579 ensures
1580 s_new.accounting_inv(),
1581 forall|fid: FrameId| #[trigger]
1586 s_new.frames.dom().contains(fid) ==> s_new.regions.slot_owners[frame_to_index(
1587 s_new.frames[fid].paddr,
1588 )].usage == PageUsage::Frame,
1589 forall|sid: SegmentId, paddr: Paddr|
1591 #![trigger
1592 s_new.segments.dom().contains(sid),
1593 frame_to_index(paddr)]
1594 s_new.segments.dom().contains(sid) && s_new.segments[sid].range.start <= paddr
1595 < s_new.segments[sid].range.end && paddr % PAGE_SIZE == 0
1596 ==> s_new.regions.slot_owners[frame_to_index(paddr)].usage == PageUsage::Frame,
1597{
1598 assert forall|idx: usize|
1601 #![trigger s_new.regions.slot_owners[idx]]
1602 idx < max_meta_slots() && s_new.regions.slot_owners[idx].inner_perms.ref_count.value()
1603 == REF_COUNT_UNUSED implies handle_count(s_new.frames, idx) == 0
1604 && s_new.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1605 s_new.segments,
1606 index_to_frame(idx),
1607 ) == 0 by {
1608 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1609 };
1610 assert forall|idx: usize|
1613 #![trigger s_new.regions.slot_owners[idx]]
1614 idx < max_meta_slots() && s_new.regions.slot_owners[idx].usage == PageUsage::Frame
1615 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1616 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value()
1617 != REF_COUNT_UNIQUE implies handle_count(s_new.frames, idx) > 0
1618 || s_new.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1619 s_new.segments,
1620 index_to_frame(idx),
1621 ) > 0 by {
1622 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1623 };
1624 assert forall|idx: usize|
1627 #![trigger s_new.regions.slot_owners[idx]]
1628 idx < max_meta_slots() && s_new.regions.slot_owners[idx].usage == PageUsage::Frame && (
1629 handle_count(s_new.frames, idx) > 0 || s_new.regions.slot_owners[idx].paths_in_pt.len() > 0
1630 || segment_cover_count(s_new.segments, index_to_frame(idx)) > 0) implies {
1631 let so = s_new.regions.slot_owners[idx];
1632 let rc = so.inner_perms.ref_count.value();
1633 &&& rc != REF_COUNT_UNUSED
1634 &&& rc != REF_COUNT_UNIQUE
1635 &&& rc == handle_count(s_new.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1636 s_new.segments,
1637 index_to_frame(idx),
1638 )
1639 &&& so.inner_perms.storage.is_init()
1640 } by {
1641 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1642 };
1643 assert forall|sid: SegmentId, paddr: Paddr|
1648 #![trigger
1649 s_new.segments.dom().contains(sid),
1650 frame_to_index(paddr)]
1651 s_new.segments.dom().contains(sid) && s_new.segments[sid].range.start <= paddr
1652 < s_new.segments[sid].range.end && paddr % PAGE_SIZE
1653 == 0 implies s_new.regions.slot_owners[frame_to_index(paddr)].usage
1654 == PageUsage::Frame by {
1655 let idx = frame_to_index(paddr);
1656 assert(s_old.regions.slot_owners[idx].usage == PageUsage::Frame);
1658 lemma_segment_cover_contains(s_old.segments, sid, paddr);
1661 assert(s_old.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
1662 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1664 };
1665 assert forall|fid: FrameId| #[trigger]
1671 s_new.frames.dom().contains(fid) implies s_new.regions.slot_owners[frame_to_index(
1672 s_new.frames[fid].paddr,
1673 )].usage == PageUsage::Frame by {
1674 let idx = frame_to_index(s_new.frames[fid].paddr);
1675 assert(s_old.frames.dom().filter(
1677 |gid: FrameId| frame_to_index(s_old.frames[gid].paddr) == idx,
1678 ).contains(fid));
1679 assert(handle_count(s_old.frames, idx) >= 1);
1680 assert(s_old.regions.slot_owners[idx].usage == PageUsage::Frame);
1682 assert(s_old.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
1683 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1686 };
1687}
1688
1689proof fn lemma_coverage_preserved_slots_eq<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1697 requires
1698 s_old.structural_inv(),
1699 s_new.regions.slots == s_old.regions.slots,
1700 forall|idx: usize|
1701 #![trigger s_new.regions.slot_owners[idx]]
1702 !s_old.regions.slots.contains_key(idx) ==> s_new.regions.slot_owners[idx]
1703 == s_old.regions.slot_owners[idx],
1704 ensures
1705 forall|idx: usize|
1706 idx < max_meta_slots() ==> #[trigger] s_new.regions.slots.contains_key(idx) || (
1707 s_new.regions.slot_owners[idx].usage == PageUsage::PageTable
1708 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value()
1709 != REF_COUNT_UNUSED),
1710{
1711 assert forall|idx: usize|
1712 idx < max_meta_slots() implies #[trigger] s_new.regions.slots.contains_key(idx) || (
1713 s_new.regions.slot_owners[idx].usage == PageUsage::PageTable
1714 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED) by {
1715 if !s_new.regions.slots.contains_key(idx) {
1716 assert(!s_old.regions.slots.contains_key(idx));
1719 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1720 }
1721 };
1722}
1723
1724proof fn step_new_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>)
1725 requires
1726 old(s).inv(),
1727 ensures
1728 final(s).inv(),
1729{
1730 let ghost s_before = *s;
1731 let tracked owner = vm_space::new_vm_space_step(&mut s.regions);
1732 let ghost id = fresh_vm_space_id(s.vm_spaces);
1733 lemma_fresh_vm_space_id_not_in_dom(s.vm_spaces);
1734 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1737 let ghost root_idx = vm_space::vm_space_root_idx(owner);
1743 assert forall|idx: usize|
1744 idx < max_meta_slots() implies #[trigger] s.regions.slots.contains_key(idx) || (
1745 s.regions.slot_owners[idx].usage == PageUsage::PageTable
1746 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED) by {
1747 if idx == root_idx {
1748 } else {
1750 assert(s.regions.slots.contains_key(idx) == s_before.regions.slots.contains_key(idx));
1753 if s.regions.slot_owners[idx] != s_before.regions.slot_owners[idx] {
1754 assert(s_before.regions.slot_owners[idx].inner_perms.ref_count.value()
1758 == REF_COUNT_UNUSED);
1759 assert(s_before.regions.slots.contains_key(idx));
1760 }
1761 }
1762 };
1763 s.insert_vm_space(id, owner);
1764}
1765
1766proof fn step_drop_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId)
1767 requires
1768 old(s).inv(),
1769 old(s).vm_spaces.dom().contains(vs),
1770 forall|c: CursorId| #[trigger]
1771 old(s).cursors.dom().contains(c) ==> old(s).cursors[c].vm_space != vs,
1772 forall|v: VmIoId| #[trigger]
1773 old(s).vm_ios.dom().contains(v) ==> old(s).vm_ios[v].vm_space != Some(vs),
1774 ensures
1775 final(s).inv(),
1776{
1777 let tracked owner = s.extract_vm_space(vs);
1778 vm_space::drop_vm_space_step(owner);
1779}
1780
1781proof fn step_open_cursor<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId, va: Range<Vaddr>)
1782 requires
1783 old(s).inv(),
1784 old(s).vm_spaces.dom().contains(vs),
1785 ensures
1786 final(s).inv(),
1787{
1788 let ghost s_before = *s;
1789 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1790 let tracked res = cursor::open_cursor_step(vm_space_ref, &mut s.regions, vs, va);
1791 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1794 match res {
1795 Option::Some(entry) => {
1796 let ghost id = fresh_cursor_id(s.cursors);
1797 lemma_fresh_cursor_id_not_in_dom(s.cursors);
1798 s.insert_cursor(id, entry);
1799 },
1800 Option::None => {},
1801 }
1802}
1803
1804proof fn step_open_cursor_mut<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId, va: Range<Vaddr>)
1805 requires
1806 old(s).inv(),
1807 old(s).vm_spaces.dom().contains(vs),
1808 ensures
1809 final(s).inv(),
1810{
1811 let ghost s_before = *s;
1812 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1813 let tracked res = cursor::open_cursor_mut_step(vm_space_ref, &mut s.regions, vs, va);
1814 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1817 match res {
1818 Option::Some(entry) => {
1819 let ghost id = fresh_cursor_id(s.cursors);
1820 lemma_fresh_cursor_id_not_in_dom(s.cursors);
1821 s.insert_cursor(id, entry);
1822 },
1823 Option::None => {},
1824 }
1825}
1826
1827proof fn step_drop_cursor<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1828 requires
1829 old(s).inv(),
1830 old(s).cursors.dom().contains(c),
1831 ensures
1832 final(s).inv(),
1833{
1834 let tracked entry = s.extract_cursor(c);
1835 cursor::drop_cursor_step(entry);
1836}
1837
1838proof fn step_query<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1839 requires
1840 old(s).inv(),
1841 old(s).cursors.dom().contains(c),
1842 ensures
1843 final(s).inv(),
1844{
1845 let ghost old_frames = s.frames;
1846 let ghost old_regions = s.regions;
1847 let tracked mut entry = s.extract_cursor(c);
1848 let ghost res = cursor::cursor_query_step(&mut entry, &mut s.regions);
1849 match res {
1850 Option::None => {
1851 s.insert_cursor(c, entry);
1854 },
1855 Option::Some(paddr) => {
1856 let ghost target_idx = frame_to_index(paddr);
1861 s.regions.inv_implies_correct_addr(paddr);
1862 let ghost id = fresh_frame_id(s.frames);
1863 lemma_fresh_frame_id_not_in_dom(s.frames);
1864 let tracked frame_entry = axiom_frame_entry_new(paddr);
1865 s.insert_frame(id, frame_entry);
1866 assert(s.regions.slot_owners[target_idx].usage == PageUsage::Frame);
1874 assert forall|idx: usize|
1876 #![trigger s.regions.slot_owners[idx]]
1877 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
1878 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1879 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1880 s.segments,
1881 index_to_frame(idx),
1882 ) == 0 by {
1883 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1884 if idx == target_idx {
1885 assert(false);
1888 } else {
1889 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1894 }
1895 };
1896 assert forall|idx: usize|
1897 #![trigger s.regions.slot_owners[idx]]
1898 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
1899 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1900 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
1901 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1902 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1903 s.segments,
1904 index_to_frame(idx),
1905 ) > 0 by {
1906 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1907 if idx == target_idx {
1908 assert(handle_count(s.frames, target_idx) >= 1);
1910 } else {
1911 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1912 }
1913 };
1914 assert forall|idx: usize|
1915 #![trigger s.regions.slot_owners[idx]]
1916 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
1917 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
1918 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
1919 let so = s.regions.slot_owners[idx];
1920 let rc = so.inner_perms.ref_count.value();
1921 &&& rc != REF_COUNT_UNUSED
1922 &&& rc != REF_COUNT_UNIQUE
1923 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1924 s.segments,
1925 index_to_frame(idx),
1926 )
1927 &&& so.inner_perms.storage.is_init()
1928 } by {
1929 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1930 if idx == target_idx {
1931 if old_regions.slot_owners[target_idx].inner_perms.ref_count.value()
1932 == REF_COUNT_UNUSED {
1933 assert(REF_COUNT_UNUSED == 0u32);
1938 assert(s.regions.slot_owners[target_idx].inner_perms.ref_count.value()
1939 == 1);
1940 assert(handle_count(s.frames, target_idx) == 1);
1941 assert(s.regions.slot_owners[target_idx].paths_in_pt.len()
1942 == old_regions.slot_owners[target_idx].paths_in_pt.len());
1943 assert(old_regions.slot_owners[target_idx].paths_in_pt.len() == 0);
1944 assert(segment_cover_count(s.segments, index_to_frame(target_idx)) == 0);
1945 } else if old_regions.slot_owners[target_idx].inner_perms.ref_count.value()
1946 == REF_COUNT_UNIQUE {
1947 assert(false);
1948 } else {
1949 let pre_so = old_regions.slot_owners[target_idx];
1952 let pre_rc = pre_so.inner_perms.ref_count.value();
1953 let pre_paths = pre_so.paths_in_pt.len();
1954 let pre_H = handle_count(old_frames, target_idx);
1955 let pre_cover = segment_cover_count(s.segments, index_to_frame(target_idx));
1956 if pre_H == 0 && pre_paths == 0 && pre_cover == 0 {
1957 assert(false);
1958 } else {
1959 assert(pre_rc == pre_H + pre_paths + pre_cover);
1963 assert(handle_count(s.frames, target_idx) == pre_H + 1);
1964 }
1965 }
1966 } else {
1967 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1968 }
1969 };
1970 s.insert_cursor(c, entry);
1971 },
1972 }
1973}
1974
1975proof fn step_find_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1976 requires
1977 old(s).inv(),
1978 old(s).cursors.dom().contains(c),
1979 ensures
1980 final(s).inv(),
1981{
1982 let tracked mut entry = s.extract_cursor(c);
1983 cursor::cursor_find_next_step(&mut entry, &mut s.regions, len);
1984 s.insert_cursor(c, entry);
1985}
1986
1987proof fn step_jump<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, va: Vaddr)
1988 requires
1989 old(s).inv(),
1990 old(s).cursors.dom().contains(c),
1991 ensures
1992 final(s).inv(),
1993{
1994 let tracked mut entry = s.extract_cursor(c);
1995 cursor::cursor_jump_step(&mut entry, &mut s.regions, va);
1996 s.insert_cursor(c, entry);
1997}
1998
1999proof fn step_protect_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
2000 requires
2001 old(s).inv(),
2002 old(s).cursors.dom().contains(c),
2003 ensures
2004 final(s).inv(),
2005{
2006 let tracked mut entry = s.extract_cursor(c);
2007 cursor::cursor_protect_next_step(&mut entry, &mut s.regions, len);
2008 s.insert_cursor(c, entry);
2009}
2010
2011proof fn step_map<'rcu>(
2012 tracked s: &mut VmStore<'rcu>,
2013 c: CursorId,
2014 fid: FrameId,
2015 prop: PageProperty,
2016)
2017 requires
2018 old(s).inv(),
2019 old(s).cursors.dom().contains(c),
2020 old(s).frames.dom().contains(fid),
2021 ensures
2022 final(s).inv(),
2023{
2024 assert(s.regions.slot_owners[frame_to_index(s.frames[fid].paddr)].usage == PageUsage::Frame);
2027 let ghost paddr = s.frames[fid].paddr;
2028 let ghost target_idx = frame_to_index(paddr);
2029 let ghost old_frames = s.frames;
2030 let ghost old_regions = s.regions;
2031 assert(has_safe_slot(paddr));
2033 s.regions.inv_implies_correct_addr(paddr);
2034 assert(old_frames.dom().filter(
2037 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == target_idx,
2038 ).contains(fid));
2039 assert(handle_count(old_frames, target_idx) >= 1);
2040 let ghost pre_rc_target = old_regions.slot_owners[target_idx].inner_perms.ref_count.value();
2043 let ghost pre_paths_target = old_regions.slot_owners[target_idx].paths_in_pt.len();
2044 let ghost pre_cover_target = segment_cover_count(s.segments, index_to_frame(target_idx));
2045 assert(pre_rc_target != REF_COUNT_UNUSED);
2046 assert(pre_rc_target != REF_COUNT_UNIQUE);
2047 assert(pre_rc_target == handle_count(old_frames, target_idx) + pre_paths_target
2048 + pre_cover_target);
2049 assert(old_regions.slot_owners[target_idx].inner_perms.storage.is_init());
2050 let tracked mut entry = s.extract_cursor(c);
2051 let tracked _frame_entry = s.extract_frame(fid);
2055 cursor::map_step(&mut entry, &mut s.regions, &mut s.tlb_model, paddr, prop);
2056 assert forall|idx: usize|
2062 #![trigger s.regions.slot_owners[idx]]
2063 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2064 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2065 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2066 s.segments,
2067 index_to_frame(idx),
2068 ) == 0 by {
2069 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2071 lemma_handle_count_remove(old_frames, fid, idx);
2072 if idx == target_idx {
2073 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == pre_rc_target);
2076 assert(false);
2077 }
2078 };
2079 assert forall|idx: usize|
2080 #![trigger s.regions.slot_owners[idx]]
2081 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2082 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2083 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2084 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2085 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2086 s.segments,
2087 index_to_frame(idx),
2088 ) > 0 by {
2089 lemma_handle_count_remove(old_frames, fid, idx);
2090 if idx == target_idx {
2091 assert(s.regions.slot_owners[idx].paths_in_pt.len() == pre_paths_target + 1);
2093 } else if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
2094 assert(s.regions.slot_owners[idx].usage != PageUsage::Frame);
2096 } else {
2097 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2100 }
2101 };
2102 assert forall|idx: usize|
2103 #![trigger s.regions.slot_owners[idx]]
2104 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
2105 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
2106 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2107 let so = s.regions.slot_owners[idx];
2108 let rc = so.inner_perms.ref_count.value();
2109 &&& rc != REF_COUNT_UNUSED
2110 &&& rc != REF_COUNT_UNIQUE
2111 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2112 s.segments,
2113 index_to_frame(idx),
2114 )
2115 &&& so.inner_perms.storage.is_init()
2116 } by {
2117 lemma_handle_count_remove(old_frames, fid, idx);
2118 if idx == target_idx {
2119 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == pre_rc_target);
2125 assert(s.regions.slot_owners[idx].paths_in_pt.len() == pre_paths_target + 1);
2126 assert(handle_count(s.frames, idx) == (handle_count(old_frames, idx) - 1) as nat);
2127 } else if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
2128 assert(s.regions.slot_owners[idx].usage != PageUsage::Frame);
2129 } else {
2130 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2131 }
2132 };
2133 assert forall|fid_other: FrameId| #[trigger]
2139 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
2140 s.frames[fid_other].paddr,
2141 )].usage == PageUsage::Frame by {
2142 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2143 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
2145 if other_idx == target_idx {
2146 assert(s.regions.slot_owners[target_idx].usage
2148 == old_regions.slot_owners[target_idx].usage);
2149 } else {
2150 assert(old_frames.dom().filter(
2157 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
2158 ).contains(fid_other));
2159 assert(handle_count(old_frames, other_idx) >= 1);
2160 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value()
2161 != REF_COUNT_UNUSED);
2162 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
2163 }
2164 };
2165 assert forall|sid: SegmentId, paddr_c: Paddr|
2170 #![trigger
2171 s.segments.dom().contains(sid),
2172 frame_to_index(paddr_c)]
2173 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
2174 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
2175 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
2176 == PageUsage::Frame by {
2177 let cov_idx = frame_to_index(paddr_c);
2178 lemma_segment_cover_contains(old_regions_segments_helper(s), sid, paddr_c);
2180 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
2181 assert(old_regions.slot_owners[cov_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
2182 if cov_idx == target_idx {
2183 assert(s.regions.slot_owners[target_idx].usage
2185 == old_regions.slot_owners[target_idx].usage);
2186 } else {
2187 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
2189 }
2190 };
2191 s.insert_cursor(c, entry);
2192}
2193
2194spec fn old_regions_segments_helper<'rcu>(s: &VmStore<'rcu>) -> Map<SegmentId, SegmentEntry> {
2198 s.segments
2199}
2200
2201proof fn step_unmap<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
2202 requires
2203 old(s).inv(),
2204 old(s).cursors.dom().contains(c),
2205 ensures
2206 final(s).inv(),
2207{
2208 let ghost s_before = *s;
2209 let ghost old_regions = s.regions;
2210 let ghost old_frames = s.frames;
2211 let tracked mut entry = s.extract_cursor(c);
2212 cursor::cursor_mut_regions_step(
2213 &mut entry,
2214 &mut s.regions,
2215 &mut s.tlb_model,
2216 cursor::CursorMutRegionsMethod::Unmap(len),
2217 );
2218 lemma_coverage_preserved_slots_eq(s_before, *s);
2221 assert forall|idx: usize|
2227 #![trigger s.regions.slot_owners[idx]]
2228 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2229 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2230 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2231 s.segments,
2232 index_to_frame(idx),
2233 ) == 0 by {
2234 assert(s.regions.slot_owners.contains_key(idx));
2238 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0) by {
2247 if segment_cover_count(old(s).segments, index_to_frame(idx)) > 0 {
2248 let pa = index_to_frame(idx);
2249 let sid = lemma_segment_cover_witness(old(s).segments, pa);
2250 assert(pa == (idx * PAGE_SIZE) as usize);
2254 assert(pa % PAGE_SIZE == 0);
2255 assert(frame_to_index(pa) == idx);
2256 assert(old_regions.slot_owners[idx].usage == PageUsage::Frame);
2258 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
2260 != REF_COUNT_UNUSED);
2261 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX);
2262 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX);
2264 }
2265 };
2266 if old_regions.slot_owners[idx].usage == PageUsage::Frame {
2268 assert(s.regions.slot_owners[idx].usage != PageUsage::MMIO);
2271 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
2272 } else if old_regions.slot_owners[idx].usage == PageUsage::MMIO {
2279 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2282 } else {
2283 assert(s.regions.slot_owners[idx].usage != PageUsage::MMIO);
2286 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
2287 assert(handle_count(s.frames, idx) == 0) by {
2288 let filt = s.frames.dom().filter(
2289 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
2290 );
2291 assert forall|fid: FrameId| #[trigger] filt.contains(fid) implies false by {
2292 assert(s.frames.dom().contains(fid));
2296 assert(frame_to_index(s.frames[fid].paddr) == idx);
2297 assert(s.regions.slot_owners[idx].usage == PageUsage::Frame);
2298 };
2299 assert(filt == Set::empty());
2300 };
2301 }
2302 };
2303 assert forall|idx: usize|
2304 #![trigger s.regions.slot_owners[idx]]
2305 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2306 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2307 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2308 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2309 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2310 s.segments,
2311 index_to_frame(idx),
2312 ) > 0 by {
2313 assert(s.regions.slot_owners.contains_key(idx));
2322 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED) by {
2323 if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
2324 assert(old_regions.slot_owners.contains_key(idx));
2326 assert(old_regions.slot_owners[idx].paths_in_pt == Set::empty());
2327 assert(s.regions.slot_owners[idx].paths_in_pt.len() == 0);
2333 assert(false);
2334 }
2335 };
2336 if handle_count(old_frames, idx) > 0 {
2339 assert(handle_count(s.frames, idx) > 0);
2340 } else if segment_cover_count(s.segments, index_to_frame(idx)) > 0 {
2341 } else {
2343 assert(s.regions.slot_owners[idx].paths_in_pt.len() > 0);
2349 }
2350 };
2351 assert forall|idx: usize|
2352 #![trigger s.regions.slot_owners[idx]]
2353 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
2354 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
2355 > 0) implies {
2356 let so = s.regions.slot_owners[idx];
2357 let rc = so.inner_perms.ref_count.value();
2358 &&& rc != REF_COUNT_UNUSED
2359 &&& rc != REF_COUNT_UNIQUE
2360 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2361 s.segments,
2362 index_to_frame(idx),
2363 )
2364 &&& so.inner_perms.storage.is_init()
2365 } by {
2366 if handle_count(s.frames, idx) > 0 {
2373 assert(handle_count(old_frames, idx) > 0);
2375 } else {
2376 assert(old_regions.slot_owners[idx].paths_in_pt.len() > 0);
2385 }
2386 };
2398 assert forall|fid_other: FrameId| #[trigger]
2401 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
2402 s.frames[fid_other].paddr,
2403 )].usage == PageUsage::Frame by {
2404 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2405 assert(s.regions.slot_owners[other_idx].usage == old_regions.slot_owners[other_idx].usage);
2406 };
2407 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
2414 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
2415 &&& so.usage == PageUsage::Frame
2416 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
2417 &&& so.inner_perms.in_list.value() == 0
2418 &&& so.paths_in_pt.is_empty()
2419 } by {
2420 let u_idx = frame_to_index(s.unique_frames[u].paddr);
2421 assert(old(s).unique_frames.dom().contains(u));
2422 assert(old_regions.slot_owners[u_idx].usage == PageUsage::Frame);
2424 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
2425 assert(old_regions.slot_owners[u_idx].paths_in_pt.is_empty());
2426 assert(old_regions.slot_owners[u_idx].inner_perms.in_list.value() == 0);
2427 assert(has_safe_slot(s.unique_frames[u].paddr));
2429 s.regions.inv_implies_correct_addr(s.unique_frames[u].paddr);
2430 assert(s.regions.slot_owners.contains_key(u_idx));
2431 assert(s.regions.slot_owners[u_idx].usage == old_regions.slot_owners[u_idx].usage);
2433 assert(s.regions.slot_owners[u_idx].inner_perms.in_list
2434 == old_regions.slot_owners[u_idx].inner_perms.in_list);
2435 assert(s.regions.slot_owners[u_idx].paths_in_pt.len()
2438 <= old_regions.slot_owners[u_idx].paths_in_pt.len());
2439 assert(old_regions.slot_owners[u_idx].paths_in_pt.len() == 0);
2440 assert(s.regions.slot_owners[u_idx].paths_in_pt =~= Set::empty());
2441 assert(s.regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
2442 };
2443 s.insert_cursor(c, entry);
2444}
2445
2446proof fn step_new_vm_io<'rcu>(
2447 tracked s: &mut VmStore<'rcu>,
2448 vs: VmSpaceId,
2449 vaddr: Vaddr,
2450 len: usize,
2451 kind: VmIoKind,
2452)
2453 requires
2454 old(s).inv(),
2455 old(s).vm_spaces.dom().contains(vs),
2456 ensures
2457 final(s).inv(),
2458{
2459 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
2460 let tracked res = io::new_vm_io_step(vm_space_ref, Some(vs), vaddr, len, kind);
2461 match res {
2462 Option::Some(entry) => {
2463 let ghost id = fresh_vm_io_id(s.vm_ios);
2464 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2465 s.insert_vm_io(id, entry);
2466 },
2467 Option::None => {},
2468 }
2469}
2470
2471proof fn step_new_kernel_vm_io<'rcu>(
2472 tracked s: &mut VmStore<'rcu>,
2473 vaddr: Vaddr,
2474 len: usize,
2475 kind: VmIoKind,
2476)
2477 requires
2478 old(s).inv(),
2479 ensures
2480 final(s).inv(),
2481{
2482 let tracked entry = io::new_kernel_vm_io_step(vaddr, len, kind);
2483 let ghost id = fresh_vm_io_id(s.vm_ios);
2484 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2485 s.insert_vm_io(id, entry);
2486}
2487
2488proof fn step_drop_vm_io<'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId)
2489 requires
2490 old(s).inv(),
2491 old(s).vm_ios.dom().contains(vio),
2492 ensures
2493 final(s).inv(),
2494{
2495 let tracked entry = s.extract_vm_io(vio);
2496 io::drop_vm_io_step(entry);
2497}
2498
2499proof fn step_vm_io_method<'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId, method: io::VmIoMethod)
2500 requires
2501 old(s).inv(),
2502 old(s).vm_ios.dom().contains(vio),
2503 ensures
2504 final(s).inv(),
2505{
2506 let tracked mut entry = s.extract_vm_io(vio);
2507 io::vm_io_method_step(&mut entry, method);
2508 s.insert_vm_io(vio, entry);
2509}
2510
2511proof fn step_read<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
2512 requires
2513 old(s).inv(),
2514 old(s).vm_ios.dom().contains(source),
2515 old(s).vm_ios.dom().contains(dest),
2516 source != dest,
2517 old(s).vm_ios[source].vm_space is None,
2518 old(s).vm_ios[source].kind == VmIoKind::Reader,
2519 old(s).vm_ios[dest].vm_space is None,
2520 old(s).vm_ios[dest].kind == VmIoKind::Writer,
2521 ensures
2522 final(s).inv(),
2523{
2524 let tracked mut src = s.extract_vm_io(source);
2525 let tracked mut dst = s.extract_vm_io(dest);
2526 let tracked val = io::read_step(&mut src, &mut dst);
2527 s.insert_vm_io(source, src);
2528 s.insert_vm_io(dest, dst);
2529 let ghost id = fresh_vm_io_id(s.vm_ios);
2530 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2531 s.insert_vm_io(id, val);
2532}
2533
2534proof fn step_write<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
2535 requires
2536 old(s).inv(),
2537 old(s).vm_ios.dom().contains(source),
2538 old(s).vm_ios.dom().contains(dest),
2539 source != dest,
2540 old(s).vm_ios[source].vm_space is None,
2541 old(s).vm_ios[source].kind == VmIoKind::Reader,
2542 old(s).vm_ios[dest].vm_space is None,
2543 old(s).vm_ios[dest].kind == VmIoKind::Writer,
2544 ensures
2545 final(s).inv(),
2546{
2547 let tracked mut src = s.extract_vm_io(source);
2548 let tracked mut dst = s.extract_vm_io(dest);
2549 io::write_step(&mut src, &mut dst);
2550 s.insert_vm_io(source, src);
2551 s.insert_vm_io(dest, dst);
2552}
2553
2554proof fn step_frame_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2555 requires
2556 old(s).inv(),
2557 ensures
2558 final(s).inv(),
2559{
2560 let ghost old_frames = s.frames;
2567 let ghost old_regions = s.regions;
2568 if !has_safe_slot(paddr) || s.regions.slots.contains_key(frame_to_index(paddr)) {
2569 let tracked res = frame::from_unused_step(&mut s.regions, paddr);
2570 match res {
2571 Option::Some(entry) => {
2572 let ghost id = fresh_frame_id(s.frames);
2573 lemma_fresh_frame_id_not_in_dom(s.frames);
2574 let ghost target_idx = frame_to_index(paddr);
2575 let ghost entry_paddr = entry.paddr;
2576 s.insert_frame(id, entry);
2577 assert(s.frames[id].paddr == paddr);
2578
2579 assert(handle_count(old_frames, target_idx) == 0);
2582 assert(old_regions.slot_owners[target_idx].paths_in_pt.is_empty());
2583
2584 assert forall|idx: usize|
2587 #![trigger s.regions.slot_owners[idx]]
2588 idx < max_meta_slots()
2589 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2590 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2591 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
2592 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2593 if idx == target_idx {
2594 assert(false);
2596 } else {
2597 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2598 }
2599 };
2600
2601 assert forall|idx: usize|
2605 #![trigger s.regions.slot_owners[idx]]
2606 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2607 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2608 != REF_COUNT_UNUSED
2609 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2610 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2611 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2612 s.segments,
2613 index_to_frame(idx),
2614 ) > 0 by {
2615 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2616 if idx == target_idx {
2617 assert(handle_count(s.frames, idx) == 1);
2618 } else {
2619 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2620 }
2621 };
2622
2623 assert forall|idx: usize|
2625 #![trigger s.regions.slot_owners[idx]]
2626 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2627 && (handle_count(s.frames, idx) > 0
2628 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2629 s.segments,
2630 index_to_frame(idx),
2631 ) > 0) implies {
2632 let so = s.regions.slot_owners[idx];
2633 let rc = so.inner_perms.ref_count.value();
2634 &&& rc != REF_COUNT_UNUSED
2635 &&& rc != REF_COUNT_UNIQUE
2636 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
2637 + segment_cover_count(s.segments, index_to_frame(idx))
2638 &&& so.inner_perms.storage.is_init()
2639 } by {
2640 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2641 if idx == target_idx {
2642 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
2643 == REF_COUNT_UNUSED);
2644 assert(handle_count(old_frames, idx) == 0);
2645 assert(handle_count(s.frames, idx) == 1);
2646 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
2649 } else {
2650 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2653 }
2654 };
2655 },
2656 Option::None => {
2657 assert(s.regions == old_regions);
2659 },
2660 }
2661 }
2662}
2663
2664proof fn step_frame_from_in_use<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2665 requires
2666 old(s).inv(),
2667 ensures
2668 final(s).inv(),
2669{
2670 let ghost old_frames = s.frames;
2675 let ghost old_regions = s.regions;
2676 if !has_safe_slot(paddr) || s.regions.slots.contains_key(frame_to_index(paddr)) {
2677 let tracked res = frame::from_in_use_step(&mut s.regions, paddr);
2678 match res {
2679 Option::Some(entry) => {
2680 let ghost id = fresh_frame_id(s.frames);
2681 lemma_fresh_frame_id_not_in_dom(s.frames);
2682 let ghost target_idx = frame_to_index(paddr);
2683 s.insert_frame(id, entry);
2684 assert(s.frames[id].paddr == paddr);
2685
2686 assert forall|idx: usize|
2689 #![trigger s.regions.slot_owners[idx]]
2690 idx < max_meta_slots()
2691 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2692 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2693 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
2694 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2695 if idx == target_idx {
2696 assert(false);
2697 } else {
2698 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2699 }
2700 };
2701
2702 assert forall|idx: usize|
2705 #![trigger s.regions.slot_owners[idx]]
2706 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2707 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2708 != REF_COUNT_UNUSED
2709 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2710 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2711 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2712 s.segments,
2713 index_to_frame(idx),
2714 ) > 0 by {
2715 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2716 if idx == target_idx {
2717 assert(handle_count(s.frames, idx) >= 1);
2718 } else {
2719 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2720 }
2721 };
2722
2723 assert forall|idx: usize|
2725 #![trigger s.regions.slot_owners[idx]]
2726 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2727 && (handle_count(s.frames, idx) > 0
2728 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2729 s.segments,
2730 index_to_frame(idx),
2731 ) > 0) implies {
2732 let so = s.regions.slot_owners[idx];
2733 let rc = so.inner_perms.ref_count.value();
2734 &&& rc != REF_COUNT_UNUSED
2735 &&& rc != REF_COUNT_UNIQUE
2736 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
2737 + segment_cover_count(s.segments, index_to_frame(idx))
2738 &&& so.inner_perms.storage.is_init()
2739 } by {
2740 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2741 if idx == target_idx {
2742 assert(old_regions.slot_owners[idx].usage == PageUsage::Frame);
2746 } else {
2747 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2748 }
2749 };
2750 },
2751 Option::None => {
2752 assert(s.regions == old_regions);
2753 },
2754 }
2755 }
2756}
2757
2758proof fn step_frame_drop<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
2759 requires
2760 old(s).inv(),
2761 old(s).frames.dom().contains(fid),
2762 segment_cover_count(old(s).segments, old(s).frames[fid].paddr) == 0,
2767 ensures
2768 final(s).inv(),
2769{
2770 lemma_frame_drop_pre_derivable(*s, fid);
2773 let ghost p = s.frames[fid].paddr;
2774 assert(has_safe_slot(p));
2775 s.regions.inv_implies_correct_addr(p);
2776 let ghost idx_p = frame_to_index(p);
2777 assert(s.frames.dom().filter(
2781 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx_p,
2782 ).contains(fid));
2783 assert(handle_count(s.frames, idx_p) >= 1);
2784 let ghost target_idx = frame_to_index(p);
2785 let ghost old_frames = s.frames;
2786 let ghost old_regions = s.regions;
2787 let tracked entry = s.extract_frame(fid);
2788 frame::drop_step(&mut s.regions, entry);
2789
2790 assert forall|idx: usize|
2799 #![trigger s.regions.slot_owners[idx]]
2800 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2801 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2802 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2803 s.segments,
2804 index_to_frame(idx),
2805 ) == 0 by {
2806 lemma_handle_count_remove(old_frames, fid, idx);
2807 if idx == target_idx {
2808 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() == 1);
2810 assert(handle_count(old_frames, idx) == 1);
2813 assert(handle_count(s.frames, idx) == 0);
2814 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
2816 } else {
2817 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2818 }
2819 };
2820
2821 assert forall|idx: usize|
2826 #![trigger s.regions.slot_owners[idx]]
2827 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2828 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2829 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2830 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2831 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2832 s.segments,
2833 index_to_frame(idx),
2834 ) > 0 by {
2835 lemma_handle_count_remove(old_frames, fid, idx);
2836 if idx == target_idx {
2837 assert(handle_count(old_frames, idx) >= 1);
2842 } else {
2843 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2844 }
2845 };
2846
2847 assert forall|idx: usize|
2848 #![trigger s.regions.slot_owners[idx]]
2849 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
2850 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
2851 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2852 let so = s.regions.slot_owners[idx];
2853 let rc = so.inner_perms.ref_count.value();
2854 &&& rc != REF_COUNT_UNUSED
2855 &&& rc != REF_COUNT_UNIQUE
2856 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2857 s.segments,
2858 index_to_frame(idx),
2859 )
2860 &&& so.inner_perms.storage.is_init()
2861 } by {
2862 lemma_handle_count_remove(old_frames, fid, idx);
2863 if idx == target_idx {
2864 assert(old_regions.slot_owners[idx].usage == PageUsage::Frame);
2868 assert(handle_count(old_frames, idx) > 0);
2869 let ghost pre_rc = old_regions.slot_owners[idx].inner_perms.ref_count.value();
2870 let ghost pre_h = handle_count(old_frames, idx);
2871 let ghost pre_p = old_regions.slot_owners[idx].paths_in_pt.len();
2872 assert(pre_rc == pre_h + pre_p);
2873 let ghost post_h = handle_count(s.frames, idx);
2875 assert(post_h == (pre_h - 1) as nat);
2876 let ghost post_p = s.regions.slot_owners[idx].paths_in_pt.len();
2878 assert(post_p == pre_p);
2879 let ghost post_rc = s.regions.slot_owners[idx].inner_perms.ref_count.value();
2880 if pre_rc > 1 {
2881 assert(post_rc == (pre_rc - 1) as u64);
2883 assert(post_rc as nat == post_h + post_p);
2884 assert(s.regions.slot_owners[idx].inner_perms.storage
2885 == old_regions.slot_owners[idx].inner_perms.storage);
2886 } else {
2887 assert(pre_h == 1);
2890 assert(pre_p == 0);
2891 assert(post_h == 0);
2892 assert(post_p == 0);
2893 assert(post_rc == REF_COUNT_UNUSED);
2895 assert(false);
2899 }
2900 } else {
2901 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2904 }
2905 };
2906}
2907
2908proof fn step_segment_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, range: Range<Paddr>)
2913 requires
2914 old(s).inv(),
2915 ensures
2916 final(s).inv(),
2917{
2918 if range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0 && range.start < range.end
2925 && range.end <= MAX_PADDR && (forall|paddr: Paddr|
2926 #![trigger frame_to_index(paddr)]
2927 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
2928 ==> s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value()
2929 == REF_COUNT_UNUSED) {
2930 let ghost s_before = *s;
2931 let ghost old_regions = s.regions;
2932 let ghost old_frames = s.frames;
2933 let ghost old_segments = s.segments;
2934 assert forall|paddr: Paddr|
2938 #![trigger frame_to_index(paddr)]
2939 (range.start <= paddr < range.end && paddr % PAGE_SIZE
2940 == 0) implies s.regions.slots.contains_key(frame_to_index(paddr)) by {
2941 s.regions.inv_implies_correct_addr(paddr);
2942 };
2943 let tracked res = segment::from_unused_step(&mut s.regions, range);
2944 match res {
2945 Option::Some(entry) => {
2946 let ghost id = fresh_segment_id(s.segments);
2947 lemma_fresh_segment_id_not_in_dom(s.segments);
2948 s.insert_segment(id, entry);
2949 lemma_coverage_preserved_slots_eq(s_before, *s);
2952 assert forall|idx: usize|
2963 #![trigger s.regions.slot_owners[idx]]
2964 idx < max_meta_slots()
2965 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2966 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2967 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2968 s.segments,
2969 index_to_frame(idx),
2970 ) == 0 by {
2971 let paddr = index_to_frame(idx);
2972 assert(paddr == (idx * PAGE_SIZE) as usize);
2974 assert(paddr % PAGE_SIZE == 0);
2975 assert(frame_to_index(paddr) == idx);
2976 if range.start <= paddr < range.end {
2977 assert(false);
2979 } else {
2980 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2982 assert(!(entry.range.start <= paddr < entry.range.end));
2985 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
2986 }
2987 };
2988 assert forall|idx: usize|
2989 #![trigger s.regions.slot_owners[idx]]
2990 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2991 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2992 != REF_COUNT_UNUSED
2993 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2994 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2995 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2996 s.segments,
2997 index_to_frame(idx),
2998 ) > 0 by {
2999 let paddr = index_to_frame(idx);
3000 assert(paddr == (idx * PAGE_SIZE) as usize);
3001 assert(paddr % PAGE_SIZE == 0);
3002 assert(frame_to_index(paddr) == idx);
3003 if range.start <= paddr < range.end {
3004 assert(entry.range == range);
3005 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
3006 } else {
3007 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3008 assert(!(entry.range.start <= paddr < entry.range.end));
3009 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
3010 }
3011 };
3012 assert forall|idx: usize|
3013 #![trigger s.regions.slot_owners[idx]]
3014 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
3015 && (handle_count(s.frames, idx) > 0
3016 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3017 s.segments,
3018 index_to_frame(idx),
3019 ) > 0) implies {
3020 let so = s.regions.slot_owners[idx];
3021 let rc = so.inner_perms.ref_count.value();
3022 &&& rc != REF_COUNT_UNUSED
3023 &&& rc != REF_COUNT_UNIQUE
3024 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
3025 + segment_cover_count(s.segments, index_to_frame(idx))
3026 &&& so.inner_perms.storage.is_init()
3027 } by {
3028 let paddr = index_to_frame(idx);
3029 assert(paddr == (idx * PAGE_SIZE) as usize);
3030 assert(paddr % PAGE_SIZE == 0);
3031 assert(frame_to_index(paddr) == idx);
3032 if range.start <= paddr < range.end {
3033 assert(entry.range == range);
3034 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
3035 assert(handle_count(s.frames, idx) == 0);
3038 } else {
3039 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3040 assert(!(entry.range.start <= paddr < entry.range.end));
3041 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
3042 }
3043 };
3044 assert forall|idx: usize|
3046 idx
3047 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3048 == 0 by {
3049 let paddr = index_to_frame(idx);
3050 assert(paddr == (idx * PAGE_SIZE) as usize);
3051 assert(paddr % PAGE_SIZE == 0);
3052 assert(frame_to_index(paddr) == idx);
3053 if range.start <= paddr < range.end {
3054 } else {
3056 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3058 }
3059 };
3060 assert forall|fid_other: FrameId| #[trigger]
3065 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3066 s.frames[fid_other].paddr,
3067 )].usage == PageUsage::Frame by {
3068 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3069 let other_paddr = index_to_frame(other_idx);
3070 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
3072 assert(old_frames.dom().filter(
3074 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
3075 ).contains(fid_other));
3076 assert(handle_count(old_frames, other_idx) >= 1);
3077 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value()
3078 != REF_COUNT_UNUSED);
3079 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
3083 };
3084 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
3089 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
3090 &&& so.usage == PageUsage::Frame
3091 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
3092 &&& so.inner_perms.in_list.value() == 0
3093 &&& so.paths_in_pt.is_empty()
3094 } by {
3095 let u_idx = frame_to_index(s.unique_frames[u].paddr);
3096 assert(old(s).unique_frames.dom().contains(u));
3097 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value()
3099 == REF_COUNT_UNIQUE);
3100 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value()
3101 != REF_COUNT_UNUSED);
3102 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
3104 };
3105 },
3106 Option::None => {
3107 assert(s.regions == old_regions);
3108 assert(s.segments == old_segments);
3109 },
3110 }
3111 }
3112}
3113
3114proof fn step_segment_drop<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
3118 requires
3119 old(s).inv(),
3120 old(s).segments.dom().contains(sid),
3121 ensures
3122 final(s).inv(),
3123{
3124 let ghost s_before = *s;
3125 let ghost old_regions = s.regions;
3126 let ghost old_frames = s.frames;
3127 let ghost old_segments = s.segments;
3128 let ghost range = s.segments[sid].range;
3129 assert forall|paddr: Paddr|
3132 #![trigger frame_to_index(paddr)]
3133 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) implies {
3134 let so = old_regions.slot_owners[frame_to_index(paddr)];
3135 &&& so.inner_perms.ref_count.value() >= 1
3136 &&& so.inner_perms.ref_count.value() <= REF_COUNT_MAX
3137 &&& so.usage == PageUsage::Frame
3138 &&& so.inner_perms.ref_count.value() == 1 ==> so.paths_in_pt.is_empty()
3139 } by {
3140 let idx = frame_to_index(paddr);
3141 lemma_segment_cover_contains(old_segments, sid, paddr);
3143 assert(old_regions.slot_owners[idx].usage == PageUsage::Frame);
3145 let so = old_regions.slot_owners[idx];
3148 let rc = so.inner_perms.ref_count.value();
3149 assert(rc != REF_COUNT_UNUSED);
3150 assert(rc != REF_COUNT_UNIQUE);
3151 assert(rc == handle_count(old_frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3152 old_segments,
3153 paddr,
3154 ));
3155 assert(old_regions.slot_owners.contains_key(idx));
3159 if rc == 1 {
3162 assert(handle_count(old_frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3163 old_segments,
3164 paddr,
3165 ) == 1);
3166 assert(so.paths_in_pt.len() == 0);
3167 assert(so.paths_in_pt == Set::empty());
3168 }
3169 };
3170 let tracked entry = s.extract_segment(sid);
3171 segment::drop_step(&mut s.regions, entry);
3172 lemma_coverage_preserved_slots_eq(s_before, *s);
3175
3176 assert forall|idx: usize|
3193 idx
3194 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3195 == 0 by {
3196 let paddr = index_to_frame(idx);
3197 assert(paddr == (idx * PAGE_SIZE) as usize);
3198 assert(paddr % PAGE_SIZE == 0);
3199 assert(frame_to_index(paddr) == idx);
3200 if range.start <= paddr < range.end {
3201 } else {
3203 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3204 }
3205 };
3206 assert forall|idx: usize|
3208 #![trigger s.regions.slot_owners[idx]]
3209 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3210 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3211 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3212 s.segments,
3213 index_to_frame(idx),
3214 ) == 0 by {
3215 let paddr = index_to_frame(idx);
3216 assert(paddr == (idx * PAGE_SIZE) as usize);
3217 assert(paddr % PAGE_SIZE == 0);
3218 assert(frame_to_index(paddr) == idx);
3219 if range.start <= paddr < range.end {
3220 lemma_segment_cover_contains(old_segments, sid, paddr);
3227 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3228 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() == 1);
3229 assert(handle_count(old_frames, idx) == 0);
3230 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
3231 } else {
3232 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3234 assert(!(entry.range.start <= paddr < entry.range.end));
3235 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3236 }
3237 };
3238 assert forall|idx: usize|
3239 #![trigger s.regions.slot_owners[idx]]
3240 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
3241 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3242 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3243 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3244 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3245 s.segments,
3246 index_to_frame(idx),
3247 ) > 0 by {
3248 let paddr = index_to_frame(idx);
3249 assert(paddr == (idx * PAGE_SIZE) as usize);
3250 assert(paddr % PAGE_SIZE == 0);
3251 assert(frame_to_index(paddr) == idx);
3252 if range.start <= paddr < range.end {
3253 lemma_segment_cover_contains(old_segments, sid, paddr);
3258 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3259 } else {
3260 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3261 assert(!(entry.range.start <= paddr < entry.range.end));
3262 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3263 }
3264 };
3265 assert forall|idx: usize|
3266 #![trigger s.regions.slot_owners[idx]]
3267 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
3268 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
3269 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
3270 let so = s.regions.slot_owners[idx];
3271 let rc = so.inner_perms.ref_count.value();
3272 &&& rc != REF_COUNT_UNUSED
3273 &&& rc != REF_COUNT_UNIQUE
3274 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3275 s.segments,
3276 index_to_frame(idx),
3277 )
3278 &&& so.inner_perms.storage.is_init()
3279 } by {
3280 let paddr = index_to_frame(idx);
3281 assert(paddr == (idx * PAGE_SIZE) as usize);
3282 assert(paddr % PAGE_SIZE == 0);
3283 assert(frame_to_index(paddr) == idx);
3284 if range.start <= paddr < range.end {
3285 lemma_segment_cover_contains(old_segments, sid, paddr);
3286 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3287 let pre_rc = old_regions.slot_owners[idx].inner_perms.ref_count.value();
3289 let pre_H = handle_count(old_frames, idx);
3290 let pre_P = old_regions.slot_owners[idx].paths_in_pt.len();
3291 let pre_cover = segment_cover_count(old_segments, paddr);
3292 assert(pre_rc == pre_H + pre_P + pre_cover);
3293 assert(pre_rc != REF_COUNT_UNIQUE);
3294 let post_rc = s.regions.slot_owners[idx].inner_perms.ref_count.value();
3295 assert(post_rc != REF_COUNT_UNUSED);
3296 assert(pre_rc > 1) by {
3297 if pre_rc == 1 {
3298 assert(post_rc == REF_COUNT_UNUSED);
3299 }
3300 };
3301 assert(post_rc == (pre_rc - 1) as u64);
3302 assert(s.regions.slot_owners[idx].paths_in_pt
3303 == old_regions.slot_owners[idx].paths_in_pt);
3304 assert(handle_count(s.frames, idx) == pre_H);
3305 assert(segment_cover_count(s.segments, paddr) == (pre_cover - 1) as nat);
3306 assert(s.regions.slot_owners.contains_key(idx));
3310 assert(s.regions.slot_owners[idx].inner_perms.storage.is_init());
3311 } else {
3312 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3313 assert(!(entry.range.start <= paddr < entry.range.end));
3314 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3315 }
3316 };
3317 assert forall|fid_other: FrameId| #[trigger]
3322 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3323 s.frames[fid_other].paddr,
3324 )].usage == PageUsage::Frame by {
3325 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3326 let other_paddr = index_to_frame(other_idx);
3327 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
3329 assert(old_frames.dom().filter(
3331 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
3332 ).contains(fid_other));
3333 assert(handle_count(old_frames, other_idx) >= 1);
3334 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value() >= 1);
3336 if range.start <= other_paddr < range.end {
3338 } else {
3340 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
3342 }
3343 };
3344 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3348 #![trigger
3349 s.segments.dom().contains(sid_other),
3350 frame_to_index(paddr_c)]
3351 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3352 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3353 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
3354 == PageUsage::Frame by {
3355 let cov_idx = frame_to_index(paddr_c);
3356 assert(sid_other != sid);
3358 assert(old_segments.dom().contains(sid_other));
3360 assert(old_segments[sid_other] == s.segments[sid_other]);
3361 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
3363 };
3365 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
3370 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
3371 &&& so.usage == PageUsage::Frame
3372 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
3373 &&& so.inner_perms.in_list.value() == 0
3374 &&& so.paths_in_pt.is_empty()
3375 } by {
3376 let u_paddr = s.unique_frames[u].paddr;
3377 let u_idx = frame_to_index(u_paddr);
3378 assert(old(s).unique_frames.dom().contains(u));
3379 assert(has_safe_slot(u_paddr));
3380 s.regions.inv_implies_correct_addr(u_paddr);
3381 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
3383 assert(old_regions.slot_owners[u_idx].usage == PageUsage::Frame);
3384 assert(!(range.start <= u_paddr < range.end)) by {
3386 if range.start <= u_paddr < range.end {
3387 lemma_segment_cover_contains(old_segments, sid, u_paddr);
3388 }
3389 };
3390 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
3392 };
3393}
3394
3395proof fn step_segment_split<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId, offset: usize)
3400 requires
3401 old(s).inv(),
3402 old(s).segments.dom().contains(sid),
3403 offset % PAGE_SIZE == 0,
3404 0 < offset,
3405 offset < (old(s).segments[sid].range.end - old(s).segments[sid].range.start),
3406 ensures
3407 final(s).inv(),
3408{
3409 let ghost old_regions = s.regions;
3410 let ghost old_frames = s.frames;
3411 let ghost old_segments = s.segments;
3412 let ghost range = s.segments[sid].range;
3413 let ghost mid = (range.start + offset) as Paddr;
3414 let ghost entry_left = SegmentEntry { range: range.start..mid };
3415 let ghost entry_right = SegmentEntry { range: mid..range.end };
3416 let ghost id_left = fresh_segment_id(s.segments);
3422 lemma_fresh_segment_id_not_in_dom(s.segments);
3423 assert(id_left != sid);
3424 let ghost stub_entry = SegmentEntry { range: range.start..mid };
3425 let ghost id_right = fresh_segment_id(s.segments.insert(id_left, stub_entry));
3426 lemma_fresh_segment_id_not_in_dom(s.segments.insert(id_left, stub_entry));
3427 assert(id_right != sid);
3428 assert(id_right != id_left);
3429 let tracked _orig = s.extract_segment(sid);
3431 assert(!s.segments.dom().contains(id_left));
3432 let tracked entry_l = axiom_segment_entry_new(range.start..mid);
3433 s.insert_segment(id_left, entry_l);
3434 assert(!s.segments.dom().contains(id_right));
3435 let tracked entry_r = axiom_segment_entry_new(mid..range.end);
3436 s.insert_segment(id_right, entry_r);
3437 assert(s.regions == old_regions);
3442 assert forall|paddr: Paddr| #[trigger]
3443 frame_to_index(paddr) < max_meta_slots() implies segment_cover_count(s.segments, paddr)
3444 == segment_cover_count(old_segments, paddr) by {
3445 lemma_segment_cover_split(
3446 old_segments,
3447 sid,
3448 id_left,
3449 id_right,
3450 entry_left,
3451 entry_right,
3452 paddr,
3453 );
3454 };
3455 assert(entry_left.range.start % PAGE_SIZE == 0);
3462 assert(entry_right.range.start % PAGE_SIZE == 0);
3463 assert(entry_left.range.end % PAGE_SIZE == 0);
3464 assert(entry_right.range.end % PAGE_SIZE == 0);
3465 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3469 #![trigger
3470 s.segments.dom().contains(sid_other),
3471 frame_to_index(paddr_c)]
3472 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3473 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3474 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
3475 == PageUsage::Frame by {
3476 if sid_other == id_left {
3477 assert(old_segments.dom().contains(sid));
3478 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
3479 } else if sid_other == id_right {
3480 assert(old_segments.dom().contains(sid));
3481 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
3482 } else {
3483 assert(old_segments.dom().contains(sid_other));
3484 assert(old_segments[sid_other] == s.segments[sid_other]);
3485 }
3486 };
3487 assert forall|idx: usize|
3492 #![trigger s.regions.slot_owners[idx]]
3493 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3494 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3495 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3496 s.segments,
3497 index_to_frame(idx),
3498 ) == 0 by {
3499 let paddr = index_to_frame(idx);
3500 assert(paddr == (idx * PAGE_SIZE) as usize);
3501 assert(frame_to_index(paddr) == idx);
3502 lemma_segment_cover_split(
3503 old_segments,
3504 sid,
3505 id_left,
3506 id_right,
3507 entry_left,
3508 entry_right,
3509 paddr,
3510 );
3511 };
3512 assert forall|idx: usize|
3513 #![trigger s.regions.slot_owners[idx]]
3514 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
3515 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3516 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3517 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3518 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3519 s.segments,
3520 index_to_frame(idx),
3521 ) > 0 by {
3522 let paddr = index_to_frame(idx);
3523 assert(paddr == (idx * PAGE_SIZE) as usize);
3524 assert(frame_to_index(paddr) == idx);
3525 lemma_segment_cover_split(
3526 old_segments,
3527 sid,
3528 id_left,
3529 id_right,
3530 entry_left,
3531 entry_right,
3532 paddr,
3533 );
3534 };
3535 assert forall|idx: usize|
3536 #![trigger s.regions.slot_owners[idx]]
3537 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
3538 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
3539 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
3540 let so = s.regions.slot_owners[idx];
3541 let rc = so.inner_perms.ref_count.value();
3542 &&& rc != REF_COUNT_UNUSED
3543 &&& rc != REF_COUNT_UNIQUE
3544 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3545 s.segments,
3546 index_to_frame(idx),
3547 )
3548 &&& so.inner_perms.storage.is_init()
3549 } by {
3550 let paddr = index_to_frame(idx);
3551 assert(paddr == (idx * PAGE_SIZE) as usize);
3552 assert(frame_to_index(paddr) == idx);
3553 lemma_segment_cover_split(
3554 old_segments,
3555 sid,
3556 id_left,
3557 id_right,
3558 entry_left,
3559 entry_right,
3560 paddr,
3561 );
3562 };
3563 }
3566
3567proof fn step_segment_next<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
3594 requires
3595 old(s).inv(),
3596 old(s).segments.dom().contains(sid),
3597 ensures
3598 final(s).inv(),
3599{
3600 let ghost old_regions = s.regions;
3601 let ghost old_frames = s.frames;
3602 let ghost old_segments = s.segments;
3603 let ghost range = s.segments[sid].range;
3604 let ghost paddr = range.start;
3605 let ghost target_idx = frame_to_index(paddr);
3606 let ghost new_range_start = (paddr + PAGE_SIZE) as Paddr;
3607 let ghost new_range_end = range.end;
3608 let ghost will_become_empty = new_range_start >= new_range_end;
3609 let ghost new_entry_ghost = SegmentEntry { range: new_range_start..new_range_end };
3610
3611 lemma_segment_cover_contains(old_segments, sid, paddr);
3613 assert(segment_cover_count(old_segments, paddr) >= 1);
3614 assert(old_regions.slot_owners[target_idx].usage == PageUsage::Frame);
3615 let ghost so_pre = old_regions.slot_owners[target_idx];
3616 let ghost pre_rc = so_pre.inner_perms.ref_count.value();
3617 let ghost pre_H = handle_count(old_frames, target_idx);
3618 let ghost pre_P = so_pre.paths_in_pt.len();
3619 let ghost pre_cover = segment_cover_count(old_segments, paddr);
3620 assert(pre_rc == pre_H + pre_P + pre_cover);
3621 assert(pre_rc != REF_COUNT_UNUSED);
3622 assert(pre_rc != REF_COUNT_UNIQUE);
3623 assert(old_regions.slot_owners.contains_key(target_idx));
3624 assert(has_safe_slot(paddr));
3625 s.regions.inv_implies_correct_addr(paddr);
3626 assert(s.regions.slots.contains_key(target_idx));
3627 assert(range.start % PAGE_SIZE == 0);
3629 assert(range.end <= MAX_PADDR);
3630 assert(range.start + PAGE_SIZE <= MAX_PADDR);
3631
3632 let ghost fid = fresh_frame_id(s.frames);
3634 lemma_fresh_frame_id_not_in_dom(s.frames);
3635 let tracked frame_entry = axiom_frame_entry_new(paddr);
3636 s.insert_frame(fid, frame_entry);
3637 let tracked _old_entry = s.extract_segment(sid);
3639 segment::segment_next_embedded(&mut s.regions, paddr);
3640 if !will_become_empty {
3641 let tracked new_entry = axiom_segment_entry_new(new_range_start..new_range_end);
3642 s.insert_segment(sid, new_entry);
3643 assert(new_entry == new_entry_ghost);
3644 assert(s.segments == old_segments.remove(sid).insert(sid, new_entry_ghost));
3645 } else {
3646 assert(s.segments == old_segments.remove(sid));
3647 }
3648 assert(s.frames == old_frames.insert(fid, frame_entry));
3649
3650 assert forall|paddr_c: Paddr| paddr_c % PAGE_SIZE == 0 implies #[trigger] segment_cover_count(
3653 s.segments,
3654 paddr_c,
3655 ) == (if paddr_c == paddr {
3656 1nat
3657 } else {
3658 0nat
3659 }) + 0nat
3660 || true by {
3664 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3665 };
3666 assert forall|paddr_c: Paddr|
3668 paddr_c % PAGE_SIZE == 0 && paddr_c == paddr implies #[trigger] segment_cover_count(
3669 s.segments,
3670 paddr_c,
3671 ) + 1 == segment_cover_count(old_segments, paddr_c) by {
3672 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3673 };
3674 assert forall|paddr_c: Paddr|
3675 paddr_c % PAGE_SIZE == 0 && paddr_c != paddr implies #[trigger] segment_cover_count(
3676 s.segments,
3677 paddr_c,
3678 ) == segment_cover_count(old_segments, paddr_c) by {
3679 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3680 };
3681
3682 assert forall|idx: usize|
3684 idx
3685 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3686 == 0 by {
3687 let paddr_c = index_to_frame(idx);
3688 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3689 if idx == target_idx {
3690 } else {
3692 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3693 }
3694 };
3695 assert forall|fid_other: FrameId| #[trigger]
3699 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3700 s.frames[fid_other].paddr,
3701 )].usage == PageUsage::Frame by {
3702 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3703 if fid_other == fid {
3704 assert(s.frames[fid_other].paddr == paddr);
3705 assert(other_idx == target_idx);
3706 } else {
3707 assert(old_frames.dom().contains(fid_other));
3708 assert(s.frames[fid_other] == old_frames[fid_other]);
3709 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
3710 }
3711 };
3712 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3714 #![trigger
3715 s.segments.dom().contains(sid_other),
3716 frame_to_index(paddr_c)]
3717 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3718 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3719 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
3720 == PageUsage::Frame by {
3721 let cov_idx = frame_to_index(paddr_c);
3722 if !will_become_empty && sid_other == sid {
3723 assert(old_segments.dom().contains(sid));
3725 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
3726 } else {
3727 assert(sid_other != sid);
3728 assert(old_segments.dom().contains(sid_other));
3729 assert(old_segments[sid_other] == s.segments[sid_other]);
3730 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
3731 }
3732 };
3733 if !will_become_empty {
3735 assert(new_range_start % PAGE_SIZE == 0);
3736 assert(new_range_end % PAGE_SIZE == 0);
3737 }
3738 assert forall|idx: usize|
3741 #![trigger s.regions.slot_owners[idx]]
3742 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3743 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3744 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3745 s.segments,
3746 index_to_frame(idx),
3747 ) == 0 by {
3748 let paddr_c = index_to_frame(idx);
3749 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3750 assert(frame_to_index(paddr_c) == idx);
3751 if idx == target_idx {
3752 assert(false);
3754 } else {
3755 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3756 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3757 }
3758 };
3759 assert forall|idx: usize|
3760 #![trigger s.regions.slot_owners[idx]]
3761 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
3762 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3763 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3764 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3765 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3766 s.segments,
3767 index_to_frame(idx),
3768 ) > 0 by {
3769 let paddr_c = index_to_frame(idx);
3770 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3771 if idx == target_idx {
3772 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3774 assert(handle_count(s.frames, target_idx) >= 1);
3775 } else {
3776 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3777 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3778 }
3779 };
3780 assert forall|idx: usize|
3781 #![trigger s.regions.slot_owners[idx]]
3782 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
3783 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
3784 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
3785 let so = s.regions.slot_owners[idx];
3786 let rc = so.inner_perms.ref_count.value();
3787 &&& rc != REF_COUNT_UNUSED
3788 &&& rc != REF_COUNT_UNIQUE
3789 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3790 s.segments,
3791 index_to_frame(idx),
3792 )
3793 &&& so.inner_perms.storage.is_init()
3794 } by {
3795 let paddr_c = index_to_frame(idx);
3796 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3797 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3798 if idx == target_idx {
3799 } else {
3805 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3806 }
3807 };
3808 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
3812 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
3813 &&& so.usage == PageUsage::Frame
3814 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
3815 &&& so.inner_perms.in_list.value() == 0
3816 &&& so.paths_in_pt.is_empty()
3817 } by {
3818 let u_paddr = s.unique_frames[u].paddr;
3819 let u_idx = frame_to_index(u_paddr);
3820 assert(old(s).unique_frames.dom().contains(u));
3821 assert(has_safe_slot(u_paddr));
3822 s.regions.inv_implies_correct_addr(u_paddr);
3823 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
3824 assert(old_regions.slot_owners[u_idx].usage == PageUsage::Frame);
3825 assert(u_idx != target_idx) by {
3827 lemma_segment_cover_contains(old_segments, sid, paddr);
3828 };
3829 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
3830 };
3831}
3832
3833proof fn step_segment_clone_range<'rcu>(
3834 tracked s: &mut VmStore<'rcu>,
3835 sid: SegmentId,
3836 sub_range: Range<Paddr>,
3837)
3838 requires
3839 old(s).inv(),
3840 old(s).segments.dom().contains(sid),
3841 sub_range.start % PAGE_SIZE == 0,
3842 sub_range.end % PAGE_SIZE == 0,
3843 old(s).segments[sid].range.start <= sub_range.start,
3844 sub_range.start < sub_range.end,
3845 sub_range.end <= old(s).segments[sid].range.end,
3846 forall|paddr: Paddr|
3847 #![trigger frame_to_index(paddr)]
3848 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) ==> old(
3849 s,
3850 ).regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1
3851 <= REF_COUNT_MAX,
3852 ensures
3853 final(s).inv(),
3854{
3855 let ghost old_regions = s.regions;
3856 let ghost old_frames = s.frames;
3857 let ghost old_segments = s.segments;
3858 let ghost sid_range = s.segments[sid].range;
3859 let ghost new_entry_ghost = SegmentEntry { range: sub_range };
3860
3861 assert(sid_range.end <= MAX_PADDR);
3864 assert(sub_range.end <= MAX_PADDR);
3865
3866 assert forall|paddr: Paddr|
3874 #![trigger frame_to_index(paddr)]
3875 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) implies {
3876 let so = old_regions.slot_owners[frame_to_index(paddr)];
3877 &&& so.usage == PageUsage::Frame
3878 &&& so.inner_perms.ref_count.value() >= 1
3879 &&& so.inner_perms.ref_count.value() + 1 <= REF_COUNT_MAX
3880 } by {
3881 assert(old_segments.dom().contains(sid));
3883 assert(sid_range.start <= paddr < sid_range.end);
3884 lemma_segment_cover_contains(old_segments, sid, paddr);
3885 assert(segment_cover_count(old_segments, paddr) >= 1);
3886 };
3888
3889 segment::segment_clone_embedded(&mut s.regions, sub_range);
3891
3892 let ghost sid2 = fresh_segment_id(s.segments);
3894 lemma_fresh_segment_id_not_in_dom(s.segments);
3895 assert(sid2 != sid);
3896 let tracked new_entry = axiom_segment_entry_new(sub_range);
3897 s.insert_segment(sid2, new_entry);
3898 assert(new_entry =~= new_entry_ghost);
3899 assert(s.segments =~= old_segments.insert(sid2, new_entry_ghost));
3900 assert(s.frames == old_frames);
3901
3902 assert forall|paddr_c: Paddr|
3904 paddr_c % PAGE_SIZE == 0 && sub_range.start <= paddr_c
3905 < sub_range.end implies #[trigger] segment_cover_count(s.segments, paddr_c)
3906 == segment_cover_count(old_segments, paddr_c) + 1 by {
3907 lemma_segment_cover_insert_inside(old_segments, sid2, new_entry_ghost, paddr_c);
3908 };
3909 assert forall|paddr_c: Paddr|
3910 paddr_c % PAGE_SIZE == 0 && !(sub_range.start <= paddr_c
3911 < sub_range.end) implies #[trigger] segment_cover_count(s.segments, paddr_c)
3912 == segment_cover_count(old_segments, paddr_c) by {
3913 lemma_segment_cover_insert_outside(old_segments, sid2, new_entry_ghost, paddr_c);
3914 };
3915
3916 assert forall|idx: usize|
3920 idx < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].usage
3921 == old_regions.slot_owners[idx].usage by {
3922 let aligned = index_to_frame(idx);
3923 assert(aligned == (idx * PAGE_SIZE) as usize);
3924 assert(frame_to_index(aligned) == idx);
3925 if sub_range.start <= aligned < sub_range.end {
3926 } else {
3928 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3929 }
3930 };
3931 assert forall|idx: usize|
3933 idx
3934 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3935 == 0 by {
3936 let aligned = index_to_frame(idx);
3937 assert(aligned == (idx * PAGE_SIZE) as usize);
3938 assert(frame_to_index(aligned) == idx);
3939 if sub_range.start <= aligned < sub_range.end {
3940 } else {
3942 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3943 }
3944 };
3945
3946 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3948 #![trigger
3949 s.segments.dom().contains(sid_other),
3950 frame_to_index(paddr_c)]
3951 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3952 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3953 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
3954 == PageUsage::Frame by {
3955 let cov_idx = frame_to_index(paddr_c);
3956 if sid_other == sid2 {
3957 assert(s.segments[sid2].range == sub_range);
3959 assert(old_segments.dom().contains(sid));
3960 assert(sid_range.start <= paddr_c < sid_range.end);
3961 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
3962 } else {
3963 assert(old_segments.dom().contains(sid_other));
3964 assert(old_segments[sid_other] == s.segments[sid_other]);
3965 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
3966 }
3967 assert(has_safe_slot(paddr_c));
3972 s.regions.inv_implies_correct_addr(paddr_c);
3973 assert(s.regions.slot_owners.contains_key(cov_idx));
3974 };
3975
3976 assert forall|fid_other: FrameId| #[trigger]
3978 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3979 s.frames[fid_other].paddr,
3980 )].usage == PageUsage::Frame by {
3981 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3982 assert(old_frames.dom().contains(fid_other));
3983 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
3984 assert(has_safe_slot(s.frames[fid_other].paddr));
3985 s.regions.inv_implies_correct_addr(s.frames[fid_other].paddr);
3986 assert(s.regions.slot_owners.contains_key(other_idx));
3987 };
3990
3991 assert forall|idx: usize|
3993 #![trigger s.regions.slot_owners[idx]]
3994 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3995 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3996 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3997 s.segments,
3998 index_to_frame(idx),
3999 ) == 0 by {
4000 let aligned = index_to_frame(idx);
4001 assert(aligned == (idx * PAGE_SIZE) as usize);
4002 assert(frame_to_index(aligned) == idx);
4003 if sub_range.start <= aligned < sub_range.end {
4004 assert(false);
4006 } else {
4007 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4008 }
4009 };
4010 assert forall|idx: usize|
4012 #![trigger s.regions.slot_owners[idx]]
4013 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
4014 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4015 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
4016 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
4017 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
4018 s.segments,
4019 index_to_frame(idx),
4020 ) > 0 by {
4021 let aligned = index_to_frame(idx);
4022 assert(aligned == (idx * PAGE_SIZE) as usize);
4023 assert(frame_to_index(aligned) == idx);
4024 if sub_range.start <= aligned < sub_range.end {
4025 } else {
4027 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4028 }
4029 };
4030 assert forall|idx: usize|
4032 #![trigger s.regions.slot_owners[idx]]
4033 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
4034 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
4035 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
4036 let so = s.regions.slot_owners[idx];
4037 let rc = so.inner_perms.ref_count.value();
4038 &&& rc != REF_COUNT_UNUSED
4039 &&& rc != REF_COUNT_UNIQUE
4040 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
4041 s.segments,
4042 index_to_frame(idx),
4043 )
4044 &&& so.inner_perms.storage.is_init()
4045 } by {
4046 let aligned = index_to_frame(idx);
4047 assert(aligned == (idx * PAGE_SIZE) as usize);
4048 assert(frame_to_index(aligned) == idx);
4049 if sub_range.start <= aligned < sub_range.end {
4050 } else {
4053 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4054 }
4055 };
4056 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4061 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4062 &&& so.usage == PageUsage::Frame
4063 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4064 &&& so.inner_perms.in_list.value() == 0
4065 &&& so.paths_in_pt.is_empty()
4066 } by {
4067 let u_paddr = s.unique_frames[u].paddr;
4068 let u_idx = frame_to_index(u_paddr);
4069 assert(old(s).unique_frames.dom().contains(u));
4070 assert(has_safe_slot(u_paddr));
4071 s.regions.inv_implies_correct_addr(u_paddr);
4072 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
4073 assert(old_regions.slot_owners[u_idx].usage == PageUsage::Frame);
4074 assert(!(sub_range.start <= u_paddr < sub_range.end)) by {
4075 if sub_range.start <= u_paddr < sub_range.end {
4076 assert(sid_range.start <= u_paddr < sid_range.end);
4078 lemma_segment_cover_contains(old_segments, sid, u_paddr);
4079 }
4080 };
4081 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4082 };
4083}
4084
4085proof fn step_segment_clone<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
4089 requires
4090 old(s).inv(),
4091 old(s).segments.dom().contains(sid),
4092 forall|paddr: Paddr|
4093 #![trigger frame_to_index(paddr)]
4094 (old(s).segments[sid].range.start <= paddr < old(s).segments[sid].range.end && paddr
4095 % PAGE_SIZE == 0) ==> old(s).regions.slot_owners[frame_to_index(
4096 paddr,
4097 )].inner_perms.ref_count.value() + 1 <= REF_COUNT_MAX,
4098 ensures
4099 final(s).inv(),
4100{
4101 let ghost r = s.segments[sid].range;
4105 assert(r.start % PAGE_SIZE == 0);
4106 assert(r.end % PAGE_SIZE == 0);
4107 assert(r.start < r.end);
4108 assert(r.end <= MAX_PADDR);
4109 step_segment_clone_range(s, sid, r);
4110}
4111
4112proof fn step_segment_slice<'rcu>(
4115 tracked s: &mut VmStore<'rcu>,
4116 sid: SegmentId,
4117 sub_range: Range<Paddr>,
4118)
4119 requires
4120 old(s).inv(),
4121 old(s).segments.dom().contains(sid),
4122 sub_range.start % PAGE_SIZE == 0,
4123 sub_range.end % PAGE_SIZE == 0,
4124 old(s).segments[sid].range.start <= sub_range.start,
4125 sub_range.start < sub_range.end,
4126 sub_range.end <= old(s).segments[sid].range.end,
4127 forall|paddr: Paddr|
4128 #![trigger frame_to_index(paddr)]
4129 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) ==> old(
4130 s,
4131 ).regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1
4132 <= REF_COUNT_MAX,
4133 ensures
4134 final(s).inv(),
4135{
4136 step_segment_clone_range(s, sid, sub_range);
4137}
4138
4139proof fn step_unique_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
4140 requires
4141 old(s).inv(),
4142 ensures
4143 final(s).inv(),
4144{
4145 if has_safe_slot(paddr) && s.regions.slots.contains_key(frame_to_index(paddr))
4149 && s.regions.slot_owners[frame_to_index(paddr)].usage is Unused
4150 && s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value()
4151 == REF_COUNT_UNUSED {
4152 let ghost old_regions = s.regions;
4153 let ghost old_frames = s.frames;
4154 let ghost old_segments = s.segments;
4155 let ghost old_unique = s.unique_frames;
4156 let ghost idx = frame_to_index(paddr);
4157
4158 s.regions.inv_implies_correct_addr(paddr);
4160 assert(s.regions.slot_owners.contains_key(idx));
4161 assert(index_to_frame(idx) == paddr);
4162
4163 assert(handle_count(old_frames, idx) == 0);
4165 assert(old_regions.slot_owners[idx].paths_in_pt.is_empty());
4166 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0);
4167
4168 unique::unique_from_unused_embedded(&mut s.regions, paddr);
4170
4171 let ghost uid = fresh_unique_id(s.unique_frames);
4173 lemma_fresh_unique_id_not_in_dom(s.unique_frames);
4174 let tracked entry = axiom_unique_entry_new(paddr);
4175 s.insert_unique(uid, entry);
4176 assert(s.unique_frames =~= old_unique.insert(uid, UniqueEntry { paddr }));
4177 assert(s.frames == old_frames);
4178 assert(s.segments == old_segments);
4179
4180 assert forall|i: usize|
4182 i
4183 < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].inner_perms.in_list.value()
4184 == 0 by {
4185 if i != idx {
4186 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4187 }
4188 };
4189 assert forall|fid: FrameId| #[trigger]
4191 s.frames.dom().contains(fid) implies s.regions.slot_owners[frame_to_index(
4192 s.frames[fid].paddr,
4193 )].usage == PageUsage::Frame by {
4194 let other_idx = frame_to_index(s.frames[fid].paddr);
4195 assert(old_frames.dom().contains(fid));
4196 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
4197 if other_idx == idx {
4198 assert(false);
4200 }
4201 };
4202 assert forall|sid: SegmentId, paddr_c: Paddr|
4204 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4205 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4206 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4207 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
4208 == PageUsage::Frame by {
4209 let cov_idx = frame_to_index(paddr_c);
4210 assert(old_segments.dom().contains(sid));
4211 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
4212 if cov_idx == idx {
4213 assert(false);
4214 }
4215 };
4216 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4218 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4219 &&& so.usage == PageUsage::Frame
4220 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4221 &&& so.inner_perms.in_list.value() == 0
4222 &&& so.paths_in_pt.is_empty()
4223 } by {
4224 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4225 if u == uid {
4226 assert(s.unique_frames[u].paddr == paddr);
4227 assert(u_idx == idx);
4228 } else {
4229 assert(old_unique.dom().contains(u));
4230 assert(s.unique_frames[u] == old_unique[u]);
4231 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value()
4232 == REF_COUNT_UNIQUE);
4233 assert(u_idx != idx);
4234 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4235 }
4236 };
4237 assert forall|u: UniqueId| #[trigger]
4239 s.unique_frames.dom().contains(u) implies has_safe_slot(s.unique_frames[u].paddr) by {
4240 if u != uid {
4241 assert(old_unique.dom().contains(u));
4242 }
4243 };
4244 assert forall|u1: UniqueId, u2: UniqueId|
4246 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4247 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4248 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4249 if u1 == uid && u2 != uid {
4250 assert(old_unique.dom().contains(u2));
4251 assert(s.unique_frames[u2].paddr == paddr);
4252 assert(frame_to_index(s.unique_frames[u2].paddr) == idx);
4253 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
4254 == REF_COUNT_UNIQUE);
4255 assert(false);
4256 } else if u2 == uid && u1 != uid {
4257 assert(old_unique.dom().contains(u1));
4258 assert(s.unique_frames[u1].paddr == paddr);
4259 assert(frame_to_index(s.unique_frames[u1].paddr) == idx);
4260 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
4261 == REF_COUNT_UNIQUE);
4262 assert(false);
4263 } else if u1 != uid && u2 != uid {
4264 assert(old_unique.dom().contains(u1));
4265 assert(old_unique.dom().contains(u2));
4266 }
4267 };
4268
4269 assert forall|i: usize|
4271 #![trigger s.regions.slot_owners[i]]
4272 i < max_meta_slots() && s.regions.slot_owners[i].inner_perms.ref_count.value()
4273 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4274 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4275 s.segments,
4276 index_to_frame(i),
4277 ) == 0 by {
4278 if i == idx {
4279 assert(false);
4281 } else {
4282 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4283 }
4284 };
4285 assert forall|i: usize|
4287 #![trigger s.regions.slot_owners[i]]
4288 i < max_meta_slots() && s.regions.slot_owners[i].usage == PageUsage::Frame
4289 && s.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4290 && s.regions.slot_owners[i].inner_perms.ref_count.value()
4291 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
4292 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4293 s.segments,
4294 index_to_frame(i),
4295 ) > 0 by {
4296 if i == idx {
4297 assert(false);
4299 } else {
4300 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4301 }
4302 };
4303 assert forall|i: usize|
4305 #![trigger s.regions.slot_owners[i]]
4306 i < max_meta_slots() && s.regions.slot_owners[i].usage == PageUsage::Frame && (
4307 handle_count(s.frames, i) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0
4308 || segment_cover_count(s.segments, index_to_frame(i)) > 0) implies {
4309 let so = s.regions.slot_owners[i];
4310 let rc = so.inner_perms.ref_count.value();
4311 &&& rc != REF_COUNT_UNUSED
4312 &&& rc != REF_COUNT_UNIQUE
4313 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4314 s.segments,
4315 index_to_frame(i),
4316 )
4317 &&& so.inner_perms.storage.is_init()
4318 } by {
4319 if i == idx {
4320 assert(handle_count(s.frames, idx) == 0);
4323 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4324 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4325 } else {
4326 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4327 }
4328 };
4329 }
4330}
4331
4332proof fn step_unique_drop<'rcu>(tracked s: &mut VmStore<'rcu>, uid: UniqueId)
4340 requires
4341 old(s).inv(),
4342 old(s).unique_frames.dom().contains(uid),
4343 ensures
4344 final(s).inv(),
4345{
4346 let ghost old_regions = s.regions;
4347 let ghost old_frames = s.frames;
4348 let ghost old_segments = s.segments;
4349 let ghost old_unique = s.unique_frames;
4350 let ghost paddr = s.unique_frames[uid].paddr;
4351 let ghost idx = frame_to_index(paddr);
4352
4353 assert(has_safe_slot(paddr));
4356 s.regions.inv_implies_correct_addr(paddr);
4357 assert(s.regions.slot_owners.contains_key(idx));
4358 assert(index_to_frame(idx) == paddr);
4359 assert(s.regions.slot_owners[idx].usage == PageUsage::Frame);
4360 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
4361 assert(s.regions.slot_owners[idx].inner_perms.in_list.value() == 0);
4362 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4363 assert(s.regions.slot_owners[idx].inner_perms.storage.is_init());
4364
4365 assert(handle_count(old_frames, idx) == 0) by {
4369 if handle_count(old_frames, idx) > 0 {
4370 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE);
4371 assert(false);
4372 }
4373 };
4374 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0) by {
4375 if segment_cover_count(old_segments, index_to_frame(idx)) > 0 {
4376 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE);
4377 assert(false);
4378 }
4379 };
4380
4381 let tracked _entry = s.extract_unique(uid);
4383 unique::unique_drop_embedded(&mut s.regions, paddr);
4384 assert(s.unique_frames =~= old_unique.remove(uid));
4385 assert(s.frames == old_frames);
4386 assert(s.segments == old_segments);
4387
4388 assert forall|i: usize|
4390 i < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].inner_perms.in_list.value()
4391 == 0 by {
4392 if i != idx {
4393 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4394 }
4395 };
4396 assert forall|fid: FrameId| #[trigger]
4398 s.frames.dom().contains(fid) implies s.regions.slot_owners[frame_to_index(
4399 s.frames[fid].paddr,
4400 )].usage == PageUsage::Frame by {
4401 let other_idx = frame_to_index(s.frames[fid].paddr);
4402 assert(old_frames.dom().contains(fid));
4403 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
4404 if other_idx != idx {
4405 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4406 }
4407 };
4408 assert forall|sid: SegmentId, paddr_c: Paddr|
4410 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4411 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4412 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4413 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
4414 == PageUsage::Frame by {
4415 let cov_idx = frame_to_index(paddr_c);
4416 assert(old_segments.dom().contains(sid));
4417 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
4418 if cov_idx != idx {
4419 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4420 }
4421 };
4422 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4424 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4425 &&& so.usage == PageUsage::Frame
4426 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4427 &&& so.inner_perms.in_list.value() == 0
4428 &&& so.paths_in_pt.is_empty()
4429 } by {
4430 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4431 assert(old_unique.dom().contains(u));
4432 assert(u != uid);
4433 if u_idx == idx {
4435 assert(s.unique_frames[u].paddr == paddr) by {
4436 assert(old_unique[u].paddr == s.unique_frames[u].paddr);
4437 };
4438 assert(u == uid);
4439 assert(false);
4440 }
4441 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4442 };
4443 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies has_safe_slot(
4445 s.unique_frames[u].paddr,
4446 ) by {
4447 assert(old_unique.dom().contains(u));
4448 };
4449 assert forall|u1: UniqueId, u2: UniqueId|
4450 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4451 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4452 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4453 assert(old_unique.dom().contains(u1));
4454 assert(old_unique.dom().contains(u2));
4455 };
4456
4457 assert forall|i: usize|
4459 #![trigger s.regions.slot_owners[i]]
4460 i < max_meta_slots() && s.regions.slot_owners[i].inner_perms.ref_count.value()
4461 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4462 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4463 s.segments,
4464 index_to_frame(i),
4465 ) == 0 by {
4466 if i == idx {
4467 assert(handle_count(s.frames, idx) == 0);
4470 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4471 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4472 } else {
4473 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4474 }
4475 };
4476 assert forall|i: usize|
4478 #![trigger s.regions.slot_owners[i]]
4479 i < max_meta_slots() && s.regions.slot_owners[i].usage == PageUsage::Frame
4480 && s.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4481 && s.regions.slot_owners[i].inner_perms.ref_count.value()
4482 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
4483 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4484 s.segments,
4485 index_to_frame(i),
4486 ) > 0 by {
4487 if i == idx {
4488 assert(false);
4490 } else {
4491 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4492 }
4493 };
4494 assert forall|i: usize|
4496 #![trigger s.regions.slot_owners[i]]
4497 i < max_meta_slots() && s.regions.slot_owners[i].usage == PageUsage::Frame && (handle_count(
4498 s.frames,
4499 i,
4500 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4501 s.segments,
4502 index_to_frame(i),
4503 ) > 0) implies {
4504 let so = s.regions.slot_owners[i];
4505 let rc = so.inner_perms.ref_count.value();
4506 &&& rc != REF_COUNT_UNUSED
4507 &&& rc != REF_COUNT_UNIQUE
4508 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4509 s.segments,
4510 index_to_frame(i),
4511 )
4512 &&& so.inner_perms.storage.is_init()
4513 } by {
4514 if i == idx {
4515 assert(handle_count(s.frames, idx) == 0);
4517 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4518 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4519 } else {
4520 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4521 }
4522 };
4523}
4524
4525proof fn step_from_unique<'rcu>(tracked s: &mut VmStore<'rcu>, uid: UniqueId)
4531 requires
4532 old(s).inv(),
4533 old(s).unique_frames.dom().contains(uid),
4534 ensures
4535 final(s).inv(),
4536{
4537 let ghost old_regions = s.regions;
4538 let ghost old_frames = s.frames;
4539 let ghost old_segments = s.segments;
4540 let ghost old_unique = s.unique_frames;
4541 let ghost paddr = s.unique_frames[uid].paddr;
4542 let ghost idx = frame_to_index(paddr);
4543
4544 assert(has_safe_slot(paddr));
4546 s.regions.inv_implies_correct_addr(paddr);
4547 assert(s.regions.slot_owners.contains_key(idx));
4548 assert(index_to_frame(idx) == paddr);
4549 assert(s.regions.slot_owners[idx].usage == PageUsage::Frame);
4550 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
4551 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4552 assert(s.regions.slot_owners[idx].inner_perms.storage.is_init());
4553
4554 assert(handle_count(old_frames, idx) == 0) by {
4556 if handle_count(old_frames, idx) > 0 {
4557 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE);
4558 assert(false);
4559 }
4560 };
4561 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0) by {
4562 if segment_cover_count(old_segments, index_to_frame(idx)) > 0 {
4563 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE);
4564 assert(false);
4565 }
4566 };
4567
4568 let tracked _ue = s.extract_unique(uid);
4570 unique::from_unique_embedded(&mut s.regions, paddr);
4571
4572 let ghost fid = fresh_frame_id(s.frames);
4574 lemma_fresh_frame_id_not_in_dom(s.frames);
4575 let tracked fe = axiom_frame_entry_new(paddr);
4576 s.insert_frame(fid, fe);
4577 assert(s.frames =~= old_frames.insert(fid, FrameEntry { paddr }));
4578 assert(s.unique_frames =~= old_unique.remove(uid));
4579 assert(s.segments == old_segments);
4580 assert(s.frames[fid].paddr == paddr);
4581
4582 assert forall|i: usize|
4584 i < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].inner_perms.in_list.value()
4585 == 0 by {
4586 if i != idx {
4587 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4588 }
4589 };
4590 assert forall|fid_other: FrameId| #[trigger]
4592 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
4593 s.frames[fid_other].paddr,
4594 )].usage == PageUsage::Frame by {
4595 let other_idx = frame_to_index(s.frames[fid_other].paddr);
4596 if fid_other == fid {
4597 assert(s.frames[fid_other].paddr == paddr);
4598 assert(other_idx == idx);
4599 } else {
4600 assert(old_frames.dom().contains(fid_other));
4601 assert(s.frames[fid_other] == old_frames[fid_other]);
4602 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
4603 if other_idx != idx {
4604 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4605 }
4606 }
4607 };
4608 assert forall|sid: SegmentId, paddr_c: Paddr|
4610 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4611 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4612 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4613 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
4614 == PageUsage::Frame by {
4615 let cov_idx = frame_to_index(paddr_c);
4616 assert(old_segments.dom().contains(sid));
4617 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
4618 if cov_idx != idx {
4619 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4620 }
4621 };
4622 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4624 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4625 &&& so.usage == PageUsage::Frame
4626 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4627 &&& so.inner_perms.in_list.value() == 0
4628 &&& so.paths_in_pt.is_empty()
4629 } by {
4630 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4631 assert(old_unique.dom().contains(u));
4632 assert(u != uid);
4633 if u_idx == idx {
4634 assert(old_unique[u].paddr == s.unique_frames[u].paddr);
4635 assert(u == uid);
4636 assert(false);
4637 }
4638 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4639 };
4640 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies has_safe_slot(
4641 s.unique_frames[u].paddr,
4642 ) by {
4643 assert(old_unique.dom().contains(u));
4644 };
4645 assert forall|u1: UniqueId, u2: UniqueId|
4646 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4647 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4648 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4649 assert(old_unique.dom().contains(u1));
4650 assert(old_unique.dom().contains(u2));
4651 };
4652
4653 assert forall|i: usize|
4655 #![trigger s.regions.slot_owners[i]]
4656 i < max_meta_slots() && s.regions.slot_owners[i].inner_perms.ref_count.value()
4657 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4658 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4659 s.segments,
4660 index_to_frame(i),
4661 ) == 0 by {
4662 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4663 if i == idx {
4664 assert(false);
4665 } else {
4666 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4667 }
4668 };
4669 assert forall|i: usize|
4671 #![trigger s.regions.slot_owners[i]]
4672 i < max_meta_slots() && s.regions.slot_owners[i].usage == PageUsage::Frame
4673 && s.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4674 && s.regions.slot_owners[i].inner_perms.ref_count.value()
4675 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
4676 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4677 s.segments,
4678 index_to_frame(i),
4679 ) > 0 by {
4680 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4681 if i == idx {
4682 assert(handle_count(s.frames, idx) == 1);
4683 } else {
4684 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4685 }
4686 };
4687 assert forall|i: usize|
4689 #![trigger s.regions.slot_owners[i]]
4690 i < max_meta_slots() && s.regions.slot_owners[i].usage == PageUsage::Frame && (handle_count(
4691 s.frames,
4692 i,
4693 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4694 s.segments,
4695 index_to_frame(i),
4696 ) > 0) implies {
4697 let so = s.regions.slot_owners[i];
4698 let rc = so.inner_perms.ref_count.value();
4699 &&& rc != REF_COUNT_UNUSED
4700 &&& rc != REF_COUNT_UNIQUE
4701 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4702 s.segments,
4703 index_to_frame(i),
4704 )
4705 &&& so.inner_perms.storage.is_init()
4706 } by {
4707 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4708 if i == idx {
4709 assert(handle_count(s.frames, idx) == 1);
4712 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4713 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4714 } else {
4715 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4716 }
4717 };
4718}
4719
4720proof fn step_try_from_shared<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
4727 requires
4728 old(s).inv(),
4729 old(s).frames.dom().contains(fid),
4730 ensures
4731 final(s).inv(),
4732{
4733 let ghost paddr = s.frames[fid].paddr;
4734 let ghost idx = frame_to_index(paddr);
4735 assert(has_safe_slot(paddr));
4738 s.regions.inv_implies_correct_addr(paddr);
4739 assert(s.regions.slot_owners.contains_key(idx));
4740 assert(index_to_frame(idx) == paddr);
4741 assert(s.regions.slot_owners[idx].usage == PageUsage::Frame);
4742 assert(s.frames.dom().filter(
4743 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
4744 ).contains(fid));
4745 assert(handle_count(s.frames, idx) >= 1);
4746
4747 if s.regions.slot_owners[idx].inner_perms.ref_count.value() == 1 {
4748 let ghost old_regions = s.regions;
4749 let ghost old_frames = s.frames;
4750 let ghost old_segments = s.segments;
4751 let ghost old_unique = s.unique_frames;
4752
4753 assert(handle_count(old_frames, idx) == 1);
4756 assert(s.regions.slot_owners[idx].paths_in_pt.len() == 0);
4757 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0);
4758 assert(s.regions.slot_owners[idx].paths_in_pt =~= Set::empty());
4759
4760 let tracked _fe = s.extract_frame(fid);
4762 assert(s.frames =~= old_frames.remove(fid));
4763 unique::try_from_shared_embedded(&mut s.regions, paddr);
4764
4765 let ghost uid = fresh_unique_id(s.unique_frames);
4767 lemma_fresh_unique_id_not_in_dom(s.unique_frames);
4768 let tracked ue = axiom_unique_entry_new(paddr);
4769 s.insert_unique(uid, ue);
4770 assert(s.unique_frames =~= old_unique.insert(uid, UniqueEntry { paddr }));
4771 assert(s.segments == old_segments);
4772 assert(handle_count(s.frames, idx) == 0) by {
4774 lemma_handle_count_remove(old_frames, fid, idx);
4775 };
4776
4777 assert forall|i: usize|
4779 i
4780 < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].inner_perms.in_list.value()
4781 == 0 by {
4782 if i != idx {
4783 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4784 }
4785 };
4786 assert forall|fid_other: FrameId| #[trigger]
4790 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
4791 s.frames[fid_other].paddr,
4792 )].usage == PageUsage::Frame by {
4793 let other_idx = frame_to_index(s.frames[fid_other].paddr);
4794 assert(old_frames.dom().contains(fid_other));
4795 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
4796 if other_idx != idx {
4797 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4798 }
4799 };
4800 assert forall|sid: SegmentId, paddr_c: Paddr|
4802 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4803 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4804 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4805 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
4806 == PageUsage::Frame by {
4807 let cov_idx = frame_to_index(paddr_c);
4808 assert(old_segments.dom().contains(sid));
4809 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
4810 if cov_idx != idx {
4811 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4812 }
4813 };
4814 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4816 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4817 &&& so.usage == PageUsage::Frame
4818 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4819 &&& so.inner_perms.in_list.value() == 0
4820 &&& so.paths_in_pt.is_empty()
4821 } by {
4822 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4823 if u == uid {
4824 assert(s.unique_frames[u].paddr == paddr);
4825 assert(u_idx == idx);
4826 } else {
4827 assert(old_unique.dom().contains(u));
4828 assert(s.unique_frames[u] == old_unique[u]);
4829 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value()
4831 == REF_COUNT_UNIQUE);
4832 assert(u_idx != idx);
4833 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4834 }
4835 };
4836 assert forall|u: UniqueId| #[trigger]
4837 s.unique_frames.dom().contains(u) implies has_safe_slot(s.unique_frames[u].paddr) by {
4838 if u != uid {
4839 assert(old_unique.dom().contains(u));
4840 }
4841 };
4842 assert forall|u1: UniqueId, u2: UniqueId|
4843 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4844 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4845 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4846 if u1 == uid && u2 != uid {
4847 assert(old_unique.dom().contains(u2));
4848 assert(s.unique_frames[u2].paddr == paddr);
4849 assert(frame_to_index(s.unique_frames[u2].paddr) == idx);
4850 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
4851 == REF_COUNT_UNIQUE);
4852 assert(false);
4853 } else if u2 == uid && u1 != uid {
4854 assert(old_unique.dom().contains(u1));
4855 assert(s.unique_frames[u1].paddr == paddr);
4856 assert(frame_to_index(s.unique_frames[u1].paddr) == idx);
4857 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
4858 == REF_COUNT_UNIQUE);
4859 assert(false);
4860 } else if u1 != uid && u2 != uid {
4861 assert(old_unique.dom().contains(u1));
4862 assert(old_unique.dom().contains(u2));
4863 }
4864 };
4865
4866 assert forall|i: usize|
4868 #![trigger s.regions.slot_owners[i]]
4869 i < max_meta_slots() && s.regions.slot_owners[i].inner_perms.ref_count.value()
4870 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4871 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4872 s.segments,
4873 index_to_frame(i),
4874 ) == 0 by {
4875 lemma_handle_count_remove(old_frames, fid, i);
4876 if i == idx {
4877 assert(false);
4879 } else {
4880 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4881 }
4882 };
4883 assert forall|i: usize|
4885 #![trigger s.regions.slot_owners[i]]
4886 i < max_meta_slots() && s.regions.slot_owners[i].usage == PageUsage::Frame
4887 && s.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4888 && s.regions.slot_owners[i].inner_perms.ref_count.value()
4889 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
4890 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4891 s.segments,
4892 index_to_frame(i),
4893 ) > 0 by {
4894 lemma_handle_count_remove(old_frames, fid, i);
4895 if i == idx {
4896 assert(false);
4898 } else {
4899 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4900 }
4901 };
4902 assert forall|i: usize|
4904 #![trigger s.regions.slot_owners[i]]
4905 i < max_meta_slots() && s.regions.slot_owners[i].usage == PageUsage::Frame && (
4906 handle_count(s.frames, i) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0
4907 || segment_cover_count(s.segments, index_to_frame(i)) > 0) implies {
4908 let so = s.regions.slot_owners[i];
4909 let rc = so.inner_perms.ref_count.value();
4910 &&& rc != REF_COUNT_UNUSED
4911 &&& rc != REF_COUNT_UNIQUE
4912 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4913 s.segments,
4914 index_to_frame(i),
4915 )
4916 &&& so.inner_perms.storage.is_init()
4917 } by {
4918 lemma_handle_count_remove(old_frames, fid, i);
4919 if i == idx {
4920 assert(handle_count(s.frames, idx) == 0);
4923 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4924 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4925 } else {
4926 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4927 }
4928 };
4929 }
4930}
4931
4932pub proof fn lemma_segment_cover_insert_inside(
4935 segments: Map<SegmentId, SegmentEntry>,
4936 sid: SegmentId,
4937 entry: SegmentEntry,
4938 paddr: Paddr,
4939)
4940 requires
4941 !segments.dom().contains(sid),
4942 entry.range.start <= paddr < entry.range.end,
4943 ensures
4944 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
4945 segments,
4946 paddr,
4947 ) + 1,
4948{
4949 let segments2 = segments.insert(sid, entry);
4950 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
4951 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
4952 let old_filt = segments.dom().filter(pred);
4953 let new_filt = segments2.dom().filter(pred2);
4954 assert(segments2.dom() == segments.dom().insert(sid));
4955 assert(!old_filt.contains(sid));
4956 assert(new_filt == old_filt.insert(sid)) by {
4957 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.insert(
4958 sid,
4959 ).contains(s) by {
4960 if s != sid {
4961 assert(segments2[s] == segments[s]);
4962 }
4963 };
4964 assert forall|s: SegmentId| #[trigger]
4965 old_filt.insert(sid).contains(s) implies new_filt.contains(s) by {
4966 if s == sid {
4967 assert(segments2[s].range == entry.range);
4968 } else {
4969 assert(segments2[s] == segments[s]);
4970 }
4971 };
4972 };
4973 assert(new_filt.len() == old_filt.len() + 1);
4974}
4975
4976pub proof fn lemma_segment_cover_insert_outside(
4979 segments: Map<SegmentId, SegmentEntry>,
4980 sid: SegmentId,
4981 entry: SegmentEntry,
4982 paddr: Paddr,
4983)
4984 requires
4985 !segments.dom().contains(sid),
4986 !(entry.range.start <= paddr < entry.range.end),
4987 ensures
4988 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
4989 segments,
4990 paddr,
4991 ),
4992{
4993 let segments2 = segments.insert(sid, entry);
4994 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
4995 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
4996 let old_filt = segments.dom().filter(pred);
4997 let new_filt = segments2.dom().filter(pred2);
4998 assert(segments2.dom() == segments.dom().insert(sid));
4999 assert(new_filt == old_filt) by {
5000 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.contains(
5001 s,
5002 ) by {
5003 if s == sid {
5004 assert(false);
5006 } else {
5007 assert(segments2[s] == segments[s]);
5008 }
5009 };
5010 assert forall|s: SegmentId| #[trigger] old_filt.contains(s) implies new_filt.contains(
5011 s,
5012 ) by {
5013 assert(s != sid);
5014 assert(segments2[s] == segments[s]);
5015 };
5016 };
5017}
5018
5019pub proof fn lemma_segment_cover_contains(
5022 segments: Map<SegmentId, SegmentEntry>,
5023 sid: SegmentId,
5024 paddr: Paddr,
5025)
5026 requires
5027 segments.dom().contains(sid),
5028 segments[sid].range.start <= paddr < segments[sid].range.end,
5029 ensures
5030 segment_cover_count(segments, paddr) >= 1,
5031{
5032 let filt = segments.dom().filter(
5033 |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end,
5034 );
5035 assert(filt.contains(sid));
5036}
5037
5038pub proof fn lemma_segment_cover_remove_inside(
5041 segments: Map<SegmentId, SegmentEntry>,
5042 sid: SegmentId,
5043 paddr: Paddr,
5044)
5045 requires
5046 segments.dom().contains(sid),
5047 segments[sid].range.start <= paddr < segments[sid].range.end,
5048 ensures
5049 segment_cover_count(segments.remove(sid), paddr) == (segment_cover_count(segments, paddr)
5050 - 1) as nat,
5051{
5052 let segments2 = segments.remove(sid);
5053 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
5054 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
5055 let old_filt = segments.dom().filter(pred);
5056 let new_filt = segments2.dom().filter(pred2);
5057 assert(segments2.dom() == segments.dom().remove(sid));
5058 assert(old_filt.contains(sid));
5059 assert(new_filt == old_filt.remove(sid)) by {
5060 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.remove(
5061 sid,
5062 ).contains(s) by {
5063 assert(s != sid);
5064 assert(segments2[s] == segments[s]);
5065 };
5066 assert forall|s: SegmentId| #[trigger]
5067 old_filt.remove(sid).contains(s) implies new_filt.contains(s) by {
5068 assert(s != sid);
5069 assert(segments2[s] == segments[s]);
5070 };
5071 };
5072}
5073
5074pub proof fn lemma_segment_cover_shrink_front(
5085 segments: Map<SegmentId, SegmentEntry>,
5086 sid: SegmentId,
5087 new_entry: SegmentEntry,
5088 paddr_check: Paddr,
5089)
5090 requires
5091 segments.dom().contains(sid),
5092 segments[sid].range.start < segments[sid].range.end,
5095 segments[sid].range.start % PAGE_SIZE == 0,
5097 segments[sid].range.start + PAGE_SIZE <= MAX_PADDR,
5099 new_entry.range.start == (segments[sid].range.start + PAGE_SIZE) as Paddr,
5100 new_entry.range.end == segments[sid].range.end,
5101 new_entry.range.start <= new_entry.range.end,
5102 paddr_check % PAGE_SIZE == 0,
5103 ensures
5104new_entry.range.start < new_entry.range.end ==> ({
5108 let new_segments = segments.remove(sid).insert(sid, new_entry);
5109 paddr_check == segments[sid].range.start ==> segment_cover_count(
5110 new_segments,
5111 paddr_check,
5112 ) + 1 == segment_cover_count(segments, paddr_check)
5113 }),
5114 new_entry.range.start < new_entry.range.end ==> ({
5115 let new_segments = segments.remove(sid).insert(sid, new_entry);
5116 paddr_check != segments[sid].range.start ==> segment_cover_count(
5117 new_segments,
5118 paddr_check,
5119 ) == segment_cover_count(segments, paddr_check)
5120 }),
5121 new_entry.range.start >= new_entry.range.end ==> ({
5123 let new_segments = segments.remove(sid);
5124 paddr_check == segments[sid].range.start ==> segment_cover_count(
5125 new_segments,
5126 paddr_check,
5127 ) + 1 == segment_cover_count(segments, paddr_check)
5128 }),
5129 new_entry.range.start >= new_entry.range.end ==> ({
5130 let new_segments = segments.remove(sid);
5131 paddr_check != segments[sid].range.start ==> segment_cover_count(
5132 new_segments,
5133 paddr_check,
5134 ) == segment_cover_count(segments, paddr_check)
5135 }),
5136{
5137 let popped = segments[sid].range.start;
5138 let range = segments[sid].range;
5139 assert(range.start < range.end);
5142 let sid_pre_covers = range.start <= paddr_check < range.end;
5143 let new_covers = new_entry.range.start <= paddr_check < new_entry.range.end;
5144 if sid_pre_covers {
5146 lemma_segment_cover_remove_inside(segments, sid, paddr_check);
5147 } else {
5148 lemma_segment_cover_remove_outside(segments, sid, paddr_check);
5149 }
5150 if new_entry.range.start < new_entry.range.end {
5151 let new_segments = segments.remove(sid).insert(sid, new_entry);
5152 if paddr_check == popped {
5153 assert(!new_covers);
5156 assert(sid_pre_covers);
5157 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
5158 lemma_segment_cover_contains(segments, sid, paddr_check);
5159 assert(segment_cover_count(new_segments, paddr_check) + 1 == segment_cover_count(
5160 segments,
5161 paddr_check,
5162 ));
5163 } else if sid_pre_covers {
5164 assert(new_covers);
5168 lemma_segment_cover_contains(segments, sid, paddr_check);
5169 lemma_segment_cover_insert_inside(segments.remove(sid), sid, new_entry, paddr_check);
5170 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5171 segments,
5172 paddr_check,
5173 ));
5174 } else {
5175 assert(!new_covers);
5177 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
5178 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5179 segments,
5180 paddr_check,
5181 ));
5182 }
5183 } else {
5184 let new_segments = segments.remove(sid);
5186 if paddr_check == popped {
5187 assert(sid_pre_covers);
5188 lemma_segment_cover_contains(segments, sid, paddr_check);
5189 assert(segment_cover_count(new_segments, paddr_check) + 1 == segment_cover_count(
5190 segments,
5191 paddr_check,
5192 ));
5193 } else if sid_pre_covers {
5194 assert(false);
5198 } else {
5199 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5201 segments,
5202 paddr_check,
5203 ));
5204 }
5205 }
5206}
5207
5208pub proof fn lemma_segment_cover_split(
5214 segments: Map<SegmentId, SegmentEntry>,
5215 sid: SegmentId,
5216 new_left: SegmentId,
5217 new_right: SegmentId,
5218 entry_left: SegmentEntry,
5219 entry_right: SegmentEntry,
5220 paddr: Paddr,
5221)
5222 requires
5223 segments.dom().contains(sid),
5224 new_left != sid,
5227 new_right != sid,
5228 new_left != new_right,
5229 !segments.remove(sid).dom().contains(new_left),
5230 !segments.remove(sid).dom().contains(new_right),
5231 entry_left.range.start == segments[sid].range.start,
5233 entry_left.range.end == entry_right.range.start,
5234 entry_right.range.end == segments[sid].range.end,
5235 entry_left.range.start < entry_left.range.end,
5236 entry_right.range.start < entry_right.range.end,
5237 ensures
5238 segment_cover_count(
5239 segments.remove(sid).insert(new_left, entry_left).insert(new_right, entry_right),
5240 paddr,
5241 ) == segment_cover_count(segments, paddr),
5242{
5243 let mid_segments = segments.remove(sid);
5244 let with_left = mid_segments.insert(new_left, entry_left);
5245 assert(with_left.dom() == mid_segments.dom().insert(new_left));
5246 assert(!with_left.dom().contains(new_right));
5247 let sid_covers = segments[sid].range.start <= paddr && paddr < segments[sid].range.end;
5248 let left_covers = entry_left.range.start <= paddr && paddr < entry_left.range.end;
5249 let right_covers = entry_right.range.start <= paddr && paddr < entry_right.range.end;
5250 let cover_after_remove = segment_cover_count(mid_segments, paddr);
5252 if sid_covers {
5253 lemma_segment_cover_remove_inside(segments, sid, paddr);
5254 assert(cover_after_remove == (segment_cover_count(segments, paddr) - 1) as nat);
5255 } else {
5256 lemma_segment_cover_remove_outside(segments, sid, paddr);
5257 assert(cover_after_remove == segment_cover_count(segments, paddr));
5258 }
5259 let cover_after_left = segment_cover_count(with_left, paddr);
5261 if left_covers {
5262 lemma_segment_cover_insert_inside(mid_segments, new_left, entry_left, paddr);
5263 assert(cover_after_left == cover_after_remove + 1);
5264 } else {
5265 lemma_segment_cover_insert_outside(mid_segments, new_left, entry_left, paddr);
5266 assert(cover_after_left == cover_after_remove);
5267 }
5268 let final_segments = with_left.insert(new_right, entry_right);
5270 let cover_final = segment_cover_count(final_segments, paddr);
5271 if right_covers {
5272 lemma_segment_cover_insert_inside(with_left, new_right, entry_right, paddr);
5273 assert(cover_final == cover_after_left + 1);
5274 } else {
5275 lemma_segment_cover_insert_outside(with_left, new_right, entry_right, paddr);
5276 assert(cover_final == cover_after_left);
5277 }
5278 let orig = segment_cover_count(segments, paddr);
5280 if sid_covers {
5281 lemma_segment_cover_contains(segments, sid, paddr);
5283 assert(cover_after_remove == (orig - 1) as nat);
5284 assert(cover_after_remove + 1 == orig);
5285 if left_covers {
5286 assert(!right_covers);
5287 assert(cover_after_left == cover_after_remove + 1);
5288 assert(cover_final == cover_after_left);
5289 assert(cover_final == orig);
5290 } else {
5291 assert(right_covers);
5292 assert(cover_after_left == cover_after_remove);
5293 assert(cover_final == cover_after_left + 1);
5294 assert(cover_final == cover_after_remove + 1);
5295 assert(cover_final == orig);
5296 }
5297 } else {
5298 assert(!left_covers);
5299 assert(!right_covers);
5300 assert(cover_after_remove == orig);
5301 assert(cover_after_left == cover_after_remove);
5302 assert(cover_final == cover_after_left);
5303 assert(cover_final == orig);
5304 }
5305}
5306
5307pub proof fn lemma_segment_cover_remove_outside(
5310 segments: Map<SegmentId, SegmentEntry>,
5311 sid: SegmentId,
5312 paddr: Paddr,
5313)
5314 requires
5315 segments.dom().contains(sid),
5316 !(segments[sid].range.start <= paddr < segments[sid].range.end),
5317 ensures
5318 segment_cover_count(segments.remove(sid), paddr) == segment_cover_count(segments, paddr),
5319{
5320 let segments2 = segments.remove(sid);
5321 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
5322 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
5323 let old_filt = segments.dom().filter(pred);
5324 let new_filt = segments2.dom().filter(pred2);
5325 assert(segments2.dom() == segments.dom().remove(sid));
5326 assert(!old_filt.contains(sid));
5327 assert(new_filt == old_filt) by {
5328 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.contains(
5329 s,
5330 ) by {
5331 assert(s != sid);
5332 assert(segments2[s] == segments[s]);
5333 };
5334 assert forall|s: SegmentId| #[trigger] old_filt.contains(s) implies new_filt.contains(
5335 s,
5336 ) by {
5337 assert(s != sid);
5338 assert(segments2[s] == segments[s]);
5339 };
5340 };
5341}
5342
5343pub open spec fn fresh_vm_space_id<'a>(m: Map<VmSpaceId, VmSpaceOwner>) -> VmSpaceId {
5349 choose|id: VmSpaceId| !m.dom().contains(id)
5350}
5351
5352pub open spec fn fresh_cursor_id<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>) -> CursorId {
5354 choose|id: CursorId| !m.dom().contains(id)
5355}
5356
5357pub open spec fn fresh_vm_io_id<'a>(m: Map<VmIoId, VmIoEntry>) -> VmIoId {
5359 choose|id: VmIoId| !m.dom().contains(id)
5360}
5361
5362pub open spec fn fresh_frame_id(m: Map<FrameId, FrameEntry>) -> FrameId {
5364 choose|id: FrameId| !m.dom().contains(id)
5365}
5366
5367pub proof fn lemma_fresh_vm_space_id_not_in_dom<'a>(m: Map<VmSpaceId, VmSpaceOwner>)
5368 ensures
5369 !m.dom().contains(fresh_vm_space_id(m)),
5370{
5371 lemma_finite_int_set_has_unused(m.dom());
5372}
5373
5374pub proof fn lemma_fresh_cursor_id_not_in_dom<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>)
5375 ensures
5376 !m.dom().contains(fresh_cursor_id(m)),
5377{
5378 lemma_finite_int_set_has_unused(m.dom());
5379}
5380
5381pub proof fn lemma_fresh_vm_io_id_not_in_dom<'a>(m: Map<VmIoId, VmIoEntry>)
5382 ensures
5383 !m.dom().contains(fresh_vm_io_id(m)),
5384{
5385 lemma_finite_int_set_has_unused(m.dom());
5386}
5387
5388pub proof fn lemma_fresh_frame_id_not_in_dom(m: Map<FrameId, FrameEntry>)
5389 ensures
5390 !m.dom().contains(fresh_frame_id(m)),
5391{
5392 lemma_finite_int_set_has_unused(m.dom());
5393}
5394
5395pub axiom fn axiom_cursor_entry_new<'rcu>(
5397 vm_space: VmSpaceId,
5398 kind: CursorKind,
5399 va: Range<Vaddr>,
5400 tracked owner: CursorOwner<'rcu, UserPtConfig>,
5401 tracked guards: Guards<'rcu>,
5402) -> (tracked res: CursorEntry<'rcu>)
5403 ensures
5404 res.vm_space == vm_space,
5405 res.kind == kind,
5406 res.va == va,
5407 res.owner == owner,
5408 res.guards == guards,
5409;
5410
5411pub axiom fn axiom_vm_io_entry_new<'a>(
5413 vm_space: Option<VmSpaceId>,
5414 kind: VmIoKind,
5415 vaddr: Vaddr,
5416 len: usize,
5417 tracked owner: VmIoOwner,
5418) -> (tracked res: VmIoEntry)
5419 ensures
5420 res.vm_space == vm_space,
5421 res.kind == kind,
5422 res.vaddr == vaddr,
5423 res.len == len,
5424 res.owner == owner,
5425;
5426
5427pub axiom fn axiom_frame_entry_new(paddr: Paddr) -> (tracked res: FrameEntry)
5429 ensures
5430 res.paddr == paddr,
5431;
5432
5433pub axiom fn axiom_segment_entry_new(range: Range<Paddr>) -> (tracked res: SegmentEntry)
5435 ensures
5436 res.range == range,
5437;
5438
5439pub open spec fn fresh_segment_id(m: Map<SegmentId, SegmentEntry>) -> SegmentId {
5441 choose|id: SegmentId| !m.dom().contains(id)
5442}
5443
5444pub proof fn lemma_fresh_segment_id_not_in_dom(m: Map<SegmentId, SegmentEntry>)
5445 ensures
5446 !m.dom().contains(fresh_segment_id(m)),
5447{
5448 lemma_finite_int_set_has_unused(m.dom());
5449}
5450
5451pub axiom fn axiom_unique_entry_new(paddr: Paddr) -> (tracked res: UniqueEntry)
5453 ensures
5454 res.paddr == paddr,
5455;
5456
5457pub open spec fn fresh_unique_id(m: Map<UniqueId, UniqueEntry>) -> UniqueId {
5459 choose|id: UniqueId| !m.dom().contains(id)
5460}
5461
5462pub proof fn lemma_fresh_unique_id_not_in_dom(m: Map<UniqueId, UniqueEntry>)
5463 ensures
5464 !m.dom().contains(fresh_unique_id(m)),
5465{
5466 lemma_finite_int_set_has_unused(m.dom());
5467}
5468
5469}