1use vstd::pervasive::arbitrary;
15use vstd::prelude::*;
16use vstd_extra::prelude::*;
17
18use vstd::raw_ptr;
19use vstd::set;
20
21use core::marker::PhantomData;
22use core::ops::Range;
23
24use crate::Pod;
25use crate::mm::{Paddr, PodOnce, Vaddr};
26use crate::specs::arch::MAX_PADDR;
27use crate::specs::mm::page_table::Mapping;
28use ostd_pod::{decode_pod, lemma_decode_pod_inverse, pod_bytes};
29
30verus! {
31
32pub struct VirtPtr {
42 pub vaddr: Vaddr,
44 pub range: Ghost<Range<Vaddr>>,
46}
47
48pub ghost struct FrameContents {
54 pub contents: Seq<raw_ptr::MemContents<u8>>,
56 pub size: usize,
58 pub range: Range<Paddr>,
60}
61
62impl Inv for FrameContents {
63 open spec fn inv(self) -> bool {
71 &&& self.contents.len() == self.size@
72 &&& self.size@ == self.range.end - self.range.start
73 &&& self.range.start % self.size == 0
74 &&& self.range.end % self.size == 0
75 &&& self.range.start <= self.range.end < MAX_PADDR
76 }
77}
78
79pub tracked struct MemView {
92 pub mappings: Set<Mapping>,
94 pub memory: Map<Paddr, FrameContents>,
96}
97
98impl MemView {
99 pub open spec fn addr_transl(self, va: usize) -> Option<(usize, usize)> {
103 let mappings = self.mappings.filter(|m: Mapping| m.va_range.start <= va < m.va_range.end);
104 if 0 < mappings.len() {
105 let m = mappings.choose(); let off = va - m.va_range.start;
107 Some((m.pa_range.start, off as usize))
108 } else {
109 None
110 }
111 }
112
113 pub open spec fn read(self, va: usize) -> raw_ptr::MemContents<u8> {
117 let (pa, off) = self.addr_transl(va)->0;
118 self.memory[pa].contents[off as int]
119 }
120
121 pub open spec fn write(self, va: usize, x: u8) -> Self {
125 let (pa, off) = self.addr_transl(va)->0;
126 MemView {
127 memory: self.memory.insert(
128 pa,
129 FrameContents {
130 contents: self.memory[pa].contents.update(
131 off as int,
132 raw_ptr::MemContents::Init(x),
133 ),
134 ..self.memory[pa]
135 },
136 ),
137 ..self
138 }
139 }
140
141 pub open spec fn write_bytes(self, va: usize, bytes: Seq<u8>) -> Self
145 decreases bytes.len(),
146 {
147 if bytes.len() == 0 {
148 self
149 } else {
150 self.write(va, bytes[0]).write_bytes((va + 1) as usize, bytes.drop_first())
151 }
152 }
153
154 pub open spec fn read_bytes(self, va: usize, len: usize) -> Seq<u8>
160 decreases len,
161 {
162 if len == 0 {
163 Seq::empty()
164 } else {
165 seq![self.read(va).value()].add(self.read_bytes((va + 1) as usize, (len - 1) as usize))
166 }
167 }
168
169 pub proof fn lemma_write_bytes_mappings(self, va: usize, bytes: Seq<u8>)
171 ensures
172 self.write_bytes(va, bytes).mappings == self.mappings,
173 decreases bytes.len(),
174 {
175 if bytes.len() > 0 {
176 self.write(va, bytes[0]).lemma_write_bytes_mappings(
177 (va + 1) as usize,
178 bytes.drop_first(),
179 );
180 }
181 }
182
183 pub proof fn lemma_write_bytes_addr_transl(self, va: usize, bytes: Seq<u8>, query: usize)
185 ensures
186 self.write_bytes(va, bytes).addr_transl(query) == self.addr_transl(query),
187 decreases bytes.len(),
188 {
189 if bytes.len() > 0 {
190 self.write(va, bytes[0]).lemma_write_bytes_addr_transl(
191 (va + 1) as usize,
192 bytes.drop_first(),
193 query,
194 );
195 }
196 }
197
198 pub proof fn lemma_write_bytes_memory_dom_grows(self, va: usize, bytes: Seq<u8>)
200 ensures
201 self.memory.dom().subset_of(self.write_bytes(va, bytes).memory.dom()),
202 decreases bytes.len(),
203 {
204 if bytes.len() > 0 {
205 self.write(va, bytes[0]).lemma_write_bytes_memory_dom_grows(
206 (va + 1) as usize,
207 bytes.drop_first(),
208 );
209 }
210 }
211
212 pub open spec fn eq_at(self, va1: usize, va2: usize) -> bool {
214 let (pa1, off1) = self.addr_transl(va1)->0;
215 let (pa2, off2) = self.addr_transl(va2)->0;
216 self.memory[pa1].contents[off1 as int] == self.memory[pa2].contents[off2 as int]
217 }
218
219 pub open spec fn is_mapped(self, va: usize, pa: usize) -> bool {
221 self.addr_transl(va) is Some && self.addr_transl(va)->Some_0.0 == pa
222 }
223
224 pub open spec fn borrow_at(&self, vaddr: usize, len: usize) -> MemView {
229 let range_end = vaddr + len;
230
231 let valid_pas = self.memory.dom().filter(
232 |pa: usize|
233 exists|va: usize| vaddr <= va < range_end && #[trigger] self.is_mapped(va, pa),
234 );
235
236 MemView {
237 mappings: self.mappings.filter(
238 |m: Mapping| m.va_range.start < range_end && m.va_range.end > vaddr,
239 ),
240 memory: self.memory.restrict(valid_pas),
241 }
242 }
243
244 pub open spec fn mappings_are_disjoint(self) -> bool {
246 forall|m1: Mapping, m2: Mapping|
247 #![trigger self.mappings.contains(m1), self.mappings.contains(m2)]
248 self.mappings.contains(m1) && self.mappings.contains(m2) && m1 != m2 ==> {
249 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start
250 }
251 }
252
253 pub open spec fn split(self, vaddr: usize, len: usize) -> (MemView, MemView) {
259 let split_end = vaddr + len;
260
261 let left_mappings = self.mappings.filter(
263 |m: Mapping| m.va_range.start < split_end && m.va_range.end > vaddr,
264 );
265 let right_mappings = self.mappings.filter(|m: Mapping| m.va_range.end > split_end);
266
267 let left_pas = self.memory.dom().filter(
268 |pa: usize| exists|va: usize| vaddr <= va < split_end && self.is_mapped(va, pa),
269 );
270 let right_pas = self.memory.dom().filter(
271 |pa: usize| exists|va: usize| va >= split_end && self.is_mapped(va, pa),
272 );
273
274 (
275 MemView { mappings: left_mappings, memory: self.memory.restrict(left_pas) },
276 MemView { mappings: right_mappings, memory: self.memory.restrict(right_pas) },
277 )
278 }
279
280 #[verifier::external_body]
287 pub proof fn tracked_borrow_at(tracked &self, vaddr: usize, len: usize) -> (tracked r: MemView)
288 ensures
289 r == self.borrow_at(vaddr, len),
290 {
291 unimplemented!()
292 }
293
294 #[verifier::external_body]
301 pub proof fn tracked_split(tracked self, vaddr: usize, len: usize) -> (tracked r: (Self, Self))
302 ensures
303 r == self.split(vaddr, len),
304 {
305 unimplemented!()
306 }
307
308 pub proof fn lemma_split_preserves_transl(
322 original: MemView,
323 vaddr: usize,
324 len: usize,
325 left: MemView,
326 right: MemView,
327 )
328 requires
329 original.split(vaddr, len) == (left, right),
330 ensures
331 right.memory.dom().subset_of(original.memory.dom()),
332 forall|va: usize|
333 vaddr <= va < vaddr + len ==> {
334 #[trigger] original.addr_transl(va) == left.addr_transl(va)
335 },
336 forall|va: usize|
337 va >= vaddr + len ==> {
338 #[trigger] original.addr_transl(va) == right.addr_transl(va)
339 },
340 {
341 assert forall|va: usize| vaddr <= va < vaddr + len implies original.addr_transl(va)
342 == left.addr_transl(va) by {
343 assert(left.mappings == original.mappings.filter(
344 |m: Mapping| m.va_range.start < vaddr + len && m.va_range.end > vaddr,
345 ));
346 let o_mappings = original.mappings.filter(
347 |m: Mapping| m.va_range.start <= va < m.va_range.end,
348 );
349 let l_mappings = left.mappings.filter(
350 |m: Mapping| m.va_range.start <= va < m.va_range.end,
351 );
352
353 assert forall|m: Mapping| #[trigger] o_mappings.contains(m) implies l_mappings.contains(
354 m,
355 ) by {
356 assert(left.mappings.contains(m));
357 };
358 assert(o_mappings == l_mappings);
359 }
360
361 assert forall|va: usize| va >= vaddr + len implies original.addr_transl(va)
362 == right.addr_transl(va) by {
363 let split_end = vaddr + len;
364
365 let o_mappings = original.mappings.filter(
366 |m: Mapping| m.va_range.start <= va < m.va_range.end,
367 );
368 let r_mappings = right.mappings.filter(
369 |m: Mapping| m.va_range.start <= va < m.va_range.end,
370 );
371
372 assert forall|m: Mapping| o_mappings.contains(m) implies r_mappings.contains(m) by {
373 assert(right.mappings.contains(m));
374 assert(r_mappings.contains(m));
375 }
376
377 assert(o_mappings == r_mappings);
378 }
379 }
380
381 pub open spec fn join(self, other: MemView) -> MemView {
386 MemView {
387 mappings: self.mappings.union(other.mappings),
388 memory: self.memory.union_prefer_right(other.memory),
389 }
390 }
391
392 #[verifier::external_body]
402 pub proof fn tracked_join(tracked &mut self, tracked other: Self)
403 requires
404 old(self).mappings.disjoint(other.mappings),
405 ensures
406 *final(self) == old(self).join(other),
407 {
408 unimplemented!()
409 }
410
411 pub proof fn lemma_split_join_identity(
424 this: MemView,
425 lhs: MemView,
426 rhs: MemView,
427 vaddr: usize,
428 len: usize,
429 )
430 requires
431 this.split(vaddr, len) == (lhs, rhs),
432 forall|m: Mapping| #[trigger]
433 this.mappings.contains(m) ==> vaddr <= m.va_range.start < m.va_range.end,
434 forall|pa: Paddr| #[trigger]
435 this.memory.contains_key(pa) ==> exists|va: usize|
436 vaddr <= va && #[trigger] this.is_mapped(va, pa),
437 ensures
438 this.mappings == lhs.join(rhs).mappings,
439 this.memory == lhs.join(rhs).memory,
440 {
441 }
442
443 pub proof fn lemma_split_preserves_read(
452 original: MemView,
453 vaddr: usize,
454 len: usize,
455 left: MemView,
456 right: MemView,
457 )
458 requires
459 original.split(vaddr, len) == (left, right),
460 ensures
461 forall|va: usize|
462 #![trigger original.read(va)]
463 va >= vaddr + len && original.addr_transl(va) is Some
464 && original.memory.contains_key((original.addr_transl(va)->0).0)
465 ==> original.read(va) == right.read(va),
466 {
467 Self::lemma_split_preserves_transl(original, vaddr, len, left, right);
468 let split_end = vaddr + len;
469 let right_pas = original.memory.dom().filter(
470 |pa: usize| exists|va: usize| va >= split_end && original.is_mapped(va, pa),
471 );
472 assert forall|va: usize|
473 va >= split_end && original.addr_transl(va) is Some && original.memory.contains_key(
474 original.addr_transl(va).unwrap().0,
475 ) implies #[trigger] original.read(va) == right.read(va) by {
476 assert(original.addr_transl(va) == right.addr_transl(va));
477 let pa = original.addr_transl(va).unwrap().0;
478 assert(original.is_mapped(va, pa));
479 assert(right_pas.contains(pa));
480 assert(right.memory[pa] == original.memory[pa]);
481 }
482 }
483
484 pub proof fn lemma_read_bytes_eq_pointwise(a: MemView, b: MemView, va: usize, n: usize)
486 requires
487 forall|i: usize| va <= i < va + n ==> a.read(i) == b.read(i),
488 va + n <= usize::MAX,
489 ensures
490 a.read_bytes(va, n) == b.read_bytes(va, n),
491 decreases n,
492 {
493 if n == 0 {
494 return;
495 }
496 Self::lemma_read_bytes_eq_pointwise(a, b, (va + 1) as usize, (n - 1) as usize);
497 }
498}
499
500impl Inv for VirtPtr {
501 open spec fn inv(self) -> bool {
502 &&& self.range@.start <= self.vaddr <= self.range@.end
503 &&& self.range@.end >= self.range@.start
504 }
505}
506
507impl Clone for VirtPtr {
508 fn clone(&self) -> (res: Self)
509 ensures
510 res == self,
511 {
512 Self { vaddr: self.vaddr, range: Ghost(self.range@) }
513 }
514}
515
516impl Copy for VirtPtr {
517
518}
519
520impl VirtPtr {
521 #[vstd::contrib::auto_spec]
523 pub fn new(vaddr: Vaddr, len: usize) -> Self {
524 Self { vaddr, range: Ghost(Range { start: vaddr, end: (vaddr + len) as usize }) }
525 }
526
527 pub open spec fn is_defined(self) -> bool {
529 self.range@.start <= self.vaddr <= self.range@.end
530 }
531
532 pub open spec fn is_valid(self) -> bool {
536 &&& self.is_defined()
537 &&& self.vaddr < self.range@.end
538 }
539
540 #[verifier::external_body]
553 pub fn read(self, Tracked(mem): Tracked<&MemView>) -> u8
554 requires
555 mem.addr_transl(self.vaddr) is Some,
556 mem.memory[(mem.addr_transl(self.vaddr)->0).0].contents[(mem.addr_transl(
557 self.vaddr,
558 )->0).1 as int] is Init,
559 self.is_valid(),
560 returns
561 mem.read(self.vaddr).value(),
562 {
563 unimplemented!()
564 }
565
566 #[verifier::external_body]
577 pub fn write(self, Tracked(mem): Tracked<&mut MemView>, x: u8)
578 requires
579 old(mem).addr_transl(self.vaddr) is Some,
580 self.is_valid(),
581 ensures
582 *final(mem) == old(mem).write(self.vaddr, x),
583 {
584 unimplemented!()
585 }
586
587 #[verifier::external_body]
601 pub fn read_volatile<T: PodOnce>(self, Tracked(mem): Tracked<&MemView>) -> (val: T)
602 requires
603 self.inv(),
604 core::mem::size_of::<T>() <= self.range@.end - self.vaddr,
605 self.vaddr % core::mem::align_of::<T>() == 0,
606 forall|i: usize|
607 #![trigger mem.addr_transl(i)]
608 self.vaddr <= i < self.vaddr + core::mem::size_of::<T>() ==> {
609 &&& mem.addr_transl(i) is Some
610 &&& mem.memory.contains_key((mem.addr_transl(i)->0).0)
611 &&& mem.memory[(mem.addr_transl(i)->0).0].contents[(mem.addr_transl(
612 i,
613 )->0).1 as int] is Init
614 },
615 ensures
616 pod_bytes(val) == mem.read_bytes(self.vaddr, core::mem::size_of::<T>()),
617 {
618 let pnt = self.vaddr as *const T;
619 unsafe { pnt.read_volatile() }
620 }
621
622 #[verifier::external_body]
648 pub fn write_volatile<T: Pod>(self, Tracked(mem): Tracked<&mut MemView>, val: T)
649 requires
650 self.inv(),
651 core::mem::size_of::<T>() <= self.range@.end - self.vaddr,
652 self.vaddr % core::mem::align_of::<T>() == 0,
653 forall|i: usize|
654 #![trigger old(mem).addr_transl(i)]
655 self.vaddr <= i < self.vaddr + core::mem::size_of::<T>() ==> {
656 &&& old(mem).addr_transl(i) is Some
657 },
658 ensures
659 *final(mem) == old(mem).write_bytes(self.vaddr, pod_bytes(val)),
660 final(mem).mappings == old(mem).mappings,
661 old(mem).memory.dom().subset_of(final(mem).memory.dom()),
662 forall|va: usize|
663 #![trigger final(mem).addr_transl(va)]
664 old(mem).addr_transl(va) == final(mem).addr_transl(va),
665 {
666 let pnt = self.vaddr as *mut T;
667 unsafe { pnt.write_volatile(val) }
668 }
669
670 pub open spec fn add_spec(self, n: usize) -> Self {
671 VirtPtr { vaddr: (self.vaddr + n) as usize, range: self.range }
672 }
673
674 pub fn add(&mut self, n: usize)
686 requires
687 0 <= old(self).vaddr + n < usize::MAX,
692 ensures
693 *final(self) == old(self).add_spec(
694 n,
695 ),
696 {
700 self.vaddr = self.vaddr + n
701 }
702
703 pub open spec fn sub_spec(self, n: usize) -> Self {
704 VirtPtr { vaddr: (self.vaddr - n) as usize, range: self.range }
705 }
706
707 pub fn sub(self, n: usize) -> (res: Self)
720 requires
721 n <= self.vaddr,
722 returns
723 self.sub_spec(n),
724 {
725 VirtPtr { vaddr: self.vaddr - n, range: self.range }
726 }
727
728 pub open spec fn wrapping_add_spec(self, n: usize) -> Self {
729 VirtPtr { vaddr: self.vaddr.wrapping_add(n), range: self.range }
730 }
731
732 pub fn wrapping_add(self, n: usize) -> (res: Self)
735 returns
736 self.wrapping_add_spec(n),
737 {
738 VirtPtr { vaddr: self.vaddr.wrapping_add(n), range: self.range }
739 }
740
741 #[verifier::external_body]
748 pub fn cast<T>(self) -> (res: *mut T)
749 ensures
750 res as usize == self.vaddr,
751 {
752 self.vaddr as *mut T
753 }
754
755 pub open spec fn read_offset_spec(self, mem: MemView, n: usize) -> u8 {
756 mem.read((self.vaddr + n) as usize).value()
757 }
758
759 pub fn read_offset(&self, Tracked(mem): Tracked<&MemView>, n: usize) -> u8
775 requires
776 self.vaddr + n < usize::MAX,
777 self.range@.start <= self.vaddr + n < self.range@.end,
778 mem.addr_transl((self.vaddr + n) as usize) is Some,
779 mem.memory[(mem.addr_transl((self.vaddr + n) as usize)->0).0].contents[(mem.addr_transl(
780 (self.vaddr + n) as usize,
781 )->0).1 as int] is Init,
782 returns
783 self.read_offset_spec(*mem, n),
784 {
785 let mut tmp = self.clone();
786 tmp.add(n);
787 tmp.read(Tracked(mem))
788 }
789
790 pub open spec fn write_offset_spec(self, mem: MemView, n: usize, x: u8) -> MemView {
791 mem.write((self.vaddr + n) as usize, x)
792 }
793
794 pub fn write_offset(&self, Tracked(mem): Tracked<&mut MemView>, n: usize, x: u8)
803 requires
804 self.inv(),
805 self.vaddr + n < usize::MAX,
806 self.range@.start <= self.vaddr + n < self.range@.end,
807 old(mem).addr_transl((self.vaddr + n) as usize) is Some,
808 ensures
809 *final(mem) == self.write_offset_spec(*old(mem), n, x),
810 {
811 let mut tmp = self.clone();
812 tmp.add(n);
813 tmp.write(Tracked(mem), x)
814 }
815
816 pub open spec fn copy_offset_spec(
817 src: Self,
818 dst: Self,
819 mem_src: MemView,
820 mem_dst: MemView,
821 n: usize,
822 ) -> MemView {
823 let x = src.read_offset_spec(mem_src, n);
824 dst.write_offset_spec(mem_dst, n, x)
825 }
826
827 pub fn copy_offset(
844 src: &Self,
845 dst: &Self,
846 Tracked(mem_src): Tracked<&MemView>,
847 Tracked(mem_dst): Tracked<&mut MemView>,
848 n: usize,
849 )
850 requires
851 src.inv(),
852 dst.inv(),
853 src.vaddr + n < usize::MAX,
854 dst.vaddr + n < usize::MAX,
855 src.range@.start <= src.vaddr + n < src.range@.end,
856 mem_src.addr_transl((src.vaddr + n) as usize) is Some,
857 mem_src.memory.contains_key((mem_src.addr_transl((src.vaddr + n) as usize)->0).0),
858 mem_src.memory[(mem_src.addr_transl((src.vaddr + n) as usize)->0).0].contents[(
859 mem_src.addr_transl((src.vaddr + n) as usize)->0).1 as int] is Init,
860 dst.range@.start <= dst.vaddr + n < dst.range@.end,
861 old(mem_dst).addr_transl((dst.vaddr + n) as usize) is Some,
862 ensures
863 *final(mem_dst) == Self::copy_offset_spec(*src, *dst, *mem_src, *old(mem_dst), n),
864 final(mem_dst).mappings == old(mem_dst).mappings,
865 old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
866 {
867 let x = src.read_offset(Tracked(mem_src), n);
868 dst.write_offset(Tracked(mem_dst), n, x)
869 }
870
871 pub open spec fn memcpy_spec(
872 src: Self,
873 dst: Self,
874 mem_src: MemView,
875 mem_dst: MemView,
876 n: usize,
877 ) -> MemView
878 decreases n,
879 {
880 if n == 0 {
881 mem_dst
882 } else {
883 let mem_dst_1 = Self::copy_offset_spec(src, dst, mem_src, mem_dst, (n - 1) as usize);
884
885 Self::memcpy_spec(src, dst, mem_src, mem_dst_1, (n - 1) as usize)
886 }
887 }
888
889 pub fn copy_nonoverlapping(
909 src: &Self,
910 dst: &Self,
911 Tracked(mem_src): Tracked<&MemView>,
912 Tracked(mem_dst): Tracked<&mut MemView>,
913 n: usize,
914 )
915 requires
916 src.inv(),
917 dst.inv(),
918 src.range@.start <= src.vaddr,
919 src.vaddr + n <= src.range@.end,
920 forall|i: usize|
921 #![trigger mem_src.addr_transl(i)]
922 src.vaddr <= i < src.vaddr + n ==> {
923 &&& mem_src.addr_transl(i) is Some
924 &&& mem_src.memory.contains_key((mem_src.addr_transl(i)->0).0)
925 &&& mem_src.memory[(mem_src.addr_transl(i)->0).0].contents[(mem_src.addr_transl(
926 i,
927 )->0).1 as int] is Init
928 },
929 dst.range@.start <= dst.vaddr,
930 dst.vaddr + n <= dst.range@.end,
931 forall|i: usize|
932 dst.vaddr <= i < dst.vaddr + n ==> {
933 &&& old(mem_dst).addr_transl(i) is Some
934 },
935 ensures
936 *final(mem_dst) == Self::memcpy_spec(*src, *dst, *mem_src, *old(mem_dst), n),
937 final(mem_dst).mappings == old(mem_dst).mappings,
938 old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
940 forall|i: usize|
941 #![trigger final(mem_dst).addr_transl(i)]
942 dst.vaddr <= i < dst.vaddr + n ==> {
943 &&& final(mem_dst).addr_transl(i) is Some
944 },
945 decreases n,
946 {
947 if n == 0 {
948 return;
949 } else {
950 let ghost mem0 = *mem_dst;
951
952 Self::copy_offset(src, dst, Tracked(mem_src), Tracked(mem_dst), n - 1);
953
954 proof {
955 assert(forall|i: usize|
956 dst.vaddr <= i < dst.vaddr + n - 1 ==> mem_dst.addr_transl(i)
957 == #[trigger] mem0.addr_transl(i));
958 assert forall|i: usize|
959 dst.vaddr <= i < dst.vaddr + n - 1 implies mem_dst.addr_transl(i) is Some by {
960 assert(mem_dst.addr_transl(i) == mem0.addr_transl(i));
961 }
962 }
963
964 Self::copy_nonoverlapping(src, dst, Tracked(mem_src), Tracked(mem_dst), n - 1);
965 }
966 }
967
968 pub fn from_vaddr(vaddr: usize, len: usize) -> (r: Self)
980 requires
981 len <= usize::MAX - vaddr,
982 ensures
983 r.inv(),
984 r.vaddr == vaddr,
985 r.range@.start == vaddr,
986 r.range@.end == (vaddr + len) as usize,
987 len > 0 ==> r.is_valid(),
988 {
989 Self { vaddr, range: Ghost(Range { start: vaddr, end: (vaddr + len) as usize }) }
990 }
991
992 #[verus_spec(r =>
1007 requires
1008 self.is_valid(),
1009 0 <= n <= self.range@.end - self.range@.start,
1010 self.vaddr == self.range@.start,
1011 ensures
1012 r.0.range@.start == self.range@.start,
1013 r.0.range@.end == self.range@.start + n,
1014 r.0.vaddr == self.range@.start,
1015 r.1.range@.start == self.range@.start + n,
1016 r.1.range@.end == self.range@.end,
1017 r.1.vaddr == self.range@.start + n,
1018 )]
1019 pub fn split(self, n: usize) -> (Self, Self) {
1020 let left = VirtPtr {
1021 vaddr: self.vaddr,
1022 range: Ghost(Range { start: self.vaddr, end: (self.vaddr + n) as usize }),
1023 };
1024
1025 let right = VirtPtr {
1026 vaddr: self.vaddr + n,
1027 range: Ghost(Range { start: (self.vaddr + n) as usize, end: self.range@.end }),
1028 };
1029
1030 (left, right)
1031 }
1032
1033 pub fn addr(&self) -> Vaddr
1034 returns
1035 self.vaddr,
1036 {
1037 self.vaddr
1038 }
1039}
1040
1041pub tracked struct GlobalMemView {
1044 pub pt_mappings: Set<Mapping>,
1045 pub tlb_mappings: Set<Mapping>,
1046 pub unmapped_pas: Set<Paddr>,
1047 pub memory: Map<Paddr, FrameContents>,
1048}
1049
1050impl Inv for GlobalMemView {
1051 open spec fn inv(self) -> bool {
1052 &&& forall|m: Mapping|
1053 #![auto]
1054 self.tlb_mappings.contains(m) ==> {
1055 &&& m.inv()
1056 &&& forall|pa: Paddr|
1057 m.pa_range.start <= pa < m.pa_range.end ==> {
1058 &&& self.memory.dom().contains(pa)
1059 }
1060 &&& self.memory.contains_key(m.pa_range.start)
1061 &&& self.memory[m.pa_range.start].size == m.page_size
1062 &&& self.memory[m.pa_range.start].inv()
1063 }
1064 &&& forall|m: Mapping|
1065 forall|n: Mapping|
1066 #![auto]
1067 self.tlb_mappings.contains(m) ==> self.tlb_mappings.contains(n) ==> m != n
1068 ==> #[trigger] m.va_range.end <= n.va_range.start || n.va_range.end
1069 <= m.va_range.start
1070 &&& self.all_pas_accounted_for()
1071 &&& self.pas_uniquely_mapped()
1072 &&& self.unmapped_correct()
1073 }
1074}
1075
1076impl GlobalMemView {
1077 pub open spec fn addr_transl(self, va: usize) -> Option<(usize, usize)> {
1078 let mappings = self.tlb_mappings.filter(
1079 |m: Mapping| m.va_range.start <= va < m.va_range.end,
1080 );
1081 if 0 < mappings.len() {
1082 let m = mappings.choose(); let off = va - m.va_range.start;
1084 Some((m.pa_range.start, off as usize))
1085 } else {
1086 None
1087 }
1088 }
1089
1090 pub open spec fn is_mapped(self, pa: usize) -> bool {
1091 exists|m: Mapping| self.tlb_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end
1092 }
1093
1094 pub open spec fn all_pas_accounted_for(self) -> bool {
1095 forall|pa: Paddr|
1096 0 <= pa < MAX_PADDR ==> #[trigger] self.is_mapped(pa)
1097 || #[trigger] self.unmapped_pas.contains(pa)
1098 }
1099
1100 pub open spec fn pas_uniquely_mapped(self) -> bool {
1101 forall|m1: Mapping, m2: Mapping|
1102 #![trigger self.tlb_mappings.contains(m1), self.tlb_mappings.contains(m2)]
1103 self.tlb_mappings.contains(m1) && self.tlb_mappings.contains(m2) && m1 != m2
1104 ==> m1.pa_range.end <= m2.pa_range.start || m2.pa_range.end <= m1.pa_range.start
1105 }
1106
1107 pub open spec fn unmapped_correct(self) -> bool {
1108 forall|pa: Paddr| #![auto] self.is_mapped(pa) <==> !self.unmapped_pas.contains(pa)
1109 }
1110
1111 pub open spec fn take_view(self, vaddr: usize, len: usize) -> (Self, MemView) {
1112 let range_end = vaddr + len;
1113
1114 let leave_mappings: Set<Mapping> = self.tlb_mappings.filter(
1115 |m: Mapping| m.va_range.end <= vaddr || m.va_range.start > range_end,
1116 );
1117
1118 let take_mappings = self.tlb_mappings.filter(
1119 |m: Mapping| m.va_range.start < range_end && m.va_range.end > vaddr,
1120 );
1121
1122 let leave_pas = self.memory.dom().filter(
1123 |pa: usize|
1124 exists|m: Mapping|
1125 leave_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end,
1126 );
1127 let take_pas = self.memory.dom().filter(
1128 |pa: usize|
1129 exists|m: Mapping|
1130 take_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end,
1131 );
1132
1133 (
1134 GlobalMemView {
1135 tlb_mappings: leave_mappings,
1136 memory: self.memory.restrict(leave_pas),
1137 ..self
1138 },
1139 MemView { mappings: take_mappings, memory: self.memory.restrict(take_pas) },
1140 )
1141 }
1142
1143 pub axiom fn tracked_take_view(tracked &mut self, vaddr: usize, len: usize) -> (tracked view:
1144 MemView)
1145 ensures
1146 *final(self) == old(self).take_view(vaddr, len).0,
1147 view == old(self).take_view(vaddr, len).1,
1148 ;
1149
1150 pub open spec fn return_view(self, view: MemView) -> Self {
1151 GlobalMemView {
1152 tlb_mappings: self.tlb_mappings.union(view.mappings),
1153 memory: self.memory.union_prefer_right(view.memory),
1154 ..self
1155 }
1156 }
1157
1158 pub axiom fn tracked_return_view(&mut self, view: MemView)
1159 ensures
1160 *final(self) == old(self).return_view(view),
1161 ;
1162
1163 pub open spec fn tlb_flush_vaddr(self, vaddr: Vaddr) -> Self {
1164 let tlb_mappings = self.tlb_mappings.filter(
1165 |m: Mapping| m.va_range.end <= vaddr || vaddr < m.va_range.start,
1166 );
1167 GlobalMemView { tlb_mappings, ..self }
1168 }
1169
1170 pub axiom fn tracked_tlb_flush_vaddr(&mut self, vaddr: Vaddr)
1171 requires
1172 old(self).inv(),
1173 ensures
1174 *final(self) == old(self).tlb_flush_vaddr(vaddr),
1175 final(self).inv(),
1176 ;
1177
1178 pub open spec fn tlb_soft_fault(self, vaddr: Vaddr) -> Self {
1179 let mapping = self.pt_mappings.filter(
1180 |m: Mapping| m.va_range.start <= vaddr < m.va_range.end,
1181 ).choose();
1182 GlobalMemView { tlb_mappings: self.tlb_mappings.insert(mapping), ..self }
1183 }
1184
1185 pub axiom fn tracked_tlb_soft_fault(tracked &mut self, vaddr: Vaddr)
1186 requires
1187 old(self).inv(),
1188 old(self).addr_transl(vaddr) is None,
1189 ensures
1190 *final(self) == old(self).tlb_soft_fault(vaddr),
1191 final(self).inv(),
1192 ;
1193
1194 pub open spec fn pt_map(self, m: Mapping) -> Self {
1195 let pt_mappings = self.pt_mappings.insert(m);
1196 let unmapped_pas = self.unmapped_pas.difference(
1197 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1198 );
1199 GlobalMemView { pt_mappings, unmapped_pas, ..self }
1200 }
1201
1202 pub axiom fn tracked_pt_map(&mut self, m: Mapping)
1203 requires
1204 forall|pa: Paddr|
1205 m.pa_range.start <= pa < m.pa_range.end ==> old(self).unmapped_pas.contains(pa),
1206 old(self).inv(),
1207 ensures
1208 *final(self) == old(self).pt_map(m),
1209 ;
1210
1211 pub open spec fn pt_unmap(self, m: Mapping) -> Self {
1212 let pt_mappings = self.pt_mappings.remove(m);
1213 let unmapped_pas = self.unmapped_pas.union(
1214 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1215 );
1216 GlobalMemView { pt_mappings, unmapped_pas, ..self }
1217 }
1218
1219 pub axiom fn tracked_pt_unmap(&mut self, m: Mapping)
1220 requires
1221 old(self).pt_mappings.contains(m),
1222 old(self).inv(),
1223 ensures
1224 *final(self) == old(self).pt_unmap(m),
1225 final(self).inv(),
1226 ;
1227
1228 pub proof fn lemma_va_mapping_unique(self, va: usize)
1229 requires
1230 self.inv(),
1231 self.addr_transl(va) is Some,
1233 ensures
1234 self.tlb_mappings.filter(
1235 |m: Mapping| m.va_range.start <= va < m.va_range.end,
1236 ).is_singleton(),
1237 {
1238 let f = self.tlb_mappings.filter(|m: Mapping| m.va_range.start <= va < m.va_range.end);
1239 assert(f.len() > 0);
1241 assert forall|m: Mapping, n: Mapping| f.contains(m) && f.contains(n) implies m == n by {
1244 assert(self.tlb_mappings.contains(m));
1245 assert(self.tlb_mappings.contains(n));
1246 assert(m.va_range.start <= va < m.va_range.end);
1247 assert(n.va_range.start <= va < n.va_range.end);
1248 };
1250 }
1251}
1252
1253}