Skip to main content

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!