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 mappings_are_disjoint(self) -> bool {
233 forall|m1: Mapping, m2: Mapping|
234 #![trigger self.mappings.contains(m1), self.mappings.contains(m2)]
235 self.mappings.contains(m1) && self.mappings.contains(m2) && m1 != m2 ==> {
236 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start
237 }
238 }
239
240 pub open spec fn split(self, vaddr: usize, len: usize) -> (MemView, MemView) {
246 let split_end = vaddr + len;
247
248 let left_mappings = self.mappings.filter(
250 |m: Mapping| m.va_range.start < split_end && m.va_range.end > vaddr,
251 );
252 let right_mappings = self.mappings.filter(|m: Mapping| m.va_range.end > split_end);
253
254 let left_pas = self.memory.dom().filter(
255 |pa: usize| exists|va: usize| vaddr <= va < split_end && self.is_mapped(va, pa),
256 );
257 let right_pas = self.memory.dom().filter(
258 |pa: usize| exists|va: usize| va >= split_end && self.is_mapped(va, pa),
259 );
260
261 (
262 MemView { mappings: left_mappings, memory: self.memory.restrict(left_pas) },
263 MemView { mappings: right_mappings, memory: self.memory.restrict(right_pas) },
264 )
265 }
266
267 #[verifier::external_body]
274 pub proof fn tracked_borrow_at(tracked &self, vaddr: usize, len: usize) -> (tracked r: MemView)
275 ensures
276 r == self.borrow_at(vaddr, len),
277 {
278 unimplemented!()
279 }
280
281 #[verifier::external_body]
288 pub proof fn tracked_split(tracked self, vaddr: usize, len: usize) -> (tracked r: (Self, Self))
289 ensures
290 r == self.split(vaddr, len),
291 {
292 unimplemented!()
293 }
294
295 pub proof fn lemma_split_preserves_transl(
309 original: MemView,
310 vaddr: usize,
311 len: usize,
312 left: MemView,
313 right: MemView,
314 )
315 requires
316 original.split(vaddr, len) == (left, right),
317 ensures
318 right.memory.dom().subset_of(original.memory.dom()),
319 forall|va: usize|
320 vaddr <= va < vaddr + len ==> {
321 #[trigger] original.addr_transl(va) == left.addr_transl(va)
322 },
323 forall|va: usize|
324 va >= vaddr + len ==> {
325 #[trigger] original.addr_transl(va) == right.addr_transl(va)
326 },
327 {
328 assert forall|va: usize| vaddr <= va < vaddr + len implies original.addr_transl(va)
329 == left.addr_transl(va) by {
330 assert(left.mappings == original.mappings.filter(
331 |m: Mapping| m.va_range.start < vaddr + len && m.va_range.end > vaddr,
332 ));
333 let o_mappings = original.mappings.filter(
334 |m: Mapping| m.va_range.start <= va < m.va_range.end,
335 );
336 let l_mappings = left.mappings.filter(
337 |m: Mapping| m.va_range.start <= va < m.va_range.end,
338 );
339
340 assert forall|m: Mapping| #[trigger] o_mappings.contains(m) implies l_mappings.contains(
341 m,
342 ) by {
343 assert(left.mappings.contains(m));
344 };
345 assert(o_mappings == l_mappings);
346 }
347
348 assert forall|va: usize| va >= vaddr + len implies original.addr_transl(va)
349 == right.addr_transl(va) by {
350 let split_end = vaddr + len;
351
352 let o_mappings = original.mappings.filter(
353 |m: Mapping| m.va_range.start <= va < m.va_range.end,
354 );
355 let r_mappings = right.mappings.filter(
356 |m: Mapping| m.va_range.start <= va < m.va_range.end,
357 );
358
359 assert forall|m: Mapping| o_mappings.contains(m) implies r_mappings.contains(m) by {
360 assert(right.mappings.contains(m));
361 assert(r_mappings.contains(m));
362 }
363
364 assert(o_mappings == r_mappings);
365 }
366 }
367
368 pub open spec fn join(self, other: MemView) -> MemView {
373 MemView {
374 mappings: self.mappings.union(other.mappings),
375 memory: self.memory.union_prefer_right(other.memory),
376 }
377 }
378
379 #[verifier::external_body]
389 pub proof fn tracked_join(tracked &mut self, tracked other: Self)
390 requires
391 old(self).mappings.disjoint(other.mappings),
392 ensures
393 *final(self) == old(self).join(other),
394 {
395 unimplemented!()
396 }
397
398 pub proof fn lemma_split_join_identity(
411 this: MemView,
412 lhs: MemView,
413 rhs: MemView,
414 vaddr: usize,
415 len: usize,
416 )
417 requires
418 this.split(vaddr, len) == (lhs, rhs),
419 forall|m: Mapping| #[trigger]
420 this.mappings.contains(m) ==> vaddr <= m.va_range.start < m.va_range.end,
421 forall|pa: Paddr| #[trigger]
422 this.memory.contains_key(pa) ==> exists|va: usize|
423 vaddr <= va && #[trigger] this.is_mapped(va, pa),
424 ensures
425 this.mappings == lhs.join(rhs).mappings,
426 this.memory == lhs.join(rhs).memory,
427 {
428 }
429
430 pub proof fn lemma_split_preserves_read(
439 original: MemView,
440 vaddr: usize,
441 len: usize,
442 left: MemView,
443 right: MemView,
444 )
445 requires
446 original.split(vaddr, len) == (left, right),
447 ensures
448 forall|va: usize|
449 #![trigger original.read(va)]
450 va >= vaddr + len && original.addr_transl(va) is Some
451 && original.memory.contains_key((original.addr_transl(va)->0).0)
452 ==> original.read(va) == right.read(va),
453 {
454 Self::lemma_split_preserves_transl(original, vaddr, len, left, right);
455 let split_end = vaddr + len;
456 assert forall|va: usize|
457 va >= split_end && original.addr_transl(va) is Some && original.memory.contains_key(
458 original.addr_transl(va).unwrap().0,
459 ) implies #[trigger] original.read(va) == right.read(va) by {
460 let pa = original.addr_transl(va).unwrap().0;
461 assert(original.is_mapped(va, pa));
462
463 }
464 }
465
466 pub proof fn lemma_read_bytes_eq_pointwise(a: MemView, b: MemView, va: usize, n: usize)
468 requires
469 forall|i: usize| va <= i < va + n ==> a.read(i) == b.read(i),
470 va + n <= usize::MAX,
471 ensures
472 a.read_bytes(va, n) == b.read_bytes(va, n),
473 decreases n,
474 {
475 if n == 0 {
476 return;
477 }
478 Self::lemma_read_bytes_eq_pointwise(a, b, (va + 1) as usize, (n - 1) as usize);
479 }
480}
481
482impl Inv for VirtPtr {
483 open spec fn inv(self) -> bool {
484 &&& self.range@.start <= self.vaddr <= self.range@.end
485 &&& self.range@.end >= self.range@.start
486 }
487}
488
489impl Clone for VirtPtr {
490 fn clone(&self) -> (res: Self)
491 ensures
492 res == self,
493 {
494 Self { vaddr: self.vaddr, range: Ghost(self.range@) }
495 }
496}
497
498impl Copy for VirtPtr {
499
500}
501
502impl VirtPtr {
503 #[vstd::contrib::auto_spec]
505 pub fn new(vaddr: Vaddr, len: usize) -> Self {
506 Self { vaddr, range: Ghost(Range { start: vaddr, end: (vaddr + len) as usize }) }
507 }
508
509 pub open spec fn is_defined(self) -> bool {
511 self.range@.start <= self.vaddr <= self.range@.end
512 }
513
514 pub open spec fn is_valid(self) -> bool {
518 &&& self.is_defined()
519 &&& self.vaddr < self.range@.end
520 }
521
522 #[verifier::external_body]
535 pub fn read(self, Tracked(mem): Tracked<&MemView>) -> u8
536 requires
537 mem.addr_transl(self.vaddr) is Some,
538 mem.memory[(mem.addr_transl(self.vaddr)->0).0].contents[(mem.addr_transl(
539 self.vaddr,
540 )->0).1 as int] is Init,
541 self.is_valid(),
542 returns
543 mem.read(self.vaddr).value(),
544 {
545 unimplemented!()
546 }
547
548 #[verifier::external_body]
559 pub fn write(self, Tracked(mem): Tracked<&mut MemView>, x: u8)
560 requires
561 old(mem).addr_transl(self.vaddr) is Some,
562 self.is_valid(),
563 ensures
564 *final(mem) == old(mem).write(self.vaddr, x),
565 {
566 unimplemented!()
567 }
568
569 #[verifier::external_body]
583 pub fn read_volatile<T: PodOnce>(self, Tracked(mem): Tracked<&MemView>) -> (val: T)
584 requires
585 self.inv(),
586 core::mem::size_of::<T>() <= self.range@.end - self.vaddr,
587 self.vaddr % core::mem::align_of::<T>() == 0,
588 forall|i: usize|
589 #![trigger mem.addr_transl(i)]
590 self.vaddr <= i < self.vaddr + core::mem::size_of::<T>() ==> {
591 &&& mem.addr_transl(i) is Some
592 &&& mem.memory.contains_key((mem.addr_transl(i)->0).0)
593 &&& mem.memory[(mem.addr_transl(i)->0).0].contents[(mem.addr_transl(
594 i,
595 )->0).1 as int] is Init
596 },
597 ensures
598 pod_bytes(val) == mem.read_bytes(self.vaddr, core::mem::size_of::<T>()),
599 {
600 let pnt = self.vaddr as *const T;
601 unsafe { pnt.read_volatile() }
602 }
603
604 #[verifier::external_body]
630 pub fn write_volatile<T: Pod>(self, Tracked(mem): Tracked<&mut MemView>, val: T)
631 requires
632 self.inv(),
633 core::mem::size_of::<T>() <= self.range@.end - self.vaddr,
634 self.vaddr % core::mem::align_of::<T>() == 0,
635 forall|i: usize|
636 #![trigger old(mem).addr_transl(i)]
637 self.vaddr <= i < self.vaddr + core::mem::size_of::<T>() ==> {
638 &&& old(mem).addr_transl(i) is Some
639 },
640 ensures
641 *final(mem) == old(mem).write_bytes(self.vaddr, pod_bytes(val)),
642 final(mem).mappings == old(mem).mappings,
643 old(mem).memory.dom().subset_of(final(mem).memory.dom()),
644 forall|va: usize|
645 #![trigger final(mem).addr_transl(va)]
646 old(mem).addr_transl(va) == final(mem).addr_transl(va),
647 {
648 let pnt = self.vaddr as *mut T;
649 unsafe { pnt.write_volatile(val) }
650 }
651
652 pub open spec fn add_spec(self, n: usize) -> Self {
653 VirtPtr { vaddr: (self.vaddr + n) as usize, range: self.range }
654 }
655
656 pub fn add(&mut self, n: usize)
668 requires
669 0 <= old(self).vaddr + n < usize::MAX,
674 ensures
675 *final(self) == old(self).add_spec(
676 n,
677 ),
678 {
682 self.vaddr = self.vaddr + n
683 }
684
685 pub open spec fn sub_spec(self, n: usize) -> Self {
686 VirtPtr { vaddr: (self.vaddr - n) as usize, range: self.range }
687 }
688
689 pub fn sub(self, n: usize) -> (res: Self)
702 requires
703 n <= self.vaddr,
704 returns
705 self.sub_spec(n),
706 {
707 VirtPtr { vaddr: self.vaddr - n, range: self.range }
708 }
709
710 pub open spec fn wrapping_add_spec(self, n: usize) -> Self {
711 VirtPtr { vaddr: self.vaddr.wrapping_add(n), range: self.range }
712 }
713
714 pub fn wrapping_add(self, n: usize) -> (res: Self)
717 returns
718 self.wrapping_add_spec(n),
719 {
720 VirtPtr { vaddr: self.vaddr.wrapping_add(n), range: self.range }
721 }
722
723 #[verifier::external_body]
730 pub fn cast<T>(self) -> (res: *mut T)
731 ensures
732 res as usize == self.vaddr,
733 {
734 self.vaddr as *mut T
735 }
736
737 pub open spec fn read_offset_spec(self, mem: MemView, n: usize) -> u8 {
738 mem.read((self.vaddr + n) as usize).value()
739 }
740
741 pub fn read_offset(&self, Tracked(mem): Tracked<&MemView>, n: usize) -> u8
757 requires
758 self.vaddr + n < usize::MAX,
759 self.range@.start <= self.vaddr + n < self.range@.end,
760 mem.addr_transl((self.vaddr + n) as usize) is Some,
761 mem.memory[(mem.addr_transl((self.vaddr + n) as usize)->0).0].contents[(mem.addr_transl(
762 (self.vaddr + n) as usize,
763 )->0).1 as int] is Init,
764 returns
765 self.read_offset_spec(*mem, n),
766 {
767 let mut tmp = self.clone();
768 tmp.add(n);
769 tmp.read(Tracked(mem))
770 }
771
772 pub open spec fn write_offset_spec(self, mem: MemView, n: usize, x: u8) -> MemView {
773 mem.write((self.vaddr + n) as usize, x)
774 }
775
776 pub fn write_offset(&self, Tracked(mem): Tracked<&mut MemView>, n: usize, x: u8)
785 requires
786 self.inv(),
787 self.vaddr + n < usize::MAX,
788 self.range@.start <= self.vaddr + n < self.range@.end,
789 old(mem).addr_transl((self.vaddr + n) as usize) is Some,
790 ensures
791 *final(mem) == self.write_offset_spec(*old(mem), n, x),
792 {
793 let mut tmp = self.clone();
794 tmp.add(n);
795 tmp.write(Tracked(mem), x)
796 }
797
798 pub open spec fn copy_offset_spec(
799 src: Self,
800 dst: Self,
801 mem_src: MemView,
802 mem_dst: MemView,
803 n: usize,
804 ) -> MemView {
805 let x = src.read_offset_spec(mem_src, n);
806 dst.write_offset_spec(mem_dst, n, x)
807 }
808
809 pub fn copy_offset(
826 src: &Self,
827 dst: &Self,
828 Tracked(mem_src): Tracked<&MemView>,
829 Tracked(mem_dst): Tracked<&mut MemView>,
830 n: usize,
831 )
832 requires
833 src.inv(),
834 dst.inv(),
835 src.vaddr + n < usize::MAX,
836 dst.vaddr + n < usize::MAX,
837 src.range@.start <= src.vaddr + n < src.range@.end,
838 mem_src.addr_transl((src.vaddr + n) as usize) is Some,
839 mem_src.memory.contains_key((mem_src.addr_transl((src.vaddr + n) as usize)->0).0),
840 mem_src.memory[(mem_src.addr_transl((src.vaddr + n) as usize)->0).0].contents[(
841 mem_src.addr_transl((src.vaddr + n) as usize)->0).1 as int] is Init,
842 dst.range@.start <= dst.vaddr + n < dst.range@.end,
843 old(mem_dst).addr_transl((dst.vaddr + n) as usize) is Some,
844 ensures
845 *final(mem_dst) == Self::copy_offset_spec(*src, *dst, *mem_src, *old(mem_dst), n),
846 final(mem_dst).mappings == old(mem_dst).mappings,
847 old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
848 {
849 let x = src.read_offset(Tracked(mem_src), n);
850 dst.write_offset(Tracked(mem_dst), n, x)
851 }
852
853 pub open spec fn memcpy_spec(
854 src: Self,
855 dst: Self,
856 mem_src: MemView,
857 mem_dst: MemView,
858 n: usize,
859 ) -> MemView
860 decreases n,
861 {
862 if n == 0 {
863 mem_dst
864 } else {
865 let mem_dst_1 = Self::copy_offset_spec(src, dst, mem_src, mem_dst, (n - 1) as usize);
866
867 Self::memcpy_spec(src, dst, mem_src, mem_dst_1, (n - 1) as usize)
868 }
869 }
870
871 pub fn copy_nonoverlapping(
891 src: &Self,
892 dst: &Self,
893 Tracked(mem_src): Tracked<&MemView>,
894 Tracked(mem_dst): Tracked<&mut MemView>,
895 n: usize,
896 )
897 requires
898 src.inv(),
899 dst.inv(),
900 src.range@.start <= src.vaddr,
901 src.vaddr + n <= src.range@.end,
902 forall|i: usize|
903 #![trigger mem_src.addr_transl(i)]
904 src.vaddr <= i < src.vaddr + n ==> {
905 &&& mem_src.addr_transl(i) is Some
906 &&& mem_src.memory.contains_key((mem_src.addr_transl(i)->0).0)
907 &&& mem_src.memory[(mem_src.addr_transl(i)->0).0].contents[(mem_src.addr_transl(
908 i,
909 )->0).1 as int] is Init
910 },
911 dst.range@.start <= dst.vaddr,
912 dst.vaddr + n <= dst.range@.end,
913 forall|i: usize|
914 dst.vaddr <= i < dst.vaddr + n ==> {
915 &&& old(mem_dst).addr_transl(i) is Some
916 },
917 ensures
918 *final(mem_dst) == Self::memcpy_spec(*src, *dst, *mem_src, *old(mem_dst), n),
919 final(mem_dst).mappings == old(mem_dst).mappings,
920 old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
922 forall|i: usize|
923 #![trigger final(mem_dst).addr_transl(i)]
924 dst.vaddr <= i < dst.vaddr + n ==> {
925 &&& final(mem_dst).addr_transl(i) is Some
926 },
927 decreases n,
928 {
929 if n == 0 {
930 return;
931 } else {
932 let ghost mem0 = *mem_dst;
933
934 Self::copy_offset(src, dst, Tracked(mem_src), Tracked(mem_dst), n - 1);
935
936 proof {
937 assert(forall|i: usize|
938 dst.vaddr <= i < dst.vaddr + n - 1 ==> mem_dst.addr_transl(i)
939 == #[trigger] mem0.addr_transl(i));
940 assert forall|i: usize|
941 dst.vaddr <= i < dst.vaddr + n - 1 implies mem_dst.addr_transl(i) is Some by {
942 assert(mem_dst.addr_transl(i) == mem0.addr_transl(i));
943 }
944 }
945
946 Self::copy_nonoverlapping(src, dst, Tracked(mem_src), Tracked(mem_dst), n - 1);
947 }
948 }
949
950 pub fn from_vaddr(vaddr: usize, len: usize) -> (r: Self)
962 requires
963 len <= usize::MAX - vaddr,
964 ensures
965 r.inv(),
966 r.vaddr == vaddr,
967 r.range@.start == vaddr,
968 r.range@.end == (vaddr + len) as usize,
969 len > 0 ==> r.is_valid(),
970 {
971 Self { vaddr, range: Ghost(Range { start: vaddr, end: (vaddr + len) as usize }) }
972 }
973
974 #[verus_spec(r =>
989 requires
990 self.is_valid(),
991 0 <= n <= self.range@.end - self.range@.start,
992 self.vaddr == self.range@.start,
993 ensures
994 r.0.range@.start == self.range@.start,
995 r.0.range@.end == self.range@.start + n,
996 r.0.vaddr == self.range@.start,
997 r.1.range@.start == self.range@.start + n,
998 r.1.range@.end == self.range@.end,
999 r.1.vaddr == self.range@.start + n,
1000 )]
1001 pub fn split(self, n: usize) -> (Self, Self) {
1002 let left = VirtPtr {
1003 vaddr: self.vaddr,
1004 range: Ghost(Range { start: self.vaddr, end: (self.vaddr + n) as usize }),
1005 };
1006
1007 let right = VirtPtr {
1008 vaddr: self.vaddr + n,
1009 range: Ghost(Range { start: (self.vaddr + n) as usize, end: self.range@.end }),
1010 };
1011
1012 (left, right)
1013 }
1014
1015 pub fn addr(&self) -> Vaddr
1016 returns
1017 self.vaddr,
1018 {
1019 self.vaddr
1020 }
1021}
1022
1023pub tracked struct GlobalMemView {
1026 pub ghost pt_mappings: Set<Mapping>,
1027 pub ghost tlb_mappings: Set<Mapping>,
1028 pub ghost unmapped_pas: Set<Paddr>,
1029 pub memory: Map<Paddr, FrameContents>,
1030}
1031
1032impl Inv for GlobalMemView {
1033 open spec fn inv(self) -> bool {
1034 &&& forall|m: Mapping|
1035 #![trigger self.pt_mappings.contains(m)]
1036 self.pt_mappings.contains(m) ==> {
1037 &&& m.inv()
1038 &&& forall|pa: Paddr|
1039 m.pa_range.start <= pa < m.pa_range.end ==> {
1040 &&& self.memory.dom().contains(pa)
1041 }
1042 &&& self.memory.contains_key(m.pa_range.start)
1043 &&& self.memory[m.pa_range.start].size == m.page_size
1044 &&& self.memory[m.pa_range.start].inv()
1045 }
1046 &&& forall|m: Mapping|
1047 #![auto]
1048 self.tlb_mappings.contains(m) ==> self.pt_mappings.contains(m)
1049 &&& forall|m: Mapping|
1050 forall|n: Mapping|
1051 #![auto]
1052 self.pt_mappings.contains(m) ==> self.pt_mappings.contains(n) ==> m != n
1053 ==> #[trigger] m.va_range.end <= n.va_range.start || n.va_range.end
1054 <= m.va_range.start
1055 &&& forall|m1: Mapping, m2: Mapping|
1056 #![trigger self.pt_mappings.contains(m1), self.pt_mappings.contains(m2)]
1057 self.pt_mappings.contains(m1) && self.pt_mappings.contains(m2) && m1 != m2
1058 ==> m1.pa_range.end <= m2.pa_range.start || m2.pa_range.end <= m1.pa_range.start
1059 &&& forall|m: Mapping|
1060 forall|n: Mapping|
1061 #![auto]
1062 self.tlb_mappings.contains(m) ==> self.tlb_mappings.contains(n) ==> m != n
1063 ==> #[trigger] m.va_range.end <= n.va_range.start || n.va_range.end
1064 <= m.va_range.start
1065 &&& self.all_pas_accounted_for()
1066 &&& self.pas_uniquely_mapped()
1067 &&& self.unmapped_correct()
1068 }
1069}
1070
1071impl GlobalMemView {
1072 pub open spec fn addr_transl(self, va: usize) -> Option<(usize, usize)> {
1073 let mappings = self.tlb_mappings.filter(
1074 |m: Mapping| m.va_range.start <= va < m.va_range.end,
1075 );
1076 if 0 < mappings.len() {
1077 let m = mappings.choose(); let off = va - m.va_range.start;
1079 Some((m.pa_range.start, off as usize))
1080 } else {
1081 None
1082 }
1083 }
1084
1085 pub open spec fn is_mapped(self, pa: usize) -> bool {
1086 exists|m: Mapping| self.pt_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end
1087 }
1088
1089 pub open spec fn all_pas_accounted_for(self) -> bool {
1090 forall|pa: Paddr|
1091 0 <= pa < MAX_PADDR ==> #[trigger] self.is_mapped(pa)
1092 || #[trigger] self.unmapped_pas.contains(pa)
1093 }
1094
1095 pub open spec fn pas_uniquely_mapped(self) -> bool {
1096 forall|m1: Mapping, m2: Mapping|
1097 #![trigger self.tlb_mappings.contains(m1), self.tlb_mappings.contains(m2)]
1098 self.tlb_mappings.contains(m1) && self.tlb_mappings.contains(m2) && m1 != m2
1099 ==> m1.pa_range.end <= m2.pa_range.start || m2.pa_range.end <= m1.pa_range.start
1100 }
1101
1102 pub open spec fn unmapped_correct(self) -> bool {
1103 forall|pa: Paddr| #![auto] self.is_mapped(pa) <==> !self.unmapped_pas.contains(pa)
1104 }
1105
1106 pub open spec fn take_view(self, vaddr: usize, len: usize) -> (Self, MemView) {
1107 let range_end = vaddr + len;
1108
1109 let leave_mappings: Set<Mapping> = self.tlb_mappings.filter(
1110 |m: Mapping| m.va_range.end <= vaddr || m.va_range.start > range_end,
1111 );
1112
1113 let take_mappings = self.tlb_mappings.filter(
1114 |m: Mapping| m.va_range.start < range_end && m.va_range.end > vaddr,
1115 );
1116
1117 let leave_pas = self.memory.dom().filter(
1118 |pa: usize|
1119 exists|m: Mapping|
1120 leave_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end,
1121 );
1122 let take_pas = self.memory.dom().filter(
1123 |pa: usize|
1124 exists|m: Mapping|
1125 take_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end,
1126 );
1127
1128 (
1129 GlobalMemView {
1130 tlb_mappings: leave_mappings,
1131 memory: self.memory.restrict(leave_pas),
1132 ..self
1133 },
1134 MemView { mappings: take_mappings, memory: self.memory.restrict(take_pas) },
1135 )
1136 }
1137
1138 pub proof fn tracked_take_view(tracked &mut self, vaddr: usize, len: usize) -> (tracked view:
1139 MemView)
1140 requires
1141 old(self).inv(),
1142 ensures
1143 *final(self) == old(self).take_view(vaddr, len).0,
1144 view == old(self).take_view(vaddr, len).1,
1145 {
1146 let ghost taken = old(self).take_view(vaddr, len);
1147 let ghost non_leave_pas = old(self).memory.dom().difference(taken.0.memory.dom());
1148 let tracked mut non_leave_memory = self.memory.tracked_remove_keys(non_leave_pas);
1149 assert(self.memory == taken.0.memory);
1150 let tracked view_memory = non_leave_memory.tracked_remove_keys(taken.1.memory.dom());
1151 assert(view_memory == taken.1.memory);
1152 self.tlb_mappings = taken.0.tlb_mappings;
1153 MemView { mappings: taken.1.mappings, memory: view_memory }
1154 }
1155
1156 pub open spec fn return_view(self, view: MemView) -> Self {
1157 GlobalMemView {
1158 tlb_mappings: self.tlb_mappings.union(view.mappings),
1159 memory: self.memory.union_prefer_right(view.memory),
1160 ..self
1161 }
1162 }
1163
1164 pub proof fn tracked_return_view(tracked &mut self, tracked view: MemView)
1165 ensures
1166 *final(self) == old(self).return_view(view),
1167 {
1168 self.tlb_mappings = self.tlb_mappings.union(view.mappings);
1169 self.memory.tracked_union_prefer_right(view.memory);
1170 }
1171
1172 pub open spec fn tlb_flush_vaddr(self, vaddr: Vaddr) -> Self {
1173 let tlb_mappings = self.tlb_mappings.filter(
1174 |m: Mapping| m.va_range.end <= vaddr || vaddr < m.va_range.start,
1175 );
1176 GlobalMemView { tlb_mappings, ..self }
1177 }
1178
1179 pub proof fn tracked_tlb_flush_vaddr(tracked &mut self, vaddr: Vaddr)
1180 requires
1181 old(self).inv(),
1182 ensures
1183 *final(self) == old(self).tlb_flush_vaddr(vaddr),
1184 final(self).inv(),
1185 {
1186 self.tlb_mappings = old(self).tlb_flush_vaddr(vaddr).tlb_mappings;
1187
1188 assert(self.pt_mappings == old(self).pt_mappings);
1189 assert(forall|pa: Paddr| #[trigger] self.is_mapped(pa) == old(self).is_mapped(pa));
1190 }
1191
1192 pub open spec fn tlb_soft_fault(self, vaddr: Vaddr) -> Self {
1193 let mapping = self.pt_mappings.filter(
1194 |m: Mapping| m.va_range.start <= vaddr < m.va_range.end,
1195 ).choose();
1196 GlobalMemView { tlb_mappings: self.tlb_mappings.insert(mapping), ..self }
1197 }
1198
1199 pub proof fn tracked_tlb_soft_fault(tracked &mut self, vaddr: Vaddr)
1200 requires
1201 old(self).inv(),
1202 old(self).addr_transl(vaddr) is None,
1203 exists|m: Mapping|
1204 old(self).pt_mappings.contains(m) && m.va_range.start <= vaddr < m.va_range.end,
1205 ensures
1206 *final(self) == old(self).tlb_soft_fault(vaddr),
1207 final(self).inv(),
1208 {
1209 let ghost pt_candidates = old(self).pt_mappings.filter(
1210 |m: Mapping| m.va_range.start <= vaddr < m.va_range.end,
1211 );
1212 assert(pt_candidates.len() > 0) by {
1213 let m = choose|m: Mapping|
1214 old(self).pt_mappings.contains(m) && m.va_range.start <= vaddr < m.va_range.end;
1215 assert(pt_candidates.contains(m));
1216 };
1217 assert(pt_candidates.contains(pt_candidates.choose()));
1218 self.tlb_mappings = old(self).tlb_soft_fault(vaddr).tlb_mappings;
1219
1220 assert(self.pt_mappings == old(self).pt_mappings);
1221 assert(forall|pa: Paddr| #[trigger] self.is_mapped(pa) == old(self).is_mapped(pa));
1222 }
1223
1224 pub open spec fn pt_map(self, m: Mapping) -> Self {
1225 let pt_mappings = self.pt_mappings.insert(m);
1226 let unmapped_pas = self.unmapped_pas.difference(
1227 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1228 );
1229 GlobalMemView { pt_mappings, unmapped_pas, ..self }
1230 }
1231
1232 pub proof fn tracked_pt_map(tracked &mut self, m: Mapping)
1233 requires
1234 forall|pa: Paddr|
1235 m.pa_range.start <= pa < m.pa_range.end ==> old(self).unmapped_pas.contains(pa),
1236 old(self).inv(),
1237 ensures
1238 *final(self) == old(self).pt_map(m),
1239 {
1240 self.pt_mappings = self.pt_mappings.insert(m);
1241 self.unmapped_pas = self.unmapped_pas.difference(
1242 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1243 );
1244 }
1245
1246 pub open spec fn pt_unmap(self, m: Mapping) -> Self {
1247 let pt_mappings = self.pt_mappings.remove(m);
1248 let unmapped_pas = self.unmapped_pas.union(
1249 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1250 );
1251 GlobalMemView { pt_mappings, unmapped_pas, ..self }
1252 }
1253
1254 pub proof fn tracked_pt_unmap(tracked &mut self, m: Mapping)
1255 requires
1256 old(self).pt_mappings.contains(m),
1257 !old(self).tlb_mappings.contains(m),
1258 old(self).inv(),
1259 ensures
1260 *final(self) == old(self).pt_unmap(m),
1261 final(self).inv(),
1262 {
1263 self.pt_mappings = self.pt_mappings.remove(m);
1264 self.unmapped_pas = self.unmapped_pas.union(
1265 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1266 );
1267
1268 assert forall|pa: Paddr| #[trigger]
1269 self.is_mapped(pa) <==> !self.unmapped_pas.contains(pa) by {
1270 if m.pa_range.start <= pa < m.pa_range.end {
1271 if self.is_mapped(pa) {
1272 let n = choose|n: Mapping|
1273 self.pt_mappings.contains(n) && n.pa_range.start <= pa < n.pa_range.end;
1274 }
1275 } else if old(self).is_mapped(pa) {
1276 let n = choose|n: Mapping|
1277 old(self).pt_mappings.contains(n) && n.pa_range.start <= pa < n.pa_range.end;
1278 }
1279 };
1280 }
1281
1282 pub proof fn lemma_va_mapping_unique(self, va: usize)
1283 requires
1284 self.inv(),
1285 self.addr_transl(va) is Some,
1287 ensures
1288 self.tlb_mappings.filter(
1289 |m: Mapping| m.va_range.start <= va < m.va_range.end,
1290 ).is_singleton(),
1291 {
1292 }
1293}
1294
1295}