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