ostd/mm/frame/untyped.rs
1// SPDX-License-Identifier: MPL-2.0
2//! Untyped physical memory management.
3//!
4//! As detailed in [`crate::mm::frame`], untyped memory can be accessed with
5//! relaxed rules but we cannot create references to them. This module provides
6//! the declaration of untyped frames and segments, and the implementation of
7//! extra functionalities (such as [`VmIo`]) for them.
8use vstd::prelude::*;
9use vstd_extra::ownership::OwnerOf;
10
11use crate::specs::{
12 arch::{lemma_max_paddr_range, lemma_paddr_to_vaddr_properties},
13 mm::{frame::meta_owners::MetaSlotStorage, io::VmIoOwner, virt_mem::VirtPtr},
14};
15
16use super::*;
17use crate::mm::{
18 io::{Infallible, VmReader, VmWriter},
19 kspace::{KERNEL_BASE_VADDR, KERNEL_END_VADDR, LINEAR_MAPPING_BASE_VADDR, VMALLOC_BASE_VADDR},
20 paddr_to_vaddr,
21};
22
23verus! {
24
25/// The metadata of untyped frame.
26///
27/// If a structure `M` implements [`AnyUFrameMeta`], it can be used as the
28/// metadata of a type of untyped frames [`Frame<M>`]. All frames of such type
29/// will be accessible as untyped memory.
30///
31/// `Repr<MetaSlotStorage>` is required so that `Frame<M>` is well-formed (it
32/// is no longer an `AnyFrameMeta` supertrait). This makes `AnyUFrameMeta`
33/// itself dyn-incompatible — `Segment<dyn AnyUFrameMeta>` (the `USegment`
34/// alias below) was already in an unsatisfiable state under the old
35/// supertrait chain, so this doesn't lose anything in practice.
36pub trait AnyUFrameMeta: AnyFrameMeta + vstd_extra::cast_ptr::Repr<MetaSlotStorage> {
37
38}
39
40/// A smart pointer to an untyped frame with any metadata.
41///
42/// The metadata of the frame is not known at compile time but the frame must
43/// be an untyped one. An [`UFrame`] as a parameter accepts any type of
44/// untyped frame metadata.
45///
46/// The usage of this frame will not be changed while this object is alive.
47/// Verus doesn't let us do very much with `dyn` traits, so instead of a `dyn AnyFrameMeta`
48/// we use `MetaSlotStorage`, a type that is a tagged union of the metadata types we've worked with so far.
49pub type UFrame = Frame<MetaSlotStorage>;
50
51/*
52/// Makes a structure usable as untyped frame metadata.
53///
54/// If this macro is used for built-in typed frame metadata, it won't compile.
55#[macro_export]
56macro_rules! impl_untyped_frame_meta_for {
57 // Implement without specifying the drop behavior.
58 ($t:ty) => {
59 // SAFETY: Untyped frames can be safely read.
60 unsafe impl $crate::mm::frame::meta::AnyFrameMeta for $t {
61 fn is_untyped(&self) -> bool {
62 true
63 }
64 }
65 impl $crate::mm::frame::untyped::AnyUFrameMeta for $t {}
66 };
67 // Implement with a customized drop function.
68 ($t:ty, $body:expr) => {
69 // SAFETY: Untyped frames can be safely read.
70 unsafe impl $crate::mm::frame::meta::AnyFrameMeta for $t {
71 fn on_drop(&mut self, reader: &mut $crate::mm::VmReader<$crate::mm::Infallible>) {
72 $body
73 }
74
75 fn is_untyped(&self) -> bool {
76 true
77 }
78 }
79 impl $crate::mm::frame::untyped::AnyUFrameMeta for $t {}
80 };
81}
82
83// A special case of untyped metadata is the unit type.
84impl_untyped_frame_meta_for!(()); */
85
86/// A physical memory range that is untyped.
87///
88/// Untyped frames or segments can be safely read and written by the kernel or
89/// the user.
90///
91/// TODO: Perhaps we also need to define this?
92pub trait UntypedMem {
93 /// Borrows a reader that can read the untyped memory.
94 fn reader(&self) -> VmReader<'_, Infallible>;
95
96 /// Borrows a writer that can write the untyped memory.
97 fn writer(&self) -> VmWriter<'_, Infallible>;
98}
99
100#[verus_verify]
101impl<M: AnyUFrameMeta + OwnerOf> Segment<M> {
102 #[inline(always)]
103 #[verus_spec(r =>
104 with
105 -> owner: Tracked<VmIoOwner>,
106 requires
107 self.inv(),
108 ensures
109 r.inv(),
110 owner@.inv(),
111 r.wf(owner@),
112 r.cursor.vaddr == paddr_to_vaddr(self.start_paddr()),
113 r.remain_spec() == self.size(),
114 owner@.is_kernel,
115 )]
116 pub fn reader(&self) -> VmReader<'_, Infallible> {
117 proof_decl! {
118 let ghost id: nat;
119 let tracked owner: VmIoOwner;
120 }
121 proof {
122 lemma_max_paddr_range();
123 }
124
125 let vaddr = paddr_to_vaddr(self.start_paddr());
126 let len = self.size();
127 let ghost range = vaddr..(vaddr + len) as usize;
128 let ptr = VirtPtr { vaddr, range: Ghost(range) };
129 proof {
130 lemma_paddr_to_vaddr_properties(self.start_paddr());
131 assert(KERNEL_BASE_VADDR > 0) by (compute_only);
132 assert(VMALLOC_BASE_VADDR <= KERNEL_END_VADDR) by (compute_only);
133 }
134
135 let reader = unsafe {
136 #[verus_spec(with Ghost(id) => Tracked(owner))]
137 VmReader::from_kernel_space(ptr, len)
138 };
139
140 proof_with!(|= Tracked(owner));
141 reader
142 }
143
144 #[inline(always)]
145 #[verus_spec(r =>
146 with
147 -> owner: Tracked<VmIoOwner>,
148 requires
149 self.inv(),
150 ensures
151 r.inv(),
152 owner@.inv(),
153 r.wf(owner@),
154 r.cursor.vaddr == paddr_to_vaddr(self.start_paddr()),
155 r.avail_spec() == self.size(),
156 owner@.is_kernel,
157 !owner@.is_fallible,
158 )]
159 pub fn writer(&self) -> VmWriter<'_, Infallible> {
160 proof_decl! {
161 let ghost id: nat;
162 let tracked owner: VmIoOwner;
163 }
164 proof {
165 lemma_max_paddr_range();
166 }
167
168 let vaddr = paddr_to_vaddr(self.start_paddr());
169 let len = self.size();
170 let ghost range = vaddr..(vaddr + len) as usize;
171 let ptr = VirtPtr { vaddr, range: Ghost(range) };
172 proof {
173 lemma_paddr_to_vaddr_properties(self.start_paddr());
174 assert(KERNEL_BASE_VADDR > 0) by (compute_only);
175 assert(VMALLOC_BASE_VADDR <= KERNEL_END_VADDR) by (compute_only);
176 }
177
178 let writer = unsafe {
179 #[verus_spec(with Ghost(id), Tracked(false) => Tracked(owner))]
180 VmWriter::from_kernel_space(ptr, len)
181 };
182
183 proof_with!(|= Tracked(owner));
184 writer
185 }
186}
187
188/*
189// Original impl_untyped_for! macro and its invocations (removed during Verus migration):
190// This macro provided UntypedMem + VmIo implementations for both Frame<UM> and Segment<UM>.
191
192macro_rules! impl_untyped_for {
193 ($t:ident) => {
194 impl<UM: AnyUFrameMeta + ?Sized> UntypedMem for $t<UM> {
195 fn reader(&self) -> VmReader<'_, Infallible> {
196 let ptr = paddr_to_vaddr(self.start_paddr()) as *const u8;
197 unsafe { VmReader::from_kernel_space(ptr, self.size()) }
198 }
199
200 fn writer(&self) -> VmWriter<'_, Infallible> {
201 let ptr = paddr_to_vaddr(self.start_paddr()) as *mut u8;
202 unsafe { VmWriter::from_kernel_space(ptr, self.size()) }
203 }
204 }
205
206 impl<UM: AnyUFrameMeta + ?Sized> VmIo for $t<UM> {
207 fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
208 let read_len = writer.avail().min(self.size().saturating_sub(offset));
209 let max_offset = offset.checked_add(read_len).ok_or(Error::Overflow)?;
210 if max_offset > self.size() {
211 return Err(Error::InvalidArgs);
212 }
213 let len = self
214 .reader()
215 .skip(offset)
216 .read_fallible(writer)
217 .map_err(|(e, _)| e)?;
218 debug_assert!(len == read_len);
219 Ok(())
220 }
221
222 fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
223 let write_len = reader.remain().min(self.size().saturating_sub(offset));
224 let max_offset = offset.checked_add(write_len).ok_or(Error::Overflow)?;
225 if max_offset > self.size() {
226 return Err(Error::InvalidArgs);
227 }
228 let len = self
229 .writer()
230 .skip(offset)
231 .write_fallible(reader)
232 .map_err(|(e, _)| e)?;
233 debug_assert!(len == write_len);
234 Ok(())
235 }
236 }
237 };
238}
239
240impl_untyped_for!(Frame);
241impl_untyped_for!(Segment);
242*/
243} // verus!