Skip to main content

ostd/mm/
io.rs

1// SPDX-License-Identifier: MPL-2.0
2//! Abstractions for reading and writing virtual memory (VM) objects.
3//!
4//! # Safety
5//!
6//! The core virtual memory (VM) access APIs provided by this module are [`VmReader`] and
7//! [`VmWriter`], which allow for writing to or reading from a region of memory _safely_.
8//! `VmReader` and `VmWriter` objects can be constructed from memory regions of either typed memory
9//! (e.g., `&[u8]`) or untyped memory (e.g, [`UFrame`]). Behind the scene, `VmReader` and `VmWriter`
10//! must be constructed via their [`from_user_space`] and [`from_kernel_space`] methods, whose
11//! safety depends on whether the given memory regions are _valid_ or not.
12//!
13//! [`UFrame`]: crate::mm::UFrame
14//! [`from_user_space`]: `VmReader::from_user_space`
15//! [`from_kernel_space`]: `VmReader::from_kernel_space`
16//!
17//! Here is a list of conditions for memory regions to be considered valid:
18//!
19//! - The memory region as a whole must be either typed or untyped memory, not both typed and
20//!   untyped.
21//!
22//! - If the memory region is typed, we require that:
23//!   - the [validity requirements] from the official Rust documentation must be met, and
24//!   - the type of the memory region (which must exist since the memory is typed) must be
25//!     plain-old-data, so that the writer can fill it with arbitrary data safely.
26//!
27//! [validity requirements]: core::ptr#safety
28//!
29//! - If the memory region is untyped, we require that:
30//!   - the underlying pages must remain alive while the validity requirements are in effect, and
31//!   - the kernel must access the memory region using only the APIs provided in this module, but
32//!     external accesses from hardware devices or user programs do not count.
33//!
34//! We have the last requirement for untyped memory to be valid because the safety interaction with
35//! other ways to access the memory region (e.g., atomic/volatile memory loads/stores) is not
36//! currently specified. Tis may be relaxed in the future, if appropriate and necessary.
37//!
38//! Note that data races on untyped memory are explicitly allowed (since pages can be mapped to
39//! user space, making it impossible to avoid data races). However, they may produce erroneous
40//! results, such as unexpected bytes being copied, but do not cause soundness problems.
41use crate::arch::mm::{__memcpy_fallible, __memset_fallible};
42
43use core::marker::PhantomData;
44use core::ops::Range;
45use vstd::arithmetic::power2::is_pow2;
46use vstd::prelude::*;
47use vstd::simple_pptr::*;
48use vstd_extra::assert;
49use vstd_extra::ownership::Inv;
50use vstd_extra::panic::may_panic;
51
52use crate::error::*;
53pub use crate::specs::mm::io::{
54    VmIoMemView, VmIoOwner, axiom_kernel_mem_view, axiom_slice_in_kernel,
55};
56use crate::specs::mm::virt_mem::{MemView, VirtPtr};
57use crate::{
58    Pod,
59    mm::{
60        MAX_USERSPACE_VADDR,
61        kspace::{KERNEL_BASE_VADDR, KERNEL_END_VADDR},
62    },
63};
64
65verus! {
66
67proof fn lemma_add_aligned_stride(start: usize, i: usize, len: usize, align: usize)
68    requires
69        align > 0,
70        start % align == 0,
71        len % align == 0,
72    ensures
73        (start + i * len) % align as int == 0,
74{
75    let a = align as int;
76    let q_start = start as int / a;
77    let q_len = len as int / a;
78    vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, a);
79    vstd::arithmetic::div_mod::lemma_fundamental_div_mod(len as int, a);
80    assert((q_start + i * q_len) * a == q_start * a + (i * q_len) * a) by (nonlinear_arith);
81    assert((i * q_len) * a == i * (q_len * a)) by (nonlinear_arith);
82    vstd::arithmetic::div_mod::lemma_mod_multiples_basic(q_start + i as int * q_len, a);
83}
84
85/// Verus spec stub for [`<*mut T>::is_aligned`]: returns whether the pointer's address is a
86/// multiple of `align_of::<T>()`.
87pub assume_specification<T>[ <*mut T>::is_aligned ](_0: *mut T) -> (res: bool)
88    ensures
89        res <==> (_0 as usize) % core::mem::align_of::<T>() == 0,
90;
91
92/// Copies `len` bytes from `src` to `dst`, stopping early on page fault.
93/// Returns the number of bytes successfully copied (which is at most `len`).
94///
95/// The return value bound is the only thing the verifier promises; the actual
96/// memory state after the call is trusted (the underlying arch primitive is
97/// `extern "C"`).
98///
99/// # Safety
100/// - `src` must be valid for reads of `len` bytes.
101/// - `dst` must either be valid for writes of `len` bytes or be in user space.
102#[verifier::external_body]
103#[verus_spec(r =>
104    ensures
105        r <= len,
106)]
107unsafe fn memcpy_fallible(dst: VirtPtr, src: VirtPtr, len: usize) -> usize {
108    // SAFETY: The safety is upheld by the caller.
109    let failed_bytes = unsafe { __memcpy_fallible(dst.vaddr as *mut u8, src.vaddr as *const u8, len)
110    };
111    len - failed_bytes
112}
113
114/// Fills `len` bytes of memory at `dst` with the specified `value`, stopping
115/// early on page fault. Returns the number of bytes successfully set (at most `len`).
116///
117/// The return value bound is the only thing the verifier promises; the actual
118/// memory state after the call is trusted (the underlying arch primitive is
119/// `extern "C"`).
120///
121/// # Safety
122/// - `dst` must either be valid for writes of `len` bytes or be in user space.
123#[verifier::external_body]
124#[verus_spec(r =>
125    ensures
126        r <= len,
127)]
128unsafe fn memset_fallible(dst: VirtPtr, value: u8, len: usize) -> usize {
129    // SAFETY: The safety is upheld by the caller.
130    let failed_bytes = unsafe { __memset_fallible(dst.vaddr as *mut u8, value, len) };
131    len - failed_bytes
132}
133
134/// Marker type indicating that VM I/O operations may fail (e.g., user-space access).
135pub struct Fallible {}
136
137/// Marker type indicating that VM I/O operations cannot fail (e.g., kernel-space access).
138pub struct Infallible {}
139
140/// Copies `len` bytes from `src` to `dst`.
141///
142/// This is the escape hatch into the abstract [`VirtPtr`] memory model: it is
143/// the only place in the executable code that performs a multi-byte copy, and
144/// it discharges the obligation by delegating to [`VirtPtr::copy_nonoverlapping`].
145///
146/// # Safety
147///
148/// - `src` must be [valid] for reads of `len` bytes.
149/// - `dst` must be [valid] for writes of `len` bytes.
150///
151/// [valid]: crate::mm::io#safety
152#[inline]
153#[verus_spec(
154    with
155        Tracked(mem_src): Tracked<&MemView>,
156        Tracked(mem_dst): Tracked<&mut MemView>,
157    requires
158        src.inv(),
159        dst.inv(),
160        src.vaddr + len <= src.range@.end,
161        forall|i: usize|
162            #![trigger mem_src.addr_transl(i)]
163            src.vaddr <= i < src.vaddr + len ==> {
164                &&& mem_src.addr_transl(i) is Some
165                &&& mem_src.memory.contains_key((mem_src.addr_transl(i)->0).0)
166                &&& mem_src.memory[(mem_src.addr_transl(i)->0).0].contents[(mem_src.addr_transl(i)->0).1 as int] is Init
167            },
168        dst.vaddr + len <= dst.range@.end,
169        forall|i: usize|
170            dst.vaddr <= i < dst.vaddr + len ==> {
171                &&& old(mem_dst).addr_transl(i) is Some
172            },
173    ensures
174        *final(mem_dst) == VirtPtr::memcpy_spec(src, dst, *mem_src, *old(mem_dst), len),
175        final(mem_dst).mappings == old(mem_dst).mappings,
176        old(mem_dst).memory.dom().subset_of(final(mem_dst).memory.dom()),
177        forall|i: usize|
178            #![trigger final(mem_dst).addr_transl(i)]
179            dst.vaddr <= i < dst.vaddr + len ==> {
180                &&& final(mem_dst).addr_transl(i) is Some
181            },
182)]
183unsafe fn memcpy(dst: VirtPtr, src: VirtPtr, len: usize) {
184    /*
185    // Original memcpy using volatile_copy_memory (replaced during Verus migration):
186    unsafe { core::intrinsics::volatile_copy_memory(dst, src, len) };
187    */
188    VirtPtr::copy_nonoverlapping(&src, &dst, Tracked(mem_src), Tracked(mem_dst), len);
189}
190
191/// [`VmReader`] is a reader for reading data from a contiguous range of memory.
192///
193/// The memory range read by [`VmReader`] can be in either kernel space or user space.
194/// When the operating range is in kernel space, the memory within that range
195/// is guaranteed to be valid, and the corresponding memory reads are infallible.
196/// When the operating range is in user space, it is ensured that the page table of
197/// the process creating the [`VmReader`] is active for the duration of `'a`,
198/// and the corresponding memory reads are considered fallible.
199///
200/// When perform reading with a [`VmWriter`], if one of them represents typed memory,
201/// it can ensure that the reading range in this reader and writing range in the
202/// writer are not overlapped.
203///
204/// NOTE: The overlap mentioned above is at both the virtual address level
205/// and physical address level. There is not guarantee for the operation results
206/// of [`VmReader`] and [`VmWriter`] in overlapping untyped addresses, and it is
207/// the user's responsibility to handle this situation.
208pub struct VmReader<'a, Fallibility = Fallible> {
209    pub ghost_id: Ghost<nat>,
210    pub cursor: VirtPtr,
211    pub end: VirtPtr,
212    pub phantom: PhantomData<(&'a [u8], Fallibility)>,
213}
214
215/// [`VmWriter`] is a writer for writing data to a contiguous range of memory.
216///
217/// The memory range write by [`VmWriter`] can be in either kernel space or user space.
218/// When the operating range is in kernel space, the memory within that range
219/// is guaranteed to be valid, and the corresponding memory writes are infallible.
220/// When the operating range is in user space, it is ensured that the page table of
221/// the process creating the [`VmWriter`] is active for the duration of `'a`,
222/// and the corresponding memory writes are considered fallible.
223///
224/// When perform writing with a [`VmReader`], if one of them represents typed memory,
225/// it can ensure that the writing range in this writer and reading range in the
226/// reader are not overlapped.
227///
228/// NOTE: The overlap mentioned above is at both the virtual address level
229/// and physical address level. There is not guarantee for the operation results
230/// of [`VmReader`] and [`VmWriter`] in overlapping untyped addresses, and it is
231/// the user's responsibility to handle this situation.
232pub struct VmWriter<'a, Fallibility = Fallible> {
233    pub ghost_id: Ghost<nat>,
234    pub cursor: VirtPtr,
235    pub end: VirtPtr,
236    pub phantom: PhantomData<(&'a [u8], Fallibility)>,
237}
238
239#[verus_verify]
240impl<'a> VmWriter<'a, Infallible> {
241    /// Constructs a [`VmWriter`] from a pointer and a length, which represents
242    /// a memory range in kernel space.
243    ///
244    /// # Verified Properties
245    /// ## Preconditions
246    /// - The memory region represented by `ptr` and `len` must be valid for writes of `len` bytes
247    ///   during the entire lifetime `a`. This means that the underlying pages must remain alive,
248    ///   and the kernel must access the memory region using only the APIs provided in this module.
249    /// - The range `ptr.vaddr..ptr.vaddr + len` must represent a kernel space memory range.
250    /// ## Postconditions
251    /// - An infallible [`VmWriter`] will be created with the range `ptr.vaddr..ptr.vaddr + len`.
252    /// - The created [`VmWriter`] will have a unique identifier `id`, and its cursor will be
253    ///   initialized to `ptr`.
254    /// - The created [`VmWriter`] will be associated with a [`VmIoOwner`] that has the same `id`, the
255    ///   same memory range, and is marked as kernel space and infallible.
256    /// - The memory view of the associated [`VmIoOwner`] will be `None`, indicating that it does not
257    ///   have any specific permissions yet.
258    /// ## Safety
259    ///
260    /// `ptr` must be [valid] for writes of `len` bytes during the entire lifetime `a`.
261    ///
262    /// [valid]: crate::mm::io#safety
263    #[verus_spec(r =>
264        with
265            Ghost(id): Ghost<nat>,
266            Tracked(fallible): Tracked<bool>,
267                -> owner: Tracked<VmIoOwner>,
268        ensures
269            r.inv_wf(),
270            owner@.id == id,
271            owner@.is_fallible == fallible,
272            owner@.is_kernel,
273            r.cursor == ptr,
274            r.end == ptr.wrapping_add_spec(len),
275            r.cursor.range@ == ptr.range@,
276            r.end.range@ == ptr.range@,
277            fallible ==> owner@.mem_view is None,
278            !fallible && ptr.inv() && ptr.range@.start == ptr.vaddr
279                && len == ptr.range@.end - ptr.range@.start
280                && (len == 0 || KERNEL_BASE_VADDR <= ptr.vaddr)
281                && (len == 0 || ptr.vaddr + len <= KERNEL_END_VADDR) ==> {
282                &&& r.inv()
283                &&& owner@.inv()
284                &&& r.wf(owner@)
285                &&& owner@.has_write_view()
286            },
287    )]
288    pub unsafe fn from_kernel_space(ptr: VirtPtr, len: usize) -> Self {
289        let ghost range: Range<usize> = ptr.vaddr..(ptr.vaddr + len) as usize;
290        let tracked mem_view: Option<VmIoMemView> = if fallible {
291            None
292        } else {
293            let tracked mv = axiom_kernel_mem_view(range);
294            Some(VmIoMemView::WriteView(mv))
295        };
296        let tracked owner = VmIoOwner {
297            id,
298            range: ptr.vaddr..(ptr.vaddr + len) as usize,
299            is_fallible: fallible,
300            is_kernel: true,
301            mem_view,
302        };
303
304        proof_with!(|= Tracked(owner));
305        Self { ghost_id: Ghost(id), cursor: ptr, end: ptr.wrapping_add(len), phantom: PhantomData }
306    }
307
308    /// Converts an infallible writer into a fallible one.
309    #[verus_spec(r =>
310        ensures
311            r.cursor == self.cursor,
312            r.end == self.end,
313            r.ghost_id == self.ghost_id,
314    )]
315    pub fn to_fallible(self) -> VmWriter<'a, Fallible> {
316        VmWriter {
317            ghost_id: self.ghost_id,
318            cursor: self.cursor,
319            end: self.end,
320            phantom: PhantomData,
321        }
322    }
323
324    /// Writes a value of `Pod` type to the kernel-space buffer.
325    ///
326    /// If the length of the `Pod` type exceeds `self.avail()`, this method
327    /// will return `Err(InvalidArgs)`. Kernel-space writes don't fault, so
328    /// no rollback is needed — see [`VmWriter<Fallible>::write_val`] for the
329    /// user-space variant with cursor rewind.
330    ///
331    /// # Verified Properties
332    /// ## Preconditions
333    /// - The writer and its owner must satisfy their invariants.
334    /// - The owner must match this writer and carry a write memory view.
335    /// ## Postconditions
336    /// - The writer and owner still satisfy their invariants.
337    /// - On success, the cursor advances by `size_of::<T>()`.
338    /// - On error, the writer state is unchanged.
339    #[verus_spec(r =>
340        with
341            Tracked(owner): Tracked<&mut VmIoOwner>,
342        requires
343            old(self).inv(),
344            old(self).wf(*old(owner)),
345            old(owner).has_write_view(),
346        ensures
347            final(self).inv(),
348            final(owner).inv(),
349            final(self).wf(*final(owner)),
350            match r {
351                Ok(_) => {
352                    &&& final(self).avail_spec() == old(self).avail_spec() - core::mem::size_of::<T>()
353                    &&& final(self).cursor.vaddr == old(self).cursor.vaddr + core::mem::size_of::<T>()
354                },
355                Err(_) => {
356                    *old(self) == *final(self)
357                },
358            }
359    )]
360    pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> {
361        let len = core::mem::size_of::<T>();
362        if self.avail() < len {
363            return Err(Error::InvalidArgs);
364        }
365        proof_decl! {
366            let tracked mut reader_owner_inner: VmIoOwner;
367        }
368        #[verus_spec(with => Tracked(reader_owner_inner))]
369        let mut reader = VmReader::from(new_val.as_bytes());
370        #[verus_spec(with Tracked(owner), Tracked(&mut reader_owner_inner))]
371        let _ = self.write(&mut reader);
372        Ok(())
373    }
374
375    /// Panic condition for [`Self::fill`]: either the cursor isn't aligned
376    /// for `T`, or the available space isn't a multiple of `size_of::<T>()`.
377    pub open spec fn fill_panic_condition<T>(self) -> bool {
378        ||| self.cursor.vaddr as int % core::mem::align_of::<T>() as int != 0
379        ||| (self.end.vaddr - self.cursor.vaddr) % core::mem::size_of::<T>() as int != 0
380    }
381
382    /// Fills the available space by repeatedly writing the same `Pod` value.
383    ///
384    /// Returns the number of elements written.
385    ///
386    /// # Panics
387    /// If cursor isn't aligned for `T`, or `avail()` isn't a multiple of
388    /// `size_of::<T>()` ([`Self::fill_panic_condition`]).
389    #[verus_spec(r =>
390        with
391            Tracked(writer_owner): Tracked<&mut VmIoOwner>,
392                -> reader_owner: Tracked<VmIoOwner>,
393        requires
394            old(self).inv(),
395            old(self).wf(*old(writer_owner)),
396            old(writer_owner).has_write_view(),
397            core::mem::size_of::<T>() > 0,
398            core::mem::align_of::<T>() > 0,
399            core::mem::size_of::<T>() % core::mem::align_of::<T>() == 0,
400            old(self).fill_panic_condition::<T>() ==> may_panic(),
401        ensures
402            final(self).inv(),
403            final(self).wf(*final(writer_owner)),
404            !old(self).fill_panic_condition::<T>(),
405            final(self).cursor == old(self).end,
406            final(self).end == old(self).end,
407            // writer_owner: fully advanced past the filled region.
408            final(writer_owner).range.start == old(writer_owner).range.end,
409            final(writer_owner).range.end == old(writer_owner).range.end,
410            // reader_owner: brand-new ReadView over the filled region.
411            reader_owner@.inv(),
412            reader_owner@.range.start == old(writer_owner).range.start,
413            reader_owner@.range.end == old(writer_owner).range.end,
414            reader_owner@.has_read_view(),
415            reader_owner@.is_kernel == old(writer_owner).is_kernel,
416            // Return value: exactly `avail / size_of::<T>()` elements written.
417            r * core::mem::size_of::<T>() == old(self).avail_spec(),
418    )]
419    pub fn fill<T: Pod>(&mut self, value: T) -> usize {
420        let cursor = self.cursor.cast::<T>();
421        assert!(cursor.is_aligned());
422
423        let avail = self.avail();
424        assert!(avail % core::mem::size_of::<T>() == 0);
425        let len = core::mem::size_of::<T>();
426        let written_num = avail / len;
427        proof {
428            // (avail / len) * len == avail when avail % len == 0 and len > 0.
429            assert(written_num * len == avail) by (nonlinear_arith)
430                requires
431                    len > 0,
432                    avail % len == 0,
433                    written_num == avail / len,
434            ;
435        }
436
437        proof_decl! {
438            let tracked mut reader_owner_inner: VmIoOwner;
439        }
440
441        let tracked mut mv = match writer_owner.mem_view.tracked_take() {
442            VmIoMemView::WriteView(v) => v,
443            _ => { proof_from_false() },
444        };
445        let ghost mv_pre = mv;
446        let ghost start = self.cursor.vaddr;
447        let ghost end = self.end.vaddr;
448        let ghost cursor_range = self.cursor.range@;
449
450        let mut cursor_i: VirtPtr = self.cursor;
451        let mut i: usize = 0;
452        while i < written_num
453            invariant
454                self.inv(),
455                self.cursor.vaddr == start,
456                self.end.vaddr == end,
457                self.cursor.range@ == cursor_range,
458                end - start == avail,
459                avail == written_num * len,
460                len == core::mem::size_of::<T>(),
461                len > 0,
462                core::mem::align_of::<T>() > 0,
463                len % core::mem::align_of::<T>() == 0,
464                start % core::mem::align_of::<T>() == 0,
465                cursor_i.range@ == cursor_range,
466                cursor_i.vaddr == start + i * len,
467                cursor_i.vaddr <= end,
468                cursor_i.vaddr % core::mem::align_of::<T>() == 0,
469                i <= written_num,
470                mv.mappings == mv_pre.mappings,
471                forall|va: usize|
472                    #![trigger mv.addr_transl(va)]
473                    start <= va < end ==> mv.addr_transl(va) is Some,
474            decreases written_num - i,
475        {
476            proof {
477                // (i + 1) * len <= written_num * len, hence cursor_i.vaddr + len <= end
478                assert((i + 1) * len <= written_num * len) by (nonlinear_arith)
479                    requires
480                        i < written_num,
481                        len > 0,
482                ;
483                assert(i * len + len == (i + 1) * len) by (nonlinear_arith);
484                // forall va in [cursor_i.vaddr, cursor_i.vaddr + len), mv.addr_transl is Some
485                assert forall|va: usize|
486                    cursor_i.vaddr <= va < cursor_i.vaddr + len implies #[trigger] mv.addr_transl(
487                    va,
488                ) is Some by {};
489            }
490            // SAFETY: written_num is bounded by avail / size_of::<T>() so each
491            // write targets memory owned by this writer, and cursor is aligned.
492            #[allow(unused_unsafe)]
493            unsafe { cursor_i.write_volatile::<T>(Tracked(&mut mv), value) };
494            let ghost cursor_i_pre = cursor_i;
495            cursor_i = cursor_i.wrapping_add(len);
496            i = i + 1;
497            proof {
498                lemma_add_aligned_stride(start, i, len, core::mem::align_of::<T>());
499            }
500        }
501
502        proof {
503            writer_owner.mem_view = Some(VmIoMemView::WriteView(mv));
504            // Split off the front of writer_owner (the filled region) as a new
505            // VmIoOwner and convert its WriteView to a ReadView so the caller
506            // can read back what was just written.
507            reader_owner_inner = writer_owner.split(avail);
508            reader_owner_inner.write_to_read();
509        }
510
511        // All available space has been filled; cursor moves to end.
512        self.cursor = self.end;
513        proof_with!(|= Tracked(reader_owner_inner));
514        written_num
515    }
516
517    /// Writes data into `self` by reading from the provided `reader`.
518    ///
519    /// This function treats `self` as the destination buffer. It pulls data *from*
520    /// the source `reader` and writes it into the current instance.
521    ///
522    /// # Arguments
523    ///
524    /// * `reader` - The source `VmReader` to read data from.
525    ///
526    /// # Returns
527    ///
528    /// Returns the number of bytes written to `self` (which is equal to the number of bytes read from `reader`).
529    ///
530    /// # Verified Properties
531    /// ## Preconditions
532    /// - The writer, reader, and both associated owners must satisfy their invariants.
533    /// - The owners must match the given writer and reader.
534    /// - The writer owner must carry a write memory view.
535    /// - The source and destination ranges must not overlap.
536    /// - The reader owner must provide initialized readable memory for the readable range.
537    /// ## Postconditions
538    /// - The writer, reader, and both owners still satisfy their invariants.
539    /// - The owners still match the updated writer and reader.
540    /// - The returned byte count equals the minimum of writable bytes and readable bytes.
541    /// - Both cursors advance by exactly the returned byte count.
542    #[verus_spec(r =>
543        with
544            Tracked(owner_w): Tracked<&mut VmIoOwner>,
545            Tracked(owner_r): Tracked<&mut VmIoOwner>,
546        requires
547            old(self).inv(),
548            old(reader).inv(),
549            old(self).wf(*old(owner_w)),
550            old(reader).wf(*old(owner_r)),
551            old(owner_w).has_write_view(),
552            old(owner_r).read_view_initialized(),
553        ensures
554            final(self).inv(),
555            final(reader).inv(),
556            final(owner_w).inv(),
557            final(owner_r).inv(),
558            final(self).wf(*final(owner_w)),
559            final(reader).wf(*final(owner_r)),
560            r == vstd::math::min(old(self).avail_spec() as int, old(reader).remain_spec() as int),
561            final(self).avail_spec() == old(self).avail_spec() - r as usize,
562            final(self).cursor.vaddr == old(self).cursor.vaddr + r as usize,
563            final(reader).remain_spec() == old(reader).remain_spec() - r as usize,
564            final(reader).cursor.vaddr == old(reader).cursor.vaddr + r as usize,
565    )]
566    pub fn write(&mut self, reader: &mut VmReader<'_, Infallible>) -> usize {
567        proof_decl! {
568            let tracked mut _discarded_consumed_w: VmIoOwner;
569        }
570        #[verus_spec(with Tracked(owner_r), Tracked(owner_w) => Tracked(_discarded_consumed_w))]
571        reader.read(self)
572    }
573
574    /// Writes a value of the `PodOnce` type using one non-tearing memory store.
575    ///
576    /// If the length of the `PodOnce` type exceeds `self.avail()`, this method will return `Err`.
577    ///
578    /// # Panics
579    ///
580    /// This method will panic if the current position of the writer does not meet the alignment
581    /// requirements of type `T`.
582    ///
583    /// # Verified Properties
584    /// ## Preconditions
585    /// - The writer and its owner must satisfy their invariants.
586    /// - The owner must match this writer and carry a write memory view.
587    /// - Every byte in the writable range must translate in the write view.
588    /// ## Postconditions
589    /// - The writer and owner still satisfy their invariants.
590    /// - On success, the cursor advances by `size_of::<T>()` and the cursor was
591    ///   aligned to `align_of::<T>()` (the runtime `assert!` would otherwise diverge).
592    /// - On error, the writer state is unchanged.
593    #[verus_spec(r =>
594        with
595            Tracked(owner): Tracked<&mut VmIoOwner>,
596        requires
597            old(self).inv(),
598            old(self).wf(*old(owner)),
599            old(owner).has_write_view(),
600            // The runtime `assert!(cursor.is_aligned())` diverges unless the
601            // cursor is aligned for `T`.
602            old(self).cursor.vaddr % core::mem::align_of::<T>() != 0 ==> may_panic(),
603        ensures
604            final(self).inv(),
605            final(owner).inv(),
606            final(self).wf(*final(owner)),
607            match r {
608                Ok(_) => {
609                    &&& old(self).cursor.vaddr % core::mem::align_of::<T>() == 0
610                    &&& final(self).avail_spec() == old(self).avail_spec() - core::mem::size_of::<T>()
611                    &&& final(self).cursor.vaddr == old(self).cursor.vaddr + core::mem::size_of::<T>()
612                },
613                Err(_) => {
614                    *old(self) == *final(self)
615                },
616            }
617    )]
618    pub fn write_once<T: PodOnce>(&mut self, new_val: &T) -> Result<()> {
619        if self.avail() < core::mem::size_of::<T>() {
620            return Err(Error::InvalidArgs);
621        }
622        let cursor = self.cursor.cast::<T>();
623        assert!(cursor.is_aligned());
624
625        // NOTE: vostd has `const { assert!(pod_once_impls::is_non_tearing::<T>()) };` here, but
626        // verus doesn't yet support const block expressions. The non-tearing guarantee for our
627        // `PodOnce` impls is restricted to types of size 1/2/4/8 by convention.
628
629        // SAFETY: We have checked that the number of bytes available is at least the size of `T`
630        // and that the cursor is properly aligned with respect to the type `T`. All other safety
631        // requirements are the same as for `Self::write`.
632
633        let len = core::mem::size_of::<T>();
634        let tracked mut mem_dst = match owner.mem_view.tracked_take() {
635            VmIoMemView::WriteView(mv) => mv,
636            _ => { proof_from_false() },
637        };
638        let ghost mem_dst_pre = mem_dst;
639
640        proof {
641            assert forall|i: usize|
642                #![trigger mem_dst.addr_transl(i)]
643                self.cursor.vaddr <= i < self.cursor.vaddr + core::mem::size_of::<T>() implies {
644                mem_dst.addr_transl(i) is Some
645            } by {}
646        }
647        #[allow(unused_unsafe)]
648        unsafe { self.cursor.write_volatile::<T>(Tracked(&mut mem_dst), *new_val) };
649
650        self.cursor = self.cursor.wrapping_add(len);
651
652        proof {
653            owner.mem_view = Some(VmIoMemView::WriteView(mem_dst));
654
655            assert forall|va| owner.range.start <= va < owner.range.end implies mem_dst.addr_transl(
656                va,
657            ) is Some by {}
658
659            owner.advance(len);
660        }
661
662        Ok(())
663    }
664}
665
666impl<Fallibility> Clone for VmReader<'_, Fallibility> {
667    /// [`Clone`] can be implemented for [`VmReader`]
668    /// because it either points to untyped memory or represents immutable references.
669    ///
670    /// Note that we cannot implement [`Clone`] for [`VmWriter`]
671    /// because it can represent mutable references, which must remain exclusive.
672    fn clone(&self) -> Self {
673        Self { ghost_id: self.ghost_id, cursor: self.cursor, end: self.end, phantom: PhantomData }
674    }
675}
676
677#[verus_verify]
678impl<'a> VmReader<'a, Infallible> {
679    /// Constructs a [`VmReader`] from a pointer and a length, which represents
680    /// a memory range in kernel space.
681    ///
682    /// # Verified Properties
683    /// ## Preconditions
684    /// - The memory region represented by `ptr` and `len` must be valid for reads of `len` bytes
685    ///   during the entire lifetime `a`. This means that the underlying pages must remain alive,
686    ///   and the kernel must access the memory region using only the APIs provided in this module.
687    /// - The range `ptr.vaddr..ptr.vaddr + len` must represent a kernel space memory range.
688    /// ## Postconditions
689    /// - An infallible [`VmReader`] will be created with the range `ptr.vaddr..ptr.vaddr + len`.
690    /// - The created [`VmReader`] will have a unique identifier `id`, and its cursor will be
691    ///   initialized to `ptr`.
692    /// - The created [`VmReader`] will be associated with a [`VmIoOwner`] that has the same `id`,
693    ///   the same memory range, and is marked as kernel space and infallible.
694    /// ## Safety
695    ///
696    /// `ptr` must be [valid] for reads of `len` bytes during the entire lifetime `a`.
697    ///
698    /// [valid]: crate::mm::io#safety
699    #[verus_spec(r =>
700        with
701            Ghost(id): Ghost<nat>,
702            -> owner: Tracked<VmIoOwner>,
703        ensures
704            r.inv_wf(),
705            owner@.id == id,
706            owner@.is_kernel,
707            r.cursor == ptr,
708            r.end == ptr.wrapping_add_spec(len),
709            r.cursor.range@ == ptr.range@,
710            r.end.range@ == ptr.range@,
711            ptr.inv() && ptr.range@.start == ptr.vaddr
712                && len == ptr.range@.end - ptr.range@.start
713                && (len == 0 || KERNEL_BASE_VADDR <= ptr.vaddr)
714                && (len == 0 || ptr.vaddr + len <= KERNEL_END_VADDR) ==> {
715                &&& r.inv()
716                &&& owner@.inv()
717                &&& r.wf(owner@)
718                &&& owner@.read_view_initialized()
719            },
720    )]
721    pub unsafe fn from_kernel_space(ptr: VirtPtr, len: usize) -> Self {
722        let ghost range: Range<usize> = ptr.vaddr..(ptr.vaddr + len) as usize;
723        let tracked mv = axiom_kernel_mem_view(range);
724        let tracked owner = VmIoOwner {
725            id,
726            range,
727            is_fallible: false,
728            is_kernel: true,
729            mem_view: Some(VmIoMemView::ReadView(mv)),
730        };
731
732        proof_with!(|= Tracked(owner));
733        Self { ghost_id: Ghost(id), cursor: ptr, end: ptr.wrapping_add(len), phantom: PhantomData }
734    }
735
736    /// Converts an infallible reader into a fallible one.
737    pub fn to_fallible(self) -> (r: VmReader<'a, Fallible>)
738        ensures
739            r.remain_spec() == self.remain_spec(),
740            r.cursor == self.cursor,
741            r.end == self.end,
742            r.ghost_id == self.ghost_id,
743    {
744        VmReader {
745            ghost_id: self.ghost_id,
746            cursor: self.cursor,
747            end: self.end,
748            phantom: PhantomData,
749        }
750    }
751
752    /// Reads data from `self` and writes it into the provided `writer`.
753    ///
754    /// This function acts as the source side of a transfer. It copies data from
755    /// the current instance (`self`) into the destination `writer`, up to the limit
756    /// of available data in `self` or available space in `writer` (whichever is smaller).
757    ///
758    /// # Logic
759    ///
760    /// 1. Calculates the copy length: `min(self.remaining_data, writer.available_space)`.
761    /// 2. Copies bytes from `self`'s internal buffer to `writer`'s buffer.
762    /// 3. Advances the cursors of both `self` and `writer`.
763    ///
764    /// # Arguments
765    ///
766    /// * `writer` - The destination `VmWriter` where the data will be copied to.
767    ///
768    /// # Returns
769    ///
770    /// The number of bytes actually transferred.
771    ///
772    /// # Verified Properties
773    /// ## Preconditions
774    /// - The reader, writer, and both associated owners must satisfy their invariants.
775    /// - The owners must match the given reader and writer.
776    /// - The writer owner must carry a write memory view.
777    /// - The source and destination ranges must not overlap.
778    /// - The reader owner must provide initialized readable memory for the readable range.
779    /// ## Postconditions
780    /// - The reader, writer, and both owners still satisfy their invariants.
781    /// - The owners still match the updated reader and writer.
782    /// - The returned byte count equals the minimum of readable bytes and writable bytes.
783    /// - Both cursors advance by exactly the returned byte count.
784    /// - `consumed_w` is the just-written portion of the writer's owner, covering
785    ///   `[old(owner_w).range@.start, old(owner_w).range@.start + r)`.
786    #[verus_spec(r =>
787        with
788            Tracked(owner_r): Tracked<&mut VmIoOwner>,
789            Tracked(owner_w): Tracked<&mut VmIoOwner>,
790                -> consumed_w: Tracked<VmIoOwner>,
791        requires
792            old(self).inv(),
793            old(writer).inv(),
794            old(self).wf(*old(owner_r)),
795            old(writer).wf(*old(owner_w)),
796            old(owner_w).has_write_view(),
797            old(owner_r).read_view_initialized(),
798        ensures
799            final(self).inv(),
800            final(writer).inv(),
801            final(self).wf(*final(owner_r)),
802            final(writer).wf(*final(owner_w)),
803            r == vstd::math::min(old(self).remain_spec() as int, old(writer).avail_spec() as int),
804            final(self).remain_spec() == old(self).remain_spec() - r as usize,
805            final(self).cursor.vaddr == old(self).cursor.vaddr + r as usize,
806            final(writer).avail_spec() == old(writer).avail_spec() - r as usize,
807            final(writer).cursor.vaddr == old(writer).cursor.vaddr + r as usize,
808            consumed_w@.inv(),
809            consumed_w@.range.start == old(owner_w).range.start,
810            consumed_w@.range.end == old(owner_w).range.start + r as usize,
811            consumed_w@.has_write_view(),
812    )]
813    pub fn read(&mut self, writer: &mut VmWriter<'_, Infallible>) -> usize {
814        let copy_len = self.remain().min(writer.avail());
815        proof_decl! {
816            let tracked mut consumed_w_owner_inner: VmIoOwner;
817        }
818        if copy_len == 0 {
819            proof {
820                consumed_w_owner_inner = owner_w.split(0);
821            }
822            proof_with!(|= Tracked(consumed_w_owner_inner));
823            0
824        } else {
825            let tracked mv_r = match owner_r.mem_view.tracked_take() {
826                VmIoMemView::ReadView(mv) => mv,
827                _ => { proof_from_false() },
828            };
829            let tracked mut mv_w = match owner_w.mem_view.tracked_take() {
830                VmIoMemView::WriteView(mv) => mv,
831                _ => { proof_from_false() },
832            };
833            let ghost mv_w_pre = mv_w;
834
835            proof {
836                assert forall|i: usize|
837                    #![trigger mv_r.addr_transl(i)]
838                    self.cursor.vaddr <= i < self.cursor.vaddr + copy_len implies {
839                    &&& mv_r.addr_transl(i) is Some
840                    &&& mv_r.memory.contains_key(mv_r.addr_transl(i).unwrap().0)
841                    &&& mv_r.memory[mv_r.addr_transl(i).unwrap().0].contents[mv_r.addr_transl(
842                        i,
843                    ).unwrap().1 as int] is Init
844                } by {}
845            }
846            // SAFETY: The source and destination are subsets of memory ranges specified by the
847            // reader and writer, so they are valid for reading and writing.
848            unsafe {
849                #[verus_spec(with Tracked(&mv_r), Tracked(&mut mv_w))]
850                memcpy(writer.cursor, self.cursor, copy_len)
851            };
852
853            self.cursor = self.cursor.wrapping_add(copy_len);
854            writer.cursor = writer.cursor.wrapping_add(copy_len);
855
856            proof {
857                owner_w.mem_view = Some(VmIoMemView::WriteView(mv_w));
858                owner_r.mem_view = Some(VmIoMemView::ReadView(mv_r));
859
860                assert forall|va|
861                    owner_w.range.start <= va < owner_w.range.end implies mv_w.addr_transl(
862                    va,
863                ) is Some by {
864                    assert(mv_w.addr_transl(va) == mv_w_pre.addr_transl(va));
865                }
866
867                consumed_w_owner_inner = owner_w.split(copy_len);
868                owner_r.advance(copy_len);
869            }
870            proof_with!(|= Tracked(consumed_w_owner_inner));
871            copy_len
872        }
873    }
874
875    /// Reads a value of `Pod` type.
876    ///
877    /// If the length of the `Pod` type exceeds `self.remain()`,
878    /// this method will return `Err`.
879    ///
880    /// # Verified Properties
881    /// ## Preconditions
882    /// - The reader and its owner must satisfy their invariants.
883    /// - The owner must match this reader and carry an initialized read memory view.
884    /// - The caller supplies a tracked writer owner whose front `size_of::<T>()` bytes
885    ///   will become the owner of the returned value. The borrowed `writer_owner` shrinks
886    ///   to cover the remaining range.
887    /// ## Postconditions
888    /// - The reader and its owner still satisfy their invariants.
889    /// - On success, the cursor advances by `size_of::<T>()` and the returned `val_owner`
890    ///   owns the bytes backing `val`.
891    /// - On error, the reader state is unchanged.
892    #[verus_spec(r =>
893        with
894            Tracked(owner): Tracked<&mut VmIoOwner>,
895        requires
896            old(self).inv(),
897            old(self).wf(*old(owner)),
898            old(owner).read_view_initialized(),
899        ensures
900            final(self).inv(),
901            final(owner).inv(),
902            final(self).wf(*final(owner)),
903            match r {
904                Ok(_) => {
905                    &&& final(self).remain_spec() == old(self).remain_spec() - core::mem::size_of::<T>()
906                    &&& final(self).cursor.vaddr == old(self).cursor.vaddr + core::mem::size_of::<T>()
907                },
908                Err(_) => {
909                    *old(self) == *final(self)
910                },
911            }
912    )]
913    pub fn read_val<T: Pod>(&mut self) -> Result<T> {
914        let len = core::mem::size_of::<T>();
915        if self.remain() < len {
916            Err(Error::InvalidArgs)
917        } else {
918            let mut val = T::new_uninit();
919            proof_decl! {
920                let tracked mut writer_owner_inner: VmIoOwner;
921            }
922            #[verus_spec(with => Tracked(writer_owner_inner))]
923            let mut writer = VmWriter::from(val.as_bytes_mut());
924            #[verus_spec(with Tracked(owner), Tracked(&mut writer_owner_inner))]
925            let _ = self.read(&mut writer);
926            Ok(val)
927        }
928    }
929
930    /// Reads a value of the `PodOnce` type using one non-tearing memory load.
931    ///
932    /// If the length of the `PodOnce` type exceeds `self.remain()`, this method will return `Err`.
933    ///
934    /// This method will not compile if the `Pod` type is too large for the current architecture
935    /// and the operation must be tear into multiple memory loads.
936    ///
937    /// # Panics
938    ///
939    /// This method will panic if the current position of the reader does not meet the alignment
940    /// requirements of type `T`.
941    ///
942    /// # Verified Properties
943    /// ## Preconditions
944    /// - The reader and its owner must satisfy their invariants.
945    /// - The owner must match this reader and carry a read memory view.
946    /// - The readable range must translate to initialized bytes in the read view.
947    /// ## Postconditions
948    /// - The reader and owner still satisfy their invariants.
949    /// - On success, the cursor advances by `size_of::<T>()` and the cursor was
950    ///   aligned to `align_of::<T>()` (the runtime `assert!` would otherwise diverge).
951    /// - On error, the reader state is unchanged.
952    #[verus_spec(r =>
953        with
954            Tracked(owner): Tracked<&mut VmIoOwner>,
955        requires
956            old(self).inv(),
957            old(self).wf(*old(owner)),
958            old(owner).read_view_initialized(),
959            old(self).cursor.vaddr % core::mem::align_of::<T>() != 0 ==> may_panic(),
960        ensures
961            final(self).inv(),
962            final(owner).inv(),
963            final(self).wf(*final(owner)),
964            final(owner).read_view_initialized(),
965            old(self).remain_spec() >= core::mem::size_of::<T>() ==> r is Ok,
966            final(self).end == old(self).end,
967            final(self).ghost_id == old(self).ghost_id,
968            match r {
969                Ok(v) => {
970                    &&& old(self).cursor.vaddr % core::mem::align_of::<T>() == 0
971                    &&& final(self).remain_spec() == old(self).remain_spec() - core::mem::size_of::<T>()
972                    &&& final(self).cursor.vaddr == old(self).cursor.vaddr + core::mem::size_of::<T>()
973                    &&& ostd_pod::pod_bytes::<T>(v)
974                        == crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner))
975                            .read_bytes(old(self).cursor.vaddr, core::mem::size_of::<T>())
976                    &&& forall|va: usize|
977                        #![trigger crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).read(va)]
978                        final(self).cursor.vaddr <= va < old(self).end.vaddr
979                        && crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va) is Some
980                        && crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).memory.contains_key(
981                            (crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va)->0).0
982                        ) ==> {
983                            &&& crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va)
984                                == crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).addr_transl(va)
985                            &&& crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).read(va)
986                                == crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).read(va)
987                        }
988                },
989                Err(_) => {
990                    *old(self) == *final(self)
991                },
992            }
993    )]
994    pub fn read_once<T: PodOnce>(&mut self) -> Result<T> {
995        if self.remain() < core::mem::size_of::<T>() {
996            return Err(Error::InvalidArgs);
997        }
998        let cursor = self.cursor.cast::<T>();
999        assert!(cursor.is_aligned());
1000
1001        // NOTE: vostd has `const { assert!(pod_once_impls::is_non_tearing::<T>()) };` here, but
1002        // verus doesn't yet support const block expressions. The non-tearing guarantee for our
1003        // `PodOnce` impls is restricted to types of size 1/2/4/8 by convention.
1004
1005        // SAFETY: We have checked that the number of bytes remaining is at least the size of `T`
1006        // and that the cursor is properly aligned with respect to the type `T`. All other safety
1007        // requirements are the same as for `Self::read`.
1008
1009        let tracked mem_src = owner.tracked_read_view_unwrap();
1010        proof {
1011            assert forall|i: usize|
1012                #![trigger mem_src.addr_transl(i)]
1013                self.cursor.vaddr <= i < self.cursor.vaddr + core::mem::size_of::<T>() implies {
1014                &&& mem_src.addr_transl(i) is Some
1015                &&& mem_src.memory.contains_key(mem_src.addr_transl(i).unwrap().0)
1016                &&& mem_src.memory[mem_src.addr_transl(i).unwrap().0].contents[mem_src.addr_transl(
1017                    i,
1018                ).unwrap().1 as int] is Init
1019            } by {}
1020        }
1021        #[allow(unused_unsafe)]
1022        let val = unsafe { self.cursor.read_volatile::<T>(Tracked(mem_src)) };
1023        self.cursor = self.cursor.wrapping_add(core::mem::size_of::<T>());
1024
1025        proof {
1026            owner.advance(core::mem::size_of::<T>());
1027        }
1028
1029        Ok(val)
1030    }
1031}
1032
1033#[verus_verify]
1034impl<'a> VmReader<'a, Fallible> {
1035    /// Constructs a [`VmReader`] from a pointer and a length, which represents
1036    /// a memory range in USER space.
1037    ///
1038    /// # Verified Properties
1039    /// ## Preconditions
1040    /// - `ptr` must satisfy [`VirtPtr::inv`].
1041    /// ## Postconditions
1042    /// - The returned [`VmReader`] satisfies its invariant.
1043    /// - The returned reader is associated with a [`VmIoOwner`] that satisfies both [`VmIoOwner::inv`]
1044    ///   and [`VmReader::wf`].
1045    /// - The owner has the same range as `ptr`, has no memory view yet, and is marked as user-space.
1046    #[verus_spec(r =>
1047        with
1048            Ghost(id): Ghost<nat>,
1049            -> owner: Tracked<VmIoOwner>,
1050        ensures
1051            r.inv_wf(),
1052            owner@.id == id,
1053            owner@.range == ptr.range@,
1054            owner@.mem_view is None,
1055            !owner@.is_kernel,
1056            r.cursor == ptr,
1057            r.end == ptr.wrapping_add_spec(len),
1058            r.end.range@ == ptr.range@,
1059            ptr.inv() && ptr.range@.start == ptr.vaddr
1060                && len == ptr.range@.end - ptr.range@.start ==> {
1061                &&& r.inv()
1062                &&& owner@.inv()
1063                &&& r.wf(owner@)
1064            },
1065    )]
1066    pub unsafe fn from_user_space(ptr: VirtPtr, len: usize) -> Self {
1067        let tracked owner = VmIoOwner {
1068            id,
1069            range: ptr.range@,
1070            is_fallible: true,
1071            is_kernel: false,
1072            mem_view: None,
1073        };
1074        proof_with!(|= Tracked(owner));
1075        Self { ghost_id: Ghost(id), cursor: ptr, end: ptr.wrapping_add(len), phantom: PhantomData }
1076    }
1077
1078    /// Reads a value of `Pod` type from a (potentially) user-space buffer.
1079    ///
1080    /// If the length of the `Pod` type exceeds `self.remain()`, or the value
1081    /// can not be read completely (e.g. due to a page fault), this method
1082    /// returns `Err` and the reader's cursor is rolled back to its original
1083    /// position.
1084    #[verus_spec(r =>
1085        requires
1086            old(self).inv(),
1087        ensures
1088            final(self).inv(),
1089            final(self).end == old(self).end,
1090            final(self).ghost_id == old(self).ghost_id,
1091            final(self).cursor.range == old(self).cursor.range,
1092            r is Err ==> *final(self) == *old(self),
1093    )]
1094    pub fn read_val<T: Pod>(&mut self) -> Result<T> {
1095        let len = core::mem::size_of::<T>();
1096        if self.remain() < len {
1097            Err(Error::InvalidArgs)
1098        } else {
1099            let mut val = T::new_uninit();
1100            proof_decl! {
1101                let tracked mut writer_owner_inner: VmIoOwner;
1102            }
1103            #[verus_spec(with => Tracked(writer_owner_inner))]
1104            let mut writer = VmWriter::from(val.as_bytes_mut());
1105
1106            match self.read_fallible(&mut writer) {
1107                Ok(_) => Ok(val),
1108                Err((err, copied_len)) => {
1109                    self.cursor = self.cursor.sub(copied_len);
1110                    Err(err)
1111                },
1112            }
1113        }
1114    }
1115
1116    /// Collects all the remaining bytes into a `Vec<u8>`.
1117    ///
1118    /// If the memory read failed, this method will return `Err`
1119    /// and the current reader's cursor remains pointing to
1120    /// the original starting position.
1121    ///
1122    /// The destination buffer is allocated fresh inside this function. The
1123    /// kernel-space precondition for the resulting `VmWriter` is discharged
1124    /// via [`axiom_slice_in_kernel`] — the natural trust boundary where a
1125    /// native Rust slice meets the tracked-memory model.
1126    #[verus_spec(r =>
1127        requires
1128            old(self).inv(),
1129        ensures
1130            final(self).inv(),
1131            final(self).end == old(self).end,
1132            final(self).ghost_id == old(self).ghost_id,
1133            final(self).cursor.range == old(self).cursor.range,
1134            r is Err ==> *final(self) == *old(self),
1135    )]
1136    pub fn collect(&mut self) -> Result<alloc::vec::Vec<u8>> {
1137        let len = self.remain();
1138        let mut buf = alloc::vec![0u8; len];
1139
1140        let ptr = {
1141            let slice: &[u8] = buf.as_slice();
1142            let ptr = slice.as_virt_ptr();
1143            proof {
1144                axiom_slice_in_kernel(slice);
1145            }
1146            ptr
1147        };
1148        proof_decl! {
1149            let tracked mut owner: VmIoOwner;
1150        }
1151        let mut writer = unsafe {
1152            #[verus_spec(with Ghost(0nat), Tracked(false) => Tracked(owner))]
1153            VmWriter::from_kernel_space(ptr, len)
1154        };
1155        match self.read_fallible(&mut writer) {
1156            Ok(_) => Ok(buf),
1157            Err((err, copied_len)) => {
1158                self.cursor = self.cursor.sub(copied_len);
1159                Err(err)
1160            },
1161        }
1162    }
1163}
1164
1165type Result<T> = core::result::Result<T, Error>;
1166
1167/// A trait that enables reading/writing data from/to a VM object,
1168/// e.g., [`USegment`], [`Vec<UFrame>`] and [`UFrame`].
1169///
1170/// # Concurrency
1171///
1172/// The methods may be executed by multiple concurrent reader and writer
1173/// threads. In this case, if the results of concurrent reads or writes
1174/// desire predictability or atomicity, the users should add extra mechanism
1175/// for such properties.
1176///
1177/// [`USegment`]: crate::mm::USegment
1178/// [`UFrame`]: crate::mm::UFrame
1179///
1180/// Note: In this trait we follow the standard of `vstd` trait that allows precondition and
1181/// postcondition overriding by introducing `obeys_`, `_requires`, and `_ensures` spec functions.
1182///
1183/// `P` is the type of the permission/ownership token used to track the state of the VM object.
1184pub trait VmIo<P: Sized>: Send + Sync + Sized {
1185    spec fn obeys_vmio_spec() -> bool;
1186
1187    open spec fn obeys_vmio_read_requires() -> bool {
1188        false
1189    }
1190
1191    open spec fn obeys_vmio_write_requires() -> bool {
1192        false
1193    }
1194
1195    spec fn obeys_vmio_read_spec() -> bool;
1196
1197    spec fn obeys_vmio_write_spec() -> bool;
1198
1199    open spec fn read_requires(
1200        self,
1201        offset: usize,
1202        writer: VmWriter<'_>,
1203        writer_own: VmIoOwner,
1204        owner: P,
1205    ) -> bool {
1206        true
1207    }
1208
1209    open spec fn write_requires(
1210        self,
1211        offset: usize,
1212        reader: VmReader<'_>,
1213        reader_own: VmIoOwner,
1214        owner: P,
1215    ) -> bool {
1216        true
1217    }
1218
1219    spec fn read_spec(
1220        self,
1221        offset: usize,
1222        old_writer: VmWriter<'_>,
1223        new_writer: VmWriter<'_>,
1224        old_writer_own: VmIoOwner,
1225        new_writer_own: VmIoOwner,
1226        old_owner: P,
1227        new_owner: P,
1228        r: Result<()>,
1229    ) -> bool;
1230
1231    spec fn write_spec(
1232        self,
1233        offset: usize,
1234        old_reader: VmReader<'_>,
1235        new_reader: VmReader<'_>,
1236        old_writer_own: VmIoOwner,
1237        new_writer_own: VmIoOwner,
1238        old_owner: P,
1239        new_owner: P,
1240        r: Result<()>,
1241    ) -> bool;
1242
1243    /// Reads requested data at a specified offset into a given [`VmWriter`].
1244    ///
1245    /// # No short reads
1246    ///
1247    /// On success, the `writer` must be written with the requested data
1248    /// completely. If, for any reason, the requested data is only partially
1249    /// available, then the method shall return an error.
1250    fn read(
1251        &self,
1252        offset: usize,
1253        writer: &mut VmWriter<'_>,
1254        Tracked(writer_own): Tracked<&mut VmIoOwner>,
1255        Tracked(owner): Tracked<&mut P>,
1256    ) -> (r: Result<()>)
1257        requires
1258            Self::obeys_vmio_read_requires() ==> Self::read_requires(
1259                *self,
1260                offset,
1261                *old(writer),
1262                *old(writer_own),
1263                *old(owner),
1264            ),
1265        ensures
1266            Self::obeys_vmio_read_spec() ==> Self::read_spec(
1267                *self,
1268                offset,
1269                *old(writer),
1270                *final(writer),
1271                *old(writer_own),
1272                *final(writer_own),
1273                *old(owner),
1274                *final(owner),
1275                r,
1276            ),
1277    ;
1278
1279    /// Writes all data from a given `VmReader` at a specified offset.
1280    ///
1281    /// # No short writes
1282    ///
1283    /// On success, the data from the `reader` must be read to the VM object entirely.
1284    /// If, for any reason, the input data can only be written partially,
1285    /// then the method shall return an error.
1286    fn write(
1287        &self,
1288        offset: usize,
1289        reader: &mut VmReader,
1290        Tracked(writer_own): Tracked<&mut VmIoOwner>,
1291        Tracked(owner): Tracked<&mut P>,
1292    ) -> (r: Result<()>)
1293        requires
1294            Self::obeys_vmio_write_requires() ==> Self::write_requires(
1295                *self,
1296                offset,
1297                *old(reader),
1298                *old(writer_own),
1299                *old(owner),
1300            ),
1301        ensures
1302            Self::obeys_vmio_write_spec() ==> Self::write_spec(
1303                *self,
1304                offset,
1305                *old(reader),
1306                *final(reader),
1307                *old(writer_own),
1308                *final(writer_own),
1309                *old(owner),
1310                *final(owner),
1311                r,
1312            ),
1313    ;
1314
1315    /// Reads a specified number of bytes at a specified offset into a given buffer.
1316    ///
1317    /// Wraps `buf` in a [`VmWriter`] (whose tracked owner is minted internally
1318    /// from the slice via [`VmWriter::from`]) and delegates to [`Self::read`].
1319    /// The shallow contract here only forwards the result; impls with non-trivial
1320    /// `read_requires` must override.
1321    fn read_bytes(&self, offset: usize, buf: &mut [u8], Tracked(owner): Tracked<&mut P>) -> (r:
1322        Result<()>)
1323        requires
1324            !Self::obeys_vmio_read_requires(),
1325    {
1326        proof_decl! {
1327            let tracked mut writer_own_inner: VmIoOwner;
1328        }
1329        #[verus_spec(with => Tracked(writer_own_inner))]
1330        let infallible_writer = VmWriter::from(buf);
1331        let mut writer = infallible_writer.to_fallible();
1332        self.read(offset, &mut writer, Tracked(&mut writer_own_inner), Tracked(owner))
1333    }
1334
1335    /// Reads a value of a specified type at a specified offset.
1336    fn read_val<T: Pod>(&self, offset: usize, Tracked(owner): Tracked<&mut P>) -> (r: Result<T>)
1337        requires
1338            !Self::obeys_vmio_read_requires(),
1339    {
1340        let mut val = T::new_uninit();
1341        match self.read_bytes(offset, val.as_bytes_mut(), Tracked(owner)) {
1342            Ok(_) => Ok(val),
1343            Err(e) => Err(e),
1344        }
1345    }
1346
1347    /// Reads a slice of a specified type at a specified offset.
1348    fn read_slice<T: Pod>(
1349        &self,
1350        offset: usize,
1351        slice: &mut [T],
1352        Tracked(owner): Tracked<&mut P>,
1353    ) -> (r: Result<()>)
1354        requires
1355            !Self::obeys_vmio_read_requires(),
1356    {
1357        let len_in_bytes = core::mem::size_of_val(slice);
1358        let ptr = slice.as_mut_ptr() as *mut u8;
1359        // SAFETY: the slice can be transmuted to a writable byte slice since
1360        // the elements are all Plain-Old-Data (Pod) types.
1361        let buf = unsafe { core::slice::from_raw_parts_mut(ptr, len_in_bytes) };
1362        self.read_bytes(offset, buf, Tracked(owner))
1363    }
1364
1365    /// Writes a specified number of bytes from a given buffer at a specified offset.
1366    ///
1367    /// Wraps `buf` in a [`VmReader`] (whose tracked owner is minted internally
1368    /// from the slice via [`VmReader::from`]) and delegates to [`Self::write`].
1369    /// The shallow contract here only forwards the result; impls with non-trivial
1370    /// `write_requires` must override.
1371    fn write_bytes(&self, offset: usize, buf: &[u8], Tracked(owner): Tracked<&mut P>) -> (r: Result<
1372        (),
1373    >)
1374        requires
1375            !Self::obeys_vmio_write_requires(),
1376    {
1377        proof_decl! {
1378            let tracked mut reader_own_inner: VmIoOwner;
1379        }
1380        #[verus_spec(with => Tracked(reader_own_inner))]
1381        let infallible_reader = VmReader::from(buf);
1382        let mut reader = infallible_reader.to_fallible();
1383        self.write(offset, &mut reader, Tracked(&mut reader_own_inner), Tracked(owner))
1384    }
1385
1386    /// Writes a value of a specified type at a specified offset.
1387    fn write_val<T: Pod>(&self, offset: usize, new_val: &T, Tracked(owner): Tracked<&mut P>) -> (r:
1388        Result<()>)
1389        requires
1390            !Self::obeys_vmio_write_requires(),
1391    {
1392        self.write_bytes(offset, new_val.as_bytes(), Tracked(owner))
1393    }
1394
1395    /// Writes a slice of a specified type at a specified offset.
1396    fn write_slice<T: Pod>(
1397        &self,
1398        offset: usize,
1399        slice: &[T],
1400        Tracked(owner): Tracked<&mut P>,
1401    ) -> (r: Result<()>)
1402        requires
1403            !Self::obeys_vmio_write_requires(),
1404    {
1405        let len_in_bytes = core::mem::size_of_val(slice);
1406        let ptr = slice.as_ptr() as *const u8;
1407        // SAFETY: the slice can be transmuted to a readable byte slice since
1408        // the elements are all Plain-Old-Data (Pod) types.
1409        let buf = unsafe { core::slice::from_raw_parts(ptr, len_in_bytes) };
1410        self.write_bytes(offset, buf, Tracked(owner))
1411    }
1412
1413    /// Writes a sequence of values given by an iterator (`iter`) from the
1414    /// specified offset (`offset`).
1415    ///
1416    /// Stops on iterator exhaustion or write error. Returns `Ok(nr_written)`
1417    /// if at least one value was written; only the first-call error path
1418    /// surfaces as `Err`.
1419    ///
1420    /// `align` rounds the offset and item size up: `0`/`1` means no padding,
1421    /// otherwise must be a power of two. Bad `align` panics at runtime — this
1422    /// is captured as a *post-condition*, not a pre-condition, since the panic
1423    /// is what enforces it.
1424    ///
1425    /// Preconditions left for the caller:
1426    /// - `offset + (align - 1)` and `size_of::<T>() + (align - 1)` don't overflow
1427    ///   (so the post-panic call to `align_up` is safe).
1428    /// - The supplied iterator obeys Verus' prophetic iterator laws and provides
1429    ///   a `decrease` measure (true for slice iterators, `repeat_n`, and the
1430    ///   stdlib iterator combinators ostd uses).
1431    /// - `self`'s impl has no custom `write_requires` (use the override route
1432    ///   for impls that do).
1433    fn write_vals<
1434        'a,
1435        T: Pod + 'a,
1436        I: ::vstd::std_specs::iter::IteratorSpec<Item = &'a T> + Iterator<Item = &'a T>,
1437    >(&self, offset: usize, iter: I, align: usize, Tracked(owner): Tracked<&mut P>) -> (r: Result<
1438        usize,
1439    >)
1440        requires
1441            !Self::obeys_vmio_write_requires(),
1442            offset + align <= usize::MAX,
1443            core::mem::size_of::<T>() + align <= usize::MAX,
1444            iter.obeys_prophetic_iter_laws(),
1445            iter.decrease() is Some,
1446            // `align_up` (called for `align > 1`) diverges unless `align`
1447            // is a power of two.
1448            !(align <= 1 || is_pow2(align as int)) ==> may_panic(),
1449        ensures
1450            align <= 1 || is_pow2(align as int),
1451    {
1452        use ::align_ext::AlignExt;
1453        let mut nr_written: usize = 0;
1454        // `align_up` itself panics on invalid `align`, so reaching the post-`else`
1455        // statements gives us the post-condition for free.
1456        let (mut offset, item_size) = if align <= 1 {
1457            (offset, core::mem::size_of::<T>())
1458        } else {
1459            (offset.align_up(align), core::mem::size_of::<T>().align_up(align))
1460        };
1461        let mut iter = iter;
1462        loop
1463            invariant
1464                !Self::obeys_vmio_write_requires(),
1465                iter.obeys_prophetic_iter_laws(),
1466                iter.decrease() is Some,
1467                align == 0 || align == 1 || is_pow2(align as int),
1468            decreases iter.decrease().unwrap(),
1469        {
1470            match iter.next() {
1471                Some(item) => {
1472                    // Stop *before* writing if we couldn't safely advance afterwards.
1473                    if nr_written == usize::MAX || (item_size > 0 && offset > usize::MAX
1474                        - item_size) {
1475                        return Ok(nr_written);
1476                    }
1477                    match self.write_val(offset, item, Tracked(owner)) {
1478                        Ok(_) => {
1479                            offset = offset + item_size;
1480                            nr_written = nr_written + 1;
1481                        },
1482                        Err(e) => {
1483                            if nr_written > 0 {
1484                                return Ok(nr_written);
1485                            }
1486                            return Err(e);
1487                        },
1488                    }
1489                },
1490                None => return Ok(nr_written),
1491            }
1492        }
1493    }
1494}
1495
1496/// A trait that enables reading/writing data from/to a VM object using one non-tearing memory
1497/// load/store.
1498///
1499/// See also [`VmIo`], which enables reading/writing data from/to a VM object without the guarantee
1500/// of using one non-tearing memory load/store.
1501pub trait VmIoOnce: Sized {
1502    spec fn obeys_vmio_once_read_requires() -> bool;
1503
1504    spec fn obeys_vmio_once_write_requires() -> bool;
1505
1506    spec fn obeys_vmio_once_read_ensures() -> bool;
1507
1508    spec fn obeys_vmio_once_write_ensures() -> bool;
1509
1510    /// Reads a value of the `PodOnce` type at the specified offset using one non-tearing memory
1511    /// load.
1512    ///
1513    /// Except that the offset is specified explicitly, the semantics of this method is the same as
1514    /// [`VmReader::read_once`].
1515    fn read_once<T: PodOnce>(&self, offset: usize) -> Result<T>;
1516
1517    /// Writes a value of the `PodOnce` type at the specified offset using one non-tearing memory
1518    /// store.
1519    ///
1520    /// Except that the offset is specified explicitly, the semantics of this method is the same as
1521    /// [`VmWriter::write_once`].
1522    fn write_once<T: PodOnce>(&self, offset: usize, new_val: &T) -> Result<()>;
1523}
1524
1525/*
1526// Original impl_vm_io_pointer macro and invocations (removed during Verus migration):
1527macro_rules! impl_vm_io_pointer {
1528    ($typ:ty,$from:tt) => {
1529        #[inherit_methods(from = $from)]
1530        impl<T: VmIo> VmIo for $typ {
1531            fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>;
1532            fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>;
1533            fn read_val<F: Pod>(&self, offset: usize) -> Result<F>;
1534            fn read_slice<F: Pod>(&self, offset: usize, slice: &mut [F]) -> Result<()>;
1535            fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>;
1536            fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>;
1537            fn write_val<F: Pod>(&self, offset: usize, new_val: &F) -> Result<()>;
1538            fn write_slice<F: Pod>(&self, offset: usize, slice: &[F]) -> Result<()>;
1539        }
1540    };
1541}
1542
1543impl_vm_io_pointer!(&T, "(**self)");
1544impl_vm_io_pointer!(&mut T, "(**self)");
1545impl_vm_io_pointer!(Box<T>, "(**self)");
1546impl_vm_io_pointer!(Arc<T>, "(**self)");
1547*/
1548
1549/*
1550// Original impl_vm_io_once_pointer macro and invocations (removed during Verus migration):
1551macro_rules! impl_vm_io_once_pointer {
1552    ($typ:ty,$from:tt) => {
1553        #[inherit_methods(from = $from)]
1554        impl<T: VmIoOnce> VmIoOnce for $typ {
1555            fn read_once<F: PodOnce>(&self, offset: usize) -> Result<F>;
1556            fn write_once<F: PodOnce>(&self, offset: usize, new_val: &F) -> Result<()>;
1557        }
1558    };
1559}
1560
1561impl_vm_io_once_pointer!(&T, "(**self)");
1562impl_vm_io_once_pointer!(&mut T, "(**self)");
1563impl_vm_io_once_pointer!(Box<T>, "(**self)");
1564impl_vm_io_once_pointer!(Arc<T>, "(**self)");
1565*/
1566
1567#[verus_verify]
1568impl<Fallibility> VmReader<'_, Fallibility> {
1569    pub open spec fn remain_spec(&self) -> usize {
1570        (self.end.vaddr - self.cursor.vaddr) as usize
1571    }
1572
1573    /// Returns the number of remaining bytes that can be read.
1574    ///
1575    /// # Verified Properties
1576    /// ## Preconditions
1577    /// - `self` must satisfy its invariant.
1578    /// ## Postconditions
1579    /// - The returned value equals [`Self::remain_spec`].
1580    #[verus_spec(r =>
1581        requires
1582            self.inv(),
1583        ensures
1584            r == self.remain_spec(),
1585    )]
1586    #[verifier::when_used_as_spec(remain_spec)]
1587    pub fn remain(&self) -> usize {
1588        self.end.addr() - self.cursor.addr()
1589    }
1590
1591    /// Returns the cursor pointer, which refers to the address of the next byte to read.
1592    pub fn cursor(&self) -> VirtPtr {
1593        self.cursor
1594    }
1595
1596    /// Returns whether there is remaining data to read.
1597    #[verus_spec(
1598        requires
1599            self.inv(),
1600    )]
1601    pub fn has_remain(&self) -> bool {
1602        self.remain() > 0
1603    }
1604
1605    /// Limits the length of remaining data.
1606    ///
1607    /// This method ensures the post-condition `self.remain() <= max_remain`.
1608    #[verus_spec(r =>
1609        requires
1610            old(self).inv(),
1611        ensures
1612            r.inv(),
1613            r.remain_spec() <= max_remain,
1614            r.remain_spec() <= old(self).remain_spec(),
1615            r.cursor == old(self).cursor,
1616            r.ghost_id == old(self).ghost_id,
1617    )]
1618    pub fn limit(&mut self, max_remain: usize) -> &mut Self {
1619        if max_remain < self.remain() {
1620            self.end = self.cursor.wrapping_add(max_remain);
1621        }
1622        self
1623    }
1624
1625    /// Skips the first `nbytes` bytes of data.
1626    ///
1627    /// The length of remaining data is decreased accordingly.
1628    ///
1629    /// # Panics
1630    ///
1631    /// If `nbytes` is greater than `self.remain()`, then the method panics.
1632    #[verus_spec(r =>
1633        requires
1634            old(self).inv(),
1635            nbytes <= old(self).remain_spec(),
1636        ensures
1637            r.inv(),
1638            r.cursor.vaddr == old(self).cursor.vaddr + nbytes,
1639            r.remain_spec() == old(self).remain_spec() - nbytes,
1640            r.end == old(self).end,
1641            r.ghost_id == old(self).ghost_id,
1642    )]
1643    pub fn skip(&mut self, nbytes: usize) -> &mut Self {
1644        assert!(nbytes <= self.remain());
1645        self.cursor = self.cursor.wrapping_add(nbytes);
1646        self
1647    }
1648
1649    /// Same as [`Self::skip`] but returns `()` instead of `&mut Self`.
1650    ///
1651    /// Sidesteps a Verus modeling quirk: `&mut self`-returning-`&mut Self`
1652    /// reborrows don't auto-propagate the return-value's ensures (`r.*`)
1653    /// to the post-state of `*self` (`final(self).*`). Callers that don't
1654    /// need to chain can use this in-place variant to avoid `r`-vs-`self`
1655    /// reborrow tracking.
1656    #[verus_spec(
1657        with
1658            Tracked(owner): Tracked<&mut crate::specs::mm::io::VmIoOwner>,
1659        requires
1660            old(self).inv(),
1661            old(self).wf(*old(owner)),
1662            old(owner).mem_view is Some,
1663            nbytes <= old(self).remain_spec(),
1664        ensures
1665            final(self).inv(),
1666            final(owner).inv(),
1667            final(self).wf(*final(owner)),
1668            old(owner).read_view_initialized() ==> final(owner).read_view_initialized(),
1669            final(self).cursor.vaddr == old(self).cursor.vaddr + nbytes,
1670            final(self).remain_spec() == old(self).remain_spec() - nbytes,
1671            final(self).end == old(self).end,
1672            final(self).ghost_id == old(self).ghost_id,
1673
1674            old(owner).mem_view matches Some(crate::specs::mm::io::VmIoMemView::ReadView(_)) ==>
1675                forall|va: usize|
1676                    #![trigger crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).read(va)]
1677                    final(self).cursor.vaddr <= va < old(self).end.vaddr
1678                    && crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va) is Some
1679                    && crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).memory.contains_key(
1680                            (crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va)->0).0
1681                    ) ==> {
1682                        &&& crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va)
1683                            == crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).addr_transl(va)
1684                        &&& crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).read(va)
1685                            == crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).read(va)
1686                    },
1687    )]
1688    pub fn skip_in_place(&mut self, nbytes: usize) {
1689        assert!(nbytes <= self.remain());
1690        self.cursor = self.cursor.wrapping_add(nbytes);
1691        proof {
1692            owner.advance(nbytes);
1693        }
1694    }
1695}
1696
1697#[verus_verify]
1698impl<'a, Fallibility> VmWriter<'a, Fallibility> {
1699    pub open spec fn avail_spec(&self) -> usize {
1700        (self.end.vaddr - self.cursor.vaddr) as usize
1701    }
1702
1703    /// Returns the number of available bytes that can be written.
1704    ///
1705    /// This has the same implementation as [`VmReader::remain`] but semantically
1706    /// they are different.
1707    ///
1708    /// # Verified Properties
1709    /// ## Preconditions
1710    /// - `self` must satisfy its invariant.
1711    /// ## Postconditions
1712    /// - The returned value equals [`Self::avail_spec`].
1713    #[inline]
1714    #[verus_spec(r =>
1715        requires
1716            self.inv(),
1717        ensures
1718            r == self.avail_spec(),
1719    )]
1720    #[verifier::when_used_as_spec(avail_spec)]
1721    pub fn avail(&self) -> usize {
1722        self.end.addr() - self.cursor.addr()
1723    }
1724
1725    /// Returns the cursor pointer, which refers to the address of the next byte to write.
1726    pub fn cursor(&self) -> VirtPtr {
1727        self.cursor
1728    }
1729
1730    /// Returns if it has available space to write.
1731    #[verus_spec(
1732        requires
1733            self.inv(),
1734    )]
1735    pub fn has_avail(&self) -> bool {
1736        self.avail() > 0
1737    }
1738
1739    /// Limits the length of available space.
1740    ///
1741    /// This method ensures the post-condition `self.avail() <= max_avail`.
1742    #[verus_spec(r =>
1743        requires
1744            old(self).inv(),
1745        ensures
1746            r.inv(),
1747            r.avail_spec() <= max_avail,
1748            r.avail_spec() <= old(self).avail_spec(),
1749            r.cursor == old(self).cursor,
1750            r.ghost_id == old(self).ghost_id,
1751    )]
1752    pub fn limit(&mut self, max_avail: usize) -> &mut Self {
1753        if max_avail < self.avail() {
1754            self.end = self.cursor.wrapping_add(max_avail);
1755        }
1756        self
1757    }
1758
1759    /// Skips the first `nbytes` of available space.
1760    ///
1761    /// The length of available space is decreased accordingly.
1762    ///
1763    /// # Panics
1764    ///
1765    /// If `nbytes` is greater than `self.avail()`, then the method panics.
1766    #[verus_spec(r =>
1767        requires
1768            old(self).inv(),
1769            nbytes <= old(self).avail_spec(),
1770        ensures
1771            r.inv(),
1772            r.cursor.vaddr == old(self).cursor.vaddr + nbytes,
1773            r.avail_spec() == old(self).avail_spec() - nbytes,
1774            r.end == old(self).end,
1775            r.ghost_id == old(self).ghost_id,
1776    )]
1777    pub fn skip(&mut self, nbytes: usize) -> &mut Self {
1778        assert!(nbytes <= self.avail());
1779        self.cursor = self.cursor.wrapping_add(nbytes);
1780        self
1781    }
1782}
1783
1784#[verus_verify]
1785impl<'a> VmWriter<'a, Fallible> {
1786    /// Constructs a [`VmWriter`] from a pointer and a length, which represents
1787    /// a memory range in USER space.
1788    ///
1789    /// # Verified Properties
1790    /// ## Preconditions
1791    /// - `ptr` must satisfy [`VirtPtr::inv`].
1792    /// ## Postconditions
1793    /// - The returned [`VmWriter`] satisfies its invariant.
1794    /// - The returned writer is associated with a [`VmIoOwner`] that satisfies both [`VmIoOwner::inv`]
1795    ///   and [`VmWriter::wf`].
1796    /// - The owner has the same range as `ptr`, has no memory view yet, and is marked as user-space.
1797    #[verus_spec(r =>
1798        with
1799            Ghost(id): Ghost<nat>,
1800                -> owner: Tracked<VmIoOwner>,
1801        ensures
1802            r.inv_wf(),
1803            owner@.id == id,
1804            owner@.range == ptr.range@,
1805            owner@.mem_view is None,
1806            !owner@.is_kernel,
1807            r.cursor == ptr,
1808            r.end == ptr.wrapping_add_spec(len),
1809            r.end.range@ == ptr.range@,
1810            ptr.inv() && ptr.range@.start == ptr.vaddr
1811                && len == ptr.range@.end - ptr.range@.start ==> {
1812                &&& r.inv()
1813                &&& owner@.inv()
1814                &&& r.wf(owner@)
1815            },
1816    )]
1817    pub unsafe fn from_user_space(ptr: VirtPtr, len: usize) -> Self {
1818        let tracked owner = VmIoOwner {
1819            id,
1820            range: ptr.range@,
1821            is_fallible: true,
1822            is_kernel: false,
1823            mem_view: None,
1824        };
1825        proof_with!(|= Tracked(owner));
1826        Self { ghost_id: Ghost(id), cursor: ptr, end: ptr.wrapping_add(len), phantom: PhantomData }
1827    }
1828
1829    /// Writes a value of `Pod` type to user space.
1830    ///
1831    /// If the underlying memory access faults during the write, the cursor
1832    /// is rolled back to its starting position before returning `Err`.
1833    ///
1834    /// # Verified Properties
1835    /// ## Postconditions
1836    /// - On success, the cursor advances by `size_of::<T>()`.
1837    /// - On error, the cursor is at its original position (writer state preserved).
1838    #[verus_spec(r =>
1839        requires
1840            old(self).inv(),
1841        ensures
1842            final(self).inv(),
1843            final(self).end == old(self).end,
1844            final(self).ghost_id == old(self).ghost_id,
1845            final(self).cursor.range == old(self).cursor.range,
1846            r is Err ==> *final(self) == *old(self),
1847    )]
1848    pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> {
1849        let len = core::mem::size_of::<T>();
1850        if self.avail() < len {
1851            return Err(Error::InvalidArgs);
1852        }
1853        proof_decl! {
1854            let tracked mut reader_owner_inner: VmIoOwner;
1855        }
1856        #[verus_spec(with => Tracked(reader_owner_inner))]
1857        let mut reader = VmReader::from(new_val.as_bytes());
1858        match self.write_fallible(&mut reader) {
1859            Ok(_) => Ok(()),
1860            Err((err, copied_len)) => {
1861                self.cursor = self.cursor.sub(copied_len);
1862                Err(err)
1863            },
1864        }
1865    }
1866
1867    /// Writes `len` zeros to the target memory.
1868    ///
1869    /// This method attempts to fill up to `len` bytes with zeros. If the
1870    /// available memory from the current cursor position is less than `len`,
1871    /// it will only fill the available space.
1872    ///
1873    /// If the memory write failed due to an unresolvable page fault, this
1874    /// method will return `Err` with the length set so far.
1875    #[verus_spec(r =>
1876        requires
1877            old(self).inv(),
1878        ensures
1879            final(self).inv(),
1880            final(self).end == old(self).end,
1881            final(self).ghost_id == old(self).ghost_id,
1882            final(self).cursor.range == old(self).cursor.range,
1883            final(self).cursor.vaddr >= old(self).cursor.vaddr,
1884            final(self).cursor.vaddr <= old(self).end.vaddr,
1885            match r {
1886                Ok(n) => {
1887                    &&& n <= len
1888                    &&& n <= old(self).avail_spec()
1889                    &&& final(self).cursor.vaddr == old(self).cursor.vaddr + n
1890                },
1891                Err((_, n)) => {
1892                    &&& n <= len
1893                    &&& n <= old(self).avail_spec()
1894                    &&& final(self).cursor.vaddr == old(self).cursor.vaddr + n
1895                },
1896            }
1897    )]
1898    pub fn fill_zeros(&mut self, len: usize) -> core::result::Result<usize, (Error, usize)> {
1899        let len_to_set = self.avail().min(len);
1900        if len_to_set == 0 {
1901            return Ok(0);
1902        }
1903        // SAFETY: The destination is a subset of the memory range specified by
1904        // the current writer, so it is either valid for writing or in user space.
1905
1906        let set_len = unsafe { memset_fallible(self.cursor, 0u8, len_to_set) };
1907        self.cursor = self.cursor.wrapping_add(set_len);
1908
1909        if set_len < len_to_set {
1910            Err((Error::PageFault, set_len))
1911        } else {
1912            Ok(len_to_set)
1913        }
1914    }
1915}
1916
1917/// Extension trait for byte slices that produces a [`VirtPtr`] covering the
1918/// slice's bytes. Mirrors the role of [`<[u8]>::as_ptr`] but in our verified
1919/// pointer model.
1920pub trait AsVirtPtr {
1921    fn as_virt_ptr(&self) -> VirtPtr;
1922}
1923
1924#[verus_verify]
1925impl AsVirtPtr for [u8] {
1926    #[verus_spec(r =>
1927        ensures
1928            r.inv(),
1929            r.range@.start == r.vaddr,
1930            r.range@.end - r.range@.start == self.len(),
1931            r.vaddr == ::vstd_extra::external::slice::as_ptr_spec(self) as usize,
1932    )]
1933    fn as_virt_ptr(&self) -> VirtPtr {
1934        let addr = self.as_ptr() as usize;
1935        let len = self.len();
1936        proof {
1937            ::vstd_extra::external::slice::axiom_slice_addr_no_overflow(self);
1938        }
1939        let ghost range: Range<usize> = addr..(addr + len) as usize;
1940        VirtPtr { vaddr: addr, range: Ghost(range) }
1941    }
1942}
1943
1944/*
1945// Original From<&mut [u8]> for VmWriter (replaced by pub fn from during Verus migration):
1946impl<'a> From<&'a mut [u8]> for VmWriter<'a, Infallible> {
1947    fn from(slice: &'a mut [u8]) -> Self {
1948        unsafe { Self::from_kernel_space(slice.as_mut_ptr(), slice.len()) }
1949    }
1950}
1951*/
1952
1953#[verus_verify]
1954impl<'a> VmWriter<'a, Infallible> {
1955    /// Constructs a [`VmWriter<'a, Infallible>`] from a mutable byte slice.
1956    ///
1957    /// The slice's address establishes the writer's cursor range; the kernel-space
1958    /// trust ([`axiom_slice_in_kernel`] + [`axiom_kernel_mem_view`] via
1959    /// [`Self::from_kernel_space`]) supplies the tracked [`VmIoOwner`] with its
1960    /// `WriteView`. Callers receive the owner via `proof_with!`.
1961    ///
1962    /// # Safety
1963    ///
1964    /// The slice's memory must be valid for writes during `'a` — guaranteed by
1965    /// Rust's borrow checker for `&'a mut [u8]`.
1966    #[verus_spec(r =>
1967        with
1968            -> owner: Tracked<VmIoOwner>,
1969        ensures
1970            r.inv(),
1971            owner@.inv(),
1972            r.wf(*owner),
1973            owner@.has_write_view(),
1974            r.cursor.range == owner@.range,
1975            owner@.range.end - owner@.range.start == old(slice).len(),
1976    )]
1977    pub fn from(slice: &'a mut [u8]) -> Self {
1978        // SAFETY:
1979        // - The memory range points to typed memory.
1980        // - The validity requirements for write accesses are met because the pointer is converted
1981        //   from a mutable reference that outlives the lifetime `'a`.
1982        // - The type, i.e., the `u8` slice, is plain-old-data.
1983        let shared: &[u8] = &*slice;
1984        proof {
1985            axiom_slice_in_kernel(shared);
1986        }
1987        let ptr = shared.as_virt_ptr();
1988        let len = shared.len();
1989        proof_decl! {
1990            let tracked mut owner_inner: VmIoOwner;
1991        }
1992        let writer = unsafe {
1993            #[verus_spec(with Ghost(0nat), Tracked(false) => Tracked(owner_inner))]
1994            Self::from_kernel_space(ptr, len)
1995        };
1996        proof_with!(|= Tracked(owner_inner));
1997        writer
1998    }
1999}
2000
2001/*
2002// Original From<&[u8]> for VmReader (replaced by pub fn from during Verus migration):
2003impl<'a> From<&'a [u8]> for VmReader<'a, Infallible> {
2004    fn from(slice: &'a [u8]) -> Self {
2005        unsafe { Self::from_kernel_space(slice.as_ptr(), slice.len()) }
2006    }
2007}
2008*/
2009
2010#[verus_verify]
2011impl<'a> VmReader<'a, Infallible> {
2012    /// Constructs a [`VmReader<'a, Infallible>`] from a shared byte slice.
2013    ///
2014    /// The slice's address establishes the reader's cursor range; the kernel-space
2015    /// trust ([`axiom_slice_in_kernel`] + [`axiom_kernel_mem_view`] via
2016    /// [`Self::from_kernel_space`]) supplies the tracked [`VmIoOwner`] with its
2017    /// initialized `ReadView`. Callers receive the owner via `proof_with!`.
2018    ///
2019    /// # Safety
2020    ///
2021    /// The slice's memory must be valid for reads during `'a` — guaranteed by
2022    /// Rust's borrow checker for `&'a [u8]`.
2023    #[verus_spec(r =>
2024        with
2025            -> owner: Tracked<VmIoOwner>,
2026        ensures
2027            r.inv(),
2028            owner@.inv(),
2029            r.wf(*owner),
2030            owner@.read_view_initialized(),
2031            r.cursor.range == owner@.range,
2032            owner@.range.end - owner@.range.start == slice.len(),
2033    )]
2034    pub fn from(slice: &'a [u8]) -> Self {
2035        // SAFETY:
2036        // - The memory range points to typed memory.
2037        // - The validity requirements for read accesses are met because the pointer is converted
2038        //   from a shared reference that outlives the lifetime `'a`.
2039        // - The type, i.e., the `u8` slice, is plain-old-data.
2040        proof {
2041            axiom_slice_in_kernel(slice);
2042        }
2043        let ptr = slice.as_virt_ptr();
2044        let len = slice.len();
2045        proof_decl! {
2046            let tracked mut owner_inner: VmIoOwner;
2047        }
2048        let reader = unsafe {
2049            #[verus_spec(with Ghost(0nat) => Tracked(owner_inner))]
2050            Self::from_kernel_space(ptr, len)
2051        };
2052        proof_with!(|= Tracked(owner_inner));
2053        reader
2054    }
2055}
2056
2057} // verus!
2058/// Fallible memory read from a `VmWriter`.
2059pub trait FallibleVmRead<F> {
2060    fn read_fallible(
2061        &mut self,
2062        writer: &mut VmWriter<'_, F>,
2063    ) -> core::result::Result<usize, (Error, usize)>;
2064}
2065
2066/// Fallible memory write from a `VmReader`.
2067pub trait FallibleVmWrite<F> {
2068    fn write_fallible(
2069        &mut self,
2070        reader: &mut VmReader<'_, F>,
2071    ) -> core::result::Result<usize, (Error, usize)>;
2072}
2073
2074macro_rules! impl_read_fallible {
2075    ($reader_fallibility:ty, $writer_fallibility:ty) => {
2076        ::vstd::prelude::verus! {
2077        impl<'a> FallibleVmRead<$writer_fallibility> for VmReader<'a, $reader_fallibility> {
2078            #[verus_spec(r =>
2079                requires
2080                    old(self).inv(),
2081                    old(writer).inv(),
2082                ensures
2083                    final(self).end == old(self).end,
2084                    final(self).ghost_id == old(self).ghost_id,
2085                    final(self).cursor.range == old(self).cursor.range,
2086                    final(writer).end == old(writer).end,
2087                    final(writer).ghost_id == old(writer).ghost_id,
2088                    final(writer).cursor.range == old(writer).cursor.range,
2089                    final(self).inv(),
2090                    final(writer).inv(),
2091                    match r {
2092                        Ok(n) => {
2093                            &&& final(self).cursor.vaddr == old(self).cursor.vaddr + n
2094                            &&& final(writer).cursor.vaddr == old(writer).cursor.vaddr + n
2095                            &&& n <= old(self).remain_spec()
2096                            &&& n <= old(writer).avail_spec()
2097                        },
2098                        Err((_, copied_len)) => {
2099                            &&& final(self).cursor.vaddr == old(self).cursor.vaddr + copied_len
2100                            &&& final(writer).cursor.vaddr == old(writer).cursor.vaddr + copied_len
2101                            &&& copied_len <= old(self).remain_spec()
2102                            &&& copied_len <= old(writer).avail_spec()
2103                        },
2104                    }
2105            )]
2106            fn read_fallible(
2107                &mut self,
2108                writer: &mut VmWriter<'_, $writer_fallibility>,
2109            ) -> core::result::Result<usize, (Error, usize)> {
2110                let copy_len = self.remain().min(writer.avail());
2111                if copy_len == 0 {
2112                    return Ok(0);
2113                }
2114
2115                // SAFETY: The source and destination are subsets of memory ranges specified by
2116                // the reader and writer, so they are either valid for reading and writing or in
2117                // user space.
2118                let copied_len = unsafe {
2119                    memcpy_fallible(writer.cursor, self.cursor, copy_len)
2120                };
2121                self.cursor = self.cursor.wrapping_add(copied_len);
2122                writer.cursor = writer.cursor.wrapping_add(copied_len);
2123
2124                if copied_len < copy_len {
2125                    Err((Error::PageFault, copied_len))
2126                } else {
2127                    Ok(copied_len)
2128                }
2129            }
2130        }
2131        } // verus!
2132};
2133}
2134
2135macro_rules! impl_write_fallible {
2136    ($writer_fallibility:ty, $reader_fallibility:ty) => {
2137        ::vstd::prelude::verus! {
2138        impl<'a> FallibleVmWrite<$reader_fallibility> for VmWriter<'a, $writer_fallibility> {
2139            #[verus_spec(r =>
2140                requires
2141                    old(self).inv(),
2142                    old(reader).inv(),
2143                ensures
2144                    final(self).end == old(self).end,
2145                    final(self).ghost_id == old(self).ghost_id,
2146                    final(self).cursor.range == old(self).cursor.range,
2147                    final(reader).end == old(reader).end,
2148                    final(reader).ghost_id == old(reader).ghost_id,
2149                    final(reader).cursor.range == old(reader).cursor.range,
2150                    final(self).inv(),
2151                    final(reader).inv(),
2152                    match r {
2153                        Ok(n) => {
2154                            &&& final(self).cursor.vaddr == old(self).cursor.vaddr + n
2155                            &&& final(reader).cursor.vaddr == old(reader).cursor.vaddr + n
2156                            &&& n <= old(self).avail_spec()
2157                            &&& n <= old(reader).remain_spec()
2158                        },
2159                        Err((_, copied_len)) => {
2160                            &&& final(self).cursor.vaddr == old(self).cursor.vaddr + copied_len
2161                            &&& final(reader).cursor.vaddr == old(reader).cursor.vaddr + copied_len
2162                            &&& copied_len <= old(self).avail_spec()
2163                            &&& copied_len <= old(reader).remain_spec()
2164                        },
2165                    }
2166            )]
2167            fn write_fallible(
2168                &mut self,
2169                reader: &mut VmReader<'_, $reader_fallibility>,
2170            ) -> core::result::Result<usize, (Error, usize)> {
2171                reader.read_fallible(self)
2172            }
2173        }
2174        } // verus!
2175};
2176}
2177
2178impl_read_fallible!(Fallible, Infallible);
2179impl_read_fallible!(Fallible, Fallible);
2180impl_read_fallible!(Infallible, Fallible);
2181impl_write_fallible!(Fallible, Infallible);
2182impl_write_fallible!(Fallible, Fallible);
2183impl_write_fallible!(Infallible, Fallible);
2184
2185verus! {
2186
2187/// A marker trait for POD types that can be read or written with one instruction.
2188///
2189/// This trait is mostly a hint, since it's safe and can be implemented for _any_ POD type. If it
2190/// is implemented for a type that cannot be read or written with a single instruction, calling
2191/// `read_once`/`write_once` will lead to a failed compile-time assertion.
2192pub trait PodOnce: Pod {
2193
2194}
2195
2196#[cfg(any(
2197    target_arch = "x86_64",
2198    target_arch = "riscv64",
2199    target_arch = "loongarch64"
2200))]
2201mod pod_once_impls {
2202    use super::PodOnce;
2203
2204    impl PodOnce for u8 {
2205
2206    }
2207
2208    impl PodOnce for u16 {
2209
2210    }
2211
2212    impl PodOnce for u32 {
2213
2214    }
2215
2216    impl PodOnce for u64 {
2217
2218    }
2219
2220    impl PodOnce for usize {
2221
2222    }
2223
2224    impl PodOnce for i8 {
2225
2226    }
2227
2228    impl PodOnce for i16 {
2229
2230    }
2231
2232    impl PodOnce for i32 {
2233
2234    }
2235
2236    impl PodOnce for i64 {
2237
2238    }
2239
2240    impl PodOnce for isize {
2241
2242    }
2243
2244    /// Checks whether the memory operation created by `ptr::read_volatile` and
2245    /// `ptr::write_volatile` doesn't tear.
2246    ///
2247    /// Note that the Rust documentation makes no such guarantee, and even the wording in the LLVM
2248    /// LangRef is ambiguous. But this is unlikely to break in practice because the Linux kernel
2249    /// also uses "volatile" semantics to implement `READ_ONCE`/`WRITE_ONCE`.
2250    pub(super) const fn is_non_tearing<T>() -> bool {
2251        let size = core::mem::size_of::<T>();
2252
2253        size == 1 || size == 2 || size == 4 || size == 8
2254    }
2255
2256}
2257
2258} // verus!