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 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!