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        recommends
1189            Self::obeys_vmio_spec(),
1190    {
1191        false
1192    }
1193
1194    open spec fn obeys_vmio_write_requires() -> bool
1195        recommends
1196            Self::obeys_vmio_spec(),
1197    {
1198        false
1199    }
1200
1201    spec fn obeys_vmio_read_spec() -> bool
1202        recommends
1203            Self::obeys_vmio_spec(),
1204    ;
1205
1206    spec fn obeys_vmio_write_spec() -> bool
1207        recommends
1208            Self::obeys_vmio_spec(),
1209    ;
1210
1211    open spec fn read_requires(
1212        self,
1213        offset: usize,
1214        writer: VmWriter<'_>,
1215        writer_own: VmIoOwner,
1216        owner: P,
1217    ) -> bool {
1218        true
1219    }
1220
1221    open spec fn write_requires(
1222        self,
1223        offset: usize,
1224        reader: VmReader<'_>,
1225        reader_own: VmIoOwner,
1226        owner: P,
1227    ) -> bool {
1228        true
1229    }
1230
1231    spec fn read_spec(
1232        self,
1233        offset: usize,
1234        old_writer: VmWriter<'_>,
1235        new_writer: VmWriter<'_>,
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    spec fn write_spec(
1244        self,
1245        offset: usize,
1246        old_reader: VmReader<'_>,
1247        new_reader: VmReader<'_>,
1248        old_writer_own: VmIoOwner,
1249        new_writer_own: VmIoOwner,
1250        old_owner: P,
1251        new_owner: P,
1252        r: Result<()>,
1253    ) -> bool;
1254
1255    /// Reads requested data at a specified offset into a given [`VmWriter`].
1256    ///
1257    /// # No short reads
1258    ///
1259    /// On success, the `writer` must be written with the requested data
1260    /// completely. If, for any reason, the requested data is only partially
1261    /// available, then the method shall return an error.
1262    fn read(
1263        &self,
1264        offset: usize,
1265        writer: &mut VmWriter<'_>,
1266        Tracked(writer_own): Tracked<&mut VmIoOwner>,
1267        Tracked(owner): Tracked<&mut P>,
1268    ) -> (r: Result<()>)
1269        requires
1270            Self::obeys_vmio_read_requires() ==> Self::read_requires(
1271                *self,
1272                offset,
1273                *old(writer),
1274                *old(writer_own),
1275                *old(owner),
1276            ),
1277        ensures
1278            Self::obeys_vmio_read_spec() ==> Self::read_spec(
1279                *self,
1280                offset,
1281                *old(writer),
1282                *final(writer),
1283                *old(writer_own),
1284                *final(writer_own),
1285                *old(owner),
1286                *final(owner),
1287                r,
1288            ),
1289    ;
1290
1291    /// Writes all data from a given `VmReader` at a specified offset.
1292    ///
1293    /// # No short writes
1294    ///
1295    /// On success, the data from the `reader` must be read to the VM object entirely.
1296    /// If, for any reason, the input data can only be written partially,
1297    /// then the method shall return an error.
1298    fn write(
1299        &self,
1300        offset: usize,
1301        reader: &mut VmReader,
1302        Tracked(writer_own): Tracked<&mut VmIoOwner>,
1303        Tracked(owner): Tracked<&mut P>,
1304    ) -> (r: Result<()>)
1305        requires
1306            Self::obeys_vmio_write_requires() ==> Self::write_requires(
1307                *self,
1308                offset,
1309                *old(reader),
1310                *old(writer_own),
1311                *old(owner),
1312            ),
1313        ensures
1314            Self::obeys_vmio_write_spec() ==> Self::write_spec(
1315                *self,
1316                offset,
1317                *old(reader),
1318                *final(reader),
1319                *old(writer_own),
1320                *final(writer_own),
1321                *old(owner),
1322                *final(owner),
1323                r,
1324            ),
1325    ;
1326
1327    /// Reads a specified number of bytes at a specified offset into a given buffer.
1328    ///
1329    /// Wraps `buf` in a [`VmWriter`] (whose tracked owner is minted internally
1330    /// from the slice via [`VmWriter::from`]) and delegates to [`Self::read`].
1331    /// The shallow contract here only forwards the result; impls with non-trivial
1332    /// `read_requires` must override.
1333    fn read_bytes(&self, offset: usize, buf: &mut [u8], Tracked(owner): Tracked<&mut P>) -> (r:
1334        Result<()>)
1335        requires
1336            !Self::obeys_vmio_read_requires(),
1337    {
1338        proof_decl! {
1339            let tracked mut writer_own_inner: VmIoOwner;
1340        }
1341        #[verus_spec(with => Tracked(writer_own_inner))]
1342        let infallible_writer = VmWriter::from(buf);
1343        let mut writer = infallible_writer.to_fallible();
1344        self.read(offset, &mut writer, Tracked(&mut writer_own_inner), Tracked(owner))
1345    }
1346
1347    /// Reads a value of a specified type at a specified offset.
1348    fn read_val<T: Pod>(&self, offset: usize, Tracked(owner): Tracked<&mut P>) -> (r: Result<T>)
1349        requires
1350            !Self::obeys_vmio_read_requires(),
1351    {
1352        let mut val = T::new_uninit();
1353        match self.read_bytes(offset, val.as_bytes_mut(), Tracked(owner)) {
1354            Ok(_) => Ok(val),
1355            Err(e) => Err(e),
1356        }
1357    }
1358
1359    /// Reads a slice of a specified type at a specified offset.
1360    fn read_slice<T: Pod>(
1361        &self,
1362        offset: usize,
1363        slice: &mut [T],
1364        Tracked(owner): Tracked<&mut P>,
1365    ) -> (r: Result<()>)
1366        requires
1367            !Self::obeys_vmio_read_requires(),
1368    {
1369        let len_in_bytes = core::mem::size_of_val(slice);
1370        let ptr = slice.as_mut_ptr() as *mut u8;
1371        // SAFETY: the slice can be transmuted to a writable byte slice since
1372        // the elements are all Plain-Old-Data (Pod) types.
1373        let buf = unsafe { core::slice::from_raw_parts_mut(ptr, len_in_bytes) };
1374        self.read_bytes(offset, buf, Tracked(owner))
1375    }
1376
1377    /// Writes a specified number of bytes from a given buffer at a specified offset.
1378    ///
1379    /// Wraps `buf` in a [`VmReader`] (whose tracked owner is minted internally
1380    /// from the slice via [`VmReader::from`]) and delegates to [`Self::write`].
1381    /// The shallow contract here only forwards the result; impls with non-trivial
1382    /// `write_requires` must override.
1383    fn write_bytes(&self, offset: usize, buf: &[u8], Tracked(owner): Tracked<&mut P>) -> (r: Result<
1384        (),
1385    >)
1386        requires
1387            !Self::obeys_vmio_write_requires(),
1388    {
1389        proof_decl! {
1390            let tracked mut reader_own_inner: VmIoOwner;
1391        }
1392        #[verus_spec(with => Tracked(reader_own_inner))]
1393        let infallible_reader = VmReader::from(buf);
1394        let mut reader = infallible_reader.to_fallible();
1395        self.write(offset, &mut reader, Tracked(&mut reader_own_inner), Tracked(owner))
1396    }
1397
1398    /// Writes a value of a specified type at a specified offset.
1399    fn write_val<T: Pod>(&self, offset: usize, new_val: &T, Tracked(owner): Tracked<&mut P>) -> (r:
1400        Result<()>)
1401        requires
1402            !Self::obeys_vmio_write_requires(),
1403    {
1404        self.write_bytes(offset, new_val.as_bytes(), Tracked(owner))
1405    }
1406
1407    /// Writes a slice of a specified type at a specified offset.
1408    fn write_slice<T: Pod>(
1409        &self,
1410        offset: usize,
1411        slice: &[T],
1412        Tracked(owner): Tracked<&mut P>,
1413    ) -> (r: Result<()>)
1414        requires
1415            !Self::obeys_vmio_write_requires(),
1416    {
1417        let len_in_bytes = core::mem::size_of_val(slice);
1418        let ptr = slice.as_ptr() as *const u8;
1419        // SAFETY: the slice can be transmuted to a readable byte slice since
1420        // the elements are all Plain-Old-Data (Pod) types.
1421        let buf = unsafe { core::slice::from_raw_parts(ptr, len_in_bytes) };
1422        self.write_bytes(offset, buf, Tracked(owner))
1423    }
1424
1425    /// Writes a sequence of values given by an iterator (`iter`) from the
1426    /// specified offset (`offset`).
1427    ///
1428    /// Stops on iterator exhaustion or write error. Returns `Ok(nr_written)`
1429    /// if at least one value was written; only the first-call error path
1430    /// surfaces as `Err`.
1431    ///
1432    /// `align` rounds the offset and item size up: `0`/`1` means no padding,
1433    /// otherwise must be a power of two. Bad `align` panics at runtime — this
1434    /// is captured as a *post-condition*, not a pre-condition, since the panic
1435    /// is what enforces it.
1436    ///
1437    /// Preconditions left for the caller:
1438    /// - `offset + (align - 1)` and `size_of::<T>() + (align - 1)` don't overflow
1439    ///   (so the post-panic call to `align_up` is safe).
1440    /// - The supplied iterator obeys Verus' prophetic iterator laws and provides
1441    ///   a `decrease` measure (true for slice iterators, `repeat_n`, and the
1442    ///   stdlib iterator combinators ostd uses).
1443    /// - `self`'s impl has no custom `write_requires` (use the override route
1444    ///   for impls that do).
1445    fn write_vals<
1446        'a,
1447        T: Pod + 'a,
1448        I: ::vstd::std_specs::iter::IteratorSpec<Item = &'a T> + Iterator<Item = &'a T>,
1449    >(&self, offset: usize, iter: I, align: usize, Tracked(owner): Tracked<&mut P>) -> (r: Result<
1450        usize,
1451    >)
1452        requires
1453            !Self::obeys_vmio_write_requires(),
1454            offset + align <= usize::MAX,
1455            core::mem::size_of::<T>() + align <= usize::MAX,
1456            iter.obeys_prophetic_iter_laws(),
1457            iter.decrease() is Some,
1458            // `align_up` (called for `align > 1`) diverges unless `align`
1459            // is a power of two.
1460            !(align <= 1 || is_pow2(align as int)) ==> may_panic(),
1461        ensures
1462            align <= 1 || is_pow2(align as int),
1463    {
1464        use ::align_ext::AlignExt;
1465        let mut nr_written: usize = 0;
1466        // `align_up` itself panics on invalid `align`, so reaching the post-`else`
1467        // statements gives us the post-condition for free.
1468        let (mut offset, item_size) = if align <= 1 {
1469            (offset, core::mem::size_of::<T>())
1470        } else {
1471            (offset.align_up(align), core::mem::size_of::<T>().align_up(align))
1472        };
1473        let mut iter = iter;
1474        loop
1475            invariant
1476                !Self::obeys_vmio_write_requires(),
1477                iter.obeys_prophetic_iter_laws(),
1478                iter.decrease() is Some,
1479                align == 0 || align == 1 || is_pow2(align as int),
1480            decreases iter.decrease().unwrap(),
1481        {
1482            match iter.next() {
1483                Some(item) => {
1484                    // Stop *before* writing if we couldn't safely advance afterwards.
1485                    if nr_written == usize::MAX || (item_size > 0 && offset > usize::MAX
1486                        - item_size) {
1487                        return Ok(nr_written);
1488                    }
1489                    match self.write_val(offset, item, Tracked(owner)) {
1490                        Ok(_) => {
1491                            offset = offset + item_size;
1492                            nr_written = nr_written + 1;
1493                        },
1494                        Err(e) => {
1495                            if nr_written > 0 {
1496                                return Ok(nr_written);
1497                            }
1498                            return Err(e);
1499                        },
1500                    }
1501                },
1502                None => return Ok(nr_written),
1503            }
1504        }
1505    }
1506}
1507
1508/// A trait that enables reading/writing data from/to a VM object using one non-tearing memory
1509/// load/store.
1510///
1511/// See also [`VmIo`], which enables reading/writing data from/to a VM object without the guarantee
1512/// of using one non-tearing memory load/store.
1513pub trait VmIoOnce: Sized {
1514    spec fn obeys_vmio_once_read_requires() -> bool;
1515
1516    spec fn obeys_vmio_once_write_requires() -> bool;
1517
1518    spec fn obeys_vmio_once_read_ensures() -> bool;
1519
1520    spec fn obeys_vmio_once_write_ensures() -> bool;
1521
1522    /// Reads a value of the `PodOnce` type at the specified offset using one non-tearing memory
1523    /// load.
1524    ///
1525    /// Except that the offset is specified explicitly, the semantics of this method is the same as
1526    /// [`VmReader::read_once`].
1527    fn read_once<T: PodOnce>(&self, offset: usize) -> Result<T>;
1528
1529    /// Writes a value of the `PodOnce` type at the specified offset using one non-tearing memory
1530    /// store.
1531    ///
1532    /// Except that the offset is specified explicitly, the semantics of this method is the same as
1533    /// [`VmWriter::write_once`].
1534    fn write_once<T: PodOnce>(&self, offset: usize, new_val: &T) -> Result<()>;
1535}
1536
1537/*
1538// Original impl_vm_io_pointer macro and invocations (removed during Verus migration):
1539macro_rules! impl_vm_io_pointer {
1540    ($typ:ty,$from:tt) => {
1541        #[inherit_methods(from = $from)]
1542        impl<T: VmIo> VmIo for $typ {
1543            fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>;
1544            fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>;
1545            fn read_val<F: Pod>(&self, offset: usize) -> Result<F>;
1546            fn read_slice<F: Pod>(&self, offset: usize, slice: &mut [F]) -> Result<()>;
1547            fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>;
1548            fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>;
1549            fn write_val<F: Pod>(&self, offset: usize, new_val: &F) -> Result<()>;
1550            fn write_slice<F: Pod>(&self, offset: usize, slice: &[F]) -> Result<()>;
1551        }
1552    };
1553}
1554
1555impl_vm_io_pointer!(&T, "(**self)");
1556impl_vm_io_pointer!(&mut T, "(**self)");
1557impl_vm_io_pointer!(Box<T>, "(**self)");
1558impl_vm_io_pointer!(Arc<T>, "(**self)");
1559*/
1560
1561/*
1562// Original impl_vm_io_once_pointer macro and invocations (removed during Verus migration):
1563macro_rules! impl_vm_io_once_pointer {
1564    ($typ:ty,$from:tt) => {
1565        #[inherit_methods(from = $from)]
1566        impl<T: VmIoOnce> VmIoOnce for $typ {
1567            fn read_once<F: PodOnce>(&self, offset: usize) -> Result<F>;
1568            fn write_once<F: PodOnce>(&self, offset: usize, new_val: &F) -> Result<()>;
1569        }
1570    };
1571}
1572
1573impl_vm_io_once_pointer!(&T, "(**self)");
1574impl_vm_io_once_pointer!(&mut T, "(**self)");
1575impl_vm_io_once_pointer!(Box<T>, "(**self)");
1576impl_vm_io_once_pointer!(Arc<T>, "(**self)");
1577*/
1578
1579#[verus_verify]
1580impl<Fallibility> VmReader<'_, Fallibility> {
1581    pub open spec fn remain_spec(&self) -> usize {
1582        (self.end.vaddr - self.cursor.vaddr) as usize
1583    }
1584
1585    /// Returns the number of remaining bytes that can be read.
1586    ///
1587    /// # Verified Properties
1588    /// ## Preconditions
1589    /// - `self` must satisfy its invariant.
1590    /// ## Postconditions
1591    /// - The returned value equals [`Self::remain_spec`].
1592    #[verus_spec(r =>
1593        requires
1594            self.inv(),
1595        ensures
1596            r == self.remain_spec(),
1597    )]
1598    #[verifier::when_used_as_spec(remain_spec)]
1599    pub fn remain(&self) -> usize {
1600        self.end.addr() - self.cursor.addr()
1601    }
1602
1603    /// Returns the cursor pointer, which refers to the address of the next byte to read.
1604    pub fn cursor(&self) -> VirtPtr {
1605        self.cursor
1606    }
1607
1608    /// Returns whether there is remaining data to read.
1609    #[verus_spec(
1610        requires
1611            self.inv(),
1612    )]
1613    pub fn has_remain(&self) -> bool {
1614        self.remain() > 0
1615    }
1616
1617    /// Limits the length of remaining data.
1618    ///
1619    /// This method ensures the post-condition `self.remain() <= max_remain`.
1620    #[verus_spec(r =>
1621        requires
1622            old(self).inv(),
1623        ensures
1624            r.inv(),
1625            r.remain_spec() <= max_remain,
1626            r.remain_spec() <= old(self).remain_spec(),
1627            r.cursor == old(self).cursor,
1628            r.ghost_id == old(self).ghost_id,
1629    )]
1630    pub fn limit(&mut self, max_remain: usize) -> &mut Self {
1631        if max_remain < self.remain() {
1632            self.end = self.cursor.wrapping_add(max_remain);
1633        }
1634        self
1635    }
1636
1637    /// Skips the first `nbytes` bytes of data.
1638    ///
1639    /// The length of remaining data is decreased accordingly.
1640    ///
1641    /// # Panics
1642    ///
1643    /// If `nbytes` is greater than `self.remain()`, then the method panics.
1644    #[verus_spec(r =>
1645        requires
1646            old(self).inv(),
1647            nbytes <= old(self).remain_spec(),
1648        ensures
1649            r.inv(),
1650            r.cursor.vaddr == old(self).cursor.vaddr + nbytes,
1651            r.remain_spec() == old(self).remain_spec() - nbytes,
1652            r.end == old(self).end,
1653            r.ghost_id == old(self).ghost_id,
1654    )]
1655    pub fn skip(&mut self, nbytes: usize) -> &mut Self {
1656        assert!(nbytes <= self.remain());
1657        self.cursor = self.cursor.wrapping_add(nbytes);
1658        self
1659    }
1660
1661    /// Same as [`Self::skip`] but returns `()` instead of `&mut Self`.
1662    ///
1663    /// Sidesteps a Verus modeling quirk: `&mut self`-returning-`&mut Self`
1664    /// reborrows don't auto-propagate the return-value's ensures (`r.*`)
1665    /// to the post-state of `*self` (`final(self).*`). Callers that don't
1666    /// need to chain can use this in-place variant to avoid `r`-vs-`self`
1667    /// reborrow tracking.
1668    #[verus_spec(
1669        with
1670            Tracked(owner): Tracked<&mut crate::specs::mm::io::VmIoOwner>,
1671        requires
1672            old(self).inv(),
1673            old(self).wf(*old(owner)),
1674            old(owner).mem_view is Some,
1675            nbytes <= old(self).remain_spec(),
1676        ensures
1677            final(self).inv(),
1678            final(owner).inv(),
1679            final(self).wf(*final(owner)),
1680            old(owner).read_view_initialized() ==> final(owner).read_view_initialized(),
1681            final(self).cursor.vaddr == old(self).cursor.vaddr + nbytes,
1682            final(self).remain_spec() == old(self).remain_spec() - nbytes,
1683            final(self).end == old(self).end,
1684            final(self).ghost_id == old(self).ghost_id,
1685
1686            old(owner).mem_view matches Some(crate::specs::mm::io::VmIoMemView::ReadView(_)) ==>
1687                forall|va: usize|
1688                    #![trigger crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).read(va)]
1689                    final(self).cursor.vaddr <= va < old(self).end.vaddr
1690                    && crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va) is Some
1691                    && crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).memory.contains_key(
1692                            (crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va)->0).0
1693                    ) ==> {
1694                        &&& crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).addr_transl(va)
1695                            == crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).addr_transl(va)
1696                        &&& crate::specs::mm::io::VmIoOwner::read_view_of(*old(owner)).read(va)
1697                            == crate::specs::mm::io::VmIoOwner::read_view_of(*final(owner)).read(va)
1698                    },
1699    )]
1700    pub fn skip_in_place(&mut self, nbytes: usize) {
1701        assert!(nbytes <= self.remain());
1702        self.cursor = self.cursor.wrapping_add(nbytes);
1703        proof {
1704            owner.advance(nbytes);
1705        }
1706    }
1707}
1708
1709#[verus_verify]
1710impl<'a, Fallibility> VmWriter<'a, Fallibility> {
1711    pub open spec fn avail_spec(&self) -> usize {
1712        (self.end.vaddr - self.cursor.vaddr) as usize
1713    }
1714
1715    /// Returns the number of available bytes that can be written.
1716    ///
1717    /// This has the same implementation as [`VmReader::remain`] but semantically
1718    /// they are different.
1719    ///
1720    /// # Verified Properties
1721    /// ## Preconditions
1722    /// - `self` must satisfy its invariant.
1723    /// ## Postconditions
1724    /// - The returned value equals [`Self::avail_spec`].
1725    #[inline]
1726    #[verus_spec(r =>
1727        requires
1728            self.inv(),
1729        ensures
1730            r == self.avail_spec(),
1731    )]
1732    #[verifier::when_used_as_spec(avail_spec)]
1733    pub fn avail(&self) -> usize {
1734        self.end.addr() - self.cursor.addr()
1735    }
1736
1737    /// Returns the cursor pointer, which refers to the address of the next byte to write.
1738    pub fn cursor(&self) -> VirtPtr {
1739        self.cursor
1740    }
1741
1742    /// Returns if it has available space to write.
1743    #[verus_spec(
1744        requires
1745            self.inv(),
1746    )]
1747    pub fn has_avail(&self) -> bool {
1748        self.avail() > 0
1749    }
1750
1751    /// Limits the length of available space.
1752    ///
1753    /// This method ensures the post-condition `self.avail() <= max_avail`.
1754    #[verus_spec(r =>
1755        requires
1756            old(self).inv(),
1757        ensures
1758            r.inv(),
1759            r.avail_spec() <= max_avail,
1760            r.avail_spec() <= old(self).avail_spec(),
1761            r.cursor == old(self).cursor,
1762            r.ghost_id == old(self).ghost_id,
1763    )]
1764    pub fn limit(&mut self, max_avail: usize) -> &mut Self {
1765        if max_avail < self.avail() {
1766            self.end = self.cursor.wrapping_add(max_avail);
1767        }
1768        self
1769    }
1770
1771    /// Skips the first `nbytes` of available space.
1772    ///
1773    /// The length of available space is decreased accordingly.
1774    ///
1775    /// # Panics
1776    ///
1777    /// If `nbytes` is greater than `self.avail()`, then the method panics.
1778    #[verus_spec(r =>
1779        requires
1780            old(self).inv(),
1781            nbytes <= old(self).avail_spec(),
1782        ensures
1783            r.inv(),
1784            r.cursor.vaddr == old(self).cursor.vaddr + nbytes,
1785            r.avail_spec() == old(self).avail_spec() - nbytes,
1786            r.end == old(self).end,
1787            r.ghost_id == old(self).ghost_id,
1788    )]
1789    pub fn skip(&mut self, nbytes: usize) -> &mut Self {
1790        assert!(nbytes <= self.avail());
1791        self.cursor = self.cursor.wrapping_add(nbytes);
1792        self
1793    }
1794}
1795
1796#[verus_verify]
1797impl<'a> VmWriter<'a, Fallible> {
1798    /// Constructs a [`VmWriter`] from a pointer and a length, which represents
1799    /// a memory range in USER space.
1800    ///
1801    /// # Verified Properties
1802    /// ## Preconditions
1803    /// - `ptr` must satisfy [`VirtPtr::inv`].
1804    /// ## Postconditions
1805    /// - The returned [`VmWriter`] satisfies its invariant.
1806    /// - The returned writer is associated with a [`VmIoOwner`] that satisfies both [`VmIoOwner::inv`]
1807    ///   and [`VmWriter::wf`].
1808    /// - The owner has the same range as `ptr`, has no memory view yet, and is marked as user-space.
1809    #[verus_spec(r =>
1810        with
1811            Ghost(id): Ghost<nat>,
1812                -> owner: Tracked<VmIoOwner>,
1813        ensures
1814            r.inv_wf(),
1815            owner@.id == id,
1816            owner@.range == ptr.range@,
1817            owner@.mem_view is None,
1818            !owner@.is_kernel,
1819            r.cursor == ptr,
1820            r.end == ptr.wrapping_add_spec(len),
1821            r.end.range@ == ptr.range@,
1822            ptr.inv() && ptr.range@.start == ptr.vaddr
1823                && len == ptr.range@.end - ptr.range@.start ==> {
1824                &&& r.inv()
1825                &&& owner@.inv()
1826                &&& r.wf(owner@)
1827            },
1828    )]
1829    pub unsafe fn from_user_space(ptr: VirtPtr, len: usize) -> Self {
1830        let tracked owner = VmIoOwner {
1831            id,
1832            range: ptr.range@,
1833            is_fallible: true,
1834            is_kernel: false,
1835            mem_view: None,
1836        };
1837        proof_with!(|= Tracked(owner));
1838        Self { ghost_id: Ghost(id), cursor: ptr, end: ptr.wrapping_add(len), phantom: PhantomData }
1839    }
1840
1841    /// Writes a value of `Pod` type to user space.
1842    ///
1843    /// If the underlying memory access faults during the write, the cursor
1844    /// is rolled back to its starting position before returning `Err`.
1845    ///
1846    /// # Verified Properties
1847    /// ## Postconditions
1848    /// - On success, the cursor advances by `size_of::<T>()`.
1849    /// - On error, the cursor is at its original position (writer state preserved).
1850    #[verus_spec(r =>
1851        requires
1852            old(self).inv(),
1853        ensures
1854            final(self).inv(),
1855            final(self).end == old(self).end,
1856            final(self).ghost_id == old(self).ghost_id,
1857            final(self).cursor.range == old(self).cursor.range,
1858            r is Err ==> *final(self) == *old(self),
1859    )]
1860    pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> {
1861        let len = core::mem::size_of::<T>();
1862        if self.avail() < len {
1863            return Err(Error::InvalidArgs);
1864        }
1865        proof_decl! {
1866            let tracked mut reader_owner_inner: VmIoOwner;
1867        }
1868        #[verus_spec(with => Tracked(reader_owner_inner))]
1869        let mut reader = VmReader::from(new_val.as_bytes());
1870        match self.write_fallible(&mut reader) {
1871            Ok(_) => Ok(()),
1872            Err((err, copied_len)) => {
1873                self.cursor = self.cursor.sub(copied_len);
1874                Err(err)
1875            },
1876        }
1877    }
1878
1879    /// Writes `len` zeros to the target memory.
1880    ///
1881    /// This method attempts to fill up to `len` bytes with zeros. If the
1882    /// available memory from the current cursor position is less than `len`,
1883    /// it will only fill the available space.
1884    ///
1885    /// If the memory write failed due to an unresolvable page fault, this
1886    /// method will return `Err` with the length set so far.
1887    #[verus_spec(r =>
1888        requires
1889            old(self).inv(),
1890        ensures
1891            final(self).inv(),
1892            final(self).end == old(self).end,
1893            final(self).ghost_id == old(self).ghost_id,
1894            final(self).cursor.range == old(self).cursor.range,
1895            final(self).cursor.vaddr >= old(self).cursor.vaddr,
1896            final(self).cursor.vaddr <= old(self).end.vaddr,
1897            match r {
1898                Ok(n) => {
1899                    &&& n <= len
1900                    &&& n <= old(self).avail_spec()
1901                    &&& final(self).cursor.vaddr == old(self).cursor.vaddr + n
1902                },
1903                Err((_, n)) => {
1904                    &&& n <= len
1905                    &&& n <= old(self).avail_spec()
1906                    &&& final(self).cursor.vaddr == old(self).cursor.vaddr + n
1907                },
1908            }
1909    )]
1910    pub fn fill_zeros(&mut self, len: usize) -> core::result::Result<usize, (Error, usize)> {
1911        let len_to_set = self.avail().min(len);
1912        if len_to_set == 0 {
1913            return Ok(0);
1914        }
1915        // SAFETY: The destination is a subset of the memory range specified by
1916        // the current writer, so it is either valid for writing or in user space.
1917
1918        let set_len = unsafe { memset_fallible(self.cursor, 0u8, len_to_set) };
1919        self.cursor = self.cursor.wrapping_add(set_len);
1920
1921        if set_len < len_to_set {
1922            Err((Error::PageFault, set_len))
1923        } else {
1924            Ok(len_to_set)
1925        }
1926    }
1927}
1928
1929/// Extension trait for byte slices that produces a [`VirtPtr`] covering the
1930/// slice's bytes. Mirrors the role of [`<[u8]>::as_ptr`] but in our verified
1931/// pointer model.
1932pub trait AsVirtPtr {
1933    fn as_virt_ptr(&self) -> VirtPtr;
1934}
1935
1936#[verus_verify]
1937impl AsVirtPtr for [u8] {
1938    #[verus_spec(r =>
1939        ensures
1940            r.inv(),
1941            r.range@.start == r.vaddr,
1942            r.range@.end - r.range@.start == self.len(),
1943            r.vaddr == ::vstd_extra::external::slice::as_ptr_spec(self) as usize,
1944    )]
1945    fn as_virt_ptr(&self) -> VirtPtr {
1946        let addr = self.as_ptr() as usize;
1947        let len = self.len();
1948        proof {
1949            ::vstd_extra::external::slice::axiom_slice_addr_no_overflow(self);
1950        }
1951        let ghost range: Range<usize> = addr..(addr + len) as usize;
1952        VirtPtr { vaddr: addr, range: Ghost(range) }
1953    }
1954}
1955
1956/*
1957// Original From<&mut [u8]> for VmWriter (replaced by pub fn from during Verus migration):
1958impl<'a> From<&'a mut [u8]> for VmWriter<'a, Infallible> {
1959    fn from(slice: &'a mut [u8]) -> Self {
1960        unsafe { Self::from_kernel_space(slice.as_mut_ptr(), slice.len()) }
1961    }
1962}
1963*/
1964
1965#[verus_verify]
1966impl<'a> VmWriter<'a, Infallible> {
1967    /// Constructs a [`VmWriter<'a, Infallible>`] from a mutable byte slice.
1968    ///
1969    /// The slice's address establishes the writer's cursor range; the kernel-space
1970    /// trust ([`axiom_slice_in_kernel`] + [`axiom_kernel_mem_view`] via
1971    /// [`Self::from_kernel_space`]) supplies the tracked [`VmIoOwner`] with its
1972    /// `WriteView`. Callers receive the owner via `proof_with!`.
1973    ///
1974    /// # Safety
1975    ///
1976    /// The slice's memory must be valid for writes during `'a` — guaranteed by
1977    /// Rust's borrow checker for `&'a mut [u8]`.
1978    #[verus_spec(r =>
1979        with
1980            -> owner: Tracked<VmIoOwner>,
1981        ensures
1982            r.inv(),
1983            owner@.inv(),
1984            r.wf(*owner),
1985            owner@.has_write_view(),
1986            r.cursor.range == owner@.range,
1987            owner@.range.end - owner@.range.start == old(slice).len(),
1988    )]
1989    pub fn from(slice: &'a mut [u8]) -> Self {
1990        // SAFETY:
1991        // - The memory range points to typed memory.
1992        // - The validity requirements for write accesses are met because the pointer is converted
1993        //   from a mutable reference that outlives the lifetime `'a`.
1994        // - The type, i.e., the `u8` slice, is plain-old-data.
1995        let shared: &[u8] = &*slice;
1996        proof {
1997            axiom_slice_in_kernel(shared);
1998        }
1999        let ptr = shared.as_virt_ptr();
2000        let len = shared.len();
2001        proof_decl! {
2002            let tracked mut owner_inner: VmIoOwner;
2003        }
2004        let writer = unsafe {
2005            #[verus_spec(with Ghost(0nat), Tracked(false) => Tracked(owner_inner))]
2006            Self::from_kernel_space(ptr, len)
2007        };
2008        proof_with!(|= Tracked(owner_inner));
2009        writer
2010    }
2011}
2012
2013/*
2014// Original From<&[u8]> for VmReader (replaced by pub fn from during Verus migration):
2015impl<'a> From<&'a [u8]> for VmReader<'a, Infallible> {
2016    fn from(slice: &'a [u8]) -> Self {
2017        unsafe { Self::from_kernel_space(slice.as_ptr(), slice.len()) }
2018    }
2019}
2020*/
2021
2022#[verus_verify]
2023impl<'a> VmReader<'a, Infallible> {
2024    /// Constructs a [`VmReader<'a, Infallible>`] from a shared byte slice.
2025    ///
2026    /// The slice's address establishes the reader's cursor range; the kernel-space
2027    /// trust ([`axiom_slice_in_kernel`] + [`axiom_kernel_mem_view`] via
2028    /// [`Self::from_kernel_space`]) supplies the tracked [`VmIoOwner`] with its
2029    /// initialized `ReadView`. Callers receive the owner via `proof_with!`.
2030    ///
2031    /// # Safety
2032    ///
2033    /// The slice's memory must be valid for reads during `'a` — guaranteed by
2034    /// Rust's borrow checker for `&'a [u8]`.
2035    #[verus_spec(r =>
2036        with
2037            -> owner: Tracked<VmIoOwner>,
2038        ensures
2039            r.inv(),
2040            owner@.inv(),
2041            r.wf(*owner),
2042            owner@.read_view_initialized(),
2043            r.cursor.range == owner@.range,
2044            owner@.range.end - owner@.range.start == slice.len(),
2045    )]
2046    pub fn from(slice: &'a [u8]) -> Self {
2047        // SAFETY:
2048        // - The memory range points to typed memory.
2049        // - The validity requirements for read accesses are met because the pointer is converted
2050        //   from a shared reference that outlives the lifetime `'a`.
2051        // - The type, i.e., the `u8` slice, is plain-old-data.
2052        proof {
2053            axiom_slice_in_kernel(slice);
2054        }
2055        let ptr = slice.as_virt_ptr();
2056        let len = slice.len();
2057        proof_decl! {
2058            let tracked mut owner_inner: VmIoOwner;
2059        }
2060        let reader = unsafe {
2061            #[verus_spec(with Ghost(0nat) => Tracked(owner_inner))]
2062            Self::from_kernel_space(ptr, len)
2063        };
2064        proof_with!(|= Tracked(owner_inner));
2065        reader
2066    }
2067}
2068
2069} // verus!
2070/// Fallible memory read from a `VmWriter`.
2071pub trait FallibleVmRead<F> {
2072    fn read_fallible(
2073        &mut self,
2074        writer: &mut VmWriter<'_, F>,
2075    ) -> core::result::Result<usize, (Error, usize)>;
2076}
2077
2078/// Fallible memory write from a `VmReader`.
2079pub trait FallibleVmWrite<F> {
2080    fn write_fallible(
2081        &mut self,
2082        reader: &mut VmReader<'_, F>,
2083    ) -> core::result::Result<usize, (Error, usize)>;
2084}
2085
2086macro_rules! impl_read_fallible {
2087    ($reader_fallibility:ty, $writer_fallibility:ty) => {
2088        ::vstd::prelude::verus! {
2089        impl<'a> FallibleVmRead<$writer_fallibility> for VmReader<'a, $reader_fallibility> {
2090            #[verus_spec(r =>
2091                requires
2092                    old(self).inv(),
2093                    old(writer).inv(),
2094                ensures
2095                    final(self).end == old(self).end,
2096                    final(self).ghost_id == old(self).ghost_id,
2097                    final(self).cursor.range == old(self).cursor.range,
2098                    final(writer).end == old(writer).end,
2099                    final(writer).ghost_id == old(writer).ghost_id,
2100                    final(writer).cursor.range == old(writer).cursor.range,
2101                    final(self).inv(),
2102                    final(writer).inv(),
2103                    match r {
2104                        Ok(n) => {
2105                            &&& final(self).cursor.vaddr == old(self).cursor.vaddr + n
2106                            &&& final(writer).cursor.vaddr == old(writer).cursor.vaddr + n
2107                            &&& n <= old(self).remain_spec()
2108                            &&& n <= old(writer).avail_spec()
2109                        },
2110                        Err((_, copied_len)) => {
2111                            &&& final(self).cursor.vaddr == old(self).cursor.vaddr + copied_len
2112                            &&& final(writer).cursor.vaddr == old(writer).cursor.vaddr + copied_len
2113                            &&& copied_len <= old(self).remain_spec()
2114                            &&& copied_len <= old(writer).avail_spec()
2115                        },
2116                    }
2117            )]
2118            fn read_fallible(
2119                &mut self,
2120                writer: &mut VmWriter<'_, $writer_fallibility>,
2121            ) -> core::result::Result<usize, (Error, usize)> {
2122                let copy_len = self.remain().min(writer.avail());
2123                if copy_len == 0 {
2124                    return Ok(0);
2125                }
2126
2127                // SAFETY: The source and destination are subsets of memory ranges specified by
2128                // the reader and writer, so they are either valid for reading and writing or in
2129                // user space.
2130                let copied_len = unsafe {
2131                    memcpy_fallible(writer.cursor, self.cursor, copy_len)
2132                };
2133                self.cursor = self.cursor.wrapping_add(copied_len);
2134                writer.cursor = writer.cursor.wrapping_add(copied_len);
2135
2136                if copied_len < copy_len {
2137                    Err((Error::PageFault, copied_len))
2138                } else {
2139                    Ok(copied_len)
2140                }
2141            }
2142        }
2143        } // verus!
2144};
2145}
2146
2147macro_rules! impl_write_fallible {
2148    ($writer_fallibility:ty, $reader_fallibility:ty) => {
2149        ::vstd::prelude::verus! {
2150        impl<'a> FallibleVmWrite<$reader_fallibility> for VmWriter<'a, $writer_fallibility> {
2151            #[verus_spec(r =>
2152                requires
2153                    old(self).inv(),
2154                    old(reader).inv(),
2155                ensures
2156                    final(self).end == old(self).end,
2157                    final(self).ghost_id == old(self).ghost_id,
2158                    final(self).cursor.range == old(self).cursor.range,
2159                    final(reader).end == old(reader).end,
2160                    final(reader).ghost_id == old(reader).ghost_id,
2161                    final(reader).cursor.range == old(reader).cursor.range,
2162                    final(self).inv(),
2163                    final(reader).inv(),
2164                    match r {
2165                        Ok(n) => {
2166                            &&& final(self).cursor.vaddr == old(self).cursor.vaddr + n
2167                            &&& final(reader).cursor.vaddr == old(reader).cursor.vaddr + n
2168                            &&& n <= old(self).avail_spec()
2169                            &&& n <= old(reader).remain_spec()
2170                        },
2171                        Err((_, copied_len)) => {
2172                            &&& final(self).cursor.vaddr == old(self).cursor.vaddr + copied_len
2173                            &&& final(reader).cursor.vaddr == old(reader).cursor.vaddr + copied_len
2174                            &&& copied_len <= old(self).avail_spec()
2175                            &&& copied_len <= old(reader).remain_spec()
2176                        },
2177                    }
2178            )]
2179            fn write_fallible(
2180                &mut self,
2181                reader: &mut VmReader<'_, $reader_fallibility>,
2182            ) -> core::result::Result<usize, (Error, usize)> {
2183                reader.read_fallible(self)
2184            }
2185        }
2186        } // verus!
2187};
2188}
2189
2190impl_read_fallible!(Fallible, Infallible);
2191impl_read_fallible!(Fallible, Fallible);
2192impl_read_fallible!(Infallible, Fallible);
2193impl_write_fallible!(Fallible, Infallible);
2194impl_write_fallible!(Fallible, Fallible);
2195impl_write_fallible!(Infallible, Fallible);
2196
2197verus! {
2198
2199/// A marker trait for POD types that can be read or written with one instruction.
2200///
2201/// This trait is mostly a hint, since it's safe and can be implemented for _any_ POD type. If it
2202/// is implemented for a type that cannot be read or written with a single instruction, calling
2203/// `read_once`/`write_once` will lead to a failed compile-time assertion.
2204pub trait PodOnce: Pod {
2205
2206}
2207
2208#[cfg(any(
2209    target_arch = "x86_64",
2210    target_arch = "riscv64",
2211    target_arch = "loongarch64"
2212))]
2213mod pod_once_impls {
2214    use super::PodOnce;
2215
2216    impl PodOnce for u8 {
2217
2218    }
2219
2220    impl PodOnce for u16 {
2221
2222    }
2223
2224    impl PodOnce for u32 {
2225
2226    }
2227
2228    impl PodOnce for u64 {
2229
2230    }
2231
2232    impl PodOnce for usize {
2233
2234    }
2235
2236    impl PodOnce for i8 {
2237
2238    }
2239
2240    impl PodOnce for i16 {
2241
2242    }
2243
2244    impl PodOnce for i32 {
2245
2246    }
2247
2248    impl PodOnce for i64 {
2249
2250    }
2251
2252    impl PodOnce for isize {
2253
2254    }
2255
2256    /// Checks whether the memory operation created by `ptr::read_volatile` and
2257    /// `ptr::write_volatile` doesn't tear.
2258    ///
2259    /// Note that the Rust documentation makes no such guarantee, and even the wording in the LLVM
2260    /// LangRef is ambiguous. But this is unlikely to break in practice because the Linux kernel
2261    /// also uses "volatile" semantics to implement `READ_ONCE`/`WRITE_ONCE`.
2262    pub(super) const fn is_non_tearing<T>() -> bool {
2263        let size = core::mem::size_of::<T>();
2264
2265        size == 1 || size == 2 || size == 4 || size == 8
2266    }
2267
2268}
2269
2270} // verus!