ostd/specs/mm/
tlb.rs

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