1pub mod cursor;
183pub mod frame;
184pub mod io;
185pub mod segment;
186pub mod trace;
187pub mod vm_space;
188
189use core::ops::Range;
190
191use vstd::prelude::*;
192use vstd_extra::ownership::*;
193
194use crate::mm::frame::{MetaSlot, UFrame, has_safe_slot};
195use crate::mm::page_prop::PageProperty;
196use crate::mm::vm_space::UserPtConfig;
197use crate::mm::vm_space::vm_space_specs::VmSpaceOwner;
198use crate::mm::{MAX_USERSPACE_VADDR, Paddr, Vaddr};
199use crate::specs::arch::mm::{MAX_PADDR, PAGE_SIZE};
200use crate::specs::mm::frame::mapping::{frame_to_index, index_to_frame, max_meta_slots};
201use crate::specs::mm::frame::meta_owners::{
202 PageUsage, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
203};
204use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
205use crate::specs::mm::io::VmIoOwner;
206use crate::specs::mm::page_table::cursor::owners::CursorOwner;
207use crate::specs::mm::page_table::node::Guards;
208use crate::specs::mm::tlb::TlbModel;
209
210verus! {
211
212pub type VmSpaceId = int;
217
218pub type CursorId = int;
220
221pub type VmIoId = int;
223
224pub type FrameId = int;
226
227pub type SegmentId = int;
230
231pub tracked struct FrameEntry {
238 pub paddr: Paddr,
239}
240
241pub tracked struct SegmentEntry {
259 pub range: Range<Paddr>,
260}
261
262pub open spec fn segment_cover_count(segments: Map<SegmentId, SegmentEntry>, paddr: Paddr) -> nat {
272 segments.dom().filter(
273 |sid: SegmentId| segments[sid].range.start <= paddr && paddr < segments[sid].range.end,
274 ).len()
275}
276
277pub proof fn lemma_segment_cover_witness(
282 segments: Map<SegmentId, SegmentEntry>,
283 paddr: Paddr,
284) -> (sid: SegmentId)
285 requires
286 segment_cover_count(segments, paddr) > 0,
287 ensures
288 segments.dom().contains(sid),
289 segments[sid].range.start <= paddr < segments[sid].range.end,
290{
291 let covering = segments.dom().filter(
292 |sid: SegmentId| segments[sid].range.start <= paddr && paddr < segments[sid].range.end,
293 );
294 assert(covering.len() > 0);
295 let sid = covering.choose();
296 assert(covering.contains(sid));
297 sid
298}
299
300pub open spec fn handle_count(frames: Map<FrameId, FrameEntry>, idx: usize) -> nat {
306 frames.dom().filter(|fid: FrameId| frame_to_index(frames[fid].paddr) == idx).len()
307}
308
309pub proof fn lemma_handle_count_insert_fresh(
314 frames: Map<FrameId, FrameEntry>,
315 id: FrameId,
316 entry: FrameEntry,
317 idx: usize,
318)
319 requires
320 !frames.dom().contains(id),
321 frames.dom().finite(),
322 ensures
323 handle_count(frames.insert(id, entry), idx) == handle_count(frames, idx) + (
324 if frame_to_index(entry.paddr) == idx {
325 1nat
326 } else {
327 0nat
328 }),
329{
330 let frames2 = frames.insert(id, entry);
331 let new_filt = frames2.dom().filter(|fid: FrameId| frame_to_index(frames2[fid].paddr) == idx);
332 let old_filt = frames.dom().filter(|fid: FrameId| frame_to_index(frames[fid].paddr) == idx);
333 assert(frames2.dom() =~= frames.dom().insert(id));
334 if frame_to_index(entry.paddr) == idx {
335 assert(new_filt =~= old_filt.insert(id)) by {
336 assert forall|fid: FrameId| #[trigger] new_filt.contains(fid) implies old_filt.insert(
337 id,
338 ).contains(fid) by {
339 if fid != id {
340 assert(frames2[fid] == frames[fid]);
341 }
342 };
343 assert forall|fid: FrameId| #[trigger]
344 old_filt.insert(id).contains(fid) implies new_filt.contains(fid) by {
345 if fid != id {
346 assert(frames2[fid] == frames[fid]);
347 } else {
348 assert(frames2[id] == entry);
349 }
350 };
351 };
352 assert(!old_filt.contains(id));
353 assert(old_filt.finite());
354 assert(new_filt.len() == old_filt.len() + 1);
355 } else {
356 assert(new_filt =~= old_filt) by {
357 assert forall|fid: FrameId| #[trigger] new_filt.contains(fid) implies old_filt.contains(
358 fid,
359 ) by {
360 if fid != id {
361 assert(frames2[fid] == frames[fid]);
362 } else {
363 assert(frames2[id] == entry);
364 }
365 };
366 assert forall|fid: FrameId| #[trigger] old_filt.contains(fid) implies new_filt.contains(
367 fid,
368 ) by {
369 assert(fid != id);
370 assert(frames2[fid] == frames[fid]);
371 };
372 };
373 }
374}
375
376pub proof fn lemma_handle_count_remove(frames: Map<FrameId, FrameEntry>, fid: FrameId, idx: usize)
380 requires
381 frames.dom().contains(fid),
382 frames.dom().finite(),
383 ensures
384 handle_count(frames.remove(fid), idx) == handle_count(frames, idx) - (if frame_to_index(
385 frames[fid].paddr,
386 ) == idx {
387 1nat
388 } else {
389 0nat
390 }),
391{
392 let frames2 = frames.remove(fid);
393 let new_filt = frames2.dom().filter(|gid: FrameId| frame_to_index(frames2[gid].paddr) == idx);
394 let old_filt = frames.dom().filter(|gid: FrameId| frame_to_index(frames[gid].paddr) == idx);
395 assert(frames2.dom() =~= frames.dom().remove(fid));
396 if frame_to_index(frames[fid].paddr) == idx {
397 assert(old_filt.contains(fid));
398 assert(new_filt =~= old_filt.remove(fid)) by {
399 assert forall|gid: FrameId| #[trigger] new_filt.contains(gid) implies old_filt.remove(
400 fid,
401 ).contains(gid) by {
402 assert(gid != fid);
403 assert(frames2[gid] == frames[gid]);
404 };
405 assert forall|gid: FrameId| #[trigger]
406 old_filt.remove(fid).contains(gid) implies new_filt.contains(gid) by {
407 assert(gid != fid);
408 assert(frames2[gid] == frames[gid]);
409 };
410 };
411 assert(old_filt.finite());
412 assert(new_filt.len() == (old_filt.len() - 1) as nat);
413 } else {
414 assert(!old_filt.contains(fid));
415 assert(new_filt =~= old_filt) by {
416 assert forall|gid: FrameId| #[trigger] new_filt.contains(gid) implies old_filt.contains(
417 gid,
418 ) by {
419 assert(gid != fid);
420 assert(frames2[gid] == frames[gid]);
421 };
422 assert forall|gid: FrameId| #[trigger] old_filt.contains(gid) implies new_filt.contains(
423 gid,
424 ) by {
425 assert(gid != fid);
426 assert(frames2[gid] == frames[gid]);
427 };
428 };
429 }
430}
431
432pub proof fn lemma_frame_drop_pre_derivable<'rcu>(s: VmStore<'rcu>, fid: FrameId)
462 requires
463 s.inv(),
464 s.frames.dom().contains(fid),
465 segment_cover_count(s.segments, s.frames[fid].paddr) == 0,
466 ensures
467 frame::drop_pre(s.regions, s.frames[fid].paddr),
468 s.regions.slot_owners[frame_to_index(s.frames[fid].paddr)].inner_perms.ref_count.value()
469 == 1 ==> handle_count(s.frames, frame_to_index(s.frames[fid].paddr)) == 1,
470{
471 let paddr = s.frames[fid].paddr;
472 let idx = frame_to_index(paddr);
473 assert(has_safe_slot(paddr));
475 s.regions.inv_implies_correct_addr(paddr);
476 assert(idx < max_meta_slots());
477 assert(s.frames.dom().filter(
479 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
480 ).contains(fid));
481 assert(handle_count(s.frames, idx) >= 1);
482 assert(s.regions.slot_owners[idx].usage == PageUsage::Frame);
484 let so = s.regions.slot_owners[idx];
486 let rc = so.inner_perms.ref_count.value();
487 assert(rc != REF_COUNT_UNUSED);
488 assert(rc != REF_COUNT_UNIQUE);
489 assert(rc == handle_count(s.frames, idx) + so.paths_in_pt.len());
490 assert(so.inner_perms.storage.is_init());
491 assert(rc > 0);
494 assert(s.regions.slot_owners.contains_key(idx));
497 assert(s.regions.slot_owners[idx].inv());
498 assert(rc <= REF_COUNT_MAX);
501 assert(so.inner_perms.in_list.value() == 0);
502 if rc == 1 {
504 assert(handle_count(s.frames, idx) + so.paths_in_pt.len() == 1);
505 assert(so.paths_in_pt.len() == 0);
506 assert(so.paths_in_pt =~= Set::empty());
507 assert(handle_count(s.frames, idx) == 1);
508 }
509}
510
511pub enum VmIoKind {
513 Reader,
514 Writer,
515}
516
517pub tracked struct VmIoEntry {
536 pub vm_space: Option<VmSpaceId>,
537 pub kind: VmIoKind,
538 pub vaddr: Vaddr,
539 pub len: usize,
540 pub owner: VmIoOwner,
541}
542
543impl VmIoEntry {
544 pub open spec fn inv(self) -> bool {
546 &&& self.owner.inv()
547 &&& match self.vm_space {
548 Some(_) => self.owner.mem_view is None,
549 None => match self.kind {
550 VmIoKind::Reader => self.owner.read_view_initialized(),
551 VmIoKind::Writer => self.owner.has_write_view(),
552 },
553 }
554 }
555
556 pub open spec fn is_kernel_reader(self) -> bool {
567 &&& self.vm_space is None
568 &&& self.kind == VmIoKind::Reader
569 }
570
571 pub open spec fn is_kernel_writer(self) -> bool {
572 &&& self.vm_space is None
573 &&& self.kind == VmIoKind::Writer
574 }
575}
576
577pub enum CursorKind {
582 ReadOnly,
583 Mutable,
584}
585
586pub tracked struct CursorEntry<'rcu> {
592 pub vm_space: VmSpaceId,
593 pub kind: CursorKind,
594 pub va: Range<Vaddr>,
595 pub owner: CursorOwner<'rcu, UserPtConfig>,
596 pub guards: Guards<'rcu>,
597}
598
599impl<'rcu> CursorEntry<'rcu> {
600 pub open spec fn inv(self) -> bool {
608 &&& self.owner.inv()
609 &&& self.owner.children_not_locked(self.guards)
610 &&& self.owner.nodes_locked(self.guards)
611 &&& !self.owner.popped_too_high
612 }
613}
614
615pub tracked struct VmStore<'rcu> {
623 pub regions: MetaRegionOwners,
624 pub tlb_model: TlbModel,
625 pub vm_spaces: Map<VmSpaceId, VmSpaceOwner>,
626 pub cursors: Map<CursorId, CursorEntry<'rcu>>,
627 pub vm_ios: Map<VmIoId, VmIoEntry>,
628 pub frames: Map<FrameId, FrameEntry>,
629 pub segments: Map<SegmentId, SegmentEntry>,
630}
631
632impl<'a, 'rcu> VmStore<'rcu> {
633 pub open spec fn inv(self) -> bool {
644 self.structural_inv() && self.accounting_inv()
645 }
646
647 pub open spec fn structural_inv(self) -> bool {
653 &&& self.regions.inv()
654 &&& forall|idx: usize|
672 idx < max_meta_slots() ==> #[trigger] self.regions.slots.contains_key(
673 idx,
674 )
675 &&& forall|idx: usize|
680 idx < max_meta_slots()
681 ==> #[trigger] self.regions.slot_owners[idx].inner_perms.in_list.value() == 0
682 &&& self.tlb_model.inv()
683 &&& forall|id: VmSpaceId| #[trigger]
684 self.vm_spaces.dom().contains(id) ==> self.vm_spaces[id].inv()
685 &&& forall|id: CursorId| #[trigger]
686 self.cursors.dom().contains(id) ==> self.cursors[id].inv()
687 &&& forall|id: CursorId| #[trigger]
688 self.cursors.dom().contains(id) ==> self.cursors[id].owner.metaregion_sound(
689 self.regions,
690 )
691 &&& forall|id: CursorId| #[trigger]
692 self.cursors.dom().contains(id) ==> self.vm_spaces.dom().contains(
693 self.cursors[id].vm_space,
694 )
695 &&& forall|id: VmIoId| #[trigger] self.vm_ios.dom().contains(id) ==> self.vm_ios[id].inv()
696 &&& forall|id: VmIoId| #[trigger]
697 self.vm_ios.dom().contains(id) ==> (self.vm_ios[id].vm_space matches Some(vs)
698 ==> self.vm_spaces.dom().contains(vs))
699 &&& forall|id: VmIoId| #[trigger]
700 self.vm_ios.dom().contains(id) ==> self.vm_ios[id].vm_space is Some ==> (
701 self.vm_ios[id].vaddr as nat) + (self.vm_ios[id].len as nat)
702 <= MAX_USERSPACE_VADDR as nat
703 &&& forall|fid: FrameId| #[trigger]
713 self.frames.dom().contains(fid) ==> has_safe_slot(
714 self.frames[fid].paddr,
715 )
716 &&& forall|fid: FrameId| #[trigger]
725 self.frames.dom().contains(fid) ==> self.regions.slot_owners[frame_to_index(
726 self.frames[fid].paddr,
727 )].usage
728 == PageUsage::Frame
729 &&& self.frames.dom().finite()
734 &&& self.segments.dom().finite()
737 &&& forall|sid: SegmentId| #[trigger]
743 self.segments.dom().contains(sid) ==> {
744 let r = self.segments[sid].range;
745 &&& r.start % PAGE_SIZE == 0
746 &&& r.end % PAGE_SIZE == 0
747 &&& r.start < r.end
748 &&& r.end <= MAX_PADDR
749 }
750 &&& forall|sid: SegmentId, paddr: Paddr|
758 #![trigger
759 self.segments.dom().contains(sid),
760 frame_to_index(paddr)]
761 self.segments.dom().contains(sid) && self.segments[sid].range.start <= paddr
762 < self.segments[sid].range.end && paddr % PAGE_SIZE == 0
763 ==> self.regions.slot_owners[frame_to_index(paddr)].usage
764 == PageUsage::Frame
765 }
771
772 pub open spec fn accounting_inv(self) -> bool {
802 &&& forall|idx: usize|
841 #![trigger self.regions.slot_owners[idx]]
842 idx < max_meta_slots() && self.regions.slot_owners[idx].inner_perms.ref_count.value()
843 == REF_COUNT_UNUSED ==> handle_count(self.frames, idx) == 0
844 && self.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
845 self.segments,
846 index_to_frame(idx),
847 )
848 == 0
849 &&& forall|idx: usize|
854 #![trigger self.regions.slot_owners[idx]]
855 idx < max_meta_slots() && self.regions.slot_owners[idx].usage == PageUsage::Frame
856 && self.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
857 && self.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNIQUE
858 ==> handle_count(self.frames, idx) > 0
859 || self.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
860 self.segments,
861 index_to_frame(idx),
862 )
863 > 0
864 &&& forall|idx: usize|
872 #![trigger self.regions.slot_owners[idx]]
873 idx < max_meta_slots() && self.regions.slot_owners[idx].usage == PageUsage::Frame && (
874 handle_count(self.frames, idx) > 0 || self.regions.slot_owners[idx].paths_in_pt.len()
875 > 0 || segment_cover_count(self.segments, index_to_frame(idx)) > 0) ==> {
876 let so = self.regions.slot_owners[idx];
877 let rc = so.inner_perms.ref_count.value();
878 &&& rc != REF_COUNT_UNUSED
879 &&& rc != REF_COUNT_UNIQUE
880 &&& rc == handle_count(self.frames, idx) + so.paths_in_pt.len()
881 + segment_cover_count(self.segments, index_to_frame(idx))
882 &&& so.inner_perms.storage.is_init()
883 }
884 }
885}
886
887pub enum Op {
893 NewVmSpace,
894 DropVmSpace { vs: VmSpaceId },
895 OpenCursor { vs: VmSpaceId, va: Range<Vaddr> },
896 OpenCursorMut { vs: VmSpaceId, va: Range<Vaddr> },
897 DropCursor { c: CursorId },
898 Query { c: CursorId },
899 FindNext { c: CursorId, len: usize },
900 Jump { c: CursorId, va: Vaddr },
901 VirtAddr { c: CursorId },
902 Map { c: CursorId, fid: FrameId, prop: PageProperty },
903 Unmap { c: CursorId, len: usize },
904 ProtectNext { c: CursorId, len: usize },
905 NewReader { vs: VmSpaceId, vaddr: Vaddr, len: usize },
906 NewWriter { vs: VmSpaceId, vaddr: Vaddr, len: usize },
907 NewKernelReader { vaddr: Vaddr, len: usize },
908 NewKernelWriter { vaddr: Vaddr, len: usize },
909 DropReader { vio: VmIoId },
910 DropWriter { vio: VmIoId },
911 ReaderReadVal { source: VmIoId },
915 ReaderCollect { source: VmIoId },
917 ReaderLimit { vio: VmIoId, max: usize },
918 ReaderSkip { vio: VmIoId, n: usize },
919 ReaderQuery { vio: VmIoId },
920 WriterWriteVal { writer: VmIoId },
922 WriterFillZeros { vio: VmIoId, len: usize },
923 WriterLimit { vio: VmIoId, max: usize },
924 WriterSkip { vio: VmIoId, n: usize },
925 WriterQuery { vio: VmIoId },
926 Read { source: VmIoId, dest: VmIoId },
929 Write { source: VmIoId, dest: VmIoId },
932 FrameFromUnused { paddr: Paddr },
935 FrameFromInUse { paddr: Paddr },
939 FrameDrop { fid: FrameId },
945 SegmentFromUnused { range: Range<Paddr> },
950 SegmentDrop { sid: SegmentId },
954 SegmentSplit { sid: SegmentId, offset: usize },
961 SegmentNext {
980 sid: SegmentId,
981 },
982 }
1033
1034pub open spec fn op_pre<'rcu>(s: VmStore<'rcu>, op: Op) -> bool {
1052 match op {
1053 Op::NewVmSpace => true,
1054 Op::DropVmSpace { vs } => s.vm_spaces.dom().contains(vs) && (forall|c: CursorId| #[trigger]
1055 s.cursors.dom().contains(c) ==> s.cursors[c].vm_space != vs) && (forall|v: VmIoId|
1056 #[trigger]
1057 s.vm_ios.dom().contains(v) ==> s.vm_ios[v].vm_space != Some(vs)),
1058 Op::OpenCursor { vs, va: _ } => s.vm_spaces.dom().contains(vs),
1059 Op::OpenCursorMut { vs, va: _ } => s.vm_spaces.dom().contains(vs),
1060 Op::DropCursor { c } => s.cursors.dom().contains(c),
1061 Op::Query { c } => s.cursors.dom().contains(c),
1062 Op::FindNext { c, len: _ } => s.cursors.dom().contains(c),
1063 Op::Jump { c, va: _ } => s.cursors.dom().contains(c),
1064 Op::VirtAddr { c } => s.cursors.dom().contains(c),
1065 Op::Map { c, fid, prop: _ } => s.cursors.dom().contains(c) && s.frames.dom().contains(fid),
1078 Op::Unmap { c, len: _ } => s.cursors.dom().contains(c),
1079 Op::ProtectNext { c, len: _ } => s.cursors.dom().contains(c),
1080 Op::NewReader { vs, vaddr: _, len: _ } => s.vm_spaces.dom().contains(vs),
1081 Op::NewWriter { vs, vaddr: _, len: _ } => s.vm_spaces.dom().contains(vs),
1082 Op::NewKernelReader { vaddr: _, len: _ } => true,
1083 Op::NewKernelWriter { vaddr: _, len: _ } => true,
1084 Op::DropReader { vio } => s.vm_ios.dom().contains(vio),
1085 Op::DropWriter { vio } => s.vm_ios.dom().contains(vio),
1086 Op::ReaderReadVal { source } => s.vm_ios.dom().contains(source),
1087 Op::ReaderCollect { source } => s.vm_ios.dom().contains(source),
1088 Op::ReaderLimit { vio, max: _ } => s.vm_ios.dom().contains(vio),
1089 Op::ReaderSkip { vio, n: _ } => s.vm_ios.dom().contains(vio),
1090 Op::ReaderQuery { vio } => s.vm_ios.dom().contains(vio),
1091 Op::WriterWriteVal { writer } => s.vm_ios.dom().contains(writer),
1092 Op::WriterFillZeros { vio, len: _ } => s.vm_ios.dom().contains(vio),
1093 Op::WriterLimit { vio, max: _ } => s.vm_ios.dom().contains(vio),
1094 Op::WriterSkip { vio, n: _ } => s.vm_ios.dom().contains(vio),
1095 Op::WriterQuery { vio } => s.vm_ios.dom().contains(vio),
1096 Op::Read { source, dest } => s.vm_ios.dom().contains(source) && s.vm_ios.dom().contains(
1102 dest,
1103 ) && source != dest && s.vm_ios[source].is_kernel_reader()
1104 && s.vm_ios[dest].is_kernel_writer(),
1105 Op::Write { source, dest } => s.vm_ios.dom().contains(source) && s.vm_ios.dom().contains(
1107 dest,
1108 ) && source != dest && s.vm_ios[source].is_kernel_reader()
1109 && s.vm_ios[dest].is_kernel_writer(),
1110 Op::FrameFromUnused { paddr: _ } => true,
1111 Op::FrameFromInUse { paddr: _ } => true,
1112 Op::FrameDrop { fid } => s.frames.dom().contains(fid) && segment_cover_count(
1129 s.segments,
1130 s.frames[fid].paddr,
1131 ) == 0,
1132 Op::SegmentFromUnused { range } => range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE
1140 == 0 && range.start < range.end && range.end <= MAX_PADDR && forall|paddr: Paddr|
1141 #![trigger frame_to_index(paddr)]
1142 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
1143 ==> s.regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value()
1144 == REF_COUNT_UNUSED,
1145 Op::SegmentDrop { sid } => s.segments.dom().contains(sid),
1151 Op::SegmentSplit { sid, offset } => s.segments.dom().contains(sid) && offset % PAGE_SIZE
1156 == 0 && 0 < offset && offset < (s.segments[sid].range.end
1157 - s.segments[sid].range.start),
1158 Op::SegmentNext { sid } => s.segments.dom().contains(sid),
1161 }
1162}
1163
1164impl<'rcu> VmStore<'rcu> {
1169 pub proof fn extract_vm_space(tracked &mut self, vs: VmSpaceId) -> (tracked res: VmSpaceOwner)
1174 requires
1175 old(self).inv(),
1176 old(self).vm_spaces.dom().contains(vs),
1177 forall|c: CursorId| #[trigger]
1178 old(self).cursors.dom().contains(c) ==> old(self).cursors[c].vm_space != vs,
1179 forall|v: VmIoId| #[trigger]
1180 old(self).vm_ios.dom().contains(v) ==> old(self).vm_ios[v].vm_space != Some(vs),
1181 ensures
1182 final(self).regions == old(self).regions,
1183 final(self).tlb_model == old(self).tlb_model,
1184 final(self).vm_spaces == old(self).vm_spaces.remove(vs),
1185 final(self).cursors == old(self).cursors,
1186 final(self).vm_ios == old(self).vm_ios,
1187 final(self).frames == old(self).frames,
1188 final(self).segments == old(self).segments,
1189 res == old(self).vm_spaces[vs],
1190 final(self).inv(),
1191 {
1192 self.vm_spaces.tracked_remove(vs)
1193 }
1194
1195 pub proof fn insert_vm_space(tracked &mut self, vs: VmSpaceId, tracked owner: VmSpaceOwner)
1198 requires
1199 old(self).inv(),
1200 !old(self).vm_spaces.dom().contains(vs),
1201 owner.inv(),
1202 ensures
1203 final(self).regions == old(self).regions,
1204 final(self).tlb_model == old(self).tlb_model,
1205 final(self).vm_spaces == old(self).vm_spaces.insert(vs, owner),
1206 final(self).cursors == old(self).cursors,
1207 final(self).vm_ios == old(self).vm_ios,
1208 final(self).frames == old(self).frames,
1209 final(self).segments == old(self).segments,
1210 final(self).inv(),
1211 {
1212 self.vm_spaces.tracked_insert(vs, owner);
1213 }
1214
1215 pub proof fn extract_cursor(tracked &mut self, c: CursorId) -> (tracked res: CursorEntry<'rcu>)
1217 requires
1218 old(self).inv(),
1219 old(self).cursors.dom().contains(c),
1220 ensures
1221 final(self).regions == old(self).regions,
1222 final(self).tlb_model == old(self).tlb_model,
1223 final(self).vm_spaces == old(self).vm_spaces,
1224 final(self).cursors == old(self).cursors.remove(c),
1225 final(self).vm_ios == old(self).vm_ios,
1226 final(self).frames == old(self).frames,
1227 final(self).segments == old(self).segments,
1228 res == old(self).cursors[c],
1229 final(self).inv(),
1230 {
1231 self.cursors.tracked_remove(c)
1232 }
1233
1234 pub proof fn insert_cursor(tracked &mut self, c: CursorId, tracked entry: CursorEntry<'rcu>)
1239 requires
1240 old(self).inv(),
1241 !old(self).cursors.dom().contains(c),
1242 entry.inv(),
1243 entry.owner.metaregion_sound(old(self).regions),
1244 old(self).vm_spaces.dom().contains(entry.vm_space),
1245 ensures
1246 final(self).regions == old(self).regions,
1247 final(self).tlb_model == old(self).tlb_model,
1248 final(self).vm_spaces == old(self).vm_spaces,
1249 final(self).cursors == old(self).cursors.insert(c, entry),
1250 final(self).vm_ios == old(self).vm_ios,
1251 final(self).frames == old(self).frames,
1252 final(self).segments == old(self).segments,
1253 final(self).inv(),
1254 {
1255 self.cursors.tracked_insert(c, entry);
1256 }
1257
1258 pub proof fn extract_vm_io(tracked &mut self, vio: VmIoId) -> (tracked res: VmIoEntry)
1260 requires
1261 old(self).inv(),
1262 old(self).vm_ios.dom().contains(vio),
1263 ensures
1264 final(self).regions == old(self).regions,
1265 final(self).tlb_model == old(self).tlb_model,
1266 final(self).vm_spaces == old(self).vm_spaces,
1267 final(self).cursors == old(self).cursors,
1268 final(self).vm_ios == old(self).vm_ios.remove(vio),
1269 final(self).frames == old(self).frames,
1270 final(self).segments == old(self).segments,
1271 res == old(self).vm_ios[vio],
1272 final(self).inv(),
1273 {
1274 self.vm_ios.tracked_remove(vio)
1275 }
1276
1277 pub proof fn insert_vm_io(tracked &mut self, vio: VmIoId, tracked entry: VmIoEntry)
1285 requires
1286 old(self).inv(),
1287 !old(self).vm_ios.dom().contains(vio),
1288 entry.inv(),
1289 entry.vm_space matches Some(vs) ==> old(self).vm_spaces.dom().contains(vs),
1290 entry.vm_space is Some ==> (entry.vaddr as nat) + (entry.len as nat)
1291 <= MAX_USERSPACE_VADDR as nat,
1292 ensures
1293 final(self).regions == old(self).regions,
1294 final(self).tlb_model == old(self).tlb_model,
1295 final(self).vm_spaces == old(self).vm_spaces,
1296 final(self).cursors == old(self).cursors,
1297 final(self).vm_ios == old(self).vm_ios.insert(vio, entry),
1298 final(self).frames == old(self).frames,
1299 final(self).segments == old(self).segments,
1300 final(self).inv(),
1301 {
1302 self.vm_ios.tracked_insert(vio, entry);
1303 }
1304
1305 pub proof fn extract_frame(tracked &mut self, fid: FrameId) -> (tracked res: FrameEntry)
1314 requires
1315 old(self).structural_inv(),
1316 old(self).frames.dom().contains(fid),
1317 ensures
1318 final(self).regions == old(self).regions,
1319 final(self).tlb_model == old(self).tlb_model,
1320 final(self).vm_spaces == old(self).vm_spaces,
1321 final(self).cursors == old(self).cursors,
1322 final(self).vm_ios == old(self).vm_ios,
1323 final(self).frames == old(self).frames.remove(fid),
1324 final(self).segments == old(self).segments,
1325 res == old(self).frames[fid],
1326 final(self).structural_inv(),
1327 {
1328 self.frames.tracked_remove(fid)
1329 }
1330
1331 pub proof fn insert_frame(tracked &mut self, fid: FrameId, tracked entry: FrameEntry)
1340 requires
1341 old(self).structural_inv(),
1342 !old(self).frames.dom().contains(fid),
1343 has_safe_slot(entry.paddr),
1344 old(self).regions.slot_owners[frame_to_index(entry.paddr)].usage == PageUsage::Frame,
1349 ensures
1350 final(self).regions == old(self).regions,
1351 final(self).tlb_model == old(self).tlb_model,
1352 final(self).vm_spaces == old(self).vm_spaces,
1353 final(self).cursors == old(self).cursors,
1354 final(self).vm_ios == old(self).vm_ios,
1355 final(self).frames == old(self).frames.insert(fid, entry),
1356 final(self).segments == old(self).segments,
1357 final(self).structural_inv(),
1358 {
1359 self.frames.tracked_insert(fid, entry);
1360 }
1361
1362 pub proof fn extract_segment(tracked &mut self, sid: SegmentId) -> (tracked res: SegmentEntry)
1369 requires
1370 old(self).segments.dom().contains(sid),
1371 old(self).segments.dom().finite(),
1372 ensures
1373 final(self).regions == old(self).regions,
1374 final(self).tlb_model == old(self).tlb_model,
1375 final(self).vm_spaces == old(self).vm_spaces,
1376 final(self).cursors == old(self).cursors,
1377 final(self).vm_ios == old(self).vm_ios,
1378 final(self).frames == old(self).frames,
1379 final(self).segments == old(self).segments.remove(sid),
1380 res == old(self).segments[sid],
1381 {
1382 self.segments.tracked_remove(sid)
1383 }
1384
1385 pub proof fn insert_segment(tracked &mut self, sid: SegmentId, tracked entry: SegmentEntry)
1390 requires
1391 !old(self).segments.dom().contains(sid),
1392 ensures
1393 final(self).regions == old(self).regions,
1394 final(self).tlb_model == old(self).tlb_model,
1395 final(self).vm_spaces == old(self).vm_spaces,
1396 final(self).cursors == old(self).cursors,
1397 final(self).vm_ios == old(self).vm_ios,
1398 final(self).frames == old(self).frames,
1399 final(self).segments == old(self).segments.insert(sid, entry),
1400 {
1401 self.segments.tracked_insert(sid, entry);
1402 }
1403}
1404
1405pub proof fn step<'rcu>(tracked s: &mut VmStore<'rcu>, op: Op)
1415 requires
1416 old(s).inv(),
1417 op_pre(*old(s), op),
1418 ensures
1419 final(s).inv(),
1420{
1421 match op {
1422 Op::NewVmSpace => step_new_vm_space(s),
1423 Op::DropVmSpace { vs } => step_drop_vm_space(s, vs),
1424 Op::OpenCursor { vs, va } => step_open_cursor(s, vs, va),
1425 Op::OpenCursorMut { vs, va } => step_open_cursor_mut(s, vs, va),
1426 Op::DropCursor { c } => step_drop_cursor(s, c),
1427 Op::Query { c } => step_query(s, c),
1428 Op::FindNext { c, len } => step_find_next(s, c, len),
1429 Op::Jump { c, va } => step_jump(s, c, va),
1430 Op::VirtAddr { c: _ } => {},
1431 Op::Map { c, fid, prop } => step_map(s, c, fid, prop),
1432 Op::Unmap { c, len } => step_unmap(s, c, len),
1433 Op::ProtectNext { c, len } => step_protect_next(s, c, len),
1434 Op::NewReader { vs, vaddr, len } => step_new_vm_io(s, vs, vaddr, len, VmIoKind::Reader),
1435 Op::NewWriter { vs, vaddr, len } => step_new_vm_io(s, vs, vaddr, len, VmIoKind::Writer),
1436 Op::NewKernelReader { vaddr, len } => step_new_kernel_vm_io(
1437 s,
1438 vaddr,
1439 len,
1440 VmIoKind::Reader,
1441 ),
1442 Op::NewKernelWriter { vaddr, len } => step_new_kernel_vm_io(
1443 s,
1444 vaddr,
1445 len,
1446 VmIoKind::Writer,
1447 ),
1448 Op::DropReader { vio } => step_drop_vm_io(s, vio),
1449 Op::DropWriter { vio } => step_drop_vm_io(s, vio),
1450 Op::ReaderReadVal { source: _ } => {},
1452 Op::ReaderCollect { source: _ } => {},
1453 Op::WriterWriteVal { writer: _ } => {},
1454 Op::ReaderLimit { vio, max } => step_vm_io_method(s, vio, io::VmIoMethod::ReaderLimit(max)),
1455 Op::ReaderSkip { vio, n } => step_vm_io_method(s, vio, io::VmIoMethod::ReaderSkip(n)),
1456 Op::ReaderQuery { vio: _ } => {},
1457 Op::WriterFillZeros { vio, len } => step_vm_io_method(
1458 s,
1459 vio,
1460 io::VmIoMethod::WriterFillZeros(len),
1461 ),
1462 Op::WriterLimit { vio, max } => step_vm_io_method(s, vio, io::VmIoMethod::WriterLimit(max)),
1463 Op::WriterSkip { vio, n } => step_vm_io_method(s, vio, io::VmIoMethod::WriterSkip(n)),
1464 Op::WriterQuery { vio: _ } => {},
1465 Op::Read { source, dest } => step_read(s, source, dest),
1467 Op::Write { source, dest } => step_write(s, source, dest),
1470 Op::FrameFromUnused { paddr } => step_frame_from_unused(s, paddr),
1471 Op::FrameFromInUse { paddr } => step_frame_from_in_use(s, paddr),
1472 Op::FrameDrop { fid } => step_frame_drop(s, fid),
1473 Op::SegmentFromUnused { range } => step_segment_from_unused(s, range),
1474 Op::SegmentDrop { sid } => step_segment_drop(s, sid),
1475 Op::SegmentSplit { sid, offset } => step_segment_split(s, sid, offset),
1476 Op::SegmentNext { sid } => step_segment_next(s, sid),
1477 }
1478}
1479
1480proof fn lemma_accounting_preserved_by_pt_alloc<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1496 requires
1497 s_old.inv(),
1498 s_new.frames == s_old.frames,
1499 s_new.segments == s_old.segments,
1501 forall|i: usize|
1502 #![trigger s_new.regions.slot_owners[i]]
1503 s_new.regions.slot_owners[i] != s_old.regions.slot_owners[i] ==> {
1504 &&& s_old.regions.slot_owners[i].inner_perms.ref_count.value() == REF_COUNT_UNUSED
1505 &&& s_new.regions.slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1506 &&& s_new.regions.slot_owners[i].usage != PageUsage::Frame
1507 },
1508 ensures
1509 s_new.accounting_inv(),
1510 forall|fid: FrameId| #[trigger]
1515 s_new.frames.dom().contains(fid) ==> s_new.regions.slot_owners[frame_to_index(
1516 s_new.frames[fid].paddr,
1517 )].usage == PageUsage::Frame,
1518 forall|sid: SegmentId, paddr: Paddr|
1520 #![trigger
1521 s_new.segments.dom().contains(sid),
1522 frame_to_index(paddr)]
1523 s_new.segments.dom().contains(sid) && s_new.segments[sid].range.start <= paddr
1524 < s_new.segments[sid].range.end && paddr % PAGE_SIZE == 0
1525 ==> s_new.regions.slot_owners[frame_to_index(paddr)].usage == PageUsage::Frame,
1526{
1527 assert forall|idx: usize|
1530 #![trigger s_new.regions.slot_owners[idx]]
1531 idx < max_meta_slots() && s_new.regions.slot_owners[idx].inner_perms.ref_count.value()
1532 == REF_COUNT_UNUSED implies handle_count(s_new.frames, idx) == 0
1533 && s_new.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1534 s_new.segments,
1535 index_to_frame(idx),
1536 ) == 0 by {
1537 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1538 };
1539 assert forall|idx: usize|
1542 #![trigger s_new.regions.slot_owners[idx]]
1543 idx < max_meta_slots() && s_new.regions.slot_owners[idx].usage == PageUsage::Frame
1544 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1545 && s_new.regions.slot_owners[idx].inner_perms.ref_count.value()
1546 != REF_COUNT_UNIQUE implies handle_count(s_new.frames, idx) > 0
1547 || s_new.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1548 s_new.segments,
1549 index_to_frame(idx),
1550 ) > 0 by {
1551 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1552 };
1553 assert forall|idx: usize|
1556 #![trigger s_new.regions.slot_owners[idx]]
1557 idx < max_meta_slots() && s_new.regions.slot_owners[idx].usage == PageUsage::Frame && (
1558 handle_count(s_new.frames, idx) > 0 || s_new.regions.slot_owners[idx].paths_in_pt.len() > 0
1559 || segment_cover_count(s_new.segments, index_to_frame(idx)) > 0) implies {
1560 let so = s_new.regions.slot_owners[idx];
1561 let rc = so.inner_perms.ref_count.value();
1562 &&& rc != REF_COUNT_UNUSED
1563 &&& rc != REF_COUNT_UNIQUE
1564 &&& rc == handle_count(s_new.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1565 s_new.segments,
1566 index_to_frame(idx),
1567 )
1568 &&& so.inner_perms.storage.is_init()
1569 } by {
1570 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1571 };
1572 assert forall|sid: SegmentId, paddr: Paddr|
1577 #![trigger
1578 s_new.segments.dom().contains(sid),
1579 frame_to_index(paddr)]
1580 s_new.segments.dom().contains(sid) && s_new.segments[sid].range.start <= paddr
1581 < s_new.segments[sid].range.end && paddr % PAGE_SIZE
1582 == 0 implies s_new.regions.slot_owners[frame_to_index(paddr)].usage
1583 == PageUsage::Frame by {
1584 let idx = frame_to_index(paddr);
1585 assert(s_old.regions.slot_owners[idx].usage == PageUsage::Frame);
1587 lemma_segment_cover_contains(s_old.segments, sid, paddr);
1590 assert(s_old.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
1591 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1593 };
1594 assert forall|fid: FrameId| #[trigger]
1600 s_new.frames.dom().contains(fid) implies s_new.regions.slot_owners[frame_to_index(
1601 s_new.frames[fid].paddr,
1602 )].usage == PageUsage::Frame by {
1603 let idx = frame_to_index(s_new.frames[fid].paddr);
1604 assert(s_old.frames.dom().filter(
1606 |gid: FrameId| frame_to_index(s_old.frames[gid].paddr) == idx,
1607 ).contains(fid));
1608 assert(handle_count(s_old.frames, idx) >= 1);
1609 assert(s_old.regions.slot_owners[idx].usage == PageUsage::Frame);
1611 assert(s_old.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
1612 assert(s_new.regions.slot_owners[idx] == s_old.regions.slot_owners[idx]);
1615 };
1616}
1617
1618proof fn step_new_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>)
1619 requires
1620 old(s).inv(),
1621 ensures
1622 final(s).inv(),
1623{
1624 let ghost s_before = *s;
1625 let tracked owner = vm_space::new_vm_space_step(&mut s.regions);
1626 let ghost id = fresh_vm_space_id(s.vm_spaces);
1627 axiom_fresh_vm_space_id_not_in_dom(s.vm_spaces);
1628 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1631 s.insert_vm_space(id, owner);
1632}
1633
1634proof fn step_drop_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId)
1635 requires
1636 old(s).inv(),
1637 old(s).vm_spaces.dom().contains(vs),
1638 forall|c: CursorId| #[trigger]
1639 old(s).cursors.dom().contains(c) ==> old(s).cursors[c].vm_space != vs,
1640 forall|v: VmIoId| #[trigger]
1641 old(s).vm_ios.dom().contains(v) ==> old(s).vm_ios[v].vm_space != Some(vs),
1642 ensures
1643 final(s).inv(),
1644{
1645 let tracked owner = s.extract_vm_space(vs);
1646 vm_space::drop_vm_space_step(owner);
1647}
1648
1649proof fn step_open_cursor<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId, va: Range<Vaddr>)
1650 requires
1651 old(s).inv(),
1652 old(s).vm_spaces.dom().contains(vs),
1653 ensures
1654 final(s).inv(),
1655{
1656 let ghost s_before = *s;
1657 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1658 let tracked res = cursor::open_cursor_step(vm_space_ref, &mut s.regions, vs, va);
1659 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1662 match res {
1663 Option::Some(entry) => {
1664 let ghost id = fresh_cursor_id(s.cursors);
1665 axiom_fresh_cursor_id_not_in_dom(s.cursors);
1666 s.insert_cursor(id, entry);
1667 },
1668 Option::None => {},
1669 }
1670}
1671
1672proof fn step_open_cursor_mut<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId, va: Range<Vaddr>)
1673 requires
1674 old(s).inv(),
1675 old(s).vm_spaces.dom().contains(vs),
1676 ensures
1677 final(s).inv(),
1678{
1679 let ghost s_before = *s;
1680 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1681 let tracked res = cursor::open_cursor_mut_step(vm_space_ref, &mut s.regions, vs, va);
1682 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1685 match res {
1686 Option::Some(entry) => {
1687 let ghost id = fresh_cursor_id(s.cursors);
1688 axiom_fresh_cursor_id_not_in_dom(s.cursors);
1689 s.insert_cursor(id, entry);
1690 },
1691 Option::None => {},
1692 }
1693}
1694
1695proof fn step_drop_cursor<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1696 requires
1697 old(s).inv(),
1698 old(s).cursors.dom().contains(c),
1699 ensures
1700 final(s).inv(),
1701{
1702 let tracked entry = s.extract_cursor(c);
1703 cursor::drop_cursor_step(entry);
1704}
1705
1706proof fn step_query<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1707 requires
1708 old(s).inv(),
1709 old(s).cursors.dom().contains(c),
1710 ensures
1711 final(s).inv(),
1712{
1713 let ghost old_frames = s.frames;
1714 let ghost old_regions = s.regions;
1715 let tracked mut entry = s.extract_cursor(c);
1716 let ghost res = cursor::cursor_query_step(&mut entry, &mut s.regions);
1717 match res {
1718 Option::None => {
1719 s.insert_cursor(c, entry);
1722 },
1723 Option::Some(paddr) => {
1724 let ghost target_idx = frame_to_index(paddr);
1729 s.regions.inv_implies_correct_addr(paddr);
1730 let ghost id = fresh_frame_id(s.frames);
1731 axiom_fresh_frame_id_not_in_dom(s.frames);
1732 let ghost entry_paddr = paddr;
1733 let tracked frame_entry = axiom_frame_entry_new(paddr);
1734 s.insert_frame(id, frame_entry);
1735 assert(s.regions.slot_owners[target_idx].usage == PageUsage::Frame);
1743 assert forall|idx: usize|
1745 #![trigger s.regions.slot_owners[idx]]
1746 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
1747 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1748 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1749 s.segments,
1750 index_to_frame(idx),
1751 ) == 0 by {
1752 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1753 if idx == target_idx {
1754 assert(false);
1757 } else {
1758 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1763 }
1764 };
1765 assert forall|idx: usize|
1766 #![trigger s.regions.slot_owners[idx]]
1767 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
1768 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1769 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
1770 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1771 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1772 s.segments,
1773 index_to_frame(idx),
1774 ) > 0 by {
1775 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1776 if idx == target_idx {
1777 assert(handle_count(s.frames, target_idx) >= 1);
1779 } else {
1780 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1781 }
1782 };
1783 assert forall|idx: usize|
1784 #![trigger s.regions.slot_owners[idx]]
1785 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
1786 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
1787 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
1788 let so = s.regions.slot_owners[idx];
1789 let rc = so.inner_perms.ref_count.value();
1790 &&& rc != REF_COUNT_UNUSED
1791 &&& rc != REF_COUNT_UNIQUE
1792 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1793 s.segments,
1794 index_to_frame(idx),
1795 )
1796 &&& so.inner_perms.storage.is_init()
1797 } by {
1798 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1799 if idx == target_idx {
1800 if old_regions.slot_owners[target_idx].inner_perms.ref_count.value()
1801 == REF_COUNT_UNUSED {
1802 assert(REF_COUNT_UNUSED == 0u32);
1807 assert(s.regions.slot_owners[target_idx].inner_perms.ref_count.value()
1808 == 1);
1809 assert(handle_count(s.frames, target_idx) == 1);
1810 assert(s.regions.slot_owners[target_idx].paths_in_pt.len()
1811 == old_regions.slot_owners[target_idx].paths_in_pt.len());
1812 assert(old_regions.slot_owners[target_idx].paths_in_pt.len() == 0);
1813 assert(segment_cover_count(s.segments, index_to_frame(target_idx)) == 0);
1814 } else if old_regions.slot_owners[target_idx].inner_perms.ref_count.value()
1815 == REF_COUNT_UNIQUE {
1816 assert(false);
1817 } else {
1818 let pre_so = old_regions.slot_owners[target_idx];
1821 let pre_rc = pre_so.inner_perms.ref_count.value();
1822 let pre_paths = pre_so.paths_in_pt.len();
1823 let pre_H = handle_count(old_frames, target_idx);
1824 let pre_cover = segment_cover_count(s.segments, index_to_frame(target_idx));
1825 if pre_H == 0 && pre_paths == 0 && pre_cover == 0 {
1826 assert(false);
1827 } else {
1828 assert(pre_rc == pre_H + pre_paths + pre_cover);
1832 assert(handle_count(s.frames, target_idx) == pre_H + 1);
1833 }
1834 }
1835 } else {
1836 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1837 }
1838 };
1839 s.insert_cursor(c, entry);
1840 },
1841 }
1842}
1843
1844proof fn step_find_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1845 requires
1846 old(s).inv(),
1847 old(s).cursors.dom().contains(c),
1848 ensures
1849 final(s).inv(),
1850{
1851 let tracked mut entry = s.extract_cursor(c);
1852 cursor::cursor_find_next_step(&mut entry, &mut s.regions, len);
1853 s.insert_cursor(c, entry);
1854}
1855
1856proof fn step_jump<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, va: Vaddr)
1857 requires
1858 old(s).inv(),
1859 old(s).cursors.dom().contains(c),
1860 ensures
1861 final(s).inv(),
1862{
1863 let tracked mut entry = s.extract_cursor(c);
1864 cursor::cursor_jump_step(&mut entry, &mut s.regions, va);
1865 s.insert_cursor(c, entry);
1866}
1867
1868proof fn step_protect_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1869 requires
1870 old(s).inv(),
1871 old(s).cursors.dom().contains(c),
1872 ensures
1873 final(s).inv(),
1874{
1875 let tracked mut entry = s.extract_cursor(c);
1876 cursor::cursor_protect_next_step(&mut entry, &mut s.regions, len);
1877 s.insert_cursor(c, entry);
1878}
1879
1880proof fn step_map<'rcu>(
1881 tracked s: &mut VmStore<'rcu>,
1882 c: CursorId,
1883 fid: FrameId,
1884 prop: PageProperty,
1885)
1886 requires
1887 old(s).inv(),
1888 old(s).cursors.dom().contains(c),
1889 old(s).frames.dom().contains(fid),
1890 ensures
1891 final(s).inv(),
1892{
1893 assert(s.regions.slot_owners[frame_to_index(s.frames[fid].paddr)].usage == PageUsage::Frame);
1896 let ghost paddr = s.frames[fid].paddr;
1897 let ghost target_idx = frame_to_index(paddr);
1898 let ghost old_frames = s.frames;
1899 let ghost old_regions = s.regions;
1900 assert(has_safe_slot(paddr));
1902 s.regions.inv_implies_correct_addr(paddr);
1903 assert(old_frames.dom().filter(
1906 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == target_idx,
1907 ).contains(fid));
1908 assert(handle_count(old_frames, target_idx) >= 1);
1909 let ghost pre_rc_target = old_regions.slot_owners[target_idx].inner_perms.ref_count.value();
1912 let ghost pre_paths_target = old_regions.slot_owners[target_idx].paths_in_pt.len();
1913 let ghost pre_cover_target = segment_cover_count(s.segments, index_to_frame(target_idx));
1914 assert(pre_rc_target != REF_COUNT_UNUSED);
1915 assert(pre_rc_target != REF_COUNT_UNIQUE);
1916 assert(pre_rc_target == handle_count(old_frames, target_idx) + pre_paths_target
1917 + pre_cover_target);
1918 assert(old_regions.slot_owners[target_idx].inner_perms.storage.is_init());
1919 let tracked mut entry = s.extract_cursor(c);
1920 let tracked _frame_entry = s.extract_frame(fid);
1924 cursor::map_step(&mut entry, &mut s.regions, &mut s.tlb_model, paddr, prop);
1925 assert forall|idx: usize|
1931 #![trigger s.regions.slot_owners[idx]]
1932 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
1933 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1934 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1935 s.segments,
1936 index_to_frame(idx),
1937 ) == 0 by {
1938 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1940 lemma_handle_count_remove(old_frames, fid, idx);
1941 if idx == target_idx {
1942 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == pre_rc_target);
1945 assert(false);
1946 }
1947 };
1948 assert forall|idx: usize|
1949 #![trigger s.regions.slot_owners[idx]]
1950 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
1951 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1952 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
1953 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1954 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1955 s.segments,
1956 index_to_frame(idx),
1957 ) > 0 by {
1958 lemma_handle_count_remove(old_frames, fid, idx);
1959 if idx == target_idx {
1960 assert(s.regions.slot_owners[idx].paths_in_pt.len() == pre_paths_target + 1);
1962 } else if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
1963 assert(s.regions.slot_owners[idx].usage != PageUsage::Frame);
1965 } else {
1966 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
1969 }
1970 };
1971 assert forall|idx: usize|
1972 #![trigger s.regions.slot_owners[idx]]
1973 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
1974 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
1975 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
1976 let so = s.regions.slot_owners[idx];
1977 let rc = so.inner_perms.ref_count.value();
1978 &&& rc != REF_COUNT_UNUSED
1979 &&& rc != REF_COUNT_UNIQUE
1980 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1981 s.segments,
1982 index_to_frame(idx),
1983 )
1984 &&& so.inner_perms.storage.is_init()
1985 } by {
1986 lemma_handle_count_remove(old_frames, fid, idx);
1987 if idx == target_idx {
1988 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() == pre_rc_target);
1994 assert(s.regions.slot_owners[idx].paths_in_pt.len() == pre_paths_target + 1);
1995 assert(handle_count(s.frames, idx) == (handle_count(old_frames, idx) - 1) as nat);
1996 } else if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
1997 assert(s.regions.slot_owners[idx].usage != PageUsage::Frame);
1998 } else {
1999 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2000 }
2001 };
2002 assert forall|fid_other: FrameId| #[trigger]
2008 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
2009 s.frames[fid_other].paddr,
2010 )].usage == PageUsage::Frame by {
2011 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2012 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
2014 if other_idx == target_idx {
2015 assert(s.regions.slot_owners[target_idx].usage
2017 == old_regions.slot_owners[target_idx].usage);
2018 } else {
2019 assert(old_frames.dom().filter(
2026 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
2027 ).contains(fid_other));
2028 assert(handle_count(old_frames, other_idx) >= 1);
2029 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value()
2030 != REF_COUNT_UNUSED);
2031 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
2032 }
2033 };
2034 assert forall|sid: SegmentId, paddr_c: Paddr|
2039 #![trigger
2040 s.segments.dom().contains(sid),
2041 frame_to_index(paddr_c)]
2042 s.segments.dom().contains(sid) && s.segments[sid].range.start <= paddr_c
2043 < s.segments[sid].range.end && paddr_c % PAGE_SIZE
2044 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
2045 == PageUsage::Frame by {
2046 let cov_idx = frame_to_index(paddr_c);
2047 lemma_segment_cover_contains(old_regions_segments_helper(s), sid, paddr_c);
2049 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
2050 assert(old_regions.slot_owners[cov_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
2051 if cov_idx == target_idx {
2052 assert(s.regions.slot_owners[target_idx].usage
2054 == old_regions.slot_owners[target_idx].usage);
2055 } else {
2056 assert(s.regions.slot_owners[cov_idx] == old_regions.slot_owners[cov_idx]);
2058 }
2059 };
2060 s.insert_cursor(c, entry);
2061}
2062
2063spec fn old_regions_segments_helper<'rcu>(s: &VmStore<'rcu>) -> Map<SegmentId, SegmentEntry> {
2067 s.segments
2068}
2069
2070proof fn step_unmap<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
2071 requires
2072 old(s).inv(),
2073 old(s).cursors.dom().contains(c),
2074 ensures
2075 final(s).inv(),
2076{
2077 let ghost old_regions = s.regions;
2078 let ghost old_frames = s.frames;
2079 let tracked mut entry = s.extract_cursor(c);
2080 cursor::cursor_mut_regions_step(
2081 &mut entry,
2082 &mut s.regions,
2083 &mut s.tlb_model,
2084 cursor::CursorMutRegionsMethod::Unmap(len),
2085 );
2086 assert forall|idx: usize|
2092 #![trigger s.regions.slot_owners[idx]]
2093 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2094 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2095 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2096 s.segments,
2097 index_to_frame(idx),
2098 ) == 0 by {
2099 assert(s.regions.slot_owners.contains_key(idx));
2103 assert(s.regions.slot_owners[idx].inv());
2104 assert(s.segments == old(s).segments);
2113 assert(old_regions == old(s).regions);
2114 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0) by {
2115 if segment_cover_count(old(s).segments, index_to_frame(idx)) > 0 {
2116 let pa = index_to_frame(idx);
2117 let sid = lemma_segment_cover_witness(old(s).segments, pa);
2118 assert(pa == (idx * PAGE_SIZE) as usize);
2122 assert(pa % PAGE_SIZE == 0);
2123 assert(frame_to_index(pa) == idx);
2124 assert(old_regions.slot_owners[idx].usage == PageUsage::Frame);
2126 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
2128 != REF_COUNT_UNUSED);
2129 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX);
2130 assert(s.regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX);
2132 }
2133 };
2134 if old_regions.slot_owners[idx].usage == PageUsage::Frame {
2136 assert(s.regions.slot_owners[idx].usage != PageUsage::MMIO);
2139 assert(s.regions.slot_owners[idx].paths_in_pt =~= Set::empty());
2140 } else if old_regions.slot_owners[idx].usage == PageUsage::MMIO {
2147 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2150 } else {
2151 assert(s.regions.slot_owners[idx].usage != PageUsage::MMIO);
2154 assert(s.regions.slot_owners[idx].paths_in_pt =~= Set::empty());
2155 assert(handle_count(s.frames, idx) == 0) by {
2156 let filt = s.frames.dom().filter(
2157 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
2158 );
2159 assert forall|fid: FrameId| #[trigger] filt.contains(fid) implies false by {
2160 assert(s.frames.dom().contains(fid));
2164 assert(frame_to_index(s.frames[fid].paddr) == idx);
2165 assert(s.regions.slot_owners[idx].usage == PageUsage::Frame);
2166 };
2167 assert(filt =~= Set::empty());
2168 };
2169 }
2170 };
2171 assert forall|idx: usize|
2172 #![trigger s.regions.slot_owners[idx]]
2173 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2174 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2175 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2176 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2177 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2178 s.segments,
2179 index_to_frame(idx),
2180 ) > 0 by {
2181 assert(s.regions.slot_owners.contains_key(idx));
2190 assert(s.regions.slot_owners[idx].inv());
2191 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED) by {
2192 if old_regions.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED {
2193 assert(old_regions.slot_owners.contains_key(idx));
2195 assert(old_regions.slot_owners[idx].inv());
2196 assert(old_regions.slot_owners[idx].paths_in_pt =~= Set::empty());
2197 assert(s.regions.slot_owners[idx].paths_in_pt.len() == 0);
2203 assert(false);
2204 }
2205 };
2206 if handle_count(old_frames, idx) > 0 {
2209 assert(handle_count(s.frames, idx) > 0);
2210 } else if segment_cover_count(s.segments, index_to_frame(idx)) > 0 {
2211 } else {
2213 assert(s.regions.slot_owners[idx].paths_in_pt.len() > 0);
2219 }
2220 };
2221 assert forall|idx: usize|
2222 #![trigger s.regions.slot_owners[idx]]
2223 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
2224 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
2225 > 0) implies {
2226 let so = s.regions.slot_owners[idx];
2227 let rc = so.inner_perms.ref_count.value();
2228 &&& rc != REF_COUNT_UNUSED
2229 &&& rc != REF_COUNT_UNIQUE
2230 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2231 s.segments,
2232 index_to_frame(idx),
2233 )
2234 &&& so.inner_perms.storage.is_init()
2235 } by {
2236 if handle_count(s.frames, idx) > 0 {
2243 assert(handle_count(old_frames, idx) > 0);
2245 } else {
2246 assert(old_regions.slot_owners[idx].paths_in_pt.len() > 0);
2255 }
2256 };
2268 assert forall|fid_other: FrameId| #[trigger]
2271 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
2272 s.frames[fid_other].paddr,
2273 )].usage == PageUsage::Frame by {
2274 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2275 assert(s.regions.slot_owners[other_idx].usage == old_regions.slot_owners[other_idx].usage);
2276 };
2277 s.insert_cursor(c, entry);
2278}
2279
2280proof fn step_new_vm_io<'rcu>(
2281 tracked s: &mut VmStore<'rcu>,
2282 vs: VmSpaceId,
2283 vaddr: Vaddr,
2284 len: usize,
2285 kind: VmIoKind,
2286)
2287 requires
2288 old(s).inv(),
2289 old(s).vm_spaces.dom().contains(vs),
2290 ensures
2291 final(s).inv(),
2292{
2293 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
2294 let tracked res = io::new_vm_io_step(vm_space_ref, Some(vs), vaddr, len, kind);
2295 match res {
2296 Option::Some(entry) => {
2297 let ghost id = fresh_vm_io_id(s.vm_ios);
2298 axiom_fresh_vm_io_id_not_in_dom(s.vm_ios);
2299 s.insert_vm_io(id, entry);
2300 },
2301 Option::None => {},
2302 }
2303}
2304
2305proof fn step_new_kernel_vm_io<'rcu>(
2306 tracked s: &mut VmStore<'rcu>,
2307 vaddr: Vaddr,
2308 len: usize,
2309 kind: VmIoKind,
2310)
2311 requires
2312 old(s).inv(),
2313 ensures
2314 final(s).inv(),
2315{
2316 let tracked entry = io::new_kernel_vm_io_step(vaddr, len, kind);
2317 let ghost id = fresh_vm_io_id(s.vm_ios);
2318 axiom_fresh_vm_io_id_not_in_dom(s.vm_ios);
2319 s.insert_vm_io(id, entry);
2320}
2321
2322proof fn step_drop_vm_io<'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId)
2323 requires
2324 old(s).inv(),
2325 old(s).vm_ios.dom().contains(vio),
2326 ensures
2327 final(s).inv(),
2328{
2329 let tracked entry = s.extract_vm_io(vio);
2330 io::drop_vm_io_step(entry);
2331}
2332
2333proof fn step_vm_io_method<'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId, method: io::VmIoMethod)
2334 requires
2335 old(s).inv(),
2336 old(s).vm_ios.dom().contains(vio),
2337 ensures
2338 final(s).inv(),
2339{
2340 let tracked mut entry = s.extract_vm_io(vio);
2341 io::vm_io_method_step(&mut entry, method);
2342 s.insert_vm_io(vio, entry);
2343}
2344
2345proof fn step_read<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
2346 requires
2347 old(s).inv(),
2348 old(s).vm_ios.dom().contains(source),
2349 old(s).vm_ios.dom().contains(dest),
2350 source != dest,
2351 old(s).vm_ios[source].vm_space is None,
2352 old(s).vm_ios[source].kind == VmIoKind::Reader,
2353 old(s).vm_ios[dest].vm_space is None,
2354 old(s).vm_ios[dest].kind == VmIoKind::Writer,
2355 ensures
2356 final(s).inv(),
2357{
2358 let tracked mut src = s.extract_vm_io(source);
2359 let tracked mut dst = s.extract_vm_io(dest);
2360 let tracked val = io::read_step(&mut src, &mut dst);
2361 s.insert_vm_io(source, src);
2362 s.insert_vm_io(dest, dst);
2363 let ghost id = fresh_vm_io_id(s.vm_ios);
2364 axiom_fresh_vm_io_id_not_in_dom(s.vm_ios);
2365 s.insert_vm_io(id, val);
2366}
2367
2368proof fn step_write<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
2369 requires
2370 old(s).inv(),
2371 old(s).vm_ios.dom().contains(source),
2372 old(s).vm_ios.dom().contains(dest),
2373 source != dest,
2374 old(s).vm_ios[source].vm_space is None,
2375 old(s).vm_ios[source].kind == VmIoKind::Reader,
2376 old(s).vm_ios[dest].vm_space is None,
2377 old(s).vm_ios[dest].kind == VmIoKind::Writer,
2378 ensures
2379 final(s).inv(),
2380{
2381 let tracked mut src = s.extract_vm_io(source);
2382 let tracked mut dst = s.extract_vm_io(dest);
2383 io::write_step(&mut src, &mut dst);
2384 s.insert_vm_io(source, src);
2385 s.insert_vm_io(dest, dst);
2386}
2387
2388proof fn step_frame_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2389 requires
2390 old(s).inv(),
2391 ensures
2392 final(s).inv(),
2393{
2394 if has_safe_slot(paddr) {
2401 s.regions.inv_implies_correct_addr(paddr);
2402 assert(s.regions.slots.contains_key(frame_to_index(paddr)));
2403 }
2404 let ghost old_frames = s.frames;
2405 let ghost old_regions = s.regions;
2406 let tracked res = frame::from_unused_step(&mut s.regions, paddr);
2407 match res {
2408 Option::Some(entry) => {
2409 let ghost id = fresh_frame_id(s.frames);
2410 axiom_fresh_frame_id_not_in_dom(s.frames);
2411 let ghost target_idx = frame_to_index(paddr);
2412 let ghost entry_paddr = entry.paddr;
2413 s.insert_frame(id, entry);
2414 assert(s.frames[id].paddr == paddr);
2415
2416 assert(handle_count(old_frames, target_idx) == 0);
2419 assert(old_regions.slot_owners[target_idx].paths_in_pt.is_empty());
2420
2421 assert forall|idx: usize|
2424 #![trigger s.regions.slot_owners[idx]]
2425 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2426 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2427 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
2428 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2429 if idx == target_idx {
2430 assert(false);
2432 } else {
2433 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2434 }
2435 };
2436
2437 assert forall|idx: usize|
2441 #![trigger s.regions.slot_owners[idx]]
2442 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2443 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2444 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2445 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2446 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2447 s.segments,
2448 index_to_frame(idx),
2449 ) > 0 by {
2450 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2451 if idx == target_idx {
2452 assert(handle_count(s.frames, idx) == 1);
2453 } else {
2454 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2455 }
2456 };
2457
2458 assert forall|idx: usize|
2460 #![trigger s.regions.slot_owners[idx]]
2461 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
2462 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
2463 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2464 let so = s.regions.slot_owners[idx];
2465 let rc = so.inner_perms.ref_count.value();
2466 &&& rc != REF_COUNT_UNUSED
2467 &&& rc != REF_COUNT_UNIQUE
2468 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2469 s.segments,
2470 index_to_frame(idx),
2471 )
2472 &&& so.inner_perms.storage.is_init()
2473 } by {
2474 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2475 if idx == target_idx {
2476 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value()
2477 == REF_COUNT_UNUSED);
2478 assert(handle_count(old_frames, idx) == 0);
2479 assert(handle_count(s.frames, idx) == 1);
2480 assert(segment_cover_count(s.segments, index_to_frame(idx)) == 0);
2483 } else {
2484 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2487 }
2488 };
2489 },
2490 Option::None => {
2491 assert(s.regions =~= old_regions);
2493 },
2494 }
2495}
2496
2497proof fn step_frame_from_in_use<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2498 requires
2499 old(s).inv(),
2500 ensures
2501 final(s).inv(),
2502{
2503 if has_safe_slot(paddr) {
2508 s.regions.inv_implies_correct_addr(paddr);
2509 assert(s.regions.slots.contains_key(frame_to_index(paddr)));
2510 }
2511 let ghost old_frames = s.frames;
2512 let ghost old_regions = s.regions;
2513 let tracked res = frame::from_in_use_step(&mut s.regions, paddr);
2514 match res {
2515 Option::Some(entry) => {
2516 let ghost id = fresh_frame_id(s.frames);
2517 axiom_fresh_frame_id_not_in_dom(s.frames);
2518 let ghost target_idx = frame_to_index(paddr);
2519 s.insert_frame(id, entry);
2520 assert(s.frames[id].paddr == paddr);
2521
2522 assert forall|idx: usize|
2525 #![trigger s.regions.slot_owners[idx]]
2526 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2527 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2528 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
2529 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2530 if idx == target_idx {
2531 assert(false);
2532 } else {
2533 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2534 }
2535 };
2536
2537 assert forall|idx: usize|
2540 #![trigger s.regions.slot_owners[idx]]
2541 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2542 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2543 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2544 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2545 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2546 s.segments,
2547 index_to_frame(idx),
2548 ) > 0 by {
2549 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2550 if idx == target_idx {
2551 assert(handle_count(s.frames, idx) >= 1);
2552 } else {
2553 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2554 }
2555 };
2556
2557 assert forall|idx: usize|
2559 #![trigger s.regions.slot_owners[idx]]
2560 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
2561 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
2562 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2563 let so = s.regions.slot_owners[idx];
2564 let rc = so.inner_perms.ref_count.value();
2565 &&& rc != REF_COUNT_UNUSED
2566 &&& rc != REF_COUNT_UNIQUE
2567 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2568 s.segments,
2569 index_to_frame(idx),
2570 )
2571 &&& so.inner_perms.storage.is_init()
2572 } by {
2573 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
2574 if idx == target_idx {
2575 assert(old_regions.slot_owners[idx].usage == PageUsage::Frame);
2579 } else {
2580 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2581 }
2582 };
2583 },
2584 Option::None => {
2585 assert(s.regions =~= old_regions);
2586 },
2587 }
2588}
2589
2590proof fn step_frame_drop<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
2591 requires
2592 old(s).inv(),
2593 old(s).frames.dom().contains(fid),
2594 segment_cover_count(old(s).segments, old(s).frames[fid].paddr) == 0,
2599 ensures
2600 final(s).inv(),
2601{
2602 lemma_frame_drop_pre_derivable(*s, fid);
2605 let ghost p = s.frames[fid].paddr;
2606 assert(has_safe_slot(p));
2607 s.regions.inv_implies_correct_addr(p);
2608 let ghost idx_p = frame_to_index(p);
2609 assert(idx_p < max_meta_slots());
2610 assert(s.frames.dom().filter(
2614 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx_p,
2615 ).contains(fid));
2616 assert(handle_count(s.frames, idx_p) >= 1);
2617 let ghost target_idx = frame_to_index(p);
2618 let ghost old_frames = s.frames;
2619 let ghost old_regions = s.regions;
2620 let tracked entry = s.extract_frame(fid);
2621 frame::drop_step(&mut s.regions, entry);
2622
2623 assert forall|idx: usize|
2632 #![trigger s.regions.slot_owners[idx]]
2633 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2634 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2635 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2636 s.segments,
2637 index_to_frame(idx),
2638 ) == 0 by {
2639 lemma_handle_count_remove(old_frames, fid, idx);
2640 if idx == target_idx {
2641 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() == 1);
2643 assert(handle_count(old_frames, idx) == 1);
2646 assert(handle_count(s.frames, idx) == 0);
2647 assert(s.regions.slot_owners[idx].paths_in_pt.is_empty());
2649 } else {
2650 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2651 }
2652 };
2653
2654 assert forall|idx: usize|
2659 #![trigger s.regions.slot_owners[idx]]
2660 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2661 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2662 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2663 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2664 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2665 s.segments,
2666 index_to_frame(idx),
2667 ) > 0 by {
2668 lemma_handle_count_remove(old_frames, fid, idx);
2669 if idx == target_idx {
2670 assert(handle_count(old_frames, idx) >= 1);
2675 } else {
2676 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2677 }
2678 };
2679
2680 assert forall|idx: usize|
2681 #![trigger s.regions.slot_owners[idx]]
2682 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
2683 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
2684 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2685 let so = s.regions.slot_owners[idx];
2686 let rc = so.inner_perms.ref_count.value();
2687 &&& rc != REF_COUNT_UNUSED
2688 &&& rc != REF_COUNT_UNIQUE
2689 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2690 s.segments,
2691 index_to_frame(idx),
2692 )
2693 &&& so.inner_perms.storage.is_init()
2694 } by {
2695 lemma_handle_count_remove(old_frames, fid, idx);
2696 if idx == target_idx {
2697 assert(old_regions.slot_owners[idx].usage == PageUsage::Frame);
2701 assert(handle_count(old_frames, idx) > 0);
2702 let ghost pre_rc = old_regions.slot_owners[idx].inner_perms.ref_count.value();
2703 let ghost pre_h = handle_count(old_frames, idx);
2704 let ghost pre_p = old_regions.slot_owners[idx].paths_in_pt.len();
2705 assert(pre_rc == pre_h + pre_p);
2706 let ghost post_h = handle_count(s.frames, idx);
2708 assert(post_h == (pre_h - 1) as nat);
2709 let ghost post_p = s.regions.slot_owners[idx].paths_in_pt.len();
2711 assert(post_p == pre_p);
2712 let ghost post_rc = s.regions.slot_owners[idx].inner_perms.ref_count.value();
2713 if pre_rc > 1 {
2714 assert(post_rc == (pre_rc - 1) as u64);
2716 assert(post_rc as nat == post_h + post_p);
2717 assert(post_rc >= 1);
2718 assert(post_rc <= REF_COUNT_MAX);
2719 assert(s.regions.slot_owners[idx].inner_perms.storage
2720 == old_regions.slot_owners[idx].inner_perms.storage);
2721 } else {
2722 assert(pre_h == 1);
2725 assert(pre_p == 0);
2726 assert(post_h == 0);
2727 assert(post_p == 0);
2728 assert(post_rc == REF_COUNT_UNUSED);
2730 assert(false);
2734 }
2735 } else {
2736 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2739 }
2740 };
2741}
2742
2743proof fn step_segment_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, range: Range<Paddr>)
2748 requires
2749 old(s).inv(),
2750 range.start % PAGE_SIZE == 0,
2751 range.end % PAGE_SIZE == 0,
2752 range.start < range.end,
2753 range.end <= MAX_PADDR,
2754 forall|paddr: Paddr|
2755 #![trigger frame_to_index(paddr)]
2756 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) ==> old(
2757 s,
2758 ).regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value()
2759 == REF_COUNT_UNUSED,
2760 ensures
2761 final(s).inv(),
2762{
2763 let ghost old_regions = s.regions;
2764 let ghost old_frames = s.frames;
2765 let ghost old_segments = s.segments;
2766 assert forall|paddr: Paddr|
2769 #![trigger frame_to_index(paddr)]
2770 (range.start <= paddr < range.end && paddr % PAGE_SIZE
2771 == 0) implies s.regions.slots.contains_key(frame_to_index(paddr)) by {
2772 s.regions.inv_implies_correct_addr(paddr);
2773 };
2774 let tracked res = segment::from_unused_step(&mut s.regions, range);
2775 match res {
2776 Option::Some(entry) => {
2777 let ghost id = fresh_segment_id(s.segments);
2778 axiom_fresh_segment_id_not_in_dom(s.segments);
2779 s.insert_segment(id, entry);
2780 assert forall|idx: usize|
2791 #![trigger s.regions.slot_owners[idx]]
2792 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2793 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2794 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2795 s.segments,
2796 index_to_frame(idx),
2797 ) == 0 by {
2798 let paddr = index_to_frame(idx);
2799 assert(paddr == (idx * PAGE_SIZE) as usize);
2801 assert(paddr % PAGE_SIZE == 0);
2802 assert(frame_to_index(paddr) == idx);
2803 if range.start <= paddr < range.end {
2804 assert(false);
2806 } else {
2807 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2809 assert(!(entry.range.start <= paddr < entry.range.end));
2812 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
2813 }
2814 };
2815 assert forall|idx: usize|
2816 #![trigger s.regions.slot_owners[idx]]
2817 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
2818 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
2819 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
2820 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2821 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2822 s.segments,
2823 index_to_frame(idx),
2824 ) > 0 by {
2825 let paddr = index_to_frame(idx);
2826 assert(paddr == (idx * PAGE_SIZE) as usize);
2827 assert(paddr % PAGE_SIZE == 0);
2828 assert(frame_to_index(paddr) == idx);
2829 if range.start <= paddr < range.end {
2830 assert(entry.range == range);
2831 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
2832 } else {
2833 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2834 assert(!(entry.range.start <= paddr < entry.range.end));
2835 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
2836 }
2837 };
2838 assert forall|idx: usize|
2839 #![trigger s.regions.slot_owners[idx]]
2840 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
2841 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
2842 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
2843 let so = s.regions.slot_owners[idx];
2844 let rc = so.inner_perms.ref_count.value();
2845 &&& rc != REF_COUNT_UNUSED
2846 &&& rc != REF_COUNT_UNIQUE
2847 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2848 s.segments,
2849 index_to_frame(idx),
2850 )
2851 &&& so.inner_perms.storage.is_init()
2852 } by {
2853 let paddr = index_to_frame(idx);
2854 assert(paddr == (idx * PAGE_SIZE) as usize);
2855 assert(paddr % PAGE_SIZE == 0);
2856 assert(frame_to_index(paddr) == idx);
2857 if range.start <= paddr < range.end {
2858 assert(entry.range == range);
2859 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
2860 assert(handle_count(s.frames, idx) == 0);
2863 } else {
2864 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2865 assert(!(entry.range.start <= paddr < entry.range.end));
2866 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
2867 }
2868 };
2869 assert forall|idx: usize|
2871 idx
2872 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
2873 == 0 by {
2874 let paddr = index_to_frame(idx);
2875 assert(paddr == (idx * PAGE_SIZE) as usize);
2876 assert(paddr % PAGE_SIZE == 0);
2877 assert(frame_to_index(paddr) == idx);
2878 if range.start <= paddr < range.end {
2879 } else {
2881 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2883 }
2884 };
2885 assert forall|fid_other: FrameId| #[trigger]
2890 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
2891 s.frames[fid_other].paddr,
2892 )].usage == PageUsage::Frame by {
2893 let other_idx = frame_to_index(s.frames[fid_other].paddr);
2894 let other_paddr = index_to_frame(other_idx);
2895 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
2897 assert(old_frames.dom().filter(
2899 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
2900 ).contains(fid_other));
2901 assert(handle_count(old_frames, other_idx) >= 1);
2902 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value()
2903 != REF_COUNT_UNUSED);
2904 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
2908 };
2909 },
2910 Option::None => {
2911 assert(s.regions =~= old_regions);
2912 assert(s.segments =~= old_segments);
2913 },
2914 }
2915}
2916
2917proof fn step_segment_drop<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
2921 requires
2922 old(s).inv(),
2923 old(s).segments.dom().contains(sid),
2924 ensures
2925 final(s).inv(),
2926{
2927 let ghost old_regions = s.regions;
2928 let ghost old_frames = s.frames;
2929 let ghost old_segments = s.segments;
2930 let ghost range = s.segments[sid].range;
2931 assert forall|paddr: Paddr|
2934 #![trigger frame_to_index(paddr)]
2935 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) implies {
2936 let so = old_regions.slot_owners[frame_to_index(paddr)];
2937 &&& so.inner_perms.ref_count.value() >= 1
2938 &&& so.inner_perms.ref_count.value() <= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX
2939 &&& so.usage == PageUsage::Frame
2940 &&& so.inner_perms.ref_count.value() == 1 ==> so.paths_in_pt.is_empty()
2941 } by {
2942 let idx = frame_to_index(paddr);
2943 lemma_segment_cover_contains(old_segments, sid, paddr);
2945 assert(old_regions.slot_owners[idx].usage == PageUsage::Frame);
2947 let so = old_regions.slot_owners[idx];
2950 let rc = so.inner_perms.ref_count.value();
2951 assert(rc != REF_COUNT_UNUSED);
2952 assert(rc != REF_COUNT_UNIQUE);
2953 assert(rc == handle_count(old_frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2954 old_segments,
2955 paddr,
2956 ));
2957 assert(rc >= 1);
2959 assert(old_regions.slot_owners.contains_key(idx));
2962 assert(old_regions.slot_owners[idx].inv());
2963 assert(rc <= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX);
2964 if rc == 1 {
2967 assert(handle_count(old_frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2968 old_segments,
2969 paddr,
2970 ) == 1);
2971 assert(so.paths_in_pt.len() == 0);
2972 assert(so.paths_in_pt =~= Set::empty());
2973 }
2974 };
2975 let tracked entry = s.extract_segment(sid);
2976 segment::drop_step(&mut s.regions, entry);
2977
2978 assert forall|idx: usize|
2995 idx
2996 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
2997 == 0 by {
2998 let paddr = index_to_frame(idx);
2999 assert(paddr == (idx * PAGE_SIZE) as usize);
3000 assert(paddr % PAGE_SIZE == 0);
3001 assert(frame_to_index(paddr) == idx);
3002 if range.start <= paddr < range.end {
3003 } else {
3005 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3006 }
3007 };
3008 assert forall|idx: usize|
3010 #![trigger s.regions.slot_owners[idx]]
3011 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3012 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3013 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3014 s.segments,
3015 index_to_frame(idx),
3016 ) == 0 by {
3017 let paddr = index_to_frame(idx);
3018 assert(paddr == (idx * PAGE_SIZE) as usize);
3019 assert(paddr % PAGE_SIZE == 0);
3020 assert(frame_to_index(paddr) == idx);
3021 if range.start <= paddr < range.end {
3022 lemma_segment_cover_contains(old_segments, sid, paddr);
3029 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3030 assert(old_regions.slot_owners[idx].inner_perms.ref_count.value() == 1);
3031 assert(handle_count(old_frames, idx) == 0);
3032 assert(s.regions.slot_owners[idx].paths_in_pt =~= Set::empty());
3033 } else {
3034 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3036 assert(!(entry.range.start <= paddr < entry.range.end));
3037 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3038 }
3039 };
3040 assert forall|idx: usize|
3041 #![trigger s.regions.slot_owners[idx]]
3042 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
3043 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3044 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3045 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3046 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3047 s.segments,
3048 index_to_frame(idx),
3049 ) > 0 by {
3050 let paddr = index_to_frame(idx);
3051 assert(paddr == (idx * PAGE_SIZE) as usize);
3052 assert(paddr % PAGE_SIZE == 0);
3053 assert(frame_to_index(paddr) == idx);
3054 if range.start <= paddr < range.end {
3055 lemma_segment_cover_contains(old_segments, sid, paddr);
3060 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3061 } else {
3062 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3063 assert(!(entry.range.start <= paddr < entry.range.end));
3064 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3065 }
3066 };
3067 assert forall|idx: usize|
3068 #![trigger s.regions.slot_owners[idx]]
3069 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
3070 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
3071 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
3072 let so = s.regions.slot_owners[idx];
3073 let rc = so.inner_perms.ref_count.value();
3074 &&& rc != REF_COUNT_UNUSED
3075 &&& rc != REF_COUNT_UNIQUE
3076 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3077 s.segments,
3078 index_to_frame(idx),
3079 )
3080 &&& so.inner_perms.storage.is_init()
3081 } by {
3082 let paddr = index_to_frame(idx);
3083 assert(paddr == (idx * PAGE_SIZE) as usize);
3084 assert(paddr % PAGE_SIZE == 0);
3085 assert(frame_to_index(paddr) == idx);
3086 if range.start <= paddr < range.end {
3087 lemma_segment_cover_contains(old_segments, sid, paddr);
3088 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
3089 let pre_rc = old_regions.slot_owners[idx].inner_perms.ref_count.value();
3091 let pre_H = handle_count(old_frames, idx);
3092 let pre_P = old_regions.slot_owners[idx].paths_in_pt.len();
3093 let pre_cover = segment_cover_count(old_segments, paddr);
3094 assert(pre_rc == pre_H + pre_P + pre_cover);
3095 assert(pre_rc != REF_COUNT_UNIQUE);
3096 let post_rc = s.regions.slot_owners[idx].inner_perms.ref_count.value();
3097 assert(post_rc != REF_COUNT_UNUSED);
3098 assert(pre_rc > 1) by {
3099 if pre_rc == 1 {
3100 assert(post_rc == REF_COUNT_UNUSED);
3101 }
3102 };
3103 assert(post_rc == (pre_rc - 1) as u64);
3104 assert(s.regions.slot_owners[idx].paths_in_pt
3105 == old_regions.slot_owners[idx].paths_in_pt);
3106 assert(handle_count(s.frames, idx) == pre_H);
3107 assert(segment_cover_count(s.segments, paddr) == (pre_cover - 1) as nat);
3108 assert(post_rc <= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX);
3110 assert(s.regions.slot_owners.contains_key(idx));
3113 assert(s.regions.slot_owners[idx].inv());
3114 assert(post_rc >= 1);
3115 assert(s.regions.slot_owners[idx].inner_perms.storage.is_init());
3116 } else {
3117 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3118 assert(!(entry.range.start <= paddr < entry.range.end));
3119 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
3120 }
3121 };
3122 assert forall|fid_other: FrameId| #[trigger]
3127 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3128 s.frames[fid_other].paddr,
3129 )].usage == PageUsage::Frame by {
3130 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3131 let other_paddr = index_to_frame(other_idx);
3132 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
3134 assert(old_frames.dom().filter(
3136 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
3137 ).contains(fid_other));
3138 assert(handle_count(old_frames, other_idx) >= 1);
3139 assert(old_regions.slot_owners[other_idx].inner_perms.ref_count.value() >= 1);
3141 if range.start <= other_paddr < range.end {
3143 } else {
3145 assert(s.regions.slot_owners[other_idx] == old_regions.slot_owners[other_idx]);
3147 }
3148 };
3149 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3153 #![trigger
3154 s.segments.dom().contains(sid_other),
3155 frame_to_index(paddr_c)]
3156 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3157 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3158 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
3159 == PageUsage::Frame by {
3160 let cov_idx = frame_to_index(paddr_c);
3161 assert(sid_other != sid);
3163 assert(old_segments.dom().contains(sid_other));
3165 assert(old_segments[sid_other] == s.segments[sid_other]);
3166 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
3168 };
3170}
3171
3172proof fn step_segment_split<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId, offset: usize)
3177 requires
3178 old(s).inv(),
3179 old(s).segments.dom().contains(sid),
3180 offset % PAGE_SIZE == 0,
3181 0 < offset,
3182 offset < (old(s).segments[sid].range.end - old(s).segments[sid].range.start),
3183 ensures
3184 final(s).inv(),
3185{
3186 let ghost old_regions = s.regions;
3187 let ghost old_frames = s.frames;
3188 let ghost old_segments = s.segments;
3189 let ghost range = s.segments[sid].range;
3190 let ghost mid = (range.start + offset) as Paddr;
3191 let ghost entry_left = SegmentEntry { range: range.start..mid };
3192 let ghost entry_right = SegmentEntry { range: mid..range.end };
3193 let ghost id_left = fresh_segment_id(s.segments);
3199 axiom_fresh_segment_id_not_in_dom(s.segments);
3200 assert(id_left != sid);
3201 let ghost stub_entry = SegmentEntry { range: range.start..mid };
3202 let ghost id_right = fresh_segment_id(s.segments.insert(id_left, stub_entry));
3203 axiom_fresh_segment_id_not_in_dom(s.segments.insert(id_left, stub_entry));
3204 assert(id_right != sid);
3205 assert(id_right != id_left);
3206 let tracked _orig = s.extract_segment(sid);
3208 assert(!s.segments.dom().contains(id_left));
3209 let tracked entry_l = axiom_segment_entry_new(range.start..mid);
3210 s.insert_segment(id_left, entry_l);
3211 assert(!s.segments.dom().contains(id_right));
3212 let tracked entry_r = axiom_segment_entry_new(mid..range.end);
3213 s.insert_segment(id_right, entry_r);
3214 assert(s.regions == old_regions);
3219 assert forall|paddr: Paddr| #[trigger]
3220 frame_to_index(paddr) < max_meta_slots() implies segment_cover_count(s.segments, paddr)
3221 == segment_cover_count(old_segments, paddr) by {
3222 lemma_segment_cover_split(
3223 old_segments,
3224 sid,
3225 id_left,
3226 id_right,
3227 entry_left,
3228 entry_right,
3229 paddr,
3230 );
3231 };
3232 assert(entry_left.range.start % PAGE_SIZE == 0);
3239 assert(entry_right.range.start % PAGE_SIZE == 0);
3240 assert(entry_left.range.end % PAGE_SIZE == 0);
3241 assert(entry_right.range.end % PAGE_SIZE == 0);
3242 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3246 #![trigger
3247 s.segments.dom().contains(sid_other),
3248 frame_to_index(paddr_c)]
3249 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3250 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3251 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
3252 == PageUsage::Frame by {
3253 if sid_other == id_left {
3254 assert(old_segments.dom().contains(sid));
3255 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
3256 } else if sid_other == id_right {
3257 assert(old_segments.dom().contains(sid));
3258 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
3259 } else {
3260 assert(old_segments.dom().contains(sid_other));
3261 assert(old_segments[sid_other] == s.segments[sid_other]);
3262 }
3263 };
3264 assert forall|idx: usize|
3269 #![trigger s.regions.slot_owners[idx]]
3270 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3271 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3272 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3273 s.segments,
3274 index_to_frame(idx),
3275 ) == 0 by {
3276 let paddr = index_to_frame(idx);
3277 assert(paddr == (idx * PAGE_SIZE) as usize);
3278 assert(frame_to_index(paddr) == idx);
3279 lemma_segment_cover_split(
3280 old_segments,
3281 sid,
3282 id_left,
3283 id_right,
3284 entry_left,
3285 entry_right,
3286 paddr,
3287 );
3288 };
3289 assert forall|idx: usize|
3290 #![trigger s.regions.slot_owners[idx]]
3291 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
3292 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3293 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3294 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3295 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3296 s.segments,
3297 index_to_frame(idx),
3298 ) > 0 by {
3299 let paddr = index_to_frame(idx);
3300 assert(paddr == (idx * PAGE_SIZE) as usize);
3301 assert(frame_to_index(paddr) == idx);
3302 lemma_segment_cover_split(
3303 old_segments,
3304 sid,
3305 id_left,
3306 id_right,
3307 entry_left,
3308 entry_right,
3309 paddr,
3310 );
3311 };
3312 assert forall|idx: usize|
3313 #![trigger s.regions.slot_owners[idx]]
3314 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
3315 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
3316 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
3317 let so = s.regions.slot_owners[idx];
3318 let rc = so.inner_perms.ref_count.value();
3319 &&& rc != REF_COUNT_UNUSED
3320 &&& rc != REF_COUNT_UNIQUE
3321 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3322 s.segments,
3323 index_to_frame(idx),
3324 )
3325 &&& so.inner_perms.storage.is_init()
3326 } by {
3327 let paddr = index_to_frame(idx);
3328 assert(paddr == (idx * PAGE_SIZE) as usize);
3329 assert(frame_to_index(paddr) == idx);
3330 lemma_segment_cover_split(
3331 old_segments,
3332 sid,
3333 id_left,
3334 id_right,
3335 entry_left,
3336 entry_right,
3337 paddr,
3338 );
3339 };
3340}
3341
3342proof fn step_segment_next<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
3369 requires
3370 old(s).inv(),
3371 old(s).segments.dom().contains(sid),
3372 ensures
3373 final(s).inv(),
3374{
3375 let ghost old_regions = s.regions;
3376 let ghost old_frames = s.frames;
3377 let ghost old_segments = s.segments;
3378 let ghost range = s.segments[sid].range;
3379 let ghost paddr = range.start;
3380 let ghost target_idx = frame_to_index(paddr);
3381 let ghost new_range_start = (paddr + PAGE_SIZE) as Paddr;
3382 let ghost new_range_end = range.end;
3383 let ghost will_become_empty = new_range_start >= new_range_end;
3384 let ghost new_entry_ghost = SegmentEntry { range: new_range_start..new_range_end };
3385
3386 lemma_segment_cover_contains(old_segments, sid, paddr);
3388 assert(segment_cover_count(old_segments, paddr) >= 1);
3389 assert(old_regions.slot_owners[target_idx].usage == PageUsage::Frame);
3390 let ghost so_pre = old_regions.slot_owners[target_idx];
3391 let ghost pre_rc = so_pre.inner_perms.ref_count.value();
3392 let ghost pre_H = handle_count(old_frames, target_idx);
3393 let ghost pre_P = so_pre.paths_in_pt.len();
3394 let ghost pre_cover = segment_cover_count(old_segments, paddr);
3395 assert(pre_rc == pre_H + pre_P + pre_cover);
3396 assert(pre_rc != REF_COUNT_UNUSED);
3397 assert(pre_rc != REF_COUNT_UNIQUE);
3398 assert(pre_rc >= 1);
3399 assert(old_regions.slot_owners.contains_key(target_idx));
3400 assert(old_regions.slot_owners[target_idx].inv());
3401 assert(pre_rc <= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX);
3402 assert(has_safe_slot(paddr));
3403 s.regions.inv_implies_correct_addr(paddr);
3404 assert(s.regions.slots.contains_key(target_idx));
3405 assert(range.start % PAGE_SIZE == 0);
3407 assert(range.end <= MAX_PADDR);
3408 assert(range.start + PAGE_SIZE <= MAX_PADDR);
3409
3410 let ghost fid = fresh_frame_id(s.frames);
3412 axiom_fresh_frame_id_not_in_dom(s.frames);
3413 let tracked frame_entry = axiom_frame_entry_new(paddr);
3414 s.insert_frame(fid, frame_entry);
3415 let tracked _old_entry = s.extract_segment(sid);
3417 segment::segment_next_embedded(&mut s.regions, paddr);
3418 if !will_become_empty {
3419 let tracked new_entry = axiom_segment_entry_new(new_range_start..new_range_end);
3420 s.insert_segment(sid, new_entry);
3421 assert(new_entry =~= new_entry_ghost);
3422 assert(s.segments =~= old_segments.remove(sid).insert(sid, new_entry_ghost));
3423 } else {
3424 assert(s.segments =~= old_segments.remove(sid));
3425 }
3426 assert(s.frames == old_frames.insert(fid, frame_entry));
3427
3428 assert forall|paddr_c: Paddr| paddr_c % PAGE_SIZE == 0 implies #[trigger] segment_cover_count(
3431 s.segments,
3432 paddr_c,
3433 ) == (if paddr_c == paddr {
3434 1nat
3435 } else {
3436 0nat
3437 }) + 0nat
3438 || true by {
3442 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3443 };
3444 assert forall|paddr_c: Paddr|
3446 paddr_c % PAGE_SIZE == 0 && paddr_c == paddr implies #[trigger] segment_cover_count(
3447 s.segments,
3448 paddr_c,
3449 ) + 1 == segment_cover_count(old_segments, paddr_c) by {
3450 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3451 };
3452 assert forall|paddr_c: Paddr|
3453 paddr_c % PAGE_SIZE == 0 && paddr_c != paddr implies #[trigger] segment_cover_count(
3454 s.segments,
3455 paddr_c,
3456 ) == segment_cover_count(old_segments, paddr_c) by {
3457 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
3458 };
3459
3460 assert forall|idx: usize|
3462 idx
3463 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].inner_perms.in_list.value()
3464 == 0 by {
3465 let paddr_c = index_to_frame(idx);
3466 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3467 if idx == target_idx {
3468 } else {
3470 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3471 }
3472 };
3473 assert forall|fid_other: FrameId| #[trigger]
3477 s.frames.dom().contains(fid_other) implies s.regions.slot_owners[frame_to_index(
3478 s.frames[fid_other].paddr,
3479 )].usage == PageUsage::Frame by {
3480 let other_idx = frame_to_index(s.frames[fid_other].paddr);
3481 if fid_other == fid {
3482 assert(s.frames[fid_other].paddr == paddr);
3483 assert(other_idx == target_idx);
3484 } else {
3485 assert(old_frames.dom().contains(fid_other));
3486 assert(s.frames[fid_other] == old_frames[fid_other]);
3487 assert(old_regions.slot_owners[other_idx].usage == PageUsage::Frame);
3488 }
3489 };
3490 assert forall|sid_other: SegmentId, paddr_c: Paddr|
3492 #![trigger
3493 s.segments.dom().contains(sid_other),
3494 frame_to_index(paddr_c)]
3495 s.segments.dom().contains(sid_other) && s.segments[sid_other].range.start <= paddr_c
3496 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
3497 == 0 implies s.regions.slot_owners[frame_to_index(paddr_c)].usage
3498 == PageUsage::Frame by {
3499 let cov_idx = frame_to_index(paddr_c);
3500 if !will_become_empty && sid_other == sid {
3501 assert(old_segments.dom().contains(sid));
3503 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
3504 } else {
3505 assert(sid_other != sid);
3506 assert(old_segments.dom().contains(sid_other));
3507 assert(old_segments[sid_other] == s.segments[sid_other]);
3508 assert(old_regions.slot_owners[cov_idx].usage == PageUsage::Frame);
3509 }
3510 };
3511 if !will_become_empty {
3513 assert(new_range_start % PAGE_SIZE == 0);
3514 assert(new_range_end % PAGE_SIZE == 0);
3515 assert(new_range_end <= MAX_PADDR);
3516 }
3517 assert forall|idx: usize|
3520 #![trigger s.regions.slot_owners[idx]]
3521 idx < max_meta_slots() && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3522 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
3523 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
3524 s.segments,
3525 index_to_frame(idx),
3526 ) == 0 by {
3527 let paddr_c = index_to_frame(idx);
3528 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3529 assert(frame_to_index(paddr_c) == idx);
3530 if idx == target_idx {
3531 assert(false);
3533 } else {
3534 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3535 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3536 }
3537 };
3538 assert forall|idx: usize|
3539 #![trigger s.regions.slot_owners[idx]]
3540 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame
3541 && s.regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
3542 && s.regions.slot_owners[idx].inner_perms.ref_count.value()
3543 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
3544 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
3545 s.segments,
3546 index_to_frame(idx),
3547 ) > 0 by {
3548 let paddr_c = index_to_frame(idx);
3549 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3550 if idx == target_idx {
3551 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3553 assert(handle_count(s.frames, target_idx) >= 1);
3554 } else {
3555 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3556 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3557 }
3558 };
3559 assert forall|idx: usize|
3560 #![trigger s.regions.slot_owners[idx]]
3561 idx < max_meta_slots() && s.regions.slot_owners[idx].usage == PageUsage::Frame && (
3562 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
3563 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
3564 let so = s.regions.slot_owners[idx];
3565 let rc = so.inner_perms.ref_count.value();
3566 &&& rc != REF_COUNT_UNUSED
3567 &&& rc != REF_COUNT_UNIQUE
3568 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
3569 s.segments,
3570 index_to_frame(idx),
3571 )
3572 &&& so.inner_perms.storage.is_init()
3573 } by {
3574 let paddr_c = index_to_frame(idx);
3575 assert(paddr_c == (idx * PAGE_SIZE) as usize);
3576 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
3577 if idx == target_idx {
3578 } else {
3584 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
3585 }
3586 };
3587}
3588
3589pub proof fn lemma_segment_cover_insert_inside(
3592 segments: Map<SegmentId, SegmentEntry>,
3593 sid: SegmentId,
3594 entry: SegmentEntry,
3595 paddr: Paddr,
3596)
3597 requires
3598 !segments.dom().contains(sid),
3599 segments.dom().finite(),
3600 entry.range.start <= paddr < entry.range.end,
3601 ensures
3602 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
3603 segments,
3604 paddr,
3605 ) + 1,
3606{
3607 let segments2 = segments.insert(sid, entry);
3608 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
3609 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
3610 let old_filt = segments.dom().filter(pred);
3611 let new_filt = segments2.dom().filter(pred2);
3612 assert(segments2.dom() =~= segments.dom().insert(sid));
3613 assert(!old_filt.contains(sid));
3614 assert(new_filt =~= old_filt.insert(sid)) by {
3615 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.insert(
3616 sid,
3617 ).contains(s) by {
3618 if s == sid {
3619 } else {
3620 assert(segments2[s] == segments[s]);
3621 }
3622 };
3623 assert forall|s: SegmentId| #[trigger]
3624 old_filt.insert(sid).contains(s) implies new_filt.contains(s) by {
3625 if s == sid {
3626 assert(segments2[s].range == entry.range);
3627 } else {
3628 assert(segments2[s] == segments[s]);
3629 }
3630 };
3631 };
3632 assert(old_filt.finite());
3633 assert(new_filt.len() == old_filt.len() + 1);
3634}
3635
3636pub proof fn lemma_segment_cover_insert_outside(
3639 segments: Map<SegmentId, SegmentEntry>,
3640 sid: SegmentId,
3641 entry: SegmentEntry,
3642 paddr: Paddr,
3643)
3644 requires
3645 !segments.dom().contains(sid),
3646 segments.dom().finite(),
3647 !(entry.range.start <= paddr < entry.range.end),
3648 ensures
3649 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
3650 segments,
3651 paddr,
3652 ),
3653{
3654 let segments2 = segments.insert(sid, entry);
3655 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
3656 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
3657 let old_filt = segments.dom().filter(pred);
3658 let new_filt = segments2.dom().filter(pred2);
3659 assert(segments2.dom() =~= segments.dom().insert(sid));
3660 assert(new_filt =~= old_filt) by {
3661 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.contains(
3662 s,
3663 ) by {
3664 if s == sid {
3665 assert(false);
3667 } else {
3668 assert(segments2[s] == segments[s]);
3669 }
3670 };
3671 assert forall|s: SegmentId| #[trigger] old_filt.contains(s) implies new_filt.contains(
3672 s,
3673 ) by {
3674 assert(s != sid);
3675 assert(segments2[s] == segments[s]);
3676 };
3677 };
3678}
3679
3680pub proof fn lemma_segment_cover_contains(
3683 segments: Map<SegmentId, SegmentEntry>,
3684 sid: SegmentId,
3685 paddr: Paddr,
3686)
3687 requires
3688 segments.dom().contains(sid),
3689 segments.dom().finite(),
3690 segments[sid].range.start <= paddr < segments[sid].range.end,
3691 ensures
3692 segment_cover_count(segments, paddr) >= 1,
3693{
3694 let filt = segments.dom().filter(
3695 |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end,
3696 );
3697 assert(filt.contains(sid));
3698 assert(filt.finite());
3699}
3700
3701pub proof fn lemma_segment_cover_remove_inside(
3704 segments: Map<SegmentId, SegmentEntry>,
3705 sid: SegmentId,
3706 paddr: Paddr,
3707)
3708 requires
3709 segments.dom().contains(sid),
3710 segments.dom().finite(),
3711 segments[sid].range.start <= paddr < segments[sid].range.end,
3712 ensures
3713 segment_cover_count(segments.remove(sid), paddr) == (segment_cover_count(segments, paddr)
3714 - 1) as nat,
3715{
3716 let segments2 = segments.remove(sid);
3717 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
3718 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
3719 let old_filt = segments.dom().filter(pred);
3720 let new_filt = segments2.dom().filter(pred2);
3721 assert(segments2.dom() =~= segments.dom().remove(sid));
3722 assert(old_filt.contains(sid));
3723 assert(new_filt =~= old_filt.remove(sid)) by {
3724 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.remove(
3725 sid,
3726 ).contains(s) by {
3727 assert(s != sid);
3728 assert(segments2[s] == segments[s]);
3729 };
3730 assert forall|s: SegmentId| #[trigger]
3731 old_filt.remove(sid).contains(s) implies new_filt.contains(s) by {
3732 assert(s != sid);
3733 assert(segments2[s] == segments[s]);
3734 };
3735 };
3736 assert(old_filt.finite());
3737}
3738
3739pub proof fn lemma_segment_cover_shrink_front(
3750 segments: Map<SegmentId, SegmentEntry>,
3751 sid: SegmentId,
3752 new_entry: SegmentEntry,
3753 paddr_check: Paddr,
3754)
3755 requires
3756 segments.dom().contains(sid),
3757 segments.dom().finite(),
3758 segments[sid].range.start < segments[sid].range.end,
3761 segments[sid].range.start % PAGE_SIZE == 0,
3763 segments[sid].range.start + PAGE_SIZE <= MAX_PADDR,
3765 new_entry.range.start == (segments[sid].range.start + PAGE_SIZE) as Paddr,
3766 new_entry.range.end == segments[sid].range.end,
3767 new_entry.range.start <= new_entry.range.end,
3768 paddr_check % PAGE_SIZE == 0,
3769 ensures
3770new_entry.range.start < new_entry.range.end ==> ({
3774 let new_segments = segments.remove(sid).insert(sid, new_entry);
3775 paddr_check == segments[sid].range.start ==> segment_cover_count(
3776 new_segments,
3777 paddr_check,
3778 ) + 1 == segment_cover_count(segments, paddr_check)
3779 }),
3780 new_entry.range.start < new_entry.range.end ==> ({
3781 let new_segments = segments.remove(sid).insert(sid, new_entry);
3782 paddr_check != segments[sid].range.start ==> segment_cover_count(
3783 new_segments,
3784 paddr_check,
3785 ) == segment_cover_count(segments, paddr_check)
3786 }),
3787 new_entry.range.start >= new_entry.range.end ==> ({
3789 let new_segments = segments.remove(sid);
3790 paddr_check == segments[sid].range.start ==> segment_cover_count(
3791 new_segments,
3792 paddr_check,
3793 ) + 1 == segment_cover_count(segments, paddr_check)
3794 }),
3795 new_entry.range.start >= new_entry.range.end ==> ({
3796 let new_segments = segments.remove(sid);
3797 paddr_check != segments[sid].range.start ==> segment_cover_count(
3798 new_segments,
3799 paddr_check,
3800 ) == segment_cover_count(segments, paddr_check)
3801 }),
3802{
3803 let popped = segments[sid].range.start;
3804 let range = segments[sid].range;
3805 assert(range.start < range.end);
3808 let sid_pre_covers = range.start <= paddr_check < range.end;
3809 let new_covers = new_entry.range.start <= paddr_check < new_entry.range.end;
3810 if sid_pre_covers {
3812 lemma_segment_cover_remove_inside(segments, sid, paddr_check);
3813 } else {
3814 lemma_segment_cover_remove_outside(segments, sid, paddr_check);
3815 }
3816 if new_entry.range.start < new_entry.range.end {
3817 let new_segments = segments.remove(sid).insert(sid, new_entry);
3818 if paddr_check == popped {
3819 assert(!new_covers);
3822 assert(sid_pre_covers);
3823 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
3824 lemma_segment_cover_contains(segments, sid, paddr_check);
3825 assert(segment_cover_count(new_segments, paddr_check) + 1 == segment_cover_count(
3826 segments,
3827 paddr_check,
3828 ));
3829 } else if sid_pre_covers {
3830 assert(new_covers);
3834 lemma_segment_cover_contains(segments, sid, paddr_check);
3835 lemma_segment_cover_insert_inside(segments.remove(sid), sid, new_entry, paddr_check);
3836 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
3837 segments,
3838 paddr_check,
3839 ));
3840 } else {
3841 assert(!new_covers);
3843 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
3844 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
3845 segments,
3846 paddr_check,
3847 ));
3848 }
3849 } else {
3850 let new_segments = segments.remove(sid);
3852 if paddr_check == popped {
3853 assert(sid_pre_covers);
3854 lemma_segment_cover_contains(segments, sid, paddr_check);
3855 assert(segment_cover_count(new_segments, paddr_check) + 1 == segment_cover_count(
3856 segments,
3857 paddr_check,
3858 ));
3859 } else if sid_pre_covers {
3860 assert(false);
3864 } else {
3865 assert(segment_cover_count(new_segments, paddr_check) == segment_cover_count(
3867 segments,
3868 paddr_check,
3869 ));
3870 }
3871 }
3872}
3873
3874pub proof fn lemma_segment_cover_split(
3880 segments: Map<SegmentId, SegmentEntry>,
3881 sid: SegmentId,
3882 new_left: SegmentId,
3883 new_right: SegmentId,
3884 entry_left: SegmentEntry,
3885 entry_right: SegmentEntry,
3886 paddr: Paddr,
3887)
3888 requires
3889 segments.dom().contains(sid),
3890 segments.dom().finite(),
3891 new_left != sid,
3894 new_right != sid,
3895 new_left != new_right,
3896 !segments.remove(sid).dom().contains(new_left),
3897 !segments.remove(sid).dom().contains(new_right),
3898 entry_left.range.start == segments[sid].range.start,
3900 entry_left.range.end == entry_right.range.start,
3901 entry_right.range.end == segments[sid].range.end,
3902 entry_left.range.start < entry_left.range.end,
3903 entry_right.range.start < entry_right.range.end,
3904 ensures
3905 segment_cover_count(
3906 segments.remove(sid).insert(new_left, entry_left).insert(new_right, entry_right),
3907 paddr,
3908 ) == segment_cover_count(segments, paddr),
3909{
3910 let mid_segments = segments.remove(sid);
3911 let with_left = mid_segments.insert(new_left, entry_left);
3912 assert(mid_segments.dom().finite());
3915 assert(with_left.dom() =~= mid_segments.dom().insert(new_left));
3916 assert(with_left.dom().finite());
3917 assert(!with_left.dom().contains(new_right));
3918 let sid_covers = segments[sid].range.start <= paddr && paddr < segments[sid].range.end;
3919 let left_covers = entry_left.range.start <= paddr && paddr < entry_left.range.end;
3920 let right_covers = entry_right.range.start <= paddr && paddr < entry_right.range.end;
3921 let cover_after_remove = segment_cover_count(mid_segments, paddr);
3923 if sid_covers {
3924 lemma_segment_cover_remove_inside(segments, sid, paddr);
3925 assert(cover_after_remove == (segment_cover_count(segments, paddr) - 1) as nat);
3926 } else {
3927 lemma_segment_cover_remove_outside(segments, sid, paddr);
3928 assert(cover_after_remove == segment_cover_count(segments, paddr));
3929 }
3930 let cover_after_left = segment_cover_count(with_left, paddr);
3932 if left_covers {
3933 lemma_segment_cover_insert_inside(mid_segments, new_left, entry_left, paddr);
3934 assert(cover_after_left == cover_after_remove + 1);
3935 } else {
3936 lemma_segment_cover_insert_outside(mid_segments, new_left, entry_left, paddr);
3937 assert(cover_after_left == cover_after_remove);
3938 }
3939 let final_segments = with_left.insert(new_right, entry_right);
3941 let cover_final = segment_cover_count(final_segments, paddr);
3942 if right_covers {
3943 lemma_segment_cover_insert_inside(with_left, new_right, entry_right, paddr);
3944 assert(cover_final == cover_after_left + 1);
3945 } else {
3946 lemma_segment_cover_insert_outside(with_left, new_right, entry_right, paddr);
3947 assert(cover_final == cover_after_left);
3948 }
3949 let orig = segment_cover_count(segments, paddr);
3951 if sid_covers {
3952 lemma_segment_cover_contains(segments, sid, paddr);
3954 assert(orig >= 1);
3955 assert(cover_after_remove == (orig - 1) as nat);
3956 assert(cover_after_remove + 1 == orig);
3957 if left_covers {
3958 assert(!right_covers);
3959 assert(cover_after_left == cover_after_remove + 1);
3960 assert(cover_final == cover_after_left);
3961 assert(cover_final == orig);
3962 } else {
3963 assert(right_covers);
3964 assert(cover_after_left == cover_after_remove);
3965 assert(cover_final == cover_after_left + 1);
3966 assert(cover_final == cover_after_remove + 1);
3967 assert(cover_final == orig);
3968 }
3969 } else {
3970 assert(!left_covers);
3971 assert(!right_covers);
3972 assert(cover_after_remove == orig);
3973 assert(cover_after_left == cover_after_remove);
3974 assert(cover_final == cover_after_left);
3975 assert(cover_final == orig);
3976 }
3977}
3978
3979pub proof fn lemma_segment_cover_remove_outside(
3982 segments: Map<SegmentId, SegmentEntry>,
3983 sid: SegmentId,
3984 paddr: Paddr,
3985)
3986 requires
3987 segments.dom().contains(sid),
3988 segments.dom().finite(),
3989 !(segments[sid].range.start <= paddr < segments[sid].range.end),
3990 ensures
3991 segment_cover_count(segments.remove(sid), paddr) == segment_cover_count(segments, paddr),
3992{
3993 let segments2 = segments.remove(sid);
3994 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
3995 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
3996 let old_filt = segments.dom().filter(pred);
3997 let new_filt = segments2.dom().filter(pred2);
3998 assert(segments2.dom() =~= segments.dom().remove(sid));
3999 assert(!old_filt.contains(sid));
4000 assert(new_filt =~= old_filt) by {
4001 assert forall|s: SegmentId| #[trigger] new_filt.contains(s) implies old_filt.contains(
4002 s,
4003 ) by {
4004 assert(s != sid);
4005 assert(segments2[s] == segments[s]);
4006 };
4007 assert forall|s: SegmentId| #[trigger] old_filt.contains(s) implies new_filt.contains(
4008 s,
4009 ) by {
4010 assert(s != sid);
4011 assert(segments2[s] == segments[s]);
4012 };
4013 };
4014}
4015
4016pub open spec fn fresh_vm_space_id<'a>(m: Map<VmSpaceId, VmSpaceOwner>) -> VmSpaceId {
4022 choose|id: VmSpaceId| !m.dom().contains(id)
4023}
4024
4025pub open spec fn fresh_cursor_id<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>) -> CursorId {
4027 choose|id: CursorId| !m.dom().contains(id)
4028}
4029
4030pub open spec fn fresh_vm_io_id<'a>(m: Map<VmIoId, VmIoEntry>) -> VmIoId {
4032 choose|id: VmIoId| !m.dom().contains(id)
4033}
4034
4035pub open spec fn fresh_frame_id(m: Map<FrameId, FrameEntry>) -> FrameId {
4037 choose|id: FrameId| !m.dom().contains(id)
4038}
4039
4040pub axiom fn axiom_fresh_vm_space_id_not_in_dom<'a>(m: Map<VmSpaceId, VmSpaceOwner>)
4041 ensures
4042 !m.dom().contains(fresh_vm_space_id(m)),
4043;
4044
4045pub axiom fn axiom_fresh_cursor_id_not_in_dom<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>)
4046 ensures
4047 !m.dom().contains(fresh_cursor_id(m)),
4048;
4049
4050pub axiom fn axiom_fresh_vm_io_id_not_in_dom<'a>(m: Map<VmIoId, VmIoEntry>)
4051 ensures
4052 !m.dom().contains(fresh_vm_io_id(m)),
4053;
4054
4055pub axiom fn axiom_fresh_frame_id_not_in_dom(m: Map<FrameId, FrameEntry>)
4056 ensures
4057 !m.dom().contains(fresh_frame_id(m)),
4058;
4059
4060pub axiom fn axiom_cursor_entry_new<'rcu>(
4062 vm_space: VmSpaceId,
4063 kind: CursorKind,
4064 va: Range<Vaddr>,
4065 tracked owner: CursorOwner<'rcu, UserPtConfig>,
4066 tracked guards: Guards<'rcu>,
4067) -> (tracked res: CursorEntry<'rcu>)
4068 ensures
4069 res.vm_space == vm_space,
4070 res.kind == kind,
4071 res.va == va,
4072 res.owner == owner,
4073 res.guards == guards,
4074;
4075
4076pub axiom fn axiom_vm_io_entry_new<'a>(
4078 vm_space: Option<VmSpaceId>,
4079 kind: VmIoKind,
4080 vaddr: Vaddr,
4081 len: usize,
4082 tracked owner: VmIoOwner,
4083) -> (tracked res: VmIoEntry)
4084 ensures
4085 res.vm_space == vm_space,
4086 res.kind == kind,
4087 res.vaddr == vaddr,
4088 res.len == len,
4089 res.owner == owner,
4090;
4091
4092pub axiom fn axiom_frame_entry_new(paddr: Paddr) -> (tracked res: FrameEntry)
4094 ensures
4095 res.paddr == paddr,
4096;
4097
4098pub axiom fn axiom_segment_entry_new(range: Range<Paddr>) -> (tracked res: SegmentEntry)
4100 ensures
4101 res.range == range,
4102;
4103
4104pub open spec fn fresh_segment_id(m: Map<SegmentId, SegmentEntry>) -> SegmentId {
4106 choose|id: SegmentId| !m.dom().contains(id)
4107}
4108
4109pub axiom fn axiom_fresh_segment_id_not_in_dom(m: Map<SegmentId, SegmentEntry>)
4110 ensures
4111 !m.dom().contains(fresh_segment_id(m)),
4112;
4113
4114}