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