Skip to main content

ostd/mm/
io.rs

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