1use vstd::{pervasive::arbitrary, prelude::*, raw_ptr, set};
15use vstd_extra::prelude::*;
16
17use crate::specs::{arch::MAX_PADDR, mm::page_table::Mapping};
18
19use crate::Pod;
20use crate::mm::{Paddr, PodOnce, Vaddr};
21use core::{marker::PhantomData, ops::Range};
22use ostd_pod::{decode_pod, pod_bytes};
23
24verus! {
25
26pub struct VirtPtr {
36 pub vaddr: Vaddr,
38 pub range: Ghost<Range<Vaddr>>,
40}
41
42pub ghost struct FrameContents {
48 pub contents: Seq<raw_ptr::MemContents<u8>>,
50 pub size: usize,
52 pub range: Range<Paddr>,
54}
55
56impl Inv for FrameContents {
57 open spec fn inv(self) -> bool {
65 &&& self.contents.len() == self.size@
66 &&& self.size@ == self.range.end - self.range.start
67 &&& self.range.start % self.size == 0
68 &&& self.range.end % self.size == 0
69 &&& self.range.start <= self.range.end < MAX_PADDR
70 }
71}
72
73pub tracked struct MemView {
86 pub ghost mappings: Set<Mapping>,
88 pub memory: Map<Paddr, FrameContents>,
90}
91
92impl MemView {
93 pub open spec fn addr_transl(self, va: usize) -> Option<(usize, usize)> {
97 let mappings = self.mappings.filter(|m: Mapping| m.va_range.start <= va < m.va_range.end);
98 if 0 < mappings.len() {
99 let m = mappings.choose(); let off = va - m.va_range.start;
101 Some((m.pa_range.start, off as usize))
102 } else {
103 None
104 }
105 }
106
107 pub open spec fn read(self, va: usize) -> raw_ptr::MemContents<u8> {
111 let (pa, off) = self.addr_transl(va)->0;
112 self.memory[pa].contents[off as int]
113 }
114
115 pub open spec fn write(self, va: usize, x: u8) -> Self {
119 let (pa, off) = self.addr_transl(va)->0;
120 MemView {
121 memory: self.memory.insert(
122 pa,
123 FrameContents {
124 contents: self.memory[pa].contents.update(
125 off as int,
126 raw_ptr::MemContents::Init(x),
127 ),
128 ..self.memory[pa]
129 },
130 ),
131 ..self
132 }
133 }
134
135 pub open spec fn write_bytes(self, va: usize, bytes: Seq<u8>) -> Self
139 decreases bytes.len(),
140 {
141 if bytes.len() == 0 {
142 self
143 } else {
144 self.write(va, bytes[0]).write_bytes((va + 1) as usize, bytes.drop_first())
145 }
146 }
147
148 pub open spec fn read_bytes(self, va: usize, len: usize) -> Seq<u8>
154 decreases len,
155 {
156 if len == 0 {
157 Seq::empty()
158 } else {
159 seq![self.read(va).value()].add(self.read_bytes((va + 1) as usize, (len - 1) as usize))
160 }
161 }
162
163 pub proof fn lemma_write_bytes_mappings(self, va: usize, bytes: Seq<u8>)
165 ensures
166 self.write_bytes(va, bytes).mappings == self.mappings,
167 decreases bytes.len(),
168 {
169 if bytes.len() > 0 {
170 self.write(va, bytes[0]).lemma_write_bytes_mappings(
171 (va + 1) as usize,
172 bytes.drop_first(),
173 );
174 }
175 }
176
177 pub proof fn lemma_write_bytes_addr_transl(self, va: usize, bytes: Seq<u8>, query: usize)
179 ensures
180 self.write_bytes(va, bytes).addr_transl(query) == self.addr_transl(query),
181 decreases bytes.len(),
182 {
183 if bytes.len() > 0 {
184 self.write(va, bytes[0]).lemma_write_bytes_addr_transl(
185 (va + 1) as usize,
186 bytes.drop_first(),
187 query,
188 );
189 }
190 }
191
192 pub proof fn lemma_write_bytes_memory_dom_grows(self, va: usize, bytes: Seq<u8>)
194 ensures
195 self.memory.dom().subset_of(self.write_bytes(va, bytes).memory.dom()),
196 decreases bytes.len(),
197 {
198 if bytes.len() > 0 {
199 self.write(va, bytes[0]).lemma_write_bytes_memory_dom_grows(
200 (va + 1) as usize,
201 bytes.drop_first(),
202 );
203 }
204 }
205
206 pub open spec fn is_mapped(self, va: usize, pa: usize) -> bool {
208 self.addr_transl(va) is Some && self.addr_transl(va)->Some_0.0 == pa
209 }
210
211 pub open spec fn borrow_at(&self, vaddr: usize, len: usize) -> MemView {
216 let range_end = vaddr + len;
217
218 let valid_pas = self.memory.dom().filter(
219 |pa: usize|
220 exists|va: usize| vaddr <= va < range_end && #[trigger] self.is_mapped(va, pa),
221 );
222
223 MemView {
224 mappings: self.mappings.filter(
225 |m: Mapping| m.va_range.start < range_end && m.va_range.end > vaddr,
226 ),
227 memory: self.memory.restrict(valid_pas),
228 }
229 }
230
231 pub open spec fn split(self, vaddr: usize, len: usize) -> (MemView, MemView) {
237 let split_end = vaddr + len;
238
239 let left_mappings = self.mappings.filter(
241 |m: Mapping| m.va_range.start < split_end && m.va_range.end > vaddr,
242 );
243 let right_mappings = self.mappings.filter(|m: Mapping| m.va_range.end > split_end);
244
245 let left_pas = self.memory.dom().filter(
246 |pa: usize| exists|va: usize| vaddr <= va < split_end && self.is_mapped(va, pa),
247 );
248 let right_pas = self.memory.dom().filter(
249 |pa: usize| exists|va: usize| va >= split_end && self.is_mapped(va, pa),
250 );
251
252 (
253 MemView { mappings: left_mappings, memory: self.memory.restrict(left_pas) },
254 MemView { mappings: right_mappings, memory: self.memory.restrict(right_pas) },
255 )
256 }
257
258 #[verifier::external_body]
265 pub proof fn tracked_borrow_at(tracked &self, vaddr: usize, len: usize) -> (tracked r: MemView)
266 ensures
267 r == self.borrow_at(vaddr, len),
268 {
269 unimplemented!()
270 }
271
272 #[verifier::external_body]
279 pub proof fn tracked_split(tracked self, vaddr: usize, len: usize) -> (tracked r: (Self, Self))
280 ensures
281 r == self.split(vaddr, len),
282 {
283 unimplemented!()
284 }
285
286 pub proof fn lemma_split_preserves_transl(
300 original: MemView,
301 vaddr: usize,
302 len: usize,
303 left: MemView,
304 right: MemView,
305 )
306 requires
307 original.split(vaddr, len) == (left, right),
308 ensures
309 right.memory.dom().subset_of(original.memory.dom()),
310 forall|va: usize|
311 vaddr <= va < vaddr + len ==> {
312 #[trigger] original.addr_transl(va) == left.addr_transl(va)
313 },
314 forall|va: usize|
315 va >= vaddr + len ==> {
316 #[trigger] original.addr_transl(va) == right.addr_transl(va)
317 },
318 {
319 assert forall|va: usize| vaddr <= va < vaddr + len implies original.addr_transl(va)
320 == left.addr_transl(va) by {
321 assert(left.mappings == original.mappings.filter(
322 |m: Mapping| m.va_range.start < vaddr + len && m.va_range.end > vaddr,
323 ));
324 let o_mappings = original.mappings.filter(
325 |m: Mapping| m.va_range.start <= va < m.va_range.end,
326 );
327 let l_mappings = left.mappings.filter(
328 |m: Mapping| m.va_range.start <= va < m.va_range.end,
329 );
330
331 assert forall|m: Mapping| #[trigger] o_mappings.contains(m) implies l_mappings.contains(
332 m,
333 ) by {
334 assert(left.mappings.contains(m));
335 };
336 assert(o_mappings == l_mappings);
337 }
338
339 assert forall|va: usize| va >= vaddr + len implies original.addr_transl(va)
340 == right.addr_transl(va) by {
341 let split_end = vaddr + len;
342
343 let o_mappings = original.mappings.filter(
344 |m: Mapping| m.va_range.start <= va < m.va_range.end,
345 );
346 let r_mappings = right.mappings.filter(
347 |m: Mapping| m.va_range.start <= va < m.va_range.end,
348 );
349
350 assert forall|m: Mapping| o_mappings.contains(m) implies r_mappings.contains(m) by {
351 assert(right.mappings.contains(m));
352 assert(r_mappings.contains(m));
353 }
354
355 assert(o_mappings == r_mappings);
356 }
357 }
358
359 pub open spec fn join(self, other: MemView) -> MemView {
364 MemView {
365 mappings: self.mappings.union(other.mappings),
366 memory: self.memory.union_prefer_right(other.memory),
367 }
368 }
369
370 pub proof fn tracked_join(tracked &mut self, tracked other: Self)
380 requires
381 old(self).mappings.disjoint(other.mappings),
382 ensures
383 *final(self) == old(self).join(other),
384 {
385 self.mappings = self.mappings.union(other.mappings);
386 self.memory.tracked_union_prefer_right(other.memory);
387 }
388
389 pub proof fn lemma_split_join_identity(
402 this: MemView,
403 lhs: MemView,
404 rhs: MemView,
405 vaddr: usize,
406 len: usize,
407 )
408 requires
409 this.split(vaddr, len) == (lhs, rhs),
410 forall|m: Mapping| #[trigger]
411 this.mappings.contains(m) ==> vaddr <= m.va_range.start < m.va_range.end,
412 forall|pa: Paddr| #[trigger]
413 this.memory.contains_key(pa) ==> exists|va: usize|
414 vaddr <= va && #[trigger] this.is_mapped(va, pa),
415 ensures
416 this.mappings == lhs.join(rhs).mappings,
417 this.memory == lhs.join(rhs).memory,
418 {
419 }
420
421 pub proof fn lemma_split_preserves_read(
430 original: MemView,
431 vaddr: usize,
432 len: usize,
433 left: MemView,
434 right: MemView,
435 )
436 requires
437 original.split(vaddr, len) == (left, right),
438 ensures
439 forall|va: usize|
440 #![trigger original.read(va)]
441 va >= vaddr + len && original.addr_transl(va) is Some
442 && original.memory.contains_key((original.addr_transl(va)->0).0)
443 ==> original.read(va) == right.read(va),
444 {
445 Self::lemma_split_preserves_transl(original, vaddr, len, left, right);
446 let split_end = vaddr + len;
447 assert forall|va: usize|
448 va >= split_end && original.addr_transl(va) is Some && original.memory.contains_key(
449 original.addr_transl(va).unwrap().0,
450 ) implies #[trigger] original.read(va) == right.read(va) by {
451 let pa = original.addr_transl(va).unwrap().0;
452 assert(original.is_mapped(va, pa));
453
454 }
455 }
456
457 pub proof fn lemma_read_bytes_eq_pointwise(a: MemView, b: MemView, va: usize, n: usize)
459 requires
460 forall|i: usize| va <= i < va + n ==> a.read(i) == b.read(i),
461 va + n <= usize::MAX,
462 ensures
463 a.read_bytes(va, n) == b.read_bytes(va, n),
464 decreases n,
465 {
466 if n == 0 {
467 return;
468 }
469 Self::lemma_read_bytes_eq_pointwise(a, b, (va + 1) as usize, (n - 1) as usize);
470 }
471}
472
473impl Inv for VirtPtr {
474 open spec fn inv(self) -> bool {
475 self.range@.start <= self.vaddr <= self.range@.end
476 }
477}
478
479impl Clone for VirtPtr {
480 fn clone(&self) -> (res: Self)
481 ensures
482 res == self,
483 {
484 Self { vaddr: self.vaddr, range: Ghost(self.range@) }
485 }
486}
487
488impl Copy for VirtPtr {
489
490}
491
492impl VirtPtr {
493 #[vstd::contrib::auto_spec]
495 pub fn new(vaddr: Vaddr, len: usize) -> Self {
496 Self { vaddr, range: Ghost(Range { start: vaddr, end: (vaddr + len) as usize }) }
497 }
498
499 pub open spec fn is_defined(self) -> bool {
501 self.range@.start <= self.vaddr <= self.range@.end
502 }
503
504 pub open spec fn is_valid(self) -> bool {
508 &&& self.is_defined()
509 &&& self.vaddr < self.range@.end
510 }
511
512 #[verifier::external_body]
525 pub fn read(self, Tracked(mem): Tracked<&MemView>) -> u8
526 requires
527 mem.addr_transl(self.vaddr) is Some,
528 mem.memory[(mem.addr_transl(self.vaddr)->0).0].contents[(mem.addr_transl(
529 self.vaddr,
530 )->0).1 as int] is Init,
531 self.is_valid(),
532 returns
533 mem.read(self.vaddr).value(),
534 {
535 unimplemented!()
536 }
537
538 #[verifier::external_body]
549 pub fn write(self, Tracked(mem): Tracked<&mut MemView>, x: u8)
550 requires
551 old(mem).addr_transl(self.vaddr) is Some,
552 self.is_valid(),
553 ensures
554 *final(mem) == old(mem).write(self.vaddr, x),
555 {
556 unimplemented!()
557 }
558
559 #[verifier::external_body]
573 pub fn read_volatile<T: PodOnce>(self, Tracked(mem): Tracked<&MemView>) -> (val: T)
574 requires
575 self.inv(),
576 core::mem::size_of::<T>() <= self.range@.end - self.vaddr,
577 self.vaddr % core::mem::align_of::<T>() == 0,
578 forall|i: usize|
579 #![trigger mem.addr_transl(i)]
580 self.vaddr <= i < self.vaddr + core::mem::size_of::<T>() ==> {
581 &&& mem.addr_transl(i) is Some
582 &&& mem.memory.contains_key((mem.addr_transl(i)->0).0)
583 &&& mem.memory[(mem.addr_transl(i)->0).0].contents[(mem.addr_transl(
584 i,
585 )->0).1 as int] is Init
586 },
587 ensures
588 pod_bytes(val) == mem.read_bytes(self.vaddr, core::mem::size_of::<T>()),
589 {
590 let pnt = self.vaddr as *const T;
591 unsafe { pnt.read_volatile() }
592 }
593
594 #[verifier::external_body]
620 pub fn write_volatile<T: Pod>(self, Tracked(mem): Tracked<&mut MemView>, val: T)
621 requires
622 self.inv(),
623 core::mem::size_of::<T>() <= self.range@.end - self.vaddr,
624 self.vaddr % core::mem::align_of::<T>() == 0,
625 forall|i: usize|
626 #![trigger old(mem).addr_transl(i)]
627 self.vaddr <= i < self.vaddr + core::mem::size_of::<T>() ==> {
628 &&& old(mem).addr_transl(i) is Some
629 },
630 ensures
631 *final(mem) == old(mem).write_bytes(self.vaddr, pod_bytes(val)),
632 final(mem).mappings == old(mem).mappings,
633 old(mem).memory.dom().subset_of(final(mem).memory.dom()),
634 forall|va: usize|
635 #![trigger final(mem).addr_transl(va)]
636 old(mem).addr_transl(va) == final(mem).addr_transl(va),
637 {
638 let pnt = self.vaddr as *mut T;
639 unsafe { pnt.write_volatile(val) }
640 }
641
642 pub open spec fn add_spec(self, n: usize) -> Self {
643 VirtPtr { vaddr: (self.vaddr + n) as usize, range: self.range }
644 }
645
646 pub fn add(&mut self, n: usize)
658 requires
659 0 <= old(self).vaddr + n < usize::MAX,
664 ensures
665 *final(self) == old(self).add_spec(
666 n,
667 ),
668 {
672 self.vaddr = self.vaddr + n
673 }
674
675 pub open spec fn sub_spec(self, n: usize) -> Self {
676 VirtPtr { vaddr: (self.vaddr - n) as usize, range: self.range }
677 }
678
679 pub fn sub(self, n: usize) -> (res: Self)
692 requires
693 n <= self.vaddr,
694 returns
695 self.sub_spec(n),
696 {
697 VirtPtr { vaddr: self.vaddr - n, range: self.range }
698 }
699
700 pub open spec fn wrapping_add_spec(self, n: usize) -> Self {
701 VirtPtr { vaddr: self.vaddr.wrapping_add(n), range: self.range }
702 }
703
704 pub fn wrapping_add(self, n: usize) -> (res: Self)
707 returns
708 self.wrapping_add_spec(n),
709 {
710 VirtPtr { vaddr: self.vaddr.wrapping_add(n), range: self.range }
711 }
712
713 pub fn cast<T>(self) -> (res: *mut T)
720 ensures
721 res as usize == self.vaddr,
722 {
723 core::ptr::null_mut::<T>().with_addr(self.vaddr)
728 }
729
730 pub open spec fn read_offset_spec(self, mem: MemView, n: usize) -> u8 {
731 mem.read((self.vaddr + n) as usize).value()
732 }
733
734 pub fn read_offset(&self, Tracked(mem): Tracked<&MemView>, n: usize) -> u8
750 requires
751 self.vaddr + n < usize::MAX,
752 self.range@.start <= self.vaddr + n < self.range@.end,
753 mem.addr_transl((self.vaddr + n) as usize) is Some,
754 mem.memory[(mem.addr_transl((self.vaddr + n) as usize)->0).0].contents[(mem.addr_transl(
755 (self.vaddr + n) as usize,
756 )->0).1 as int] is Init,
757 returns
758 self.read_offset_spec(*mem, n),
759 {
760 let mut tmp = self.clone();
761 tmp.add(n);
762 tmp.read(Tracked(mem))
763 }
764
765 pub open spec fn write_offset_spec(self, mem: MemView, n: usize, x: u8) -> MemView {
766 mem.write((self.vaddr + n) as usize, x)
767 }
768
769 pub fn write_offset(&self, Tracked(mem): Tracked<&mut MemView>, n: usize, x: u8)
778 requires
779 self.inv(),
780 self.vaddr + n < usize::MAX,
781 self.range@.start <= self.vaddr + n < self.range@.end,
782 old(mem).addr_transl((self.vaddr + n) as usize) is Some,
783 ensures
784 *final(mem) == self.write_offset_spec(*old(mem), n, x),
785 {
786 let mut tmp = self.clone();
787 tmp.add(n);
788 tmp.write(Tracked(mem), x)
789 }
790
791 pub open spec fn copy_offset_spec(
792 src: Self,
793 dst: Self,
794 mem_src: MemView,
795 mem_dst: MemView,
796 n: usize,
797 ) -> MemView {
798 let x = src.read_offset_spec(mem_src, n);
799 dst.write_offset_spec(mem_dst, n, x)
800 }
801
802 pub fn copy_offset(
819 src: &Self,
820 dst: &Self,
821 Tracked(mem_src): Tracked<&MemView>,
822 Tracked(mem_dst): Tracked<&mut MemView>,
823 n: usize,
824 )
825 requires
826 src.inv(),
827 dst.inv(),
828 src.vaddr + n < usize::MAX,
829 dst.vaddr + n < usize::MAX,
830 src.range@.start <= src.vaddr + n < src.range@.end,
831 mem_src.addr_transl((src.vaddr + n) as usize) is Some,
832 mem_src.memory.contains_key((mem_src.addr_transl((src.vaddr + n) as usize)->0).0),
833 mem_src.memory[(mem_src.addr_transl((src.vaddr + n) as usize)->0).0].contents[(
834 mem_src.addr_transl((src.vaddr + n) as usize)->0).1 as int] is Init,
835 dst.range@.start <= dst.vaddr + n < dst.range@.end,
836 old(mem_dst).addr_transl((dst.vaddr + n) as usize) is Some,
837 ensures
838 *final(mem_dst) == Self::copy_offset_spec(*src, *dst, *mem_src, *old(mem_dst), n),
839 final(mem_dst).mappings == old(mem_dst).mappings,
840 old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
841 {
842 let x = src.read_offset(Tracked(mem_src), n);
843 dst.write_offset(Tracked(mem_dst), n, x)
844 }
845
846 pub open spec fn memcpy_spec(
847 src: Self,
848 dst: Self,
849 mem_src: MemView,
850 mem_dst: MemView,
851 n: usize,
852 ) -> MemView
853 decreases n,
854 {
855 if n == 0 {
856 mem_dst
857 } else {
858 let mem_dst_1 = Self::copy_offset_spec(src, dst, mem_src, mem_dst, (n - 1) as usize);
859
860 Self::memcpy_spec(src, dst, mem_src, mem_dst_1, (n - 1) as usize)
861 }
862 }
863
864 pub fn copy_nonoverlapping(
884 src: &Self,
885 dst: &Self,
886 Tracked(mem_src): Tracked<&MemView>,
887 Tracked(mem_dst): Tracked<&mut MemView>,
888 n: usize,
889 )
890 requires
891 src.inv(),
892 dst.inv(),
893 src.vaddr + n <= src.range@.end,
894 forall|i: usize|
895 #![trigger mem_src.addr_transl(i)]
896 src.vaddr <= i < src.vaddr + n ==> {
897 &&& mem_src.addr_transl(i) is Some
898 &&& mem_src.memory.contains_key((mem_src.addr_transl(i)->0).0)
899 &&& mem_src.memory[(mem_src.addr_transl(i)->0).0].contents[(mem_src.addr_transl(
900 i,
901 )->0).1 as int] is Init
902 },
903 dst.vaddr + n <= dst.range@.end,
904 forall|i: usize|
905 dst.vaddr <= i < dst.vaddr + n ==> {
906 &&& old(mem_dst).addr_transl(i) is Some
907 },
908 ensures
909 *final(mem_dst) == Self::memcpy_spec(*src, *dst, *mem_src, *old(mem_dst), n),
910 final(mem_dst).mappings == old(mem_dst).mappings,
911 old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
913 forall|i: usize|
914 #![trigger final(mem_dst).addr_transl(i)]
915 dst.vaddr <= i < dst.vaddr + n ==> {
916 &&& final(mem_dst).addr_transl(i) is Some
917 },
918 decreases n,
919 {
920 if n == 0 {
921 return;
922 } else {
923 let ghost mem0 = *mem_dst;
924
925 Self::copy_offset(src, dst, Tracked(mem_src), Tracked(mem_dst), n - 1);
926
927 proof {
928 assert(forall|i: usize|
929 dst.vaddr <= i < dst.vaddr + n - 1 ==> mem_dst.addr_transl(i)
930 == #[trigger] mem0.addr_transl(i));
931 assert forall|i: usize|
932 dst.vaddr <= i < dst.vaddr + n - 1 implies mem_dst.addr_transl(i) is Some by {
933 assert(mem_dst.addr_transl(i) == mem0.addr_transl(i));
934 }
935 }
936
937 Self::copy_nonoverlapping(src, dst, Tracked(mem_src), Tracked(mem_dst), n - 1);
938 }
939 }
940
941 pub fn from_vaddr(vaddr: usize, len: usize) -> (r: Self)
953 requires
954 len <= usize::MAX - vaddr,
955 ensures
956 r.inv(),
957 r.vaddr == vaddr,
958 r.range@.start == vaddr,
959 r.range@.end == (vaddr + len) as usize,
960 len > 0 ==> r.is_valid(),
961 {
962 Self { vaddr, range: Ghost(Range { start: vaddr, end: (vaddr + len) as usize }) }
963 }
964
965 #[verus_spec(r =>
980 requires
981 self.is_valid(),
982 0 <= n <= self.range@.end - self.range@.start,
983 self.vaddr == self.range@.start,
984 ensures
985 r.0.range@.start == self.range@.start,
986 r.0.range@.end == self.range@.start + n,
987 r.0.vaddr == self.range@.start,
988 r.1.range@.start == self.range@.start + n,
989 r.1.range@.end == self.range@.end,
990 r.1.vaddr == self.range@.start + n,
991 )]
992 pub fn split(self, n: usize) -> (Self, Self) {
993 let left = VirtPtr {
994 vaddr: self.vaddr,
995 range: Ghost(Range { start: self.vaddr, end: (self.vaddr + n) as usize }),
996 };
997
998 let right = VirtPtr {
999 vaddr: self.vaddr + n,
1000 range: Ghost(Range { start: (self.vaddr + n) as usize, end: self.range@.end }),
1001 };
1002
1003 (left, right)
1004 }
1005
1006 pub fn addr(&self) -> Vaddr
1007 returns
1008 self.vaddr,
1009 {
1010 self.vaddr
1011 }
1012}
1013
1014pub tracked struct GlobalMemView {
1017 pub ghost pt_mappings: Set<Mapping>,
1018 pub ghost tlb_mappings: Set<Mapping>,
1019 pub ghost unmapped_pas: Set<Paddr>,
1020 pub memory: Map<Paddr, FrameContents>,
1021}
1022
1023impl Inv for GlobalMemView {
1024 open spec fn inv(self) -> bool {
1025 &&& forall|m: Mapping|
1026 #![trigger self.pt_mappings.contains(m)]
1027 self.pt_mappings.contains(m) ==> {
1028 &&& m.inv()
1029 &&& forall|pa: Paddr|
1030 m.pa_range.start <= pa < m.pa_range.end ==> {
1031 &&& self.memory.dom().contains(pa)
1032 }
1033 &&& self.memory.contains_key(m.pa_range.start)
1034 &&& self.memory[m.pa_range.start].size == m.page_size
1035 &&& self.memory[m.pa_range.start].inv()
1036 }
1037 &&& forall|m: Mapping|
1038 #![auto]
1039 self.tlb_mappings.contains(m) ==> self.pt_mappings.contains(m)
1040 &&& forall|m: Mapping|
1041 forall|n: Mapping|
1042 #![auto]
1043 self.pt_mappings.contains(m) ==> self.pt_mappings.contains(n) ==> m != n
1044 ==> #[trigger] m.va_range.end <= n.va_range.start || n.va_range.end
1045 <= m.va_range.start
1046 &&& forall|m1: Mapping, m2: Mapping|
1047 #![trigger self.pt_mappings.contains(m1), self.pt_mappings.contains(m2)]
1048 self.pt_mappings.contains(m1) && self.pt_mappings.contains(m2) && m1 != m2
1049 ==> m1.pa_range.end <= m2.pa_range.start || m2.pa_range.end <= m1.pa_range.start
1050 &&& self.unmapped_correct()
1051 }
1052}
1053
1054impl GlobalMemView {
1055 pub open spec fn addr_transl(self, va: usize) -> Option<(usize, usize)> {
1056 let mappings = self.tlb_mappings.filter(
1057 |m: Mapping| m.va_range.start <= va < m.va_range.end,
1058 );
1059 if 0 < mappings.len() {
1060 let m = mappings.choose(); let off = va - m.va_range.start;
1062 Some((m.pa_range.start, off as usize))
1063 } else {
1064 None
1065 }
1066 }
1067
1068 pub open spec fn is_mapped(self, pa: usize) -> bool {
1069 exists|m: Mapping| self.pt_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end
1070 }
1071
1072 pub open spec fn unmapped_correct(self) -> bool {
1073 forall|pa: Paddr| #![auto] self.is_mapped(pa) <==> !self.unmapped_pas.contains(pa)
1074 }
1075
1076 pub open spec fn take_view(self, vaddr: usize, len: usize) -> (Self, MemView) {
1077 let range_end = vaddr + len;
1078
1079 let leave_mappings: Set<Mapping> = self.tlb_mappings.filter(
1080 |m: Mapping| m.va_range.end <= vaddr || m.va_range.start > range_end,
1081 );
1082
1083 let take_mappings = self.tlb_mappings.filter(
1084 |m: Mapping| m.va_range.start < range_end && m.va_range.end > vaddr,
1085 );
1086
1087 let leave_pas = self.memory.dom().filter(
1088 |pa: usize|
1089 exists|m: Mapping|
1090 leave_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end,
1091 );
1092 let take_pas = self.memory.dom().filter(
1093 |pa: usize|
1094 exists|m: Mapping|
1095 take_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end,
1096 );
1097
1098 (
1099 GlobalMemView {
1100 tlb_mappings: leave_mappings,
1101 memory: self.memory.restrict(leave_pas),
1102 ..self
1103 },
1104 MemView { mappings: take_mappings, memory: self.memory.restrict(take_pas) },
1105 )
1106 }
1107
1108 pub proof fn tracked_take_view(tracked &mut self, vaddr: usize, len: usize) -> (tracked view:
1109 MemView)
1110 requires
1111 old(self).inv(),
1112 ensures
1113 *final(self) == old(self).take_view(vaddr, len).0,
1114 view == old(self).take_view(vaddr, len).1,
1115 {
1116 let ghost taken = old(self).take_view(vaddr, len);
1117 let ghost non_leave_pas = old(self).memory.dom().difference(taken.0.memory.dom());
1118 let tracked mut non_leave_memory = self.memory.tracked_remove_keys(non_leave_pas);
1119 assert(self.memory == taken.0.memory);
1120 let tracked view_memory = non_leave_memory.tracked_remove_keys(taken.1.memory.dom());
1121 assert(view_memory == taken.1.memory);
1122 self.tlb_mappings = taken.0.tlb_mappings;
1123 MemView { mappings: taken.1.mappings, memory: view_memory }
1124 }
1125
1126 pub open spec fn return_view(self, view: MemView) -> Self {
1127 GlobalMemView {
1128 tlb_mappings: self.tlb_mappings.union(view.mappings),
1129 memory: self.memory.union_prefer_right(view.memory),
1130 ..self
1131 }
1132 }
1133
1134 pub proof fn tracked_return_view(tracked &mut self, tracked view: MemView)
1135 ensures
1136 *final(self) == old(self).return_view(view),
1137 {
1138 self.tlb_mappings = self.tlb_mappings.union(view.mappings);
1139 self.memory.tracked_union_prefer_right(view.memory);
1140 }
1141
1142 pub open spec fn tlb_flush_vaddr(self, vaddr: Vaddr) -> Self {
1143 let tlb_mappings = self.tlb_mappings.filter(
1144 |m: Mapping| m.va_range.end <= vaddr || vaddr < m.va_range.start,
1145 );
1146 GlobalMemView { tlb_mappings, ..self }
1147 }
1148
1149 pub proof fn tracked_tlb_flush_vaddr(tracked &mut self, vaddr: Vaddr)
1150 requires
1151 old(self).inv(),
1152 ensures
1153 *final(self) == old(self).tlb_flush_vaddr(vaddr),
1154 final(self).inv(),
1155 {
1156 self.tlb_mappings = old(self).tlb_flush_vaddr(vaddr).tlb_mappings;
1157
1158 assert(self.pt_mappings == old(self).pt_mappings);
1159 assert(forall|pa: Paddr| #[trigger] self.is_mapped(pa) == old(self).is_mapped(pa));
1160 }
1161
1162 pub open spec fn tlb_soft_fault(self, vaddr: Vaddr) -> Self {
1163 let mapping = self.pt_mappings.filter(
1164 |m: Mapping| m.va_range.start <= vaddr < m.va_range.end,
1165 ).choose();
1166 GlobalMemView { tlb_mappings: self.tlb_mappings.insert(mapping), ..self }
1167 }
1168
1169 pub proof fn tracked_tlb_soft_fault(tracked &mut self, vaddr: Vaddr)
1170 requires
1171 old(self).inv(),
1172 old(self).addr_transl(vaddr) is None,
1173 exists|m: Mapping|
1174 old(self).pt_mappings.contains(m) && m.va_range.start <= vaddr < m.va_range.end,
1175 ensures
1176 *final(self) == old(self).tlb_soft_fault(vaddr),
1177 final(self).inv(),
1178 {
1179 let ghost pt_candidates = old(self).pt_mappings.filter(
1180 |m: Mapping| m.va_range.start <= vaddr < m.va_range.end,
1181 );
1182 assert(pt_candidates.len() > 0) by {
1183 let m = choose|m: Mapping|
1184 old(self).pt_mappings.contains(m) && m.va_range.start <= vaddr < m.va_range.end;
1185 assert(pt_candidates.contains(m));
1186 };
1187 assert(pt_candidates.contains(pt_candidates.choose()));
1188 self.tlb_mappings = old(self).tlb_soft_fault(vaddr).tlb_mappings;
1189
1190 assert(self.pt_mappings == old(self).pt_mappings);
1191 assert(forall|pa: Paddr| #[trigger] self.is_mapped(pa) == old(self).is_mapped(pa));
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 proof fn tracked_pt_map(tracked &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 self.pt_mappings = self.pt_mappings.insert(m);
1211 self.unmapped_pas = self.unmapped_pas.difference(
1212 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1213 );
1214 }
1215
1216 pub open spec fn pt_unmap(self, m: Mapping) -> Self {
1217 let pt_mappings = self.pt_mappings.remove(m);
1218 let unmapped_pas = self.unmapped_pas.union(
1219 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1220 );
1221 GlobalMemView { pt_mappings, unmapped_pas, ..self }
1222 }
1223
1224 pub proof fn tracked_pt_unmap(tracked &mut self, m: Mapping)
1225 requires
1226 old(self).pt_mappings.contains(m),
1227 !old(self).tlb_mappings.contains(m),
1228 old(self).inv(),
1229 ensures
1230 *final(self) == old(self).pt_unmap(m),
1231 final(self).inv(),
1232 {
1233 self.pt_mappings = self.pt_mappings.remove(m);
1234 self.unmapped_pas = self.unmapped_pas.union(
1235 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1236 );
1237
1238 assert forall|pa: Paddr| #[trigger]
1239 self.is_mapped(pa) <==> !self.unmapped_pas.contains(pa) by {
1240 if m.pa_range.start <= pa < m.pa_range.end {
1241 if self.is_mapped(pa) {
1242 let n = choose|n: Mapping|
1243 self.pt_mappings.contains(n) && n.pa_range.start <= pa < n.pa_range.end;
1244 }
1245 } else if old(self).is_mapped(pa) {
1246 let n = choose|n: Mapping|
1247 old(self).pt_mappings.contains(n) && n.pa_range.start <= pa < n.pa_range.end;
1248 }
1249 };
1250 }
1251
1252 pub proof fn lemma_va_mapping_unique(self, va: usize)
1253 requires
1254 self.inv(),
1255 self.addr_transl(va) is Some,
1257 ensures
1258 self.tlb_mappings.filter(
1259 |m: Mapping| m.va_range.start <= va < m.va_range.end,
1260 ).is_singleton(),
1261 {
1262 }
1263}
1264
1265}