1pub mod cursor;
32pub mod frame;
33pub mod io;
34pub mod kvirt_store;
35pub mod list_store;
36pub mod segment;
37pub mod trace;
38pub mod unique;
39pub mod vm_space;
40
41use vstd::prelude::*;
42use vstd_extra::{ownership::*, set_extra::*};
43
44use crate::specs::{
45 arch::*,
46 mm::{
47 frame::{
48 mapping::{frame_to_index, index_to_frame, index_to_meta, max_meta_slots},
49 meta_owners::{MetaSlotOwner, PageUsage},
50 meta_region_owners::MetaRegionOwners,
51 },
52 io::VmIoOwner,
53 page_table::{
54 cursor::owners::{CursorContinuation, CursorOwner},
55 node::Guards,
56 },
57 tlb::TlbModel,
58 },
59};
60
61use crate::mm::{
62 MAX_USERSPACE_VADDR, Paddr, Vaddr,
63 frame::{
64 MetaSlot, UFrame,
65 meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
66 },
67 page_prop::PageProperty,
68 vm_space::{UserPtConfig, vm_space_specs::VmSpaceOwner},
69};
70use core::ops::Range;
71
72verus! {
73
74broadcast use crate::specs::mm::frame::mapping::lemma_index_to_frame_biinjective;
75pub type VmSpaceId = int;
81
82pub type CursorId = int;
84
85pub type VmIoId = int;
87
88pub type FrameId = int;
90
91pub type SegmentId = int;
94
95pub type UniqueId = int;
98
99pub tracked struct FrameEntry {
106 pub ghost paddr: Paddr,
107}
108
109pub tracked struct SegmentEntry {
118 pub ghost range: Range<Paddr>,
119}
120
121pub tracked struct UniqueEntry {
123 pub ghost paddr: Paddr,
124}
125
126pub open spec fn segment_cover_count(segments: Map<SegmentId, SegmentEntry>, paddr: Paddr) -> nat {
129 segments.dom().filter(
130 |sid: SegmentId| segments[sid].range.start <= paddr && paddr < segments[sid].range.end,
131 ).len()
132}
133
134pub proof fn lemma_segment_cover_witness(
137 segments: Map<SegmentId, SegmentEntry>,
138 paddr: Paddr,
139) -> (sid: SegmentId)
140 requires
141 segment_cover_count(segments, paddr) > 0,
142 ensures
143 segments.contains_key(sid),
144 segments[sid].range.start <= paddr < segments[sid].range.end,
145{
146 let covering = segments.dom().filter(
147 |sid: SegmentId| segments[sid].range.start <= paddr && paddr < segments[sid].range.end,
148 );
149 let sid = covering.choose();
150 assert(covering.contains(sid));
151 sid
152}
153
154pub open spec fn handle_count(frames: Map<FrameId, FrameEntry>, idx: int) -> nat {
157 frames.dom().filter(|fid: FrameId| frame_to_index(frames[fid].paddr) == idx).len()
158}
159
160pub proof fn lemma_handle_count_insert_fresh(
165 frames: Map<FrameId, FrameEntry>,
166 id: FrameId,
167 entry: FrameEntry,
168 idx: int,
169)
170 requires
171 !frames.contains_key(id),
172 ensures
173 handle_count(frames.insert(id, entry), idx) == handle_count(frames, idx) + (
174 if frame_to_index(entry.paddr) == idx {
175 1nat
176 } else {
177 0nat
178 }),
179{
180 let frames2 = frames.insert(id, entry);
181 let new_filt = frames2.dom().filter(|fid: FrameId| frame_to_index(frames2[fid].paddr) == idx);
182 let old_filt = frames.dom().filter(|fid: FrameId| frame_to_index(frames[fid].paddr) == idx);
183 if frame_to_index(entry.paddr) == idx {
184 assert(new_filt == old_filt.insert(id)) by {};
185 } else {
186 assert(new_filt == old_filt) by {};
187 }
188}
189
190pub proof fn lemma_handle_count_remove(frames: Map<FrameId, FrameEntry>, fid: FrameId, idx: int)
194 requires
195 frames.contains_key(fid),
196 ensures
197 handle_count(frames.remove(fid), idx) == handle_count(frames, idx) - (if frame_to_index(
198 frames[fid].paddr,
199 ) == idx {
200 1nat
201 } else {
202 0nat
203 }),
204{
205 let frames2 = frames.remove(fid);
206 let new_filt = frames2.dom().filter(|gid: FrameId| frame_to_index(frames2[gid].paddr) == idx);
207 let old_filt = frames.dom().filter(|gid: FrameId| frame_to_index(frames[gid].paddr) == idx);
208 if frame_to_index(frames[fid].paddr) == idx {
209 assert(new_filt == old_filt.remove(fid)) by {};
210 } else {
211 assert(new_filt == old_filt) by {};
212 }
213}
214
215pub proof fn lemma_frame_drop_pre_derivable<'rcu>(s: VmStore<'rcu>, fid: FrameId)
216 requires
217 s.inv(),
218 s.frames.contains_key(fid),
219 segment_cover_count(s.segments, s.frames[fid].paddr) == 0,
220 ensures
221 frame::drop_pre(s.regions, s.frames[fid].paddr),
222 s.regions.slot_owner(s.frames[fid].paddr).ref_count() == 1 ==> handle_count(
223 s.frames,
224 frame_to_index(s.frames[fid].paddr),
225 ) == 1,
226{
227 reveal(VmStore::structural_inv);
228 reveal(VmStore::accounting_inv);
229 let paddr = s.frames[fid].paddr;
230 let idx = frame_to_index(paddr);
231 assert(s.regions.ref_count(idx) == s.regions.slot_owners[idx].ref_count_perm.value());
232
233 assert(s.frames.dom().filter(
234 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
235 ).contains(fid));
236}
237
238pub enum VmIoKind {
240 Reader,
241 Writer,
242}
243
244pub tracked struct VmIoEntry {
246 pub ghost vm_space: Option<VmSpaceId>,
247 pub ghost kind: VmIoKind,
248 pub ghost vaddr: Vaddr,
249 pub ghost len: usize,
250 pub owner: VmIoOwner,
251}
252
253impl VmIoEntry {
254 pub open spec fn inv(self) -> bool {
256 &&& self.owner.inv()
257 &&& match self.vm_space {
258 Some(_) => self.owner.mem_view is None,
259 None => match self.kind {
260 VmIoKind::Reader => self.owner.read_view_initialized(),
261 VmIoKind::Writer => self.owner.has_write_view(),
262 },
263 }
264 }
265
266 pub open spec fn is_kernel_reader(self) -> bool {
267 &&& self.vm_space is None
268 &&& self.kind == VmIoKind::Reader
269 }
270
271 pub open spec fn is_kernel_writer(self) -> bool {
272 &&& self.vm_space is None
273 &&& self.kind == VmIoKind::Writer
274 }
275}
276
277pub ghost enum CursorKind {
282 ReadOnly,
283 Mutable,
284}
285
286pub tracked struct CursorEntry<'rcu> {
292 pub ghost vm_space: VmSpaceId,
293 pub ghost kind: CursorKind,
294 pub ghost va: Range<Vaddr>,
295 pub owner: CursorOwner<'rcu, UserPtConfig>,
296 pub guards: Guards,
297}
298
299impl<'rcu> CursorEntry<'rcu> {
300 pub open spec fn inv(self) -> bool {
301 &&& self.owner.inv()
302 &&& self.owner.children_not_locked(self.guards)
303 &&& self.owner.nodes_locked(self.guards)
304 &&& !self.owner.popped_too_high
305 }
306}
307
308pub tracked struct VmStore<'rcu> {
311 pub regions: MetaRegionOwners,
312 pub tlb_model: TlbModel,
313 pub vm_spaces: Map<VmSpaceId, VmSpaceOwner>,
314 pub cursors: Map<CursorId, CursorEntry<'rcu>>,
315 pub vm_ios: Map<VmIoId, VmIoEntry>,
316 pub frames: Map<FrameId, FrameEntry>,
317 pub segments: Map<SegmentId, SegmentEntry>,
318 pub unique_frames: Map<UniqueId, UniqueEntry>,
319}
320
321impl<'a, 'rcu> VmStore<'rcu> {
322 pub open spec fn inv(self) -> bool {
324 self.structural_inv() && self.accounting_inv() && self.regions.inv()
325 }
326
327 #[verifier::opaque]
333 pub open spec fn structural_inv(self) -> bool {
334 &&& forall|idx: int|
335 0 <= idx < max_meta_slots() ==> #[trigger] self.regions.slots.contains_key(idx) || (
336 self.regions.slot_owners[idx].usage is PageTable && self.regions.ref_count(idx)
337 != REF_COUNT_UNUSED)
338 &&& forall|idx: int|
339 0 <= idx < max_meta_slots()
340 ==> #[trigger] self.regions.slot_owners[idx].in_list_perm.value() == 0
341 &&& self.tlb_model.inv()
342 &&& forall|id: VmSpaceId| #[trigger]
343 self.vm_spaces.contains_key(id) ==> self.vm_spaces[id].inv()
344 &&& forall|id: CursorId| #[trigger] self.cursors.contains_key(id) ==> self.cursors[id].inv()
345 &&& forall|id: CursorId| #[trigger]
346 self.cursors.contains_key(id) ==> self.cursors[id].owner.metaregion_sound(self.regions)
347 &&& forall|id: CursorId| #[trigger]
348 self.cursors.contains_key(id) ==> self.vm_spaces.contains_key(self.cursors[id].vm_space)
349 &&& forall|id: VmIoId| #[trigger] self.vm_ios.contains_key(id) ==> self.vm_ios[id].inv()
350 &&& forall|id: VmIoId| #[trigger]
351 self.vm_ios.contains_key(id) ==> (self.vm_ios[id].vm_space matches Some(vs)
352 ==> self.vm_spaces.contains_key(vs))
353 &&& forall|id: VmIoId| #[trigger]
354 self.vm_ios.contains_key(id) ==> self.vm_ios[id].vm_space is Some ==> (
355 self.vm_ios[id].vaddr as nat) + (self.vm_ios[id].len as nat)
356 <= MAX_USERSPACE_VADDR as nat
357 &&& forall|fid: FrameId| #[trigger]
358 self.frames.contains_key(fid) ==> valid_frame_paddr(self.frames[fid].paddr)
359 &&& forall|fid: FrameId| #[trigger]
360 self.frames.contains_key(fid) ==> self.regions.slot_owner(
361 self.frames[fid].paddr,
362 ).usage is Frame
363 &&& forall|sid: SegmentId| #[trigger]
364 self.segments.contains_key(sid) ==> {
365 let r = self.segments[sid].range;
366 &&& r.start % PAGE_SIZE == 0
367 &&& r.end % PAGE_SIZE == 0
368 &&& r.start < r.end
369 &&& r.end <= MAX_PADDR
370 }
371 &&& forall|sid: SegmentId, paddr: Paddr|
372 #![trigger
373 self.segments.contains_key(sid),
374 frame_to_index(paddr)]
375 self.segments.contains_key(sid) && self.segments[sid].range.start <= paddr
376 < self.segments[sid].range.end && paddr % PAGE_SIZE == 0
377 ==> self.regions.slot_owner(paddr).usage is Frame
378 &&& forall|uid: UniqueId| #[trigger]
379 self.unique_frames.contains_key(uid) ==> valid_frame_paddr(
380 self.unique_frames[uid].paddr,
381 )
382 &&& forall|uid: UniqueId| #[trigger]
383 self.unique_frames.contains_key(uid) ==> {
384 let so = self.regions.slot_owner(self.unique_frames[uid].paddr);
385 &&& so.usage is Frame
386 &&& so.ref_count() == REF_COUNT_UNIQUE
387 &&& so.in_list_perm.value() == 0
388 &&& so.paths_in_pt.is_empty()
389 }
390 &&& forall|uid1: UniqueId, uid2: UniqueId|
391 #![trigger
392 self.unique_frames.contains_key(uid1),
393 self.unique_frames.contains_key(uid2)]
394 self.unique_frames.contains_key(uid1) && self.unique_frames.contains_key(uid2)
395 && self.unique_frames[uid1].paddr == self.unique_frames[uid2].paddr ==> uid1 == uid2
396 }
397
398 #[verifier::opaque]
399 pub open spec fn accounting_inv(self) -> bool {
400 &&& forall|idx: int|
401 #![trigger self.regions.slot_owners[idx]]
402 0 <= idx < max_meta_slots() && self.regions.ref_count(idx) == REF_COUNT_UNUSED
403 ==> handle_count(self.frames, idx) == 0
404 && self.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
405 self.segments,
406 index_to_frame(idx),
407 ) == 0
408 &&& forall|idx: int|
409 #![trigger self.regions.slot_owners[idx]]
410 0 <= idx < max_meta_slots() && self.regions.slot_owners[idx].usage is Frame
411 && self.regions.ref_count(idx) != REF_COUNT_UNUSED && self.regions.ref_count(idx)
412 != REF_COUNT_UNIQUE ==> handle_count(self.frames, idx) > 0
413 || self.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
414 self.segments,
415 index_to_frame(idx),
416 ) > 0
417 &&& forall|idx: int|
418 #![trigger self.regions.slot_owners[idx]]
419 0 <= idx < max_meta_slots() && self.regions.slot_owners[idx].usage is Frame && (
420 handle_count(self.frames, idx) > 0 || self.regions.slot_owners[idx].paths_in_pt.len()
421 > 0 || segment_cover_count(self.segments, index_to_frame(idx)) > 0) ==> {
422 let so = self.regions.slot_owners[idx];
423 let rc = so.ref_count();
424 &&& rc != REF_COUNT_UNUSED
425 &&& rc != REF_COUNT_UNIQUE
426 &&& rc == handle_count(self.frames, idx) + so.paths_in_pt.len()
427 + segment_cover_count(self.segments, index_to_frame(idx))
428 }
429 }
430}
431
432pub enum Op {
438 NewVmSpace,
439 DropVmSpace { vs: VmSpaceId },
440 OpenCursor { vs: VmSpaceId, va: Range<Vaddr> },
441 OpenCursorMut { vs: VmSpaceId, va: Range<Vaddr> },
442 DropCursor { c: CursorId },
443 Query { c: CursorId },
444 FindNext { c: CursorId, len: usize },
445 Jump { c: CursorId, va: Vaddr },
446 VirtAddr { c: CursorId },
447 Map { c: CursorId, fid: FrameId, prop: PageProperty },
448 Unmap { c: CursorId, len: usize },
449 ProtectNext { c: CursorId, len: usize },
450 NewReader { vs: VmSpaceId, vaddr: Vaddr, len: usize },
451 NewWriter { vs: VmSpaceId, vaddr: Vaddr, len: usize },
452 NewKernelReader { vaddr: Vaddr, len: usize },
453 NewKernelWriter { vaddr: Vaddr, len: usize },
454 DropReader { vio: VmIoId },
455 DropWriter { vio: VmIoId },
456 ReaderReadVal { source: VmIoId },
458 ReaderCollect { source: VmIoId },
460 ReaderLimit { vio: VmIoId, max: usize },
461 ReaderSkip { vio: VmIoId, n: usize },
462 ReaderQuery { vio: VmIoId },
463 WriterWriteVal { writer: VmIoId },
465 WriterFillZeros { vio: VmIoId, len: usize },
466 WriterLimit { vio: VmIoId, max: usize },
467 WriterSkip { vio: VmIoId, n: usize },
468 WriterQuery { vio: VmIoId },
469 Read { source: VmIoId, dest: VmIoId },
472 Write { source: VmIoId, dest: VmIoId },
474 FrameFromUnused { paddr: Paddr },
477 FrameFromInUse { paddr: Paddr },
480 FrameDrop { fid: FrameId },
482 SegmentFromUnused { range: Range<Paddr> },
485 SegmentDrop { sid: SegmentId },
487 SegmentSplit { sid: SegmentId, offset: usize },
491 SegmentNext { sid: SegmentId },
494 SegmentClone { sid: SegmentId },
497 SegmentSlice { sid: SegmentId, sub_range: Range<Paddr> },
500 UniqueFromUnused { paddr: Paddr },
503 UniqueDrop { uid: UniqueId },
505 FromUnique { uid: UniqueId },
508 TryFromShared { fid: FrameId },
511}
512
513pub open spec fn op_pre<'rcu>(s: VmStore<'rcu>, op: Op) -> bool {
524 match op {
525 Op::NewVmSpace => true,
526 Op::DropVmSpace { vs } => s.vm_spaces.contains_key(vs) && (forall|c: CursorId| #[trigger]
527 s.cursors.contains_key(c) ==> s.cursors[c].vm_space != vs) && (forall|v: VmIoId|
528 #[trigger]
529 s.vm_ios.contains_key(v) ==> s.vm_ios[v].vm_space != Some(vs)),
530 Op::OpenCursor { vs, va: _ } => s.vm_spaces.contains_key(vs),
531 Op::OpenCursorMut { vs, va: _ } => s.vm_spaces.contains_key(vs),
532 Op::DropCursor { c } => s.cursors.contains_key(c),
533 Op::Query { c } => s.cursors.contains_key(c),
534 Op::FindNext { c, len: _ } => s.cursors.contains_key(c),
535 Op::Jump { c, va: _ } => s.cursors.contains_key(c),
536 Op::VirtAddr { c } => s.cursors.contains_key(c),
537 Op::Map { c, fid, prop: _ } => s.cursors.contains_key(c) && s.frames.contains_key(fid),
538 Op::Unmap { c, len: _ } => s.cursors.contains_key(c),
539 Op::ProtectNext { c, len: _ } => s.cursors.contains_key(c),
540 Op::NewReader { vs, vaddr: _, len: _ } => s.vm_spaces.contains_key(vs),
541 Op::NewWriter { vs, vaddr: _, len: _ } => s.vm_spaces.contains_key(vs),
542 Op::NewKernelReader { vaddr: _, len: _ } => true,
543 Op::NewKernelWriter { vaddr: _, len: _ } => true,
544 Op::DropReader { vio } => s.vm_ios.contains_key(vio),
545 Op::DropWriter { vio } => s.vm_ios.contains_key(vio),
546 Op::ReaderReadVal { source } => s.vm_ios.contains_key(source),
547 Op::ReaderCollect { source } => s.vm_ios.contains_key(source),
548 Op::ReaderLimit { vio, max: _ } => s.vm_ios.contains_key(vio),
549 Op::ReaderSkip { vio, n: _ } => s.vm_ios.contains_key(vio),
550 Op::ReaderQuery { vio } => s.vm_ios.contains_key(vio),
551 Op::WriterWriteVal { writer } => s.vm_ios.contains_key(writer),
552 Op::WriterFillZeros { vio, len: _ } => s.vm_ios.contains_key(vio),
553 Op::WriterLimit { vio, max: _ } => s.vm_ios.contains_key(vio),
554 Op::WriterSkip { vio, n: _ } => s.vm_ios.contains_key(vio),
555 Op::WriterQuery { vio } => s.vm_ios.contains_key(vio),
556 Op::Read { source, dest } => s.vm_ios.contains_key(source) && s.vm_ios.contains_key(dest)
557 && source != dest && s.vm_ios[source].is_kernel_reader()
558 && s.vm_ios[dest].is_kernel_writer(),
559 Op::Write { source, dest } => s.vm_ios.contains_key(source) && s.vm_ios.contains_key(dest)
560 && source != dest && s.vm_ios[source].is_kernel_reader()
561 && s.vm_ios[dest].is_kernel_writer(),
562 Op::FrameFromUnused { paddr: _ } => true,
563 Op::FrameFromInUse { paddr: _ } => true,
564 Op::FrameDrop { fid } => s.frames.contains_key(fid) && segment_cover_count(
565 s.segments,
566 s.frames[fid].paddr,
567 ) == 0,
568 Op::SegmentFromUnused { range: _ } => true,
569 Op::SegmentDrop { sid } => s.segments.contains_key(sid),
570 Op::SegmentSplit { sid, offset } => s.segments.contains_key(sid) && offset % PAGE_SIZE == 0
571 && 0 < offset && offset < (s.segments[sid].range.end - s.segments[sid].range.start),
572 Op::SegmentNext { sid } => s.segments.contains_key(sid),
573 Op::SegmentClone { sid } => s.segments.contains_key(sid) && forall|paddr: Paddr|
574 #![trigger frame_to_index(paddr)]
575 (s.segments[sid].range.start <= paddr < s.segments[sid].range.end && paddr % PAGE_SIZE
576 == 0) ==> s.regions.slot_owner(paddr).ref_count() + 1 <= REF_COUNT_MAX,
577 Op::SegmentSlice { sid, sub_range } => s.segments.contains_key(sid) && sub_range.start
578 % PAGE_SIZE == 0 && sub_range.end % PAGE_SIZE == 0 && s.segments[sid].range.start
579 <= sub_range.start && sub_range.start < sub_range.end && sub_range.end
580 <= s.segments[sid].range.end && forall|paddr: Paddr|
581 #![trigger frame_to_index(paddr)]
582 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0)
583 ==> s.regions.slot_owner(paddr).ref_count() + 1 <= REF_COUNT_MAX,
584 Op::UniqueFromUnused { paddr: _ } => true,
585 Op::UniqueDrop { uid } => s.unique_frames.contains_key(uid),
586 Op::FromUnique { uid } => s.unique_frames.contains_key(uid),
587 Op::TryFromShared { fid } => s.frames.contains_key(fid),
588 }
589}
590
591impl<'rcu> VmStore<'rcu> {
596 pub proof fn tracked_extract_vm_space(tracked &mut self, vs: VmSpaceId) -> (tracked res:
601 VmSpaceOwner)
602 requires
603 old(self).inv(),
604 old(self).vm_spaces.contains_key(vs),
605 forall|c: CursorId| #[trigger]
606 old(self).cursors.contains_key(c) ==> old(self).cursors[c].vm_space != vs,
607 forall|v: VmIoId| #[trigger]
608 old(self).vm_ios.contains_key(v) ==> old(self).vm_ios[v].vm_space != Some(vs),
609 ensures
610 final(self).regions == old(self).regions,
611 final(self).tlb_model == old(self).tlb_model,
612 final(self).vm_spaces == old(self).vm_spaces.remove(vs),
613 final(self).cursors == old(self).cursors,
614 final(self).vm_ios == old(self).vm_ios,
615 final(self).frames == old(self).frames,
616 final(self).segments == old(self).segments,
617 final(self).unique_frames == old(self).unique_frames,
618 res == old(self).vm_spaces[vs],
619 final(self).inv(),
620 {
621 reveal(VmStore::structural_inv);
622 reveal(VmStore::accounting_inv);
623 self.vm_spaces.tracked_remove(vs)
624 }
625
626 pub proof fn lemma_insert_vm_space(
629 tracked &mut self,
630 vs: VmSpaceId,
631 tracked owner: VmSpaceOwner,
632 )
633 requires
634 old(self).inv(),
635 !old(self).vm_spaces.contains_key(vs),
636 owner.inv(),
637 ensures
638 final(self).regions == old(self).regions,
639 final(self).tlb_model == old(self).tlb_model,
640 final(self).vm_spaces == old(self).vm_spaces.insert(vs, owner),
641 final(self).cursors == old(self).cursors,
642 final(self).vm_ios == old(self).vm_ios,
643 final(self).frames == old(self).frames,
644 final(self).segments == old(self).segments,
645 final(self).unique_frames == old(self).unique_frames,
646 final(self).inv(),
647 {
648 reveal(VmStore::structural_inv);
649 reveal(VmStore::accounting_inv);
650 self.vm_spaces.tracked_insert(vs, owner);
651 }
652
653 pub proof fn tracked_extract_cursor(tracked &mut self, c: CursorId) -> (tracked res:
655 CursorEntry<'rcu>)
656 requires
657 old(self).inv(),
658 old(self).cursors.contains_key(c),
659 ensures
660 final(self).regions == old(self).regions,
661 final(self).tlb_model == old(self).tlb_model,
662 final(self).vm_spaces == old(self).vm_spaces,
663 final(self).cursors == old(self).cursors.remove(c),
664 final(self).vm_ios == old(self).vm_ios,
665 final(self).frames == old(self).frames,
666 final(self).segments == old(self).segments,
667 final(self).unique_frames == old(self).unique_frames,
668 res == old(self).cursors[c],
669 final(self).inv(),
670 {
671 reveal(VmStore::structural_inv);
672 reveal(VmStore::accounting_inv);
673 self.cursors.tracked_remove(c)
674 }
675
676 pub proof fn lemma_insert_cursor(
681 tracked &mut self,
682 c: CursorId,
683 tracked entry: CursorEntry<'rcu>,
684 )
685 requires
686 old(self).inv(),
687 !old(self).cursors.contains_key(c),
688 entry.inv(),
689 entry.owner.metaregion_sound(old(self).regions),
690 old(self).vm_spaces.contains_key(entry.vm_space),
691 ensures
692 final(self).regions == old(self).regions,
693 final(self).tlb_model == old(self).tlb_model,
694 final(self).vm_spaces == old(self).vm_spaces,
695 final(self).cursors == old(self).cursors.insert(c, entry),
696 final(self).vm_ios == old(self).vm_ios,
697 final(self).frames == old(self).frames,
698 final(self).segments == old(self).segments,
699 final(self).unique_frames == old(self).unique_frames,
700 final(self).inv(),
701 {
702 reveal(VmStore::structural_inv);
703 reveal(VmStore::accounting_inv);
704 self.cursors.tracked_insert(c, entry);
705 }
706
707 pub proof fn tracked_extract_vm_io(tracked &mut self, vio: VmIoId) -> (tracked res: VmIoEntry)
709 requires
710 old(self).inv(),
711 old(self).vm_ios.contains_key(vio),
712 ensures
713 final(self).regions == old(self).regions,
714 final(self).tlb_model == old(self).tlb_model,
715 final(self).vm_spaces == old(self).vm_spaces,
716 final(self).cursors == old(self).cursors,
717 final(self).vm_ios == old(self).vm_ios.remove(vio),
718 final(self).frames == old(self).frames,
719 final(self).segments == old(self).segments,
720 final(self).unique_frames == old(self).unique_frames,
721 res == old(self).vm_ios[vio],
722 final(self).inv(),
723 {
724 reveal(VmStore::structural_inv);
725 reveal(VmStore::accounting_inv);
726 self.vm_ios.tracked_remove(vio)
727 }
728
729 pub proof fn lemma_insert_vm_io(tracked &mut self, vio: VmIoId, tracked entry: VmIoEntry)
731 requires
732 old(self).inv(),
733 !old(self).vm_ios.contains_key(vio),
734 entry.inv(),
735 entry.vm_space matches Some(vs) ==> old(self).vm_spaces.contains_key(vs),
736 entry.vm_space is Some ==> (entry.vaddr as nat) + (entry.len as nat)
737 <= MAX_USERSPACE_VADDR as nat,
738 ensures
739 final(self).regions == old(self).regions,
740 final(self).tlb_model == old(self).tlb_model,
741 final(self).vm_spaces == old(self).vm_spaces,
742 final(self).cursors == old(self).cursors,
743 final(self).vm_ios == old(self).vm_ios.insert(vio, entry),
744 final(self).frames == old(self).frames,
745 final(self).segments == old(self).segments,
746 final(self).unique_frames == old(self).unique_frames,
747 final(self).inv(),
748 {
749 reveal(VmStore::structural_inv);
750 reveal(VmStore::accounting_inv);
751 self.vm_ios.tracked_insert(vio, entry);
752 }
753
754 pub proof fn tracked_extract_frame(tracked &mut self, fid: FrameId) -> (tracked res: FrameEntry)
756 requires
757 old(self).structural_inv(),
758 old(self).frames.contains_key(fid),
759 ensures
760 final(self).regions == old(self).regions,
761 final(self).tlb_model == old(self).tlb_model,
762 final(self).vm_spaces == old(self).vm_spaces,
763 final(self).cursors == old(self).cursors,
764 final(self).vm_ios == old(self).vm_ios,
765 final(self).frames == old(self).frames.remove(fid),
766 final(self).segments == old(self).segments,
767 final(self).unique_frames == old(self).unique_frames,
768 res == old(self).frames[fid],
769 final(self).structural_inv(),
770 {
771 reveal(VmStore::structural_inv);
772 self.frames.tracked_remove(fid)
773 }
774
775 pub proof fn lemma_insert_frame(tracked &mut self, fid: FrameId, tracked entry: FrameEntry)
777 requires
778 old(self).structural_inv(),
779 !old(self).frames.contains_key(fid),
780 valid_frame_paddr(entry.paddr),
781 old(self).regions.slot_owner(entry.paddr).usage is Frame,
782 ensures
783 final(self).regions == old(self).regions,
784 final(self).tlb_model == old(self).tlb_model,
785 final(self).vm_spaces == old(self).vm_spaces,
786 final(self).cursors == old(self).cursors,
787 final(self).vm_ios == old(self).vm_ios,
788 final(self).frames == old(self).frames.insert(fid, entry),
789 final(self).segments == old(self).segments,
790 final(self).unique_frames == old(self).unique_frames,
791 final(self).structural_inv(),
792 {
793 reveal(VmStore::structural_inv);
794 self.frames.tracked_insert(fid, entry);
795 }
796
797 pub proof fn tracked_extract_unique(tracked &mut self, uid: UniqueId) -> (tracked res:
799 UniqueEntry)
800 requires
801 old(self).unique_frames.contains_key(uid),
802 ensures
803 final(self).regions == old(self).regions,
804 final(self).tlb_model == old(self).tlb_model,
805 final(self).vm_spaces == old(self).vm_spaces,
806 final(self).cursors == old(self).cursors,
807 final(self).vm_ios == old(self).vm_ios,
808 final(self).frames == old(self).frames,
809 final(self).segments == old(self).segments,
810 final(self).unique_frames == old(self).unique_frames.remove(uid),
811 res == old(self).unique_frames[uid],
812 {
813 self.unique_frames.tracked_remove(uid)
814 }
815
816 pub proof fn lemma_insert_unique(tracked &mut self, uid: UniqueId, tracked entry: UniqueEntry)
818 requires
819 !old(self).unique_frames.contains_key(uid),
820 ensures
821 final(self).regions == old(self).regions,
822 final(self).tlb_model == old(self).tlb_model,
823 final(self).vm_spaces == old(self).vm_spaces,
824 final(self).cursors == old(self).cursors,
825 final(self).vm_ios == old(self).vm_ios,
826 final(self).frames == old(self).frames,
827 final(self).segments == old(self).segments,
828 final(self).unique_frames == old(self).unique_frames.insert(uid, entry),
829 {
830 self.unique_frames.tracked_insert(uid, entry);
831 }
832
833 pub proof fn tracked_extract_segment(tracked &mut self, sid: SegmentId) -> (tracked res:
835 SegmentEntry)
836 requires
837 old(self).segments.contains_key(sid),
838 ensures
839 final(self).regions == old(self).regions,
840 final(self).tlb_model == old(self).tlb_model,
841 final(self).vm_spaces == old(self).vm_spaces,
842 final(self).cursors == old(self).cursors,
843 final(self).vm_ios == old(self).vm_ios,
844 final(self).frames == old(self).frames,
845 final(self).segments == old(self).segments.remove(sid),
846 final(self).unique_frames == old(self).unique_frames,
847 res == old(self).segments[sid],
848 {
849 self.segments.tracked_remove(sid)
850 }
851
852 pub proof fn lemma_insert_segment(
854 tracked &mut self,
855 sid: SegmentId,
856 tracked entry: SegmentEntry,
857 )
858 requires
859 !old(self).segments.contains_key(sid),
860 ensures
861 final(self).regions == old(self).regions,
862 final(self).tlb_model == old(self).tlb_model,
863 final(self).vm_spaces == old(self).vm_spaces,
864 final(self).cursors == old(self).cursors,
865 final(self).vm_ios == old(self).vm_ios,
866 final(self).frames == old(self).frames,
867 final(self).segments == old(self).segments.insert(sid, entry),
868 final(self).unique_frames == old(self).unique_frames,
869 {
870 self.segments.tracked_insert(sid, entry);
871 }
872}
873
874proof fn lemma_structural_inv_cursor_frame<'rcu>(s: VmStore<'rcu>, c: CursorId, fid: FrameId)
876 requires
877 s.structural_inv(),
878 s.cursors.contains_key(c),
879 s.frames.contains_key(fid),
880 ensures
881 s.tlb_model.inv(),
882 s.cursors[c].inv(),
883 s.cursors[c].owner.metaregion_sound(s.regions),
884 s.vm_spaces.contains_key(s.cursors[c].vm_space),
885 valid_frame_paddr(s.frames[fid].paddr),
886 s.regions.slot_owner(s.frames[fid].paddr).usage is Frame,
887{
888 reveal(VmStore::structural_inv);
889}
890
891proof fn lemma_structural_inv_frame<'rcu>(s: VmStore<'rcu>, fid: FrameId)
892 requires
893 s.structural_inv(),
894 s.frames.contains_key(fid),
895 ensures
896 valid_frame_paddr(s.frames[fid].paddr),
897 s.regions.slot_owner(s.frames[fid].paddr).usage is Frame,
898{
899 reveal(VmStore::structural_inv);
900}
901
902proof fn lemma_structural_inv_segment<'rcu>(s: VmStore<'rcu>, sid: SegmentId, paddr: Paddr)
903 requires
904 s.structural_inv(),
905 s.segments.contains_key(sid),
906 s.segments[sid].range.start <= paddr < s.segments[sid].range.end,
907 paddr % PAGE_SIZE == 0,
908 ensures
909 valid_frame_paddr(paddr),
910 s.regions.slot_owner(paddr).usage is Frame,
911{
912 reveal(VmStore::structural_inv);
913}
914
915proof fn lemma_accounting_inv_at<'rcu>(s: VmStore<'rcu>, idx: int)
916 requires
917 s.accounting_inv(),
918 0 <= idx < max_meta_slots(),
919 ensures
920 s.regions.ref_count(idx) == REF_COUNT_UNUSED ==> handle_count(s.frames, idx) == 0
921 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
922 s.segments,
923 index_to_frame(idx),
924 ) == 0,
925 s.regions.slot_owners[idx].usage is Frame && s.regions.ref_count(idx) != REF_COUNT_UNUSED
926 && s.regions.ref_count(idx) != REF_COUNT_UNIQUE ==> handle_count(s.frames, idx) > 0
927 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
928 s.segments,
929 index_to_frame(idx),
930 ) > 0,
931 s.regions.slot_owners[idx].usage is Frame && (handle_count(s.frames, idx) > 0
932 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
933 s.segments,
934 index_to_frame(idx),
935 ) > 0) ==> {
936 let so = s.regions.slot_owners[idx];
937 let rc = so.ref_count();
938 &&& rc != REF_COUNT_UNUSED
939 &&& rc != REF_COUNT_UNIQUE
940 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
941 s.segments,
942 index_to_frame(idx),
943 )
944 },
945{
946 reveal(VmStore::accounting_inv);
947}
948
949pub proof fn lemma_step<'rcu>(tracked s: &mut VmStore<'rcu>, op: Op)
959 requires
960 old(s).inv(),
961 op_pre(*old(s), op),
962 ensures
963 final(s).inv(),
964{
965 match op {
966 Op::NewVmSpace => lemma_step_new_vm_space(s),
967 Op::DropVmSpace { vs } => lemma_step_drop_vm_space(s, vs),
968 Op::OpenCursor { vs, va } => lemma_step_open_cursor(s, vs, va),
969 Op::OpenCursorMut { vs, va } => lemma_step_open_cursor_mut(s, vs, va),
970 Op::DropCursor { c } => lemma_step_drop_cursor(s, c),
971 Op::Query { c } => lemma_step_query(s, c),
972 Op::FindNext { c, len } => lemma_step_find_next(s, c, len),
973 Op::Jump { c, va } => lemma_step_jump(s, c, va),
974 Op::VirtAddr { c: _ } => {},
975 Op::Map { c, fid, prop } => lemma_step_map(s, c, fid, prop),
976 Op::Unmap { c, len } => lemma_step_unmap(s, c, len),
977 Op::ProtectNext { c, len } => lemma_step_protect_next(s, c, len),
978 Op::NewReader { vs, vaddr, len } => lemma_step_new_vm_io(
979 s,
980 vs,
981 vaddr,
982 len,
983 VmIoKind::Reader,
984 ),
985 Op::NewWriter { vs, vaddr, len } => lemma_step_new_vm_io(
986 s,
987 vs,
988 vaddr,
989 len,
990 VmIoKind::Writer,
991 ),
992 Op::NewKernelReader { vaddr, len } => lemma_step_new_kernel_vm_io(
993 s,
994 vaddr,
995 len,
996 VmIoKind::Reader,
997 ),
998 Op::NewKernelWriter { vaddr, len } => lemma_step_new_kernel_vm_io(
999 s,
1000 vaddr,
1001 len,
1002 VmIoKind::Writer,
1003 ),
1004 Op::DropReader { vio } => lemma_step_drop_vm_io(s, vio),
1005 Op::DropWriter { vio } => lemma_step_drop_vm_io(s, vio),
1006 Op::ReaderReadVal { source: _ } => {},
1008 Op::ReaderCollect { source: _ } => {},
1009 Op::WriterWriteVal { writer: _ } => {},
1010 Op::ReaderLimit { vio, max } => lemma_step_vm_io_method(
1011 s,
1012 vio,
1013 io::VmIoMethod::ReaderLimit(max),
1014 ),
1015 Op::ReaderSkip { vio, n } => lemma_step_vm_io_method(s, vio, io::VmIoMethod::ReaderSkip(n)),
1016 Op::ReaderQuery { vio: _ } => {},
1017 Op::WriterFillZeros { vio, len } => lemma_step_vm_io_method(
1018 s,
1019 vio,
1020 io::VmIoMethod::WriterFillZeros(len),
1021 ),
1022 Op::WriterLimit { vio, max } => lemma_step_vm_io_method(
1023 s,
1024 vio,
1025 io::VmIoMethod::WriterLimit(max),
1026 ),
1027 Op::WriterSkip { vio, n } => lemma_step_vm_io_method(s, vio, io::VmIoMethod::WriterSkip(n)),
1028 Op::WriterQuery { vio: _ } => {},
1029 Op::Read { source, dest } => lemma_step_read(s, source, dest),
1031 Op::Write { source, dest } => lemma_step_write(s, source, dest),
1034 Op::FrameFromUnused { paddr } => lemma_step_frame_from_unused(s, paddr),
1035 Op::FrameFromInUse { paddr } => lemma_step_frame_from_in_use(s, paddr),
1036 Op::FrameDrop { fid } => lemma_step_frame_drop(s, fid),
1037 Op::SegmentFromUnused { range } => lemma_step_segment_from_unused(s, range),
1038 Op::SegmentDrop { sid } => lemma_step_segment_drop(s, sid),
1039 Op::SegmentSplit { sid, offset } => lemma_step_segment_split(s, sid, offset),
1040 Op::SegmentNext { sid } => lemma_step_segment_next(s, sid),
1041 Op::SegmentClone { sid } => lemma_step_segment_clone(s, sid),
1042 Op::SegmentSlice { sid, sub_range } => lemma_step_segment_slice(s, sid, sub_range),
1043 Op::UniqueFromUnused { paddr } => lemma_step_unique_from_unused(s, paddr),
1044 Op::UniqueDrop { uid } => lemma_step_unique_drop(s, uid),
1045 Op::FromUnique { uid } => lemma_step_from_unique(s, uid),
1046 Op::TryFromShared { fid } => lemma_step_try_from_shared(s, fid),
1047 }
1048}
1049
1050proof fn lemma_accounting_preserved_by_pt_alloc<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1051 requires
1052 s_old.inv(),
1053 s_new.frames == s_old.frames,
1054 s_new.segments == s_old.segments,
1056 forall|i: int|
1057 #![trigger s_new.regions.slot_owners[i]]
1058 s_new.regions.slot_owners[i] != s_old.regions.slot_owners[i] ==> {
1059 &&& s_old.regions.ref_count(i) == REF_COUNT_UNUSED
1060 &&& s_new.regions.ref_count(i) != REF_COUNT_UNUSED
1061 &&& s_new.regions.slot_owners[i].usage !is Frame
1062 },
1063 ensures
1064 s_new.accounting_inv(),
1065 forall|fid: FrameId| #[trigger]
1066 s_new.frames.contains_key(fid) ==> s_new.regions.slot_owner(
1067 s_new.frames[fid].paddr,
1068 ).usage is Frame,
1069 forall|sid: SegmentId, paddr: Paddr|
1070 #![trigger
1071 s_new.segments.contains_key(sid),
1072 frame_to_index(paddr)]
1073 s_new.segments.contains_key(sid) && s_new.segments[sid].range.start <= paddr
1074 < s_new.segments[sid].range.end && paddr % PAGE_SIZE == 0
1075 ==> s_new.regions.slot_owner(paddr).usage is Frame,
1076{
1077 reveal(VmStore::structural_inv);
1078 reveal(VmStore::accounting_inv);
1079 assert forall|sid: SegmentId, paddr: Paddr|
1080 #![trigger
1081 s_new.segments.contains_key(sid),
1082 frame_to_index(paddr)]
1083 s_new.segments.contains_key(sid) && s_new.segments[sid].range.start <= paddr
1084 < s_new.segments[sid].range.end && paddr % PAGE_SIZE
1085 == 0 implies s_new.regions.slot_owner(paddr).usage is Frame by {
1086 let idx = frame_to_index(paddr);
1087 lemma_segment_cover_contains(s_old.segments, sid, paddr);
1088 };
1089 assert forall|fid: FrameId| #[trigger]
1090 s_new.frames.contains_key(fid) implies s_new.regions.slot_owner(
1091 s_new.frames[fid].paddr,
1092 ).usage is Frame by {
1093 let idx = frame_to_index(s_new.frames[fid].paddr);
1094 assert(s_old.frames.dom().filter(
1095 |gid: FrameId| frame_to_index(s_old.frames[gid].paddr) == idx,
1096 ).contains(fid));
1097 };
1098}
1099
1100proof fn lemma_coverage_preserved_slots_eq<'rcu>(s_old: VmStore<'rcu>, s_new: VmStore<'rcu>)
1104 requires
1105 s_old.structural_inv(),
1106 s_new.regions.slots == s_old.regions.slots,
1107 forall|idx: int|
1108 #![trigger s_new.regions.slot_owners[idx]]
1109 !s_old.regions.slots.contains_key(idx) ==> s_new.regions.slot_owners[idx]
1110 == s_old.regions.slot_owners[idx],
1111 ensures
1112 forall|idx: int|
1113 0 <= idx < max_meta_slots() ==> #[trigger] s_new.regions.slots.contains_key(idx) || (
1114 s_new.regions.slot_owners[idx].usage is PageTable && s_new.regions.ref_count(idx)
1115 != REF_COUNT_UNUSED),
1116{
1117 reveal(VmStore::structural_inv);
1118}
1119
1120proof fn lemma_step_new_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>)
1121 requires
1122 old(s).inv(),
1123 ensures
1124 final(s).inv(),
1125{
1126 reveal(VmStore::structural_inv);
1127 let ghost s_before = *s;
1128 let tracked owner = vm_space::new_vm_space_step(&mut s.regions);
1129 let ghost id = fresh_vm_space_id(s.vm_spaces);
1130 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1131}
1132
1133proof fn lemma_step_drop_vm_space<'rcu>(tracked s: &mut VmStore<'rcu>, vs: VmSpaceId)
1134 requires
1135 old(s).inv(),
1136 old(s).vm_spaces.contains_key(vs),
1137 forall|c: CursorId| #[trigger]
1138 old(s).cursors.contains_key(c) ==> old(s).cursors[c].vm_space != vs,
1139 forall|v: VmIoId| #[trigger]
1140 old(s).vm_ios.contains_key(v) ==> old(s).vm_ios[v].vm_space != Some(vs),
1141 ensures
1142 final(s).inv(),
1143{
1144 let tracked owner = s.tracked_extract_vm_space(vs);
1145}
1146
1147proof fn lemma_step_open_cursor<'rcu>(
1148 tracked s: &mut VmStore<'rcu>,
1149 vs: VmSpaceId,
1150 va: Range<Vaddr>,
1151)
1152 requires
1153 old(s).inv(),
1154 old(s).vm_spaces.contains_key(vs),
1155 ensures
1156 final(s).inv(),
1157{
1158 reveal(VmStore::structural_inv);
1159 let ghost s_before = *s;
1160 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1161 let tracked res = cursor::open_cursor_step(vm_space_ref, &mut s.regions, vs, va);
1162 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1165 match res {
1166 Option::Some(entry) => {
1167 let ghost id = fresh_cursor_id(s.cursors);
1168 },
1169 Option::None => {},
1170 }
1171}
1172
1173proof fn lemma_step_open_cursor_mut<'rcu>(
1174 tracked s: &mut VmStore<'rcu>,
1175 vs: VmSpaceId,
1176 va: Range<Vaddr>,
1177)
1178 requires
1179 old(s).inv(),
1180 old(s).vm_spaces.contains_key(vs),
1181 ensures
1182 final(s).inv(),
1183{
1184 reveal(VmStore::structural_inv);
1185 let ghost s_before = *s;
1186 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1187 let tracked res = cursor::open_cursor_mut_step(vm_space_ref, &mut s.regions, vs, va);
1188 lemma_accounting_preserved_by_pt_alloc(s_before, *s);
1191 match res {
1192 Option::Some(entry) => {
1193 let ghost id = fresh_cursor_id(s.cursors);
1194 },
1195 Option::None => {},
1196 }
1197}
1198
1199proof fn lemma_step_drop_cursor<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1200 requires
1201 old(s).inv(),
1202 old(s).cursors.contains_key(c),
1203 ensures
1204 final(s).inv(),
1205{
1206 let tracked entry = s.tracked_extract_cursor(c);
1207}
1208
1209proof fn lemma_step_query<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId)
1210 requires
1211 old(s).inv(),
1212 old(s).cursors.contains_key(c),
1213 ensures
1214 final(s).inv(),
1215{
1216 reveal(VmStore::structural_inv);
1217 reveal(VmStore::accounting_inv);
1218 let ghost old_frames = s.frames;
1219 let ghost old_regions = s.regions;
1220 let tracked mut entry = s.tracked_extract_cursor(c);
1221 let ghost res = cursor::cursor_query_step(&mut entry, &mut s.regions);
1222 match res {
1223 Option::None => {},
1224 Option::Some(paddr) => {
1225 let ghost target_idx = frame_to_index(paddr);
1226 let ghost id = fresh_frame_id(s.frames);
1227 lemma_fresh_frame_id_not_in_dom(s.frames);
1228 let tracked frame_entry = tracked_frame_entry_new(paddr);
1229 s.lemma_insert_frame(id, frame_entry);
1230 assert forall|idx: int|
1231 #![trigger s.regions.slot_owners[idx]]
1232 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
1233 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1234 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1235 s.segments,
1236 index_to_frame(idx),
1237 ) == 0 by {
1238 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1239 if idx == target_idx {
1240 assert(false);
1241 }
1242 };
1243 assert forall|idx: int|
1244 #![trigger s.regions.slot_owners[idx]]
1245 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
1246 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
1247 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1248 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1249 s.segments,
1250 index_to_frame(idx),
1251 ) > 0 by {
1252 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1253 };
1254 assert forall|idx: int|
1255 #![trigger s.regions.slot_owners[idx]]
1256 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
1257 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0
1258 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
1259 let so = s.regions.slot_owners[idx];
1260 let rc = so.ref_count();
1261 &&& rc != REF_COUNT_UNUSED
1262 &&& rc != REF_COUNT_UNIQUE
1263 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1264 s.segments,
1265 index_to_frame(idx),
1266 )
1267 } by {
1268 lemma_handle_count_insert_fresh(old_frames, id, frame_entry, idx);
1269 if idx == target_idx {
1270 if old_regions.slot_owners[target_idx].ref_count() == REF_COUNT_UNUSED {
1271 } else if old_regions.slot_owners[target_idx].ref_count() == REF_COUNT_UNIQUE {
1272 assert(false);
1273 } else {
1274 let pre_so = old_regions.slot_owners[target_idx];
1275 let pre_rc = pre_so.ref_count();
1276 let pre_paths = pre_so.paths_in_pt.len();
1277 let pre_H = handle_count(old_frames, target_idx);
1278 let pre_cover = segment_cover_count(s.segments, index_to_frame(target_idx));
1279 if pre_H == 0 && pre_paths == 0 && pre_cover == 0 {
1280 assert(false);
1281 }
1282 }
1283 }
1284 };
1285 },
1286 }
1287}
1288
1289proof fn lemma_step_find_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1290 requires
1291 old(s).inv(),
1292 old(s).cursors.contains_key(c),
1293 ensures
1294 final(s).inv(),
1295{
1296 reveal(VmStore::structural_inv);
1297 reveal(VmStore::accounting_inv);
1298 let tracked mut entry = s.tracked_extract_cursor(c);
1299}
1300
1301proof fn lemma_step_jump<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, va: Vaddr)
1302 requires
1303 old(s).inv(),
1304 old(s).cursors.contains_key(c),
1305 ensures
1306 final(s).inv(),
1307{
1308 reveal(VmStore::structural_inv);
1309 reveal(VmStore::accounting_inv);
1310 let tracked mut entry = s.tracked_extract_cursor(c);
1311}
1312
1313proof fn lemma_step_protect_next<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1314 requires
1315 old(s).inv(),
1316 old(s).cursors.contains_key(c),
1317 ensures
1318 final(s).inv(),
1319{
1320 reveal(VmStore::structural_inv);
1321 reveal(VmStore::accounting_inv);
1322 let tracked mut entry = s.tracked_extract_cursor(c);
1323}
1324
1325#[verifier::spinoff_prover]
1326proof fn lemma_step_map<'rcu>(
1327 tracked s: &mut VmStore<'rcu>,
1328 c: CursorId,
1329 fid: FrameId,
1330 prop: PageProperty,
1331)
1332 requires
1333 old(s).inv(),
1334 old(s).cursors.contains_key(c),
1335 old(s).frames.contains_key(fid),
1336 ensures
1337 final(s).inv(),
1338{
1339 let ghost s_before = *s;
1340 lemma_structural_inv_cursor_frame(*s, c, fid);
1341 let ghost paddr = s.frames[fid].paddr;
1344 let ghost target_idx = frame_to_index(paddr);
1345 let ghost old_frames = s.frames;
1346 let ghost old_regions = s.regions;
1347 s.regions.lemma_contains_valid_frame_paddr(paddr);
1348 assert(old_frames.dom().filter(
1349 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == target_idx,
1350 ).contains(fid));
1351 let ghost pre_rc_target = old_regions.slot_owners[target_idx].ref_count();
1352 lemma_accounting_inv_at(*s, target_idx);
1353 let tracked mut entry = s.tracked_extract_cursor(c);
1354 let tracked _frame_entry = s.tracked_extract_frame(fid);
1355 cursor::map_step(&mut entry, &mut s.regions, &mut s.tlb_model, paddr, prop);
1356 assert forall|idx: int|
1357 #![trigger s.regions.slot_owners[idx]]
1358 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
1359 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1360 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1361 s.segments,
1362 index_to_frame(idx),
1363 ) == 0 by {
1364 lemma_accounting_inv_at(s_before, idx);
1365 lemma_handle_count_remove(old_frames, fid, idx);
1367 if idx == target_idx {
1368 assert(false);
1371 }
1372 };
1373 assert forall|idx: int|
1374 #![trigger s.regions.slot_owners[idx]]
1375 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
1376 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
1377 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1378 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1379 s.segments,
1380 index_to_frame(idx),
1381 ) > 0 by {
1382 lemma_accounting_inv_at(s_before, idx);
1383 lemma_handle_count_remove(old_frames, fid, idx);
1384 };
1385 assert forall|idx: int|
1386 #![trigger s.regions.slot_owners[idx]]
1387 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
1388 s.frames,
1389 idx,
1390 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1391 s.segments,
1392 index_to_frame(idx),
1393 ) > 0) implies {
1394 let so = s.regions.slot_owners[idx];
1395 let rc = so.ref_count();
1396 &&& rc != REF_COUNT_UNUSED
1397 &&& rc != REF_COUNT_UNIQUE
1398 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1399 s.segments,
1400 index_to_frame(idx),
1401 )
1402 } by {
1403 lemma_accounting_inv_at(s_before, idx);
1404 lemma_handle_count_remove(old_frames, fid, idx);
1405 };
1406 assert forall|fid_other: FrameId| #[trigger]
1407 s.frames.contains_key(fid_other) implies s.regions.slot_owner(
1408 s.frames[fid_other].paddr,
1409 ).usage is Frame by {
1410 let other_idx = frame_to_index(s.frames[fid_other].paddr);
1411 lemma_structural_inv_frame(s_before, fid_other);
1412 lemma_accounting_inv_at(s_before, other_idx);
1413 if other_idx == target_idx {
1414 } else {
1415 assert(old_frames.dom().filter(
1416 |gid: FrameId| frame_to_index(old_frames[gid].paddr) == other_idx,
1417 ).contains(fid_other));
1418 }
1419 };
1420 assert forall|sid: SegmentId, paddr_c: Paddr|
1421 #![trigger
1422 s.segments.contains_key(sid),
1423 frame_to_index(paddr_c)]
1424 s.segments.contains_key(sid) && s.segments[sid].range.start <= paddr_c
1425 < s.segments[sid].range.end && paddr_c % PAGE_SIZE == 0 implies s.regions.slot_owner(
1426 paddr_c,
1427 ).usage is Frame by {
1428 let cov_idx = frame_to_index(paddr_c);
1429 lemma_structural_inv_segment(s_before, sid, paddr_c);
1430 lemma_accounting_inv_at(s_before, cov_idx);
1431 lemma_segment_cover_contains(old_regions_segments_helper(s), sid, paddr_c);
1433 };
1434 lemma_accounting_inv_intro(*s);
1435 assert(s.structural_inv()) by {
1436 reveal(VmStore::structural_inv);
1437 };
1438}
1439
1440spec fn old_regions_segments_helper<'rcu>(s: &VmStore<'rcu>) -> Map<SegmentId, SegmentEntry> {
1444 s.segments
1445}
1446
1447proof fn lemma_step_unmap<'rcu>(tracked s: &mut VmStore<'rcu>, c: CursorId, len: usize)
1448 requires
1449 old(s).inv(),
1450 old(s).cursors.contains_key(c),
1451 ensures
1452 final(s).inv(),
1453{
1454 reveal(VmStore::structural_inv);
1455 reveal(VmStore::accounting_inv);
1456 let ghost s_before = *s;
1457 let ghost old_regions = s.regions;
1458 let ghost old_frames = s.frames;
1459 let tracked mut entry = s.tracked_extract_cursor(c);
1460}
1461
1462proof fn lemma_step_new_vm_io<'rcu>(
1463 tracked s: &mut VmStore<'rcu>,
1464 vs: VmSpaceId,
1465 vaddr: Vaddr,
1466 len: usize,
1467 kind: VmIoKind,
1468)
1469 requires
1470 old(s).inv(),
1471 old(s).vm_spaces.contains_key(vs),
1472 ensures
1473 final(s).inv(),
1474{
1475 reveal(VmStore::structural_inv);
1476 let tracked vm_space_ref = s.vm_spaces.tracked_borrow(vs);
1477 let tracked res = io::new_vm_io_step(vm_space_ref, Some(vs), vaddr, len, kind);
1478 match res {
1479 Option::Some(entry) => {
1480 let ghost id = fresh_vm_io_id(s.vm_ios);
1481 },
1482 Option::None => {},
1483 }
1484}
1485
1486proof fn lemma_step_new_kernel_vm_io<'rcu>(
1487 tracked s: &mut VmStore<'rcu>,
1488 vaddr: Vaddr,
1489 len: usize,
1490 kind: VmIoKind,
1491)
1492 requires
1493 old(s).inv(),
1494 ensures
1495 final(s).inv(),
1496{
1497 let tracked entry = io::new_kernel_vm_io_step(vaddr, len, kind);
1498 let ghost id = fresh_vm_io_id(s.vm_ios);
1499}
1500
1501proof fn lemma_step_drop_vm_io<'rcu>(tracked s: &mut VmStore<'rcu>, vio: VmIoId)
1502 requires
1503 old(s).inv(),
1504 old(s).vm_ios.contains_key(vio),
1505 ensures
1506 final(s).inv(),
1507{
1508 let tracked entry = s.tracked_extract_vm_io(vio);
1509}
1510
1511proof fn lemma_step_vm_io_method<'rcu>(
1512 tracked s: &mut VmStore<'rcu>,
1513 vio: VmIoId,
1514 method: io::VmIoMethod,
1515)
1516 requires
1517 old(s).inv(),
1518 old(s).vm_ios.contains_key(vio),
1519 ensures
1520 final(s).inv(),
1521{
1522 reveal(VmStore::structural_inv);
1523 let tracked mut entry = s.tracked_extract_vm_io(vio);
1524}
1525
1526proof fn lemma_step_read<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
1527 requires
1528 old(s).inv(),
1529 old(s).vm_ios.contains_key(source),
1530 old(s).vm_ios.contains_key(dest),
1531 source != dest,
1532 old(s).vm_ios[source].vm_space is None,
1533 old(s).vm_ios[source].kind == VmIoKind::Reader,
1534 old(s).vm_ios[dest].vm_space is None,
1535 old(s).vm_ios[dest].kind == VmIoKind::Writer,
1536 ensures
1537 final(s).inv(),
1538{
1539 reveal(VmStore::structural_inv);
1540 let tracked mut src = s.tracked_extract_vm_io(source);
1541 let tracked mut dst = s.tracked_extract_vm_io(dest);
1542 let tracked val = io::read_step(&mut src, &mut dst);
1543 let ghost id = fresh_vm_io_id(s.vm_ios);
1544}
1545
1546proof fn lemma_step_write<'rcu>(tracked s: &mut VmStore<'rcu>, source: VmIoId, dest: VmIoId)
1547 requires
1548 old(s).inv(),
1549 old(s).vm_ios.contains_key(source),
1550 old(s).vm_ios.contains_key(dest),
1551 source != dest,
1552 old(s).vm_ios[source].vm_space is None,
1553 old(s).vm_ios[source].kind == VmIoKind::Reader,
1554 old(s).vm_ios[dest].vm_space is None,
1555 old(s).vm_ios[dest].kind == VmIoKind::Writer,
1556 ensures
1557 final(s).inv(),
1558{
1559 reveal(VmStore::structural_inv);
1560 let tracked mut src = s.tracked_extract_vm_io(source);
1561 let tracked mut dst = s.tracked_extract_vm_io(dest);
1562}
1563
1564proof fn lemma_step_frame_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
1565 requires
1566 old(s).inv(),
1567 ensures
1568 final(s).inv(),
1569{
1570 reveal(VmStore::structural_inv);
1571 reveal(VmStore::accounting_inv);
1572 let ghost old_frames = s.frames;
1573 let ghost old_regions = s.regions;
1574 if !valid_frame_paddr(paddr) || s.regions.slots.contains_key(frame_to_index(paddr)) {
1575 let tracked res = frame::from_unused_step(&mut s.regions, paddr);
1576 match res {
1577 Option::Some(entry) => {
1578 let ghost id = fresh_frame_id(s.frames);
1579 lemma_fresh_frame_id_not_in_dom(s.frames);
1580 let ghost target_idx = frame_to_index(paddr);
1581 s.lemma_insert_frame(id, entry);
1582
1583 assert forall|idx: int|
1584 #![trigger s.regions.slot_owners[idx]]
1585 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
1586 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1587 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
1588 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
1589 if idx == target_idx {
1590 assert(false);
1591 }
1592 };
1593 assert forall|idx: int|
1594 #![trigger s.regions.slot_owners[idx]]
1595 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
1596 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
1597 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1598 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1599 s.segments,
1600 index_to_frame(idx),
1601 ) > 0 by {
1602 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
1603 };
1604
1605 assert forall|idx: int|
1607 #![trigger s.regions.slot_owners[idx]]
1608 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
1609 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
1610 > 0 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
1611 let so = s.regions.slot_owners[idx];
1612 let rc = so.ref_count();
1613 &&& rc != REF_COUNT_UNUSED
1614 &&& rc != REF_COUNT_UNIQUE
1615 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
1616 + segment_cover_count(s.segments, index_to_frame(idx))
1617 } by {
1618 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
1619 };
1620 },
1621 Option::None => {},
1622 }
1623 }
1624}
1625
1626proof fn lemma_step_frame_from_in_use<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
1627 requires
1628 old(s).inv(),
1629 ensures
1630 final(s).inv(),
1631{
1632 reveal(VmStore::structural_inv);
1633 reveal(VmStore::accounting_inv);
1634 let ghost old_frames = s.frames;
1635 let ghost old_regions = s.regions;
1636 if !valid_frame_paddr(paddr) || s.regions.slots.contains_key(frame_to_index(paddr)) {
1637 let tracked res = frame::from_in_use_step(&mut s.regions, paddr);
1638 match res {
1639 Option::Some(entry) => {
1640 let ghost id = fresh_frame_id(s.frames);
1641 lemma_fresh_frame_id_not_in_dom(s.frames);
1642 let ghost target_idx = frame_to_index(paddr);
1643 s.lemma_insert_frame(id, entry);
1644
1645 assert forall|idx: int|
1646 #![trigger s.regions.slot_owners[idx]]
1647 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
1648 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1649 && s.regions.slot_owners[idx].paths_in_pt.is_empty() by {
1650 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
1651 if idx == target_idx {
1652 assert(false);
1653 }
1654 };
1655
1656 assert forall|idx: int|
1657 #![trigger s.regions.slot_owners[idx]]
1658 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
1659 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
1660 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1661 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1662 s.segments,
1663 index_to_frame(idx),
1664 ) > 0 by {
1665 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
1666 };
1667
1668 assert forall|idx: int|
1669 #![trigger s.regions.slot_owners[idx]]
1670 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (
1671 handle_count(s.frames, idx) > 0 || s.regions.slot_owners[idx].paths_in_pt.len()
1672 > 0 || segment_cover_count(s.segments, index_to_frame(idx)) > 0) implies {
1673 let so = s.regions.slot_owners[idx];
1674 let rc = so.ref_count();
1675 &&& rc != REF_COUNT_UNUSED
1676 &&& rc != REF_COUNT_UNIQUE
1677 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len()
1678 + segment_cover_count(s.segments, index_to_frame(idx))
1679 } by {
1680 lemma_handle_count_insert_fresh(old_frames, id, entry, idx);
1681 };
1682 },
1683 Option::None => {},
1684 }
1685 }
1686}
1687
1688proof fn lemma_step_frame_drop<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
1689 requires
1690 old(s).inv(),
1691 old(s).frames.contains_key(fid),
1692 segment_cover_count(old(s).segments, old(s).frames[fid].paddr) == 0,
1693 ensures
1694 final(s).inv(),
1695{
1696 reveal(VmStore::structural_inv);
1697 reveal(VmStore::accounting_inv);
1698 let ghost p = s.frames[fid].paddr;
1699 s.regions.lemma_contains_valid_frame_paddr(p);
1700 let ghost idx_p = frame_to_index(p);
1701 assert(s.frames.dom().filter(
1702 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx_p,
1703 ).contains(fid));
1704 let ghost target_idx = frame_to_index(p);
1705 let ghost old_frames = s.frames;
1706 let ghost old_regions = s.regions;
1707 let tracked entry = s.tracked_extract_frame(fid);
1708 frame::drop_step(&mut s.regions, entry);
1709 assert forall|idx: int|
1710 #![trigger s.regions.slot_owners[idx]]
1711 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
1712 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
1713 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1714 s.segments,
1715 index_to_frame(idx),
1716 ) == 0 by {
1717 lemma_handle_count_remove(old_frames, fid, idx);
1718 };
1719
1720 assert forall|idx: int|
1721 #![trigger s.regions.slot_owners[idx]]
1722 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
1723 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
1724 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
1725 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1726 s.segments,
1727 index_to_frame(idx),
1728 ) > 0 by {
1729 lemma_handle_count_remove(old_frames, fid, idx);
1730 };
1731
1732 assert forall|idx: int|
1733 #![trigger s.regions.slot_owners[idx]]
1734 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
1735 s.frames,
1736 idx,
1737 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1738 s.segments,
1739 index_to_frame(idx),
1740 ) > 0) implies {
1741 let so = s.regions.slot_owners[idx];
1742 let rc = so.ref_count();
1743 &&& rc != REF_COUNT_UNUSED
1744 &&& rc != REF_COUNT_UNIQUE
1745 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1746 s.segments,
1747 index_to_frame(idx),
1748 )
1749 } by {
1750 lemma_handle_count_remove(old_frames, fid, idx);
1751 if idx == target_idx {
1752 let ghost pre_rc = old_regions.ref_count(idx);
1753 let ghost post_rc = s.regions.ref_count(idx);
1754 if pre_rc > 1 {
1755 } else {
1756 assert(false);
1757 }
1758 }
1759 };
1760}
1761
1762#[verifier::spinoff_prover]
1764proof fn lemma_step_segment_from_unused_accounting<'rcu>(
1765 s_after: VmStore<'rcu>,
1766 old_store: VmStore<'rcu>,
1767 range: Range<Paddr>,
1768 id: SegmentId,
1769 entry: SegmentEntry,
1770)
1771 requires
1772 s_after.regions.inv(),
1773 s_after.frames == old_store.frames,
1774 !old_store.segments.contains_key(id),
1775 s_after.segments == old_store.segments.insert(id, entry),
1776 entry.range == range,
1777 range.start % PAGE_SIZE == 0,
1778 range.end % PAGE_SIZE == 0,
1779 range.start < range.end,
1780 range.end <= MAX_PADDR,
1781 old_store.accounting_inv(),
1782 old_store.regions.inv(),
1783 forall|paddr: Paddr|
1784 #![trigger frame_to_index(paddr)]
1785 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) ==> {
1786 let idx = frame_to_index(paddr);
1787 let so = s_after.regions.slot_owners[idx];
1788 &&& so.usage is Frame
1789 &&& so.ref_count() == 1
1790 &&& so.paths_in_pt.is_empty()
1791 &&& so.storage_perm().is_init()
1792 },
1793 forall|i: int|
1794 #![trigger s_after.regions.slot_owners[i]]
1795 i < max_meta_slots() && !(range.start <= index_to_frame(i) < range.end)
1796 ==> s_after.regions.slot_owners[i] == old_store.regions.slot_owners[i],
1797 forall|paddr: Paddr|
1798 #![trigger frame_to_index(paddr)]
1799 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
1800 ==> old_store.regions.slot_owner(paddr).ref_count() == REF_COUNT_UNUSED,
1801 ensures
1802 s_after.accounting_inv(),
1803{
1804 reveal(VmStore::accounting_inv);
1805 let old_regions = old_store.regions;
1806 let old_frames = old_store.frames;
1807 let old_segments = old_store.segments;
1808 assert forall|idx: int|
1809 #![trigger s_after.regions.slot_owners[idx]]
1810 0 <= idx < max_meta_slots() && s_after.regions.ref_count(idx)
1811 == REF_COUNT_UNUSED implies handle_count(s_after.frames, idx) == 0
1812 && s_after.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1813 s_after.segments,
1814 index_to_frame(idx),
1815 ) == 0 by {
1816 let paddr = index_to_frame(idx);
1817 if range.start <= paddr < range.end {
1818 assert(false);
1819 } else {
1820 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
1821 }
1822 };
1823 assert forall|idx: int|
1824 #![trigger s_after.regions.slot_owners[idx]]
1825 0 <= idx < max_meta_slots() && s_after.regions.slot_owners[idx].usage is Frame
1826 && s_after.regions.ref_count(idx) != REF_COUNT_UNUSED && s_after.regions.ref_count(idx)
1827 != REF_COUNT_UNIQUE implies handle_count(s_after.frames, idx) > 0
1828 || s_after.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1829 s_after.segments,
1830 index_to_frame(idx),
1831 ) > 0 by {
1832 let paddr = index_to_frame(idx);
1833 if range.start <= paddr < range.end {
1834 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
1835 } else {
1836 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
1837 }
1838 };
1839 assert forall|idx: int|
1840 #![trigger s_after.regions.slot_owners[idx]]
1841 0 <= idx < max_meta_slots() && s_after.regions.slot_owners[idx].usage is Frame && (
1842 handle_count(s_after.frames, idx) > 0 || s_after.regions.slot_owners[idx].paths_in_pt.len()
1843 > 0 || segment_cover_count(s_after.segments, index_to_frame(idx)) > 0) implies {
1844 let so = s_after.regions.slot_owners[idx];
1845 let rc = so.ref_count();
1846 &&& rc != REF_COUNT_UNUSED
1847 &&& rc != REF_COUNT_UNIQUE
1848 &&& rc == handle_count(s_after.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
1849 s_after.segments,
1850 index_to_frame(idx),
1851 )
1852 } by {
1853 let paddr = index_to_frame(idx);
1854 if range.start <= paddr < range.end {
1855 lemma_segment_cover_insert_inside(old_segments, id, entry, paddr);
1856 } else {
1857 lemma_segment_cover_insert_outside(old_segments, id, entry, paddr);
1858 }
1859 };
1860}
1861
1862#[verifier::spinoff_prover]
1864proof fn lemma_step_segment_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, range: Range<Paddr>)
1865 requires
1866 old(s).inv(),
1867 ensures
1868 final(s).inv(),
1869{
1870 reveal(VmStore::structural_inv);
1871 if range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0 && range.start < range.end
1872 && range.end <= MAX_PADDR && (forall|paddr: Paddr|
1873 #![trigger frame_to_index(paddr)]
1874 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) ==> s.regions.slot_owner(
1875 paddr,
1876 ).ref_count() == REF_COUNT_UNUSED) {
1877 let ghost s_before = *s;
1878 let ghost old_regions = s.regions;
1879 let ghost old_frames = s.frames;
1880 let ghost old_segments = s.segments;
1881 let tracked res = segment::from_unused_step(&mut s.regions, range);
1882 match res {
1883 Option::Some(entry) => {
1884 let ghost id = fresh_segment_id(s.segments);
1885 lemma_fresh_segment_id_not_in_dom(s.segments);
1886 s.lemma_insert_segment(id, entry);
1887 lemma_step_segment_from_unused_accounting(*s, s_before, range, id, entry);
1888 },
1889 Option::None => {},
1890 }
1891 }
1892}
1893
1894proof fn lemma_accounting_inv_intro<'rcu>(store: VmStore<'rcu>)
1895 requires
1896 forall|idx: int|
1897 #![trigger store.regions.slot_owners[idx]]
1898 0 <= idx < max_meta_slots() && store.regions.ref_count(idx) == REF_COUNT_UNUSED
1899 ==> handle_count(store.frames, idx) == 0
1900 && store.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
1901 store.segments,
1902 index_to_frame(idx),
1903 ) == 0,
1904 forall|idx: int|
1905 #![trigger store.regions.slot_owners[idx]]
1906 0 <= idx < max_meta_slots() && store.regions.slot_owners[idx].usage is Frame
1907 && store.regions.ref_count(idx) != REF_COUNT_UNUSED && store.regions.ref_count(idx)
1908 != REF_COUNT_UNIQUE ==> handle_count(store.frames, idx) > 0
1909 || store.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
1910 store.segments,
1911 index_to_frame(idx),
1912 ) > 0,
1913 forall|idx: int|
1914 #![trigger store.regions.slot_owners[idx]]
1915 0 <= idx < max_meta_slots() && store.regions.slot_owners[idx].usage is Frame && (
1916 handle_count(store.frames, idx) > 0 || store.regions.slot_owners[idx].paths_in_pt.len()
1917 > 0 || segment_cover_count(store.segments, index_to_frame(idx)) > 0) ==> {
1918 let so = store.regions.slot_owners[idx];
1919 let rc = so.ref_count();
1920 &&& rc != REF_COUNT_UNUSED
1921 &&& rc != REF_COUNT_UNIQUE
1922 &&& rc == handle_count(store.frames, idx) + so.paths_in_pt.len()
1923 + segment_cover_count(store.segments, index_to_frame(idx))
1924 },
1925 ensures
1926 store.accounting_inv(),
1927{
1928 reveal(VmStore::accounting_inv);
1929}
1930
1931#[verifier::spinoff_prover]
1932proof fn lemma_drop_segment_with_store_inv<'rcu>(
1933 tracked regions: &mut MetaRegionOwners,
1934 tracked entry: SegmentEntry,
1935 store: VmStore<'rcu>,
1936 sid: SegmentId,
1937)
1938 requires
1939 store.inv(),
1940 store.segments.contains_key(sid),
1941 entry == store.segments[sid],
1942 *old(regions) == store.regions,
1943 ensures
1944 final(regions).inv(),
1945 final(regions).slots == old(regions).slots,
1946 forall|paddr: Paddr|
1947 #![trigger frame_to_index(paddr)]
1948 (entry.range.start <= paddr < entry.range.end && paddr % PAGE_SIZE == 0) ==> {
1949 let idx = frame_to_index(paddr);
1950 let so_old = old(regions).slot_owners[idx];
1951 let so_new = final(regions).slot_owners[idx];
1952 &&& so_old.ref_count() >= 1
1953 &&& so_old.ref_count() <= REF_COUNT_MAX
1954 &&& so_old.usage is Frame
1955 &&& so_old.ref_count() == 1 ==> so_old.paths_in_pt.is_empty()
1956 &&& so_new.usage == so_old.usage
1957 &&& so_new.paths_in_pt == so_old.paths_in_pt
1958 &&& so_new.slot_vaddr == so_old.slot_vaddr
1959 &&& so_new.in_list_perm == so_old.in_list_perm
1960 &&& so_old.ref_count() == 1 ==> so_new.ref_count() == REF_COUNT_UNUSED
1961 &&& so_old.ref_count() > 1 ==> so_new.ref_count() == (so_old.ref_count() - 1) as u64
1962 },
1963 forall|i: int|
1964 #![trigger final(regions).slot_owners[i]]
1965 i < max_meta_slots() && !(entry.range.start <= index_to_frame(i) < entry.range.end)
1966 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
1967 forall|i: int|
1968 #![trigger final(regions).slot_owners[i]]
1969 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
1970 regions,
1971 ).slot_owners[i],
1972 forall|c: CursorOwner<'_, UserPtConfig>|
1973 #![auto]
1974 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
1975{
1976 reveal(VmStore::structural_inv);
1977 reveal(VmStore::accounting_inv);
1978 assert forall|paddr: Paddr|
1979 #![trigger store.regions.slot_owner(paddr)]
1980 (entry.range.start <= paddr < entry.range.end && paddr % PAGE_SIZE == 0) implies {
1981 let so = store.regions.slot_owner(paddr);
1982 &&& so.ref_count() >= 1
1983 &&& so.ref_count() <= REF_COUNT_MAX
1984 &&& so.usage is Frame
1985 &&& so.ref_count() == 1 ==> so.paths_in_pt.is_empty()
1986 } by {
1987 let idx = frame_to_index(paddr);
1988 lemma_segment_cover_contains(store.segments, sid, paddr);
1989 let so = store.regions.slot_owners[idx];
1990 let rc = so.ref_count();
1991 assert(store.regions.contains(idx));
1992 };
1993 segment::drop_step(regions, entry);
1994}
1995
1996#[verifier::spinoff_prover]
1998#[verifier::rlimit(50)]
1999proof fn lemma_step_segment_drop<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
2000 requires
2001 old(s).inv(),
2002 old(s).segments.contains_key(sid),
2003 ensures
2004 final(s).inv(),
2005{
2006 let ghost s_before = *s;
2007 let ghost old_regions = s.regions;
2008 let ghost old_frames = s.frames;
2009 let ghost old_segments = s.segments;
2010 let ghost range = s.segments[sid].range;
2011 let tracked entry = s.tracked_extract_segment(sid);
2012 assert(entry.range == range);
2013 lemma_drop_segment_with_store_inv(&mut s.regions, entry, s_before, sid);
2014 lemma_coverage_preserved_slots_eq(s_before, *s);
2015
2016 assert forall|idx: int|
2017 0 <= idx
2018 < max_meta_slots() implies #[trigger] s.regions.slot_owners[idx].in_list_perm.value()
2019 == 0 by {
2020 reveal(VmStore::structural_inv);
2021 let paddr = index_to_frame(idx);
2022 if range.start <= paddr < range.end {
2023 } else {
2024 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2025 }
2026 };
2027 assert forall|idx: int|
2028 #![trigger s.regions.slot_owners[idx]]
2029 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
2030 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2031 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2032 s.segments,
2033 index_to_frame(idx),
2034 ) == 0 by {
2035 lemma_accounting_inv_at(s_before, idx);
2036 let paddr = index_to_frame(idx);
2037 if range.start <= paddr < range.end {
2038 lemma_segment_cover_contains(old_segments, sid, paddr);
2039 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
2040 assert(old_regions.ref_count(idx) == 1);
2041 } else {
2042 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2043 assert(!(entry.range.start <= paddr < entry.range.end));
2044 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
2045 }
2046 };
2047 assert forall|idx: int|
2048 #![trigger s.regions.slot_owners[idx]]
2049 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2050 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
2051 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2052 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2053 s.segments,
2054 index_to_frame(idx),
2055 ) > 0 by {
2056 lemma_accounting_inv_at(s_before, idx);
2057 let paddr = index_to_frame(idx);
2058 if range.start <= paddr < range.end {
2059 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
2060 } else {
2061 assert(s.regions.slot_owners[idx] == old_regions.slot_owners[idx]);
2062 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
2063 }
2064 };
2065 assert forall|idx: int|
2066 #![trigger s.regions.slot_owners[idx]]
2067 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2068 s.frames,
2069 idx,
2070 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2071 s.segments,
2072 index_to_frame(idx),
2073 ) > 0) implies {
2074 let so = s.regions.slot_owners[idx];
2075 let rc = so.ref_count();
2076 &&& rc != REF_COUNT_UNUSED
2077 &&& rc != REF_COUNT_UNIQUE
2078 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2079 s.segments,
2080 index_to_frame(idx),
2081 )
2082 } by {
2083 lemma_accounting_inv_at(s_before, idx);
2084 let paddr = index_to_frame(idx);
2085 if range.start <= paddr < range.end {
2086 lemma_segment_cover_contains(old_segments, sid, paddr);
2087 lemma_segment_cover_remove_inside(old_segments, sid, paddr);
2088 let pre_rc = old_regions.ref_count(idx);
2090 let pre_H = handle_count(old_frames, idx);
2091 let pre_P = old_regions.slot_owners[idx].paths_in_pt.len();
2092 let pre_cover = segment_cover_count(old_segments, paddr);
2093 let post_rc = s.regions.ref_count(idx);
2094 assert(s.regions.contains(idx));
2095 } else {
2096 assert(!(entry.range.start <= paddr < entry.range.end));
2097 lemma_segment_cover_remove_outside(old_segments, sid, paddr);
2098 }
2099 };
2100 lemma_accounting_inv_intro(*s);
2101 assert(s.structural_inv()) by {
2102 reveal(VmStore::structural_inv);
2103 };
2104}
2105
2106proof fn lemma_step_segment_split<'rcu>(
2108 tracked s: &mut VmStore<'rcu>,
2109 sid: SegmentId,
2110 offset: usize,
2111)
2112 requires
2113 old(s).inv(),
2114 old(s).segments.contains_key(sid),
2115 offset % PAGE_SIZE == 0,
2116 0 < offset,
2117 offset < (old(s).segments[sid].range.end - old(s).segments[sid].range.start),
2118 ensures
2119 final(s).inv(),
2120{
2121 let ghost s_before = *s;
2122 let ghost old_regions = s.regions;
2123 let ghost old_frames = s.frames;
2124 let ghost old_segments = s.segments;
2125 let ghost range = s.segments[sid].range;
2126 assert(range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0) by {
2127 reveal(VmStore::structural_inv);
2128 };
2129 let ghost mid = (range.start + offset) as Paddr;
2130 let ghost entry_left = SegmentEntry { range: range.start..mid };
2131 let ghost entry_right = SegmentEntry { range: mid..range.end };
2132 let ghost id_left = fresh_segment_id(s.segments);
2133 lemma_fresh_segment_id_not_in_dom(s.segments);
2134 assert(id_left != sid);
2135 let ghost stub_entry = SegmentEntry { range: range.start..mid };
2136 let ghost id_right = fresh_segment_id(s.segments.insert(id_left, stub_entry));
2137 lemma_fresh_segment_id_not_in_dom(s.segments.insert(id_left, stub_entry));
2138 assert(id_right != sid);
2139 assert(id_right != id_left);
2140 let tracked _orig = s.tracked_extract_segment(sid);
2142 assert(!s.segments.contains_key(id_left));
2143 let tracked entry_l = tracked_segment_entry_new(range.start..mid);
2144 s.lemma_insert_segment(id_left, entry_l);
2145 assert(!s.segments.contains_key(id_right));
2146 let tracked entry_r = tracked_segment_entry_new(mid..range.end);
2147 s.lemma_insert_segment(id_right, entry_r);
2148 assert(s.regions == old_regions);
2149 assert forall|paddr: Paddr| #[trigger]
2150 frame_to_index(paddr) < max_meta_slots() implies segment_cover_count(s.segments, paddr)
2151 == segment_cover_count(old_segments, paddr) by {
2152 lemma_segment_cover_split(
2153 old_segments,
2154 sid,
2155 id_left,
2156 id_right,
2157 entry_left,
2158 entry_right,
2159 paddr,
2160 );
2161 };
2162 assert(entry_left.range.start % PAGE_SIZE == 0);
2163 assert(entry_right.range.start % PAGE_SIZE == 0);
2164 assert(entry_left.range.end % PAGE_SIZE == 0);
2165 assert(entry_right.range.end % PAGE_SIZE == 0);
2166 assert forall|sid_other: SegmentId, paddr_c: Paddr|
2167 #![trigger
2168 s.segments.contains_key(sid_other),
2169 frame_to_index(paddr_c)]
2170 s.segments.contains_key(sid_other) && s.segments[sid_other].range.start <= paddr_c
2171 < s.segments[sid_other].range.end && paddr_c % PAGE_SIZE
2172 == 0 implies s.regions.slot_owner(paddr_c).usage is Frame by {
2173 if sid_other == id_left {
2174 assert(old_segments.contains_key(sid));
2175 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
2176 lemma_structural_inv_segment(s_before, sid, paddr_c);
2177 } else if sid_other == id_right {
2178 assert(old_segments.contains_key(sid));
2179 assert(old_segments[sid].range.start <= paddr_c < old_segments[sid].range.end);
2180 lemma_structural_inv_segment(s_before, sid, paddr_c);
2181 } else {
2182 assert(old_segments.contains_key(sid_other));
2183 assert(old_segments[sid_other] == s.segments[sid_other]);
2184 lemma_structural_inv_segment(s_before, sid_other, paddr_c);
2185 }
2186 };
2187 assert forall|idx: int|
2188 #![trigger s.regions.slot_owners[idx]]
2189 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
2190 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2191 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2192 s.segments,
2193 index_to_frame(idx),
2194 ) == 0 by {
2195 lemma_accounting_inv_at(s_before, idx);
2196 let paddr = index_to_frame(idx);
2197 assert(paddr == (idx * PAGE_SIZE) as usize);
2198 assert(frame_to_index(paddr) == idx);
2199 lemma_segment_cover_split(
2200 old_segments,
2201 sid,
2202 id_left,
2203 id_right,
2204 entry_left,
2205 entry_right,
2206 paddr,
2207 );
2208 };
2209 assert forall|idx: int|
2210 #![trigger s.regions.slot_owners[idx]]
2211 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2212 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
2213 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2214 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2215 s.segments,
2216 index_to_frame(idx),
2217 ) > 0 by {
2218 lemma_accounting_inv_at(s_before, idx);
2219 let paddr = index_to_frame(idx);
2220 assert(paddr == (idx * PAGE_SIZE) as usize);
2221 assert(frame_to_index(paddr) == idx);
2222 lemma_segment_cover_split(
2223 old_segments,
2224 sid,
2225 id_left,
2226 id_right,
2227 entry_left,
2228 entry_right,
2229 paddr,
2230 );
2231 };
2232 assert forall|idx: int|
2233 #![trigger s.regions.slot_owners[idx]]
2234 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2235 s.frames,
2236 idx,
2237 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2238 s.segments,
2239 index_to_frame(idx),
2240 ) > 0) implies {
2241 let so = s.regions.slot_owners[idx];
2242 let rc = so.ref_count();
2243 &&& rc != REF_COUNT_UNUSED
2244 &&& rc != REF_COUNT_UNIQUE
2245 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2246 s.segments,
2247 index_to_frame(idx),
2248 )
2249 } by {
2250 lemma_accounting_inv_at(s_before, idx);
2251 let paddr = index_to_frame(idx);
2252 assert(paddr == (idx * PAGE_SIZE) as usize);
2253 assert(frame_to_index(paddr) == idx);
2254 lemma_segment_cover_split(
2255 old_segments,
2256 sid,
2257 id_left,
2258 id_right,
2259 entry_left,
2260 entry_right,
2261 paddr,
2262 );
2263 };
2264 lemma_accounting_inv_intro(*s);
2265 assert(s.structural_inv()) by {
2266 reveal(VmStore::structural_inv);
2267 };
2268}
2269
2270#[verifier::spinoff_prover]
2272#[verifier::rlimit(200)]
2273proof fn lemma_step_segment_next<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
2274 requires
2275 old(s).inv(),
2276 old(s).segments.contains_key(sid),
2277 ensures
2278 final(s).inv(),
2279{
2280 reveal(VmStore::structural_inv);
2281 reveal(VmStore::accounting_inv);
2282 let ghost old_regions = s.regions;
2283 let ghost old_frames = s.frames;
2284 let ghost old_segments = s.segments;
2285 let ghost range = s.segments[sid].range;
2286 let ghost paddr = range.start;
2287 let ghost target_idx = frame_to_index(paddr);
2288 let ghost new_range_start = (paddr + PAGE_SIZE) as Paddr;
2289 let ghost new_range_end = range.end;
2290 let ghost will_become_empty = new_range_start >= new_range_end;
2291 let ghost new_entry_ghost = SegmentEntry { range: new_range_start..new_range_end };
2292
2293 let ghost so_pre = old_regions.slot_owners[target_idx];
2295 let ghost pre_rc = so_pre.ref_count();
2296 let ghost pre_H = handle_count(old_frames, target_idx);
2297 let ghost pre_P = so_pre.paths_in_pt.len();
2298 let ghost pre_cover = segment_cover_count(old_segments, paddr);
2299 s.regions.lemma_contains_valid_frame_paddr(paddr);
2300
2301 let ghost fid = fresh_frame_id(s.frames);
2303 lemma_fresh_frame_id_not_in_dom(s.frames);
2304 let tracked frame_entry = tracked_frame_entry_new(paddr);
2305 s.lemma_insert_frame(fid, frame_entry);
2306 let tracked _old_entry = s.tracked_extract_segment(sid);
2308 if !will_become_empty {
2309 let tracked new_entry = tracked_segment_entry_new(new_range_start..new_range_end);
2310 s.lemma_insert_segment(sid, new_entry);
2311 }
2312 assert(s.frames == old_frames.insert(fid, frame_entry));
2313
2314 assert forall|paddr_c: Paddr|
2315 paddr_c % PAGE_SIZE == 0 && paddr_c == paddr implies #[trigger] segment_cover_count(
2316 s.segments,
2317 paddr_c,
2318 ) + 1 == segment_cover_count(old_segments, paddr_c) by {
2319 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
2320 };
2321 assert forall|paddr_c: Paddr|
2322 paddr_c % PAGE_SIZE == 0 && paddr_c != paddr implies #[trigger] segment_cover_count(
2323 s.segments,
2324 paddr_c,
2325 ) == segment_cover_count(old_segments, paddr_c) by {
2326 lemma_segment_cover_shrink_front(old_segments, sid, new_entry_ghost, paddr_c);
2327 };
2328
2329 assert forall|idx: int|
2330 #![trigger s.regions.slot_owners[idx]]
2331 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
2332 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2333 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2334 s.segments,
2335 index_to_frame(idx),
2336 ) == 0 by {
2337 let paddr_c = index_to_frame(idx);
2338 if idx == target_idx {
2339 lemma_segment_cover_contains(old_segments, sid, paddr);
2340 assert(false);
2341 } else {
2342 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
2343 }
2344 };
2345 assert forall|idx: int|
2346 #![trigger s.regions.slot_owners[idx]]
2347 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2348 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
2349 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2350 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2351 s.segments,
2352 index_to_frame(idx),
2353 ) > 0 by {
2354 let paddr_c = index_to_frame(idx);
2355 if idx == target_idx {
2356 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
2358 } else {
2359 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
2360 }
2361 };
2362 assert forall|idx: int|
2363 #![trigger s.regions.slot_owners[idx]]
2364 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2365 s.frames,
2366 idx,
2367 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2368 s.segments,
2369 index_to_frame(idx),
2370 ) > 0) implies {
2371 let so = s.regions.slot_owners[idx];
2372 let rc = so.ref_count();
2373 &&& rc != REF_COUNT_UNUSED
2374 &&& rc != REF_COUNT_UNIQUE
2375 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2376 s.segments,
2377 index_to_frame(idx),
2378 )
2379 } by {
2380 let paddr_c = index_to_frame(idx);
2381 lemma_handle_count_insert_fresh(old_frames, fid, frame_entry, idx);
2382 };
2383 assert forall|u: UniqueId| #[trigger] s.unique_frames.contains_key(u) implies {
2384 let so = s.regions.slot_owner(s.unique_frames[u].paddr);
2385 &&& so.usage is Frame
2386 &&& so.ref_count() == REF_COUNT_UNIQUE
2387 &&& so.in_list_perm.value() == 0
2388 &&& so.paths_in_pt.is_empty()
2389 } by {};
2390 reveal(CursorContinuation::map_children);
2391 reveal(CursorOwner::path_metaregion_sound);
2392}
2393
2394#[verifier::spinoff_prover]
2395proof fn lemma_step_segment_clone_range<'rcu>(
2396 tracked s: &mut VmStore<'rcu>,
2397 sid: SegmentId,
2398 sub_range: Range<Paddr>,
2399)
2400 requires
2401 old(s).inv(),
2402 old(s).segments.contains_key(sid),
2403 sub_range.start % PAGE_SIZE == 0,
2404 sub_range.end % PAGE_SIZE == 0,
2405 old(s).segments[sid].range.start <= sub_range.start,
2406 sub_range.start < sub_range.end,
2407 sub_range.end <= old(s).segments[sid].range.end,
2408 forall|paddr: Paddr|
2409 #![trigger frame_to_index(paddr)]
2410 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) ==> old(
2411 s,
2412 ).regions.slot_owner(paddr).ref_count() + 1 <= REF_COUNT_MAX,
2413 ensures
2414 final(s).inv(),
2415{
2416 let ghost s_before = *s;
2418 let ghost old_regions = s.regions;
2419 let ghost old_frames = s.frames;
2420 let ghost old_segments = s.segments;
2421 let ghost sid_range = s.segments[sid].range;
2422 let ghost new_entry_ghost = SegmentEntry { range: sub_range };
2423
2424 assert(sid_range.end <= MAX_PADDR) by {
2425 reveal(VmStore::structural_inv);
2426 };
2427
2428 assert forall|paddr: Paddr|
2429 #![trigger frame_to_index(paddr)]
2430 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) implies {
2431 let so = old_regions.slot_owner(paddr);
2432 &&& so.usage is Frame
2433 &&& so.ref_count() >= 1
2434 &&& so.ref_count() + 1 <= REF_COUNT_MAX
2435 } by {
2436 lemma_structural_inv_segment(s_before, sid, paddr);
2438 let idx = frame_to_index(paddr);
2439 lemma_accounting_inv_at(s_before, idx);
2440 };
2442
2443 segment::segment_clone_embedded(&mut s.regions, sub_range);
2445
2446 let ghost sid2 = fresh_segment_id(s.segments);
2448 lemma_fresh_segment_id_not_in_dom(s.segments);
2449 let tracked new_entry = tracked_segment_entry_new(sub_range);
2450 s.lemma_insert_segment(sid2, new_entry);
2451
2452 assert forall|paddr_c: Paddr|
2454 paddr_c % PAGE_SIZE == 0 && sub_range.start <= paddr_c
2455 < sub_range.end implies #[trigger] segment_cover_count(s.segments, paddr_c)
2456 == segment_cover_count(old_segments, paddr_c) + 1 by {
2457 lemma_segment_cover_insert_inside(old_segments, sid2, new_entry_ghost, paddr_c);
2458 };
2459 assert forall|paddr_c: Paddr|
2460 paddr_c % PAGE_SIZE == 0 && !(sub_range.start <= paddr_c
2461 < sub_range.end) implies #[trigger] segment_cover_count(s.segments, paddr_c)
2462 == segment_cover_count(old_segments, paddr_c) by {
2463 lemma_segment_cover_insert_outside(old_segments, sid2, new_entry_ghost, paddr_c);
2464 };
2465
2466 assert forall|idx: int|
2468 #![trigger s.regions.slot_owners[idx]]
2469 0 <= idx < max_meta_slots() && s.regions.ref_count(idx)
2470 == REF_COUNT_UNUSED implies handle_count(s.frames, idx) == 0
2471 && s.regions.slot_owners[idx].paths_in_pt.is_empty() && segment_cover_count(
2472 s.segments,
2473 index_to_frame(idx),
2474 ) == 0 by {
2475 lemma_accounting_inv_at(s_before, idx);
2476 let aligned = index_to_frame(idx);
2477 if sub_range.start <= aligned < sub_range.end {
2478 assert(false);
2480 }
2481 };
2482 assert forall|idx: int|
2484 #![trigger s.regions.slot_owners[idx]]
2485 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame
2486 && s.regions.ref_count(idx) != REF_COUNT_UNUSED && s.regions.ref_count(idx)
2487 != REF_COUNT_UNIQUE implies handle_count(s.frames, idx) > 0
2488 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2489 s.segments,
2490 index_to_frame(idx),
2491 ) > 0 by {
2492 lemma_accounting_inv_at(s_before, idx);
2493 let aligned = index_to_frame(idx);
2494 };
2495 assert forall|idx: int|
2497 #![trigger s.regions.slot_owners[idx]]
2498 0 <= idx < max_meta_slots() && s.regions.slot_owners[idx].usage is Frame && (handle_count(
2499 s.frames,
2500 idx,
2501 ) > 0 || s.regions.slot_owners[idx].paths_in_pt.len() > 0 || segment_cover_count(
2502 s.segments,
2503 index_to_frame(idx),
2504 ) > 0) implies {
2505 let so = s.regions.slot_owners[idx];
2506 let rc = so.ref_count();
2507 &&& rc != REF_COUNT_UNUSED
2508 &&& rc != REF_COUNT_UNIQUE
2509 &&& rc == handle_count(s.frames, idx) + so.paths_in_pt.len() + segment_cover_count(
2510 s.segments,
2511 index_to_frame(idx),
2512 )
2513 } by {
2514 lemma_accounting_inv_at(s_before, idx);
2515 let aligned = index_to_frame(idx);
2516 let so = s.regions.slot_owners[idx];
2517 let rc = so.ref_count();
2518 };
2519 lemma_accounting_inv_intro(*s);
2520 assert(s.structural_inv()) by {
2521 reveal(VmStore::structural_inv);
2522 };
2523}
2524
2525proof fn lemma_step_segment_clone<'rcu>(tracked s: &mut VmStore<'rcu>, sid: SegmentId)
2527 requires
2528 old(s).inv(),
2529 old(s).segments.contains_key(sid),
2530 forall|paddr: Paddr|
2531 #![trigger frame_to_index(paddr)]
2532 (old(s).segments[sid].range.start <= paddr < old(s).segments[sid].range.end && paddr
2533 % PAGE_SIZE == 0) ==> old(s).regions.slot_owner(paddr).ref_count() + 1
2534 <= REF_COUNT_MAX,
2535 ensures
2536 final(s).inv(),
2537{
2538 reveal(VmStore::structural_inv);
2539 let ghost r = s.segments[sid].range;
2540}
2541
2542proof fn lemma_step_segment_slice<'rcu>(
2544 tracked s: &mut VmStore<'rcu>,
2545 sid: SegmentId,
2546 sub_range: Range<Paddr>,
2547)
2548 requires
2549 old(s).inv(),
2550 old(s).segments.contains_key(sid),
2551 sub_range.start % PAGE_SIZE == 0,
2552 sub_range.end % PAGE_SIZE == 0,
2553 old(s).segments[sid].range.start <= sub_range.start,
2554 sub_range.start < sub_range.end,
2555 sub_range.end <= old(s).segments[sid].range.end,
2556 forall|paddr: Paddr|
2557 #![trigger frame_to_index(paddr)]
2558 (sub_range.start <= paddr < sub_range.end && paddr % PAGE_SIZE == 0) ==> old(
2559 s,
2560 ).regions.slot_owner(paddr).ref_count() + 1 <= REF_COUNT_MAX,
2561 ensures
2562 final(s).inv(),
2563{
2564}
2565
2566proof fn lemma_step_unique_from_unused<'rcu>(tracked s: &mut VmStore<'rcu>, paddr: Paddr)
2567 requires
2568 old(s).inv(),
2569 ensures
2570 final(s).inv(),
2571{
2572 reveal(VmStore::structural_inv);
2573 reveal(VmStore::accounting_inv);
2574 if valid_frame_paddr(paddr) && s.regions.slots.contains_key(frame_to_index(paddr))
2575 && s.regions.slot_owner(paddr).usage is Unused && s.regions.slot_owner(paddr).ref_count()
2576 == REF_COUNT_UNUSED {
2577 let ghost old_regions = s.regions;
2578 let ghost old_frames = s.frames;
2579 let ghost old_segments = s.segments;
2580 let ghost old_unique = s.unique_frames;
2581 let ghost idx = frame_to_index(paddr);
2582
2583 unique::unique_from_unused_embedded(&mut s.regions, paddr);
2585
2586 let ghost uid = fresh_unique_id(s.unique_frames);
2588 lemma_fresh_unique_id_not_in_dom(s.unique_frames);
2589 let tracked entry = tracked_unique_entry_new(paddr);
2590 s.lemma_insert_unique(uid, entry);
2591
2592 }
2593}
2594
2595proof fn lemma_step_unique_drop<'rcu>(tracked s: &mut VmStore<'rcu>, uid: UniqueId)
2600 requires
2601 old(s).inv(),
2602 old(s).unique_frames.contains_key(uid),
2603 ensures
2604 final(s).inv(),
2605{
2606 reveal(VmStore::structural_inv);
2607 reveal(VmStore::accounting_inv);
2608 let ghost old_regions = s.regions;
2609 let ghost old_frames = s.frames;
2610 let ghost old_segments = s.segments;
2611 let ghost old_unique = s.unique_frames;
2612 let ghost paddr = s.unique_frames[uid].paddr;
2613 let ghost idx = frame_to_index(paddr);
2614
2615}
2616
2617proof fn lemma_step_from_unique<'rcu>(tracked s: &mut VmStore<'rcu>, uid: UniqueId)
2619 requires
2620 old(s).inv(),
2621 old(s).unique_frames.contains_key(uid),
2622 ensures
2623 final(s).inv(),
2624{
2625 reveal(VmStore::structural_inv);
2626 reveal(VmStore::accounting_inv);
2627 let ghost old_regions = s.regions;
2628 let ghost old_frames = s.frames;
2629 let ghost old_segments = s.segments;
2630 let ghost old_unique = s.unique_frames;
2631 let ghost paddr = s.unique_frames[uid].paddr;
2632 let ghost idx = frame_to_index(paddr);
2633
2634 let tracked _ue = s.tracked_extract_unique(uid);
2636 unique::from_unique_embedded(&mut s.regions, paddr);
2637
2638 let ghost fid = fresh_frame_id(s.frames);
2640 lemma_fresh_frame_id_not_in_dom(s.frames);
2641 let tracked fe = tracked_frame_entry_new(paddr);
2642 s.lemma_insert_frame(fid, fe);
2643
2644 assert forall|i: int|
2646 #![trigger s.regions.slot_owners[i]]
2647 0 <= i < max_meta_slots() && s.regions.ref_count(i)
2648 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
2649 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
2650 s.segments,
2651 index_to_frame(i),
2652 ) == 0 by {
2653 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
2654 if i == idx {
2655 assert(false);
2656 }
2657 };
2658 assert forall|i: int|
2660 #![trigger s.regions.slot_owners[i]]
2661 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && s.regions.ref_count(
2662 i,
2663 ) != REF_COUNT_UNUSED && s.regions.ref_count(i) != REF_COUNT_UNIQUE implies handle_count(
2664 s.frames,
2665 i,
2666 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
2667 s.segments,
2668 index_to_frame(i),
2669 ) > 0 by {
2670 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
2671 };
2672 assert forall|i: int|
2674 #![trigger s.regions.slot_owners[i]]
2675 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
2676 s.frames,
2677 i,
2678 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
2679 s.segments,
2680 index_to_frame(i),
2681 ) > 0) implies {
2682 let so = s.regions.slot_owners[i];
2683 let rc = so.ref_count();
2684 &&& rc != REF_COUNT_UNUSED
2685 &&& rc != REF_COUNT_UNIQUE
2686 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
2687 s.segments,
2688 index_to_frame(i),
2689 )
2690 } by {
2691 lemma_handle_count_insert_fresh(old_frames, fid, fe, i);
2692 };
2693}
2694
2695proof fn lemma_step_try_from_shared<'rcu>(tracked s: &mut VmStore<'rcu>, fid: FrameId)
2702 requires
2703 old(s).inv(),
2704 old(s).frames.contains_key(fid),
2705 ensures
2706 final(s).inv(),
2707{
2708 reveal(VmStore::structural_inv);
2709 reveal(VmStore::accounting_inv);
2710 let ghost paddr = s.frames[fid].paddr;
2711 let ghost idx = frame_to_index(paddr);
2712 assert(s.frames.dom().filter(
2715 |gid: FrameId| frame_to_index(s.frames[gid].paddr) == idx,
2716 ).contains(fid));
2717
2718 if s.regions.ref_count(idx) == 1 {
2719 let ghost old_regions = s.regions;
2720 let ghost old_frames = s.frames;
2721 let ghost old_segments = s.segments;
2722 let ghost old_unique = s.unique_frames;
2723
2724 let tracked _fe = s.tracked_extract_frame(fid);
2729 unique::try_from_shared_embedded(&mut s.regions, paddr);
2730
2731 let ghost uid = fresh_unique_id(s.unique_frames);
2733 lemma_fresh_unique_id_not_in_dom(s.unique_frames);
2734 let tracked ue = tracked_unique_entry_new(paddr);
2735 s.lemma_insert_unique(uid, ue);
2736 assert forall|i: int|
2738 #![trigger s.regions.slot_owners[i]]
2739 0 <= i < max_meta_slots() && s.regions.ref_count(i)
2740 == REF_COUNT_UNUSED implies handle_count(s.frames, i) == 0
2741 && s.regions.slot_owners[i].paths_in_pt.is_empty() && segment_cover_count(
2742 s.segments,
2743 index_to_frame(i),
2744 ) == 0 by {
2745 lemma_handle_count_remove(old_frames, fid, i);
2746 if i == idx {
2747 assert(false);
2749 }
2750 };
2751 assert forall|i: int|
2753 #![trigger s.regions.slot_owners[i]]
2754 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame
2755 && s.regions.ref_count(i) != REF_COUNT_UNUSED && s.regions.ref_count(i)
2756 != REF_COUNT_UNIQUE implies handle_count(s.frames, i) > 0
2757 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
2758 s.segments,
2759 index_to_frame(i),
2760 ) > 0 by {
2761 lemma_handle_count_remove(old_frames, fid, i);
2762 if i == idx {
2763 assert(false);
2765 }
2766 };
2767 assert forall|i: int|
2769 #![trigger s.regions.slot_owners[i]]
2770 0 <= i < max_meta_slots() && s.regions.slot_owners[i].usage is Frame && (handle_count(
2771 s.frames,
2772 i,
2773 ) > 0 || s.regions.slot_owners[i].paths_in_pt.len() > 0 || segment_cover_count(
2774 s.segments,
2775 index_to_frame(i),
2776 ) > 0) implies {
2777 let so = s.regions.slot_owners[i];
2778 let rc = so.ref_count();
2779 &&& rc != REF_COUNT_UNUSED
2780 &&& rc != REF_COUNT_UNIQUE
2781 &&& rc == handle_count(s.frames, i) + so.paths_in_pt.len() + segment_cover_count(
2782 s.segments,
2783 index_to_frame(i),
2784 )
2785 } by {
2786 lemma_handle_count_remove(old_frames, fid, i);
2787 };
2788 }
2789}
2790
2791pub proof fn lemma_segment_cover_insert_inside(
2794 segments: Map<SegmentId, SegmentEntry>,
2795 sid: SegmentId,
2796 entry: SegmentEntry,
2797 paddr: Paddr,
2798)
2799 requires
2800 !segments.contains_key(sid),
2801 entry.range.start <= paddr < entry.range.end,
2802 ensures
2803 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
2804 segments,
2805 paddr,
2806 ) + 1,
2807{
2808 let segments2 = segments.insert(sid, entry);
2809 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
2810 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
2811 let old_filt = segments.dom().filter(pred);
2812 let new_filt = segments2.dom().filter(pred2);
2813 assert(new_filt == old_filt.insert(sid)) by {};
2814}
2815
2816pub proof fn lemma_segment_cover_insert_outside(
2819 segments: Map<SegmentId, SegmentEntry>,
2820 sid: SegmentId,
2821 entry: SegmentEntry,
2822 paddr: Paddr,
2823)
2824 requires
2825 !segments.contains_key(sid),
2826 !(entry.range.start <= paddr < entry.range.end),
2827 ensures
2828 segment_cover_count(segments.insert(sid, entry), paddr) == segment_cover_count(
2829 segments,
2830 paddr,
2831 ),
2832{
2833 let segments2 = segments.insert(sid, entry);
2834 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
2835 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
2836 let old_filt = segments.dom().filter(pred);
2837 let new_filt = segments2.dom().filter(pred2);
2838 assert(new_filt == old_filt) by {};
2839}
2840
2841pub proof fn lemma_segment_cover_contains(
2844 segments: Map<SegmentId, SegmentEntry>,
2845 sid: SegmentId,
2846 paddr: Paddr,
2847)
2848 requires
2849 segments.contains_key(sid),
2850 segments[sid].range.start <= paddr < segments[sid].range.end,
2851 ensures
2852 segment_cover_count(segments, paddr) >= 1,
2853{
2854 let filt = segments.dom().filter(
2855 |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end,
2856 );
2857 assert(filt.contains(sid));
2858}
2859
2860pub proof fn lemma_segment_cover_remove_inside(
2863 segments: Map<SegmentId, SegmentEntry>,
2864 sid: SegmentId,
2865 paddr: Paddr,
2866)
2867 requires
2868 segments.contains_key(sid),
2869 segments[sid].range.start <= paddr < segments[sid].range.end,
2870 ensures
2871 segment_cover_count(segments.remove(sid), paddr) == (segment_cover_count(segments, paddr)
2872 - 1) as nat,
2873{
2874 let segments2 = segments.remove(sid);
2875 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
2876 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
2877 let old_filt = segments.dom().filter(pred);
2878 let new_filt = segments2.dom().filter(pred2);
2879 assert(new_filt == old_filt.remove(sid)) by {};
2880}
2881
2882pub proof fn lemma_segment_cover_shrink_front(
2893 segments: Map<SegmentId, SegmentEntry>,
2894 sid: SegmentId,
2895 new_entry: SegmentEntry,
2896 paddr_check: Paddr,
2897)
2898 requires
2899 segments.contains_key(sid),
2900 segments[sid].range.start < segments[sid].range.end,
2903 segments[sid].range.start % PAGE_SIZE == 0,
2905 segments[sid].range.start + PAGE_SIZE <= MAX_PADDR,
2907 new_entry.range.start == (segments[sid].range.start + PAGE_SIZE) as Paddr,
2908 new_entry.range.end == segments[sid].range.end,
2909 new_entry.range.start <= new_entry.range.end,
2910 paddr_check % PAGE_SIZE == 0,
2911 ensures
2912new_entry.range.start < new_entry.range.end ==> ({
2916 let new_segments = segments.remove(sid).insert(sid, new_entry);
2917 paddr_check == segments[sid].range.start ==> segment_cover_count(
2918 new_segments,
2919 paddr_check,
2920 ) + 1 == segment_cover_count(segments, paddr_check)
2921 }),
2922 new_entry.range.start < new_entry.range.end ==> ({
2923 let new_segments = segments.remove(sid).insert(sid, new_entry);
2924 paddr_check != segments[sid].range.start ==> segment_cover_count(
2925 new_segments,
2926 paddr_check,
2927 ) == segment_cover_count(segments, paddr_check)
2928 }),
2929 new_entry.range.start >= new_entry.range.end ==> ({
2931 let new_segments = segments.remove(sid);
2932 paddr_check == segments[sid].range.start ==> segment_cover_count(
2933 new_segments,
2934 paddr_check,
2935 ) + 1 == segment_cover_count(segments, paddr_check)
2936 }),
2937 new_entry.range.start >= new_entry.range.end ==> ({
2938 let new_segments = segments.remove(sid);
2939 paddr_check != segments[sid].range.start ==> segment_cover_count(
2940 new_segments,
2941 paddr_check,
2942 ) == segment_cover_count(segments, paddr_check)
2943 }),
2944{
2945 let popped = segments[sid].range.start;
2946 let range = segments[sid].range;
2947 let sid_pre_covers = range.start <= paddr_check < range.end;
2950 let new_covers = new_entry.range.start <= paddr_check < new_entry.range.end;
2951 if sid_pre_covers {
2953 lemma_segment_cover_remove_inside(segments, sid, paddr_check);
2954 } else {
2955 lemma_segment_cover_remove_outside(segments, sid, paddr_check);
2956 }
2957 if new_entry.range.start < new_entry.range.end {
2958 let new_segments = segments.remove(sid).insert(sid, new_entry);
2959 if paddr_check == popped {
2960 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
2963 lemma_segment_cover_contains(segments, sid, paddr_check);
2964 } else if sid_pre_covers {
2965 lemma_segment_cover_contains(segments, sid, paddr_check);
2966 lemma_segment_cover_insert_inside(segments.remove(sid), sid, new_entry, paddr_check);
2967 } else {
2968 lemma_segment_cover_insert_outside(segments.remove(sid), sid, new_entry, paddr_check);
2969 }
2970 } else {
2971 let new_segments = segments.remove(sid);
2972 if paddr_check == popped {
2973 lemma_segment_cover_contains(segments, sid, paddr_check);
2974 } else if sid_pre_covers {
2975 assert(false);
2976 }
2977 }
2978}
2979
2980pub proof fn lemma_segment_cover_split(
2986 segments: Map<SegmentId, SegmentEntry>,
2987 sid: SegmentId,
2988 new_left: SegmentId,
2989 new_right: SegmentId,
2990 entry_left: SegmentEntry,
2991 entry_right: SegmentEntry,
2992 paddr: Paddr,
2993)
2994 requires
2995 segments.contains_key(sid),
2996 new_left != sid,
2999 new_right != sid,
3000 new_left != new_right,
3001 !segments.remove(sid).contains_key(new_left),
3002 !segments.remove(sid).contains_key(new_right),
3003 entry_left.range.start == segments[sid].range.start,
3005 entry_left.range.end == entry_right.range.start,
3006 entry_right.range.end == segments[sid].range.end,
3007 entry_left.range.start < entry_left.range.end,
3008 entry_right.range.start < entry_right.range.end,
3009 ensures
3010 segment_cover_count(
3011 segments.remove(sid).insert(new_left, entry_left).insert(new_right, entry_right),
3012 paddr,
3013 ) == segment_cover_count(segments, paddr),
3014{
3015 let mid_segments = segments.remove(sid);
3016 let with_left = mid_segments.insert(new_left, entry_left);
3017 let sid_covers = segments[sid].range.start <= paddr && paddr < segments[sid].range.end;
3018 let left_covers = entry_left.range.start <= paddr && paddr < entry_left.range.end;
3019 let right_covers = entry_right.range.start <= paddr && paddr < entry_right.range.end;
3020 if sid_covers {
3022 lemma_segment_cover_remove_inside(segments, sid, paddr);
3023 } else {
3024 lemma_segment_cover_remove_outside(segments, sid, paddr);
3025 }
3026 if left_covers {
3028 lemma_segment_cover_insert_inside(mid_segments, new_left, entry_left, paddr);
3029 } else {
3030 lemma_segment_cover_insert_outside(mid_segments, new_left, entry_left, paddr);
3031 }
3032 let final_segments = with_left.insert(new_right, entry_right);
3034 if right_covers {
3035 lemma_segment_cover_insert_inside(with_left, new_right, entry_right, paddr);
3036 } else {
3037 lemma_segment_cover_insert_outside(with_left, new_right, entry_right, paddr);
3038 }
3039 let orig = segment_cover_count(segments, paddr);
3041 if sid_covers {
3042 lemma_segment_cover_contains(segments, sid, paddr);
3044 }
3045}
3046
3047pub proof fn lemma_segment_cover_remove_outside(
3050 segments: Map<SegmentId, SegmentEntry>,
3051 sid: SegmentId,
3052 paddr: Paddr,
3053)
3054 requires
3055 segments.contains_key(sid),
3056 !(segments[sid].range.start <= paddr < segments[sid].range.end),
3057 ensures
3058 segment_cover_count(segments.remove(sid), paddr) == segment_cover_count(segments, paddr),
3059{
3060 let segments2 = segments.remove(sid);
3061 let pred = |s: SegmentId| segments[s].range.start <= paddr && paddr < segments[s].range.end;
3062 let pred2 = |s: SegmentId| segments2[s].range.start <= paddr && paddr < segments2[s].range.end;
3063 let old_filt = segments.dom().filter(pred);
3064 let new_filt = segments2.dom().filter(pred2);
3065 assert(new_filt == old_filt) by {};
3066}
3067
3068pub open spec fn fresh_vm_space_id<'a>(m: Map<VmSpaceId, VmSpaceOwner>) -> VmSpaceId {
3074 choose|id: VmSpaceId| !m.contains_key(id)
3075}
3076
3077pub open spec fn fresh_cursor_id<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>) -> CursorId {
3079 choose|id: CursorId| !m.contains_key(id)
3080}
3081
3082pub open spec fn fresh_vm_io_id<'a>(m: Map<VmIoId, VmIoEntry>) -> VmIoId {
3084 choose|id: VmIoId| !m.contains_key(id)
3085}
3086
3087pub open spec fn fresh_frame_id(m: Map<FrameId, FrameEntry>) -> FrameId {
3089 choose|id: FrameId| !m.contains_key(id)
3090}
3091
3092pub proof fn lemma_fresh_vm_space_id_not_in_dom<'a>(m: Map<VmSpaceId, VmSpaceOwner>)
3093 ensures
3094 !m.contains_key(fresh_vm_space_id(m)),
3095{
3096 lemma_finite_int_set_has_unused(m.dom());
3097}
3098
3099pub proof fn lemma_fresh_cursor_id_not_in_dom<'rcu>(m: Map<CursorId, CursorEntry<'rcu>>)
3100 ensures
3101 !m.contains_key(fresh_cursor_id(m)),
3102{
3103 lemma_finite_int_set_has_unused(m.dom());
3104}
3105
3106pub proof fn lemma_fresh_vm_io_id_not_in_dom<'a>(m: Map<VmIoId, VmIoEntry>)
3107 ensures
3108 !m.contains_key(fresh_vm_io_id(m)),
3109{
3110 lemma_finite_int_set_has_unused(m.dom());
3111}
3112
3113pub proof fn lemma_fresh_frame_id_not_in_dom(m: Map<FrameId, FrameEntry>)
3114 ensures
3115 !m.contains_key(fresh_frame_id(m)),
3116{
3117 lemma_finite_int_set_has_unused(m.dom());
3118}
3119
3120pub proof fn tracked_cursor_entry_new<'rcu>(
3122 vm_space: VmSpaceId,
3123 kind: CursorKind,
3124 va: Range<Vaddr>,
3125 tracked owner: CursorOwner<'rcu, UserPtConfig>,
3126 tracked guards: Guards,
3127) -> (tracked res: CursorEntry<'rcu>)
3128 ensures
3129 res.vm_space == vm_space,
3130 res.kind == kind,
3131 res.va == va,
3132 res.owner == owner,
3133 res.guards == guards,
3134{
3135 let tracked res = CursorEntry { vm_space, kind, va, owner, guards };
3136 res
3137}
3138
3139pub proof fn tracked_vm_io_entry_new<'a>(
3141 vm_space: Option<VmSpaceId>,
3142 kind: VmIoKind,
3143 vaddr: Vaddr,
3144 len: usize,
3145 tracked owner: VmIoOwner,
3146) -> tracked VmIoEntry
3147 returns
3148 (VmIoEntry { vm_space, kind, vaddr, len, owner }),
3149{
3150 let tracked res = VmIoEntry { vm_space, kind, vaddr, len, owner };
3151 res
3152}
3153
3154pub proof fn tracked_frame_entry_new(paddr: Paddr) -> tracked FrameEntry
3156 returns
3157 (FrameEntry { paddr }),
3158{
3159 let tracked res = FrameEntry { paddr };
3160 res
3161}
3162
3163pub proof fn tracked_segment_entry_new(range: Range<Paddr>) -> tracked SegmentEntry
3165 returns
3166 (SegmentEntry { range }),
3167{
3168 let tracked res = SegmentEntry { range };
3169 res
3170}
3171
3172pub open spec fn fresh_segment_id(m: Map<SegmentId, SegmentEntry>) -> SegmentId {
3174 choose|id: SegmentId| !m.contains_key(id)
3175}
3176
3177pub proof fn lemma_fresh_segment_id_not_in_dom(m: Map<SegmentId, SegmentEntry>)
3178 ensures
3179 !m.contains_key(fresh_segment_id(m)),
3180{
3181 lemma_finite_int_set_has_unused(m.dom());
3182}
3183
3184pub proof fn tracked_unique_entry_new(paddr: Paddr) -> tracked UniqueEntry
3186 returns
3187 (UniqueEntry { paddr }),
3188{
3189 let tracked res = UniqueEntry { paddr };
3190 res
3191}
3192
3193pub open spec fn fresh_unique_id(m: Map<UniqueId, UniqueEntry>) -> UniqueId {
3195 choose|id: UniqueId| !m.contains_key(id)
3196}
3197
3198pub proof fn lemma_fresh_unique_id_not_in_dom(m: Map<UniqueId, UniqueEntry>)
3199 ensures
3200 !m.contains_key(fresh_unique_id(m)),
3201{
3202 lemma_finite_int_set_has_unused(m.dom());
3203}
3204
3205}