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::*, set_extra::*};
165
166use crate::specs::{
167 arch::*,
168 mm::{
169 frame::{
170 mapping::{frame_to_index, index_to_frame, max_meta_slots},
171 meta_owners::PageUsage,
172 meta_region_owners::MetaRegionOwners,
173 },
174 io::VmIoOwner,
175 page_table::{cursor::owners::CursorOwner, node::Guards},
176 tlb::TlbModel,
177 },
178};
179
180use crate::mm::{
181 MAX_USERSPACE_VADDR, Paddr, Vaddr,
182 frame::{
183 MetaSlot, UFrame,
184 meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
185 },
186 page_prop::PageProperty,
187 vm_space::{UserPtConfig, vm_space_specs::VmSpaceOwner},
188};
189
190verus! {
191
192broadcast use crate::specs::mm::frame::mapping::lemma_index_to_frame_biinjective;
193pub type VmSpaceId = int;
199
200pub type CursorId = int;
202
203pub type VmIoId = int;
205
206pub type FrameId = int;
208
209pub type SegmentId = int;
212
213pub type UniqueId = int;
216
217pub tracked struct FrameEntry {
224 pub ghost paddr: Paddr,
225}
226
227pub tracked struct SegmentEntry {
243 pub ghost range: Range<Paddr>,
244}
245
246pub tracked struct UniqueEntry {
254 pub ghost paddr: Paddr,
255}
256
257pub open spec fn segment_cover_count(segments: Map<SegmentId, SegmentEntry>, paddr: Paddr) -> nat {
267 segments.dom().filter(
268 |sid: SegmentId| segments[sid].range.start <= paddr && paddr < segments[sid].range.end,
269 ).len()
270}
271
272pub proof fn lemma_segment_cover_witness(
277 segments: Map<SegmentId, SegmentEntry>,
278 paddr: Paddr,
279) -> (sid: SegmentId)
280 requires
281 segment_cover_count(segments, paddr) > 0,
282 ensures
283 segments.dom().contains(sid),
284 segments[sid].range.start <= paddr < segments[sid].range.end,
285{
286 let covering = segments.dom().filter(
287 |sid: SegmentId| segments[sid].range.start <= paddr && paddr < segments[sid].range.end,
288 );
289 let sid = covering.choose();
290 assert(covering.contains(sid));
291 sid
292}
293
294pub open spec fn handle_count(frames: Map<FrameId, FrameEntry>, idx: int) -> nat {
299 frames.dom().filter(|fid: FrameId| frame_to_index(frames[fid].paddr) == idx).len()
300}
301
302pub proof fn lemma_handle_count_insert_fresh(
307 frames: Map<FrameId, FrameEntry>,
308 id: FrameId,
309 entry: FrameEntry,
310 idx: int,
311)
312 requires
313 !frames.dom().contains(id),
314 ensures
315 handle_count(frames.insert(id, entry), idx) == handle_count(frames, idx) + (
316 if frame_to_index(entry.paddr) == idx {
317 1nat
318 } else {
319 0nat
320 }),
321{
322 let frames2 = frames.insert(id, entry);
323 let new_filt = frames2.dom().filter(|fid: FrameId| frame_to_index(frames2[fid].paddr) == idx);
324 let old_filt = frames.dom().filter(|fid: FrameId| frame_to_index(frames[fid].paddr) == idx);
325 assert(frames2.dom() == frames.dom().insert(id));
326 if frame_to_index(entry.paddr) == idx {
327 assert(new_filt == old_filt.insert(id)) by {
328 assert forall|fid: FrameId| #[trigger] new_filt.contains(fid) implies old_filt.insert(
329 id,
330 ).contains(fid) by {
331 if fid != id {
332 assert(frames2[fid] == frames[fid]);
333 }
334 };
335 assert forall|fid: FrameId| #[trigger]
336 old_filt.insert(id).contains(fid) implies new_filt.contains(fid) by {
337 if fid != id {
338 assert(frames2[fid] == frames[fid]);
339 } else {
340 assert(frames2[id] == entry);
341 }
342 };
343 };
344 assert(!old_filt.contains(id));
345 assert(new_filt.len() == old_filt.len() + 1);
346 } else {
347 assert(new_filt == old_filt) by {
348 assert forall|fid: FrameId| #[trigger] new_filt.contains(fid) implies old_filt.contains(
349 fid,
350 ) by {
351 if fid != id {
352 assert(frames2[fid] == frames[fid]);
353 } else {
354 assert(frames2[id] == entry);
355 }
356 };
357 assert forall|fid: FrameId| #[trigger] old_filt.contains(fid) implies new_filt.contains(
358 fid,
359 ) by {
360 assert(fid != id);
361 assert(frames2[fid] == frames[fid]);
362 };
363 };
364 }
365}
366
367pub proof fn lemma_handle_count_remove(frames: Map<FrameId, FrameEntry>, fid: FrameId, idx: int)
371 requires
372 frames.dom().contains(fid),
373 ensures
374 handle_count(frames.remove(fid), idx) == handle_count(frames, idx) - (if frame_to_index(
375 frames[fid].paddr,
376 ) == idx {
377 1nat
378 } else {
379 0nat
380 }),
381{
382 let frames2 = frames.remove(fid);
383 let new_filt = frames2.dom().filter(|gid: FrameId| frame_to_index(frames2[gid].paddr) == idx);
384 let old_filt = frames.dom().filter(|gid: FrameId| frame_to_index(frames[gid].paddr) == idx);
385 assert(frames2.dom() == frames.dom().remove(fid));
386 if frame_to_index(frames[fid].paddr) == idx {
387 assert(old_filt.contains(fid));
388 assert(new_filt == old_filt.remove(fid)) by {
389 assert forall|gid: FrameId| #[trigger] new_filt.contains(gid) implies old_filt.remove(
390 fid,
391 ).contains(gid) by {
392 assert(gid != fid);
393 assert(frames2[gid] == frames[gid]);
394 };
395 assert forall|gid: FrameId| #[trigger]
396 old_filt.remove(fid).contains(gid) implies new_filt.contains(gid) by {
397 assert(gid != fid);
398 assert(frames2[gid] == frames[gid]);
399 };
400 };
401 assert(new_filt.len() == (old_filt.len() - 1) as nat);
402 } else {
403 assert(!old_filt.contains(fid));
404 assert(new_filt == old_filt) by {
405 assert forall|gid: FrameId| #[trigger] new_filt.contains(gid) implies old_filt.contains(
406 gid,
407 ) by {
408 assert(gid != fid);
409 assert(frames2[gid] == frames[gid]);
410 };
411 assert forall|gid: FrameId| #[trigger] old_filt.contains(gid) implies new_filt.contains(
412 gid,
413 ) by {
414 assert(gid != fid);
415 assert(frames2[gid] == frames[gid]);
416 };
417 };
418 }
419}
420
421pub proof fn lemma_frame_drop_pre_derivable<'rcu>(s: VmStore<'rcu>, fid: FrameId)
451 requires
452 s.inv(),
453 s.frames.dom().contains(fid),
454 segment_cover_count(s.segments, s.frames[fid].paddr) == 0,
455 ensures
456 frame::drop_pre(s.regions, s.frames[fid].paddr),
457 s.regions.slot_owners[frame_to_index(s.frames[fid].paddr)].inner_perms.ref_count.value()
458 == 1 ==> handle_count(s.frames, frame_to_index(s.frames[fid].paddr)) == 1,
459{
460 let paddr = s.frames[fid].paddr;
461 let idx = frame_to_index(paddr);
462 s.regions.inv_implies_correct_addr(paddr);
463 assert(s.frames.dom().filter(
464 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
465 ).contains(fid));
466}
467
468pub enum VmIoKind {
470 Reader,
471 Writer,
472}
473
474pub tracked struct VmIoEntry {
493 pub ghost vm_space: Option<VmSpaceId>,
494 pub ghost kind: VmIoKind,
495 pub ghost vaddr: Vaddr,
496 pub ghost len: usize,
497 pub owner: VmIoOwner,
498}
499
500impl VmIoEntry {
501 pub open spec fn inv(self) -> bool {
503 &&& self.owner.inv()
504 &&& match self.vm_space {
505 Some(_) => self.owner.mem_view is None,
506 None => match self.kind {
507 VmIoKind::Reader => self.owner.read_view_initialized(),
508 VmIoKind::Writer => self.owner.has_write_view(),
509 },
510 }
511 }
512
513 pub open spec fn is_kernel_reader(self) -> bool {
524 &&& self.vm_space is None
525 &&& self.kind == VmIoKind::Reader
526 }
527
528 pub open spec fn is_kernel_writer(self) -> bool {
529 &&& self.vm_space is None
530 &&& self.kind == VmIoKind::Writer
531 }
532}
533
534pub ghost enum CursorKind {
539 ReadOnly,
540 Mutable,
541}
542
543pub tracked struct CursorEntry<'rcu> {
549 pub ghost vm_space: VmSpaceId,
550 pub ghost kind: CursorKind,
551 pub ghost va: Range<Vaddr>,
552 pub owner: CursorOwner<'rcu, UserPtConfig>,
553 pub guards: Guards<'rcu>,
554}
555
556impl<'rcu> CursorEntry<'rcu> {
557 pub open spec fn inv(self) -> bool {
565 &&& self.owner.inv()
566 &&& self.owner.children_not_locked(self.guards)
567 &&& self.owner.nodes_locked(self.guards)
568 &&& !self.owner.popped_too_high
569 }
570}
571
572pub tracked struct VmStore<'rcu> {
580 pub regions: MetaRegionOwners,
581 pub tlb_model: TlbModel,
582 pub vm_spaces: Map<VmSpaceId, VmSpaceOwner>,
583 pub cursors: Map<CursorId, CursorEntry<'rcu>>,
584 pub vm_ios: Map<VmIoId, VmIoEntry>,
585 pub frames: Map<FrameId, FrameEntry>,
586 pub segments: Map<SegmentId, SegmentEntry>,
587 pub unique_frames: Map<UniqueId, UniqueEntry>,
588}
589
590impl<'a, 'rcu> VmStore<'rcu> {
591 pub open spec fn inv(self) -> bool {
602 self.structural_inv() && self.accounting_inv()
603 }
604
605 pub open spec fn structural_inv(self) -> bool {
611 &&& self.regions.inv()
612 &&& forall|idx: int|
645 0 <= idx < max_meta_slots() ==> #[trigger] self.regions.slots.contains_key(idx) || (
646 self.regions.slot_owners[idx].usage is PageTable
647 && self.regions.slot_owners[idx].inner_perms.ref_count.value()
648 != REF_COUNT_UNUSED)
649 &&& forall|idx: int|
654 0 <= idx < max_meta_slots()
655 ==> #[trigger] self.regions.slot_owners[idx].inner_perms.in_list.value() == 0
656 &&& self.tlb_model.inv()
657 &&& forall|id: VmSpaceId| #[trigger]
658 self.vm_spaces.dom().contains(id) ==> self.vm_spaces[id].inv()
659 &&& forall|id: CursorId| #[trigger]
660 self.cursors.dom().contains(id) ==> self.cursors[id].inv()
661 &&& forall|id: CursorId| #[trigger]
662 self.cursors.dom().contains(id) ==> self.cursors[id].owner.metaregion_sound(
663 self.regions,
664 )
665 &&& forall|id: CursorId| #[trigger]
666 self.cursors.dom().contains(id) ==> self.vm_spaces.dom().contains(
667 self.cursors[id].vm_space,
668 )
669 &&& forall|id: VmIoId| #[trigger] self.vm_ios.dom().contains(id) ==> self.vm_ios[id].inv()
670 &&& forall|id: VmIoId| #[trigger]
671 self.vm_ios.dom().contains(id) ==> (self.vm_ios[id].vm_space matches Some(vs)
672 ==> self.vm_spaces.dom().contains(vs))
673 &&& forall|id: VmIoId| #[trigger]
674 self.vm_ios.dom().contains(id) ==> self.vm_ios[id].vm_space is Some ==> (
675 self.vm_ios[id].vaddr as nat) + (self.vm_ios[id].len as nat)
676 <= MAX_USERSPACE_VADDR as nat
677 &&& forall|fid: FrameId| #[trigger]
687 self.frames.dom().contains(fid) ==> valid_frame_paddr(
688 self.frames[fid].paddr,
689 )
690 &&& forall|fid: FrameId| #[trigger]
699 self.frames.dom().contains(fid) ==> self.regions.slot_owners[frame_to_index(
700 self.frames[fid].paddr,
701 )].usage is Frame
702 &&& forall|sid: SegmentId| #[trigger]
708 self.segments.dom().contains(sid) ==> {
709 let r = self.segments[sid].range;
710 &&& r.start % PAGE_SIZE == 0
711 &&& r.end % PAGE_SIZE == 0
712 &&& r.start < r.end
713 &&& r.end <= MAX_PADDR
714 }
715 &&& forall|sid: SegmentId, paddr: Paddr|
723 #![trigger
724 self.segments.dom().contains(sid),
725 frame_to_index(paddr)]
726 self.segments.dom().contains(sid) && self.segments[sid].range.start <= paddr
727 < self.segments[sid].range.end && paddr % PAGE_SIZE == 0
728 ==> self.regions.slot_owners[frame_to_index(
729 paddr,
730 )].usage is Frame
731 &&& forall|uid: UniqueId| #[trigger]
736 self.unique_frames.dom().contains(uid) ==> valid_frame_paddr(
737 self.unique_frames[uid].paddr,
738 )
739 &&& forall|uid: UniqueId| #[trigger]
744 self.unique_frames.dom().contains(uid) ==> {
745 let so = self.regions.slot_owners[frame_to_index(self.unique_frames[uid].paddr)];
746 &&& so.usage is Frame
747 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
748 &&& so.inner_perms.in_list.value() == 0
749 &&& so.paths_in_pt.is_empty()
750 }
751 &&& forall|uid1: UniqueId, uid2: UniqueId|
755 #![trigger
756 self.unique_frames.dom().contains(uid1),
757 self.unique_frames.dom().contains(uid2)]
758 self.unique_frames.dom().contains(uid1) && self.unique_frames.dom().contains(uid2)
759 && self.unique_frames[uid1].paddr == self.unique_frames[uid2].paddr ==> uid1 == uid2
760 }
761
762 pub open spec fn accounting_inv(self) -> bool {
792 &&& forall|idx: int|
831 #![trigger self.regions.slot_owners[idx]]
832 0 <= idx < max_meta_slots()
833 && self.regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED
834 ==> handle_count(self.frames, idx) == 0
835 && self.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
836 self.segments,
837 index_to_frame(idx),
838 )
839 == 0
840 &&& forall|idx: int|
845 #![trigger self.regions.slot_owners[idx]]
846 0 <= idx < max_meta_slots() && self.regions.slot_owners[idx].usage is Frame
847 && self.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
848 && self.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE
849 ==> handle_count(self.frames, idx) > 0
850 || self.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
851 self.segments,
852 index_to_frame(idx),
853 )
854 > 0
855 &&& forall|idx: int|
863 #![trigger self.regions.slot_owners[idx]]
864 0 <= idx < max_meta_slots() && self.regions.slot_owners[idx].usage is Frame && (
865 handle_count(self.frames, idx) > 0 || self.regions.slot_owners[idx].paths_in_pt.len()
866 > 0 || segment_cover_count(self.segments, index_to_frame(idx)) > 0) ==> {
867 let so = self.regions.slot_owners[idx];
868 let rc = so.inner_perms.ref_count.value();
869 &&& rc != REF_COUNT_UNUSED
870 &&& rc != REF_COUNT_UNIQUE
871 &&& rc == handle_count(self.frames, idx) + so.paths_in_pt.len()
872 + segment_cover_count(self.segments, index_to_frame(idx))
873 &&& so.inner_perms.storage.is_init()
874 }
875 }
876}
877
878pub enum Op {
884 NewVmSpace,
885 DropVmSpace { vs: VmSpaceId },
886 OpenCursor { vs: VmSpaceId, va: Range<Vaddr> },
887 OpenCursorMut { vs: VmSpaceId, va: Range<Vaddr> },
888 DropCursor { c: CursorId },
889 Query { c: CursorId },
890 FindNext { c: CursorId, len: usize },
891 Jump { c: CursorId, va: Vaddr },
892 VirtAddr { c: CursorId },
893 Map { c: CursorId, fid: FrameId, prop: PageProperty },
894 Unmap { c: CursorId, len: usize },
895 ProtectNext { c: CursorId, len: usize },
896 NewReader { vs: VmSpaceId, vaddr: Vaddr, len: usize },
897 NewWriter { vs: VmSpaceId, vaddr: Vaddr, len: usize },
898 NewKernelReader { vaddr: Vaddr, len: usize },
899 NewKernelWriter { vaddr: Vaddr, len: usize },
900 DropReader { vio: VmIoId },
901 DropWriter { vio: VmIoId },
902 ReaderReadVal { source: VmIoId },
906 ReaderCollect { source: VmIoId },
908 ReaderLimit { vio: VmIoId, max: usize },
909 ReaderSkip { vio: VmIoId, n: usize },
910 ReaderQuery { vio: VmIoId },
911 WriterWriteVal { writer: VmIoId },
913 WriterFillZeros { vio: VmIoId, len: usize },
914 WriterLimit { vio: VmIoId, max: usize },
915 WriterSkip { vio: VmIoId, n: usize },
916 WriterQuery { vio: VmIoId },
917 Read { source: VmIoId, dest: VmIoId },
920 Write { source: VmIoId, dest: VmIoId },
923 FrameFromUnused { paddr: Paddr },
926 FrameFromInUse { paddr: Paddr },
930 FrameDrop { fid: FrameId },
936 SegmentFromUnused { range: Range<Paddr> },
941 SegmentDrop { sid: SegmentId },
945 SegmentSplit { sid: SegmentId, offset: usize },
952 SegmentNext { sid: SegmentId },
961 SegmentClone { sid: SegmentId },
967 SegmentSlice { sid: SegmentId, sub_range: Range<Paddr> },
974 UniqueFromUnused { paddr: Paddr },
979 UniqueDrop { uid: UniqueId },
983 FromUnique { uid: UniqueId },
988 TryFromShared { fid: FrameId },
994}
995
996pub open spec fn op_pre<'rcu>(s: VmStore<'rcu>, op: Op) -> bool {
1014 match op {
1015 Op::NewVmSpace => true,
1016 Op::DropVmSpace { vs } => s.vm_spaces.dom().contains(vs) && (forall|c: CursorId| #[trigger]
1017 s.cursors.dom().contains(c) ==> s.cursors[c].vm_space != vs) && (forall|v: VmIoId|
1018 #[trigger]
1019 s.vm_ios.dom().contains(v) ==> s.vm_ios[v].vm_space != Some(vs)),
1020 Op::OpenCursor { vs, va: _ } => s.vm_spaces.dom().contains(vs),
1021 Op::OpenCursorMut { vs, va: _ } => s.vm_spaces.dom().contains(vs),
1022 Op::DropCursor { c } => s.cursors.dom().contains(c),
1023 Op::Query { c } => s.cursors.dom().contains(c),
1024 Op::FindNext { c, len: _ } => s.cursors.dom().contains(c),
1025 Op::Jump { c, va: _ } => s.cursors.dom().contains(c),
1026 Op::VirtAddr { c } => s.cursors.dom().contains(c),
1027 Op::Map { c, fid, prop: _ } => s.cursors.dom().contains(c) && s.frames.dom().contains(fid),
1040 Op::Unmap { c, len: _ } => s.cursors.dom().contains(c),
1041 Op::ProtectNext { c, len: _ } => s.cursors.dom().contains(c),
1042 Op::NewReader { vs, vaddr: _, len: _ } => s.vm_spaces.dom().contains(vs),
1043 Op::NewWriter { vs, vaddr: _, len: _ } => s.vm_spaces.dom().contains(vs),
1044 Op::NewKernelReader { vaddr: _, len: _ } => true,
1045 Op::NewKernelWriter { vaddr: _, len: _ } => true,
1046 Op::DropReader { vio } => s.vm_ios.dom().contains(vio),
1047 Op::DropWriter { vio } => s.vm_ios.dom().contains(vio),
1048 Op::ReaderReadVal { source } => s.vm_ios.dom().contains(source),
1049 Op::ReaderCollect { source } => s.vm_ios.dom().contains(source),
1050 Op::ReaderLimit { vio, max: _ } => s.vm_ios.dom().contains(vio),
1051 Op::ReaderSkip { vio, n: _ } => s.vm_ios.dom().contains(vio),
1052 Op::ReaderQuery { vio } => s.vm_ios.dom().contains(vio),
1053 Op::WriterWriteVal { writer } => s.vm_ios.dom().contains(writer),
1054 Op::WriterFillZeros { vio, len: _ } => s.vm_ios.dom().contains(vio),
1055 Op::WriterLimit { vio, max: _ } => s.vm_ios.dom().contains(vio),
1056 Op::WriterSkip { vio, n: _ } => s.vm_ios.dom().contains(vio),
1057 Op::WriterQuery { vio } => s.vm_ios.dom().contains(vio),
1058 Op::Read { source, dest } => s.vm_ios.dom().contains(source) && s.vm_ios.dom().contains(
1064 dest,
1065 ) && source != dest && s.vm_ios[source].is_kernel_reader()
1066 && s.vm_ios[dest].is_kernel_writer(),
1067 Op::Write { source, dest } => s.vm_ios.dom().contains(source) && s.vm_ios.dom().contains(
1069 dest,
1070 ) && source != dest && s.vm_ios[source].is_kernel_reader()
1071 && s.vm_ios[dest].is_kernel_writer(),
1072 Op::FrameFromUnused { paddr: _ } => true,
1073 Op::FrameFromInUse { paddr: _ } => true,
1074 Op::FrameDrop { fid } => s.frames.dom().contains(fid) && segment_cover_count(
1091 s.segments,
1092 s.frames[fid].paddr,
1093 ) == 0,
1094 Op::SegmentFromUnused { range: _ } => true,
1101 Op::SegmentDrop { sid } => s.segments.dom().contains(sid),
1107 Op::SegmentSplit { sid, offset } => s.segments.dom().contains(sid) && offset % PAGE_SIZE
1112 == 0 && 0 < offset && offset < (s.segments[sid].range.end
1113 - s.segments[sid].range.start),
1114 Op::SegmentNext { sid } => s.segments.dom().contains(sid),
1117 Op::SegmentClone { sid } => s.segments.dom().contains(sid) && forall|paddr: Paddr|
1118 #![trigger frame_to_index(paddr)]
1119 (s.segments[sid].range.start <= paddr < s.segments[sid].range.end && paddr % PAGE_SIZE
1120 == 0) ==> s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value()
1121 + 1 <= REF_COUNT_MAX,
1122 Op::SegmentSlice { sid, sub_range } => s.segments.dom().contains(sid) && sub_range.start
1128 % PAGE_SIZE == 0 && sub_range.end % PAGE_SIZE == 0 && s.segments[sid].range.start
1129 <= sub_range.start && sub_range.start < sub_range.end && sub_range.end
1130 <= s.segments[sid].range.end && forall|paddr: Paddr|
1131 #![trigger frame_to_index(paddr)]
1132 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0)
1133 ==> s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1
1134 <= REF_COUNT_MAX,
1135 Op::UniqueFromUnused { paddr: _ } => true,
1142 Op::UniqueDrop { uid } => s.unique_frames.dom().contains(uid),
1147 Op::FromUnique { uid } => s.unique_frames.dom().contains(uid),
1150 Op::TryFromShared { fid } => s.frames.dom().contains(fid),
1154 }
1155}
1156
1157impl<'rcu> VmStore<'rcu> {
1162 pub proof fn extract_vm_space(tracked &mut self, vs: VmSpaceId) -> (tracked res: VmSpaceOwner)
1167 requires
1168 old(self).inv(),
1169 old(self).vm_spaces.dom().contains(vs),
1170 forall|c: CursorId| #[trigger]
1171 old(self).cursors.dom().contains(c) ==> old(self).cursors[c].vm_space != vs,
1172 forall|v: VmIoId| #[trigger]
1173 old(self).vm_ios.dom().contains(v) ==> old(self).vm_ios[v].vm_space != Some(vs),
1174 ensures
1175 final(self).regions == old(self).regions,
1176 final(self).tlb_model == old(self).tlb_model,
1177 final(self).vm_spaces == old(self).vm_spaces.remove(vs),
1178 final(self).cursors == old(self).cursors,
1179 final(self).vm_ios == old(self).vm_ios,
1180 final(self).frames == old(self).frames,
1181 final(self).segments == old(self).segments,
1182 final(self).unique_frames == old(self).unique_frames,
1183 res == old(self).vm_spaces[vs],
1184 final(self).inv(),
1185 {
1186 self.vm_spaces.tracked_remove(vs)
1187 }
1188
1189 pub proof fn insert_vm_space(tracked &mut self, vs: VmSpaceId, tracked owner: VmSpaceOwner)
1192 requires
1193 old(self).inv(),
1194 !old(self).vm_spaces.dom().contains(vs),
1195 owner.inv(),
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.insert(vs, owner),
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 final(self).inv(),
1206 {
1207 self.vm_spaces.tracked_insert(vs, owner);
1208 }
1209
1210 pub proof fn extract_cursor(tracked &mut self, c: CursorId) -> (tracked res: CursorEntry<'rcu>)
1212 requires
1213 old(self).inv(),
1214 old(self).cursors.dom().contains(c),
1215 ensures
1216 final(self).regions == old(self).regions,
1217 final(self).tlb_model == old(self).tlb_model,
1218 final(self).vm_spaces == old(self).vm_spaces,
1219 final(self).cursors == old(self).cursors.remove(c),
1220 final(self).vm_ios == old(self).vm_ios,
1221 final(self).frames == old(self).frames,
1222 final(self).segments == old(self).segments,
1223 final(self).unique_frames == old(self).unique_frames,
1224 res == old(self).cursors[c],
1225 final(self).inv(),
1226 {
1227 self.cursors.tracked_remove(c)
1228 }
1229
1230 pub proof fn insert_cursor(tracked &mut self, c: CursorId, tracked entry: CursorEntry<'rcu>)
1235 requires
1236 old(self).inv(),
1237 !old(self).cursors.dom().contains(c),
1238 entry.inv(),
1239 entry.owner.metaregion_sound(old(self).regions),
1240 old(self).vm_spaces.dom().contains(entry.vm_space),
1241 ensures
1242 final(self).regions == old(self).regions,
1243 final(self).tlb_model == old(self).tlb_model,
1244 final(self).vm_spaces == old(self).vm_spaces,
1245 final(self).cursors == old(self).cursors.insert(c, entry),
1246 final(self).vm_ios == old(self).vm_ios,
1247 final(self).frames == old(self).frames,
1248 final(self).segments == old(self).segments,
1249 final(self).unique_frames == old(self).unique_frames,
1250 final(self).inv(),
1251 {
1252 self.cursors.tracked_insert(c, entry);
1253 }
1254
1255 pub proof fn extract_vm_io(tracked &mut self, vio: VmIoId) -> (tracked res: VmIoEntry)
1257 requires
1258 old(self).inv(),
1259 old(self).vm_ios.dom().contains(vio),
1260 ensures
1261 final(self).regions == old(self).regions,
1262 final(self).tlb_model == old(self).tlb_model,
1263 final(self).vm_spaces == old(self).vm_spaces,
1264 final(self).cursors == old(self).cursors,
1265 final(self).vm_ios == old(self).vm_ios.remove(vio),
1266 final(self).frames == old(self).frames,
1267 final(self).segments == old(self).segments,
1268 final(self).unique_frames == old(self).unique_frames,
1269 res == old(self).vm_ios[vio],
1270 final(self).inv(),
1271 {
1272 self.vm_ios.tracked_remove(vio)
1273 }
1274
1275 pub proof fn insert_vm_io(tracked &mut self, vio: VmIoId, tracked entry: VmIoEntry)
1283 requires
1284 old(self).inv(),
1285 !old(self).vm_ios.dom().contains(vio),
1286 entry.inv(),
1287 entry.vm_space matches Some(vs) ==> old(self).vm_spaces.dom().contains(vs),
1288 entry.vm_space is Some ==> (entry.vaddr as nat) + (entry.len as nat)
1289 <= MAX_USERSPACE_VADDR as nat,
1290 ensures
1291 final(self).regions == old(self).regions,
1292 final(self).tlb_model == old(self).tlb_model,
1293 final(self).vm_spaces == old(self).vm_spaces,
1294 final(self).cursors == old(self).cursors,
1295 final(self).vm_ios == old(self).vm_ios.insert(vio, entry),
1296 final(self).frames == old(self).frames,
1297 final(self).segments == old(self).segments,
1298 final(self).unique_frames == old(self).unique_frames,
1299 final(self).inv(),
1300 {
1301 self.vm_ios.tracked_insert(vio, entry);
1302 }
1303
1304 pub proof fn extract_frame(tracked &mut self, fid: FrameId) -> (tracked res: FrameEntry)
1313 requires
1314 old(self).structural_inv(),
1315 old(self).frames.dom().contains(fid),
1316 ensures
1317 final(self).regions == old(self).regions,
1318 final(self).tlb_model == old(self).tlb_model,
1319 final(self).vm_spaces == old(self).vm_spaces,
1320 final(self).cursors == old(self).cursors,
1321 final(self).vm_ios == old(self).vm_ios,
1322 final(self).frames == old(self).frames.remove(fid),
1323 final(self).segments == old(self).segments,
1324 final(self).unique_frames == old(self).unique_frames,
1325 res == old(self).frames[fid],
1326 final(self).structural_inv(),
1327 {
1328 self.frames.tracked_remove(fid)
1329 }
1330
1331 pub proof fn insert_frame(tracked &mut self, fid: FrameId, tracked entry: FrameEntry)
1340 requires
1341 old(self).structural_inv(),
1342 !old(self).frames.dom().contains(fid),
1343 valid_frame_paddr(entry.paddr),
1344 old(self).regions.slot_owners[frame_to_index(entry.paddr)].usage is Frame,
1349 ensures
1350 final(self).regions == old(self).regions,
1351 final(self).tlb_model == old(self).tlb_model,
1352 final(self).vm_spaces == old(self).vm_spaces,
1353 final(self).cursors == old(self).cursors,
1354 final(self).vm_ios == old(self).vm_ios,
1355 final(self).frames == old(self).frames.insert(fid, entry),
1356 final(self).segments == old(self).segments,
1357 final(self).unique_frames == old(self).unique_frames,
1358 final(self).structural_inv(),
1359 {
1360 self.frames.tracked_insert(fid, entry);
1361 }
1362
1363 pub proof fn extract_unique(tracked &mut self, uid: UniqueId) -> (tracked res: UniqueEntry)
1367 requires
1368 old(self).unique_frames.dom().contains(uid),
1369 ensures
1370 final(self).regions == old(self).regions,
1371 final(self).tlb_model == old(self).tlb_model,
1372 final(self).vm_spaces == old(self).vm_spaces,
1373 final(self).cursors == old(self).cursors,
1374 final(self).vm_ios == old(self).vm_ios,
1375 final(self).frames == old(self).frames,
1376 final(self).segments == old(self).segments,
1377 final(self).unique_frames == old(self).unique_frames.remove(uid),
1378 res == old(self).unique_frames[uid],
1379 {
1380 self.unique_frames.tracked_remove(uid)
1381 }
1382
1383 pub proof fn insert_unique(tracked &mut self, uid: UniqueId, tracked entry: 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.insert(uid, entry),
1400 {
1401 self.unique_frames.tracked_insert(uid, entry);
1402 }
1403
1404 pub proof fn extract_segment(tracked &mut self, sid: SegmentId) -> (tracked res: SegmentEntry)
1411 requires
1412 old(self).segments.dom().contains(sid),
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.remove(sid),
1421 final(self).unique_frames == old(self).unique_frames,
1422 res == old(self).segments[sid],
1423 {
1424 self.segments.tracked_remove(sid)
1425 }
1426
1427 pub proof fn insert_segment(tracked &mut self, sid: SegmentId, tracked entry: SegmentEntry)
1432 requires
1433 !old(self).segments.dom().contains(sid),
1434 ensures
1435 final(self).regions == old(self).regions,
1436 final(self).tlb_model == old(self).tlb_model,
1437 final(self).vm_spaces == old(self).vm_spaces,
1438 final(self).cursors == old(self).cursors,
1439 final(self).vm_ios == old(self).vm_ios,
1440 final(self).frames == old(self).frames,
1441 final(self).segments == old(self).segments.insert(sid, entry),
1442 final(self).unique_frames == old(self).unique_frames,
1443 {
1444 self.segments.tracked_insert(sid, entry);
1445 }
1446}
1447
1448pub proof fn step<'rcu>(tracked s: &mut VmStore<'rcu>, op: Op)
1458 requires
1459 old(s).inv(),
1460 op_pre(*old(s), op),
1461 ensures
1462 final(s).inv(),
1463{
1464 match op {
1465 Op::NewVmSpace => step_new_vm_space(s),
1466 Op::DropVmSpace { vs } => step_drop_vm_space(s, vs),
1467 Op::OpenCursor { vs, va } => step_open_cursor(s, vs, va),
1468 Op::OpenCursorMut { vs, va } => step_open_cursor_mut(s, vs, va),
1469 Op::DropCursor { c } => step_drop_cursor(s, c),
1470 Op::Query { c } => step_query(s, c),
1471 Op::FindNext { c, len } => step_find_next(s, c, len),
1472 Op::Jump { c, va } => step_jump(s, c, va),
1473 Op::VirtAddr { c: _ } => {},
1474 Op::Map { c, fid, prop } => step_map(s, c, fid, prop),
1475 Op::Unmap { c, len } => step_unmap(s, c, len),
1476 Op::ProtectNext { c, len } => step_protect_next(s, c, len),
1477 Op::NewReader { vs, vaddr, len } => step_new_vm_io(s, vs, vaddr, len, VmIoKind::Reader),
1478 Op::NewWriter { vs, vaddr, len } => step_new_vm_io(s, vs, vaddr, len, VmIoKind::Writer),
1479 Op::NewKernelReader { vaddr, len } => step_new_kernel_vm_io(
1480 s,
1481 vaddr,
1482 len,
1483 VmIoKind::Reader,
1484 ),
1485 Op::NewKernelWriter { vaddr, len } => step_new_kernel_vm_io(
1486 s,
1487 vaddr,
1488 len,
1489 VmIoKind::Writer,
1490 ),
1491 Op::DropReader { vio } => step_drop_vm_io(s, vio),
1492 Op::DropWriter { vio } => step_drop_vm_io(s, vio),
1493 Op::ReaderReadVal { source: _ } => {},
1495 Op::ReaderCollect { source: _ } => {},
1496 Op::WriterWriteVal { writer: _ } => {},
1497 Op::ReaderLimit { vio, max } => step_vm_io_method(s, vio, io::VmIoMethod::ReaderLimit(max)),
1498 Op::ReaderSkip { vio, n } => step_vm_io_method(s, vio, io::VmIoMethod::ReaderSkip(n)),
1499 Op::ReaderQuery { vio: _ } => {},
1500 Op::WriterFillZeros { vio, len } => step_vm_io_method(
1501 s,
1502 vio,
1503 io::VmIoMethod::WriterFillZeros(len),
1504 ),
1505 Op::WriterLimit { vio, max } => step_vm_io_method(s, vio, io::VmIoMethod::WriterLimit(max)),
1506 Op::WriterSkip { vio, n } => step_vm_io_method(s, vio, io::VmIoMethod::WriterSkip(n)),
1507 Op::WriterQuery { vio: _ } => {},
1508 Op::Read { source, dest } => step_read(s, source, dest),
1510 Op::Write { source, dest } => step_write(s, source, dest),
1513 Op::FrameFromUnused { paddr } => step_frame_from_unused(s, paddr),
1514 Op::FrameFromInUse { paddr } => step_frame_from_in_use(s, paddr),
1515 Op::FrameDrop { fid } => step_frame_drop(s, fid),
1516 Op::SegmentFromUnused { range } => step_segment_from_unused(s, range),
1517 Op::SegmentDrop { sid } => step_segment_drop(s, sid),
1518 Op::SegmentSplit { sid, offset } => step_segment_split(s, sid, offset),
1519 Op::SegmentNext { sid } => step_segment_next(s, sid),
1520 Op::SegmentClone { sid } => step_segment_clone(s, sid),
1521 Op::SegmentSlice { sid, sub_range } => step_segment_slice(s, sid, sub_range),
1522 Op::UniqueFromUnused { paddr } => step_unique_from_unused(s, paddr),
1523 Op::UniqueDrop { uid } => step_unique_drop(s, uid),
1524 Op::FromUnique { uid } => step_from_unique(s, uid),
1525 Op::TryFromShared { fid } => step_try_from_shared(s, fid),
1526 }
1527}
1528
1529proof fn lemma_accounting_preserved_by_pt_alloc<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1545 requires
1546 s_old.inv(),
1547 s_new.frames == s_old.frames,
1548 s_new.segments == s_old.segments,
1550 forall|i: int|
1551 #![trigger s_new.regions.slot_owners[i]]
1552 s_new.regions.slot_owners[i] != s_old.regions.slot_owners[i] ==> {
1553 &&& s_old.regions.slot_owners[i].inner_perms.ref_count.value() == REF_COUNT_UNUSED
1554 &&& s_new.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1555 &&& s_new.regions.slot_owners[i].usage !is Frame
1556 },
1557 ensures
1558 s_new.accounting_inv(),
1559 forall|fid: FrameId| #[trigger]
1564 s_new.frames.dom().contains(fid) ==> s_new.regions.slot_owners[frame_to_index(
1565 s_new.frames[fid].paddr,
1566 )].usage is Frame,
1567 forall|sid: SegmentId, paddr: Paddr|
1569 #![trigger
1570 s_new.segments.dom().contains(sid),
1571 frame_to_index(paddr)]
1572 s_new.segments.dom().contains(sid) && s_new.segments[sid].range.start <= paddr
1573 < s_new.segments[sid].range.end && paddr % PAGE_SIZE == 0
1574 ==> s_new.regions.slot_owners[frame_to_index(paddr)].usage is Frame,
1575{
1576 assert forall|idx: int|
1579 #![trigger s_new.regions.slot_owners[idx]]
1580 0 <= idx < max_meta_slots() && s_new.regions.slot_owners[idx].inner_perms.ref_count.value()
1581 == REF_COUNT_UNUSED implies handle_count(s_new.frames, idx) == 0
1582 && s_new.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1583 s_new.segments,
1584 index_to_frame(idx),
1585 ) == 0 by {
1586 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1587 };
1588 assert forall|idx: int|
1591 #![trigger s_new.regions.slot_owners[idx]]
1592 0 <= idx < max_meta_slots() && s_new.regions.slot_owners[idx].usage is Frame
1593 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1594 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value()
1595 != REF_COUNT_UNIQUE implies handle_count(s_new.frames, idx) > 0
1596 || s_new.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1597 s_new.segments,
1598 index_to_frame(idx),
1599 ) > 0 by {
1600 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1601 };
1602 assert forall|idx: int|
1605 #![trigger s_new.regions.slot_owners[idx]]
1606 0 <= idx < max_meta_slots() && s_new.regions.slot_owners[idx].usage is Frame && (
1607 handle_count(s_new.frames, idx) > 0 || s_new.regions.slot_owners[idx].paths_in_pt.len() > 0
1608 || segment_cover_count(s_new.segments, index_to_frame(idx)) > 0) implies {
1609 let so = s_new.regions.slot_owners[idx];
1610 let rc = so.inner_perms.ref_count.value();
1611 &&& rc != REF_COUNT_UNUSED
1612 &&& rc != REF_COUNT_UNIQUE
1613 &&& rc == handle_count(s_new.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1614 s_new.segments,
1615 index_to_frame(idx),
1616 )
1617 &&& so.inner_perms.storage.is_init()
1618 } by {
1619 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1620 };
1621 assert forall|sid: SegmentId, paddr: Paddr|
1626 #![trigger
1627 s_new.segments.dom().contains(sid),
1628 frame_to_index(paddr)]
1629 s_new.segments.dom().contains(sid) && s_new.segments[sid].range.start <= paddr
1630 < s_new.segments[sid].range.end && paddr % PAGE_SIZE
1631 == 0 implies s_new.regions.slot_owners[frame_to_index(paddr)].usage is Frame by {
1632 let idx = frame_to_index(paddr);
1633 assert(s_old.regions.slot_owners[idx].usage is Frame);
1635 lemma_segment_cover_contains(s_old.segments, sid, paddr);
1638 assert(s_old.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
1639 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1641 };
1642 assert forall|fid: FrameId| #[trigger]
1648 s_new.frames.dom().contains(fid) implies s_new.regions.slot_owners[frame_to_index(
1649 s_new.frames[fid].paddr,
1650 )].usage is Frame by {
1651 let idx = frame_to_index(s_new.frames[fid].paddr);
1652 assert(s_old.frames.dom().filter(
1654 |gid: FrameId| frame_to_index(s_old.frames[gid].paddr) == idx,
1655 ).contains(fid));
1656 assert(handle_count(s_old.frames, idx) >= 1);
1657 assert(s_old.regions.slot_owners[idx].usage is Frame);
1659 assert(s_old.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
1660 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1663 };
1664}
1665
1666proof fn lemma_coverage_preserved_slots_eq<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1674 requires
1675 s_old.structural_inv(),
1676 s_new.regions.slots == s_old.regions.slots,
1677 forall|idx: int|
1678 #![trigger s_new.regions.slot_owners[idx]]
1679 !s_old.regions.slots.contains_key(idx) ==> s_new.regions.slot_owners[idx]
1680 == s_old.regions.slot_owners[idx],
1681 ensures
1682 forall|idx: int|
1683 0 <= idx < max_meta_slots() ==> #[trigger] s_new.regions.slots.contains_key(idx) || (
1684 s_new.regions.slot_owners[idx].usage is PageTable
1685 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value()
1686 != REF_COUNT_UNUSED),
1687{
1688 assert forall|idx: int|
1689 0 <= idx < max_meta_slots() implies #[trigger] s_new.regions.slots.contains_key(idx) || (
1690 s_new.regions.slot_owners[idx].usage is PageTable
1691 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED) by {
1692 if !s_new.regions.slots.contains_key(idx) {
1693 assert(!s_old.regions.slots.contains_key(idx));
1696 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1697 }
1698 };
1699}
1700
1701proof fn step_new_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>)
1702 requires
1703 old(s).inv(),
1704 ensures
1705 final(s).inv(),
1706{
1707 let ghost s_before = *s;
1708 let tracked owner = vm_space::new_vm_space_step(&mut s.regions);
1709 let ghost id = fresh_vm_space_id(s.vm_spaces);
1710 lemma_fresh_vm_space_id_not_in_dom(s.vm_spaces);
1711 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1714 let ghost root_idx = vm_space::vm_space_root_idx(owner);
1720 assert forall|idx: int|
1721 0 <= idx < max_meta_slots() implies #[trigger] s.regions.slots.contains_key(idx) || (
1722 s.regions.slot_owners[idx].usage is PageTable
1723 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED) by {
1724 if idx == root_idx {
1725 } else {
1727 assert(s.regions.slots.contains_key(idx) == s_before.regions.slots.contains_key(idx));
1730 if s.regions.slot_owners[idx] != s_before.regions.slot_owners[idx] {
1731 assert(s_before.regions.slot_owners[idx].inner_perms.ref_count.value()
1735 == REF_COUNT_UNUSED);
1736 assert(s_before.regions.slots.contains_key(idx));
1737 }
1738 }
1739 };
1740 s.insert_vm_space(id, owner);
1741}
1742
1743proof fn step_drop_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId)
1744 requires
1745 old(s).inv(),
1746 old(s).vm_spaces.dom().contains(vs),
1747 forall|c: CursorId| #[trigger]
1748 old(s).cursors.dom().contains(c) ==> old(s).cursors[c].vm_space != vs,
1749 forall|v: VmIoId| #[trigger]
1750 old(s).vm_ios.dom().contains(v) ==> old(s).vm_ios[v].vm_space != Some(vs),
1751 ensures
1752 final(s).inv(),
1753{
1754 let tracked owner = s.extract_vm_space(vs);
1755 vm_space::drop_vm_space_step(owner);
1756}
1757
1758proof fn step_open_cursor<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId, va: Range<Vaddr>)
1759 requires
1760 old(s).inv(),
1761 old(s).vm_spaces.dom().contains(vs),
1762 ensures
1763 final(s).inv(),
1764{
1765 let ghost s_before = *s;
1766 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1767 let tracked res = cursor::open_cursor_step(vm_space_ref, &mut s.regions, vs, va);
1768 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1771 match res {
1772 Option::Some(entry) => {
1773 let ghost id = fresh_cursor_id(s.cursors);
1774 lemma_fresh_cursor_id_not_in_dom(s.cursors);
1775 s.insert_cursor(id, entry);
1776 },
1777 Option::None => {},
1778 }
1779}
1780
1781proof fn step_open_cursor_mut<'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_mut_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_drop_cursor<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1805 requires
1806 old(s).inv(),
1807 old(s).cursors.dom().contains(c),
1808 ensures
1809 final(s).inv(),
1810{
1811 let tracked entry = s.extract_cursor(c);
1812 cursor::drop_cursor_step(entry);
1813}
1814
1815proof fn step_query<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1816 requires
1817 old(s).inv(),
1818 old(s).cursors.dom().contains(c),
1819 ensures
1820 final(s).inv(),
1821{
1822 let ghost old_frames = s.frames;
1823 let ghost old_regions = s.regions;
1824 let tracked mut entry = s.extract_cursor(c);
1825 let ghost res = cursor::cursor_query_step(&mut entry, &mut s.regions);
1826 match res {
1827 Option::None => {
1828 s.insert_cursor(c, entry);
1831 },
1832 Option::Some(paddr) => {
1833 let ghost target_idx = frame_to_index(paddr);
1838 s.regions.inv_implies_correct_addr(paddr);
1839 let ghost id = fresh_frame_id(s.frames);
1840 lemma_fresh_frame_id_not_in_dom(s.frames);
1841 let tracked frame_entry = tracked_frame_entry_new(paddr);
1842 s.insert_frame(id, frame_entry);
1843 assert(s.regions.slot_owners[target_idx].usage is Frame);
1851 assert forall|idx: int|
1853 #![trigger s.regions.slot_owners[idx]]
1854 0 <= idx < max_meta_slots()
1855 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
1856 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1857 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1858 s.segments,
1859 index_to_frame(idx),
1860 ) == 0 by {
1861 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1862 if idx == target_idx {
1863 assert(false);
1866 } else {
1867 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1872 }
1873 };
1874 assert forall|idx: int|
1875 #![trigger s.regions.slot_owners[idx]]
1876 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
1877 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1878 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
1879 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1880 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1881 s.segments,
1882 index_to_frame(idx),
1883 ) > 0 by {
1884 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1885 if idx == target_idx {
1886 assert(handle_count(s.frames, target_idx) >= 1);
1888 } else {
1889 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1890 }
1891 };
1892 assert forall|idx: int|
1893 #![trigger s.regions.slot_owners[idx]]
1894 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
1895 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
1896 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
1897 let so = s.regions.slot_owners[idx];
1898 let rc = so.inner_perms.ref_count.value();
1899 &&& rc != REF_COUNT_UNUSED
1900 &&& rc != REF_COUNT_UNIQUE
1901 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1902 s.segments,
1903 index_to_frame(idx),
1904 )
1905 &&& so.inner_perms.storage.is_init()
1906 } by {
1907 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1908 if idx == target_idx {
1909 if old_regions.slot_owners[target_idx].inner_perms.ref_count.value()
1910 == REF_COUNT_UNUSED {
1911 assert(REF_COUNT_UNUSED == 0u32);
1916 assert(s.regions.slot_owners[target_idx].inner_perms.ref_count.value()
1917 == 1);
1918 assert(handle_count(s.frames, target_idx) == 1);
1919 assert(s.regions.slot_owners[target_idx].paths_in_pt.len()
1920 == old_regions.slot_owners[target_idx].paths_in_pt.len());
1921 assert(old_regions.slot_owners[target_idx].paths_in_pt.len() == 0);
1922 assert(segment_cover_count(s.segments, index_to_frame(target_idx)) == 0);
1923 } else if old_regions.slot_owners[target_idx].inner_perms.ref_count.value()
1924 == REF_COUNT_UNIQUE {
1925 assert(false);
1926 } else {
1927 let pre_so = old_regions.slot_owners[target_idx];
1930 let pre_rc = pre_so.inner_perms.ref_count.value();
1931 let pre_paths = pre_so.paths_in_pt.len();
1932 let pre_H = handle_count(old_frames, target_idx);
1933 let pre_cover = segment_cover_count(s.segments, index_to_frame(target_idx));
1934 if pre_H == 0 && pre_paths == 0 && pre_cover == 0 {
1935 assert(false);
1936 } else {
1937 assert(pre_rc == pre_H + pre_paths + pre_cover);
1941 assert(handle_count(s.frames, target_idx) == pre_H + 1);
1942 }
1943 }
1944 } else {
1945 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1946 }
1947 };
1948 s.insert_cursor(c, entry);
1949 },
1950 }
1951}
1952
1953proof fn step_find_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1954 requires
1955 old(s).inv(),
1956 old(s).cursors.dom().contains(c),
1957 ensures
1958 final(s).inv(),
1959{
1960 let tracked mut entry = s.extract_cursor(c);
1961 cursor::cursor_find_next_step(&mut entry, &mut s.regions, len);
1962 s.insert_cursor(c, entry);
1963}
1964
1965proof fn step_jump<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, va: Vaddr)
1966 requires
1967 old(s).inv(),
1968 old(s).cursors.dom().contains(c),
1969 ensures
1970 final(s).inv(),
1971{
1972 let tracked mut entry = s.extract_cursor(c);
1973 cursor::cursor_jump_step(&mut entry, &mut s.regions, va);
1974 s.insert_cursor(c, entry);
1975}
1976
1977proof fn step_protect_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1978 requires
1979 old(s).inv(),
1980 old(s).cursors.dom().contains(c),
1981 ensures
1982 final(s).inv(),
1983{
1984 let tracked mut entry = s.extract_cursor(c);
1985 cursor::cursor_protect_next_step(&mut entry, &mut s.regions, len);
1986 s.insert_cursor(c, entry);
1987}
1988
1989proof fn step_map<'rcu>(
1990 tracked s: &mut VmStore<'rcu>,
1991 c: CursorId,
1992 fid: FrameId,
1993 prop: PageProperty,
1994)
1995 requires
1996 old(s).inv(),
1997 old(s).cursors.dom().contains(c),
1998 old(s).frames.dom().contains(fid),
1999 ensures
2000 final(s).inv(),
2001{
2002 assert(s.regions.slot_owners[frame_to_index(s.frames[fid].paddr)].usage is Frame);
2005 let ghost paddr = s.frames[fid].paddr;
2006 let ghost target_idx = frame_to_index(paddr);
2007 let ghost old_frames = s.frames;
2008 let ghost old_regions = s.regions;
2009 assert(valid_frame_paddr(paddr));
2011 s.regions.inv_implies_correct_addr(paddr);
2012 assert(old_frames.dom().filter(
2015 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == target_idx,
2016 ).contains(fid));
2017 assert(handle_count(old_frames, target_idx) >= 1);
2018 let ghost pre_rc_target = old_regions.slot_owners[target_idx].inner_perms.ref_count.value();
2021 let ghost pre_paths_target = old_regions.slot_owners[target_idx].paths_in_pt.len();
2022 let ghost pre_cover_target = segment_cover_count(s.segments, index_to_frame(target_idx));
2023 assert(pre_rc_target != REF_COUNT_UNUSED);
2024 assert(pre_rc_target != REF_COUNT_UNIQUE);
2025 assert(pre_rc_target == handle_count(old_frames, target_idx) + pre_paths_target
2026 + pre_cover_target);
2027 assert(old_regions.slot_owners[target_idx].inner_perms.storage.is_init());
2028 let tracked mut entry = s.extract_cursor(c);
2029 let tracked _frame_entry = s.extract_frame(fid);
2033 cursor::map_step(&mut entry, &mut s.regions, &mut s.tlb_model, paddr, prop);
2034 assert forall|idx: int|
2040 #![trigger s.regions.slot_owners[idx]]
2041 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2042 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2043 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2044 s.segments,
2045 index_to_frame(idx),
2046 ) == 0 by {
2047 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2049 lemma_handle_count_remove(old_frames, fid, idx);
2050 if idx == target_idx {
2051 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == pre_rc_target);
2054 assert(false);
2055 }
2056 };
2057 assert forall|idx: int|
2058 #![trigger s.regions.slot_owners[idx]]
2059 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2060 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2061 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2062 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2063 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2064 s.segments,
2065 index_to_frame(idx),
2066 ) > 0 by {
2067 lemma_handle_count_remove(old_frames, fid, idx);
2068 if idx == target_idx {
2069 assert(s.regions.slot_owners[idx].paths_in_pt.len() == pre_paths_target + 1);
2071 } else if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
2072 assert(s.regions.slot_owners[idx].usage !is Frame);
2074 } else {
2075 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2078 }
2079 };
2080 assert forall|idx: int|
2081 #![trigger s.regions.slot_owners[idx]]
2082 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2083 s.frames,
2084 idx,
2085 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2086 s.segments,
2087 index_to_frame(idx),
2088 ) > 0) implies {
2089 let so = s.regions.slot_owners[idx];
2090 let rc = so.inner_perms.ref_count.value();
2091 &&& rc != REF_COUNT_UNUSED
2092 &&& rc != REF_COUNT_UNIQUE
2093 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2094 s.segments,
2095 index_to_frame(idx),
2096 )
2097 &&& so.inner_perms.storage.is_init()
2098 } by {
2099 lemma_handle_count_remove(old_frames, fid, idx);
2100 if idx == target_idx {
2101 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == pre_rc_target);
2107 assert(s.regions.slot_owners[idx].paths_in_pt.len() == pre_paths_target + 1);
2108 assert(handle_count(s.frames, idx) == (handle_count(old_frames, idx) - 1) as nat);
2109 } else if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
2110 assert(s.regions.slot_owners[idx].usage !is Frame);
2111 } else {
2112 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2113 }
2114 };
2115 assert forall|fid_other: FrameId| #[trigger]
2121 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
2122 s.frames[fid_other].paddr,
2123 )].usage is Frame by {
2124 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2125 assert(old_regions.slot_owners[other_idx].usage is Frame);
2127 if other_idx == target_idx {
2128 assert(s.regions.slot_owners[target_idx].usage
2130 == old_regions.slot_owners[target_idx].usage);
2131 } else {
2132 assert(old_frames.dom().filter(
2139 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
2140 ).contains(fid_other));
2141 assert(handle_count(old_frames, other_idx) >= 1);
2142 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value()
2143 != REF_COUNT_UNUSED);
2144 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
2145 }
2146 };
2147 assert forall|sid: SegmentId, paddr_c: Paddr|
2152 #![trigger
2153 s.segments.dom().contains(sid),
2154 frame_to_index(paddr_c)]
2155 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
2156 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
2157 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
2158 let cov_idx = frame_to_index(paddr_c);
2159 lemma_segment_cover_contains(old_regions_segments_helper(s), sid, paddr_c);
2161 assert(old_regions.slot_owners[cov_idx].usage is Frame);
2162 assert(old_regions.slot_owners[cov_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
2163 if cov_idx == target_idx {
2164 assert(s.regions.slot_owners[target_idx].usage
2166 == old_regions.slot_owners[target_idx].usage);
2167 } else {
2168 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
2170 }
2171 };
2172 s.insert_cursor(c, entry);
2173}
2174
2175spec fn old_regions_segments_helper<'rcu>(s: &VmStore<'rcu>) -> Map<SegmentId, SegmentEntry> {
2179 s.segments
2180}
2181
2182proof fn step_unmap<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
2183 requires
2184 old(s).inv(),
2185 old(s).cursors.dom().contains(c),
2186 ensures
2187 final(s).inv(),
2188{
2189 let ghost s_before = *s;
2190 let ghost old_regions = s.regions;
2191 let ghost old_frames = s.frames;
2192 let tracked mut entry = s.extract_cursor(c);
2193 cursor::cursor_mut_regions_step(
2194 &mut entry,
2195 &mut s.regions,
2196 &mut s.tlb_model,
2197 cursor::CursorMutRegionsMethod::Unmap(len),
2198 );
2199 lemma_coverage_preserved_slots_eq(s_before, *s);
2202 assert forall|idx: int|
2208 #![trigger s.regions.slot_owners[idx]]
2209 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2210 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2211 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2212 s.segments,
2213 index_to_frame(idx),
2214 ) == 0 by {
2215 assert(s.regions.slot_owners.contains_key(idx));
2219 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0) by {
2228 if segment_cover_count(old(s).segments, index_to_frame(idx)) > 0 {
2229 let pa = index_to_frame(idx);
2230 let sid = lemma_segment_cover_witness(old(s).segments, pa);
2231 assert(pa == (idx * PAGE_SIZE) as usize);
2235 assert(pa % PAGE_SIZE == 0);
2236 assert(frame_to_index(pa) == idx);
2237 assert(old_regions.slot_owners[idx].usage is Frame);
2239 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
2241 != REF_COUNT_UNUSED);
2242 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX);
2243 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX);
2245 }
2246 };
2247 if old_regions.slot_owners[idx].usage is Frame {
2249 assert(s.regions.slot_owners[idx].usage != PageUsage::MMIO);
2252 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
2253 } else if old_regions.slot_owners[idx].usage == PageUsage::MMIO {
2260 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2263 } else {
2264 assert(s.regions.slot_owners[idx].usage != PageUsage::MMIO);
2267 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
2268 assert(handle_count(s.frames, idx) == 0) by {
2269 let filt = s.frames.dom().filter(
2270 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
2271 );
2272 assert forall|fid: FrameId| #[trigger] filt.contains(fid) implies false by {
2273 assert(s.frames.dom().contains(fid));
2277 assert(frame_to_index(s.frames[fid].paddr) == idx);
2278 assert(s.regions.slot_owners[idx].usage is Frame);
2279 };
2280 assert(filt == Set::empty());
2281 };
2282 }
2283 };
2284 assert forall|idx: int|
2285 #![trigger s.regions.slot_owners[idx]]
2286 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2287 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2288 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2289 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2290 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2291 s.segments,
2292 index_to_frame(idx),
2293 ) > 0 by {
2294 assert(s.regions.slot_owners.contains_key(idx));
2303 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED) by {
2304 if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
2305 assert(old_regions.slot_owners.contains_key(idx));
2307 assert(old_regions.slot_owners[idx].paths_in_pt == Set::empty());
2308 assert(s.regions.slot_owners[idx].paths_in_pt.len() == 0);
2314 assert(false);
2315 }
2316 };
2317 if handle_count(old_frames, idx) > 0 {
2320 assert(handle_count(s.frames, idx) > 0);
2321 } else if segment_cover_count(s.segments, index_to_frame(idx)) > 0 {
2322 } else {
2324 assert(s.regions.slot_owners[idx].paths_in_pt.len() > 0);
2330 }
2331 };
2332 assert forall|idx: int|
2333 #![trigger s.regions.slot_owners[idx]]
2334 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2335 s.frames,
2336 idx,
2337 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0) implies {
2338 let so = s.regions.slot_owners[idx];
2339 let rc = so.inner_perms.ref_count.value();
2340 &&& rc != REF_COUNT_UNUSED
2341 &&& rc != REF_COUNT_UNIQUE
2342 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2343 s.segments,
2344 index_to_frame(idx),
2345 )
2346 &&& so.inner_perms.storage.is_init()
2347 } by {
2348 if handle_count(s.frames, idx) > 0 {
2355 assert(handle_count(old_frames, idx) > 0);
2357 } else {
2358 assert(old_regions.slot_owners[idx].paths_in_pt.len() > 0);
2367 }
2368 };
2380 assert forall|fid_other: FrameId| #[trigger]
2383 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
2384 s.frames[fid_other].paddr,
2385 )].usage is Frame by {
2386 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2387 assert(s.regions.slot_owners[other_idx].usage == old_regions.slot_owners[other_idx].usage);
2388 };
2389 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
2396 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
2397 &&& so.usage is Frame
2398 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
2399 &&& so.inner_perms.in_list.value() == 0
2400 &&& so.paths_in_pt.is_empty()
2401 } by {
2402 let u_idx = frame_to_index(s.unique_frames[u].paddr);
2403 assert(old(s).unique_frames.dom().contains(u));
2404 assert(old_regions.slot_owners[u_idx].usage is Frame);
2406 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
2407 assert(old_regions.slot_owners[u_idx].paths_in_pt.is_empty());
2408 assert(old_regions.slot_owners[u_idx].inner_perms.in_list.value() == 0);
2409 assert(valid_frame_paddr(s.unique_frames[u].paddr));
2411 s.regions.inv_implies_correct_addr(s.unique_frames[u].paddr);
2412 assert(s.regions.slot_owners.contains_key(u_idx));
2413 assert(s.regions.slot_owners[u_idx].usage == old_regions.slot_owners[u_idx].usage);
2415 assert(s.regions.slot_owners[u_idx].inner_perms.in_list
2416 == old_regions.slot_owners[u_idx].inner_perms.in_list);
2417 assert(s.regions.slot_owners[u_idx].paths_in_pt.len()
2420 <= old_regions.slot_owners[u_idx].paths_in_pt.len());
2421 assert(old_regions.slot_owners[u_idx].paths_in_pt.len() == 0);
2422 assert(s.regions.slot_owners[u_idx].paths_in_pt =~= Set::empty());
2423 assert(s.regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
2424 };
2425 s.insert_cursor(c, entry);
2426}
2427
2428proof fn step_new_vm_io<'rcu>(
2429 tracked s: &mut VmStore<'rcu>,
2430 vs: VmSpaceId,
2431 vaddr: Vaddr,
2432 len: usize,
2433 kind: VmIoKind,
2434)
2435 requires
2436 old(s).inv(),
2437 old(s).vm_spaces.dom().contains(vs),
2438 ensures
2439 final(s).inv(),
2440{
2441 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
2442 let tracked res = io::new_vm_io_step(vm_space_ref, Some(vs), vaddr, len, kind);
2443 match res {
2444 Option::Some(entry) => {
2445 let ghost id = fresh_vm_io_id(s.vm_ios);
2446 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2447 s.insert_vm_io(id, entry);
2448 },
2449 Option::None => {},
2450 }
2451}
2452
2453proof fn step_new_kernel_vm_io<'rcu>(
2454 tracked s: &mut VmStore<'rcu>,
2455 vaddr: Vaddr,
2456 len: usize,
2457 kind: VmIoKind,
2458)
2459 requires
2460 old(s).inv(),
2461 ensures
2462 final(s).inv(),
2463{
2464 let tracked entry = io::new_kernel_vm_io_step(vaddr, len, kind);
2465 let ghost id = fresh_vm_io_id(s.vm_ios);
2466 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2467 s.insert_vm_io(id, entry);
2468}
2469
2470proof fn step_drop_vm_io<'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId)
2471 requires
2472 old(s).inv(),
2473 old(s).vm_ios.dom().contains(vio),
2474 ensures
2475 final(s).inv(),
2476{
2477 let tracked entry = s.extract_vm_io(vio);
2478 io::drop_vm_io_step(entry);
2479}
2480
2481proof fn step_vm_io_method<'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId, method: io::VmIoMethod)
2482 requires
2483 old(s).inv(),
2484 old(s).vm_ios.dom().contains(vio),
2485 ensures
2486 final(s).inv(),
2487{
2488 let tracked mut entry = s.extract_vm_io(vio);
2489 io::vm_io_method_step(&mut entry, method);
2490 s.insert_vm_io(vio, entry);
2491}
2492
2493proof fn step_read<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
2494 requires
2495 old(s).inv(),
2496 old(s).vm_ios.dom().contains(source),
2497 old(s).vm_ios.dom().contains(dest),
2498 source != dest,
2499 old(s).vm_ios[source].vm_space is None,
2500 old(s).vm_ios[source].kind == VmIoKind::Reader,
2501 old(s).vm_ios[dest].vm_space is None,
2502 old(s).vm_ios[dest].kind == VmIoKind::Writer,
2503 ensures
2504 final(s).inv(),
2505{
2506 let tracked mut src = s.extract_vm_io(source);
2507 let tracked mut dst = s.extract_vm_io(dest);
2508 let tracked val = io::read_step(&mut src, &mut dst);
2509 s.insert_vm_io(source, src);
2510 s.insert_vm_io(dest, dst);
2511 let ghost id = fresh_vm_io_id(s.vm_ios);
2512 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2513 s.insert_vm_io(id, val);
2514}
2515
2516proof fn step_write<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
2517 requires
2518 old(s).inv(),
2519 old(s).vm_ios.dom().contains(source),
2520 old(s).vm_ios.dom().contains(dest),
2521 source != dest,
2522 old(s).vm_ios[source].vm_space is None,
2523 old(s).vm_ios[source].kind == VmIoKind::Reader,
2524 old(s).vm_ios[dest].vm_space is None,
2525 old(s).vm_ios[dest].kind == VmIoKind::Writer,
2526 ensures
2527 final(s).inv(),
2528{
2529 let tracked mut src = s.extract_vm_io(source);
2530 let tracked mut dst = s.extract_vm_io(dest);
2531 s.insert_vm_io(source, src);
2532 s.insert_vm_io(dest, dst);
2533}
2534
2535proof fn step_frame_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2536 requires
2537 old(s).inv(),
2538 ensures
2539 final(s).inv(),
2540{
2541 let ghost old_frames = s.frames;
2548 let ghost old_regions = s.regions;
2549 if !valid_frame_paddr(paddr) || s.regions.slots.contains_key(frame_to_index(paddr)) {
2550 let tracked res = frame::from_unused_step(&mut s.regions, paddr);
2551 match res {
2552 Option::Some(entry) => {
2553 let ghost id = fresh_frame_id(s.frames);
2554 lemma_fresh_frame_id_not_in_dom(s.frames);
2555 let ghost target_idx = frame_to_index(paddr);
2556 let ghost entry_paddr = entry.paddr;
2557 s.insert_frame(id, entry);
2558 assert(s.frames[id].paddr == paddr);
2559
2560 assert(handle_count(old_frames, target_idx) == 0);
2563 assert(old_regions.slot_owners[target_idx].paths_in_pt.is_empty());
2564
2565 assert forall|idx: int|
2568 #![trigger s.regions.slot_owners[idx]]
2569 0 <= idx < max_meta_slots()
2570 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2571 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2572 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
2573 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2574 if idx == target_idx {
2575 assert(false);
2577 } else {
2578 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2579 }
2580 };
2581
2582 assert forall|idx: int|
2586 #![trigger s.regions.slot_owners[idx]]
2587 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2588 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2589 != REF_COUNT_UNUSED
2590 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2591 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2592 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2593 s.segments,
2594 index_to_frame(idx),
2595 ) > 0 by {
2596 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2597 if idx == target_idx {
2598 assert(handle_count(s.frames, idx) == 1);
2599 } else {
2600 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2601 }
2602 };
2603
2604 assert forall|idx: int|
2606 #![trigger s.regions.slot_owners[idx]]
2607 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
2608 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
2609 > 0 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2610 let so = s.regions.slot_owners[idx];
2611 let rc = so.inner_perms.ref_count.value();
2612 &&& rc != REF_COUNT_UNUSED
2613 &&& rc != REF_COUNT_UNIQUE
2614 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
2615 + segment_cover_count(s.segments, index_to_frame(idx))
2616 &&& so.inner_perms.storage.is_init()
2617 } by {
2618 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2619 if idx == target_idx {
2620 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
2621 == REF_COUNT_UNUSED);
2622 assert(handle_count(old_frames, idx) == 0);
2623 assert(handle_count(s.frames, idx) == 1);
2624 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
2627 } else {
2628 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2631 }
2632 };
2633 },
2634 Option::None => {
2635 assert(s.regions == old_regions);
2637 },
2638 }
2639 }
2640}
2641
2642proof fn step_frame_from_in_use<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2643 requires
2644 old(s).inv(),
2645 ensures
2646 final(s).inv(),
2647{
2648 let ghost old_frames = s.frames;
2653 let ghost old_regions = s.regions;
2654 if !valid_frame_paddr(paddr) || s.regions.slots.contains_key(frame_to_index(paddr)) {
2655 let tracked res = frame::from_in_use_step(&mut s.regions, paddr);
2656 match res {
2657 Option::Some(entry) => {
2658 let ghost id = fresh_frame_id(s.frames);
2659 lemma_fresh_frame_id_not_in_dom(s.frames);
2660 let ghost target_idx = frame_to_index(paddr);
2661 s.insert_frame(id, entry);
2662 assert(s.frames[id].paddr == paddr);
2663
2664 assert forall|idx: int|
2667 #![trigger s.regions.slot_owners[idx]]
2668 0 <= idx < max_meta_slots()
2669 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2670 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2671 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
2672 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2673 if idx == target_idx {
2674 assert(false);
2675 } else {
2676 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2677 }
2678 };
2679
2680 assert forall|idx: int|
2683 #![trigger s.regions.slot_owners[idx]]
2684 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2685 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2686 != REF_COUNT_UNUSED
2687 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2688 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2689 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2690 s.segments,
2691 index_to_frame(idx),
2692 ) > 0 by {
2693 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2694 if idx == target_idx {
2695 assert(handle_count(s.frames, idx) >= 1);
2696 } else {
2697 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2698 }
2699 };
2700
2701 assert forall|idx: int|
2703 #![trigger s.regions.slot_owners[idx]]
2704 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
2705 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
2706 > 0 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2707 let so = s.regions.slot_owners[idx];
2708 let rc = so.inner_perms.ref_count.value();
2709 &&& rc != REF_COUNT_UNUSED
2710 &&& rc != REF_COUNT_UNIQUE
2711 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
2712 + segment_cover_count(s.segments, index_to_frame(idx))
2713 &&& so.inner_perms.storage.is_init()
2714 } by {
2715 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2716 if idx == target_idx {
2717 assert(old_regions.slot_owners[idx].usage is Frame);
2721 } else {
2722 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2723 }
2724 };
2725 },
2726 Option::None => {
2727 assert(s.regions == old_regions);
2728 },
2729 }
2730 }
2731}
2732
2733proof fn step_frame_drop<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
2734 requires
2735 old(s).inv(),
2736 old(s).frames.dom().contains(fid),
2737 segment_cover_count(old(s).segments, old(s).frames[fid].paddr) == 0,
2742 ensures
2743 final(s).inv(),
2744{
2745 lemma_frame_drop_pre_derivable(*s, fid);
2748 let ghost p = s.frames[fid].paddr;
2749 assert(valid_frame_paddr(p));
2750 s.regions.inv_implies_correct_addr(p);
2751 let ghost idx_p = frame_to_index(p);
2752 assert(s.frames.dom().filter(
2756 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx_p,
2757 ).contains(fid));
2758 assert(handle_count(s.frames, idx_p) >= 1);
2759 let ghost target_idx = frame_to_index(p);
2760 let ghost old_frames = s.frames;
2761 let ghost old_regions = s.regions;
2762 let tracked entry = s.extract_frame(fid);
2763 frame::drop_step(&mut s.regions, entry);
2764
2765 assert forall|idx: int|
2774 #![trigger s.regions.slot_owners[idx]]
2775 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2776 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2777 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2778 s.segments,
2779 index_to_frame(idx),
2780 ) == 0 by {
2781 lemma_handle_count_remove(old_frames, fid, idx);
2782 if idx == target_idx {
2783 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() == 1);
2785 assert(handle_count(old_frames, idx) == 1);
2788 assert(handle_count(s.frames, idx) == 0);
2789 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
2791 } else {
2792 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2793 }
2794 };
2795
2796 assert forall|idx: int|
2801 #![trigger s.regions.slot_owners[idx]]
2802 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2803 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2804 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2805 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2806 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2807 s.segments,
2808 index_to_frame(idx),
2809 ) > 0 by {
2810 lemma_handle_count_remove(old_frames, fid, idx);
2811 if idx == target_idx {
2812 assert(handle_count(old_frames, idx) >= 1);
2817 } else {
2818 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2819 }
2820 };
2821
2822 assert forall|idx: int|
2823 #![trigger s.regions.slot_owners[idx]]
2824 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2825 s.frames,
2826 idx,
2827 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2828 s.segments,
2829 index_to_frame(idx),
2830 ) > 0) implies {
2831 let so = s.regions.slot_owners[idx];
2832 let rc = so.inner_perms.ref_count.value();
2833 &&& rc != REF_COUNT_UNUSED
2834 &&& rc != REF_COUNT_UNIQUE
2835 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2836 s.segments,
2837 index_to_frame(idx),
2838 )
2839 &&& so.inner_perms.storage.is_init()
2840 } by {
2841 lemma_handle_count_remove(old_frames, fid, idx);
2842 if idx == target_idx {
2843 assert(old_regions.slot_owners[idx].usage is Frame);
2847 assert(handle_count(old_frames, idx) > 0);
2848 let ghost pre_rc = old_regions.slot_owners[idx].inner_perms.ref_count.value();
2849 let ghost pre_h = handle_count(old_frames, idx);
2850 let ghost pre_p = old_regions.slot_owners[idx].paths_in_pt.len();
2851 assert(pre_rc == pre_h + pre_p);
2852 let ghost post_h = handle_count(s.frames, idx);
2854 assert(post_h == (pre_h - 1) as nat);
2855 let ghost post_p = s.regions.slot_owners[idx].paths_in_pt.len();
2857 assert(post_p == pre_p);
2858 let ghost post_rc = s.regions.slot_owners[idx].inner_perms.ref_count.value();
2859 if pre_rc > 1 {
2860 assert(post_rc == (pre_rc - 1) as u64);
2862 assert(post_rc as nat == post_h + post_p);
2863 assert(s.regions.slot_owners[idx].inner_perms.storage
2864 == old_regions.slot_owners[idx].inner_perms.storage);
2865 } else {
2866 assert(pre_h == 1);
2869 assert(pre_p == 0);
2870 assert(post_h == 0);
2871 assert(post_p == 0);
2872 assert(post_rc == REF_COUNT_UNUSED);
2874 assert(false);
2878 }
2879 } else {
2880 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2883 }
2884 };
2885}
2886
2887proof fn step_segment_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, range: Range<Paddr>)
2892 requires
2893 old(s).inv(),
2894 ensures
2895 final(s).inv(),
2896{
2897 if range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0 && range.start < range.end
2904 && range.end <= MAX_PADDR && (forall|paddr: Paddr|
2905 #![trigger frame_to_index(paddr)]
2906 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
2907 ==> s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value()
2908 == REF_COUNT_UNUSED) {
2909 let ghost s_before = *s;
2910 let ghost old_regions = s.regions;
2911 let ghost old_frames = s.frames;
2912 let ghost old_segments = s.segments;
2913 assert forall|paddr: Paddr|
2917 #![trigger frame_to_index(paddr)]
2918 (range.start <= paddr < range.end && paddr % PAGE_SIZE
2919 == 0) implies s.regions.slots.contains_key(frame_to_index(paddr)) by {
2920 s.regions.inv_implies_correct_addr(paddr);
2921 };
2922 let tracked res = segment::from_unused_step(&mut s.regions, range);
2923 match res {
2924 Option::Some(entry) => {
2925 let ghost id = fresh_segment_id(s.segments);
2926 lemma_fresh_segment_id_not_in_dom(s.segments);
2927 s.insert_segment(id, entry);
2928 lemma_coverage_preserved_slots_eq(s_before, *s);
2931 assert forall|idx: int|
2942 #![trigger s.regions.slot_owners[idx]]
2943 0 <= idx < max_meta_slots()
2944 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2945 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2946 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2947 s.segments,
2948 index_to_frame(idx),
2949 ) == 0 by {
2950 let paddr = index_to_frame(idx);
2951 assert(paddr == (idx * PAGE_SIZE) as usize);
2953 assert(paddr % PAGE_SIZE == 0);
2954 assert(frame_to_index(paddr) == idx);
2955 if range.start <= paddr < range.end {
2956 assert(false);
2958 } else {
2959 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2961 assert(!(entry.range.start <= paddr < entry.range.end));
2964 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
2965 }
2966 };
2967 assert forall|idx: int|
2968 #![trigger s.regions.slot_owners[idx]]
2969 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2970 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2971 != REF_COUNT_UNUSED
2972 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2973 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2974 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2975 s.segments,
2976 index_to_frame(idx),
2977 ) > 0 by {
2978 let paddr = index_to_frame(idx);
2979 assert(paddr == (idx * PAGE_SIZE) as usize);
2980 assert(paddr % PAGE_SIZE == 0);
2981 assert(frame_to_index(paddr) == idx);
2982 if range.start <= paddr < range.end {
2983 assert(entry.range == range);
2984 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
2985 } else {
2986 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2987 assert(!(entry.range.start <= paddr < entry.range.end));
2988 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
2989 }
2990 };
2991 assert forall|idx: int|
2992 #![trigger s.regions.slot_owners[idx]]
2993 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
2994 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
2995 > 0 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2996 let so = s.regions.slot_owners[idx];
2997 let rc = so.inner_perms.ref_count.value();
2998 &&& rc != REF_COUNT_UNUSED
2999 &&& rc != REF_COUNT_UNIQUE
3000 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
3001 + segment_cover_count(s.segments, index_to_frame(idx))
3002 &&& so.inner_perms.storage.is_init()
3003 } by {
3004 let paddr = index_to_frame(idx);
3005 assert(paddr == (idx * PAGE_SIZE) as usize);
3006 assert(paddr % PAGE_SIZE == 0);
3007 assert(frame_to_index(paddr) == idx);
3008 if range.start <= paddr < range.end {
3009 assert(entry.range == range);
3010 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
3011 assert(handle_count(s.frames, idx) == 0);
3014 } else {
3015 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3016 assert(!(entry.range.start <= paddr < entry.range.end));
3017 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
3018 }
3019 };
3020 assert forall|idx: int|
3022 0 <= idx
3023 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3024 == 0 by {
3025 let paddr = index_to_frame(idx);
3026 assert(paddr == (idx * PAGE_SIZE) as usize);
3027 assert(paddr % PAGE_SIZE == 0);
3028 assert(frame_to_index(paddr) == idx);
3029 if range.start <= paddr < range.end {
3030 } else {
3032 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3034 }
3035 };
3036 assert forall|fid_other: FrameId| #[trigger]
3041 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3042 s.frames[fid_other].paddr,
3043 )].usage is Frame by {
3044 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3045 let other_paddr = index_to_frame(other_idx);
3046 assert(old_regions.slot_owners[other_idx].usage is Frame);
3048 assert(old_frames.dom().filter(
3050 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
3051 ).contains(fid_other));
3052 assert(handle_count(old_frames, other_idx) >= 1);
3053 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value()
3054 != REF_COUNT_UNUSED);
3055 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
3059 };
3060 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
3065 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
3066 &&& so.usage is Frame
3067 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
3068 &&& so.inner_perms.in_list.value() == 0
3069 &&& so.paths_in_pt.is_empty()
3070 } by {
3071 let u_idx = frame_to_index(s.unique_frames[u].paddr);
3072 assert(old(s).unique_frames.dom().contains(u));
3073 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value()
3075 == REF_COUNT_UNIQUE);
3076 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value()
3077 != REF_COUNT_UNUSED);
3078 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
3080 };
3081 },
3082 Option::None => {
3083 assert(s.regions == old_regions);
3084 assert(s.segments == old_segments);
3085 },
3086 }
3087 }
3088}
3089
3090proof fn step_segment_drop<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
3094 requires
3095 old(s).inv(),
3096 old(s).segments.dom().contains(sid),
3097 ensures
3098 final(s).inv(),
3099{
3100 let ghost s_before = *s;
3101 let ghost old_regions = s.regions;
3102 let ghost old_frames = s.frames;
3103 let ghost old_segments = s.segments;
3104 let ghost range = s.segments[sid].range;
3105 assert forall|paddr: Paddr|
3108 #![trigger frame_to_index(paddr)]
3109 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) implies {
3110 let so = old_regions.slot_owners[frame_to_index(paddr)];
3111 &&& so.inner_perms.ref_count.value() >= 1
3112 &&& so.inner_perms.ref_count.value() <= REF_COUNT_MAX
3113 &&& so.usage is Frame
3114 &&& so.inner_perms.ref_count.value() == 1 ==> so.paths_in_pt.is_empty()
3115 } by {
3116 let idx = frame_to_index(paddr);
3117 lemma_segment_cover_contains(old_segments, sid, paddr);
3119 assert(old_regions.slot_owners[idx].usage is Frame);
3121 let so = old_regions.slot_owners[idx];
3124 let rc = so.inner_perms.ref_count.value();
3125 assert(rc != REF_COUNT_UNUSED);
3126 assert(rc != REF_COUNT_UNIQUE);
3127 assert(rc == handle_count(old_frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3128 old_segments,
3129 paddr,
3130 ));
3131 assert(old_regions.slot_owners.contains_key(idx));
3135 if rc == 1 {
3138 assert(handle_count(old_frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3139 old_segments,
3140 paddr,
3141 ) == 1);
3142 assert(so.paths_in_pt.len() == 0);
3143 assert(so.paths_in_pt == Set::empty());
3144 }
3145 };
3146 let tracked entry = s.extract_segment(sid);
3147 segment::drop_step(&mut s.regions, entry);
3148 lemma_coverage_preserved_slots_eq(s_before, *s);
3151
3152 assert forall|idx: int|
3169 0 <= idx
3170 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3171 == 0 by {
3172 let paddr = index_to_frame(idx);
3173 assert(paddr == (idx * PAGE_SIZE) as usize);
3174 assert(paddr % PAGE_SIZE == 0);
3175 assert(frame_to_index(paddr) == idx);
3176 if range.start <= paddr < range.end {
3177 } else {
3179 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3180 }
3181 };
3182 assert forall|idx: int|
3184 #![trigger s.regions.slot_owners[idx]]
3185 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3186 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3187 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3188 s.segments,
3189 index_to_frame(idx),
3190 ) == 0 by {
3191 let paddr = index_to_frame(idx);
3192 assert(paddr == (idx * PAGE_SIZE) as usize);
3193 assert(paddr % PAGE_SIZE == 0);
3194 assert(frame_to_index(paddr) == idx);
3195 if range.start <= paddr < range.end {
3196 lemma_segment_cover_contains(old_segments, sid, paddr);
3203 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3204 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() == 1);
3205 assert(handle_count(old_frames, idx) == 0);
3206 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
3207 } else {
3208 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3210 assert(!(entry.range.start <= paddr < entry.range.end));
3211 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3212 }
3213 };
3214 assert forall|idx: int|
3215 #![trigger s.regions.slot_owners[idx]]
3216 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
3217 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3218 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3219 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3220 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3221 s.segments,
3222 index_to_frame(idx),
3223 ) > 0 by {
3224 let paddr = index_to_frame(idx);
3225 assert(paddr == (idx * PAGE_SIZE) as usize);
3226 assert(paddr % PAGE_SIZE == 0);
3227 assert(frame_to_index(paddr) == idx);
3228 if range.start <= paddr < range.end {
3229 lemma_segment_cover_contains(old_segments, sid, paddr);
3234 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3235 } else {
3236 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3237 assert(!(entry.range.start <= paddr < entry.range.end));
3238 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3239 }
3240 };
3241 assert forall|idx: int|
3242 #![trigger s.regions.slot_owners[idx]]
3243 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
3244 s.frames,
3245 idx,
3246 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3247 s.segments,
3248 index_to_frame(idx),
3249 ) > 0) implies {
3250 let so = s.regions.slot_owners[idx];
3251 let rc = so.inner_perms.ref_count.value();
3252 &&& rc != REF_COUNT_UNUSED
3253 &&& rc != REF_COUNT_UNIQUE
3254 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3255 s.segments,
3256 index_to_frame(idx),
3257 )
3258 &&& so.inner_perms.storage.is_init()
3259 } by {
3260 let paddr = index_to_frame(idx);
3261 assert(paddr == (idx * PAGE_SIZE) as usize);
3262 assert(paddr % PAGE_SIZE == 0);
3263 assert(frame_to_index(paddr) == idx);
3264 if range.start <= paddr < range.end {
3265 lemma_segment_cover_contains(old_segments, sid, paddr);
3266 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3267 let pre_rc = old_regions.slot_owners[idx].inner_perms.ref_count.value();
3269 let pre_H = handle_count(old_frames, idx);
3270 let pre_P = old_regions.slot_owners[idx].paths_in_pt.len();
3271 let pre_cover = segment_cover_count(old_segments, paddr);
3272 assert(pre_rc == pre_H + pre_P + pre_cover);
3273 assert(pre_rc != REF_COUNT_UNIQUE);
3274 let post_rc = s.regions.slot_owners[idx].inner_perms.ref_count.value();
3275 assert(post_rc != REF_COUNT_UNUSED);
3276 assert(pre_rc > 1) by {
3277 if pre_rc == 1 {
3278 assert(post_rc == REF_COUNT_UNUSED);
3279 }
3280 };
3281 assert(post_rc == (pre_rc - 1) as u64);
3282 assert(s.regions.slot_owners[idx].paths_in_pt
3283 == old_regions.slot_owners[idx].paths_in_pt);
3284 assert(handle_count(s.frames, idx) == pre_H);
3285 assert(segment_cover_count(s.segments, paddr) == (pre_cover - 1) as nat);
3286 assert(s.regions.slot_owners.contains_key(idx));
3290 assert(s.regions.slot_owners[idx].inner_perms.storage.is_init());
3291 } else {
3292 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3293 assert(!(entry.range.start <= paddr < entry.range.end));
3294 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3295 }
3296 };
3297 assert forall|fid_other: FrameId| #[trigger]
3302 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3303 s.frames[fid_other].paddr,
3304 )].usage is Frame by {
3305 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3306 let other_paddr = index_to_frame(other_idx);
3307 assert(old_regions.slot_owners[other_idx].usage is Frame);
3309 assert(old_frames.dom().filter(
3311 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
3312 ).contains(fid_other));
3313 assert(handle_count(old_frames, other_idx) >= 1);
3314 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value() >= 1);
3316 if range.start <= other_paddr < range.end {
3318 } else {
3320 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
3322 }
3323 };
3324 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3328 #![trigger
3329 s.segments.dom().contains(sid_other),
3330 frame_to_index(paddr_c)]
3331 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3332 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3333 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
3334 let cov_idx = frame_to_index(paddr_c);
3335 assert(sid_other != sid);
3337 assert(old_segments.dom().contains(sid_other));
3339 assert(old_segments[sid_other] == s.segments[sid_other]);
3340 assert(old_regions.slot_owners[cov_idx].usage is Frame);
3342 };
3344 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
3349 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
3350 &&& so.usage is Frame
3351 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
3352 &&& so.inner_perms.in_list.value() == 0
3353 &&& so.paths_in_pt.is_empty()
3354 } by {
3355 let u_paddr = s.unique_frames[u].paddr;
3356 let u_idx = frame_to_index(u_paddr);
3357 assert(old(s).unique_frames.dom().contains(u));
3358 assert(valid_frame_paddr(u_paddr));
3359 s.regions.inv_implies_correct_addr(u_paddr);
3360 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
3362 assert(old_regions.slot_owners[u_idx].usage is Frame);
3363 assert(!(range.start <= u_paddr < range.end)) by {
3365 if range.start <= u_paddr < range.end {
3366 lemma_segment_cover_contains(old_segments, sid, u_paddr);
3367 }
3368 };
3369 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
3371 };
3372}
3373
3374proof fn step_segment_split<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId, offset: usize)
3379 requires
3380 old(s).inv(),
3381 old(s).segments.dom().contains(sid),
3382 offset % PAGE_SIZE == 0,
3383 0 < offset,
3384 offset < (old(s).segments[sid].range.end - old(s).segments[sid].range.start),
3385 ensures
3386 final(s).inv(),
3387{
3388 let ghost old_regions = s.regions;
3389 let ghost old_frames = s.frames;
3390 let ghost old_segments = s.segments;
3391 let ghost range = s.segments[sid].range;
3392 let ghost mid = (range.start + offset) as Paddr;
3393 let ghost entry_left = SegmentEntry { range: range.start..mid };
3394 let ghost entry_right = SegmentEntry { range: mid..range.end };
3395 let ghost id_left = fresh_segment_id(s.segments);
3401 lemma_fresh_segment_id_not_in_dom(s.segments);
3402 assert(id_left != sid);
3403 let ghost stub_entry = SegmentEntry { range: range.start..mid };
3404 let ghost id_right = fresh_segment_id(s.segments.insert(id_left, stub_entry));
3405 lemma_fresh_segment_id_not_in_dom(s.segments.insert(id_left, stub_entry));
3406 assert(id_right != sid);
3407 assert(id_right != id_left);
3408 let tracked _orig = s.extract_segment(sid);
3410 assert(!s.segments.dom().contains(id_left));
3411 let tracked entry_l = tracked_segment_entry_new(range.start..mid);
3412 s.insert_segment(id_left, entry_l);
3413 assert(!s.segments.dom().contains(id_right));
3414 let tracked entry_r = tracked_segment_entry_new(mid..range.end);
3415 s.insert_segment(id_right, entry_r);
3416 assert(s.regions == old_regions);
3421 assert forall|paddr: Paddr| #[trigger]
3422 frame_to_index(paddr) < max_meta_slots() implies segment_cover_count(s.segments, paddr)
3423 == segment_cover_count(old_segments, paddr) by {
3424 lemma_segment_cover_split(
3425 old_segments,
3426 sid,
3427 id_left,
3428 id_right,
3429 entry_left,
3430 entry_right,
3431 paddr,
3432 );
3433 };
3434 assert(entry_left.range.start % PAGE_SIZE == 0);
3441 assert(entry_right.range.start % PAGE_SIZE == 0);
3442 assert(entry_left.range.end % PAGE_SIZE == 0);
3443 assert(entry_right.range.end % PAGE_SIZE == 0);
3444 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3448 #![trigger
3449 s.segments.dom().contains(sid_other),
3450 frame_to_index(paddr_c)]
3451 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3452 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3453 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
3454 if sid_other == id_left {
3455 assert(old_segments.dom().contains(sid));
3456 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
3457 } else if sid_other == id_right {
3458 assert(old_segments.dom().contains(sid));
3459 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
3460 } else {
3461 assert(old_segments.dom().contains(sid_other));
3462 assert(old_segments[sid_other] == s.segments[sid_other]);
3463 }
3464 };
3465 assert forall|idx: int|
3470 #![trigger s.regions.slot_owners[idx]]
3471 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3472 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3473 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3474 s.segments,
3475 index_to_frame(idx),
3476 ) == 0 by {
3477 let paddr = index_to_frame(idx);
3478 assert(paddr == (idx * PAGE_SIZE) as usize);
3479 assert(frame_to_index(paddr) == idx);
3480 lemma_segment_cover_split(
3481 old_segments,
3482 sid,
3483 id_left,
3484 id_right,
3485 entry_left,
3486 entry_right,
3487 paddr,
3488 );
3489 };
3490 assert forall|idx: int|
3491 #![trigger s.regions.slot_owners[idx]]
3492 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
3493 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3494 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3495 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3496 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3497 s.segments,
3498 index_to_frame(idx),
3499 ) > 0 by {
3500 let paddr = index_to_frame(idx);
3501 assert(paddr == (idx * PAGE_SIZE) as usize);
3502 assert(frame_to_index(paddr) == idx);
3503 lemma_segment_cover_split(
3504 old_segments,
3505 sid,
3506 id_left,
3507 id_right,
3508 entry_left,
3509 entry_right,
3510 paddr,
3511 );
3512 };
3513 assert forall|idx: int|
3514 #![trigger s.regions.slot_owners[idx]]
3515 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
3516 s.frames,
3517 idx,
3518 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3519 s.segments,
3520 index_to_frame(idx),
3521 ) > 0) implies {
3522 let so = s.regions.slot_owners[idx];
3523 let rc = so.inner_perms.ref_count.value();
3524 &&& rc != REF_COUNT_UNUSED
3525 &&& rc != REF_COUNT_UNIQUE
3526 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3527 s.segments,
3528 index_to_frame(idx),
3529 )
3530 &&& so.inner_perms.storage.is_init()
3531 } by {
3532 let paddr = index_to_frame(idx);
3533 assert(paddr == (idx * PAGE_SIZE) as usize);
3534 assert(frame_to_index(paddr) == idx);
3535 lemma_segment_cover_split(
3536 old_segments,
3537 sid,
3538 id_left,
3539 id_right,
3540 entry_left,
3541 entry_right,
3542 paddr,
3543 );
3544 };
3545 }
3548
3549proof fn step_segment_next<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
3576 requires
3577 old(s).inv(),
3578 old(s).segments.dom().contains(sid),
3579 ensures
3580 final(s).inv(),
3581{
3582 let ghost old_regions = s.regions;
3583 let ghost old_frames = s.frames;
3584 let ghost old_segments = s.segments;
3585 let ghost range = s.segments[sid].range;
3586 let ghost paddr = range.start;
3587 let ghost target_idx = frame_to_index(paddr);
3588 let ghost new_range_start = (paddr + PAGE_SIZE) as Paddr;
3589 let ghost new_range_end = range.end;
3590 let ghost will_become_empty = new_range_start >= new_range_end;
3591 let ghost new_entry_ghost = SegmentEntry { range: new_range_start..new_range_end };
3592
3593 lemma_segment_cover_contains(old_segments, sid, paddr);
3595 assert(segment_cover_count(old_segments, paddr) >= 1);
3596 assert(old_regions.slot_owners[target_idx].usage is Frame);
3597 let ghost so_pre = old_regions.slot_owners[target_idx];
3598 let ghost pre_rc = so_pre.inner_perms.ref_count.value();
3599 let ghost pre_H = handle_count(old_frames, target_idx);
3600 let ghost pre_P = so_pre.paths_in_pt.len();
3601 let ghost pre_cover = segment_cover_count(old_segments, paddr);
3602 assert(pre_rc == pre_H + pre_P + pre_cover);
3603 assert(pre_rc != REF_COUNT_UNUSED);
3604 assert(pre_rc != REF_COUNT_UNIQUE);
3605 assert(old_regions.slot_owners.contains_key(target_idx));
3606 assert(valid_frame_paddr(paddr));
3607 s.regions.inv_implies_correct_addr(paddr);
3608 assert(s.regions.slots.contains_key(target_idx));
3609 assert(range.start % PAGE_SIZE == 0);
3611 assert(range.end <= MAX_PADDR);
3612 assert(range.start + PAGE_SIZE <= MAX_PADDR);
3613
3614 let ghost fid = fresh_frame_id(s.frames);
3616 lemma_fresh_frame_id_not_in_dom(s.frames);
3617 let tracked frame_entry = tracked_frame_entry_new(paddr);
3618 s.insert_frame(fid, frame_entry);
3619 let tracked _old_entry = s.extract_segment(sid);
3621 segment::segment_next_embedded(&mut s.regions, paddr);
3622 if !will_become_empty {
3623 let tracked new_entry = tracked_segment_entry_new(new_range_start..new_range_end);
3624 s.insert_segment(sid, new_entry);
3625 assert(new_entry == new_entry_ghost);
3626 assert(s.segments == old_segments.remove(sid).insert(sid, new_entry_ghost));
3627 } else {
3628 assert(s.segments == old_segments.remove(sid));
3629 }
3630 assert(s.frames == old_frames.insert(fid, frame_entry));
3631
3632 assert forall|paddr_c: Paddr| paddr_c % PAGE_SIZE == 0 implies #[trigger] segment_cover_count(
3635 s.segments,
3636 paddr_c,
3637 ) == (if paddr_c == paddr {
3638 1nat
3639 } else {
3640 0nat
3641 }) + 0nat
3642 || true by {
3646 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3647 };
3648 assert forall|paddr_c: Paddr|
3650 paddr_c % PAGE_SIZE == 0 && paddr_c == paddr implies #[trigger] segment_cover_count(
3651 s.segments,
3652 paddr_c,
3653 ) + 1 == segment_cover_count(old_segments, paddr_c) by {
3654 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3655 };
3656 assert forall|paddr_c: Paddr|
3657 paddr_c % PAGE_SIZE == 0 && paddr_c != paddr implies #[trigger] segment_cover_count(
3658 s.segments,
3659 paddr_c,
3660 ) == segment_cover_count(old_segments, paddr_c) by {
3661 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3662 };
3663
3664 assert forall|idx: int|
3666 0 <= idx
3667 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3668 == 0 by {
3669 let paddr_c = index_to_frame(idx);
3670 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3671 if idx == target_idx {
3672 } else {
3674 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3675 }
3676 };
3677 assert forall|fid_other: FrameId| #[trigger]
3681 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3682 s.frames[fid_other].paddr,
3683 )].usage is Frame by {
3684 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3685 if fid_other == fid {
3686 assert(s.frames[fid_other].paddr == paddr);
3687 assert(other_idx == target_idx);
3688 } else {
3689 assert(old_frames.dom().contains(fid_other));
3690 assert(s.frames[fid_other] == old_frames[fid_other]);
3691 assert(old_regions.slot_owners[other_idx].usage is Frame);
3692 }
3693 };
3694 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3696 #![trigger
3697 s.segments.dom().contains(sid_other),
3698 frame_to_index(paddr_c)]
3699 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3700 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3701 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
3702 let cov_idx = frame_to_index(paddr_c);
3703 if !will_become_empty && sid_other == sid {
3704 assert(old_segments.dom().contains(sid));
3706 assert(old_regions.slot_owners[cov_idx].usage is Frame);
3707 } else {
3708 assert(sid_other != sid);
3709 assert(old_segments.dom().contains(sid_other));
3710 assert(old_segments[sid_other] == s.segments[sid_other]);
3711 assert(old_regions.slot_owners[cov_idx].usage is Frame);
3712 }
3713 };
3714 if !will_become_empty {
3716 assert(new_range_start % PAGE_SIZE == 0);
3717 assert(new_range_end % PAGE_SIZE == 0);
3718 }
3719 assert forall|idx: int|
3722 #![trigger s.regions.slot_owners[idx]]
3723 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3724 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3725 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3726 s.segments,
3727 index_to_frame(idx),
3728 ) == 0 by {
3729 let paddr_c = index_to_frame(idx);
3730 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3731 assert(frame_to_index(paddr_c) == idx);
3732 if idx == target_idx {
3733 assert(false);
3735 } else {
3736 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3737 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3738 }
3739 };
3740 assert forall|idx: int|
3741 #![trigger s.regions.slot_owners[idx]]
3742 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
3743 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3744 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3745 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3746 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3747 s.segments,
3748 index_to_frame(idx),
3749 ) > 0 by {
3750 let paddr_c = index_to_frame(idx);
3751 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3752 if idx == target_idx {
3753 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3755 assert(handle_count(s.frames, target_idx) >= 1);
3756 } else {
3757 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3758 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3759 }
3760 };
3761 assert forall|idx: int|
3762 #![trigger s.regions.slot_owners[idx]]
3763 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
3764 s.frames,
3765 idx,
3766 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3767 s.segments,
3768 index_to_frame(idx),
3769 ) > 0) implies {
3770 let so = s.regions.slot_owners[idx];
3771 let rc = so.inner_perms.ref_count.value();
3772 &&& rc != REF_COUNT_UNUSED
3773 &&& rc != REF_COUNT_UNIQUE
3774 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3775 s.segments,
3776 index_to_frame(idx),
3777 )
3778 &&& so.inner_perms.storage.is_init()
3779 } by {
3780 let paddr_c = index_to_frame(idx);
3781 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3782 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3783 if idx == target_idx {
3784 } else {
3790 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3791 }
3792 };
3793 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
3797 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
3798 &&& so.usage is Frame
3799 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
3800 &&& so.inner_perms.in_list.value() == 0
3801 &&& so.paths_in_pt.is_empty()
3802 } by {
3803 let u_paddr = s.unique_frames[u].paddr;
3804 let u_idx = frame_to_index(u_paddr);
3805 assert(old(s).unique_frames.dom().contains(u));
3806 assert(valid_frame_paddr(u_paddr));
3807 s.regions.inv_implies_correct_addr(u_paddr);
3808 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
3809 assert(old_regions.slot_owners[u_idx].usage is Frame);
3810 assert(u_idx != target_idx) by {
3812 lemma_segment_cover_contains(old_segments, sid, paddr);
3813 };
3814 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
3815 };
3816}
3817
3818proof fn step_segment_clone_range<'rcu>(
3819 tracked s: &mut VmStore<'rcu>,
3820 sid: SegmentId,
3821 sub_range: Range<Paddr>,
3822)
3823 requires
3824 old(s).inv(),
3825 old(s).segments.dom().contains(sid),
3826 sub_range.start % PAGE_SIZE == 0,
3827 sub_range.end % PAGE_SIZE == 0,
3828 old(s).segments[sid].range.start <= sub_range.start,
3829 sub_range.start < sub_range.end,
3830 sub_range.end <= old(s).segments[sid].range.end,
3831 forall|paddr: Paddr|
3832 #![trigger frame_to_index(paddr)]
3833 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) ==> old(
3834 s,
3835 ).regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1
3836 <= REF_COUNT_MAX,
3837 ensures
3838 final(s).inv(),
3839{
3840 let ghost old_regions = s.regions;
3841 let ghost old_frames = s.frames;
3842 let ghost old_segments = s.segments;
3843 let ghost sid_range = s.segments[sid].range;
3844 let ghost new_entry_ghost = SegmentEntry { range: sub_range };
3845
3846 assert(sid_range.end <= MAX_PADDR);
3849 assert(sub_range.end <= MAX_PADDR);
3850
3851 assert forall|paddr: Paddr|
3859 #![trigger frame_to_index(paddr)]
3860 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) implies {
3861 let so = old_regions.slot_owners[frame_to_index(paddr)];
3862 &&& so.usage is Frame
3863 &&& so.inner_perms.ref_count.value() >= 1
3864 &&& so.inner_perms.ref_count.value() + 1 <= REF_COUNT_MAX
3865 } by {
3866 assert(old_segments.dom().contains(sid));
3868 assert(sid_range.start <= paddr < sid_range.end);
3869 lemma_segment_cover_contains(old_segments, sid, paddr);
3870 assert(segment_cover_count(old_segments, paddr) >= 1);
3871 };
3873
3874 segment::segment_clone_embedded(&mut s.regions, sub_range);
3876
3877 let ghost sid2 = fresh_segment_id(s.segments);
3879 lemma_fresh_segment_id_not_in_dom(s.segments);
3880 assert(sid2 != sid);
3881 let tracked new_entry = tracked_segment_entry_new(sub_range);
3882 s.insert_segment(sid2, new_entry);
3883 assert(new_entry =~= new_entry_ghost);
3884 assert(s.segments =~= old_segments.insert(sid2, new_entry_ghost));
3885 assert(s.frames == old_frames);
3886
3887 assert forall|paddr_c: Paddr|
3889 paddr_c % PAGE_SIZE == 0 && sub_range.start <= paddr_c
3890 < sub_range.end implies #[trigger] segment_cover_count(s.segments, paddr_c)
3891 == segment_cover_count(old_segments, paddr_c) + 1 by {
3892 lemma_segment_cover_insert_inside(old_segments, sid2, new_entry_ghost, paddr_c);
3893 };
3894 assert forall|paddr_c: Paddr|
3895 paddr_c % PAGE_SIZE == 0 && !(sub_range.start <= paddr_c
3896 < sub_range.end) implies #[trigger] segment_cover_count(s.segments, paddr_c)
3897 == segment_cover_count(old_segments, paddr_c) by {
3898 lemma_segment_cover_insert_outside(old_segments, sid2, new_entry_ghost, paddr_c);
3899 };
3900
3901 assert forall|idx: int|
3905 0 <= idx < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].usage
3906 == old_regions.slot_owners[idx].usage by {
3907 let aligned = index_to_frame(idx);
3908 assert(aligned == (idx * PAGE_SIZE) as usize);
3909 assert(frame_to_index(aligned) == idx);
3910 if sub_range.start <= aligned < sub_range.end {
3911 } else {
3913 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3914 }
3915 };
3916 assert forall|idx: int|
3918 0 <= idx
3919 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3920 == 0 by {
3921 let aligned = index_to_frame(idx);
3922 assert(aligned == (idx * PAGE_SIZE) as usize);
3923 assert(frame_to_index(aligned) == idx);
3924 if sub_range.start <= aligned < sub_range.end {
3925 } else {
3927 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3928 }
3929 };
3930
3931 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3933 #![trigger
3934 s.segments.dom().contains(sid_other),
3935 frame_to_index(paddr_c)]
3936 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3937 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3938 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
3939 let cov_idx = frame_to_index(paddr_c);
3940 if sid_other == sid2 {
3941 assert(s.segments[sid2].range == sub_range);
3943 assert(old_segments.dom().contains(sid));
3944 assert(sid_range.start <= paddr_c < sid_range.end);
3945 assert(old_regions.slot_owners[cov_idx].usage is Frame);
3946 } else {
3947 assert(old_segments.dom().contains(sid_other));
3948 assert(old_segments[sid_other] == s.segments[sid_other]);
3949 assert(old_regions.slot_owners[cov_idx].usage is Frame);
3950 }
3951 assert(valid_frame_paddr(paddr_c));
3956 s.regions.inv_implies_correct_addr(paddr_c);
3957 assert(s.regions.slot_owners.contains_key(cov_idx));
3958 };
3959
3960 assert forall|fid_other: FrameId| #[trigger]
3962 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3963 s.frames[fid_other].paddr,
3964 )].usage is Frame by {
3965 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3966 assert(old_frames.dom().contains(fid_other));
3967 assert(old_regions.slot_owners[other_idx].usage is Frame);
3968 assert(valid_frame_paddr(s.frames[fid_other].paddr));
3969 s.regions.inv_implies_correct_addr(s.frames[fid_other].paddr);
3970 assert(s.regions.slot_owners.contains_key(other_idx));
3971 };
3974
3975 assert forall|idx: int|
3977 #![trigger s.regions.slot_owners[idx]]
3978 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3979 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3980 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3981 s.segments,
3982 index_to_frame(idx),
3983 ) == 0 by {
3984 let aligned = index_to_frame(idx);
3985 assert(aligned == (idx * PAGE_SIZE) as usize);
3986 assert(frame_to_index(aligned) == idx);
3987 if sub_range.start <= aligned < sub_range.end {
3988 assert(false);
3990 } else {
3991 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3992 }
3993 };
3994 assert forall|idx: int|
3996 #![trigger s.regions.slot_owners[idx]]
3997 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
3998 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3999 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
4000 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
4001 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
4002 s.segments,
4003 index_to_frame(idx),
4004 ) > 0 by {
4005 let aligned = index_to_frame(idx);
4006 assert(aligned == (idx * PAGE_SIZE) as usize);
4007 assert(frame_to_index(aligned) == idx);
4008 if sub_range.start <= aligned < sub_range.end {
4009 } else {
4011 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4012 }
4013 };
4014 assert forall|idx: int|
4016 #![trigger s.regions.slot_owners[idx]]
4017 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
4018 s.frames,
4019 idx,
4020 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
4021 s.segments,
4022 index_to_frame(idx),
4023 ) > 0) implies {
4024 let so = s.regions.slot_owners[idx];
4025 let rc = so.inner_perms.ref_count.value();
4026 &&& rc != REF_COUNT_UNUSED
4027 &&& rc != REF_COUNT_UNIQUE
4028 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
4029 s.segments,
4030 index_to_frame(idx),
4031 )
4032 &&& so.inner_perms.storage.is_init()
4033 } by {
4034 let aligned = index_to_frame(idx);
4035 assert(aligned == (idx * PAGE_SIZE) as usize);
4036 assert(frame_to_index(aligned) == idx);
4037 if sub_range.start <= aligned < sub_range.end {
4038 } else {
4041 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4042 }
4043 };
4044 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4049 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4050 &&& so.usage is Frame
4051 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4052 &&& so.inner_perms.in_list.value() == 0
4053 &&& so.paths_in_pt.is_empty()
4054 } by {
4055 let u_paddr = s.unique_frames[u].paddr;
4056 let u_idx = frame_to_index(u_paddr);
4057 assert(old(s).unique_frames.dom().contains(u));
4058 assert(valid_frame_paddr(u_paddr));
4059 s.regions.inv_implies_correct_addr(u_paddr);
4060 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
4061 assert(old_regions.slot_owners[u_idx].usage is Frame);
4062 assert(!(sub_range.start <= u_paddr < sub_range.end)) by {
4063 if sub_range.start <= u_paddr < sub_range.end {
4064 assert(sid_range.start <= u_paddr < sid_range.end);
4066 lemma_segment_cover_contains(old_segments, sid, u_paddr);
4067 }
4068 };
4069 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4070 };
4071}
4072
4073proof fn step_segment_clone<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
4077 requires
4078 old(s).inv(),
4079 old(s).segments.dom().contains(sid),
4080 forall|paddr: Paddr|
4081 #![trigger frame_to_index(paddr)]
4082 (old(s).segments[sid].range.start <= paddr < old(s).segments[sid].range.end && paddr
4083 % PAGE_SIZE == 0) ==> old(s).regions.slot_owners[frame_to_index(
4084 paddr,
4085 )].inner_perms.ref_count.value() + 1 <= REF_COUNT_MAX,
4086 ensures
4087 final(s).inv(),
4088{
4089 let ghost r = s.segments[sid].range;
4093 assert(r.start % PAGE_SIZE == 0);
4094 assert(r.end % PAGE_SIZE == 0);
4095 assert(r.start < r.end);
4096 assert(r.end <= MAX_PADDR);
4097 step_segment_clone_range(s, sid, r);
4098}
4099
4100proof fn step_segment_slice<'rcu>(
4103 tracked s: &mut VmStore<'rcu>,
4104 sid: SegmentId,
4105 sub_range: Range<Paddr>,
4106)
4107 requires
4108 old(s).inv(),
4109 old(s).segments.dom().contains(sid),
4110 sub_range.start % PAGE_SIZE == 0,
4111 sub_range.end % PAGE_SIZE == 0,
4112 old(s).segments[sid].range.start <= sub_range.start,
4113 sub_range.start < sub_range.end,
4114 sub_range.end <= old(s).segments[sid].range.end,
4115 forall|paddr: Paddr|
4116 #![trigger frame_to_index(paddr)]
4117 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) ==> old(
4118 s,
4119 ).regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1
4120 <= REF_COUNT_MAX,
4121 ensures
4122 final(s).inv(),
4123{
4124 step_segment_clone_range(s, sid, sub_range);
4125}
4126
4127proof fn step_unique_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
4128 requires
4129 old(s).inv(),
4130 ensures
4131 final(s).inv(),
4132{
4133 if valid_frame_paddr(paddr) && s.regions.slots.contains_key(frame_to_index(paddr))
4137 && s.regions.slot_owners[frame_to_index(paddr)].usage is Unused
4138 && s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value()
4139 == REF_COUNT_UNUSED {
4140 let ghost old_regions = s.regions;
4141 let ghost old_frames = s.frames;
4142 let ghost old_segments = s.segments;
4143 let ghost old_unique = s.unique_frames;
4144 let ghost idx = frame_to_index(paddr);
4145
4146 s.regions.inv_implies_correct_addr(paddr);
4148 assert(s.regions.slot_owners.contains_key(idx));
4149 assert(index_to_frame(idx) == paddr);
4150
4151 assert(handle_count(old_frames, idx) == 0);
4153 assert(old_regions.slot_owners[idx].paths_in_pt.is_empty());
4154 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0);
4155
4156 unique::unique_from_unused_embedded(&mut s.regions, paddr);
4158
4159 let ghost uid = fresh_unique_id(s.unique_frames);
4161 lemma_fresh_unique_id_not_in_dom(s.unique_frames);
4162 let tracked entry = tracked_unique_entry_new(paddr);
4163 s.insert_unique(uid, entry);
4164 assert(s.unique_frames =~= old_unique.insert(uid, UniqueEntry { paddr }));
4165 assert(s.frames == old_frames);
4166 assert(s.segments == old_segments);
4167
4168 assert forall|i: int|
4170 0 <= i
4171 < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].inner_perms.in_list.value()
4172 == 0 by {
4173 if i != idx {
4174 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4175 }
4176 };
4177 assert forall|fid: FrameId| #[trigger]
4179 s.frames.dom().contains(fid) implies s.regions.slot_owners[frame_to_index(
4180 s.frames[fid].paddr,
4181 )].usage is Frame by {
4182 let other_idx = frame_to_index(s.frames[fid].paddr);
4183 assert(old_frames.dom().contains(fid));
4184 assert(old_regions.slot_owners[other_idx].usage is Frame);
4185 if other_idx == idx {
4186 assert(false);
4188 }
4189 };
4190 assert forall|sid: SegmentId, paddr_c: Paddr|
4192 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4193 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4194 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4195 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
4196 let cov_idx = frame_to_index(paddr_c);
4197 assert(old_segments.dom().contains(sid));
4198 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4199 if cov_idx == idx {
4200 assert(false);
4201 }
4202 };
4203 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4205 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4206 &&& so.usage is Frame
4207 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4208 &&& so.inner_perms.in_list.value() == 0
4209 &&& so.paths_in_pt.is_empty()
4210 } by {
4211 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4212 if u == uid {
4213 assert(s.unique_frames[u].paddr == paddr);
4214 assert(u_idx == idx);
4215 } else {
4216 assert(old_unique.dom().contains(u));
4217 assert(s.unique_frames[u] == old_unique[u]);
4218 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value()
4219 == REF_COUNT_UNIQUE);
4220 assert(u_idx != idx);
4221 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4222 }
4223 };
4224 assert forall|u: UniqueId| #[trigger]
4226 s.unique_frames.dom().contains(u) implies valid_frame_paddr(
4227 s.unique_frames[u].paddr,
4228 ) by {
4229 if u != uid {
4230 assert(old_unique.dom().contains(u));
4231 }
4232 };
4233 assert forall|u1: UniqueId, u2: UniqueId|
4235 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4236 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4237 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4238 if u1 == uid && u2 != uid {
4239 assert(old_unique.dom().contains(u2));
4240 assert(s.unique_frames[u2].paddr == paddr);
4241 assert(frame_to_index(s.unique_frames[u2].paddr) == idx);
4242 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
4243 == REF_COUNT_UNIQUE);
4244 assert(false);
4245 } else if u2 == uid && u1 != uid {
4246 assert(old_unique.dom().contains(u1));
4247 assert(s.unique_frames[u1].paddr == paddr);
4248 assert(frame_to_index(s.unique_frames[u1].paddr) == idx);
4249 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
4250 == REF_COUNT_UNIQUE);
4251 assert(false);
4252 } else if u1 != uid && u2 != uid {
4253 assert(old_unique.dom().contains(u1));
4254 assert(old_unique.dom().contains(u2));
4255 }
4256 };
4257
4258 assert forall|i: int|
4260 #![trigger s.regions.slot_owners[i]]
4261 0 <= i < max_meta_slots() && s.regions.slot_owners[i].inner_perms.ref_count.value()
4262 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4263 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4264 s.segments,
4265 index_to_frame(i),
4266 ) == 0 by {
4267 if i == idx {
4268 assert(false);
4270 } else {
4271 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4272 }
4273 };
4274 assert forall|i: int|
4276 #![trigger s.regions.slot_owners[i]]
4277 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
4278 && s.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4279 && s.regions.slot_owners[i].inner_perms.ref_count.value()
4280 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
4281 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4282 s.segments,
4283 index_to_frame(i),
4284 ) > 0 by {
4285 if i == idx {
4286 assert(false);
4288 } else {
4289 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4290 }
4291 };
4292 assert forall|i: int|
4294 #![trigger s.regions.slot_owners[i]]
4295 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
4296 s.frames,
4297 i,
4298 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4299 s.segments,
4300 index_to_frame(i),
4301 ) > 0) implies {
4302 let so = s.regions.slot_owners[i];
4303 let rc = so.inner_perms.ref_count.value();
4304 &&& rc != REF_COUNT_UNUSED
4305 &&& rc != REF_COUNT_UNIQUE
4306 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4307 s.segments,
4308 index_to_frame(i),
4309 )
4310 &&& so.inner_perms.storage.is_init()
4311 } by {
4312 if i == idx {
4313 assert(handle_count(s.frames, idx) == 0);
4316 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4317 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4318 } else {
4319 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4320 }
4321 };
4322 }
4323}
4324
4325proof fn step_unique_drop<'rcu>(tracked s: &mut VmStore<'rcu>, uid: UniqueId)
4333 requires
4334 old(s).inv(),
4335 old(s).unique_frames.dom().contains(uid),
4336 ensures
4337 final(s).inv(),
4338{
4339 let ghost old_regions = s.regions;
4340 let ghost old_frames = s.frames;
4341 let ghost old_segments = s.segments;
4342 let ghost old_unique = s.unique_frames;
4343 let ghost paddr = s.unique_frames[uid].paddr;
4344 let ghost idx = frame_to_index(paddr);
4345
4346 assert(valid_frame_paddr(paddr));
4349 s.regions.inv_implies_correct_addr(paddr);
4350 assert(s.regions.slot_owners.contains_key(idx));
4351 assert(index_to_frame(idx) == paddr);
4352 assert(s.regions.slot_owners[idx].usage is Frame);
4353 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
4354 assert(s.regions.slot_owners[idx].inner_perms.in_list.value() == 0);
4355 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4356 assert(s.regions.slot_owners[idx].inner_perms.storage.is_init());
4357
4358 assert(handle_count(old_frames, idx) == 0) by {
4362 if handle_count(old_frames, idx) > 0 {
4363 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE);
4364 assert(false);
4365 }
4366 };
4367 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0) by {
4368 if segment_cover_count(old_segments, index_to_frame(idx)) > 0 {
4369 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE);
4370 assert(false);
4371 }
4372 };
4373
4374 let tracked _entry = s.extract_unique(uid);
4376 unique::unique_drop_embedded(&mut s.regions, paddr);
4377 assert(s.unique_frames =~= old_unique.remove(uid));
4378 assert(s.frames == old_frames);
4379 assert(s.segments == old_segments);
4380
4381 assert forall|i: int|
4383 0 <= i
4384 < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].inner_perms.in_list.value()
4385 == 0 by {
4386 if i != idx {
4387 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4388 }
4389 };
4390 assert forall|fid: FrameId| #[trigger]
4392 s.frames.dom().contains(fid) implies s.regions.slot_owners[frame_to_index(
4393 s.frames[fid].paddr,
4394 )].usage is Frame by {
4395 let other_idx = frame_to_index(s.frames[fid].paddr);
4396 assert(old_frames.dom().contains(fid));
4397 assert(old_regions.slot_owners[other_idx].usage is Frame);
4398 if other_idx != idx {
4399 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4400 }
4401 };
4402 assert forall|sid: SegmentId, paddr_c: Paddr|
4404 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4405 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4406 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4407 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
4408 let cov_idx = frame_to_index(paddr_c);
4409 assert(old_segments.dom().contains(sid));
4410 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4411 if cov_idx != idx {
4412 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4413 }
4414 };
4415 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4417 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4418 &&& so.usage is Frame
4419 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4420 &&& so.inner_perms.in_list.value() == 0
4421 &&& so.paths_in_pt.is_empty()
4422 } by {
4423 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4424 assert(old_unique.dom().contains(u));
4425 assert(u != uid);
4426 if u_idx == idx {
4428 assert(s.unique_frames[u].paddr == paddr) by {
4429 assert(old_unique[u].paddr == s.unique_frames[u].paddr);
4430 };
4431 assert(u == uid);
4432 assert(false);
4433 }
4434 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4435 };
4436 assert forall|u: UniqueId| #[trigger]
4438 s.unique_frames.dom().contains(u) implies valid_frame_paddr(s.unique_frames[u].paddr) by {
4439 assert(old_unique.dom().contains(u));
4440 };
4441 assert forall|u1: UniqueId, u2: UniqueId|
4442 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4443 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4444 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4445 assert(old_unique.dom().contains(u1));
4446 assert(old_unique.dom().contains(u2));
4447 };
4448
4449 assert forall|i: int|
4451 #![trigger s.regions.slot_owners[i]]
4452 0 <= i < max_meta_slots() && s.regions.slot_owners[i].inner_perms.ref_count.value()
4453 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4454 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4455 s.segments,
4456 index_to_frame(i),
4457 ) == 0 by {
4458 if i == idx {
4459 assert(handle_count(s.frames, idx) == 0);
4462 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4463 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4464 } else {
4465 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4466 }
4467 };
4468 assert forall|i: int|
4470 #![trigger s.regions.slot_owners[i]]
4471 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
4472 && s.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4473 && s.regions.slot_owners[i].inner_perms.ref_count.value()
4474 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
4475 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4476 s.segments,
4477 index_to_frame(i),
4478 ) > 0 by {
4479 if i == idx {
4480 assert(false);
4482 } else {
4483 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4484 }
4485 };
4486 assert forall|i: int|
4488 #![trigger s.regions.slot_owners[i]]
4489 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
4490 s.frames,
4491 i,
4492 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4493 s.segments,
4494 index_to_frame(i),
4495 ) > 0) implies {
4496 let so = s.regions.slot_owners[i];
4497 let rc = so.inner_perms.ref_count.value();
4498 &&& rc != REF_COUNT_UNUSED
4499 &&& rc != REF_COUNT_UNIQUE
4500 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4501 s.segments,
4502 index_to_frame(i),
4503 )
4504 &&& so.inner_perms.storage.is_init()
4505 } by {
4506 if i == idx {
4507 assert(handle_count(s.frames, idx) == 0);
4509 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4510 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4511 } else {
4512 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4513 }
4514 };
4515}
4516
4517proof fn step_from_unique<'rcu>(tracked s: &mut VmStore<'rcu>, uid: UniqueId)
4523 requires
4524 old(s).inv(),
4525 old(s).unique_frames.dom().contains(uid),
4526 ensures
4527 final(s).inv(),
4528{
4529 let ghost old_regions = s.regions;
4530 let ghost old_frames = s.frames;
4531 let ghost old_segments = s.segments;
4532 let ghost old_unique = s.unique_frames;
4533 let ghost paddr = s.unique_frames[uid].paddr;
4534 let ghost idx = frame_to_index(paddr);
4535
4536 assert(valid_frame_paddr(paddr));
4538 s.regions.inv_implies_correct_addr(paddr);
4539 assert(s.regions.slot_owners.contains_key(idx));
4540 assert(index_to_frame(idx) == paddr);
4541 assert(s.regions.slot_owners[idx].usage is Frame);
4542 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNIQUE);
4543 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4544 assert(s.regions.slot_owners[idx].inner_perms.storage.is_init());
4545
4546 assert(handle_count(old_frames, idx) == 0) by {
4548 if handle_count(old_frames, idx) > 0 {
4549 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE);
4550 assert(false);
4551 }
4552 };
4553 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0) by {
4554 if segment_cover_count(old_segments, index_to_frame(idx)) > 0 {
4555 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE);
4556 assert(false);
4557 }
4558 };
4559
4560 let tracked _ue = s.extract_unique(uid);
4562 unique::from_unique_embedded(&mut s.regions, paddr);
4563
4564 let ghost fid = fresh_frame_id(s.frames);
4566 lemma_fresh_frame_id_not_in_dom(s.frames);
4567 let tracked fe = tracked_frame_entry_new(paddr);
4568 s.insert_frame(fid, fe);
4569 assert(s.frames =~= old_frames.insert(fid, FrameEntry { paddr }));
4570 assert(s.unique_frames =~= old_unique.remove(uid));
4571 assert(s.segments == old_segments);
4572 assert(s.frames[fid].paddr == paddr);
4573
4574 assert forall|i: int|
4576 0 <= i
4577 < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].inner_perms.in_list.value()
4578 == 0 by {
4579 if i != idx {
4580 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4581 }
4582 };
4583 assert forall|fid_other: FrameId| #[trigger]
4585 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
4586 s.frames[fid_other].paddr,
4587 )].usage is Frame by {
4588 let other_idx = frame_to_index(s.frames[fid_other].paddr);
4589 if fid_other == fid {
4590 assert(s.frames[fid_other].paddr == paddr);
4591 assert(other_idx == idx);
4592 } else {
4593 assert(old_frames.dom().contains(fid_other));
4594 assert(s.frames[fid_other] == old_frames[fid_other]);
4595 assert(old_regions.slot_owners[other_idx].usage is Frame);
4596 if other_idx != idx {
4597 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4598 }
4599 }
4600 };
4601 assert forall|sid: SegmentId, paddr_c: Paddr|
4603 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4604 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4605 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4606 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
4607 let cov_idx = frame_to_index(paddr_c);
4608 assert(old_segments.dom().contains(sid));
4609 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4610 if cov_idx != idx {
4611 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4612 }
4613 };
4614 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4616 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4617 &&& so.usage is Frame
4618 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4619 &&& so.inner_perms.in_list.value() == 0
4620 &&& so.paths_in_pt.is_empty()
4621 } by {
4622 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4623 assert(old_unique.dom().contains(u));
4624 assert(u != uid);
4625 if u_idx == idx {
4626 assert(old_unique[u].paddr == s.unique_frames[u].paddr);
4627 assert(u == uid);
4628 assert(false);
4629 }
4630 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4631 };
4632 assert forall|u: UniqueId| #[trigger]
4633 s.unique_frames.dom().contains(u) implies valid_frame_paddr(s.unique_frames[u].paddr) by {
4634 assert(old_unique.dom().contains(u));
4635 };
4636 assert forall|u1: UniqueId, u2: UniqueId|
4637 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4638 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4639 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4640 assert(old_unique.dom().contains(u1));
4641 assert(old_unique.dom().contains(u2));
4642 };
4643
4644 assert forall|i: int|
4646 #![trigger s.regions.slot_owners[i]]
4647 0 <= i < max_meta_slots() && s.regions.slot_owners[i].inner_perms.ref_count.value()
4648 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4649 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4650 s.segments,
4651 index_to_frame(i),
4652 ) == 0 by {
4653 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4654 if i == idx {
4655 assert(false);
4656 } else {
4657 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4658 }
4659 };
4660 assert forall|i: int|
4662 #![trigger s.regions.slot_owners[i]]
4663 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
4664 && s.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4665 && s.regions.slot_owners[i].inner_perms.ref_count.value()
4666 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
4667 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4668 s.segments,
4669 index_to_frame(i),
4670 ) > 0 by {
4671 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4672 if i == idx {
4673 assert(handle_count(s.frames, idx) == 1);
4674 } else {
4675 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4676 }
4677 };
4678 assert forall|i: int|
4680 #![trigger s.regions.slot_owners[i]]
4681 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
4682 s.frames,
4683 i,
4684 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4685 s.segments,
4686 index_to_frame(i),
4687 ) > 0) implies {
4688 let so = s.regions.slot_owners[i];
4689 let rc = so.inner_perms.ref_count.value();
4690 &&& rc != REF_COUNT_UNUSED
4691 &&& rc != REF_COUNT_UNIQUE
4692 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4693 s.segments,
4694 index_to_frame(i),
4695 )
4696 &&& so.inner_perms.storage.is_init()
4697 } by {
4698 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4699 if i == idx {
4700 assert(handle_count(s.frames, idx) == 1);
4703 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4704 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4705 } else {
4706 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4707 }
4708 };
4709}
4710
4711proof fn step_try_from_shared<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
4718 requires
4719 old(s).inv(),
4720 old(s).frames.dom().contains(fid),
4721 ensures
4722 final(s).inv(),
4723{
4724 let ghost paddr = s.frames[fid].paddr;
4725 let ghost idx = frame_to_index(paddr);
4726 assert(valid_frame_paddr(paddr));
4729 s.regions.inv_implies_correct_addr(paddr);
4730 assert(s.regions.slot_owners.contains_key(idx));
4731 assert(index_to_frame(idx) == paddr);
4732 assert(s.regions.slot_owners[idx].usage is Frame);
4733 assert(s.frames.dom().filter(
4734 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
4735 ).contains(fid));
4736 assert(handle_count(s.frames, idx) >= 1);
4737
4738 if s.regions.slot_owners[idx].inner_perms.ref_count.value() == 1 {
4739 let ghost old_regions = s.regions;
4740 let ghost old_frames = s.frames;
4741 let ghost old_segments = s.segments;
4742 let ghost old_unique = s.unique_frames;
4743
4744 assert(handle_count(old_frames, idx) == 1);
4747 assert(s.regions.slot_owners[idx].paths_in_pt.len() == 0);
4748 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0);
4749 assert(s.regions.slot_owners[idx].paths_in_pt =~= Set::empty());
4750
4751 let tracked _fe = s.extract_frame(fid);
4753 assert(s.frames =~= old_frames.remove(fid));
4754 unique::try_from_shared_embedded(&mut s.regions, paddr);
4755
4756 let ghost uid = fresh_unique_id(s.unique_frames);
4758 lemma_fresh_unique_id_not_in_dom(s.unique_frames);
4759 let tracked ue = tracked_unique_entry_new(paddr);
4760 s.insert_unique(uid, ue);
4761 assert(s.unique_frames =~= old_unique.insert(uid, UniqueEntry { paddr }));
4762 assert(s.segments == old_segments);
4763 assert(handle_count(s.frames, idx) == 0) by {
4765 lemma_handle_count_remove(old_frames, fid, idx);
4766 };
4767
4768 assert forall|i: int|
4770 0 <= i
4771 < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].inner_perms.in_list.value()
4772 == 0 by {
4773 if i != idx {
4774 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4775 }
4776 };
4777 assert forall|fid_other: FrameId| #[trigger]
4781 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
4782 s.frames[fid_other].paddr,
4783 )].usage is Frame by {
4784 let other_idx = frame_to_index(s.frames[fid_other].paddr);
4785 assert(old_frames.dom().contains(fid_other));
4786 assert(old_regions.slot_owners[other_idx].usage is Frame);
4787 if other_idx != idx {
4788 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4789 }
4790 };
4791 assert forall|sid: SegmentId, paddr_c: Paddr|
4793 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4794 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4795 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4796 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage is Frame by {
4797 let cov_idx = frame_to_index(paddr_c);
4798 assert(old_segments.dom().contains(sid));
4799 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4800 if cov_idx != idx {
4801 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4802 }
4803 };
4804 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4806 let so = s.regions.slot_owners[frame_to_index(s.unique_frames[u].paddr)];
4807 &&& so.usage is Frame
4808 &&& so.inner_perms.ref_count.value() == REF_COUNT_UNIQUE
4809 &&& so.inner_perms.in_list.value() == 0
4810 &&& so.paths_in_pt.is_empty()
4811 } by {
4812 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4813 if u == uid {
4814 assert(s.unique_frames[u].paddr == paddr);
4815 assert(u_idx == idx);
4816 } else {
4817 assert(old_unique.dom().contains(u));
4818 assert(s.unique_frames[u] == old_unique[u]);
4819 assert(old_regions.slot_owners[u_idx].inner_perms.ref_count.value()
4821 == REF_COUNT_UNIQUE);
4822 assert(u_idx != idx);
4823 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4824 }
4825 };
4826 assert forall|u: UniqueId| #[trigger]
4827 s.unique_frames.dom().contains(u) implies valid_frame_paddr(
4828 s.unique_frames[u].paddr,
4829 ) by {
4830 if u != uid {
4831 assert(old_unique.dom().contains(u));
4832 }
4833 };
4834 assert forall|u1: UniqueId, u2: UniqueId|
4835 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4836 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4837 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4838 if u1 == uid && u2 != uid {
4839 assert(old_unique.dom().contains(u2));
4840 assert(s.unique_frames[u2].paddr == paddr);
4841 assert(frame_to_index(s.unique_frames[u2].paddr) == idx);
4842 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
4843 == REF_COUNT_UNIQUE);
4844 assert(false);
4845 } else if u2 == uid && u1 != uid {
4846 assert(old_unique.dom().contains(u1));
4847 assert(s.unique_frames[u1].paddr == paddr);
4848 assert(frame_to_index(s.unique_frames[u1].paddr) == idx);
4849 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
4850 == REF_COUNT_UNIQUE);
4851 assert(false);
4852 } else if u1 != uid && u2 != uid {
4853 assert(old_unique.dom().contains(u1));
4854 assert(old_unique.dom().contains(u2));
4855 }
4856 };
4857
4858 assert forall|i: int|
4860 #![trigger s.regions.slot_owners[i]]
4861 0 <= i < max_meta_slots() && s.regions.slot_owners[i].inner_perms.ref_count.value()
4862 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4863 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4864 s.segments,
4865 index_to_frame(i),
4866 ) == 0 by {
4867 lemma_handle_count_remove(old_frames, fid, i);
4868 if i == idx {
4869 assert(false);
4871 } else {
4872 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4873 }
4874 };
4875 assert forall|i: int|
4877 #![trigger s.regions.slot_owners[i]]
4878 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
4879 && s.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
4880 && s.regions.slot_owners[i].inner_perms.ref_count.value()
4881 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
4882 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4883 s.segments,
4884 index_to_frame(i),
4885 ) > 0 by {
4886 lemma_handle_count_remove(old_frames, fid, i);
4887 if i == idx {
4888 assert(false);
4890 } else {
4891 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4892 }
4893 };
4894 assert forall|i: int|
4896 #![trigger s.regions.slot_owners[i]]
4897 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
4898 s.frames,
4899 i,
4900 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4901 s.segments,
4902 index_to_frame(i),
4903 ) > 0) implies {
4904 let so = s.regions.slot_owners[i];
4905 let rc = so.inner_perms.ref_count.value();
4906 &&& rc != REF_COUNT_UNUSED
4907 &&& rc != REF_COUNT_UNIQUE
4908 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4909 s.segments,
4910 index_to_frame(i),
4911 )
4912 &&& so.inner_perms.storage.is_init()
4913 } by {
4914 lemma_handle_count_remove(old_frames, fid, i);
4915 if i == idx {
4916 assert(handle_count(s.frames, idx) == 0);
4919 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4920 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4921 } else {
4922 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4923 }
4924 };
4925 }
4926}
4927
4928pub proof fn lemma_segment_cover_insert_inside(
4931 segments: Map<SegmentId, SegmentEntry>,
4932 sid: SegmentId,
4933 entry: SegmentEntry,
4934 paddr: Paddr,
4935)
4936 requires
4937 !segments.dom().contains(sid),
4938 entry.range.start <= paddr < entry.range.end,
4939 ensures
4940 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
4941 segments,
4942 paddr,
4943 ) + 1,
4944{
4945 let segments2 = segments.insert(sid, entry);
4946 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
4947 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
4948 let old_filt = segments.dom().filter(pred);
4949 let new_filt = segments2.dom().filter(pred2);
4950 assert(segments2.dom() == segments.dom().insert(sid));
4951 assert(!old_filt.contains(sid));
4952 assert(new_filt == old_filt.insert(sid)) by {
4953 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.insert(
4954 sid,
4955 ).contains(s) by {
4956 if s != sid {
4957 assert(segments2[s] == segments[s]);
4958 }
4959 };
4960 assert forall|s: SegmentId| #[trigger]
4961 old_filt.insert(sid).contains(s) implies new_filt.contains(s) by {
4962 if s == sid {
4963 assert(segments2[s].range == entry.range);
4964 } else {
4965 assert(segments2[s] == segments[s]);
4966 }
4967 };
4968 };
4969 assert(new_filt.len() == old_filt.len() + 1);
4970}
4971
4972pub proof fn lemma_segment_cover_insert_outside(
4975 segments: Map<SegmentId, SegmentEntry>,
4976 sid: SegmentId,
4977 entry: SegmentEntry,
4978 paddr: Paddr,
4979)
4980 requires
4981 !segments.dom().contains(sid),
4982 !(entry.range.start <= paddr < entry.range.end),
4983 ensures
4984 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
4985 segments,
4986 paddr,
4987 ),
4988{
4989 let segments2 = segments.insert(sid, entry);
4990 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
4991 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
4992 let old_filt = segments.dom().filter(pred);
4993 let new_filt = segments2.dom().filter(pred2);
4994 assert(segments2.dom() == segments.dom().insert(sid));
4995 assert(new_filt == old_filt) by {
4996 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.contains(
4997 s,
4998 ) by {
4999 if s == sid {
5000 assert(false);
5002 } else {
5003 assert(segments2[s] == segments[s]);
5004 }
5005 };
5006 assert forall|s: SegmentId| #[trigger] old_filt.contains(s) implies new_filt.contains(
5007 s,
5008 ) by {
5009 assert(s != sid);
5010 assert(segments2[s] == segments[s]);
5011 };
5012 };
5013}
5014
5015pub proof fn lemma_segment_cover_contains(
5018 segments: Map<SegmentId, SegmentEntry>,
5019 sid: SegmentId,
5020 paddr: Paddr,
5021)
5022 requires
5023 segments.dom().contains(sid),
5024 segments[sid].range.start <= paddr < segments[sid].range.end,
5025 ensures
5026 segment_cover_count(segments, paddr) >= 1,
5027{
5028 let filt = segments.dom().filter(
5029 |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end,
5030 );
5031 assert(filt.contains(sid));
5032}
5033
5034pub proof fn lemma_segment_cover_remove_inside(
5037 segments: Map<SegmentId, SegmentEntry>,
5038 sid: SegmentId,
5039 paddr: Paddr,
5040)
5041 requires
5042 segments.dom().contains(sid),
5043 segments[sid].range.start <= paddr < segments[sid].range.end,
5044 ensures
5045 segment_cover_count(segments.remove(sid), paddr) == (segment_cover_count(segments, paddr)
5046 - 1) as nat,
5047{
5048 let segments2 = segments.remove(sid);
5049 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
5050 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
5051 let old_filt = segments.dom().filter(pred);
5052 let new_filt = segments2.dom().filter(pred2);
5053 assert(segments2.dom() == segments.dom().remove(sid));
5054 assert(old_filt.contains(sid));
5055 assert(new_filt == old_filt.remove(sid)) by {
5056 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.remove(
5057 sid,
5058 ).contains(s) by {
5059 assert(s != sid);
5060 assert(segments2[s] == segments[s]);
5061 };
5062 assert forall|s: SegmentId| #[trigger]
5063 old_filt.remove(sid).contains(s) implies new_filt.contains(s) by {
5064 assert(s != sid);
5065 assert(segments2[s] == segments[s]);
5066 };
5067 };
5068}
5069
5070pub proof fn lemma_segment_cover_shrink_front(
5081 segments: Map<SegmentId, SegmentEntry>,
5082 sid: SegmentId,
5083 new_entry: SegmentEntry,
5084 paddr_check: Paddr,
5085)
5086 requires
5087 segments.dom().contains(sid),
5088 segments[sid].range.start < segments[sid].range.end,
5091 segments[sid].range.start % PAGE_SIZE == 0,
5093 segments[sid].range.start + PAGE_SIZE <= MAX_PADDR,
5095 new_entry.range.start == (segments[sid].range.start + PAGE_SIZE) as Paddr,
5096 new_entry.range.end == segments[sid].range.end,
5097 new_entry.range.start <= new_entry.range.end,
5098 paddr_check % PAGE_SIZE == 0,
5099 ensures
5100new_entry.range.start < new_entry.range.end ==> ({
5104 let new_segments = segments.remove(sid).insert(sid, new_entry);
5105 paddr_check == segments[sid].range.start ==> segment_cover_count(
5106 new_segments,
5107 paddr_check,
5108 ) + 1 == segment_cover_count(segments, paddr_check)
5109 }),
5110 new_entry.range.start < new_entry.range.end ==> ({
5111 let new_segments = segments.remove(sid).insert(sid, new_entry);
5112 paddr_check != segments[sid].range.start ==> segment_cover_count(
5113 new_segments,
5114 paddr_check,
5115 ) == segment_cover_count(segments, paddr_check)
5116 }),
5117 new_entry.range.start >= new_entry.range.end ==> ({
5119 let new_segments = segments.remove(sid);
5120 paddr_check == segments[sid].range.start ==> segment_cover_count(
5121 new_segments,
5122 paddr_check,
5123 ) + 1 == segment_cover_count(segments, paddr_check)
5124 }),
5125 new_entry.range.start >= new_entry.range.end ==> ({
5126 let new_segments = segments.remove(sid);
5127 paddr_check != segments[sid].range.start ==> segment_cover_count(
5128 new_segments,
5129 paddr_check,
5130 ) == segment_cover_count(segments, paddr_check)
5131 }),
5132{
5133 let popped = segments[sid].range.start;
5134 let range = segments[sid].range;
5135 assert(range.start < range.end);
5138 let sid_pre_covers = range.start <= paddr_check < range.end;
5139 let new_covers = new_entry.range.start <= paddr_check < new_entry.range.end;
5140 if sid_pre_covers {
5142 lemma_segment_cover_remove_inside(segments, sid, paddr_check);
5143 } else {
5144 lemma_segment_cover_remove_outside(segments, sid, paddr_check);
5145 }
5146 if new_entry.range.start < new_entry.range.end {
5147 let new_segments = segments.remove(sid).insert(sid, new_entry);
5148 if paddr_check == popped {
5149 assert(!new_covers);
5152 assert(sid_pre_covers);
5153 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
5154 lemma_segment_cover_contains(segments, sid, paddr_check);
5155 assert(segment_cover_count(new_segments, paddr_check) + 1 == segment_cover_count(
5156 segments,
5157 paddr_check,
5158 ));
5159 } else if sid_pre_covers {
5160 assert(new_covers);
5164 lemma_segment_cover_contains(segments, sid, paddr_check);
5165 lemma_segment_cover_insert_inside(segments.remove(sid), sid, new_entry, paddr_check);
5166 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5167 segments,
5168 paddr_check,
5169 ));
5170 } else {
5171 assert(!new_covers);
5173 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
5174 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5175 segments,
5176 paddr_check,
5177 ));
5178 }
5179 } else {
5180 let new_segments = segments.remove(sid);
5182 if paddr_check == popped {
5183 assert(sid_pre_covers);
5184 lemma_segment_cover_contains(segments, sid, paddr_check);
5185 assert(segment_cover_count(new_segments, paddr_check) + 1 == segment_cover_count(
5186 segments,
5187 paddr_check,
5188 ));
5189 } else if sid_pre_covers {
5190 assert(false);
5194 } else {
5195 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5197 segments,
5198 paddr_check,
5199 ));
5200 }
5201 }
5202}
5203
5204pub proof fn lemma_segment_cover_split(
5210 segments: Map<SegmentId, SegmentEntry>,
5211 sid: SegmentId,
5212 new_left: SegmentId,
5213 new_right: SegmentId,
5214 entry_left: SegmentEntry,
5215 entry_right: SegmentEntry,
5216 paddr: Paddr,
5217)
5218 requires
5219 segments.dom().contains(sid),
5220 new_left != sid,
5223 new_right != sid,
5224 new_left != new_right,
5225 !segments.remove(sid).dom().contains(new_left),
5226 !segments.remove(sid).dom().contains(new_right),
5227 entry_left.range.start == segments[sid].range.start,
5229 entry_left.range.end == entry_right.range.start,
5230 entry_right.range.end == segments[sid].range.end,
5231 entry_left.range.start < entry_left.range.end,
5232 entry_right.range.start < entry_right.range.end,
5233 ensures
5234 segment_cover_count(
5235 segments.remove(sid).insert(new_left, entry_left).insert(new_right, entry_right),
5236 paddr,
5237 ) == segment_cover_count(segments, paddr),
5238{
5239 let mid_segments = segments.remove(sid);
5240 let with_left = mid_segments.insert(new_left, entry_left);
5241 assert(with_left.dom() == mid_segments.dom().insert(new_left));
5242 assert(!with_left.dom().contains(new_right));
5243 let sid_covers = segments[sid].range.start <= paddr && paddr < segments[sid].range.end;
5244 let left_covers = entry_left.range.start <= paddr && paddr < entry_left.range.end;
5245 let right_covers = entry_right.range.start <= paddr && paddr < entry_right.range.end;
5246 let cover_after_remove = segment_cover_count(mid_segments, paddr);
5248 if sid_covers {
5249 lemma_segment_cover_remove_inside(segments, sid, paddr);
5250 assert(cover_after_remove == (segment_cover_count(segments, paddr) - 1) as nat);
5251 } else {
5252 lemma_segment_cover_remove_outside(segments, sid, paddr);
5253 assert(cover_after_remove == segment_cover_count(segments, paddr));
5254 }
5255 let cover_after_left = segment_cover_count(with_left, paddr);
5257 if left_covers {
5258 lemma_segment_cover_insert_inside(mid_segments, new_left, entry_left, paddr);
5259 assert(cover_after_left == cover_after_remove + 1);
5260 } else {
5261 lemma_segment_cover_insert_outside(mid_segments, new_left, entry_left, paddr);
5262 assert(cover_after_left == cover_after_remove);
5263 }
5264 let final_segments = with_left.insert(new_right, entry_right);
5266 let cover_final = segment_cover_count(final_segments, paddr);
5267 if right_covers {
5268 lemma_segment_cover_insert_inside(with_left, new_right, entry_right, paddr);
5269 assert(cover_final == cover_after_left + 1);
5270 } else {
5271 lemma_segment_cover_insert_outside(with_left, new_right, entry_right, paddr);
5272 assert(cover_final == cover_after_left);
5273 }
5274 let orig = segment_cover_count(segments, paddr);
5276 if sid_covers {
5277 lemma_segment_cover_contains(segments, sid, paddr);
5279 assert(cover_after_remove == (orig - 1) as nat);
5280 assert(cover_after_remove + 1 == orig);
5281 if left_covers {
5282 assert(!right_covers);
5283 assert(cover_after_left == cover_after_remove + 1);
5284 assert(cover_final == cover_after_left);
5285 assert(cover_final == orig);
5286 } else {
5287 assert(right_covers);
5288 assert(cover_after_left == cover_after_remove);
5289 assert(cover_final == cover_after_left + 1);
5290 assert(cover_final == cover_after_remove + 1);
5291 assert(cover_final == orig);
5292 }
5293 } else {
5294 assert(!left_covers);
5295 assert(!right_covers);
5296 assert(cover_after_remove == orig);
5297 assert(cover_after_left == cover_after_remove);
5298 assert(cover_final == cover_after_left);
5299 assert(cover_final == orig);
5300 }
5301}
5302
5303pub proof fn lemma_segment_cover_remove_outside(
5306 segments: Map<SegmentId, SegmentEntry>,
5307 sid: SegmentId,
5308 paddr: Paddr,
5309)
5310 requires
5311 segments.dom().contains(sid),
5312 !(segments[sid].range.start <= paddr < segments[sid].range.end),
5313 ensures
5314 segment_cover_count(segments.remove(sid), paddr) == segment_cover_count(segments, paddr),
5315{
5316 let segments2 = segments.remove(sid);
5317 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
5318 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
5319 let old_filt = segments.dom().filter(pred);
5320 let new_filt = segments2.dom().filter(pred2);
5321 assert(segments2.dom() == segments.dom().remove(sid));
5322 assert(!old_filt.contains(sid));
5323 assert(new_filt == old_filt) by {
5324 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.contains(
5325 s,
5326 ) by {
5327 assert(s != sid);
5328 assert(segments2[s] == segments[s]);
5329 };
5330 assert forall|s: SegmentId| #[trigger] old_filt.contains(s) implies new_filt.contains(
5331 s,
5332 ) by {
5333 assert(s != sid);
5334 assert(segments2[s] == segments[s]);
5335 };
5336 };
5337}
5338
5339pub open spec fn fresh_vm_space_id<'a>(m: Map<VmSpaceId, VmSpaceOwner>) -> VmSpaceId {
5345 choose|id: VmSpaceId| !m.dom().contains(id)
5346}
5347
5348pub open spec fn fresh_cursor_id<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>) -> CursorId {
5350 choose|id: CursorId| !m.dom().contains(id)
5351}
5352
5353pub open spec fn fresh_vm_io_id<'a>(m: Map<VmIoId, VmIoEntry>) -> VmIoId {
5355 choose|id: VmIoId| !m.dom().contains(id)
5356}
5357
5358pub open spec fn fresh_frame_id(m: Map<FrameId, FrameEntry>) -> FrameId {
5360 choose|id: FrameId| !m.dom().contains(id)
5361}
5362
5363pub proof fn lemma_fresh_vm_space_id_not_in_dom<'a>(m: Map<VmSpaceId, VmSpaceOwner>)
5364 ensures
5365 !m.dom().contains(fresh_vm_space_id(m)),
5366{
5367 lemma_finite_int_set_has_unused(m.dom());
5368}
5369
5370pub proof fn lemma_fresh_cursor_id_not_in_dom<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>)
5371 ensures
5372 !m.dom().contains(fresh_cursor_id(m)),
5373{
5374 lemma_finite_int_set_has_unused(m.dom());
5375}
5376
5377pub proof fn lemma_fresh_vm_io_id_not_in_dom<'a>(m: Map<VmIoId, VmIoEntry>)
5378 ensures
5379 !m.dom().contains(fresh_vm_io_id(m)),
5380{
5381 lemma_finite_int_set_has_unused(m.dom());
5382}
5383
5384pub proof fn lemma_fresh_frame_id_not_in_dom(m: Map<FrameId, FrameEntry>)
5385 ensures
5386 !m.dom().contains(fresh_frame_id(m)),
5387{
5388 lemma_finite_int_set_has_unused(m.dom());
5389}
5390
5391pub proof fn tracked_cursor_entry_new<'rcu>(
5393 vm_space: VmSpaceId,
5394 kind: CursorKind,
5395 va: Range<Vaddr>,
5396 tracked owner: CursorOwner<'rcu, UserPtConfig>,
5397 tracked guards: Guards<'rcu>,
5398) -> (tracked res: CursorEntry<'rcu>)
5399 ensures
5400 res.vm_space == vm_space,
5401 res.kind == kind,
5402 res.va == va,
5403 res.owner == owner,
5404 res.guards == guards,
5405{
5406 let tracked res = CursorEntry { vm_space, kind, va, owner, guards };
5407 res
5408}
5409
5410pub proof fn tracked_vm_io_entry_new<'a>(
5412 vm_space: Option<VmSpaceId>,
5413 kind: VmIoKind,
5414 vaddr: Vaddr,
5415 len: usize,
5416 tracked owner: VmIoOwner,
5417) -> tracked VmIoEntry
5418 returns
5419 (VmIoEntry { vm_space, kind, vaddr, len, owner }),
5420{
5421 let tracked res = VmIoEntry { vm_space, kind, vaddr, len, owner };
5422 res
5423}
5424
5425pub proof fn tracked_frame_entry_new(paddr: Paddr) -> tracked FrameEntry
5427 returns
5428 (FrameEntry { paddr }),
5429{
5430 let tracked res = FrameEntry { paddr };
5431 res
5432}
5433
5434pub proof fn tracked_segment_entry_new(range: Range<Paddr>) -> tracked SegmentEntry
5436 returns
5437 (SegmentEntry { range }),
5438{
5439 let tracked res = SegmentEntry { range };
5440 res
5441}
5442
5443pub open spec fn fresh_segment_id(m: Map<SegmentId, SegmentEntry>) -> SegmentId {
5445 choose|id: SegmentId| !m.dom().contains(id)
5446}
5447
5448pub proof fn lemma_fresh_segment_id_not_in_dom(m: Map<SegmentId, SegmentEntry>)
5449 ensures
5450 !m.dom().contains(fresh_segment_id(m)),
5451{
5452 lemma_finite_int_set_has_unused(m.dom());
5453}
5454
5455pub proof fn tracked_unique_entry_new(paddr: Paddr) -> tracked UniqueEntry
5457 returns
5458 (UniqueEntry { paddr }),
5459{
5460 let tracked res = UniqueEntry { paddr };
5461 res
5462}
5463
5464pub open spec fn fresh_unique_id(m: Map<UniqueId, UniqueEntry>) -> UniqueId {
5466 choose|id: UniqueId| !m.dom().contains(id)
5467}
5468
5469pub proof fn lemma_fresh_unique_id_not_in_dom(m: Map<UniqueId, UniqueEntry>)
5470 ensures
5471 !m.dom().contains(fresh_unique_id(m)),
5472{
5473 lemma_finite_int_set_has_unused(m.dom());
5474}
5475
5476}