1use core::{marker::PhantomData, ops::Range};
15
16use ostd_pod::{decode_pod, lemma_decode_pod_inverse, pod_bytes};
17
18use vstd::prelude::*;
19
20use vstd::{pervasive::arbitrary, raw_ptr, set};
21use vstd_extra::prelude::*;
22
23use crate::specs::{arch::MAX_PADDR, mm::page_table::Mapping};
24
25use crate::Pod;
26use crate::mm::{Paddr, PodOnce, Vaddr};
27
28verus! {
29
30pub struct VirtPtr {
40 pub vaddr: Vaddr,
42 pub range: Ghost<Range<Vaddr>>,
44}
45
46pub ghost struct FrameContents {
52 pub contents: Seq<raw_ptr::MemContents<u8>>,
54 pub size: usize,
56 pub range: Range<Paddr>,
58}
59
60impl Inv for FrameContents {
61 open spec fn inv(self) -> bool {
69 &&& self.contents.len() == self.size@
70 &&& self.size@ == self.range.end - self.range.start
71 &&& self.range.start % self.size == 0
72 &&& self.range.end % self.size == 0
73 &&& self.range.start <= self.range.end < MAX_PADDR
74 }
75}
76
77pub tracked struct MemView {
90 pub ghost mappings: Set<Mapping>,
92 pub memory: Map<Paddr, FrameContents>,
94}
95
96impl MemView {
97 pub open spec fn addr_transl(self, va: usize) -> Option<(usize, usize)> {
101 let mappings = self.mappings.filter(|m: Mapping| m.va_range.start <= va < m.va_range.end);
102 if 0 < mappings.len() {
103 let m = mappings.choose(); let off = va - m.va_range.start;
105 Some((m.pa_range.start, off as usize))
106 } else {
107 None
108 }
109 }
110
111 pub open spec fn read(self, va: usize) -> raw_ptr::MemContents<u8> {
115 let (pa, off) = self.addr_transl(va)->0;
116 self.memory[pa].contents[off as int]
117 }
118
119 pub open spec fn write(self, va: usize, x: u8) -> Self {
123 let (pa, off) = self.addr_transl(va)->0;
124 MemView {
125 memory: self.memory.insert(
126 pa,
127 FrameContents {
128 contents: self.memory[pa].contents.update(
129 off as int,
130 raw_ptr::MemContents::Init(x),
131 ),
132 ..self.memory[pa]
133 },
134 ),
135 ..self
136 }
137 }
138
139 pub open spec fn write_bytes(self, va: usize, bytes: Seq<u8>) -> Self
143 decreases bytes.len(),
144 {
145 if bytes.len() == 0 {
146 self
147 } else {
148 self.write(va, bytes[0]).write_bytes((va + 1) as usize, bytes.drop_first())
149 }
150 }
151
152 pub open spec fn read_bytes(self, va: usize, len: usize) -> Seq<u8>
158 decreases len,
159 {
160 if len == 0 {
161 Seq::empty()
162 } else {
163 seq![self.read(va).value()].add(self.read_bytes((va + 1) as usize, (len - 1) as usize))
164 }
165 }
166
167 pub proof fn lemma_write_bytes_mappings(self, va: usize, bytes: Seq<u8>)
169 ensures
170 self.write_bytes(va, bytes).mappings == self.mappings,
171 decreases bytes.len(),
172 {
173 if bytes.len() > 0 {
174 self.write(va, bytes[0]).lemma_write_bytes_mappings(
175 (va + 1) as usize,
176 bytes.drop_first(),
177 );
178 }
179 }
180
181 pub proof fn lemma_write_bytes_addr_transl(self, va: usize, bytes: Seq<u8>, query: usize)
183 ensures
184 self.write_bytes(va, bytes).addr_transl(query) == self.addr_transl(query),
185 decreases bytes.len(),
186 {
187 if bytes.len() > 0 {
188 self.write(va, bytes[0]).lemma_write_bytes_addr_transl(
189 (va + 1) as usize,
190 bytes.drop_first(),
191 query,
192 );
193 }
194 }
195
196 pub proof fn lemma_write_bytes_memory_dom_grows(self, va: usize, bytes: Seq<u8>)
198 ensures
199 self.memory.dom().subset_of(self.write_bytes(va, bytes).memory.dom()),
200 decreases bytes.len(),
201 {
202 if bytes.len() > 0 {
203 self.write(va, bytes[0]).lemma_write_bytes_memory_dom_grows(
204 (va + 1) as usize,
205 bytes.drop_first(),
206 );
207 }
208 }
209
210 pub open spec fn eq_at(self, va1: usize, va2: usize) -> bool {
212 let (pa1, off1) = self.addr_transl(va1)->0;
213 let (pa2, off2) = self.addr_transl(va2)->0;
214 self.memory[pa1].contents[off1 as int] == self.memory[pa2].contents[off2 as int]
215 }
216
217 pub open spec fn is_mapped(self, va: usize, pa: usize) -> bool {
219 self.addr_transl(va) is Some && self.addr_transl(va)->Some_0.0 == pa
220 }
221
222 pub open spec fn borrow_at(&self, vaddr: usize, len: usize) -> MemView {
227 let range_end = vaddr + len;
228
229 let valid_pas = self.memory.dom().filter(
230 |pa: usize|
231 exists|va: usize| vaddr <= va < range_end && #[trigger] self.is_mapped(va, pa),
232 );
233
234 MemView {
235 mappings: self.mappings.filter(
236 |m: Mapping| m.va_range.start < range_end && m.va_range.end > vaddr,
237 ),
238 memory: self.memory.restrict(valid_pas),
239 }
240 }
241
242 pub open spec fn mappings_are_disjoint(self) -> bool {
244 forall|m1: Mapping, m2: Mapping|
245 #![trigger self.mappings.contains(m1), self.mappings.contains(m2)]
246 self.mappings.contains(m1) && self.mappings.contains(m2) && m1 != m2 ==> {
247 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start
248 }
249 }
250
251 pub open spec fn split(self, vaddr: usize, len: usize) -> (MemView, MemView) {
257 let split_end = vaddr + len;
258
259 let left_mappings = self.mappings.filter(
261 |m: Mapping| m.va_range.start < split_end && m.va_range.end > vaddr,
262 );
263 let right_mappings = self.mappings.filter(|m: Mapping| m.va_range.end > split_end);
264
265 let left_pas = self.memory.dom().filter(
266 |pa: usize| exists|va: usize| vaddr <= va < split_end && self.is_mapped(va, pa),
267 );
268 let right_pas = self.memory.dom().filter(
269 |pa: usize| exists|va: usize| va >= split_end && self.is_mapped(va, pa),
270 );
271
272 (
273 MemView { mappings: left_mappings, memory: self.memory.restrict(left_pas) },
274 MemView { mappings: right_mappings, memory: self.memory.restrict(right_pas) },
275 )
276 }
277
278 #[verifier::external_body]
285 pub proof fn tracked_borrow_at(tracked &self, vaddr: usize, len: usize) -> (tracked r: MemView)
286 ensures
287 r == self.borrow_at(vaddr, len),
288 {
289 unimplemented!()
290 }
291
292 #[verifier::external_body]
299 pub proof fn tracked_split(tracked self, vaddr: usize, len: usize) -> (tracked r: (Self, Self))
300 ensures
301 r == self.split(vaddr, len),
302 {
303 unimplemented!()
304 }
305
306 pub proof fn lemma_split_preserves_transl(
320 original: MemView,
321 vaddr: usize,
322 len: usize,
323 left: MemView,
324 right: MemView,
325 )
326 requires
327 original.split(vaddr, len) == (left, right),
328 ensures
329 right.memory.dom().subset_of(original.memory.dom()),
330 forall|va: usize|
331 vaddr <= va < vaddr + len ==> {
332 #[trigger] original.addr_transl(va) == left.addr_transl(va)
333 },
334 forall|va: usize|
335 va >= vaddr + len ==> {
336 #[trigger] original.addr_transl(va) == right.addr_transl(va)
337 },
338 {
339 assert forall|va: usize| vaddr <= va < vaddr + len implies original.addr_transl(va)
340 == left.addr_transl(va) by {
341 assert(left.mappings == original.mappings.filter(
342 |m: Mapping| m.va_range.start < vaddr + len && m.va_range.end > vaddr,
343 ));
344 let o_mappings = original.mappings.filter(
345 |m: Mapping| m.va_range.start <= va < m.va_range.end,
346 );
347 let l_mappings = left.mappings.filter(
348 |m: Mapping| m.va_range.start <= va < m.va_range.end,
349 );
350
351 assert forall|m: Mapping| #[trigger] o_mappings.contains(m) implies l_mappings.contains(
352 m,
353 ) by {
354 assert(left.mappings.contains(m));
355 };
356 assert(o_mappings == l_mappings);
357 }
358
359 assert forall|va: usize| va >= vaddr + len implies original.addr_transl(va)
360 == right.addr_transl(va) by {
361 let split_end = vaddr + len;
362
363 let o_mappings = original.mappings.filter(
364 |m: Mapping| m.va_range.start <= va < m.va_range.end,
365 );
366 let r_mappings = right.mappings.filter(
367 |m: Mapping| m.va_range.start <= va < m.va_range.end,
368 );
369
370 assert forall|m: Mapping| o_mappings.contains(m) implies r_mappings.contains(m) by {
371 assert(right.mappings.contains(m));
372 assert(r_mappings.contains(m));
373 }
374
375 assert(o_mappings == r_mappings);
376 }
377 }
378
379 pub open spec fn join(self, other: MemView) -> MemView {
384 MemView {
385 mappings: self.mappings.union(other.mappings),
386 memory: self.memory.union_prefer_right(other.memory),
387 }
388 }
389
390 #[verifier::external_body]
400 pub proof fn tracked_join(tracked &mut self, tracked other: Self)
401 requires
402 old(self).mappings.disjoint(other.mappings),
403 ensures
404 *final(self) == old(self).join(other),
405 {
406 unimplemented!()
407 }
408
409 pub proof fn lemma_split_join_identity(
422 this: MemView,
423 lhs: MemView,
424 rhs: MemView,
425 vaddr: usize,
426 len: usize,
427 )
428 requires
429 this.split(vaddr, len) == (lhs, rhs),
430 forall|m: Mapping| #[trigger]
431 this.mappings.contains(m) ==> vaddr <= m.va_range.start < m.va_range.end,
432 forall|pa: Paddr| #[trigger]
433 this.memory.contains_key(pa) ==> exists|va: usize|
434 vaddr <= va && #[trigger] this.is_mapped(va, pa),
435 ensures
436 this.mappings == lhs.join(rhs).mappings,
437 this.memory == lhs.join(rhs).memory,
438 {
439 }
440
441 pub proof fn lemma_split_preserves_read(
450 original: MemView,
451 vaddr: usize,
452 len: usize,
453 left: MemView,
454 right: MemView,
455 )
456 requires
457 original.split(vaddr, len) == (left, right),
458 ensures
459 forall|va: usize|
460 #![trigger original.read(va)]
461 va >= vaddr + len && original.addr_transl(va) is Some
462 && original.memory.contains_key((original.addr_transl(va)->0).0)
463 ==> original.read(va) == right.read(va),
464 {
465 Self::lemma_split_preserves_transl(original, vaddr, len, left, right);
466 let split_end = vaddr + len;
467 assert forall|va: usize|
468 va >= split_end && original.addr_transl(va) is Some && original.memory.contains_key(
469 original.addr_transl(va).unwrap().0,
470 ) implies #[trigger] original.read(va) == right.read(va) by {
471 let pa = original.addr_transl(va).unwrap().0;
472 assert(original.is_mapped(va, pa));
473
474 }
475 }
476
477 pub proof fn lemma_read_bytes_eq_pointwise(a: MemView, b: MemView, va: usize, n: usize)
479 requires
480 forall|i: usize| va <= i < va + n ==> a.read(i) == b.read(i),
481 va + n <= usize::MAX,
482 ensures
483 a.read_bytes(va, n) == b.read_bytes(va, n),
484 decreases n,
485 {
486 if n == 0 {
487 return;
488 }
489 Self::lemma_read_bytes_eq_pointwise(a, b, (va + 1) as usize, (n - 1) as usize);
490 }
491}
492
493impl Inv for VirtPtr {
494 open spec fn inv(self) -> bool {
495 &&& self.range@.start <= self.vaddr <= self.range@.end
496 &&& self.range@.end >= self.range@.start
497 }
498}
499
500impl Clone for VirtPtr {
501 fn clone(&self) -> (res: Self)
502 ensures
503 res == self,
504 {
505 Self { vaddr: self.vaddr, range: Ghost(self.range@) }
506 }
507}
508
509impl Copy for VirtPtr {
510
511}
512
513impl VirtPtr {
514 #[vstd::contrib::auto_spec]
516 pub fn new(vaddr: Vaddr, len: usize) -> Self {
517 Self { vaddr, range: Ghost(Range { start: vaddr, end: (vaddr + len) as usize }) }
518 }
519
520 pub open spec fn is_defined(self) -> bool {
522 self.range@.start <= self.vaddr <= self.range@.end
523 }
524
525 pub open spec fn is_valid(self) -> bool {
529 &&& self.is_defined()
530 &&& self.vaddr < self.range@.end
531 }
532
533 #[verifier::external_body]
546 pub fn read(self, Tracked(mem): Tracked<&MemView>) -> u8
547 requires
548 mem.addr_transl(self.vaddr) is Some,
549 mem.memory[(mem.addr_transl(self.vaddr)->0).0].contents[(mem.addr_transl(
550 self.vaddr,
551 )->0).1 as int] is Init,
552 self.is_valid(),
553 returns
554 mem.read(self.vaddr).value(),
555 {
556 unimplemented!()
557 }
558
559 #[verifier::external_body]
570 pub fn write(self, Tracked(mem): Tracked<&mut MemView>, x: u8)
571 requires
572 old(mem).addr_transl(self.vaddr) is Some,
573 self.is_valid(),
574 ensures
575 *final(mem) == old(mem).write(self.vaddr, x),
576 {
577 unimplemented!()
578 }
579
580 #[verifier::external_body]
594 pub fn read_volatile<T: PodOnce>(self, Tracked(mem): Tracked<&MemView>) -> (val: T)
595 requires
596 self.inv(),
597 core::mem::size_of::<T>() <= self.range@.end - self.vaddr,
598 self.vaddr % core::mem::align_of::<T>() == 0,
599 forall|i: usize|
600 #![trigger mem.addr_transl(i)]
601 self.vaddr <= i < self.vaddr + core::mem::size_of::<T>() ==> {
602 &&& mem.addr_transl(i) is Some
603 &&& mem.memory.contains_key((mem.addr_transl(i)->0).0)
604 &&& mem.memory[(mem.addr_transl(i)->0).0].contents[(mem.addr_transl(
605 i,
606 )->0).1 as int] is Init
607 },
608 ensures
609 pod_bytes(val) == mem.read_bytes(self.vaddr, core::mem::size_of::<T>()),
610 {
611 let pnt = self.vaddr as *const T;
612 unsafe { pnt.read_volatile() }
613 }
614
615 #[verifier::external_body]
641 pub fn write_volatile<T: Pod>(self, Tracked(mem): Tracked<&mut MemView>, val: T)
642 requires
643 self.inv(),
644 core::mem::size_of::<T>() <= self.range@.end - self.vaddr,
645 self.vaddr % core::mem::align_of::<T>() == 0,
646 forall|i: usize|
647 #![trigger old(mem).addr_transl(i)]
648 self.vaddr <= i < self.vaddr + core::mem::size_of::<T>() ==> {
649 &&& old(mem).addr_transl(i) is Some
650 },
651 ensures
652 *final(mem) == old(mem).write_bytes(self.vaddr, pod_bytes(val)),
653 final(mem).mappings == old(mem).mappings,
654 old(mem).memory.dom().subset_of(final(mem).memory.dom()),
655 forall|va: usize|
656 #![trigger final(mem).addr_transl(va)]
657 old(mem).addr_transl(va) == final(mem).addr_transl(va),
658 {
659 let pnt = self.vaddr as *mut T;
660 unsafe { pnt.write_volatile(val) }
661 }
662
663 pub open spec fn add_spec(self, n: usize) -> Self {
664 VirtPtr { vaddr: (self.vaddr + n) as usize, range: self.range }
665 }
666
667 pub fn add(&mut self, n: usize)
679 requires
680 0 <= old(self).vaddr + n < usize::MAX,
685 ensures
686 *final(self) == old(self).add_spec(
687 n,
688 ),
689 {
693 self.vaddr = self.vaddr + n
694 }
695
696 pub open spec fn sub_spec(self, n: usize) -> Self {
697 VirtPtr { vaddr: (self.vaddr - n) as usize, range: self.range }
698 }
699
700 pub fn sub(self, n: usize) -> (res: Self)
713 requires
714 n <= self.vaddr,
715 returns
716 self.sub_spec(n),
717 {
718 VirtPtr { vaddr: self.vaddr - n, range: self.range }
719 }
720
721 pub open spec fn wrapping_add_spec(self, n: usize) -> Self {
722 VirtPtr { vaddr: self.vaddr.wrapping_add(n), range: self.range }
723 }
724
725 pub fn wrapping_add(self, n: usize) -> (res: Self)
728 returns
729 self.wrapping_add_spec(n),
730 {
731 VirtPtr { vaddr: self.vaddr.wrapping_add(n), range: self.range }
732 }
733
734 #[verifier::external_body]
741 pub fn cast<T>(self) -> (res: *mut T)
742 ensures
743 res as usize == self.vaddr,
744 {
745 self.vaddr as *mut T
746 }
747
748 pub open spec fn read_offset_spec(self, mem: MemView, n: usize) -> u8 {
749 mem.read((self.vaddr + n) as usize).value()
750 }
751
752 pub fn read_offset(&self, Tracked(mem): Tracked<&MemView>, n: usize) -> u8
768 requires
769 self.vaddr + n < usize::MAX,
770 self.range@.start <= self.vaddr + n < self.range@.end,
771 mem.addr_transl((self.vaddr + n) as usize) is Some,
772 mem.memory[(mem.addr_transl((self.vaddr + n) as usize)->0).0].contents[(mem.addr_transl(
773 (self.vaddr + n) as usize,
774 )->0).1 as int] is Init,
775 returns
776 self.read_offset_spec(*mem, n),
777 {
778 let mut tmp = self.clone();
779 tmp.add(n);
780 tmp.read(Tracked(mem))
781 }
782
783 pub open spec fn write_offset_spec(self, mem: MemView, n: usize, x: u8) -> MemView {
784 mem.write((self.vaddr + n) as usize, x)
785 }
786
787 pub fn write_offset(&self, Tracked(mem): Tracked<&mut MemView>, n: usize, x: u8)
796 requires
797 self.inv(),
798 self.vaddr + n < usize::MAX,
799 self.range@.start <= self.vaddr + n < self.range@.end,
800 old(mem).addr_transl((self.vaddr + n) as usize) is Some,
801 ensures
802 *final(mem) == self.write_offset_spec(*old(mem), n, x),
803 {
804 let mut tmp = self.clone();
805 tmp.add(n);
806 tmp.write(Tracked(mem), x)
807 }
808
809 pub open spec fn copy_offset_spec(
810 src: Self,
811 dst: Self,
812 mem_src: MemView,
813 mem_dst: MemView,
814 n: usize,
815 ) -> MemView {
816 let x = src.read_offset_spec(mem_src, n);
817 dst.write_offset_spec(mem_dst, n, x)
818 }
819
820 pub fn copy_offset(
837 src: &Self,
838 dst: &Self,
839 Tracked(mem_src): Tracked<&MemView>,
840 Tracked(mem_dst): Tracked<&mut MemView>,
841 n: usize,
842 )
843 requires
844 src.inv(),
845 dst.inv(),
846 src.vaddr + n < usize::MAX,
847 dst.vaddr + n < usize::MAX,
848 src.range@.start <= src.vaddr + n < src.range@.end,
849 mem_src.addr_transl((src.vaddr + n) as usize) is Some,
850 mem_src.memory.contains_key((mem_src.addr_transl((src.vaddr + n) as usize)->0).0),
851 mem_src.memory[(mem_src.addr_transl((src.vaddr + n) as usize)->0).0].contents[(
852 mem_src.addr_transl((src.vaddr + n) as usize)->0).1 as int] is Init,
853 dst.range@.start <= dst.vaddr + n < dst.range@.end,
854 old(mem_dst).addr_transl((dst.vaddr + n) as usize) is Some,
855 ensures
856 *final(mem_dst) == Self::copy_offset_spec(*src, *dst, *mem_src, *old(mem_dst), n),
857 final(mem_dst).mappings == old(mem_dst).mappings,
858 old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
859 {
860 let x = src.read_offset(Tracked(mem_src), n);
861 dst.write_offset(Tracked(mem_dst), n, x)
862 }
863
864 pub open spec fn memcpy_spec(
865 src: Self,
866 dst: Self,
867 mem_src: MemView,
868 mem_dst: MemView,
869 n: usize,
870 ) -> MemView
871 decreases n,
872 {
873 if n == 0 {
874 mem_dst
875 } else {
876 let mem_dst_1 = Self::copy_offset_spec(src, dst, mem_src, mem_dst, (n - 1) as usize);
877
878 Self::memcpy_spec(src, dst, mem_src, mem_dst_1, (n - 1) as usize)
879 }
880 }
881
882 pub fn copy_nonoverlapping(
902 src: &Self,
903 dst: &Self,
904 Tracked(mem_src): Tracked<&MemView>,
905 Tracked(mem_dst): Tracked<&mut MemView>,
906 n: usize,
907 )
908 requires
909 src.inv(),
910 dst.inv(),
911 src.range@.start <= src.vaddr,
912 src.vaddr + n <= src.range@.end,
913 forall|i: usize|
914 #![trigger mem_src.addr_transl(i)]
915 src.vaddr <= i < src.vaddr + n ==> {
916 &&& mem_src.addr_transl(i) is Some
917 &&& mem_src.memory.contains_key((mem_src.addr_transl(i)->0).0)
918 &&& mem_src.memory[(mem_src.addr_transl(i)->0).0].contents[(mem_src.addr_transl(
919 i,
920 )->0).1 as int] is Init
921 },
922 dst.range@.start <= dst.vaddr,
923 dst.vaddr + n <= dst.range@.end,
924 forall|i: usize|
925 dst.vaddr <= i < dst.vaddr + n ==> {
926 &&& old(mem_dst).addr_transl(i) is Some
927 },
928 ensures
929 *final(mem_dst) == Self::memcpy_spec(*src, *dst, *mem_src, *old(mem_dst), n),
930 final(mem_dst).mappings == old(mem_dst).mappings,
931 old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
933 forall|i: usize|
934 #![trigger final(mem_dst).addr_transl(i)]
935 dst.vaddr <= i < dst.vaddr + n ==> {
936 &&& final(mem_dst).addr_transl(i) is Some
937 },
938 decreases n,
939 {
940 if n == 0 {
941 return;
942 } else {
943 let ghost mem0 = *mem_dst;
944
945 Self::copy_offset(src, dst, Tracked(mem_src), Tracked(mem_dst), n - 1);
946
947 proof {
948 assert(forall|i: usize|
949 dst.vaddr <= i < dst.vaddr + n - 1 ==> mem_dst.addr_transl(i)
950 == #[trigger] mem0.addr_transl(i));
951 assert forall|i: usize|
952 dst.vaddr <= i < dst.vaddr + n - 1 implies mem_dst.addr_transl(i) is Some by {
953 assert(mem_dst.addr_transl(i) == mem0.addr_transl(i));
954 }
955 }
956
957 Self::copy_nonoverlapping(src, dst, Tracked(mem_src), Tracked(mem_dst), n - 1);
958 }
959 }
960
961 pub fn from_vaddr(vaddr: usize, len: usize) -> (r: Self)
973 requires
974 len <= usize::MAX - vaddr,
975 ensures
976 r.inv(),
977 r.vaddr == vaddr,
978 r.range@.start == vaddr,
979 r.range@.end == (vaddr + len) as usize,
980 len > 0 ==> r.is_valid(),
981 {
982 Self { vaddr, range: Ghost(Range { start: vaddr, end: (vaddr + len) as usize }) }
983 }
984
985 #[verus_spec(r =>
1000 requires
1001 self.is_valid(),
1002 0 <= n <= self.range@.end - self.range@.start,
1003 self.vaddr == self.range@.start,
1004 ensures
1005 r.0.range@.start == self.range@.start,
1006 r.0.range@.end == self.range@.start + n,
1007 r.0.vaddr == self.range@.start,
1008 r.1.range@.start == self.range@.start + n,
1009 r.1.range@.end == self.range@.end,
1010 r.1.vaddr == self.range@.start + n,
1011 )]
1012 pub fn split(self, n: usize) -> (Self, Self) {
1013 let left = VirtPtr {
1014 vaddr: self.vaddr,
1015 range: Ghost(Range { start: self.vaddr, end: (self.vaddr + n) as usize }),
1016 };
1017
1018 let right = VirtPtr {
1019 vaddr: self.vaddr + n,
1020 range: Ghost(Range { start: (self.vaddr + n) as usize, end: self.range@.end }),
1021 };
1022
1023 (left, right)
1024 }
1025
1026 pub fn addr(&self) -> Vaddr
1027 returns
1028 self.vaddr,
1029 {
1030 self.vaddr
1031 }
1032}
1033
1034pub tracked struct GlobalMemView {
1037 pub ghost pt_mappings: Set<Mapping>,
1038 pub ghost tlb_mappings: Set<Mapping>,
1039 pub ghost unmapped_pas: Set<Paddr>,
1040 pub memory: Map<Paddr, FrameContents>,
1041}
1042
1043impl Inv for GlobalMemView {
1044 open spec fn inv(self) -> bool {
1045 &&& forall|m: Mapping|
1046 #![trigger self.pt_mappings.contains(m)]
1047 self.pt_mappings.contains(m) ==> {
1048 &&& m.inv()
1049 &&& forall|pa: Paddr|
1050 m.pa_range.start <= pa < m.pa_range.end ==> {
1051 &&& self.memory.dom().contains(pa)
1052 }
1053 &&& self.memory.contains_key(m.pa_range.start)
1054 &&& self.memory[m.pa_range.start].size == m.page_size
1055 &&& self.memory[m.pa_range.start].inv()
1056 }
1057 &&& forall|m: Mapping|
1058 #![auto]
1059 self.tlb_mappings.contains(m) ==> self.pt_mappings.contains(m)
1060 &&& forall|m: Mapping|
1061 forall|n: Mapping|
1062 #![auto]
1063 self.pt_mappings.contains(m) ==> self.pt_mappings.contains(n) ==> m != n
1064 ==> #[trigger] m.va_range.end <= n.va_range.start || n.va_range.end
1065 <= m.va_range.start
1066 &&& forall|m1: Mapping, m2: Mapping|
1067 #![trigger self.pt_mappings.contains(m1), self.pt_mappings.contains(m2)]
1068 self.pt_mappings.contains(m1) && self.pt_mappings.contains(m2) && m1 != m2
1069 ==> m1.pa_range.end <= m2.pa_range.start || m2.pa_range.end <= m1.pa_range.start
1070 &&& forall|m: Mapping|
1071 forall|n: Mapping|
1072 #![auto]
1073 self.tlb_mappings.contains(m) ==> self.tlb_mappings.contains(n) ==> m != n
1074 ==> #[trigger] m.va_range.end <= n.va_range.start || n.va_range.end
1075 <= m.va_range.start
1076 &&& self.all_pas_accounted_for()
1077 &&& self.pas_uniquely_mapped()
1078 &&& self.unmapped_correct()
1079 }
1080}
1081
1082impl GlobalMemView {
1083 pub open spec fn addr_transl(self, va: usize) -> Option<(usize, usize)> {
1084 let mappings = self.tlb_mappings.filter(
1085 |m: Mapping| m.va_range.start <= va < m.va_range.end,
1086 );
1087 if 0 < mappings.len() {
1088 let m = mappings.choose(); let off = va - m.va_range.start;
1090 Some((m.pa_range.start, off as usize))
1091 } else {
1092 None
1093 }
1094 }
1095
1096 pub open spec fn is_mapped(self, pa: usize) -> bool {
1097 exists|m: Mapping| self.pt_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end
1098 }
1099
1100 pub open spec fn all_pas_accounted_for(self) -> bool {
1101 forall|pa: Paddr|
1102 0 <= pa < MAX_PADDR ==> #[trigger] self.is_mapped(pa)
1103 || #[trigger] self.unmapped_pas.contains(pa)
1104 }
1105
1106 pub open spec fn pas_uniquely_mapped(self) -> bool {
1107 forall|m1: Mapping, m2: Mapping|
1108 #![trigger self.tlb_mappings.contains(m1), self.tlb_mappings.contains(m2)]
1109 self.tlb_mappings.contains(m1) && self.tlb_mappings.contains(m2) && m1 != m2
1110 ==> m1.pa_range.end <= m2.pa_range.start || m2.pa_range.end <= m1.pa_range.start
1111 }
1112
1113 pub open spec fn unmapped_correct(self) -> bool {
1114 forall|pa: Paddr| #![auto] self.is_mapped(pa) <==> !self.unmapped_pas.contains(pa)
1115 }
1116
1117 pub open spec fn take_view(self, vaddr: usize, len: usize) -> (Self, MemView) {
1118 let range_end = vaddr + len;
1119
1120 let leave_mappings: Set<Mapping> = self.tlb_mappings.filter(
1121 |m: Mapping| m.va_range.end <= vaddr || m.va_range.start > range_end,
1122 );
1123
1124 let take_mappings = self.tlb_mappings.filter(
1125 |m: Mapping| m.va_range.start < range_end && m.va_range.end > vaddr,
1126 );
1127
1128 let leave_pas = self.memory.dom().filter(
1129 |pa: usize|
1130 exists|m: Mapping|
1131 leave_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end,
1132 );
1133 let take_pas = self.memory.dom().filter(
1134 |pa: usize|
1135 exists|m: Mapping|
1136 take_mappings.contains(m) && m.pa_range.start <= pa < m.pa_range.end,
1137 );
1138
1139 (
1140 GlobalMemView {
1141 tlb_mappings: leave_mappings,
1142 memory: self.memory.restrict(leave_pas),
1143 ..self
1144 },
1145 MemView { mappings: take_mappings, memory: self.memory.restrict(take_pas) },
1146 )
1147 }
1148
1149 pub proof fn tracked_take_view(tracked &mut self, vaddr: usize, len: usize) -> (tracked view:
1150 MemView)
1151 requires
1152 old(self).inv(),
1153 ensures
1154 *final(self) == old(self).take_view(vaddr, len).0,
1155 view == old(self).take_view(vaddr, len).1,
1156 {
1157 let ghost taken = old(self).take_view(vaddr, len);
1158 let ghost non_leave_pas = old(self).memory.dom().difference(taken.0.memory.dom());
1159 let tracked mut non_leave_memory = self.memory.tracked_remove_keys(non_leave_pas);
1160 assert(self.memory == taken.0.memory);
1161 let tracked view_memory = non_leave_memory.tracked_remove_keys(taken.1.memory.dom());
1162 assert(view_memory == taken.1.memory);
1163 self.tlb_mappings = taken.0.tlb_mappings;
1164 MemView { mappings: taken.1.mappings, memory: view_memory }
1165 }
1166
1167 pub open spec fn return_view(self, view: MemView) -> Self {
1168 GlobalMemView {
1169 tlb_mappings: self.tlb_mappings.union(view.mappings),
1170 memory: self.memory.union_prefer_right(view.memory),
1171 ..self
1172 }
1173 }
1174
1175 pub proof fn tracked_return_view(tracked &mut self, tracked view: MemView)
1176 ensures
1177 *final(self) == old(self).return_view(view),
1178 {
1179 self.tlb_mappings = self.tlb_mappings.union(view.mappings);
1180 self.memory.tracked_union_prefer_right(view.memory);
1181 }
1182
1183 pub open spec fn tlb_flush_vaddr(self, vaddr: Vaddr) -> Self {
1184 let tlb_mappings = self.tlb_mappings.filter(
1185 |m: Mapping| m.va_range.end <= vaddr || vaddr < m.va_range.start,
1186 );
1187 GlobalMemView { tlb_mappings, ..self }
1188 }
1189
1190 pub proof fn tracked_tlb_flush_vaddr(tracked &mut self, vaddr: Vaddr)
1191 requires
1192 old(self).inv(),
1193 ensures
1194 *final(self) == old(self).tlb_flush_vaddr(vaddr),
1195 final(self).inv(),
1196 {
1197 self.tlb_mappings = old(self).tlb_flush_vaddr(vaddr).tlb_mappings;
1198
1199 assert(self.pt_mappings == old(self).pt_mappings);
1200 assert(forall|pa: Paddr| #[trigger] self.is_mapped(pa) == old(self).is_mapped(pa));
1201 }
1202
1203 pub open spec fn tlb_soft_fault(self, vaddr: Vaddr) -> Self {
1204 let mapping = self.pt_mappings.filter(
1205 |m: Mapping| m.va_range.start <= vaddr < m.va_range.end,
1206 ).choose();
1207 GlobalMemView { tlb_mappings: self.tlb_mappings.insert(mapping), ..self }
1208 }
1209
1210 pub proof fn tracked_tlb_soft_fault(tracked &mut self, vaddr: Vaddr)
1211 requires
1212 old(self).inv(),
1213 old(self).addr_transl(vaddr) is None,
1214 exists|m: Mapping|
1215 old(self).pt_mappings.contains(m) && m.va_range.start <= vaddr < m.va_range.end,
1216 ensures
1217 *final(self) == old(self).tlb_soft_fault(vaddr),
1218 final(self).inv(),
1219 {
1220 let ghost pt_candidates = old(self).pt_mappings.filter(
1221 |m: Mapping| m.va_range.start <= vaddr < m.va_range.end,
1222 );
1223 assert(pt_candidates.len() > 0) by {
1224 let m = choose|m: Mapping|
1225 old(self).pt_mappings.contains(m) && m.va_range.start <= vaddr < m.va_range.end;
1226 assert(pt_candidates.contains(m));
1227 };
1228 assert(pt_candidates.contains(pt_candidates.choose()));
1229 self.tlb_mappings = old(self).tlb_soft_fault(vaddr).tlb_mappings;
1230
1231 assert(self.pt_mappings == old(self).pt_mappings);
1232 assert(forall|pa: Paddr| #[trigger] self.is_mapped(pa) == old(self).is_mapped(pa));
1233 }
1234
1235 pub open spec fn pt_map(self, m: Mapping) -> Self {
1236 let pt_mappings = self.pt_mappings.insert(m);
1237 let unmapped_pas = self.unmapped_pas.difference(
1238 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1239 );
1240 GlobalMemView { pt_mappings, unmapped_pas, ..self }
1241 }
1242
1243 pub proof fn tracked_pt_map(tracked &mut self, m: Mapping)
1244 requires
1245 forall|pa: Paddr|
1246 m.pa_range.start <= pa < m.pa_range.end ==> old(self).unmapped_pas.contains(pa),
1247 old(self).inv(),
1248 ensures
1249 *final(self) == old(self).pt_map(m),
1250 {
1251 self.pt_mappings = self.pt_mappings.insert(m);
1252 self.unmapped_pas = self.unmapped_pas.difference(
1253 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1254 );
1255 }
1256
1257 pub open spec fn pt_unmap(self, m: Mapping) -> Self {
1258 let pt_mappings = self.pt_mappings.remove(m);
1259 let unmapped_pas = self.unmapped_pas.union(
1260 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1261 );
1262 GlobalMemView { pt_mappings, unmapped_pas, ..self }
1263 }
1264
1265 pub proof fn tracked_pt_unmap(tracked &mut self, m: Mapping)
1266 requires
1267 old(self).pt_mappings.contains(m),
1268 !old(self).tlb_mappings.contains(m),
1269 old(self).inv(),
1270 ensures
1271 *final(self) == old(self).pt_unmap(m),
1272 final(self).inv(),
1273 {
1274 self.pt_mappings = self.pt_mappings.remove(m);
1275 self.unmapped_pas = self.unmapped_pas.union(
1276 Set::<usize>::range(m.pa_range.start, m.pa_range.end),
1277 );
1278
1279 assert forall|pa: Paddr| #[trigger]
1280 self.is_mapped(pa) <==> !self.unmapped_pas.contains(pa) by {
1281 if m.pa_range.start <= pa < m.pa_range.end {
1282 if self.is_mapped(pa) {
1283 let n = choose|n: Mapping|
1284 self.pt_mappings.contains(n) && n.pa_range.start <= pa < n.pa_range.end;
1285 }
1286 } else if old(self).is_mapped(pa) {
1287 let n = choose|n: Mapping|
1288 old(self).pt_mappings.contains(n) && n.pa_range.start <= pa < n.pa_range.end;
1289 }
1290 };
1291 }
1292
1293 pub proof fn lemma_va_mapping_unique(self, va: usize)
1294 requires
1295 self.inv(),
1296 self.addr_transl(va) is Some,
1298 ensures
1299 self.tlb_mappings.filter(
1300 |m: Mapping| m.va_range.start <= va < m.va_range.end,
1301 ).is_singleton(),
1302 {
1303 }
1304}
1305
1306}