1use vstd::prelude::*;
2use vstd_extra::ownership::*;
3
4use crate::specs::mm::page_table::*;
5
6use crate::mm::{Paddr, Vaddr, tlb::TlbFlushOp};
7
8verus! {
9
10pub ghost struct TlbModel {
11 pub pending: Seq<TlbFlushOp>,
12 pub mappings: Set<Mapping>,
13}
14
15impl Inv for TlbModel {
16 open spec fn inv(self) -> bool {
17 &&& forall|m: Mapping| #![auto] self.mappings has m ==> m.inv()
18 &&& forall|m: Mapping, n: Mapping|
19 #![auto]
20 self.mappings has m ==> self.mappings has n ==> m != n ==> Mapping::disjoint_vaddrs(
21 m,
22 n,
23 )
24 &&& forall|m: Mapping, n: Mapping|
25 #![auto]
26 self.mappings has m ==> self.mappings has n ==> m != n ==> Mapping::disjoint_paddrs(
27 m,
28 n,
29 )
30 }
31}
32
33impl TlbModel {
34 pub open spec fn update(self, pt: PageTableView, va: Vaddr) -> Self {
35 let m = pt.mappings.filter(|m: Mapping| m.va_range.start <= va < m.va_range.end).choose();
36 TlbModel { pending: self.pending, mappings: self.mappings.insert(m) }
37 }
38
39 pub axiom fn tracked_update(&mut self, pt: PageTableView, va: Vaddr)
40 requires
41 old(self).inv(),
42 forall|m: Mapping|
43 old(self).mappings has m ==> !(m.va_range.start <= va < m.va_range.end),
44 exists|m: Mapping| pt.mappings has m ==> m.va_range.start <= va < m.va_range.end,
45 ensures
46 *final(self) == old(self).update(pt, va),
47 ;
48
49 pub open spec fn flush(self, va: Vaddr) -> Self {
50 let m = self.mappings.filter(|m: Mapping| m.va_range.start <= va < m.va_range.end);
51 TlbModel { pending: self.pending, mappings: self.mappings - m }
52 }
53
54 pub axiom fn tracked_flush(&mut self, va: Vaddr)
55 requires
56 old(self).inv(),
57 ensures
58 *final(self) == old(self).flush(va),
59 ;
60
61 pub open spec fn consistent_with_pt(self, pt: PageTableView) -> bool {
62 self.mappings <= pt.mappings
63 }
64
65 pub proof fn lemma_flush_preserves_inv(self, va: Vaddr)
66 requires
67 self.inv(),
68 ensures
69 self.flush(va).inv(),
70 {
71 }
72
73 pub proof fn lemma_update_preserves_consistent(self, pt: PageTableView, va: Vaddr)
74 requires
75 pt.inv(),
76 self.inv(),
77 self.consistent_with_pt(pt),
78 exists|m: Mapping| pt.mappings has m && m.va_range.start <= va < m.va_range.end,
79 ensures
80 self.update(pt, va).consistent_with_pt(pt),
81 {
82 let filtered = pt.mappings.filter(|m: Mapping| m.va_range.start <= va < m.va_range.end);
83 let m = filtered.choose();
84
85 let witness: Mapping = choose|a: Mapping|
86 pt.mappings has a && a.va_range.start <= va < a.va_range.end;
87 assert(filtered.contains(witness));
88
89 if self.mappings.contains(m) {
90 } else {
91 assert(filtered.contains(m));
92 assert(pt.mappings.contains(m));
93 }
94 }
95
96 pub proof fn lemma_consistent_with_pt_implies_inv(self, pt: PageTableView)
97 requires
98 self.inv(),
99 self.consistent_with_pt(pt),
100 pt.inv(),
101 ensures
102 self.inv(),
103 {
104 }
105
106 pub open spec fn issue_tlb_flush(self, op: TlbFlushOp) -> Self {
107 TlbModel { pending: self.pending.push(op), mappings: self.mappings }
108 }
109
110 pub proof fn tracked_issue_tlb_flush(tracked &mut self, tracked op: TlbFlushOp)
111 requires
112 old(self).inv(),
113 ensures
114 *final(self) == old(self).issue_tlb_flush(op),
115 final(self).inv(),
116 {
117 self.pending.tracked_push(op);
118 }
119
120 pub open spec fn dispatch_tlb_flush_spec(self) -> Self {
121 let op = self.pending.last();
122 let popped = TlbModel {
123 pending: self.pending[..self.pending.len() - 1],
124 mappings: self.mappings,
125 };
126 match op {
127 TlbFlushOp::All => popped,
128 TlbFlushOp::Address(va) => popped.flush(va),
129 TlbFlushOp::Range(range) => popped.flush(range.start),
130 }
131 }
132}
133
134}