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