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