ostd/mm/page_prop.rs
1// SPDX-License-Identifier: MPL-2.0
2//! Definitions of page mapping properties.
3use vstd::prelude::*;
4use vstd_extra::prelude::*;
5
6use core::fmt::Debug;
7
8use bitflags::bitflags;
9
10/// The property of a mapped virtual memory page.
11#[verus_verify]
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub struct PageProperty {
14 /// The flags associated with the page,
15 pub flags: PageFlags,
16 /// The cache policy for the page.
17 pub cache: CachePolicy,
18 pub priv_flags: PrivilegedPageFlags,
19}
20
21#[verus_verify]
22impl PageProperty {
23 /// Creates a new `PageProperty` with the given flags and cache policy for the user.
24 #[verus_verify(dual_spec)]
25 #[verus_spec(returns Self::new_user(flags, cache))]
26 pub fn new_user(flags: PageFlags, cache: CachePolicy) -> Self {
27 Self {
28 flags,
29 cache,
30 priv_flags: PrivilegedPageFlags::USER(),
31 }
32 }
33
34 /// Creates a page property that implies an invalid page without mappings.
35 #[verus_verify(dual_spec)]
36 #[verus_spec(returns Self::new_absent())]
37 pub fn new_absent() -> Self {
38 Self {
39 flags: PageFlags::empty(),
40 cache: CachePolicy::Writeback,
41 priv_flags: PrivilegedPageFlags::empty(),
42 }
43 }
44}
45
46// TODO: Make it more abstract when supporting other architectures.
47/// A type to control the cacheability of the main memory.
48///
49/// The type currently follows the definition as defined by the AMD64 manual.
50#[verus_verify]
51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub enum CachePolicy {
53 /// Uncacheable (UC).
54 ///
55 /// Reads from, and writes to, UC memory are not cacheable.
56 /// Reads from UC memory cannot be speculative.
57 /// Write-combining to UC memory is not allowed.
58 /// Reads from or writes to UC memory cause the write buffers to be written to memory
59 /// and be invalidated prior to the access to UC memory.
60 ///
61 /// The UC memory type is useful for memory-mapped I/O devices
62 /// where strict ordering of reads and writes is important.
63 Uncacheable,
64 /// Write-Combining (WC).
65 ///
66 /// Reads from, and writes to, WC memory are not cacheable.
67 /// Reads from WC memory can be speculative.
68 ///
69 /// Writes to this memory type can be combined internally by the processor
70 /// and written to memory as a single write operation to reduce memory accesses.
71 ///
72 /// The WC memory type is useful for graphics-display memory buffers
73 /// where the order of writes is not important.
74 WriteCombining,
75 /// Write-Protect (WP).
76 ///
77 /// Reads from WP memory are cacheable and allocate cache lines on a read miss.
78 /// Reads from WP memory can be speculative.
79 ///
80 /// Writes to WP memory that hit in the cache do not update the cache.
81 /// Instead, all writes update memory (write to memory),
82 /// and writes that hit in the cache invalidate the cache line.
83 /// Write buffering of WP memory is allowed.
84 ///
85 /// The WP memory type is useful for shadowed-ROM memory
86 /// where updates must be immediately visible to all devices that read the shadow locations.
87 WriteProtected,
88 /// Writethrough (WT).
89 ///
90 /// Reads from WT memory are cacheable and allocate cache lines on a read miss.
91 /// Reads from WT memory can be speculative.
92 ///
93 /// All writes to WT memory update main memory,
94 /// and writes that hit in the cache update the cache line.
95 /// Writes that miss the cache do not allocate a cache line.
96 /// Write buffering of WT memory is allowed.
97 Writethrough,
98 /// Writeback (WB).
99 ///
100 /// The WB memory is the "normal" memory. See detailed descriptions in the manual.
101 ///
102 /// This type of memory provides the highest-possible performance
103 /// and is useful for most software and data stored in system memory (DRAM).
104 Writeback,
105}
106
107bitflags! {
108 /// Page protection permissions and access status.
109 pub struct PageFlags: u8 {
110 /// Readable.
111 const R = 0b00000001;
112 /// Writable.
113 const W = 0b00000010;
114 /// Executable.
115 const X = 0b00000100;
116 /// Readable + writable.
117 //const RW = Self::R.bits | Self::W.bits;
118 const RW = 0b00000011;
119 /// Readable + executable.
120 //const RX = Self::R.bits | Self::X.bits;
121 const RX = 0b00000101;
122 /// Readable + writable + executable.
123 //const RWX = Self::R.bits | Self::W.bits | Self::X.bits;
124 const RWX = 0b00000111;
125 /// Has the memory page been read or written.
126 const ACCESSED = 0b00001000;
127 /// Has the memory page been written.
128 const DIRTY = 0b00010000;
129
130 /// The first bit available for software use.
131 const AVAIL1 = 0b01000000;
132 /// The second bit available for software use.
133 const AVAIL2 = 0b10000000;
134 }
135}
136
137bitflags! {
138 /// Page property that are only accessible in OSTD.
139 pub struct PrivilegedPageFlags: u8 {
140 /// Accessible from user mode.
141 const USER = 0b00000001;
142 /// Global page that won't be evicted from TLB with normal TLB flush.
143 const GLOBAL = 0b00000010;
144
145 /// (TEE only) If the page is shared with the host.
146 /// Otherwise the page is ensured confidential and not visible outside the guest.
147 #[cfg(all(target_arch = "x86_64", feature = "cvm_guest"))]
148 const SHARED = 0b10000000;
149 }
150}
151
152verus! {
153
154impl Inv for PageProperty {
155 open spec fn inv(self) -> bool {
156 &&& self.flags.bits() & PageFlags::all().bits() == self.flags.bits()
157 &&& self.priv_flags.bits() & PrivilegedPageFlags::all().bits() == self.priv_flags.bits()
158 }
159}
160
161impl PageProperty {
162 /// Adding and removing `AVAIL1` is reversible when it is used as a reserved tag.
163 pub proof fn lemma_avail1_tag_encoding(self)
164 ensures
165 self.flags.union(PageFlags::AVAIL1()).contains(PageFlags::AVAIL1()),
166 !self.flags.difference(PageFlags::AVAIL1()).contains(PageFlags::AVAIL1()),
167 !self.flags.contains(PageFlags::AVAIL1()) ==> self.flags.difference(PageFlags::AVAIL1())
168 == self.flags,
169 !self.flags.contains(PageFlags::AVAIL1()) ==> self.flags.union(
170 PageFlags::AVAIL1(),
171 ).difference(PageFlags::AVAIL1()) == self.flags,
172 self.flags.contains(PageFlags::AVAIL1()) ==> self.flags.difference(
173 PageFlags::AVAIL1(),
174 ).union(PageFlags::AVAIL1()) == self.flags,
175 {
176 broadcast use PageFlags::lemma_consts;
177
178 let tag = PageFlags::AVAIL1();
179 let bits = self.flags.bits();
180 let tag_bits = tag.bits();
181 assert(((bits | tag_bits) & tag_bits) == tag_bits) by (bit_vector);
182 assert(((bits & !tag_bits) & tag_bits) == 0u8) by (bit_vector);
183 if !self.flags.contains(tag) {
184 assert((bits & tag_bits) != tag_bits);
185 assert((bits & tag_bits) == 0u8) by (bit_vector)
186 requires
187 tag_bits == 0x40u8,
188 (bits & tag_bits) != tag_bits,
189 ;
190 assert((bits & !tag_bits) == bits) by (bit_vector)
191 requires
192 (bits & tag_bits) == 0u8,
193 ;
194 assert(((bits | tag_bits) & !tag_bits) == bits) by (bit_vector)
195 requires
196 (bits & tag_bits) == 0u8,
197 ;
198 PageFlags::lemma_eq_from_bits(self.flags.difference(tag), self.flags);
199 PageFlags::lemma_eq_from_bits(self.flags.union(tag).difference(tag), self.flags);
200 } else {
201 assert((bits & tag_bits) == tag_bits);
202 assert(((bits & !tag_bits) | tag_bits) == bits) by (bit_vector)
203 requires
204 (bits & tag_bits) == tag_bits,
205 ;
206 PageFlags::lemma_eq_from_bits(self.flags.difference(tag).union(tag), self.flags);
207 }
208 }
209}
210
211} // verus!