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::{MetaSlotOwner, 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_owner(s.frames[fid].paddr).ref_count() == 1 ==> handle_count(
458 s.frames,
459 frame_to_index(s.frames[fid].paddr),
460 ) == 1,
461{
462 let paddr = s.frames[fid].paddr;
463 let idx = frame_to_index(paddr);
464 assert(s.regions.slot_owners[idx].ref_count()
465 == s.regions.slot_owners[idx].ref_count_perm.value());
466
467 assert(s.frames.dom().filter(
468 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
469 ).contains(fid));
470}
471
472pub enum VmIoKind {
474 Reader,
475 Writer,
476}
477
478pub tracked struct VmIoEntry {
497 pub ghost vm_space: Option<VmSpaceId>,
498 pub ghost kind: VmIoKind,
499 pub ghost vaddr: Vaddr,
500 pub ghost len: usize,
501 pub owner: VmIoOwner,
502}
503
504impl VmIoEntry {
505 pub open spec fn inv(self) -> bool {
507 &&& self.owner.inv()
508 &&& match self.vm_space {
509 Some(_) => self.owner.mem_view is None,
510 None => match self.kind {
511 VmIoKind::Reader => self.owner.read_view_initialized(),
512 VmIoKind::Writer => self.owner.has_write_view(),
513 },
514 }
515 }
516
517 pub open spec fn is_kernel_reader(self) -> bool {
528 &&& self.vm_space is None
529 &&& self.kind == VmIoKind::Reader
530 }
531
532 pub open spec fn is_kernel_writer(self) -> bool {
533 &&& self.vm_space is None
534 &&& self.kind == VmIoKind::Writer
535 }
536}
537
538pub ghost enum CursorKind {
543 ReadOnly,
544 Mutable,
545}
546
547pub tracked struct CursorEntry<'rcu> {
553 pub ghost vm_space: VmSpaceId,
554 pub ghost kind: CursorKind,
555 pub ghost va: Range<Vaddr>,
556 pub owner: CursorOwner<'rcu, UserPtConfig>,
557 pub guards: Guards<'rcu>,
558}
559
560impl<'rcu> CursorEntry<'rcu> {
561 pub open spec fn inv(self) -> bool {
569 &&& self.owner.inv()
570 &&& self.owner.children_not_locked(self.guards)
571 &&& self.owner.nodes_locked(self.guards)
572 &&& !self.owner.popped_too_high
573 }
574}
575
576pub tracked struct VmStore<'rcu> {
584 pub regions: MetaRegionOwners,
585 pub tlb_model: TlbModel,
586 pub vm_spaces: Map<VmSpaceId, VmSpaceOwner>,
587 pub cursors: Map<CursorId, CursorEntry<'rcu>>,
588 pub vm_ios: Map<VmIoId, VmIoEntry>,
589 pub frames: Map<FrameId, FrameEntry>,
590 pub segments: Map<SegmentId, SegmentEntry>,
591 pub unique_frames: Map<UniqueId, UniqueEntry>,
592}
593
594impl<'a, 'rcu> VmStore<'rcu> {
595 pub open spec fn inv(self) -> bool {
606 self.structural_inv() && self.accounting_inv()
607 }
608
609 pub open spec fn structural_inv(self) -> bool {
615 &&& self.regions.inv()
616 &&& forall|idx: int|
649 0 <= idx < max_meta_slots() ==> #[trigger] self.regions.slots.contains_key(idx) || (
650 self.regions.slot_owners[idx].usage is PageTable
651 && self.regions.slot_owners[idx].ref_count()
652 != REF_COUNT_UNUSED)
653 &&& forall|idx: int|
658 0 <= idx < max_meta_slots()
659 ==> #[trigger] self.regions.slot_owners[idx].in_list_perm.value() == 0
660 &&& self.tlb_model.inv()
661 &&& forall|id: VmSpaceId| #[trigger]
662 self.vm_spaces.dom().contains(id) ==> self.vm_spaces[id].inv()
663 &&& forall|id: CursorId| #[trigger]
664 self.cursors.dom().contains(id) ==> self.cursors[id].inv()
665 &&& forall|id: CursorId| #[trigger]
666 self.cursors.dom().contains(id) ==> self.cursors[id].owner.metaregion_sound(
667 self.regions,
668 )
669 &&& forall|id: CursorId| #[trigger]
670 self.cursors.dom().contains(id) ==> self.vm_spaces.dom().contains(
671 self.cursors[id].vm_space,
672 )
673 &&& forall|id: VmIoId| #[trigger] self.vm_ios.dom().contains(id) ==> self.vm_ios[id].inv()
674 &&& forall|id: VmIoId| #[trigger]
675 self.vm_ios.dom().contains(id) ==> (self.vm_ios[id].vm_space matches Some(vs)
676 ==> self.vm_spaces.dom().contains(vs))
677 &&& forall|id: VmIoId| #[trigger]
678 self.vm_ios.dom().contains(id) ==> self.vm_ios[id].vm_space is Some ==> (
679 self.vm_ios[id].vaddr as nat) + (self.vm_ios[id].len as nat)
680 <= MAX_USERSPACE_VADDR as nat
681 &&& forall|fid: FrameId| #[trigger]
691 self.frames.dom().contains(fid) ==> valid_frame_paddr(
692 self.frames[fid].paddr,
693 )
694 &&& forall|fid: FrameId| #[trigger]
703 self.frames.dom().contains(fid) ==> self.regions.slot_owner(
704 self.frames[fid].paddr,
705 ).usage is Frame
706 &&& forall|sid: SegmentId| #[trigger]
712 self.segments.dom().contains(sid) ==> {
713 let r = self.segments[sid].range;
714 &&& r.start % PAGE_SIZE == 0
715 &&& r.end % PAGE_SIZE == 0
716 &&& r.start < r.end
717 &&& r.end <= MAX_PADDR
718 }
719 &&& forall|sid: SegmentId, paddr: Paddr|
727 #![trigger
728 self.segments.dom().contains(sid),
729 frame_to_index(paddr)]
730 self.segments.dom().contains(sid) && self.segments[sid].range.start <= paddr
731 < self.segments[sid].range.end && paddr % PAGE_SIZE == 0
732 ==> self.regions.slot_owner(
733 paddr,
734 ).usage is Frame
735 &&& forall|uid: UniqueId| #[trigger]
740 self.unique_frames.dom().contains(uid) ==> valid_frame_paddr(
741 self.unique_frames[uid].paddr,
742 )
743 &&& forall|uid: UniqueId| #[trigger]
748 self.unique_frames.dom().contains(uid) ==> {
749 let so = self.regions.slot_owner(self.unique_frames[uid].paddr);
750 &&& so.usage is Frame
751 &&& so.ref_count() == REF_COUNT_UNIQUE
752 &&& so.in_list_perm.value() == 0
753 &&& so.paths_in_pt.is_empty()
754 }
755 &&& forall|uid1: UniqueId, uid2: UniqueId|
759 #![trigger
760 self.unique_frames.dom().contains(uid1),
761 self.unique_frames.dom().contains(uid2)]
762 self.unique_frames.dom().contains(uid1) && self.unique_frames.dom().contains(uid2)
763 && self.unique_frames[uid1].paddr == self.unique_frames[uid2].paddr ==> uid1 == uid2
764 }
765
766 pub open spec fn accounting_inv(self) -> bool {
796 &&& forall|idx: int|
835 #![trigger self.regions.slot_owners[idx]]
836 0 <= idx < max_meta_slots() && self.regions.slot_owners[idx].ref_count()
837 == REF_COUNT_UNUSED ==> handle_count(self.frames, idx) == 0
838 && self.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
839 self.segments,
840 index_to_frame(idx),
841 )
842 == 0
843 &&& forall|idx: int|
848 #![trigger self.regions.slot_owners[idx]]
849 0 <= idx < max_meta_slots() && self.regions.slot_owners[idx].usage is Frame
850 && self.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
851 && self.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE ==> handle_count(
852 self.frames,
853 idx,
854 ) > 0 || self.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
855 self.segments,
856 index_to_frame(idx),
857 )
858 > 0
859 &&& forall|idx: int|
867 #![trigger self.regions.slot_owners[idx]]
868 0 <= idx < max_meta_slots() && self.regions.slot_owners[idx].usage is Frame && (
869 handle_count(self.frames, idx) > 0 || self.regions.slot_owners[idx].paths_in_pt.len()
870 > 0 || segment_cover_count(self.segments, index_to_frame(idx)) > 0) ==> {
871 let so = self.regions.slot_owners[idx];
872 let rc = so.ref_count();
873 &&& rc != REF_COUNT_UNUSED
874 &&& rc != REF_COUNT_UNIQUE
875 &&& rc == handle_count(self.frames, idx) + so.paths_in_pt.len()
876 + segment_cover_count(self.segments, index_to_frame(idx))
877 &&& so.storage_perm().is_init()
878 }
879 }
880}
881
882pub enum Op {
888 NewVmSpace,
889 DropVmSpace { vs: VmSpaceId },
890 OpenCursor { vs: VmSpaceId, va: Range<Vaddr> },
891 OpenCursorMut { vs: VmSpaceId, va: Range<Vaddr> },
892 DropCursor { c: CursorId },
893 Query { c: CursorId },
894 FindNext { c: CursorId, len: usize },
895 Jump { c: CursorId, va: Vaddr },
896 VirtAddr { c: CursorId },
897 Map { c: CursorId, fid: FrameId, prop: PageProperty },
898 Unmap { c: CursorId, len: usize },
899 ProtectNext { c: CursorId, len: usize },
900 NewReader { vs: VmSpaceId, vaddr: Vaddr, len: usize },
901 NewWriter { vs: VmSpaceId, vaddr: Vaddr, len: usize },
902 NewKernelReader { vaddr: Vaddr, len: usize },
903 NewKernelWriter { vaddr: Vaddr, len: usize },
904 DropReader { vio: VmIoId },
905 DropWriter { vio: VmIoId },
906 ReaderReadVal { source: VmIoId },
910 ReaderCollect { source: VmIoId },
912 ReaderLimit { vio: VmIoId, max: usize },
913 ReaderSkip { vio: VmIoId, n: usize },
914 ReaderQuery { vio: VmIoId },
915 WriterWriteVal { writer: VmIoId },
917 WriterFillZeros { vio: VmIoId, len: usize },
918 WriterLimit { vio: VmIoId, max: usize },
919 WriterSkip { vio: VmIoId, n: usize },
920 WriterQuery { vio: VmIoId },
921 Read { source: VmIoId, dest: VmIoId },
924 Write { source: VmIoId, dest: VmIoId },
927 FrameFromUnused { paddr: Paddr },
930 FrameFromInUse { paddr: Paddr },
934 FrameDrop { fid: FrameId },
940 SegmentFromUnused { range: Range<Paddr> },
945 SegmentDrop { sid: SegmentId },
949 SegmentSplit { sid: SegmentId, offset: usize },
956 SegmentNext { sid: SegmentId },
965 SegmentClone { sid: SegmentId },
971 SegmentSlice { sid: SegmentId, sub_range: Range<Paddr> },
978 UniqueFromUnused { paddr: Paddr },
983 UniqueDrop { uid: UniqueId },
987 FromUnique { uid: UniqueId },
992 TryFromShared { fid: FrameId },
998}
999
1000pub open spec fn op_pre<'rcu>(s: VmStore<'rcu>, op: Op) -> bool {
1018 match op {
1019 Op::NewVmSpace => true,
1020 Op::DropVmSpace { vs } => s.vm_spaces.dom().contains(vs) && (forall|c: CursorId| #[trigger]
1021 s.cursors.dom().contains(c) ==> s.cursors[c].vm_space != vs) && (forall|v: VmIoId|
1022 #[trigger]
1023 s.vm_ios.dom().contains(v) ==> s.vm_ios[v].vm_space != Some(vs)),
1024 Op::OpenCursor { vs, va: _ } => s.vm_spaces.dom().contains(vs),
1025 Op::OpenCursorMut { vs, va: _ } => s.vm_spaces.dom().contains(vs),
1026 Op::DropCursor { c } => s.cursors.dom().contains(c),
1027 Op::Query { c } => s.cursors.dom().contains(c),
1028 Op::FindNext { c, len: _ } => s.cursors.dom().contains(c),
1029 Op::Jump { c, va: _ } => s.cursors.dom().contains(c),
1030 Op::VirtAddr { c } => s.cursors.dom().contains(c),
1031 Op::Map { c, fid, prop: _ } => s.cursors.dom().contains(c) && s.frames.dom().contains(fid),
1044 Op::Unmap { c, len: _ } => s.cursors.dom().contains(c),
1045 Op::ProtectNext { c, len: _ } => s.cursors.dom().contains(c),
1046 Op::NewReader { vs, vaddr: _, len: _ } => s.vm_spaces.dom().contains(vs),
1047 Op::NewWriter { vs, vaddr: _, len: _ } => s.vm_spaces.dom().contains(vs),
1048 Op::NewKernelReader { vaddr: _, len: _ } => true,
1049 Op::NewKernelWriter { vaddr: _, len: _ } => true,
1050 Op::DropReader { vio } => s.vm_ios.dom().contains(vio),
1051 Op::DropWriter { vio } => s.vm_ios.dom().contains(vio),
1052 Op::ReaderReadVal { source } => s.vm_ios.dom().contains(source),
1053 Op::ReaderCollect { source } => s.vm_ios.dom().contains(source),
1054 Op::ReaderLimit { vio, max: _ } => s.vm_ios.dom().contains(vio),
1055 Op::ReaderSkip { vio, n: _ } => s.vm_ios.dom().contains(vio),
1056 Op::ReaderQuery { vio } => s.vm_ios.dom().contains(vio),
1057 Op::WriterWriteVal { writer } => s.vm_ios.dom().contains(writer),
1058 Op::WriterFillZeros { vio, len: _ } => s.vm_ios.dom().contains(vio),
1059 Op::WriterLimit { vio, max: _ } => s.vm_ios.dom().contains(vio),
1060 Op::WriterSkip { vio, n: _ } => s.vm_ios.dom().contains(vio),
1061 Op::WriterQuery { vio } => s.vm_ios.dom().contains(vio),
1062 Op::Read { source, dest } => s.vm_ios.dom().contains(source) && s.vm_ios.dom().contains(
1068 dest,
1069 ) && source != dest && s.vm_ios[source].is_kernel_reader()
1070 && s.vm_ios[dest].is_kernel_writer(),
1071 Op::Write { source, dest } => s.vm_ios.dom().contains(source) && s.vm_ios.dom().contains(
1073 dest,
1074 ) && source != dest && s.vm_ios[source].is_kernel_reader()
1075 && s.vm_ios[dest].is_kernel_writer(),
1076 Op::FrameFromUnused { paddr: _ } => true,
1077 Op::FrameFromInUse { paddr: _ } => true,
1078 Op::FrameDrop { fid } => s.frames.dom().contains(fid) && segment_cover_count(
1095 s.segments,
1096 s.frames[fid].paddr,
1097 ) == 0,
1098 Op::SegmentFromUnused { range: _ } => true,
1105 Op::SegmentDrop { sid } => s.segments.dom().contains(sid),
1111 Op::SegmentSplit { sid, offset } => s.segments.dom().contains(sid) && offset % PAGE_SIZE
1116 == 0 && 0 < offset && offset < (s.segments[sid].range.end
1117 - s.segments[sid].range.start),
1118 Op::SegmentNext { sid } => s.segments.dom().contains(sid),
1121 Op::SegmentClone { sid } => s.segments.dom().contains(sid) && forall|paddr: Paddr|
1122 #![trigger frame_to_index(paddr)]
1123 (s.segments[sid].range.start <= paddr < s.segments[sid].range.end && paddr % PAGE_SIZE
1124 == 0) ==> s.regions.slot_owner(paddr).ref_count() + 1 <= REF_COUNT_MAX,
1125 Op::SegmentSlice { sid, sub_range } => s.segments.dom().contains(sid) && sub_range.start
1131 % PAGE_SIZE == 0 && sub_range.end % PAGE_SIZE == 0 && s.segments[sid].range.start
1132 <= sub_range.start && sub_range.start < sub_range.end && sub_range.end
1133 <= s.segments[sid].range.end && forall|paddr: Paddr|
1134 #![trigger frame_to_index(paddr)]
1135 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0)
1136 ==> s.regions.slot_owner(paddr).ref_count() + 1 <= REF_COUNT_MAX,
1137 Op::UniqueFromUnused { paddr: _ } => true,
1144 Op::UniqueDrop { uid } => s.unique_frames.dom().contains(uid),
1149 Op::FromUnique { uid } => s.unique_frames.dom().contains(uid),
1152 Op::TryFromShared { fid } => s.frames.dom().contains(fid),
1156 }
1157}
1158
1159impl<'rcu> VmStore<'rcu> {
1164 pub proof fn tracked_extract_vm_space(tracked &mut self, vs: VmSpaceId) -> (tracked res:
1169 VmSpaceOwner)
1170 requires
1171 old(self).inv(),
1172 old(self).vm_spaces.dom().contains(vs),
1173 forall|c: CursorId| #[trigger]
1174 old(self).cursors.dom().contains(c) ==> old(self).cursors[c].vm_space != vs,
1175 forall|v: VmIoId| #[trigger]
1176 old(self).vm_ios.dom().contains(v) ==> old(self).vm_ios[v].vm_space != Some(vs),
1177 ensures
1178 final(self).regions == old(self).regions,
1179 final(self).tlb_model == old(self).tlb_model,
1180 final(self).vm_spaces == old(self).vm_spaces.remove(vs),
1181 final(self).cursors == old(self).cursors,
1182 final(self).vm_ios == old(self).vm_ios,
1183 final(self).frames == old(self).frames,
1184 final(self).segments == old(self).segments,
1185 final(self).unique_frames == old(self).unique_frames,
1186 res == old(self).vm_spaces[vs],
1187 final(self).inv(),
1188 {
1189 self.vm_spaces.tracked_remove(vs)
1190 }
1191
1192 pub proof fn lemma_insert_vm_space(
1195 tracked &mut self,
1196 vs: VmSpaceId,
1197 tracked owner: VmSpaceOwner,
1198 )
1199 requires
1200 old(self).inv(),
1201 !old(self).vm_spaces.dom().contains(vs),
1202 owner.inv(),
1203 ensures
1204 final(self).regions == old(self).regions,
1205 final(self).tlb_model == old(self).tlb_model,
1206 final(self).vm_spaces == old(self).vm_spaces.insert(vs, owner),
1207 final(self).cursors == old(self).cursors,
1208 final(self).vm_ios == old(self).vm_ios,
1209 final(self).frames == old(self).frames,
1210 final(self).segments == old(self).segments,
1211 final(self).unique_frames == old(self).unique_frames,
1212 final(self).inv(),
1213 {
1214 self.vm_spaces.tracked_insert(vs, owner);
1215 }
1216
1217 pub proof fn tracked_extract_cursor(tracked &mut self, c: CursorId) -> (tracked res:
1219 CursorEntry<'rcu>)
1220 requires
1221 old(self).inv(),
1222 old(self).cursors.dom().contains(c),
1223 ensures
1224 final(self).regions == old(self).regions,
1225 final(self).tlb_model == old(self).tlb_model,
1226 final(self).vm_spaces == old(self).vm_spaces,
1227 final(self).cursors == old(self).cursors.remove(c),
1228 final(self).vm_ios == old(self).vm_ios,
1229 final(self).frames == old(self).frames,
1230 final(self).segments == old(self).segments,
1231 final(self).unique_frames == old(self).unique_frames,
1232 res == old(self).cursors[c],
1233 final(self).inv(),
1234 {
1235 self.cursors.tracked_remove(c)
1236 }
1237
1238 pub proof fn lemma_insert_cursor(
1243 tracked &mut self,
1244 c: CursorId,
1245 tracked entry: CursorEntry<'rcu>,
1246 )
1247 requires
1248 old(self).inv(),
1249 !old(self).cursors.dom().contains(c),
1250 entry.inv(),
1251 entry.owner.metaregion_sound(old(self).regions),
1252 old(self).vm_spaces.dom().contains(entry.vm_space),
1253 ensures
1254 final(self).regions == old(self).regions,
1255 final(self).tlb_model == old(self).tlb_model,
1256 final(self).vm_spaces == old(self).vm_spaces,
1257 final(self).cursors == old(self).cursors.insert(c, entry),
1258 final(self).vm_ios == old(self).vm_ios,
1259 final(self).frames == old(self).frames,
1260 final(self).segments == old(self).segments,
1261 final(self).unique_frames == old(self).unique_frames,
1262 final(self).inv(),
1263 {
1264 self.cursors.tracked_insert(c, entry);
1265 }
1266
1267 pub proof fn tracked_extract_vm_io(tracked &mut self, vio: VmIoId) -> (tracked res: VmIoEntry)
1269 requires
1270 old(self).inv(),
1271 old(self).vm_ios.dom().contains(vio),
1272 ensures
1273 final(self).regions == old(self).regions,
1274 final(self).tlb_model == old(self).tlb_model,
1275 final(self).vm_spaces == old(self).vm_spaces,
1276 final(self).cursors == old(self).cursors,
1277 final(self).vm_ios == old(self).vm_ios.remove(vio),
1278 final(self).frames == old(self).frames,
1279 final(self).segments == old(self).segments,
1280 final(self).unique_frames == old(self).unique_frames,
1281 res == old(self).vm_ios[vio],
1282 final(self).inv(),
1283 {
1284 self.vm_ios.tracked_remove(vio)
1285 }
1286
1287 pub proof fn lemma_insert_vm_io(tracked &mut self, vio: VmIoId, tracked entry: VmIoEntry)
1295 requires
1296 old(self).inv(),
1297 !old(self).vm_ios.dom().contains(vio),
1298 entry.inv(),
1299 entry.vm_space matches Some(vs) ==> old(self).vm_spaces.dom().contains(vs),
1300 entry.vm_space is Some ==> (entry.vaddr as nat) + (entry.len as nat)
1301 <= MAX_USERSPACE_VADDR as nat,
1302 ensures
1303 final(self).regions == old(self).regions,
1304 final(self).tlb_model == old(self).tlb_model,
1305 final(self).vm_spaces == old(self).vm_spaces,
1306 final(self).cursors == old(self).cursors,
1307 final(self).vm_ios == old(self).vm_ios.insert(vio, entry),
1308 final(self).frames == old(self).frames,
1309 final(self).segments == old(self).segments,
1310 final(self).unique_frames == old(self).unique_frames,
1311 final(self).inv(),
1312 {
1313 self.vm_ios.tracked_insert(vio, entry);
1314 }
1315
1316 pub proof fn tracked_extract_frame(tracked &mut self, fid: FrameId) -> (tracked res: FrameEntry)
1325 requires
1326 old(self).structural_inv(),
1327 old(self).frames.dom().contains(fid),
1328 ensures
1329 final(self).regions == old(self).regions,
1330 final(self).tlb_model == old(self).tlb_model,
1331 final(self).vm_spaces == old(self).vm_spaces,
1332 final(self).cursors == old(self).cursors,
1333 final(self).vm_ios == old(self).vm_ios,
1334 final(self).frames == old(self).frames.remove(fid),
1335 final(self).segments == old(self).segments,
1336 final(self).unique_frames == old(self).unique_frames,
1337 res == old(self).frames[fid],
1338 final(self).structural_inv(),
1339 {
1340 self.frames.tracked_remove(fid)
1341 }
1342
1343 pub proof fn lemma_insert_frame(tracked &mut self, fid: FrameId, tracked entry: FrameEntry)
1352 requires
1353 old(self).structural_inv(),
1354 !old(self).frames.dom().contains(fid),
1355 valid_frame_paddr(entry.paddr),
1356 old(self).regions.slot_owner(entry.paddr).usage is Frame,
1361 ensures
1362 final(self).regions == old(self).regions,
1363 final(self).tlb_model == old(self).tlb_model,
1364 final(self).vm_spaces == old(self).vm_spaces,
1365 final(self).cursors == old(self).cursors,
1366 final(self).vm_ios == old(self).vm_ios,
1367 final(self).frames == old(self).frames.insert(fid, entry),
1368 final(self).segments == old(self).segments,
1369 final(self).unique_frames == old(self).unique_frames,
1370 final(self).structural_inv(),
1371 {
1372 self.frames.tracked_insert(fid, entry);
1373 }
1374
1375 pub proof fn tracked_extract_unique(tracked &mut self, uid: UniqueId) -> (tracked res:
1379 UniqueEntry)
1380 requires
1381 old(self).unique_frames.dom().contains(uid),
1382 ensures
1383 final(self).regions == old(self).regions,
1384 final(self).tlb_model == old(self).tlb_model,
1385 final(self).vm_spaces == old(self).vm_spaces,
1386 final(self).cursors == old(self).cursors,
1387 final(self).vm_ios == old(self).vm_ios,
1388 final(self).frames == old(self).frames,
1389 final(self).segments == old(self).segments,
1390 final(self).unique_frames == old(self).unique_frames.remove(uid),
1391 res == old(self).unique_frames[uid],
1392 {
1393 self.unique_frames.tracked_remove(uid)
1394 }
1395
1396 pub proof fn lemma_insert_unique(tracked &mut self, uid: UniqueId, tracked entry: UniqueEntry)
1402 requires
1403 !old(self).unique_frames.dom().contains(uid),
1404 ensures
1405 final(self).regions == old(self).regions,
1406 final(self).tlb_model == old(self).tlb_model,
1407 final(self).vm_spaces == old(self).vm_spaces,
1408 final(self).cursors == old(self).cursors,
1409 final(self).vm_ios == old(self).vm_ios,
1410 final(self).frames == old(self).frames,
1411 final(self).segments == old(self).segments,
1412 final(self).unique_frames == old(self).unique_frames.insert(uid, entry),
1413 {
1414 self.unique_frames.tracked_insert(uid, entry);
1415 }
1416
1417 pub proof fn tracked_extract_segment(tracked &mut self, sid: SegmentId) -> (tracked res:
1424 SegmentEntry)
1425 requires
1426 old(self).segments.dom().contains(sid),
1427 ensures
1428 final(self).regions == old(self).regions,
1429 final(self).tlb_model == old(self).tlb_model,
1430 final(self).vm_spaces == old(self).vm_spaces,
1431 final(self).cursors == old(self).cursors,
1432 final(self).vm_ios == old(self).vm_ios,
1433 final(self).frames == old(self).frames,
1434 final(self).segments == old(self).segments.remove(sid),
1435 final(self).unique_frames == old(self).unique_frames,
1436 res == old(self).segments[sid],
1437 {
1438 self.segments.tracked_remove(sid)
1439 }
1440
1441 pub proof fn lemma_insert_segment(
1446 tracked &mut self,
1447 sid: SegmentId,
1448 tracked entry: SegmentEntry,
1449 )
1450 requires
1451 !old(self).segments.dom().contains(sid),
1452 ensures
1453 final(self).regions == old(self).regions,
1454 final(self).tlb_model == old(self).tlb_model,
1455 final(self).vm_spaces == old(self).vm_spaces,
1456 final(self).cursors == old(self).cursors,
1457 final(self).vm_ios == old(self).vm_ios,
1458 final(self).frames == old(self).frames,
1459 final(self).segments == old(self).segments.insert(sid, entry),
1460 final(self).unique_frames == old(self).unique_frames,
1461 {
1462 self.segments.tracked_insert(sid, entry);
1463 }
1464}
1465
1466pub proof fn lemma_step<'rcu>(tracked s: &mut VmStore<'rcu>, op: Op)
1476 requires
1477 old(s).inv(),
1478 op_pre(*old(s), op),
1479 ensures
1480 final(s).inv(),
1481{
1482 match op {
1483 Op::NewVmSpace => lemma_step_new_vm_space(s),
1484 Op::DropVmSpace { vs } => lemma_step_drop_vm_space(s, vs),
1485 Op::OpenCursor { vs, va } => lemma_step_open_cursor(s, vs, va),
1486 Op::OpenCursorMut { vs, va } => lemma_step_open_cursor_mut(s, vs, va),
1487 Op::DropCursor { c } => lemma_step_drop_cursor(s, c),
1488 Op::Query { c } => lemma_step_query(s, c),
1489 Op::FindNext { c, len } => lemma_step_find_next(s, c, len),
1490 Op::Jump { c, va } => lemma_step_jump(s, c, va),
1491 Op::VirtAddr { c: _ } => {},
1492 Op::Map { c, fid, prop } => lemma_step_map(s, c, fid, prop),
1493 Op::Unmap { c, len } => lemma_step_unmap(s, c, len),
1494 Op::ProtectNext { c, len } => lemma_step_protect_next(s, c, len),
1495 Op::NewReader { vs, vaddr, len } => lemma_step_new_vm_io(
1496 s,
1497 vs,
1498 vaddr,
1499 len,
1500 VmIoKind::Reader,
1501 ),
1502 Op::NewWriter { vs, vaddr, len } => lemma_step_new_vm_io(
1503 s,
1504 vs,
1505 vaddr,
1506 len,
1507 VmIoKind::Writer,
1508 ),
1509 Op::NewKernelReader { vaddr, len } => lemma_step_new_kernel_vm_io(
1510 s,
1511 vaddr,
1512 len,
1513 VmIoKind::Reader,
1514 ),
1515 Op::NewKernelWriter { vaddr, len } => lemma_step_new_kernel_vm_io(
1516 s,
1517 vaddr,
1518 len,
1519 VmIoKind::Writer,
1520 ),
1521 Op::DropReader { vio } => lemma_step_drop_vm_io(s, vio),
1522 Op::DropWriter { vio } => lemma_step_drop_vm_io(s, vio),
1523 Op::ReaderReadVal { source: _ } => {},
1525 Op::ReaderCollect { source: _ } => {},
1526 Op::WriterWriteVal { writer: _ } => {},
1527 Op::ReaderLimit { vio, max } => lemma_step_vm_io_method(
1528 s,
1529 vio,
1530 io::VmIoMethod::ReaderLimit(max),
1531 ),
1532 Op::ReaderSkip { vio, n } => lemma_step_vm_io_method(s, vio, io::VmIoMethod::ReaderSkip(n)),
1533 Op::ReaderQuery { vio: _ } => {},
1534 Op::WriterFillZeros { vio, len } => lemma_step_vm_io_method(
1535 s,
1536 vio,
1537 io::VmIoMethod::WriterFillZeros(len),
1538 ),
1539 Op::WriterLimit { vio, max } => lemma_step_vm_io_method(
1540 s,
1541 vio,
1542 io::VmIoMethod::WriterLimit(max),
1543 ),
1544 Op::WriterSkip { vio, n } => lemma_step_vm_io_method(s, vio, io::VmIoMethod::WriterSkip(n)),
1545 Op::WriterQuery { vio: _ } => {},
1546 Op::Read { source, dest } => lemma_step_read(s, source, dest),
1548 Op::Write { source, dest } => lemma_step_write(s, source, dest),
1551 Op::FrameFromUnused { paddr } => lemma_step_frame_from_unused(s, paddr),
1552 Op::FrameFromInUse { paddr } => lemma_step_frame_from_in_use(s, paddr),
1553 Op::FrameDrop { fid } => lemma_step_frame_drop(s, fid),
1554 Op::SegmentFromUnused { range } => lemma_step_segment_from_unused(s, range),
1555 Op::SegmentDrop { sid } => lemma_step_segment_drop(s, sid),
1556 Op::SegmentSplit { sid, offset } => lemma_step_segment_split(s, sid, offset),
1557 Op::SegmentNext { sid } => lemma_step_segment_next(s, sid),
1558 Op::SegmentClone { sid } => lemma_step_segment_clone(s, sid),
1559 Op::SegmentSlice { sid, sub_range } => lemma_step_segment_slice(s, sid, sub_range),
1560 Op::UniqueFromUnused { paddr } => lemma_step_unique_from_unused(s, paddr),
1561 Op::UniqueDrop { uid } => lemma_step_unique_drop(s, uid),
1562 Op::FromUnique { uid } => lemma_step_from_unique(s, uid),
1563 Op::TryFromShared { fid } => lemma_step_try_from_shared(s, fid),
1564 }
1565}
1566
1567proof fn lemma_accounting_preserved_by_pt_alloc<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1583 requires
1584 s_old.inv(),
1585 s_new.frames == s_old.frames,
1586 s_new.segments == s_old.segments,
1588 forall|i: int|
1589 #![trigger s_new.regions.slot_owners[i]]
1590 s_new.regions.slot_owners[i] != s_old.regions.slot_owners[i] ==> {
1591 &&& s_old.regions.slot_owners[i].ref_count() == REF_COUNT_UNUSED
1592 &&& s_new.regions.slot_owners[i].ref_count() != REF_COUNT_UNUSED
1593 &&& s_new.regions.slot_owners[i].usage !is Frame
1594 },
1595 ensures
1596 s_new.accounting_inv(),
1597 forall|fid: FrameId| #[trigger]
1602 s_new.frames.dom().contains(fid) ==> s_new.regions.slot_owner(
1603 s_new.frames[fid].paddr,
1604 ).usage is Frame,
1605 forall|sid: SegmentId, paddr: Paddr|
1607 #![trigger
1608 s_new.segments.dom().contains(sid),
1609 frame_to_index(paddr)]
1610 s_new.segments.dom().contains(sid) && s_new.segments[sid].range.start <= paddr
1611 < s_new.segments[sid].range.end && paddr % PAGE_SIZE == 0
1612 ==> s_new.regions.slot_owner(paddr).usage is Frame,
1613{
1614 assert forall|idx: int|
1617 #![trigger s_new.regions.slot_owners[idx]]
1618 0 <= idx < max_meta_slots() && s_new.regions.slot_owners[idx].ref_count()
1619 == REF_COUNT_UNUSED implies handle_count(s_new.frames, idx) == 0
1620 && s_new.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1621 s_new.segments,
1622 index_to_frame(idx),
1623 ) == 0 by {
1624 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1625 };
1626 assert forall|idx: int|
1629 #![trigger s_new.regions.slot_owners[idx]]
1630 0 <= idx < max_meta_slots() && s_new.regions.slot_owners[idx].usage is Frame
1631 && s_new.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
1632 && s_new.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE implies handle_count(
1633 s_new.frames,
1634 idx,
1635 ) > 0 || s_new.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1636 s_new.segments,
1637 index_to_frame(idx),
1638 ) > 0 by {
1639 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1640 };
1641 assert forall|idx: int|
1644 #![trigger s_new.regions.slot_owners[idx]]
1645 0 <= idx < max_meta_slots() && s_new.regions.slot_owners[idx].usage is Frame && (
1646 handle_count(s_new.frames, idx) > 0 || s_new.regions.slot_owners[idx].paths_in_pt.len() > 0
1647 || segment_cover_count(s_new.segments, index_to_frame(idx)) > 0) implies {
1648 let so = s_new.regions.slot_owners[idx];
1649 let rc = so.ref_count();
1650 &&& rc != REF_COUNT_UNUSED
1651 &&& rc != REF_COUNT_UNIQUE
1652 &&& rc == handle_count(s_new.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1653 s_new.segments,
1654 index_to_frame(idx),
1655 )
1656 &&& so.storage_perm().is_init()
1657 } by {
1658 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1659 };
1660 assert forall|sid: SegmentId, paddr: Paddr|
1665 #![trigger
1666 s_new.segments.dom().contains(sid),
1667 frame_to_index(paddr)]
1668 s_new.segments.dom().contains(sid) && s_new.segments[sid].range.start <= paddr
1669 < s_new.segments[sid].range.end && paddr % PAGE_SIZE
1670 == 0 implies s_new.regions.slot_owner(paddr).usage is Frame by {
1671 let idx = frame_to_index(paddr);
1672 assert(s_old.regions.slot_owners[idx].usage is Frame);
1674 lemma_segment_cover_contains(s_old.segments, sid, paddr);
1677 assert(s_old.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED);
1678 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1680 };
1681 assert forall|fid: FrameId| #[trigger]
1687 s_new.frames.dom().contains(fid) implies s_new.regions.slot_owner(
1688 s_new.frames[fid].paddr,
1689 ).usage is Frame by {
1690 let idx = frame_to_index(s_new.frames[fid].paddr);
1691 assert(s_old.frames.dom().filter(
1693 |gid: FrameId| frame_to_index(s_old.frames[gid].paddr) == idx,
1694 ).contains(fid));
1695 assert(handle_count(s_old.frames, idx) >= 1);
1696 assert(s_old.regions.slot_owners[idx].usage is Frame);
1698 assert(s_old.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED);
1699 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1702 };
1703}
1704
1705proof fn lemma_coverage_preserved_slots_eq<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1713 requires
1714 s_old.structural_inv(),
1715 s_new.regions.slots == s_old.regions.slots,
1716 forall|idx: int|
1717 #![trigger s_new.regions.slot_owners[idx]]
1718 !s_old.regions.slots.contains_key(idx) ==> s_new.regions.slot_owners[idx]
1719 == s_old.regions.slot_owners[idx],
1720 ensures
1721 forall|idx: int|
1722 0 <= idx < max_meta_slots() ==> #[trigger] s_new.regions.slots.contains_key(idx) || (
1723 s_new.regions.slot_owners[idx].usage is PageTable
1724 && s_new.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED),
1725{
1726 assert forall|idx: int|
1727 0 <= idx < max_meta_slots() implies #[trigger] s_new.regions.slots.contains_key(idx) || (
1728 s_new.regions.slot_owners[idx].usage is PageTable && s_new.regions.slot_owners[idx].ref_count()
1729 != REF_COUNT_UNUSED) by {
1730 if !s_new.regions.slots.contains_key(idx) {
1731 assert(!s_old.regions.slots.contains_key(idx));
1734 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1735 }
1736 };
1737}
1738
1739proof fn lemma_step_new_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>)
1740 requires
1741 old(s).inv(),
1742 ensures
1743 final(s).inv(),
1744{
1745 let ghost s_before = *s;
1746 let tracked owner = vm_space::new_vm_space_step(&mut s.regions);
1747 let ghost id = fresh_vm_space_id(s.vm_spaces);
1748 lemma_fresh_vm_space_id_not_in_dom(s.vm_spaces);
1749 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1752 let ghost root_idx = vm_space::vm_space_root_idx(owner);
1758 assert forall|idx: int|
1759 0 <= idx < max_meta_slots() implies #[trigger] s.regions.slots.contains_key(idx) || (
1760 s.regions.slot_owners[idx].usage is PageTable && s.regions.slot_owners[idx].ref_count()
1761 != REF_COUNT_UNUSED) by {
1762 if idx == root_idx {
1763 } else {
1765 assert(s.regions.slots.contains_key(idx) == s_before.regions.slots.contains_key(idx));
1768 if s.regions.slot_owners[idx] != s_before.regions.slot_owners[idx] {
1769 assert(s_before.regions.slot_owners[idx].ref_count() == REF_COUNT_UNUSED);
1773 assert(s_before.regions.slots.contains_key(idx));
1774 }
1775 }
1776 };
1777 s.lemma_insert_vm_space(id, owner);
1778}
1779
1780proof fn lemma_step_drop_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId)
1781 requires
1782 old(s).inv(),
1783 old(s).vm_spaces.dom().contains(vs),
1784 forall|c: CursorId| #[trigger]
1785 old(s).cursors.dom().contains(c) ==> old(s).cursors[c].vm_space != vs,
1786 forall|v: VmIoId| #[trigger]
1787 old(s).vm_ios.dom().contains(v) ==> old(s).vm_ios[v].vm_space != Some(vs),
1788 ensures
1789 final(s).inv(),
1790{
1791 let tracked owner = s.tracked_extract_vm_space(vs);
1792 vm_space::drop_vm_space_step(owner);
1793}
1794
1795proof fn lemma_step_open_cursor<'rcu>(
1796 tracked s: &mut VmStore<'rcu>,
1797 vs: VmSpaceId,
1798 va: Range<Vaddr>,
1799)
1800 requires
1801 old(s).inv(),
1802 old(s).vm_spaces.dom().contains(vs),
1803 ensures
1804 final(s).inv(),
1805{
1806 let ghost s_before = *s;
1807 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1808 let tracked res = cursor::open_cursor_step(vm_space_ref, &mut s.regions, vs, va);
1809 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1812 match res {
1813 Option::Some(entry) => {
1814 let ghost id = fresh_cursor_id(s.cursors);
1815 lemma_fresh_cursor_id_not_in_dom(s.cursors);
1816 s.lemma_insert_cursor(id, entry);
1817 },
1818 Option::None => {},
1819 }
1820}
1821
1822proof fn lemma_step_open_cursor_mut<'rcu>(
1823 tracked s: &mut VmStore<'rcu>,
1824 vs: VmSpaceId,
1825 va: Range<Vaddr>,
1826)
1827 requires
1828 old(s).inv(),
1829 old(s).vm_spaces.dom().contains(vs),
1830 ensures
1831 final(s).inv(),
1832{
1833 let ghost s_before = *s;
1834 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1835 let tracked res = cursor::open_cursor_mut_step(vm_space_ref, &mut s.regions, vs, va);
1836 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1839 match res {
1840 Option::Some(entry) => {
1841 let ghost id = fresh_cursor_id(s.cursors);
1842 lemma_fresh_cursor_id_not_in_dom(s.cursors);
1843 s.lemma_insert_cursor(id, entry);
1844 },
1845 Option::None => {},
1846 }
1847}
1848
1849proof fn lemma_step_drop_cursor<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1850 requires
1851 old(s).inv(),
1852 old(s).cursors.dom().contains(c),
1853 ensures
1854 final(s).inv(),
1855{
1856 let tracked entry = s.tracked_extract_cursor(c);
1857 cursor::drop_cursor_step(entry);
1858}
1859
1860proof fn lemma_step_query<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1861 requires
1862 old(s).inv(),
1863 old(s).cursors.dom().contains(c),
1864 ensures
1865 final(s).inv(),
1866{
1867 let ghost old_frames = s.frames;
1868 let ghost old_regions = s.regions;
1869 let tracked mut entry = s.tracked_extract_cursor(c);
1870 let ghost res = cursor::cursor_query_step(&mut entry, &mut s.regions);
1871 match res {
1872 Option::None => {
1873 s.lemma_insert_cursor(c, entry);
1876 },
1877 Option::Some(paddr) => {
1878 let ghost target_idx = frame_to_index(paddr);
1883 s.regions.lemma_contains_valid_frame_paddr(paddr);
1884 let ghost id = fresh_frame_id(s.frames);
1885 lemma_fresh_frame_id_not_in_dom(s.frames);
1886 let tracked frame_entry = tracked_frame_entry_new(paddr);
1887 s.lemma_insert_frame(id, frame_entry);
1888 assert(s.regions.slot_owners[target_idx].usage is Frame);
1896 assert forall|idx: int|
1898 #![trigger s.regions.slot_owners[idx]]
1899 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
1900 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1901 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1902 s.segments,
1903 index_to_frame(idx),
1904 ) == 0 by {
1905 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1906 if idx == target_idx {
1907 assert(false);
1910 } else {
1911 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1916 }
1917 };
1918 assert forall|idx: int|
1919 #![trigger s.regions.slot_owners[idx]]
1920 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
1921 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
1922 && s.regions.slot_owners[idx].ref_count()
1923 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1924 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1925 s.segments,
1926 index_to_frame(idx),
1927 ) > 0 by {
1928 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1929 if idx == target_idx {
1930 assert(handle_count(s.frames, target_idx) >= 1);
1932 } else {
1933 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1934 }
1935 };
1936 assert forall|idx: int|
1937 #![trigger s.regions.slot_owners[idx]]
1938 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
1939 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
1940 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
1941 let so = s.regions.slot_owners[idx];
1942 let rc = so.ref_count();
1943 &&& rc != REF_COUNT_UNUSED
1944 &&& rc != REF_COUNT_UNIQUE
1945 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1946 s.segments,
1947 index_to_frame(idx),
1948 )
1949 &&& so.storage_perm().is_init()
1950 } by {
1951 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1952 if idx == target_idx {
1953 if old_regions.slot_owners[target_idx].ref_count() == REF_COUNT_UNUSED {
1954 assert(REF_COUNT_UNUSED == 0u32);
1959 assert(s.regions.slot_owners[target_idx].ref_count() == 1);
1960 assert(handle_count(s.frames, target_idx) == 1);
1961 assert(s.regions.slot_owners[target_idx].paths_in_pt.len()
1962 == old_regions.slot_owners[target_idx].paths_in_pt.len());
1963 assert(old_regions.slot_owners[target_idx].paths_in_pt.len() == 0);
1964 assert(segment_cover_count(s.segments, index_to_frame(target_idx)) == 0);
1965 } else if old_regions.slot_owners[target_idx].ref_count() == REF_COUNT_UNIQUE {
1966 assert(false);
1967 } else {
1968 let pre_so = old_regions.slot_owners[target_idx];
1971 let pre_rc = pre_so.ref_count();
1972 let pre_paths = pre_so.paths_in_pt.len();
1973 let pre_H = handle_count(old_frames, target_idx);
1974 let pre_cover = segment_cover_count(s.segments, index_to_frame(target_idx));
1975 if pre_H == 0 && pre_paths == 0 && pre_cover == 0 {
1976 assert(false);
1977 } else {
1978 assert(pre_rc == pre_H + pre_paths + pre_cover);
1982 assert(handle_count(s.frames, target_idx) == pre_H + 1);
1983 }
1984 }
1985 } else {
1986 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1987 }
1988 };
1989 s.lemma_insert_cursor(c, entry);
1990 },
1991 }
1992}
1993
1994proof fn lemma_step_find_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1995 requires
1996 old(s).inv(),
1997 old(s).cursors.dom().contains(c),
1998 ensures
1999 final(s).inv(),
2000{
2001 let tracked mut entry = s.tracked_extract_cursor(c);
2002 cursor::cursor_find_next_step(&mut entry, &mut s.regions, len);
2003 s.lemma_insert_cursor(c, entry);
2004}
2005
2006proof fn lemma_step_jump<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, va: Vaddr)
2007 requires
2008 old(s).inv(),
2009 old(s).cursors.dom().contains(c),
2010 ensures
2011 final(s).inv(),
2012{
2013 let tracked mut entry = s.tracked_extract_cursor(c);
2014 cursor::cursor_jump_step(&mut entry, &mut s.regions, va);
2015 s.lemma_insert_cursor(c, entry);
2016}
2017
2018proof fn lemma_step_protect_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
2019 requires
2020 old(s).inv(),
2021 old(s).cursors.dom().contains(c),
2022 ensures
2023 final(s).inv(),
2024{
2025 let tracked mut entry = s.tracked_extract_cursor(c);
2026 cursor::cursor_protect_next_step(&mut entry, &mut s.regions, len);
2027 s.lemma_insert_cursor(c, entry);
2028}
2029
2030#[verifier::spinoff_prover]
2031proof fn lemma_step_map<'rcu>(
2032 tracked s: &mut VmStore<'rcu>,
2033 c: CursorId,
2034 fid: FrameId,
2035 prop: PageProperty,
2036)
2037 requires
2038 old(s).inv(),
2039 old(s).cursors.dom().contains(c),
2040 old(s).frames.dom().contains(fid),
2041 ensures
2042 final(s).inv(),
2043{
2044 hide(VmStore::inv);
2045 hide(VmStore::structural_inv);
2046 hide(VmStore::accounting_inv);
2047 assert(s.structural_inv()) by {
2048 reveal(VmStore::inv);
2049 };
2050 assert(s.accounting_inv()) by {
2051 reveal(VmStore::inv);
2052 };
2053 assert(s.regions.inv() && s.tlb_model.inv() && s.cursors[c].inv()
2054 && s.cursors[c].owner.metaregion_sound(s.regions) && s.vm_spaces.dom().contains(
2055 s.cursors[c].vm_space,
2056 )) by {
2057 reveal(VmStore::structural_inv);
2058 };
2059 assert(s.regions.slot_owner(s.frames[fid].paddr).usage is Frame) by {
2062 reveal(VmStore::structural_inv);
2063 };
2064 let ghost paddr = s.frames[fid].paddr;
2065 let ghost target_idx = frame_to_index(paddr);
2066 let ghost old_frames = s.frames;
2067 let ghost old_regions = s.regions;
2068 assert(valid_frame_paddr(paddr)) by {
2070 reveal(VmStore::structural_inv);
2071 };
2072 s.regions.lemma_contains_valid_frame_paddr(paddr);
2073 assert(old_frames.dom().filter(
2076 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == target_idx,
2077 ).contains(fid));
2078 assert(handle_count(old_frames, target_idx) >= 1);
2079 let ghost pre_rc_target = old_regions.slot_owners[target_idx].ref_count();
2082 let ghost pre_paths_target = old_regions.slot_owners[target_idx].paths_in_pt.len();
2083 let ghost pre_cover_target = segment_cover_count(s.segments, index_to_frame(target_idx));
2084 assert(pre_rc_target != REF_COUNT_UNUSED && pre_rc_target != REF_COUNT_UNIQUE && pre_rc_target
2085 == handle_count(old_frames, target_idx) + pre_paths_target + pre_cover_target
2086 && old_regions.slot_owners[target_idx].storage_perm().is_init()) by {
2087 reveal(VmStore::accounting_inv);
2088 };
2089 let tracked mut entry = s.tracked_extract_cursor(c);
2090 assert(s.structural_inv()) by {
2094 reveal(VmStore::inv);
2095 };
2096 let tracked _frame_entry = s.tracked_extract_frame(fid);
2097 assert(entry.inv());
2098 assert(entry.owner.metaregion_sound(s.regions));
2099 assert(s.regions.inv());
2100 assert(s.tlb_model.inv());
2101 cursor::map_step(&mut entry, &mut s.regions, &mut s.tlb_model, paddr, prop);
2102 assert forall|idx: int|
2108 #![trigger s.regions.slot_owners[idx]]
2109 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
2110 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2111 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2112 s.segments,
2113 index_to_frame(idx),
2114 ) == 0 by {
2115 reveal(VmStore::accounting_inv);
2116 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2118 lemma_handle_count_remove(old_frames, fid, idx);
2119 if idx == target_idx {
2120 assert(s.regions.slot_owners[idx].ref_count() == pre_rc_target);
2123 assert(false);
2124 }
2125 };
2126 assert forall|idx: int|
2127 #![trigger s.regions.slot_owners[idx]]
2128 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2129 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
2130 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE implies handle_count(
2131 s.frames,
2132 idx,
2133 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2134 s.segments,
2135 index_to_frame(idx),
2136 ) > 0 by {
2137 reveal(VmStore::accounting_inv);
2138 lemma_handle_count_remove(old_frames, fid, idx);
2139 if idx == target_idx {
2140 assert(s.regions.slot_owners[idx].paths_in_pt.len() == pre_paths_target + 1);
2142 } else if old_regions.slot_owners[idx].ref_count() == REF_COUNT_UNUSED {
2143 assert(s.regions.slot_owners[idx].usage !is Frame);
2145 } else {
2146 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2149 }
2150 };
2151 assert forall|idx: int|
2152 #![trigger s.regions.slot_owners[idx]]
2153 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2154 s.frames,
2155 idx,
2156 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2157 s.segments,
2158 index_to_frame(idx),
2159 ) > 0) implies {
2160 let so = s.regions.slot_owners[idx];
2161 let rc = so.ref_count();
2162 &&& rc != REF_COUNT_UNUSED
2163 &&& rc != REF_COUNT_UNIQUE
2164 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2165 s.segments,
2166 index_to_frame(idx),
2167 )
2168 &&& so.storage_perm().is_init()
2169 } by {
2170 reveal(VmStore::accounting_inv);
2171 lemma_handle_count_remove(old_frames, fid, idx);
2172 if idx == target_idx {
2173 assert(s.regions.slot_owners[idx].ref_count() == pre_rc_target);
2179 assert(s.regions.slot_owners[idx].paths_in_pt.len() == pre_paths_target + 1);
2180 assert(handle_count(s.frames, idx) == (handle_count(old_frames, idx) - 1) as nat);
2181 } else if old_regions.slot_owners[idx].ref_count() == REF_COUNT_UNUSED {
2182 assert(s.regions.slot_owners[idx].usage !is Frame);
2183 } else {
2184 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2185 }
2186 };
2187 assert forall|fid_other: FrameId| #[trigger]
2193 s.frames.dom().contains(fid_other) implies s.regions.slot_owner(
2194 s.frames[fid_other].paddr,
2195 ).usage is Frame by {
2196 reveal(VmStore::structural_inv);
2197 reveal(VmStore::accounting_inv);
2198 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2199 assert(old_regions.slot_owners[other_idx].usage is Frame);
2201 if other_idx == target_idx {
2202 assert(s.regions.slot_owners[target_idx].usage
2204 == old_regions.slot_owners[target_idx].usage);
2205 } else {
2206 assert(old_frames.dom().filter(
2213 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
2214 ).contains(fid_other));
2215 assert(handle_count(old_frames, other_idx) >= 1);
2216 assert(old_regions.slot_owners[other_idx].ref_count() != REF_COUNT_UNUSED);
2217 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
2218 }
2219 };
2220 assert forall|sid: SegmentId, paddr_c: Paddr|
2225 #![trigger
2226 s.segments.dom().contains(sid),
2227 frame_to_index(paddr_c)]
2228 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
2229 < s.segments[sid].range.end && paddr_c % PAGE_SIZE == 0 implies s.regions.slot_owner(
2230 paddr_c,
2231 ).usage is Frame by {
2232 reveal(VmStore::structural_inv);
2233 reveal(VmStore::accounting_inv);
2234 let cov_idx = frame_to_index(paddr_c);
2235 lemma_segment_cover_contains(old_regions_segments_helper(s), sid, paddr_c);
2237 assert(old_regions.slot_owners[cov_idx].usage is Frame);
2238 assert(old_regions.slot_owners[cov_idx].ref_count() != REF_COUNT_UNUSED);
2239 if cov_idx == target_idx {
2240 assert(s.regions.slot_owners[target_idx].usage
2242 == old_regions.slot_owners[target_idx].usage);
2243 } else {
2244 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
2246 }
2247 };
2248 lemma_accounting_inv_intro(*s);
2249 assert(s.structural_inv()) by {
2250 reveal(VmStore::structural_inv);
2251 };
2252 assert(s.inv()) by {
2253 reveal(VmStore::inv);
2254 };
2255 assert(s.vm_spaces.dom().contains(entry.vm_space));
2256 s.lemma_insert_cursor(c, entry);
2257}
2258
2259spec fn old_regions_segments_helper<'rcu>(s: &VmStore<'rcu>) -> Map<SegmentId, SegmentEntry> {
2263 s.segments
2264}
2265
2266proof fn lemma_step_unmap<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
2267 requires
2268 old(s).inv(),
2269 old(s).cursors.dom().contains(c),
2270 ensures
2271 final(s).inv(),
2272{
2273 let ghost s_before = *s;
2274 let ghost old_regions = s.regions;
2275 let ghost old_frames = s.frames;
2276 let tracked mut entry = s.tracked_extract_cursor(c);
2277 cursor::cursor_mut_regions_step(
2278 &mut entry,
2279 &mut s.regions,
2280 &mut s.tlb_model,
2281 cursor::CursorMutRegionsMethod::Unmap(len),
2282 );
2283 lemma_coverage_preserved_slots_eq(s_before, *s);
2286 assert forall|idx: int|
2292 #![trigger s.regions.slot_owners[idx]]
2293 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
2294 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2295 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2296 s.segments,
2297 index_to_frame(idx),
2298 ) == 0 by {
2299 assert(s.regions.contains(idx));
2303 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0) by {
2312 if segment_cover_count(old(s).segments, index_to_frame(idx)) > 0 {
2313 let pa = index_to_frame(idx);
2314 let sid = lemma_segment_cover_witness(old(s).segments, pa);
2315 assert(pa == (idx * PAGE_SIZE) as usize);
2319 assert(pa % PAGE_SIZE == 0);
2320 assert(frame_to_index(pa) == idx);
2321 assert(old_regions.slot_owners[idx].usage is Frame);
2323 assert(old_regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED);
2325 assert(old_regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX);
2326 assert(s.regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX);
2328 }
2329 };
2330 if old_regions.slot_owners[idx].usage is Frame {
2332 assert(s.regions.slot_owners[idx].usage != PageUsage::MMIO);
2335 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
2336 } else if old_regions.slot_owners[idx].usage == PageUsage::MMIO {
2343 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2346 } else {
2347 assert(s.regions.slot_owners[idx].usage != PageUsage::MMIO);
2350 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
2351 assert(handle_count(s.frames, idx) == 0) by {
2352 let filt = s.frames.dom().filter(
2353 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
2354 );
2355 assert forall|fid: FrameId| #[trigger] filt.contains(fid) implies false by {
2356 assert(s.frames.dom().contains(fid));
2360 assert(frame_to_index(s.frames[fid].paddr) == idx);
2361 assert(s.regions.slot_owners[idx].usage is Frame);
2362 };
2363 assert(filt == Set::empty());
2364 };
2365 }
2366 };
2367 assert forall|idx: int|
2368 #![trigger s.regions.slot_owners[idx]]
2369 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2370 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
2371 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE implies handle_count(
2372 s.frames,
2373 idx,
2374 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2375 s.segments,
2376 index_to_frame(idx),
2377 ) > 0 by {
2378 assert(s.regions.contains(idx));
2387 assert(old_regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED) by {
2388 if old_regions.slot_owners[idx].ref_count() == REF_COUNT_UNUSED {
2389 assert(old_regions.contains(idx));
2391 assert(old_regions.slot_owners[idx].paths_in_pt == Set::empty());
2392 assert(s.regions.slot_owners[idx].paths_in_pt.len() == 0);
2398 assert(false);
2399 }
2400 };
2401 if handle_count(old_frames, idx) > 0 {
2404 assert(handle_count(s.frames, idx) > 0);
2405 } else if segment_cover_count(s.segments, index_to_frame(idx)) > 0 {
2406 } else {
2408 assert(s.regions.slot_owners[idx].paths_in_pt.len() > 0);
2414 }
2415 };
2416 assert forall|idx: int|
2417 #![trigger s.regions.slot_owners[idx]]
2418 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2419 s.frames,
2420 idx,
2421 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0) implies {
2422 let so = s.regions.slot_owners[idx];
2423 let rc = so.ref_count();
2424 &&& rc != REF_COUNT_UNUSED
2425 &&& rc != REF_COUNT_UNIQUE
2426 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2427 s.segments,
2428 index_to_frame(idx),
2429 )
2430 &&& so.storage_perm().is_init()
2431 } by {
2432 if handle_count(s.frames, idx) > 0 {
2439 assert(handle_count(old_frames, idx) > 0);
2441 } else {
2442 assert(old_regions.slot_owners[idx].paths_in_pt.len() > 0);
2451 }
2452 };
2464 assert forall|fid_other: FrameId| #[trigger]
2467 s.frames.dom().contains(fid_other) implies s.regions.slot_owner(
2468 s.frames[fid_other].paddr,
2469 ).usage is Frame by {
2470 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2471 assert(s.regions.slot_owners[other_idx].usage == old_regions.slot_owners[other_idx].usage);
2472 };
2473 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
2480 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
2481 &&& so.usage is Frame
2482 &&& so.ref_count() == REF_COUNT_UNIQUE
2483 &&& so.in_list_perm.value() == 0
2484 &&& so.paths_in_pt.is_empty()
2485 } by {
2486 let u_idx = frame_to_index(s.unique_frames[u].paddr);
2487 assert(old(s).unique_frames.dom().contains(u));
2488 assert(old_regions.slot_owners[u_idx].usage is Frame);
2490 assert(old_regions.slot_owners[u_idx].ref_count() == REF_COUNT_UNIQUE);
2491 assert(old_regions.slot_owners[u_idx].paths_in_pt.is_empty());
2492 assert(old_regions.slot_owners[u_idx].in_list_perm.value() == 0);
2493 assert(valid_frame_paddr(s.unique_frames[u].paddr));
2495 s.regions.lemma_contains_valid_frame_paddr(s.unique_frames[u].paddr);
2496 assert(s.regions.contains(u_idx));
2497 assert(s.regions.slot_owners[u_idx].usage == old_regions.slot_owners[u_idx].usage);
2499 assert(s.regions.slot_owners[u_idx].in_list_perm
2500 == old_regions.slot_owners[u_idx].in_list_perm);
2501 assert(s.regions.slot_owners[u_idx].paths_in_pt.len()
2504 <= old_regions.slot_owners[u_idx].paths_in_pt.len());
2505 assert(old_regions.slot_owners[u_idx].paths_in_pt.len() == 0);
2506 assert(s.regions.slot_owners[u_idx].paths_in_pt =~= Set::empty());
2507 assert(s.regions.slot_owners[u_idx].ref_count() == REF_COUNT_UNIQUE);
2508 };
2509 s.lemma_insert_cursor(c, entry);
2510}
2511
2512proof fn lemma_step_new_vm_io<'rcu>(
2513 tracked s: &mut VmStore<'rcu>,
2514 vs: VmSpaceId,
2515 vaddr: Vaddr,
2516 len: usize,
2517 kind: VmIoKind,
2518)
2519 requires
2520 old(s).inv(),
2521 old(s).vm_spaces.dom().contains(vs),
2522 ensures
2523 final(s).inv(),
2524{
2525 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
2526 let tracked res = io::new_vm_io_step(vm_space_ref, Some(vs), vaddr, len, kind);
2527 match res {
2528 Option::Some(entry) => {
2529 let ghost id = fresh_vm_io_id(s.vm_ios);
2530 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2531 s.lemma_insert_vm_io(id, entry);
2532 },
2533 Option::None => {},
2534 }
2535}
2536
2537proof fn lemma_step_new_kernel_vm_io<'rcu>(
2538 tracked s: &mut VmStore<'rcu>,
2539 vaddr: Vaddr,
2540 len: usize,
2541 kind: VmIoKind,
2542)
2543 requires
2544 old(s).inv(),
2545 ensures
2546 final(s).inv(),
2547{
2548 let tracked entry = io::new_kernel_vm_io_step(vaddr, len, kind);
2549 let ghost id = fresh_vm_io_id(s.vm_ios);
2550 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2551 s.lemma_insert_vm_io(id, entry);
2552}
2553
2554proof fn lemma_step_drop_vm_io<'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId)
2555 requires
2556 old(s).inv(),
2557 old(s).vm_ios.dom().contains(vio),
2558 ensures
2559 final(s).inv(),
2560{
2561 let tracked entry = s.tracked_extract_vm_io(vio);
2562 io::drop_vm_io_step(entry);
2563}
2564
2565proof fn lemma_step_vm_io_method<'rcu>(
2566 tracked s: &mut VmStore<'rcu>,
2567 vio: VmIoId,
2568 method: io::VmIoMethod,
2569)
2570 requires
2571 old(s).inv(),
2572 old(s).vm_ios.dom().contains(vio),
2573 ensures
2574 final(s).inv(),
2575{
2576 let tracked mut entry = s.tracked_extract_vm_io(vio);
2577 io::vm_io_method_step(&mut entry, method);
2578 s.lemma_insert_vm_io(vio, entry);
2579}
2580
2581proof fn lemma_step_read<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
2582 requires
2583 old(s).inv(),
2584 old(s).vm_ios.dom().contains(source),
2585 old(s).vm_ios.dom().contains(dest),
2586 source != dest,
2587 old(s).vm_ios[source].vm_space is None,
2588 old(s).vm_ios[source].kind == VmIoKind::Reader,
2589 old(s).vm_ios[dest].vm_space is None,
2590 old(s).vm_ios[dest].kind == VmIoKind::Writer,
2591 ensures
2592 final(s).inv(),
2593{
2594 let tracked mut src = s.tracked_extract_vm_io(source);
2595 let tracked mut dst = s.tracked_extract_vm_io(dest);
2596 let tracked val = io::read_step(&mut src, &mut dst);
2597 s.lemma_insert_vm_io(source, src);
2598 s.lemma_insert_vm_io(dest, dst);
2599 let ghost id = fresh_vm_io_id(s.vm_ios);
2600 lemma_fresh_vm_io_id_not_in_dom(s.vm_ios);
2601 s.lemma_insert_vm_io(id, val);
2602}
2603
2604proof fn lemma_step_write<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
2605 requires
2606 old(s).inv(),
2607 old(s).vm_ios.dom().contains(source),
2608 old(s).vm_ios.dom().contains(dest),
2609 source != dest,
2610 old(s).vm_ios[source].vm_space is None,
2611 old(s).vm_ios[source].kind == VmIoKind::Reader,
2612 old(s).vm_ios[dest].vm_space is None,
2613 old(s).vm_ios[dest].kind == VmIoKind::Writer,
2614 ensures
2615 final(s).inv(),
2616{
2617 let tracked mut src = s.tracked_extract_vm_io(source);
2618 let tracked mut dst = s.tracked_extract_vm_io(dest);
2619 s.lemma_insert_vm_io(source, src);
2620 s.lemma_insert_vm_io(dest, dst);
2621}
2622
2623proof fn lemma_step_frame_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2624 requires
2625 old(s).inv(),
2626 ensures
2627 final(s).inv(),
2628{
2629 let ghost old_frames = s.frames;
2636 let ghost old_regions = s.regions;
2637 if !valid_frame_paddr(paddr) || s.regions.slots.contains_key(frame_to_index(paddr)) {
2638 let tracked res = frame::from_unused_step(&mut s.regions, paddr);
2639 match res {
2640 Option::Some(entry) => {
2641 let ghost id = fresh_frame_id(s.frames);
2642 lemma_fresh_frame_id_not_in_dom(s.frames);
2643 let ghost target_idx = frame_to_index(paddr);
2644 let ghost entry_paddr = entry.paddr;
2645 s.lemma_insert_frame(id, entry);
2646 assert(s.frames[id].paddr == paddr);
2647
2648 assert(handle_count(old_frames, target_idx) == 0);
2651 assert(old_regions.slot_owners[target_idx].paths_in_pt.is_empty());
2652
2653 assert forall|idx: int|
2656 #![trigger s.regions.slot_owners[idx]]
2657 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
2658 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2659 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
2660 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2661 if idx == target_idx {
2662 assert(false);
2664 } else {
2665 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2666 }
2667 };
2668
2669 assert forall|idx: int|
2673 #![trigger s.regions.slot_owners[idx]]
2674 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2675 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
2676 && s.regions.slot_owners[idx].ref_count()
2677 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2678 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2679 s.segments,
2680 index_to_frame(idx),
2681 ) > 0 by {
2682 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2683 if idx == target_idx {
2684 assert(handle_count(s.frames, idx) == 1);
2685 } else {
2686 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2687 }
2688 };
2689
2690 assert forall|idx: int|
2692 #![trigger s.regions.slot_owners[idx]]
2693 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
2694 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
2695 > 0 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2696 let so = s.regions.slot_owners[idx];
2697 let rc = so.ref_count();
2698 &&& rc != REF_COUNT_UNUSED
2699 &&& rc != REF_COUNT_UNIQUE
2700 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
2701 + segment_cover_count(s.segments, index_to_frame(idx))
2702 &&& so.storage_perm().is_init()
2703 } by {
2704 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2705 if idx == target_idx {
2706 assert(old_regions.slot_owners[idx].ref_count() == REF_COUNT_UNUSED);
2707 assert(handle_count(old_frames, idx) == 0);
2708 assert(handle_count(s.frames, idx) == 1);
2709 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
2712 } else {
2713 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2716 }
2717 };
2718 },
2719 Option::None => {
2720 assert(s.regions == old_regions);
2722 },
2723 }
2724 }
2725}
2726
2727proof fn lemma_step_frame_from_in_use<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2728 requires
2729 old(s).inv(),
2730 ensures
2731 final(s).inv(),
2732{
2733 let ghost old_frames = s.frames;
2738 let ghost old_regions = s.regions;
2739 if !valid_frame_paddr(paddr) || s.regions.slots.contains_key(frame_to_index(paddr)) {
2740 let tracked res = frame::from_in_use_step(&mut s.regions, paddr);
2741 match res {
2742 Option::Some(entry) => {
2743 let ghost id = fresh_frame_id(s.frames);
2744 lemma_fresh_frame_id_not_in_dom(s.frames);
2745 let ghost target_idx = frame_to_index(paddr);
2746 s.lemma_insert_frame(id, entry);
2747 assert(s.frames[id].paddr == paddr);
2748
2749 assert forall|idx: int|
2752 #![trigger s.regions.slot_owners[idx]]
2753 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
2754 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2755 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
2756 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2757 if idx == target_idx {
2758 assert(false);
2759 } else {
2760 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2761 }
2762 };
2763
2764 assert forall|idx: int|
2767 #![trigger s.regions.slot_owners[idx]]
2768 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2769 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
2770 && s.regions.slot_owners[idx].ref_count()
2771 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2772 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2773 s.segments,
2774 index_to_frame(idx),
2775 ) > 0 by {
2776 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2777 if idx == target_idx {
2778 assert(handle_count(s.frames, idx) >= 1);
2779 } else {
2780 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2781 }
2782 };
2783
2784 assert forall|idx: int|
2786 #![trigger s.regions.slot_owners[idx]]
2787 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
2788 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
2789 > 0 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2790 let so = s.regions.slot_owners[idx];
2791 let rc = so.ref_count();
2792 &&& rc != REF_COUNT_UNUSED
2793 &&& rc != REF_COUNT_UNIQUE
2794 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
2795 + segment_cover_count(s.segments, index_to_frame(idx))
2796 &&& so.storage_perm().is_init()
2797 } by {
2798 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2799 if idx == target_idx {
2800 assert(old_regions.slot_owners[idx].usage is Frame);
2804 } else {
2805 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2806 }
2807 };
2808 },
2809 Option::None => {
2810 assert(s.regions == old_regions);
2811 },
2812 }
2813 }
2814}
2815
2816proof fn lemma_step_frame_drop<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
2817 requires
2818 old(s).inv(),
2819 old(s).frames.dom().contains(fid),
2820 segment_cover_count(old(s).segments, old(s).frames[fid].paddr) == 0,
2825 ensures
2826 final(s).inv(),
2827{
2828 lemma_frame_drop_pre_derivable(*s, fid);
2831 let ghost p = s.frames[fid].paddr;
2832 assert(valid_frame_paddr(p));
2833 s.regions.lemma_contains_valid_frame_paddr(p);
2834 let ghost idx_p = frame_to_index(p);
2835 assert(s.frames.dom().filter(
2839 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx_p,
2840 ).contains(fid));
2841 assert(handle_count(s.frames, idx_p) >= 1);
2842 let ghost target_idx = frame_to_index(p);
2843 let ghost old_frames = s.frames;
2844 let ghost old_regions = s.regions;
2845 let tracked entry = s.tracked_extract_frame(fid);
2846 frame::drop_step(&mut s.regions, entry);
2847
2848 assert forall|idx: int|
2857 #![trigger s.regions.slot_owners[idx]]
2858 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
2859 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2860 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2861 s.segments,
2862 index_to_frame(idx),
2863 ) == 0 by {
2864 lemma_handle_count_remove(old_frames, fid, idx);
2865 if idx == target_idx {
2866 assert(old_regions.slot_owners[idx].ref_count() == 1);
2868 assert(handle_count(old_frames, idx) == 1);
2871 assert(handle_count(s.frames, idx) == 0);
2872 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
2874 } else {
2875 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2876 }
2877 };
2878
2879 assert forall|idx: int|
2884 #![trigger s.regions.slot_owners[idx]]
2885 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2886 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
2887 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE implies handle_count(
2888 s.frames,
2889 idx,
2890 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2891 s.segments,
2892 index_to_frame(idx),
2893 ) > 0 by {
2894 lemma_handle_count_remove(old_frames, fid, idx);
2895 if idx == target_idx {
2896 assert(handle_count(old_frames, idx) >= 1);
2901 } else {
2902 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2903 }
2904 };
2905
2906 assert forall|idx: int|
2907 #![trigger s.regions.slot_owners[idx]]
2908 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2909 s.frames,
2910 idx,
2911 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2912 s.segments,
2913 index_to_frame(idx),
2914 ) > 0) implies {
2915 let so = s.regions.slot_owners[idx];
2916 let rc = so.ref_count();
2917 &&& rc != REF_COUNT_UNUSED
2918 &&& rc != REF_COUNT_UNIQUE
2919 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2920 s.segments,
2921 index_to_frame(idx),
2922 )
2923 &&& so.storage_perm().is_init()
2924 } by {
2925 lemma_handle_count_remove(old_frames, fid, idx);
2926 if idx == target_idx {
2927 assert(old_regions.slot_owners[idx].usage is Frame);
2931 assert(handle_count(old_frames, idx) > 0);
2932 let ghost pre_rc = old_regions.slot_owners[idx].ref_count();
2933 let ghost pre_h = handle_count(old_frames, idx);
2934 let ghost pre_p = old_regions.slot_owners[idx].paths_in_pt.len();
2935 assert(pre_rc == pre_h + pre_p);
2936 let ghost post_h = handle_count(s.frames, idx);
2938 assert(post_h == (pre_h - 1) as nat);
2939 let ghost post_p = s.regions.slot_owners[idx].paths_in_pt.len();
2941 assert(post_p == pre_p);
2942 let ghost post_rc = s.regions.slot_owners[idx].ref_count();
2943 if pre_rc > 1 {
2944 assert(post_rc == (pre_rc - 1) as u64);
2946 assert(post_rc as nat == post_h + post_p);
2947 assert(s.regions.slot_owners[idx].storage_perm()
2948 == old_regions.slot_owners[idx].storage_perm());
2949 } else {
2950 assert(pre_h == 1);
2953 assert(pre_p == 0);
2954 assert(post_h == 0);
2955 assert(post_p == 0);
2956 assert(post_rc == REF_COUNT_UNUSED);
2958 assert(false);
2962 }
2963 } else {
2964 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2967 }
2968 };
2969}
2970
2971#[verifier::spinoff_prover]
2976proof fn lemma_step_segment_from_unused_accounting<'rcu>(
2977 s_after: VmStore<'rcu>,
2978 old_store: VmStore<'rcu>,
2979 range: Range<Paddr>,
2980 id: SegmentId,
2981 entry: SegmentEntry,
2982)
2983 requires
2984 s_after.regions.inv(),
2985 s_after.frames == old_store.frames,
2986 !old_store.segments.dom().contains(id),
2988 s_after.segments == old_store.segments.insert(id, entry),
2989 entry.range == range,
2990 range.start % PAGE_SIZE == 0,
2992 range.end % PAGE_SIZE == 0,
2993 range.start < range.end,
2994 range.end <= MAX_PADDR,
2995 old_store.accounting_inv(),
2997 old_store.regions.inv(),
2998 forall|paddr: Paddr|
3000 #![trigger frame_to_index(paddr)]
3001 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) ==> {
3002 let idx = frame_to_index(paddr);
3003 let so = s_after.regions.slot_owners[idx];
3004 &&& so.usage is Frame
3005 &&& so.ref_count() == 1
3006 &&& so.paths_in_pt.is_empty()
3007 &&& so.storage_perm().is_init()
3008 },
3009 forall|i: int|
3011 #![trigger s_after.regions.slot_owners[i]]
3012 i < max_meta_slots() && !(range.start <= index_to_frame(i) < range.end)
3013 ==> s_after.regions.slot_owners[i] == old_store.regions.slot_owners[i],
3014 forall|paddr: Paddr|
3016 #![trigger frame_to_index(paddr)]
3017 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
3018 ==> old_store.regions.slot_owner(paddr).ref_count() == REF_COUNT_UNUSED,
3019 ensures
3020 s_after.accounting_inv(),
3021{
3022 let old_regions = old_store.regions;
3023 let old_frames = old_store.frames;
3024 let old_segments = old_store.segments;
3025 assert forall|idx: int|
3026 #![trigger s_after.regions.slot_owners[idx]]
3027 0 <= idx < max_meta_slots() && s_after.regions.slot_owners[idx].ref_count()
3028 == REF_COUNT_UNUSED implies handle_count(s_after.frames, idx) == 0
3029 && s_after.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3030 s_after.segments,
3031 index_to_frame(idx),
3032 ) == 0 by {
3033 let paddr = index_to_frame(idx);
3034 if range.start <= paddr < range.end {
3035 assert(false);
3036 } else {
3037 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
3038 }
3039 };
3040 assert forall|idx: int|
3041 #![trigger s_after.regions.slot_owners[idx]]
3042 0 <= idx < max_meta_slots() && s_after.regions.slot_owners[idx].usage is Frame
3043 && s_after.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
3044 && s_after.regions.slot_owners[idx].ref_count()
3045 != REF_COUNT_UNIQUE implies handle_count(s_after.frames, idx) > 0
3046 || s_after.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3047 s_after.segments,
3048 index_to_frame(idx),
3049 ) > 0 by {
3050 let paddr = index_to_frame(idx);
3051 if range.start <= paddr < range.end {
3052 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
3053 } else {
3054 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
3055 }
3056 };
3057 assert forall|idx: int|
3058 #![trigger s_after.regions.slot_owners[idx]]
3059 0 <= idx < max_meta_slots() && s_after.regions.slot_owners[idx].usage is Frame && (
3060 handle_count(s_after.frames, idx) > 0 || s_after.regions.slot_owners[idx].paths_in_pt.len()
3061 > 0 || segment_cover_count(s_after.segments, index_to_frame(idx)) > 0) implies {
3062 let so = s_after.regions.slot_owners[idx];
3063 let rc = so.ref_count();
3064 &&& rc != REF_COUNT_UNUSED
3065 &&& rc != REF_COUNT_UNIQUE
3066 &&& rc == handle_count(s_after.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3067 s_after.segments,
3068 index_to_frame(idx),
3069 )
3070 &&& so.storage_perm().is_init()
3071 } by {
3072 let paddr = index_to_frame(idx);
3073 if range.start <= paddr < range.end {
3074 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
3075 } else {
3078 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
3079 }
3080 };
3081}
3082
3083#[verifier::spinoff_prover]
3088proof fn lemma_step_segment_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, range: Range<Paddr>)
3089 requires
3090 old(s).inv(),
3091 ensures
3092 final(s).inv(),
3093{
3094 hide(VmStore::accounting_inv);
3095 if range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0 && range.start < range.end
3102 && range.end <= MAX_PADDR && (forall|paddr: Paddr|
3103 #![trigger frame_to_index(paddr)]
3104 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) ==> s.regions.slot_owner(
3105 paddr,
3106 ).ref_count() == REF_COUNT_UNUSED) {
3107 let ghost s_before = *s;
3108 let ghost old_regions = s.regions;
3109 let ghost old_frames = s.frames;
3110 let ghost old_segments = s.segments;
3111 let tracked res = segment::from_unused_step(&mut s.regions, range);
3115 match res {
3116 Option::Some(entry) => {
3117 let ghost id = fresh_segment_id(s.segments);
3118 lemma_fresh_segment_id_not_in_dom(s.segments);
3119 s.lemma_insert_segment(id, entry);
3120 lemma_step_segment_from_unused_accounting(*s, s_before, range, id, entry);
3126 },
3135 Option::None => {},
3136 }
3137 }
3138}
3139
3140proof fn lemma_accounting_inv_intro<'rcu>(store: VmStore<'rcu>)
3141 requires
3142 forall|idx: int|
3143 #![trigger store.regions.slot_owners[idx]]
3144 0 <= idx < max_meta_slots() && store.regions.slot_owners[idx].ref_count()
3145 == REF_COUNT_UNUSED ==> handle_count(store.frames, idx) == 0
3146 && store.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3147 store.segments,
3148 index_to_frame(idx),
3149 ) == 0,
3150 forall|idx: int|
3151 #![trigger store.regions.slot_owners[idx]]
3152 0 <= idx < max_meta_slots() && store.regions.slot_owners[idx].usage is Frame
3153 && store.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
3154 && store.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE ==> handle_count(
3155 store.frames,
3156 idx,
3157 ) > 0 || store.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3158 store.segments,
3159 index_to_frame(idx),
3160 ) > 0,
3161 forall|idx: int|
3162 #![trigger store.regions.slot_owners[idx]]
3163 0 <= idx < max_meta_slots() && store.regions.slot_owners[idx].usage is Frame && (
3164 handle_count(store.frames, idx) > 0 || store.regions.slot_owners[idx].paths_in_pt.len()
3165 > 0 || segment_cover_count(store.segments, index_to_frame(idx)) > 0) ==> {
3166 let so = store.regions.slot_owners[idx];
3167 let rc = so.ref_count();
3168 &&& rc != REF_COUNT_UNUSED
3169 &&& rc != REF_COUNT_UNIQUE
3170 &&& rc == handle_count(store.frames, idx) + so.paths_in_pt.len()
3171 + segment_cover_count(store.segments, index_to_frame(idx))
3172 &&& so.storage_perm().is_init()
3173 },
3174 ensures
3175 store.accounting_inv(),
3176{
3177 reveal(VmStore::accounting_inv);
3178}
3179
3180#[verifier::spinoff_prover]
3181proof fn lemma_drop_segment_with_store_inv<'rcu>(
3182 tracked regions: &mut MetaRegionOwners,
3183 tracked entry: SegmentEntry,
3184 store: VmStore<'rcu>,
3185 sid: SegmentId,
3186)
3187 requires
3188 store.inv(),
3189 store.segments.dom().contains(sid),
3190 entry == store.segments[sid],
3191 *old(regions) == store.regions,
3192 ensures
3193 final(regions).inv(),
3194 final(regions).slots == old(regions).slots,
3195 forall|paddr: Paddr|
3196 #![trigger frame_to_index(paddr)]
3197 (entry.range.start <= paddr < entry.range.end && paddr % PAGE_SIZE == 0) ==> {
3198 let idx = frame_to_index(paddr);
3199 let so_old = old(regions).slot_owners[idx];
3200 let so_new = final(regions).slot_owners[idx];
3201 &&& so_old.ref_count() >= 1
3202 &&& so_old.ref_count() <= REF_COUNT_MAX
3203 &&& so_old.usage is Frame
3204 &&& so_old.ref_count() == 1 ==> so_old.paths_in_pt.is_empty()
3205 &&& so_new.usage == so_old.usage
3206 &&& so_new.paths_in_pt == so_old.paths_in_pt
3207 &&& so_new.slot_vaddr == so_old.slot_vaddr
3208 &&& so_new.in_list_perm == so_old.in_list_perm
3209 &&& so_old.ref_count() == 1 ==> so_new.ref_count() == REF_COUNT_UNUSED
3210 &&& so_old.ref_count() > 1 ==> so_new.ref_count() == (so_old.ref_count() - 1) as u64
3211 },
3212 forall|i: int|
3213 #![trigger final(regions).slot_owners[i]]
3214 i < max_meta_slots() && !(entry.range.start <= index_to_frame(i) < entry.range.end)
3215 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
3216 forall|i: int|
3217 #![trigger final(regions).slot_owners[i]]
3218 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
3219 regions,
3220 ).slot_owners[i],
3221 forall|c: CursorOwner<'_, UserPtConfig>|
3222 #![auto]
3223 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
3224{
3225 assert forall|paddr: Paddr|
3226 #![trigger store.regions.slot_owner(paddr)]
3227 (entry.range.start <= paddr < entry.range.end && paddr % PAGE_SIZE == 0) implies {
3228 let so = store.regions.slot_owner(paddr);
3229 &&& so.ref_count() >= 1
3230 &&& so.ref_count() <= REF_COUNT_MAX
3231 &&& so.usage is Frame
3232 &&& so.ref_count() == 1 ==> so.paths_in_pt.is_empty()
3233 } by {
3234 let idx = frame_to_index(paddr);
3235 lemma_segment_cover_contains(store.segments, sid, paddr);
3236 let so = store.regions.slot_owners[idx];
3237 let rc = so.ref_count();
3238 assert(store.regions.contains(idx));
3239 if rc == 1 {
3240 }
3241 };
3242 segment::drop_step(regions, entry);
3243}
3244
3245#[verifier::spinoff_prover]
3249#[verifier::rlimit(50)]
3250proof fn lemma_step_segment_drop<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
3251 requires
3252 old(s).inv(),
3253 old(s).segments.dom().contains(sid),
3254 ensures
3255 final(s).inv(),
3256{
3257 hide(MetaSlotOwner::storage_perm);
3258 hide(MetaSlotOwner::vtable_ptr_perm);
3259 hide(VmStore::inv);
3260 hide(VmStore::structural_inv);
3261 hide(VmStore::accounting_inv);
3262 assert(s.structural_inv()) by {
3263 reveal(VmStore::inv);
3264 };
3265 assert(s.accounting_inv()) by {
3266 reveal(VmStore::inv);
3267 };
3268 assert(s.regions.inv()) by {
3269 reveal(VmStore::structural_inv);
3270 };
3271 let ghost s_before = *s;
3272 let ghost old_regions = s.regions;
3273 let ghost old_frames = s.frames;
3274 let ghost old_segments = s.segments;
3275 let ghost range = s.segments[sid].range;
3276 let tracked entry = s.tracked_extract_segment(sid);
3277 assert(entry.range == range);
3278 lemma_drop_segment_with_store_inv(&mut s.regions, entry, s_before, sid);
3279 lemma_coverage_preserved_slots_eq(s_before, *s);
3282
3283 assert forall|idx: int|
3300 0 <= idx
3301 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].in_list_perm.value()
3302 == 0 by {
3303 reveal(VmStore::structural_inv);
3304 let paddr = index_to_frame(idx);
3305 assert(paddr == (idx * PAGE_SIZE) as usize);
3306 assert(paddr % PAGE_SIZE == 0);
3307 assert(frame_to_index(paddr) == idx);
3308 if range.start <= paddr < range.end {
3309 } else {
3311 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3312 }
3313 };
3314 assert forall|idx: int|
3316 #![trigger s.regions.slot_owners[idx]]
3317 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
3318 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3319 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3320 s.segments,
3321 index_to_frame(idx),
3322 ) == 0 by {
3323 reveal(VmStore::accounting_inv);
3324 let paddr = index_to_frame(idx);
3325 assert(paddr == (idx * PAGE_SIZE) as usize);
3326 assert(paddr % PAGE_SIZE == 0);
3327 assert(frame_to_index(paddr) == idx);
3328 if range.start <= paddr < range.end {
3329 lemma_segment_cover_contains(old_segments, sid, paddr);
3336 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3337 assert(old_regions.slot_owners[idx].ref_count() == 1);
3338 assert(handle_count(old_frames, idx) == 0);
3339 assert(s.regions.slot_owners[idx].paths_in_pt == Set::empty());
3340 } else {
3341 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3343 assert(!(entry.range.start <= paddr < entry.range.end));
3344 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3345 }
3346 };
3347 assert forall|idx: int|
3348 #![trigger s.regions.slot_owners[idx]]
3349 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
3350 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
3351 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE implies handle_count(
3352 s.frames,
3353 idx,
3354 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3355 s.segments,
3356 index_to_frame(idx),
3357 ) > 0 by {
3358 reveal(VmStore::accounting_inv);
3359 let paddr = index_to_frame(idx);
3360 assert(paddr == (idx * PAGE_SIZE) as usize);
3361 assert(paddr % PAGE_SIZE == 0);
3362 assert(frame_to_index(paddr) == idx);
3363 if range.start <= paddr < range.end {
3364 lemma_segment_cover_contains(old_segments, sid, paddr);
3369 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3370 } else {
3371 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3372 assert(!(entry.range.start <= paddr < entry.range.end));
3373 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3374 }
3375 };
3376 assert forall|idx: int|
3377 #![trigger s.regions.slot_owners[idx]]
3378 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
3379 s.frames,
3380 idx,
3381 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3382 s.segments,
3383 index_to_frame(idx),
3384 ) > 0) implies {
3385 let so = s.regions.slot_owners[idx];
3386 let rc = so.ref_count();
3387 &&& rc != REF_COUNT_UNUSED
3388 &&& rc != REF_COUNT_UNIQUE
3389 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3390 s.segments,
3391 index_to_frame(idx),
3392 )
3393 &&& so.storage_perm().is_init()
3394 } by {
3395 reveal(VmStore::accounting_inv);
3396 let paddr = index_to_frame(idx);
3397 assert(paddr == (idx * PAGE_SIZE) as usize);
3398 assert(paddr % PAGE_SIZE == 0);
3399 assert(frame_to_index(paddr) == idx);
3400 if range.start <= paddr < range.end {
3401 lemma_segment_cover_contains(old_segments, sid, paddr);
3402 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3403 let pre_rc = old_regions.slot_owners[idx].ref_count();
3405 let pre_H = handle_count(old_frames, idx);
3406 let pre_P = old_regions.slot_owners[idx].paths_in_pt.len();
3407 let pre_cover = segment_cover_count(old_segments, paddr);
3408 assert(pre_rc == pre_H + pre_P + pre_cover);
3409 assert(pre_rc != REF_COUNT_UNIQUE);
3410 let post_rc = s.regions.slot_owners[idx].ref_count();
3411 assert(post_rc != REF_COUNT_UNUSED);
3412 assert(pre_rc > 1) by {
3413 if pre_rc == 1 {
3414 assert(post_rc == REF_COUNT_UNUSED);
3415 }
3416 };
3417 assert(post_rc == (pre_rc - 1) as u64);
3418 assert(s.regions.slot_owners[idx].paths_in_pt
3419 == old_regions.slot_owners[idx].paths_in_pt);
3420 assert(handle_count(s.frames, idx) == pre_H);
3421 assert(segment_cover_count(s.segments, paddr) == (pre_cover - 1) as nat);
3422 assert(s.regions.contains(idx));
3426 assert(s.regions.slot_owners[idx].storage_perm().is_init());
3427 } else {
3428 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3429 assert(!(entry.range.start <= paddr < entry.range.end));
3430 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3431 }
3432 };
3433 assert forall|fid_other: FrameId| #[trigger]
3438 s.frames.dom().contains(fid_other) implies s.regions.slot_owner(
3439 s.frames[fid_other].paddr,
3440 ).usage is Frame by {
3441 reveal(VmStore::structural_inv);
3442 reveal(VmStore::accounting_inv);
3443 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3444 let other_paddr = index_to_frame(other_idx);
3445 assert(old_regions.slot_owners[other_idx].usage is Frame);
3447 assert(old_frames.dom().filter(
3449 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
3450 ).contains(fid_other));
3451 assert(handle_count(old_frames, other_idx) >= 1);
3452 assert(old_regions.slot_owners[other_idx].ref_count() >= 1);
3454 if range.start <= other_paddr < range.end {
3456 } else {
3458 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
3460 }
3461 };
3462 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3466 #![trigger
3467 s.segments.dom().contains(sid_other),
3468 frame_to_index(paddr_c)]
3469 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3470 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3471 == 0 implies s.regions.slot_owner(paddr_c).usage is Frame by {
3472 reveal(VmStore::structural_inv);
3473 let cov_idx = frame_to_index(paddr_c);
3474 assert(sid_other != sid);
3476 assert(old_segments.dom().contains(sid_other));
3478 assert(old_segments[sid_other] == s.segments[sid_other]);
3479 assert(old_regions.slot_owners[cov_idx].usage is Frame);
3481 };
3483 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
3488 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
3489 &&& so.usage is Frame
3490 &&& so.ref_count() == REF_COUNT_UNIQUE
3491 &&& so.in_list_perm.value() == 0
3492 &&& so.paths_in_pt.is_empty()
3493 } by {
3494 reveal(VmStore::structural_inv);
3495 reveal(VmStore::accounting_inv);
3496 let u_paddr = s.unique_frames[u].paddr;
3497 let u_idx = frame_to_index(u_paddr);
3498 assert(old(s).unique_frames.dom().contains(u));
3499 assert(valid_frame_paddr(u_paddr));
3500 s.regions.lemma_contains_valid_frame_paddr(u_paddr);
3501 assert(old_regions.slot_owners[u_idx].ref_count() == REF_COUNT_UNIQUE);
3503 assert(old_regions.slot_owners[u_idx].usage is Frame);
3504 assert(!(range.start <= u_paddr < range.end)) by {
3506 if range.start <= u_paddr < range.end {
3507 lemma_segment_cover_contains(old_segments, sid, u_paddr);
3508 }
3509 };
3510 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
3512 };
3513 lemma_accounting_inv_intro(*s);
3514 assert(s.structural_inv()) by {
3515 reveal(VmStore::structural_inv);
3516 };
3517 assert(s.inv()) by {
3518 reveal(VmStore::inv);
3519 };
3520}
3521
3522proof fn lemma_step_segment_split<'rcu>(
3527 tracked s: &mut VmStore<'rcu>,
3528 sid: SegmentId,
3529 offset: usize,
3530)
3531 requires
3532 old(s).inv(),
3533 old(s).segments.dom().contains(sid),
3534 offset % PAGE_SIZE == 0,
3535 0 < offset,
3536 offset < (old(s).segments[sid].range.end - old(s).segments[sid].range.start),
3537 ensures
3538 final(s).inv(),
3539{
3540 let ghost old_regions = s.regions;
3541 let ghost old_frames = s.frames;
3542 let ghost old_segments = s.segments;
3543 let ghost range = s.segments[sid].range;
3544 let ghost mid = (range.start + offset) as Paddr;
3545 let ghost entry_left = SegmentEntry { range: range.start..mid };
3546 let ghost entry_right = SegmentEntry { range: mid..range.end };
3547 let ghost id_left = fresh_segment_id(s.segments);
3553 lemma_fresh_segment_id_not_in_dom(s.segments);
3554 assert(id_left != sid);
3555 let ghost stub_entry = SegmentEntry { range: range.start..mid };
3556 let ghost id_right = fresh_segment_id(s.segments.insert(id_left, stub_entry));
3557 lemma_fresh_segment_id_not_in_dom(s.segments.insert(id_left, stub_entry));
3558 assert(id_right != sid);
3559 assert(id_right != id_left);
3560 let tracked _orig = s.tracked_extract_segment(sid);
3562 assert(!s.segments.dom().contains(id_left));
3563 let tracked entry_l = tracked_segment_entry_new(range.start..mid);
3564 s.lemma_insert_segment(id_left, entry_l);
3565 assert(!s.segments.dom().contains(id_right));
3566 let tracked entry_r = tracked_segment_entry_new(mid..range.end);
3567 s.lemma_insert_segment(id_right, entry_r);
3568 assert(s.regions == old_regions);
3573 assert forall|paddr: Paddr| #[trigger]
3574 frame_to_index(paddr) < max_meta_slots() implies segment_cover_count(s.segments, paddr)
3575 == segment_cover_count(old_segments, paddr) by {
3576 lemma_segment_cover_split(
3577 old_segments,
3578 sid,
3579 id_left,
3580 id_right,
3581 entry_left,
3582 entry_right,
3583 paddr,
3584 );
3585 };
3586 assert(entry_left.range.start % PAGE_SIZE == 0);
3593 assert(entry_right.range.start % PAGE_SIZE == 0);
3594 assert(entry_left.range.end % PAGE_SIZE == 0);
3595 assert(entry_right.range.end % PAGE_SIZE == 0);
3596 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3600 #![trigger
3601 s.segments.dom().contains(sid_other),
3602 frame_to_index(paddr_c)]
3603 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3604 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3605 == 0 implies s.regions.slot_owner(paddr_c).usage is Frame by {
3606 if sid_other == id_left {
3607 assert(old_segments.dom().contains(sid));
3608 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
3609 } else if sid_other == id_right {
3610 assert(old_segments.dom().contains(sid));
3611 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
3612 } else {
3613 assert(old_segments.dom().contains(sid_other));
3614 assert(old_segments[sid_other] == s.segments[sid_other]);
3615 }
3616 };
3617 assert forall|idx: int|
3622 #![trigger s.regions.slot_owners[idx]]
3623 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
3624 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3625 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3626 s.segments,
3627 index_to_frame(idx),
3628 ) == 0 by {
3629 let paddr = index_to_frame(idx);
3630 assert(paddr == (idx * PAGE_SIZE) as usize);
3631 assert(frame_to_index(paddr) == idx);
3632 lemma_segment_cover_split(
3633 old_segments,
3634 sid,
3635 id_left,
3636 id_right,
3637 entry_left,
3638 entry_right,
3639 paddr,
3640 );
3641 };
3642 assert forall|idx: int|
3643 #![trigger s.regions.slot_owners[idx]]
3644 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
3645 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
3646 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE implies handle_count(
3647 s.frames,
3648 idx,
3649 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3650 s.segments,
3651 index_to_frame(idx),
3652 ) > 0 by {
3653 let paddr = index_to_frame(idx);
3654 assert(paddr == (idx * PAGE_SIZE) as usize);
3655 assert(frame_to_index(paddr) == idx);
3656 lemma_segment_cover_split(
3657 old_segments,
3658 sid,
3659 id_left,
3660 id_right,
3661 entry_left,
3662 entry_right,
3663 paddr,
3664 );
3665 };
3666 assert forall|idx: int|
3667 #![trigger s.regions.slot_owners[idx]]
3668 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
3669 s.frames,
3670 idx,
3671 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3672 s.segments,
3673 index_to_frame(idx),
3674 ) > 0) implies {
3675 let so = s.regions.slot_owners[idx];
3676 let rc = so.ref_count();
3677 &&& rc != REF_COUNT_UNUSED
3678 &&& rc != REF_COUNT_UNIQUE
3679 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3680 s.segments,
3681 index_to_frame(idx),
3682 )
3683 &&& so.storage_perm().is_init()
3684 } by {
3685 let paddr = index_to_frame(idx);
3686 assert(paddr == (idx * PAGE_SIZE) as usize);
3687 assert(frame_to_index(paddr) == idx);
3688 lemma_segment_cover_split(
3689 old_segments,
3690 sid,
3691 id_left,
3692 id_right,
3693 entry_left,
3694 entry_right,
3695 paddr,
3696 );
3697 };
3698 }
3701
3702proof fn lemma_step_segment_next<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
3729 requires
3730 old(s).inv(),
3731 old(s).segments.dom().contains(sid),
3732 ensures
3733 final(s).inv(),
3734{
3735 let ghost old_regions = s.regions;
3736 let ghost old_frames = s.frames;
3737 let ghost old_segments = s.segments;
3738 let ghost range = s.segments[sid].range;
3739 let ghost paddr = range.start;
3740 let ghost target_idx = frame_to_index(paddr);
3741 let ghost new_range_start = (paddr + PAGE_SIZE) as Paddr;
3742 let ghost new_range_end = range.end;
3743 let ghost will_become_empty = new_range_start >= new_range_end;
3744 let ghost new_entry_ghost = SegmentEntry { range: new_range_start..new_range_end };
3745
3746 lemma_segment_cover_contains(old_segments, sid, paddr);
3748 assert(segment_cover_count(old_segments, paddr) >= 1);
3749 assert(old_regions.slot_owners[target_idx].usage is Frame);
3750 let ghost so_pre = old_regions.slot_owners[target_idx];
3751 let ghost pre_rc = so_pre.ref_count();
3752 let ghost pre_H = handle_count(old_frames, target_idx);
3753 let ghost pre_P = so_pre.paths_in_pt.len();
3754 let ghost pre_cover = segment_cover_count(old_segments, paddr);
3755 assert(pre_rc == pre_H + pre_P + pre_cover);
3756 assert(pre_rc != REF_COUNT_UNUSED);
3757 assert(pre_rc != REF_COUNT_UNIQUE);
3758 assert(old_regions.contains(target_idx));
3759 assert(valid_frame_paddr(paddr));
3760 s.regions.lemma_contains_valid_frame_paddr(paddr);
3761 assert(s.regions.contains(target_idx));
3762 assert(range.start % PAGE_SIZE == 0);
3764 assert(range.end <= MAX_PADDR);
3765 assert(range.start + PAGE_SIZE <= MAX_PADDR);
3766
3767 let ghost fid = fresh_frame_id(s.frames);
3769 lemma_fresh_frame_id_not_in_dom(s.frames);
3770 let tracked frame_entry = tracked_frame_entry_new(paddr);
3771 s.lemma_insert_frame(fid, frame_entry);
3772 let tracked _old_entry = s.tracked_extract_segment(sid);
3774 segment::segment_next_embedded(&mut s.regions, paddr);
3775 if !will_become_empty {
3776 let tracked new_entry = tracked_segment_entry_new(new_range_start..new_range_end);
3777 s.lemma_insert_segment(sid, new_entry);
3778 assert(new_entry == new_entry_ghost);
3779 assert(s.segments == old_segments.remove(sid).insert(sid, new_entry_ghost));
3780 } else {
3781 assert(s.segments == old_segments.remove(sid));
3782 }
3783 assert(s.frames == old_frames.insert(fid, frame_entry));
3784
3785 assert forall|paddr_c: Paddr| paddr_c % PAGE_SIZE == 0 implies #[trigger] segment_cover_count(
3788 s.segments,
3789 paddr_c,
3790 ) == (if paddr_c == paddr {
3791 1nat
3792 } else {
3793 0nat
3794 }) + 0nat
3795 || true by {
3799 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3800 };
3801 assert forall|paddr_c: Paddr|
3803 paddr_c % PAGE_SIZE == 0 && paddr_c == paddr implies #[trigger] segment_cover_count(
3804 s.segments,
3805 paddr_c,
3806 ) + 1 == segment_cover_count(old_segments, paddr_c) by {
3807 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3808 };
3809 assert forall|paddr_c: Paddr|
3810 paddr_c % PAGE_SIZE == 0 && paddr_c != paddr implies #[trigger] segment_cover_count(
3811 s.segments,
3812 paddr_c,
3813 ) == segment_cover_count(old_segments, paddr_c) by {
3814 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3815 };
3816
3817 assert forall|idx: int|
3819 0 <= idx
3820 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].in_list_perm.value()
3821 == 0 by {
3822 let paddr_c = index_to_frame(idx);
3823 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3824 if idx == target_idx {
3825 } else {
3827 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3828 }
3829 };
3830 assert forall|fid_other: FrameId| #[trigger]
3834 s.frames.dom().contains(fid_other) implies s.regions.slot_owner(
3835 s.frames[fid_other].paddr,
3836 ).usage is Frame by {
3837 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3838 if fid_other == fid {
3839 assert(s.frames[fid_other].paddr == paddr);
3840 assert(other_idx == target_idx);
3841 } else {
3842 assert(old_frames.dom().contains(fid_other));
3843 assert(s.frames[fid_other] == old_frames[fid_other]);
3844 assert(old_regions.slot_owners[other_idx].usage is Frame);
3845 }
3846 };
3847 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3849 #![trigger
3850 s.segments.dom().contains(sid_other),
3851 frame_to_index(paddr_c)]
3852 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3853 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3854 == 0 implies s.regions.slot_owner(paddr_c).usage is Frame by {
3855 let cov_idx = frame_to_index(paddr_c);
3856 if !will_become_empty && sid_other == sid {
3857 assert(old_segments.dom().contains(sid));
3859 assert(old_regions.slot_owners[cov_idx].usage is Frame);
3860 } else {
3861 assert(sid_other != sid);
3862 assert(old_segments.dom().contains(sid_other));
3863 assert(old_segments[sid_other] == s.segments[sid_other]);
3864 assert(old_regions.slot_owners[cov_idx].usage is Frame);
3865 }
3866 };
3867 if !will_become_empty {
3869 assert(new_range_start % PAGE_SIZE == 0);
3870 assert(new_range_end % PAGE_SIZE == 0);
3871 }
3872 assert forall|idx: int|
3875 #![trigger s.regions.slot_owners[idx]]
3876 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
3877 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3878 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3879 s.segments,
3880 index_to_frame(idx),
3881 ) == 0 by {
3882 let paddr_c = index_to_frame(idx);
3883 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3884 assert(frame_to_index(paddr_c) == idx);
3885 if idx == target_idx {
3886 assert(false);
3888 } else {
3889 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3890 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3891 }
3892 };
3893 assert forall|idx: int|
3894 #![trigger s.regions.slot_owners[idx]]
3895 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
3896 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
3897 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE implies handle_count(
3898 s.frames,
3899 idx,
3900 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3901 s.segments,
3902 index_to_frame(idx),
3903 ) > 0 by {
3904 let paddr_c = index_to_frame(idx);
3905 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3906 if idx == target_idx {
3907 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3909 assert(handle_count(s.frames, target_idx) >= 1);
3910 } else {
3911 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3912 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3913 }
3914 };
3915 assert forall|idx: int|
3916 #![trigger s.regions.slot_owners[idx]]
3917 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
3918 s.frames,
3919 idx,
3920 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3921 s.segments,
3922 index_to_frame(idx),
3923 ) > 0) implies {
3924 let so = s.regions.slot_owners[idx];
3925 let rc = so.ref_count();
3926 &&& rc != REF_COUNT_UNUSED
3927 &&& rc != REF_COUNT_UNIQUE
3928 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3929 s.segments,
3930 index_to_frame(idx),
3931 )
3932 &&& so.storage_perm().is_init()
3933 } by {
3934 let paddr_c = index_to_frame(idx);
3935 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3936 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3937 if idx == target_idx {
3938 } else {
3944 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3945 }
3946 };
3947 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
3951 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
3952 &&& so.usage is Frame
3953 &&& so.ref_count() == REF_COUNT_UNIQUE
3954 &&& so.in_list_perm.value() == 0
3955 &&& so.paths_in_pt.is_empty()
3956 } by {
3957 let u_paddr = s.unique_frames[u].paddr;
3958 let u_idx = frame_to_index(u_paddr);
3959 assert(old(s).unique_frames.dom().contains(u));
3960 assert(valid_frame_paddr(u_paddr));
3961 s.regions.lemma_contains_valid_frame_paddr(u_paddr);
3962 assert(old_regions.slot_owners[u_idx].ref_count() == REF_COUNT_UNIQUE);
3963 assert(old_regions.slot_owners[u_idx].usage is Frame);
3964 assert(u_idx != target_idx) by {
3966 lemma_segment_cover_contains(old_segments, sid, paddr);
3967 };
3968 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
3969 };
3970}
3971
3972#[verifier::spinoff_prover]
3973#[verifier::rlimit(200)]
3974proof fn lemma_step_segment_clone_range<'rcu>(
3975 tracked s: &mut VmStore<'rcu>,
3976 sid: SegmentId,
3977 sub_range: Range<Paddr>,
3978)
3979 requires
3980 old(s).inv(),
3981 old(s).segments.dom().contains(sid),
3982 sub_range.start % PAGE_SIZE == 0,
3983 sub_range.end % PAGE_SIZE == 0,
3984 old(s).segments[sid].range.start <= sub_range.start,
3985 sub_range.start < sub_range.end,
3986 sub_range.end <= old(s).segments[sid].range.end,
3987 forall|paddr: Paddr|
3988 #![trigger frame_to_index(paddr)]
3989 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) ==> old(
3990 s,
3991 ).regions.slot_owner(paddr).ref_count() + 1 <= REF_COUNT_MAX,
3992 ensures
3993 final(s).inv(),
3994{
3995 hide(VmStore::inv);
3996 hide(VmStore::structural_inv);
3997 hide(VmStore::accounting_inv);
3998 assert(s.structural_inv()) by {
3999 reveal(VmStore::inv);
4000 };
4001 assert(s.accounting_inv()) by {
4002 reveal(VmStore::inv);
4003 };
4004 assert(s.regions.inv()) by {
4005 reveal(VmStore::structural_inv);
4006 };
4007 let ghost old_regions = s.regions;
4008 let ghost old_frames = s.frames;
4009 let ghost old_segments = s.segments;
4010 let ghost sid_range = s.segments[sid].range;
4011 let ghost new_entry_ghost = SegmentEntry { range: sub_range };
4012
4013 assert(sid_range.end <= MAX_PADDR) by {
4016 reveal(VmStore::structural_inv);
4017 };
4018 assert(sub_range.end <= MAX_PADDR);
4019
4020 assert forall|paddr: Paddr|
4028 #![trigger old_regions.slot_owner(paddr)]
4029 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) implies {
4030 let so = old_regions.slot_owner(paddr);
4031 &&& so.usage is Frame
4032 &&& so.ref_count() >= 1
4033 &&& so.ref_count() + 1 <= REF_COUNT_MAX
4034 } by {
4035 reveal(VmStore::structural_inv);
4036 reveal(VmStore::accounting_inv);
4037 assert(old_segments.dom().contains(sid));
4039 assert(sid_range.start <= paddr < sid_range.end);
4040 lemma_segment_cover_contains(old_segments, sid, paddr);
4041 assert(segment_cover_count(old_segments, paddr) >= 1);
4042 };
4044
4045 segment::segment_clone_embedded(&mut s.regions, sub_range);
4047
4048 let ghost sid2 = fresh_segment_id(s.segments);
4050 lemma_fresh_segment_id_not_in_dom(s.segments);
4051 assert(sid2 != sid);
4052 let tracked new_entry = tracked_segment_entry_new(sub_range);
4053 s.lemma_insert_segment(sid2, new_entry);
4054 assert(new_entry =~= new_entry_ghost);
4055 assert(s.segments =~= old_segments.insert(sid2, new_entry_ghost));
4056 assert(s.frames == old_frames);
4057
4058 assert forall|paddr_c: Paddr|
4060 paddr_c % PAGE_SIZE == 0 && sub_range.start <= paddr_c
4061 < sub_range.end implies #[trigger] segment_cover_count(s.segments, paddr_c)
4062 == segment_cover_count(old_segments, paddr_c) + 1 by {
4063 lemma_segment_cover_insert_inside(old_segments, sid2, new_entry_ghost, paddr_c);
4064 };
4065 assert forall|paddr_c: Paddr|
4066 paddr_c % PAGE_SIZE == 0 && !(sub_range.start <= paddr_c
4067 < sub_range.end) implies #[trigger] segment_cover_count(s.segments, paddr_c)
4068 == segment_cover_count(old_segments, paddr_c) by {
4069 lemma_segment_cover_insert_outside(old_segments, sid2, new_entry_ghost, paddr_c);
4070 };
4071
4072 assert forall|idx: int|
4076 0 <= idx < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].usage
4077 == old_regions.slot_owners[idx].usage by {
4078 reveal(VmStore::structural_inv);
4079 let aligned = index_to_frame(idx);
4080 assert(aligned == (idx * PAGE_SIZE) as usize);
4081 assert(frame_to_index(aligned) == idx);
4082 if sub_range.start <= aligned < sub_range.end {
4083 } else {
4085 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4086 }
4087 };
4088 assert forall|idx: int|
4090 0 <= idx
4091 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].in_list_perm.value()
4092 == 0 by {
4093 reveal(VmStore::structural_inv);
4094 let aligned = index_to_frame(idx);
4095 assert(aligned == (idx * PAGE_SIZE) as usize);
4096 assert(frame_to_index(aligned) == idx);
4097 if sub_range.start <= aligned < sub_range.end {
4098 } else {
4100 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4101 }
4102 };
4103
4104 assert forall|sid_other: SegmentId, paddr_c: Paddr|
4106 #![trigger
4107 s.segments.dom().contains(sid_other),
4108 frame_to_index(paddr_c)]
4109 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
4110 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
4111 == 0 implies s.regions.slot_owner(paddr_c).usage is Frame by {
4112 reveal(VmStore::structural_inv);
4113 let cov_idx = frame_to_index(paddr_c);
4114 if sid_other == sid2 {
4115 assert(s.segments[sid2].range == sub_range);
4117 assert(old_segments.dom().contains(sid));
4118 assert(sid_range.start <= paddr_c < sid_range.end);
4119 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4120 } else {
4121 assert(old_segments.dom().contains(sid_other));
4122 assert(old_segments[sid_other] == s.segments[sid_other]);
4123 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4124 }
4125 assert(valid_frame_paddr(paddr_c));
4130 s.regions.lemma_contains_valid_frame_paddr(paddr_c);
4131 assert(s.regions.contains(cov_idx));
4132 };
4133
4134 assert forall|fid_other: FrameId| #[trigger]
4136 s.frames.dom().contains(fid_other) implies s.regions.slot_owner(
4137 s.frames[fid_other].paddr,
4138 ).usage is Frame by {
4139 reveal(VmStore::structural_inv);
4140 let other_idx = frame_to_index(s.frames[fid_other].paddr);
4141 assert(old_frames.dom().contains(fid_other));
4142 assert(old_regions.slot_owners[other_idx].usage is Frame);
4143 assert(valid_frame_paddr(s.frames[fid_other].paddr));
4144 s.regions.lemma_contains_valid_frame_paddr(s.frames[fid_other].paddr);
4145 assert(s.regions.contains(other_idx));
4146 };
4149
4150 assert forall|idx: int|
4152 #![trigger s.regions.slot_owners[idx]]
4153 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].ref_count()
4154 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
4155 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
4156 s.segments,
4157 index_to_frame(idx),
4158 ) == 0 by {
4159 reveal(VmStore::accounting_inv);
4160 let aligned = index_to_frame(idx);
4161 assert(aligned == (idx * PAGE_SIZE) as usize);
4162 assert(frame_to_index(aligned) == idx);
4163 if sub_range.start <= aligned < sub_range.end {
4164 assert(false);
4166 } else {
4167 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4168 }
4169 };
4170 assert forall|idx: int|
4172 #![trigger s.regions.slot_owners[idx]]
4173 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
4174 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
4175 && s.regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE implies handle_count(
4176 s.frames,
4177 idx,
4178 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
4179 s.segments,
4180 index_to_frame(idx),
4181 ) > 0 by {
4182 reveal(VmStore::accounting_inv);
4183 let aligned = index_to_frame(idx);
4184 assert(aligned == (idx * PAGE_SIZE) as usize);
4185 assert(frame_to_index(aligned) == idx);
4186 if sub_range.start <= aligned < sub_range.end {
4187 } else {
4189 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4190 }
4191 };
4192 assert forall|idx: int|
4194 #![trigger s.regions.slot_owners[idx]]
4195 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
4196 s.frames,
4197 idx,
4198 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
4199 s.segments,
4200 index_to_frame(idx),
4201 ) > 0) implies {
4202 let so = s.regions.slot_owners[idx];
4203 let rc = so.ref_count();
4204 &&& rc != REF_COUNT_UNUSED
4205 &&& rc != REF_COUNT_UNIQUE
4206 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
4207 s.segments,
4208 index_to_frame(idx),
4209 )
4210 &&& so.storage_perm().is_init()
4211 } by {
4212 reveal(VmStore::accounting_inv);
4213 let aligned = index_to_frame(idx);
4214 assert(aligned == (idx * PAGE_SIZE) as usize);
4215 assert(frame_to_index(aligned) == idx);
4216 if sub_range.start <= aligned < sub_range.end {
4217 } else {
4220 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
4221 }
4222 };
4223 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4228 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
4229 &&& so.usage is Frame
4230 &&& so.ref_count() == REF_COUNT_UNIQUE
4231 &&& so.in_list_perm.value() == 0
4232 &&& so.paths_in_pt.is_empty()
4233 } by {
4234 reveal(VmStore::structural_inv);
4235 reveal(VmStore::accounting_inv);
4236 let u_paddr = s.unique_frames[u].paddr;
4237 let u_idx = frame_to_index(u_paddr);
4238 assert(old(s).unique_frames.dom().contains(u));
4239 assert(valid_frame_paddr(u_paddr));
4240 s.regions.lemma_contains_valid_frame_paddr(u_paddr);
4241 assert(old_regions.slot_owners[u_idx].ref_count() == REF_COUNT_UNIQUE);
4242 assert(old_regions.slot_owners[u_idx].usage is Frame);
4243 assert(!(sub_range.start <= u_paddr < sub_range.end)) by {
4244 if sub_range.start <= u_paddr < sub_range.end {
4245 assert(sid_range.start <= u_paddr < sid_range.end);
4247 lemma_segment_cover_contains(old_segments, sid, u_paddr);
4248 }
4249 };
4250 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4251 };
4252 lemma_accounting_inv_intro(*s);
4253 assert(s.structural_inv()) by {
4254 reveal(VmStore::structural_inv);
4255 };
4256 assert(s.inv()) by {
4257 reveal(VmStore::inv);
4258 };
4259}
4260
4261proof fn lemma_step_segment_clone<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
4265 requires
4266 old(s).inv(),
4267 old(s).segments.dom().contains(sid),
4268 forall|paddr: Paddr|
4269 #![trigger frame_to_index(paddr)]
4270 (old(s).segments[sid].range.start <= paddr < old(s).segments[sid].range.end && paddr
4271 % PAGE_SIZE == 0) ==> old(s).regions.slot_owner(paddr).ref_count() + 1
4272 <= REF_COUNT_MAX,
4273 ensures
4274 final(s).inv(),
4275{
4276 let ghost r = s.segments[sid].range;
4280 assert(r.start % PAGE_SIZE == 0);
4281 assert(r.end % PAGE_SIZE == 0);
4282 assert(r.start < r.end);
4283 assert(r.end <= MAX_PADDR);
4284 lemma_step_segment_clone_range(s, sid, r);
4285}
4286
4287proof fn lemma_step_segment_slice<'rcu>(
4290 tracked s: &mut VmStore<'rcu>,
4291 sid: SegmentId,
4292 sub_range: Range<Paddr>,
4293)
4294 requires
4295 old(s).inv(),
4296 old(s).segments.dom().contains(sid),
4297 sub_range.start % PAGE_SIZE == 0,
4298 sub_range.end % PAGE_SIZE == 0,
4299 old(s).segments[sid].range.start <= sub_range.start,
4300 sub_range.start < sub_range.end,
4301 sub_range.end <= old(s).segments[sid].range.end,
4302 forall|paddr: Paddr|
4303 #![trigger frame_to_index(paddr)]
4304 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) ==> old(
4305 s,
4306 ).regions.slot_owner(paddr).ref_count() + 1 <= REF_COUNT_MAX,
4307 ensures
4308 final(s).inv(),
4309{
4310 lemma_step_segment_clone_range(s, sid, sub_range);
4311}
4312
4313proof fn lemma_step_unique_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
4314 requires
4315 old(s).inv(),
4316 ensures
4317 final(s).inv(),
4318{
4319 if valid_frame_paddr(paddr) && s.regions.slots.contains_key(frame_to_index(paddr))
4323 && s.regions.slot_owner(paddr).usage is Unused && s.regions.slot_owner(paddr).ref_count()
4324 == REF_COUNT_UNUSED {
4325 let ghost old_regions = s.regions;
4326 let ghost old_frames = s.frames;
4327 let ghost old_segments = s.segments;
4328 let ghost old_unique = s.unique_frames;
4329 let ghost idx = frame_to_index(paddr);
4330
4331 s.regions.lemma_contains_valid_frame_paddr(paddr);
4333 assert(s.regions.contains(idx));
4334 assert(index_to_frame(idx) == paddr);
4335
4336 assert(handle_count(old_frames, idx) == 0);
4338 assert(old_regions.slot_owners[idx].paths_in_pt.is_empty());
4339 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0);
4340
4341 unique::unique_from_unused_embedded(&mut s.regions, paddr);
4343
4344 let ghost uid = fresh_unique_id(s.unique_frames);
4346 lemma_fresh_unique_id_not_in_dom(s.unique_frames);
4347 let tracked entry = tracked_unique_entry_new(paddr);
4348 s.lemma_insert_unique(uid, entry);
4349 assert(s.unique_frames =~= old_unique.insert(uid, UniqueEntry { paddr }));
4350 assert(s.frames == old_frames);
4351 assert(s.segments == old_segments);
4352
4353 assert forall|i: int|
4355 0 <= i
4356 < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].in_list_perm.value()
4357 == 0 by {
4358 if i != idx {
4359 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4360 }
4361 };
4362 assert forall|fid: FrameId| #[trigger]
4364 s.frames.dom().contains(fid) implies s.regions.slot_owner(
4365 s.frames[fid].paddr,
4366 ).usage is Frame by {
4367 let other_idx = frame_to_index(s.frames[fid].paddr);
4368 assert(old_frames.dom().contains(fid));
4369 assert(old_regions.slot_owners[other_idx].usage is Frame);
4370 if other_idx == idx {
4371 assert(false);
4373 }
4374 };
4375 assert forall|sid: SegmentId, paddr_c: Paddr|
4377 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4378 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4379 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4380 == 0 implies s.regions.slot_owner(paddr_c).usage is Frame by {
4381 let cov_idx = frame_to_index(paddr_c);
4382 assert(old_segments.dom().contains(sid));
4383 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4384 if cov_idx == idx {
4385 assert(false);
4386 }
4387 };
4388 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4390 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
4391 &&& so.usage is Frame
4392 &&& so.ref_count() == REF_COUNT_UNIQUE
4393 &&& so.in_list_perm.value() == 0
4394 &&& so.paths_in_pt.is_empty()
4395 } by {
4396 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4397 if u == uid {
4398 assert(s.unique_frames[u].paddr == paddr);
4399 assert(u_idx == idx);
4400 } else {
4401 assert(old_unique.dom().contains(u));
4402 assert(s.unique_frames[u] == old_unique[u]);
4403 assert(old_regions.slot_owners[u_idx].ref_count() == REF_COUNT_UNIQUE);
4404 assert(u_idx != idx);
4405 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4406 }
4407 };
4408 assert forall|u: UniqueId| #[trigger]
4410 s.unique_frames.dom().contains(u) implies valid_frame_paddr(
4411 s.unique_frames[u].paddr,
4412 ) by {
4413 if u != uid {
4414 assert(old_unique.dom().contains(u));
4415 }
4416 };
4417 assert forall|u1: UniqueId, u2: UniqueId|
4419 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4420 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4421 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4422 if u1 == uid && u2 != uid {
4423 assert(old_unique.dom().contains(u2));
4424 assert(s.unique_frames[u2].paddr == paddr);
4425 assert(frame_to_index(s.unique_frames[u2].paddr) == idx);
4426 assert(old_regions.slot_owners[idx].ref_count() == REF_COUNT_UNIQUE);
4427 assert(false);
4428 } else if u2 == uid && u1 != uid {
4429 assert(old_unique.dom().contains(u1));
4430 assert(s.unique_frames[u1].paddr == paddr);
4431 assert(frame_to_index(s.unique_frames[u1].paddr) == idx);
4432 assert(old_regions.slot_owners[idx].ref_count() == REF_COUNT_UNIQUE);
4433 assert(false);
4434 } else if u1 != uid && u2 != uid {
4435 assert(old_unique.dom().contains(u1));
4436 assert(old_unique.dom().contains(u2));
4437 }
4438 };
4439
4440 assert forall|i: int|
4442 #![trigger s.regions.slot_owners[i]]
4443 0 <= i < max_meta_slots() && s.regions.slot_owners[i].ref_count()
4444 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4445 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4446 s.segments,
4447 index_to_frame(i),
4448 ) == 0 by {
4449 if i == idx {
4450 assert(false);
4452 } else {
4453 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4454 }
4455 };
4456 assert forall|i: int|
4458 #![trigger s.regions.slot_owners[i]]
4459 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
4460 && s.regions.slot_owners[i].ref_count() != REF_COUNT_UNUSED
4461 && s.regions.slot_owners[i].ref_count() != REF_COUNT_UNIQUE implies handle_count(
4462 s.frames,
4463 i,
4464 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4465 s.segments,
4466 index_to_frame(i),
4467 ) > 0 by {
4468 if i == idx {
4469 assert(false);
4471 } else {
4472 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4473 }
4474 };
4475 assert forall|i: int|
4477 #![trigger s.regions.slot_owners[i]]
4478 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
4479 s.frames,
4480 i,
4481 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4482 s.segments,
4483 index_to_frame(i),
4484 ) > 0) implies {
4485 let so = s.regions.slot_owners[i];
4486 let rc = so.ref_count();
4487 &&& rc != REF_COUNT_UNUSED
4488 &&& rc != REF_COUNT_UNIQUE
4489 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4490 s.segments,
4491 index_to_frame(i),
4492 )
4493 &&& so.storage_perm().is_init()
4494 } by {
4495 if i == idx {
4496 assert(handle_count(s.frames, idx) == 0);
4499 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4500 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4501 } else {
4502 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4503 }
4504 };
4505 }
4506}
4507
4508proof fn lemma_step_unique_drop<'rcu>(tracked s: &mut VmStore<'rcu>, uid: UniqueId)
4516 requires
4517 old(s).inv(),
4518 old(s).unique_frames.dom().contains(uid),
4519 ensures
4520 final(s).inv(),
4521{
4522 let ghost old_regions = s.regions;
4523 let ghost old_frames = s.frames;
4524 let ghost old_segments = s.segments;
4525 let ghost old_unique = s.unique_frames;
4526 let ghost paddr = s.unique_frames[uid].paddr;
4527 let ghost idx = frame_to_index(paddr);
4528
4529 assert(valid_frame_paddr(paddr));
4532 s.regions.lemma_contains_valid_frame_paddr(paddr);
4533 assert(s.regions.contains(idx));
4534 assert(index_to_frame(idx) == paddr);
4535 assert(s.regions.slot_owners[idx].usage is Frame);
4536 assert(s.regions.slot_owners[idx].ref_count() == REF_COUNT_UNIQUE);
4537 assert(s.regions.slot_owners[idx].in_list_perm.value() == 0);
4538 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4539 assert(s.regions.slot_owners[idx].storage_perm().is_init());
4540
4541 assert(handle_count(old_frames, idx) == 0) by {
4545 if handle_count(old_frames, idx) > 0 {
4546 assert(old_regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE);
4547 assert(false);
4548 }
4549 };
4550 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0) by {
4551 if segment_cover_count(old_segments, index_to_frame(idx)) > 0 {
4552 assert(old_regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE);
4553 assert(false);
4554 }
4555 };
4556
4557 let tracked _entry = s.tracked_extract_unique(uid);
4559 unique::unique_drop_embedded(&mut s.regions, paddr);
4560 assert(s.unique_frames =~= old_unique.remove(uid));
4561 assert(s.frames == old_frames);
4562 assert(s.segments == old_segments);
4563
4564 assert forall|i: int|
4566 0 <= i < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].in_list_perm.value()
4567 == 0 by {
4568 if i != idx {
4569 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4570 }
4571 };
4572 assert forall|fid: FrameId| #[trigger]
4574 s.frames.dom().contains(fid) implies s.regions.slot_owner(
4575 s.frames[fid].paddr,
4576 ).usage is Frame by {
4577 let other_idx = frame_to_index(s.frames[fid].paddr);
4578 assert(old_frames.dom().contains(fid));
4579 assert(old_regions.slot_owners[other_idx].usage is Frame);
4580 if other_idx != idx {
4581 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4582 }
4583 };
4584 assert forall|sid: SegmentId, paddr_c: Paddr|
4586 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4587 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4588 < s.segments[sid].range.end && paddr_c % PAGE_SIZE == 0 implies s.regions.slot_owner(
4589 paddr_c,
4590 ).usage is Frame by {
4591 let cov_idx = frame_to_index(paddr_c);
4592 assert(old_segments.dom().contains(sid));
4593 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4594 if cov_idx != idx {
4595 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4596 }
4597 };
4598 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4600 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
4601 &&& so.usage is Frame
4602 &&& so.ref_count() == REF_COUNT_UNIQUE
4603 &&& so.in_list_perm.value() == 0
4604 &&& so.paths_in_pt.is_empty()
4605 } by {
4606 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4607 assert(old_unique.dom().contains(u));
4608 assert(u != uid);
4609 if u_idx == idx {
4611 assert(s.unique_frames[u].paddr == paddr) by {
4612 assert(old_unique[u].paddr == s.unique_frames[u].paddr);
4613 };
4614 assert(u == uid);
4615 assert(false);
4616 }
4617 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4618 };
4619 assert forall|u: UniqueId| #[trigger]
4621 s.unique_frames.dom().contains(u) implies valid_frame_paddr(s.unique_frames[u].paddr) by {
4622 assert(old_unique.dom().contains(u));
4623 };
4624 assert forall|u1: UniqueId, u2: UniqueId|
4625 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4626 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4627 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4628 assert(old_unique.dom().contains(u1));
4629 assert(old_unique.dom().contains(u2));
4630 };
4631
4632 assert forall|i: int|
4634 #![trigger s.regions.slot_owners[i]]
4635 0 <= i < max_meta_slots() && s.regions.slot_owners[i].ref_count()
4636 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4637 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4638 s.segments,
4639 index_to_frame(i),
4640 ) == 0 by {
4641 if i == idx {
4642 assert(handle_count(s.frames, idx) == 0);
4645 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4646 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4647 } else {
4648 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4649 }
4650 };
4651 assert forall|i: int|
4653 #![trigger s.regions.slot_owners[i]]
4654 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
4655 && s.regions.slot_owners[i].ref_count() != REF_COUNT_UNUSED
4656 && s.regions.slot_owners[i].ref_count() != REF_COUNT_UNIQUE implies handle_count(
4657 s.frames,
4658 i,
4659 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4660 s.segments,
4661 index_to_frame(i),
4662 ) > 0 by {
4663 if i == idx {
4664 assert(false);
4666 } else {
4667 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4668 }
4669 };
4670 assert forall|i: int|
4672 #![trigger s.regions.slot_owners[i]]
4673 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
4674 s.frames,
4675 i,
4676 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4677 s.segments,
4678 index_to_frame(i),
4679 ) > 0) implies {
4680 let so = s.regions.slot_owners[i];
4681 let rc = so.ref_count();
4682 &&& rc != REF_COUNT_UNUSED
4683 &&& rc != REF_COUNT_UNIQUE
4684 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4685 s.segments,
4686 index_to_frame(i),
4687 )
4688 &&& so.storage_perm().is_init()
4689 } by {
4690 if i == idx {
4691 assert(handle_count(s.frames, idx) == 0);
4693 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4694 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4695 } else {
4696 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4697 }
4698 };
4699}
4700
4701proof fn lemma_step_from_unique<'rcu>(tracked s: &mut VmStore<'rcu>, uid: UniqueId)
4707 requires
4708 old(s).inv(),
4709 old(s).unique_frames.dom().contains(uid),
4710 ensures
4711 final(s).inv(),
4712{
4713 let ghost old_regions = s.regions;
4714 let ghost old_frames = s.frames;
4715 let ghost old_segments = s.segments;
4716 let ghost old_unique = s.unique_frames;
4717 let ghost paddr = s.unique_frames[uid].paddr;
4718 let ghost idx = frame_to_index(paddr);
4719
4720 assert(valid_frame_paddr(paddr));
4722 s.regions.lemma_contains_valid_frame_paddr(paddr);
4723 assert(s.regions.contains(idx));
4724 assert(index_to_frame(idx) == paddr);
4725 assert(s.regions.slot_owners[idx].usage is Frame);
4726 assert(s.regions.slot_owners[idx].ref_count() == REF_COUNT_UNIQUE);
4727 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4728 assert(s.regions.slot_owners[idx].storage_perm().is_init());
4729
4730 assert(handle_count(old_frames, idx) == 0) by {
4732 if handle_count(old_frames, idx) > 0 {
4733 assert(old_regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE);
4734 assert(false);
4735 }
4736 };
4737 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0) by {
4738 if segment_cover_count(old_segments, index_to_frame(idx)) > 0 {
4739 assert(old_regions.slot_owners[idx].ref_count() != REF_COUNT_UNIQUE);
4740 assert(false);
4741 }
4742 };
4743
4744 let tracked _ue = s.tracked_extract_unique(uid);
4746 unique::from_unique_embedded(&mut s.regions, paddr);
4747
4748 let ghost fid = fresh_frame_id(s.frames);
4750 lemma_fresh_frame_id_not_in_dom(s.frames);
4751 let tracked fe = tracked_frame_entry_new(paddr);
4752 s.lemma_insert_frame(fid, fe);
4753 assert(s.frames =~= old_frames.insert(fid, FrameEntry { paddr }));
4754 assert(s.unique_frames =~= old_unique.remove(uid));
4755 assert(s.segments == old_segments);
4756 assert(s.frames[fid].paddr == paddr);
4757
4758 assert forall|i: int|
4760 0 <= i < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].in_list_perm.value()
4761 == 0 by {
4762 if i != idx {
4763 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4764 }
4765 };
4766 assert forall|fid_other: FrameId| #[trigger]
4768 s.frames.dom().contains(fid_other) implies s.regions.slot_owner(
4769 s.frames[fid_other].paddr,
4770 ).usage is Frame by {
4771 let other_idx = frame_to_index(s.frames[fid_other].paddr);
4772 if fid_other == fid {
4773 assert(s.frames[fid_other].paddr == paddr);
4774 assert(other_idx == idx);
4775 } else {
4776 assert(old_frames.dom().contains(fid_other));
4777 assert(s.frames[fid_other] == old_frames[fid_other]);
4778 assert(old_regions.slot_owners[other_idx].usage is Frame);
4779 if other_idx != idx {
4780 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4781 }
4782 }
4783 };
4784 assert forall|sid: SegmentId, paddr_c: Paddr|
4786 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4787 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4788 < s.segments[sid].range.end && paddr_c % PAGE_SIZE == 0 implies s.regions.slot_owner(
4789 paddr_c,
4790 ).usage is Frame by {
4791 let cov_idx = frame_to_index(paddr_c);
4792 assert(old_segments.dom().contains(sid));
4793 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4794 if cov_idx != idx {
4795 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4796 }
4797 };
4798 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4800 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
4801 &&& so.usage is Frame
4802 &&& so.ref_count() == REF_COUNT_UNIQUE
4803 &&& so.in_list_perm.value() == 0
4804 &&& so.paths_in_pt.is_empty()
4805 } by {
4806 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4807 assert(old_unique.dom().contains(u));
4808 assert(u != uid);
4809 if u_idx == idx {
4810 assert(old_unique[u].paddr == s.unique_frames[u].paddr);
4811 assert(u == uid);
4812 assert(false);
4813 }
4814 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
4815 };
4816 assert forall|u: UniqueId| #[trigger]
4817 s.unique_frames.dom().contains(u) implies valid_frame_paddr(s.unique_frames[u].paddr) by {
4818 assert(old_unique.dom().contains(u));
4819 };
4820 assert forall|u1: UniqueId, u2: UniqueId|
4821 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
4822 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
4823 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
4824 assert(old_unique.dom().contains(u1));
4825 assert(old_unique.dom().contains(u2));
4826 };
4827
4828 assert forall|i: int|
4830 #![trigger s.regions.slot_owners[i]]
4831 0 <= i < max_meta_slots() && s.regions.slot_owners[i].ref_count()
4832 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
4833 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
4834 s.segments,
4835 index_to_frame(i),
4836 ) == 0 by {
4837 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4838 if i == idx {
4839 assert(false);
4840 } else {
4841 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4842 }
4843 };
4844 assert forall|i: int|
4846 #![trigger s.regions.slot_owners[i]]
4847 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
4848 && s.regions.slot_owners[i].ref_count() != REF_COUNT_UNUSED
4849 && s.regions.slot_owners[i].ref_count() != REF_COUNT_UNIQUE implies handle_count(
4850 s.frames,
4851 i,
4852 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4853 s.segments,
4854 index_to_frame(i),
4855 ) > 0 by {
4856 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4857 if i == idx {
4858 assert(handle_count(s.frames, idx) == 1);
4859 } else {
4860 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4861 }
4862 };
4863 assert forall|i: int|
4865 #![trigger s.regions.slot_owners[i]]
4866 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
4867 s.frames,
4868 i,
4869 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
4870 s.segments,
4871 index_to_frame(i),
4872 ) > 0) implies {
4873 let so = s.regions.slot_owners[i];
4874 let rc = so.ref_count();
4875 &&& rc != REF_COUNT_UNUSED
4876 &&& rc != REF_COUNT_UNIQUE
4877 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
4878 s.segments,
4879 index_to_frame(i),
4880 )
4881 &&& so.storage_perm().is_init()
4882 } by {
4883 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
4884 if i == idx {
4885 assert(handle_count(s.frames, idx) == 1);
4888 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
4889 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
4890 } else {
4891 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4892 }
4893 };
4894}
4895
4896proof fn lemma_step_try_from_shared<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
4903 requires
4904 old(s).inv(),
4905 old(s).frames.dom().contains(fid),
4906 ensures
4907 final(s).inv(),
4908{
4909 let ghost paddr = s.frames[fid].paddr;
4910 let ghost idx = frame_to_index(paddr);
4911 assert(valid_frame_paddr(paddr));
4914 s.regions.lemma_contains_valid_frame_paddr(paddr);
4915 assert(s.regions.contains(idx));
4916 assert(index_to_frame(idx) == paddr);
4917 assert(s.regions.slot_owners[idx].usage is Frame);
4918 assert(s.frames.dom().filter(
4919 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
4920 ).contains(fid));
4921 assert(handle_count(s.frames, idx) >= 1);
4922
4923 if s.regions.slot_owners[idx].ref_count() == 1 {
4924 let ghost old_regions = s.regions;
4925 let ghost old_frames = s.frames;
4926 let ghost old_segments = s.segments;
4927 let ghost old_unique = s.unique_frames;
4928
4929 assert(handle_count(old_frames, idx) == 1);
4932 assert(s.regions.slot_owners[idx].paths_in_pt.len() == 0);
4933 assert(segment_cover_count(old_segments, index_to_frame(idx)) == 0);
4934 assert(s.regions.slot_owners[idx].paths_in_pt =~= Set::empty());
4935
4936 let tracked _fe = s.tracked_extract_frame(fid);
4938 assert(s.frames =~= old_frames.remove(fid));
4939 unique::try_from_shared_embedded(&mut s.regions, paddr);
4940
4941 let ghost uid = fresh_unique_id(s.unique_frames);
4943 lemma_fresh_unique_id_not_in_dom(s.unique_frames);
4944 let tracked ue = tracked_unique_entry_new(paddr);
4945 s.lemma_insert_unique(uid, ue);
4946 assert(s.unique_frames =~= old_unique.insert(uid, UniqueEntry { paddr }));
4947 assert(s.segments == old_segments);
4948 assert(handle_count(s.frames, idx) == 0) by {
4950 lemma_handle_count_remove(old_frames, fid, idx);
4951 };
4952
4953 assert forall|i: int|
4955 0 <= i
4956 < max_meta_slots() implies #[trigger] s.regions.slot_owners[i].in_list_perm.value()
4957 == 0 by {
4958 if i != idx {
4959 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
4960 }
4961 };
4962 assert forall|fid_other: FrameId| #[trigger]
4966 s.frames.dom().contains(fid_other) implies s.regions.slot_owner(
4967 s.frames[fid_other].paddr,
4968 ).usage is Frame by {
4969 let other_idx = frame_to_index(s.frames[fid_other].paddr);
4970 assert(old_frames.dom().contains(fid_other));
4971 assert(old_regions.slot_owners[other_idx].usage is Frame);
4972 if other_idx != idx {
4973 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
4974 }
4975 };
4976 assert forall|sid: SegmentId, paddr_c: Paddr|
4978 #![trigger s.segments.dom().contains(sid), frame_to_index(paddr_c)]
4979 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
4980 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
4981 == 0 implies s.regions.slot_owner(paddr_c).usage is Frame by {
4982 let cov_idx = frame_to_index(paddr_c);
4983 assert(old_segments.dom().contains(sid));
4984 assert(old_regions.slot_owners[cov_idx].usage is Frame);
4985 if cov_idx != idx {
4986 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
4987 }
4988 };
4989 assert forall|u: UniqueId| #[trigger] s.unique_frames.dom().contains(u) implies {
4991 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
4992 &&& so.usage is Frame
4993 &&& so.ref_count() == REF_COUNT_UNIQUE
4994 &&& so.in_list_perm.value() == 0
4995 &&& so.paths_in_pt.is_empty()
4996 } by {
4997 let u_idx = frame_to_index(s.unique_frames[u].paddr);
4998 if u == uid {
4999 assert(s.unique_frames[u].paddr == paddr);
5000 assert(u_idx == idx);
5001 } else {
5002 assert(old_unique.dom().contains(u));
5003 assert(s.unique_frames[u] == old_unique[u]);
5004 assert(old_regions.slot_owners[u_idx].ref_count() == REF_COUNT_UNIQUE);
5006 assert(u_idx != idx);
5007 assert(s.regions.slot_owners[u_idx] == old_regions.slot_owners[u_idx]);
5008 }
5009 };
5010 assert forall|u: UniqueId| #[trigger]
5011 s.unique_frames.dom().contains(u) implies valid_frame_paddr(
5012 s.unique_frames[u].paddr,
5013 ) by {
5014 if u != uid {
5015 assert(old_unique.dom().contains(u));
5016 }
5017 };
5018 assert forall|u1: UniqueId, u2: UniqueId|
5019 #![trigger s.unique_frames.dom().contains(u1), s.unique_frames.dom().contains(u2)]
5020 s.unique_frames.dom().contains(u1) && s.unique_frames.dom().contains(u2)
5021 && s.unique_frames[u1].paddr == s.unique_frames[u2].paddr implies u1 == u2 by {
5022 if u1 == uid && u2 != uid {
5023 assert(old_unique.dom().contains(u2));
5024 assert(s.unique_frames[u2].paddr == paddr);
5025 assert(frame_to_index(s.unique_frames[u2].paddr) == idx);
5026 assert(old_regions.slot_owners[idx].ref_count() == REF_COUNT_UNIQUE);
5027 assert(false);
5028 } else if u2 == uid && u1 != uid {
5029 assert(old_unique.dom().contains(u1));
5030 assert(s.unique_frames[u1].paddr == paddr);
5031 assert(frame_to_index(s.unique_frames[u1].paddr) == idx);
5032 assert(old_regions.slot_owners[idx].ref_count() == REF_COUNT_UNIQUE);
5033 assert(false);
5034 } else if u1 != uid && u2 != uid {
5035 assert(old_unique.dom().contains(u1));
5036 assert(old_unique.dom().contains(u2));
5037 }
5038 };
5039
5040 assert forall|i: int|
5042 #![trigger s.regions.slot_owners[i]]
5043 0 <= i < max_meta_slots() && s.regions.slot_owners[i].ref_count()
5044 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
5045 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
5046 s.segments,
5047 index_to_frame(i),
5048 ) == 0 by {
5049 lemma_handle_count_remove(old_frames, fid, i);
5050 if i == idx {
5051 assert(false);
5053 } else {
5054 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
5055 }
5056 };
5057 assert forall|i: int|
5059 #![trigger s.regions.slot_owners[i]]
5060 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
5061 && s.regions.slot_owners[i].ref_count() != REF_COUNT_UNUSED
5062 && s.regions.slot_owners[i].ref_count() != REF_COUNT_UNIQUE implies handle_count(
5063 s.frames,
5064 i,
5065 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
5066 s.segments,
5067 index_to_frame(i),
5068 ) > 0 by {
5069 lemma_handle_count_remove(old_frames, fid, i);
5070 if i == idx {
5071 assert(false);
5073 } else {
5074 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
5075 }
5076 };
5077 assert forall|i: int|
5079 #![trigger s.regions.slot_owners[i]]
5080 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
5081 s.frames,
5082 i,
5083 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
5084 s.segments,
5085 index_to_frame(i),
5086 ) > 0) implies {
5087 let so = s.regions.slot_owners[i];
5088 let rc = so.ref_count();
5089 &&& rc != REF_COUNT_UNUSED
5090 &&& rc != REF_COUNT_UNIQUE
5091 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
5092 s.segments,
5093 index_to_frame(i),
5094 )
5095 &&& so.storage_perm().is_init()
5096 } by {
5097 lemma_handle_count_remove(old_frames, fid, i);
5098 if i == idx {
5099 assert(handle_count(s.frames, idx) == 0);
5102 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
5103 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
5104 } else {
5105 assert(s.regions.slot_owners[i] == old_regions.slot_owners[i]);
5106 }
5107 };
5108 }
5109}
5110
5111pub proof fn lemma_segment_cover_insert_inside(
5114 segments: Map<SegmentId, SegmentEntry>,
5115 sid: SegmentId,
5116 entry: SegmentEntry,
5117 paddr: Paddr,
5118)
5119 requires
5120 !segments.dom().contains(sid),
5121 entry.range.start <= paddr < entry.range.end,
5122 ensures
5123 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
5124 segments,
5125 paddr,
5126 ) + 1,
5127{
5128 let segments2 = segments.insert(sid, entry);
5129 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
5130 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
5131 let old_filt = segments.dom().filter(pred);
5132 let new_filt = segments2.dom().filter(pred2);
5133 assert(segments2.dom() == segments.dom().insert(sid));
5134 assert(!old_filt.contains(sid));
5135 assert(new_filt == old_filt.insert(sid)) by {
5136 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.insert(
5137 sid,
5138 ).contains(s) by {
5139 if s != sid {
5140 assert(segments2[s] == segments[s]);
5141 }
5142 };
5143 assert forall|s: SegmentId| #[trigger]
5144 old_filt.insert(sid).contains(s) implies new_filt.contains(s) by {
5145 if s == sid {
5146 assert(segments2[s].range == entry.range);
5147 } else {
5148 assert(segments2[s] == segments[s]);
5149 }
5150 };
5151 };
5152 assert(new_filt.len() == old_filt.len() + 1);
5153}
5154
5155pub proof fn lemma_segment_cover_insert_outside(
5158 segments: Map<SegmentId, SegmentEntry>,
5159 sid: SegmentId,
5160 entry: SegmentEntry,
5161 paddr: Paddr,
5162)
5163 requires
5164 !segments.dom().contains(sid),
5165 !(entry.range.start <= paddr < entry.range.end),
5166 ensures
5167 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
5168 segments,
5169 paddr,
5170 ),
5171{
5172 let segments2 = segments.insert(sid, entry);
5173 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
5174 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
5175 let old_filt = segments.dom().filter(pred);
5176 let new_filt = segments2.dom().filter(pred2);
5177 assert(segments2.dom() == segments.dom().insert(sid));
5178 assert(new_filt == old_filt) by {
5179 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.contains(
5180 s,
5181 ) by {
5182 if s == sid {
5183 assert(false);
5185 } else {
5186 assert(segments2[s] == segments[s]);
5187 }
5188 };
5189 assert forall|s: SegmentId| #[trigger] old_filt.contains(s) implies new_filt.contains(
5190 s,
5191 ) by {
5192 assert(s != sid);
5193 assert(segments2[s] == segments[s]);
5194 };
5195 };
5196}
5197
5198pub proof fn lemma_segment_cover_contains(
5201 segments: Map<SegmentId, SegmentEntry>,
5202 sid: SegmentId,
5203 paddr: Paddr,
5204)
5205 requires
5206 segments.dom().contains(sid),
5207 segments[sid].range.start <= paddr < segments[sid].range.end,
5208 ensures
5209 segment_cover_count(segments, paddr) >= 1,
5210{
5211 let filt = segments.dom().filter(
5212 |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end,
5213 );
5214 assert(filt.contains(sid));
5215}
5216
5217pub proof fn lemma_segment_cover_remove_inside(
5220 segments: Map<SegmentId, SegmentEntry>,
5221 sid: SegmentId,
5222 paddr: Paddr,
5223)
5224 requires
5225 segments.dom().contains(sid),
5226 segments[sid].range.start <= paddr < segments[sid].range.end,
5227 ensures
5228 segment_cover_count(segments.remove(sid), paddr) == (segment_cover_count(segments, paddr)
5229 - 1) as nat,
5230{
5231 let segments2 = segments.remove(sid);
5232 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
5233 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
5234 let old_filt = segments.dom().filter(pred);
5235 let new_filt = segments2.dom().filter(pred2);
5236 assert(segments2.dom() == segments.dom().remove(sid));
5237 assert(old_filt.contains(sid));
5238 assert(new_filt == old_filt.remove(sid)) by {
5239 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.remove(
5240 sid,
5241 ).contains(s) by {
5242 assert(s != sid);
5243 assert(segments2[s] == segments[s]);
5244 };
5245 assert forall|s: SegmentId| #[trigger]
5246 old_filt.remove(sid).contains(s) implies new_filt.contains(s) by {
5247 assert(s != sid);
5248 assert(segments2[s] == segments[s]);
5249 };
5250 };
5251}
5252
5253pub proof fn lemma_segment_cover_shrink_front(
5264 segments: Map<SegmentId, SegmentEntry>,
5265 sid: SegmentId,
5266 new_entry: SegmentEntry,
5267 paddr_check: Paddr,
5268)
5269 requires
5270 segments.dom().contains(sid),
5271 segments[sid].range.start < segments[sid].range.end,
5274 segments[sid].range.start % PAGE_SIZE == 0,
5276 segments[sid].range.start + PAGE_SIZE <= MAX_PADDR,
5278 new_entry.range.start == (segments[sid].range.start + PAGE_SIZE) as Paddr,
5279 new_entry.range.end == segments[sid].range.end,
5280 new_entry.range.start <= new_entry.range.end,
5281 paddr_check % PAGE_SIZE == 0,
5282 ensures
5283new_entry.range.start < new_entry.range.end ==> ({
5287 let new_segments = segments.remove(sid).insert(sid, new_entry);
5288 paddr_check == segments[sid].range.start ==> segment_cover_count(
5289 new_segments,
5290 paddr_check,
5291 ) + 1 == segment_cover_count(segments, paddr_check)
5292 }),
5293 new_entry.range.start < new_entry.range.end ==> ({
5294 let new_segments = segments.remove(sid).insert(sid, new_entry);
5295 paddr_check != segments[sid].range.start ==> segment_cover_count(
5296 new_segments,
5297 paddr_check,
5298 ) == segment_cover_count(segments, paddr_check)
5299 }),
5300 new_entry.range.start >= new_entry.range.end ==> ({
5302 let new_segments = segments.remove(sid);
5303 paddr_check == segments[sid].range.start ==> segment_cover_count(
5304 new_segments,
5305 paddr_check,
5306 ) + 1 == segment_cover_count(segments, paddr_check)
5307 }),
5308 new_entry.range.start >= new_entry.range.end ==> ({
5309 let new_segments = segments.remove(sid);
5310 paddr_check != segments[sid].range.start ==> segment_cover_count(
5311 new_segments,
5312 paddr_check,
5313 ) == segment_cover_count(segments, paddr_check)
5314 }),
5315{
5316 let popped = segments[sid].range.start;
5317 let range = segments[sid].range;
5318 assert(range.start < range.end);
5321 let sid_pre_covers = range.start <= paddr_check < range.end;
5322 let new_covers = new_entry.range.start <= paddr_check < new_entry.range.end;
5323 if sid_pre_covers {
5325 lemma_segment_cover_remove_inside(segments, sid, paddr_check);
5326 } else {
5327 lemma_segment_cover_remove_outside(segments, sid, paddr_check);
5328 }
5329 if new_entry.range.start < new_entry.range.end {
5330 let new_segments = segments.remove(sid).insert(sid, new_entry);
5331 if paddr_check == popped {
5332 assert(!new_covers);
5335 assert(sid_pre_covers);
5336 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
5337 lemma_segment_cover_contains(segments, sid, paddr_check);
5338 assert(segment_cover_count(new_segments, paddr_check) + 1 == segment_cover_count(
5339 segments,
5340 paddr_check,
5341 ));
5342 } else if sid_pre_covers {
5343 assert(new_covers);
5347 lemma_segment_cover_contains(segments, sid, paddr_check);
5348 lemma_segment_cover_insert_inside(segments.remove(sid), sid, new_entry, paddr_check);
5349 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5350 segments,
5351 paddr_check,
5352 ));
5353 } else {
5354 assert(!new_covers);
5356 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
5357 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5358 segments,
5359 paddr_check,
5360 ));
5361 }
5362 } else {
5363 let new_segments = segments.remove(sid);
5365 if paddr_check == popped {
5366 assert(sid_pre_covers);
5367 lemma_segment_cover_contains(segments, sid, paddr_check);
5368 assert(segment_cover_count(new_segments, paddr_check) + 1 == segment_cover_count(
5369 segments,
5370 paddr_check,
5371 ));
5372 } else if sid_pre_covers {
5373 assert(false);
5377 } else {
5378 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
5380 segments,
5381 paddr_check,
5382 ));
5383 }
5384 }
5385}
5386
5387pub proof fn lemma_segment_cover_split(
5393 segments: Map<SegmentId, SegmentEntry>,
5394 sid: SegmentId,
5395 new_left: SegmentId,
5396 new_right: SegmentId,
5397 entry_left: SegmentEntry,
5398 entry_right: SegmentEntry,
5399 paddr: Paddr,
5400)
5401 requires
5402 segments.dom().contains(sid),
5403 new_left != sid,
5406 new_right != sid,
5407 new_left != new_right,
5408 !segments.remove(sid).dom().contains(new_left),
5409 !segments.remove(sid).dom().contains(new_right),
5410 entry_left.range.start == segments[sid].range.start,
5412 entry_left.range.end == entry_right.range.start,
5413 entry_right.range.end == segments[sid].range.end,
5414 entry_left.range.start < entry_left.range.end,
5415 entry_right.range.start < entry_right.range.end,
5416 ensures
5417 segment_cover_count(
5418 segments.remove(sid).insert(new_left, entry_left).insert(new_right, entry_right),
5419 paddr,
5420 ) == segment_cover_count(segments, paddr),
5421{
5422 let mid_segments = segments.remove(sid);
5423 let with_left = mid_segments.insert(new_left, entry_left);
5424 assert(with_left.dom() == mid_segments.dom().insert(new_left));
5425 assert(!with_left.dom().contains(new_right));
5426 let sid_covers = segments[sid].range.start <= paddr && paddr < segments[sid].range.end;
5427 let left_covers = entry_left.range.start <= paddr && paddr < entry_left.range.end;
5428 let right_covers = entry_right.range.start <= paddr && paddr < entry_right.range.end;
5429 let cover_after_remove = segment_cover_count(mid_segments, paddr);
5431 if sid_covers {
5432 lemma_segment_cover_remove_inside(segments, sid, paddr);
5433 assert(cover_after_remove == (segment_cover_count(segments, paddr) - 1) as nat);
5434 } else {
5435 lemma_segment_cover_remove_outside(segments, sid, paddr);
5436 assert(cover_after_remove == segment_cover_count(segments, paddr));
5437 }
5438 let cover_after_left = segment_cover_count(with_left, paddr);
5440 if left_covers {
5441 lemma_segment_cover_insert_inside(mid_segments, new_left, entry_left, paddr);
5442 assert(cover_after_left == cover_after_remove + 1);
5443 } else {
5444 lemma_segment_cover_insert_outside(mid_segments, new_left, entry_left, paddr);
5445 assert(cover_after_left == cover_after_remove);
5446 }
5447 let final_segments = with_left.insert(new_right, entry_right);
5449 let cover_final = segment_cover_count(final_segments, paddr);
5450 if right_covers {
5451 lemma_segment_cover_insert_inside(with_left, new_right, entry_right, paddr);
5452 assert(cover_final == cover_after_left + 1);
5453 } else {
5454 lemma_segment_cover_insert_outside(with_left, new_right, entry_right, paddr);
5455 assert(cover_final == cover_after_left);
5456 }
5457 let orig = segment_cover_count(segments, paddr);
5459 if sid_covers {
5460 lemma_segment_cover_contains(segments, sid, paddr);
5462 assert(cover_after_remove == (orig - 1) as nat);
5463 assert(cover_after_remove + 1 == orig);
5464 if left_covers {
5465 assert(!right_covers);
5466 assert(cover_after_left == cover_after_remove + 1);
5467 assert(cover_final == cover_after_left);
5468 assert(cover_final == orig);
5469 } else {
5470 assert(right_covers);
5471 assert(cover_after_left == cover_after_remove);
5472 assert(cover_final == cover_after_left + 1);
5473 assert(cover_final == cover_after_remove + 1);
5474 assert(cover_final == orig);
5475 }
5476 } else {
5477 assert(!left_covers);
5478 assert(!right_covers);
5479 assert(cover_after_remove == orig);
5480 assert(cover_after_left == cover_after_remove);
5481 assert(cover_final == cover_after_left);
5482 assert(cover_final == orig);
5483 }
5484}
5485
5486pub proof fn lemma_segment_cover_remove_outside(
5489 segments: Map<SegmentId, SegmentEntry>,
5490 sid: SegmentId,
5491 paddr: Paddr,
5492)
5493 requires
5494 segments.dom().contains(sid),
5495 !(segments[sid].range.start <= paddr < segments[sid].range.end),
5496 ensures
5497 segment_cover_count(segments.remove(sid), paddr) == segment_cover_count(segments, paddr),
5498{
5499 let segments2 = segments.remove(sid);
5500 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
5501 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
5502 let old_filt = segments.dom().filter(pred);
5503 let new_filt = segments2.dom().filter(pred2);
5504 assert(segments2.dom() == segments.dom().remove(sid));
5505 assert(!old_filt.contains(sid));
5506 assert(new_filt == old_filt) by {
5507 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.contains(
5508 s,
5509 ) by {
5510 assert(s != sid);
5511 assert(segments2[s] == segments[s]);
5512 };
5513 assert forall|s: SegmentId| #[trigger] old_filt.contains(s) implies new_filt.contains(
5514 s,
5515 ) by {
5516 assert(s != sid);
5517 assert(segments2[s] == segments[s]);
5518 };
5519 };
5520}
5521
5522pub open spec fn fresh_vm_space_id<'a>(m: Map<VmSpaceId, VmSpaceOwner>) -> VmSpaceId {
5528 choose|id: VmSpaceId| !m.dom().contains(id)
5529}
5530
5531pub open spec fn fresh_cursor_id<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>) -> CursorId {
5533 choose|id: CursorId| !m.dom().contains(id)
5534}
5535
5536pub open spec fn fresh_vm_io_id<'a>(m: Map<VmIoId, VmIoEntry>) -> VmIoId {
5538 choose|id: VmIoId| !m.dom().contains(id)
5539}
5540
5541pub open spec fn fresh_frame_id(m: Map<FrameId, FrameEntry>) -> FrameId {
5543 choose|id: FrameId| !m.dom().contains(id)
5544}
5545
5546pub proof fn lemma_fresh_vm_space_id_not_in_dom<'a>(m: Map<VmSpaceId, VmSpaceOwner>)
5547 ensures
5548 !m.dom().contains(fresh_vm_space_id(m)),
5549{
5550 lemma_finite_int_set_has_unused(m.dom());
5551}
5552
5553pub proof fn lemma_fresh_cursor_id_not_in_dom<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>)
5554 ensures
5555 !m.dom().contains(fresh_cursor_id(m)),
5556{
5557 lemma_finite_int_set_has_unused(m.dom());
5558}
5559
5560pub proof fn lemma_fresh_vm_io_id_not_in_dom<'a>(m: Map<VmIoId, VmIoEntry>)
5561 ensures
5562 !m.dom().contains(fresh_vm_io_id(m)),
5563{
5564 lemma_finite_int_set_has_unused(m.dom());
5565}
5566
5567pub proof fn lemma_fresh_frame_id_not_in_dom(m: Map<FrameId, FrameEntry>)
5568 ensures
5569 !m.dom().contains(fresh_frame_id(m)),
5570{
5571 lemma_finite_int_set_has_unused(m.dom());
5572}
5573
5574pub proof fn tracked_cursor_entry_new<'rcu>(
5576 vm_space: VmSpaceId,
5577 kind: CursorKind,
5578 va: Range<Vaddr>,
5579 tracked owner: CursorOwner<'rcu, UserPtConfig>,
5580 tracked guards: Guards<'rcu>,
5581) -> (tracked res: CursorEntry<'rcu>)
5582 ensures
5583 res.vm_space == vm_space,
5584 res.kind == kind,
5585 res.va == va,
5586 res.owner == owner,
5587 res.guards == guards,
5588{
5589 let tracked res = CursorEntry { vm_space, kind, va, owner, guards };
5590 res
5591}
5592
5593pub proof fn tracked_vm_io_entry_new<'a>(
5595 vm_space: Option<VmSpaceId>,
5596 kind: VmIoKind,
5597 vaddr: Vaddr,
5598 len: usize,
5599 tracked owner: VmIoOwner,
5600) -> tracked VmIoEntry
5601 returns
5602 (VmIoEntry { vm_space, kind, vaddr, len, owner }),
5603{
5604 let tracked res = VmIoEntry { vm_space, kind, vaddr, len, owner };
5605 res
5606}
5607
5608pub proof fn tracked_frame_entry_new(paddr: Paddr) -> tracked FrameEntry
5610 returns
5611 (FrameEntry { paddr }),
5612{
5613 let tracked res = FrameEntry { paddr };
5614 res
5615}
5616
5617pub proof fn tracked_segment_entry_new(range: Range<Paddr>) -> tracked SegmentEntry
5619 returns
5620 (SegmentEntry { range }),
5621{
5622 let tracked res = SegmentEntry { range };
5623 res
5624}
5625
5626pub open spec fn fresh_segment_id(m: Map<SegmentId, SegmentEntry>) -> SegmentId {
5628 choose|id: SegmentId| !m.dom().contains(id)
5629}
5630
5631pub proof fn lemma_fresh_segment_id_not_in_dom(m: Map<SegmentId, SegmentEntry>)
5632 ensures
5633 !m.dom().contains(fresh_segment_id(m)),
5634{
5635 lemma_finite_int_set_has_unused(m.dom());
5636}
5637
5638pub proof fn tracked_unique_entry_new(paddr: Paddr) -> tracked UniqueEntry
5640 returns
5641 (UniqueEntry { paddr }),
5642{
5643 let tracked res = UniqueEntry { paddr };
5644 res
5645}
5646
5647pub open spec fn fresh_unique_id(m: Map<UniqueId, UniqueEntry>) -> UniqueId {
5649 choose|id: UniqueId| !m.dom().contains(id)
5650}
5651
5652pub proof fn lemma_fresh_unique_id_not_in_dom(m: Map<UniqueId, UniqueEntry>)
5653 ensures
5654 !m.dom().contains(fresh_unique_id(m)),
5655{
5656 lemma_finite_int_set_has_unused(m.dom());
5657}
5658
5659}