Skip to main content

ostd/mm/io/
mod.rs

1// SPDX-License-Identifier: MPL-2.0
2
3//! Abstractions for reading and writing virtual memory (VM) objects.
4//!
5//! # Safety
6//!
7//! The core virtual memory (VM) access APIs provided by this module are [`VmReader`] and
8//! [`VmWriter`], which allow for writing to or reading from a region of memory _safely_.
9//! `VmReader` and `VmWriter` objects can be constructed from memory regions of either typed memory
10//! (e.g., `&[u8]`) or untyped memory (e.g, [`UFrame`]). Behind the scene, `VmReader` and `VmWriter`
11//! must be constructed via their [`from_user_space`] and [`from_kernel_space`] methods, whose
12//! safety depends on whether the given memory regions are _valid_ or not.
13//!
14//! [`UFrame`]: crate::mm::UFrame
15//! [`from_user_space`]: `VmReader::from_user_space`
16//! [`from_kernel_space`]: `VmReader::from_kernel_space`
17//!
18//! Here is a list of conditions for memory regions to be considered valid:
19//!
20//! - The memory region as a whole must be either typed or untyped memory, not both typed and
21//!   untyped.
22//!
23//! - If the memory region is typed, we require that:
24//!   - the [validity requirements] from the official Rust documentation must be met, and
25//!   - the type of the memory region (which must exist since the memory is typed) must be
26//!     plain-old-data, so that the writer can fill it with arbitrary data safely.
27//!
28//! [validity requirements]: core::ptr#safety
29//!
30//! - If the memory region is untyped, we require that:
31//!   - the underlying pages must remain alive while the validity requirements are in effect, and
32//!   - the kernel must access the memory region using only the APIs provided in this module, but
33//!     external accesses from hardware devices or user programs do not count.
34//!
35//! We have the last requirement for untyped memory to be valid because the safety interaction with
36//! other ways to access the memory region (e.g., atomic/volatile memory loads/stores) is not
37//! currently specified. Tis may be relaxed in the future, if appropriate and necessary.
38//!
39//! Note that data races on untyped memory are explicitly allowed (since pages can be mapped to
40//! user space, making it impossible to avoid data races). However, they may produce erroneous
41//! results, such as unexpected bytes being copied, but do not cause soundness problems.
42
43pub(crate) mod copy;
44pub mod util;
45
46use core::{marker::PhantomData, mem::MaybeUninit};
47
48use ostd_pod::Pod;
49
50use self::copy::{memcpy, memset};
51use crate::{
52    Error,
53    arch::mm::{__atomic_cmpxchg_fallible, __atomic_load_fallible},
54    mm::kspace::{KERNEL_BASE_VADDR, KERNEL_END_VADDR},
55    prelude::*,
56};
57
58/// A trait that enables reading/writing data from/to a VM object,
59/// e.g., [`USegment`], [`Vec<UFrame>`] and [`UFrame`].
60///
61/// # Concurrency
62///
63/// The methods may be executed by multiple concurrent reader and writer
64/// threads. In this case, if the results of concurrent reads or writes
65/// desire predictability or atomicity, the users should add extra mechanism
66/// for such properties.
67///
68/// [`USegment`]: crate::mm::USegment
69/// [`UFrame`]: crate::mm::UFrame
70pub trait VmIo {
71    /// Reads requested data at a specified offset into a given `VmWriter`.
72    ///
73    /// # No short reads
74    ///
75    /// On success, the `writer` must be written with the requested data
76    /// completely. If, for any reason, the requested data is only partially
77    /// available, then the method shall return an error.
78    fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>;
79
80    /// Reads a specified number of bytes at a specified offset into a given buffer.
81    ///
82    /// # No short reads
83    ///
84    /// Similar to [`read`].
85    ///
86    /// [`read`]: VmIo::read
87    fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
88        let mut writer = VmWriter::from(buf).to_fallible();
89        self.read(offset, &mut writer)
90    }
91
92    /// Reads a value of a specified type at a specified offset.
93    fn read_val<T: Pod>(&self, offset: usize) -> Result<T> {
94        // Why not use `MaybeUninit` for a faster implementation?
95        //
96        // ```rust
97        // let mut val: MaybeUninit<T> = MaybeUninit::uninit();
98        // let writer = unsafe {
99        //     VmWriter::from_kernel_space(val.as_mut_ptr().cast(), size_of::<T>())
100        // };
101        // self.read(offset, &mut writer.to_fallible())?;
102        // Ok(unsafe { val.assume_init() })
103        // ```
104        //
105        // The above implementation avoids initializing `val` upfront,
106        // so it is more efficient than our actual implementation.
107        // Unfortunately, it is unsound.
108        // This is because the `read` method,
109        // which could be implemented outside OSTD and thus is untrusted,
110        // may not really initialize the bits of `val` at all!
111
112        let mut val = T::new_zeroed();
113        self.read_bytes(offset, val.as_mut_bytes())?;
114        Ok(val)
115    }
116
117    /// Reads a slice of a specified type at a specified offset.
118    ///
119    /// # No short reads
120    ///
121    /// Similar to [`read`].
122    ///
123    /// [`read`]: VmIo::read
124    fn read_slice<T: Pod>(&self, offset: usize, slice: &mut [T]) -> Result<()> {
125        let len_in_bytes = size_of_val(slice);
126        let ptr = slice as *mut [T] as *mut u8;
127        // SAFETY: the slice can be transmuted to a writable byte slice since the elements
128        // are all Plain-Old-Data (Pod) types.
129        let buf = unsafe { core::slice::from_raw_parts_mut(ptr, len_in_bytes) };
130        self.read_bytes(offset, buf)
131    }
132
133    /// Writes all data from a given `VmReader` at a specified offset.
134    ///
135    /// # No short writes
136    ///
137    /// On success, the data from the `reader` must be read to the VM object entirely.
138    /// If, for any reason, the input data can only be written partially,
139    /// then the method shall return an error.
140    fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>;
141
142    /// Writes a specified number of bytes from a given buffer at a specified offset.
143    ///
144    /// # No short writes
145    ///
146    /// Similar to [`write`].
147    ///
148    /// [`write`]: VmIo::write
149    fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
150        let mut reader = VmReader::from(buf).to_fallible();
151        self.write(offset, &mut reader)
152    }
153
154    /// Writes a value of a specified type at a specified offset.
155    fn write_val<T: Pod>(&self, offset: usize, new_val: &T) -> Result<()> {
156        self.write_bytes(offset, new_val.as_bytes())?;
157        Ok(())
158    }
159
160    /// Writes a slice of a specified type at a specified offset.
161    ///
162    /// # No short write
163    ///
164    /// Similar to [`write`].
165    ///
166    /// [`write`]: VmIo::write
167    fn write_slice<T: Pod>(&self, offset: usize, slice: &[T]) -> Result<()> {
168        let len_in_bytes = size_of_val(slice);
169        let ptr = slice as *const [T] as *const u8;
170        // SAFETY: the slice can be transmuted to a readable byte slice since the elements
171        // are all Plain-Old-Data (Pod) types.
172        let buf = unsafe { core::slice::from_raw_parts(ptr, len_in_bytes) };
173        self.write_bytes(offset, buf)
174    }
175}
176
177/// A trait that enables filling bytes (e.g., filling zeros) to a VM object.
178pub trait VmIoFill {
179    /// Writes `len` zeros at a specified offset.
180    ///
181    /// Unlike the methods in [`VmIo`], this method allows for short writes because `len` can be
182    /// effectively unbounded. However, if not all bytes can be written successfully, an `Err(_)`
183    /// will be returned with the error and the number of zeros that have been written thus far.
184    ///
185    /// # A slow, general implementation
186    ///
187    /// Suppose that [`VmIo`] has already been implemented for the type,
188    /// this method can be implemented in the following general way.
189    ///
190    /// ```rust
191    /// fn fill_zeros(&self, offset: usize, len: usize) -> Result<(), (Error, usize)> {
192    ///     for i in 0..len {
193    ///         match self.write_slice(offset + i, &[0u8]) {
194    ///             Ok(()) => continue,
195    ///             Err(err) => return Err((err, i)),
196    ///         }
197    ///     }
198    ///     Ok(())
199    /// }
200    /// ```
201    ///
202    /// But we choose not to provide a general, default implementation
203    /// because doing so would make it too easy for a concrete type of `VmIoFill`
204    /// to settle with a slower implementation for such a performance-sensitive operation.
205    fn fill_zeros(&self, offset: usize, len: usize) -> Result<(), (Error, usize)>;
206}
207
208/// A trait that enables reading/writing data from/to a VM object using one non-tearing memory
209/// load/store.
210///
211/// See also [`VmIo`], which enables reading/writing data from/to a VM object without the guarantee
212/// of using one non-tearing memory load/store.
213pub trait VmIoOnce {
214    /// Reads a value of the `PodOnce` type at the specified offset using one non-tearing memory
215    /// load.
216    ///
217    /// Except that the offset is specified explicitly, the semantics of this method is the same as
218    /// [`VmReader::read_once`].
219    fn read_once<T: PodOnce>(&self, offset: usize) -> Result<T>;
220
221    /// Writes a value of the `PodOnce` type at the specified offset using one non-tearing memory
222    /// store.
223    ///
224    /// Except that the offset is specified explicitly, the semantics of this method is the same as
225    /// [`VmWriter::write_once`].
226    fn write_once<T: PodOnce>(&self, offset: usize, new_val: &T) -> Result<()>;
227}
228
229/// A marker type used for _fallible_ memory,
230/// where memory access _might_ trigger page faults.
231///
232/// The most prominent example of fallible memory is user virtual memory.
233///
234/// By definition, infallible memory is a subset of fallible memory.
235/// As a consequence, any code that intends to work with fallible memory
236/// should work for both user virtual memory and kernel virtual memory.
237///
238/// [`VmReader`] and [`VmWriter`] types use this marker type
239/// to indicate the property of the underlying memory.
240pub enum Fallible {}
241
242/// A marker type used for _infallible_ memory,
243/// where memory access is valid and won't trigger page faults.
244///
245/// The most prominent example of infallible memory is kernel virtual memory
246/// (at least for the part where Rust code and data reside).
247///
248/// [`VmReader`] and [`VmWriter`] types use this marker type
249/// to indicate the property of the underlying memory.
250pub enum Infallible {}
251
252/// A marker type for I/O memory regions.
253///
254/// This marker is used by [`memcpy`] and [`memset`]
255/// to indicate that a source or destination operand
256/// resides in I/O memory (MMIO).
257///
258/// Unlike [`Fallible`] and [`Infallible`],
259/// `Io` cannot statically determine
260/// whether a memory access will fault:
261/// MMIO fallibility is platform-dependent.
262/// For example, on Intel TDX
263/// every MMIO access triggers a #VE exception,
264/// whereas on a non-CVM x86 host
265/// the same access completes without faulting.
266pub(crate) enum Io {}
267
268/// Fallible memory read from a `VmWriter`.
269pub trait FallibleVmRead<F> {
270    /// Reads all data into the writer until one of the three conditions is met:
271    /// 1. The reader has no remaining data.
272    /// 2. The writer has no available space.
273    /// 3. The reader/writer encounters some error.
274    ///
275    /// On success, the number of bytes read is returned;
276    /// On error, both the error and the number of bytes read so far are returned.
277    fn read_fallible(&mut self, writer: &mut VmWriter<'_, F>) -> Result<usize, (Error, usize)>;
278}
279
280/// Fallible memory write from a `VmReader`.
281pub trait FallibleVmWrite<F> {
282    /// Writes all data from the reader until one of the three conditions is met:
283    /// 1. The reader has no remaining data.
284    /// 2. The writer has no available space.
285    /// 3. The reader/writer encounters some error.
286    ///
287    /// On success, the number of bytes written is returned;
288    /// On error, both the error and the number of bytes written so far are returned.
289    fn write_fallible(&mut self, reader: &mut VmReader<'_, F>) -> Result<usize, (Error, usize)>;
290}
291
292/// `VmReader` is a reader for reading data from a contiguous range of memory.
293///
294/// The memory range read by `VmReader` can be in either kernel space or user space.
295/// When the operating range is in kernel space, the memory within that range
296/// is guaranteed to be valid, and the corresponding memory reads are infallible.
297/// When the operating range is in user space, it is ensured that the page table of
298/// the process creating the `VmReader` is active for the duration of `'a`,
299/// and the corresponding memory reads are considered fallible.
300///
301/// When perform reading with a `VmWriter`, if one of them represents typed memory,
302/// it can ensure that the reading range in this reader and writing range in the
303/// writer are not overlapped.
304///
305/// NOTE: The overlap mentioned above is at both the virtual address level
306/// and physical address level. There is not guarantee for the operation results
307/// of `VmReader` and `VmWriter` in overlapping untyped addresses, and it is
308/// the user's responsibility to handle this situation.
309pub struct VmReader<'a, Fallibility = Fallible> {
310    cursor: *const u8,
311    end: *const u8,
312    phantom: PhantomData<(&'a [u8], Fallibility)>,
313}
314
315// `Clone` can be implemented for `VmReader`
316// because it either points to untyped memory or represents immutable references.
317// Note that we cannot implement `Clone` for `VmWriter`
318// because it can represent mutable references, which must remain exclusive.
319impl<Fallibility> Clone for VmReader<'_, Fallibility> {
320    fn clone(&self) -> Self {
321        Self {
322            cursor: self.cursor,
323            end: self.end,
324            phantom: PhantomData,
325        }
326    }
327}
328
329macro_rules! impl_read_fallible {
330    ($reader_fallibility:ty, $writer_fallibility:ty) => {
331        impl<'a> FallibleVmRead<$writer_fallibility> for VmReader<'a, $reader_fallibility> {
332            fn read_fallible(
333                &mut self,
334                writer: &mut VmWriter<'_, $writer_fallibility>,
335            ) -> Result<usize, (Error, usize)> {
336                let copy_len = self.remain().min(writer.avail());
337                if copy_len == 0 {
338                    return Ok(0);
339                }
340
341                // SAFETY: The source and destination are subsets of memory ranges specified by
342                // the reader and writer, so they are either valid for reading and writing or in
343                // user space.
344                let copied_len = unsafe {
345                    memcpy::<$writer_fallibility, $reader_fallibility>(
346                        writer.cursor,
347                        self.cursor,
348                        copy_len,
349                    )
350                };
351                self.cursor = self.cursor.wrapping_add(copied_len);
352                writer.cursor = writer.cursor.wrapping_add(copied_len);
353
354                if copied_len < copy_len {
355                    Err((Error::PageFault, copied_len))
356                } else {
357                    Ok(copied_len)
358                }
359            }
360        }
361    };
362}
363
364macro_rules! impl_write_fallible {
365    ($writer_fallibility:ty, $reader_fallibility:ty) => {
366        impl<'a> FallibleVmWrite<$reader_fallibility> for VmWriter<'a, $writer_fallibility> {
367            fn write_fallible(
368                &mut self,
369                reader: &mut VmReader<'_, $reader_fallibility>,
370            ) -> Result<usize, (Error, usize)> {
371                reader.read_fallible(self)
372            }
373        }
374    };
375}
376
377impl_read_fallible!(Fallible, Infallible);
378impl_read_fallible!(Fallible, Fallible);
379impl_read_fallible!(Infallible, Fallible);
380impl_write_fallible!(Fallible, Infallible);
381impl_write_fallible!(Fallible, Fallible);
382impl_write_fallible!(Infallible, Fallible);
383
384impl<'a> VmReader<'a, Infallible> {
385    /// Constructs a `VmReader` from a pointer and a length, which represents
386    /// a memory range in kernel space.
387    ///
388    /// # Safety
389    ///
390    /// `ptr` must be [valid] for reads of `len` bytes during the entire lifetime `a`.
391    ///
392    /// [valid]: crate::mm::io#safety
393    pub unsafe fn from_kernel_space(ptr: *const u8, len: usize) -> Self {
394        // Rust is allowed to give the reference to a zero-sized object a very small address,
395        // falling out of the kernel virtual address space range.
396        // So when `len` is zero, we should not and need not to check `ptr`.
397        debug_assert!(len == 0 || KERNEL_BASE_VADDR <= ptr.addr());
398        debug_assert!(len == 0 || ptr.addr().checked_add(len).unwrap() <= KERNEL_END_VADDR);
399
400        Self {
401            cursor: ptr,
402            end: ptr.wrapping_add(len),
403            phantom: PhantomData,
404        }
405    }
406
407    /// Reads all data into the writer until one of the two conditions is met:
408    /// 1. The reader has no remaining data.
409    /// 2. The writer has no available space.
410    ///
411    /// Returns the number of bytes read.
412    pub fn read(&mut self, writer: &mut VmWriter<'_, Infallible>) -> usize {
413        let copy_len = self.remain().min(writer.avail());
414        if copy_len == 0 {
415            return 0;
416        }
417
418        // SAFETY: The source and destination are subsets of memory ranges specified by the reader
419        // and writer, so they are valid for reading and writing.
420        unsafe { memcpy::<Infallible, Infallible>(writer.cursor, self.cursor, copy_len) };
421        self.cursor = self.cursor.wrapping_add(copy_len);
422        writer.cursor = writer.cursor.wrapping_add(copy_len);
423
424        copy_len
425    }
426
427    /// Reads a value of `Pod` type.
428    ///
429    /// If the length of the `Pod` type exceeds `self.remain()`,
430    /// this method will return `Err`.
431    pub fn read_val<T: Pod>(&mut self) -> Result<T> {
432        if self.remain() < size_of::<T>() {
433            return Err(Error::InvalidArgs);
434        }
435
436        let cursor = self.cursor.cast::<T>();
437
438        // SAFETY: We have checked that the number of bytes remaining is at least the size of `T`.
439        // All other safety requirements are the same as for `Self::read`.
440        let val = unsafe { core::intrinsics::unaligned_volatile_load(cursor) };
441        self.cursor = self.cursor.wrapping_add(size_of::<T>());
442
443        Ok(val)
444    }
445
446    /// Reads a value of the `PodOnce` type using one non-tearing memory load.
447    ///
448    /// If the length of the `PodOnce` type exceeds `self.remain()`, this method will return `Err`.
449    ///
450    /// This method will not compile if the `Pod` type is too large for the current architecture
451    /// and the operation must be tear into multiple memory loads.
452    ///
453    /// # Panics
454    ///
455    /// This method will panic if the current position of the reader does not meet the alignment
456    /// requirements of type `T`.
457    pub fn read_once<T: PodOnce>(&mut self) -> Result<T> {
458        if self.remain() < size_of::<T>() {
459            return Err(Error::InvalidArgs);
460        }
461
462        let cursor = self.cursor.cast::<T>();
463        assert!(cursor.is_aligned());
464
465        const { assert!(pod_once_impls::is_non_tearing::<T>()) };
466
467        // SAFETY: We have checked that the number of bytes remaining is at least the size of `T`
468        // and that the cursor is properly aligned with respect to the type `T`. All other safety
469        // requirements are the same as for `Self::read`.
470        let val = unsafe { cursor.read_volatile() };
471        self.cursor = self.cursor.wrapping_add(size_of::<T>());
472
473        Ok(val)
474    }
475
476    // Currently, there are no volatile atomic operations in `core::intrinsics`. Therefore, we do
477    // not provide an infallible implementation of `VmReader::atomic_load`.
478
479    /// Converts to a fallible reader.
480    pub fn to_fallible(self) -> VmReader<'a, Fallible> {
481        // It is safe to construct a fallible reader since an infallible reader covers the
482        // capabilities of a fallible reader.
483        VmReader {
484            cursor: self.cursor,
485            end: self.end,
486            phantom: PhantomData,
487        }
488    }
489}
490
491impl VmReader<'_, Fallible> {
492    /// Constructs a `VmReader` from a pointer and a length, which represents
493    /// a memory range in user space.
494    ///
495    /// # Safety
496    ///
497    /// The virtual address range `ptr..ptr + len` must be in user space.
498    pub unsafe fn from_user_space(ptr: *const u8, len: usize) -> Self {
499        debug_assert!(super::is_in_user_space(ptr.addr(), len));
500
501        Self {
502            cursor: ptr,
503            end: ptr.wrapping_add(len),
504            phantom: PhantomData,
505        }
506    }
507
508    /// Reads a value of `Pod` type.
509    ///
510    /// If the length of the `Pod` type exceeds `self.remain()`,
511    /// or the value can not be read completely,
512    /// this method will return `Err`.
513    ///
514    /// If the memory read failed, this method will return `Err`
515    /// and the current reader's cursor remains pointing to
516    /// the original starting position.
517    pub fn read_val<T: Pod>(&mut self) -> Result<T> {
518        if self.remain() < size_of::<T>() {
519            return Err(Error::InvalidArgs);
520        }
521
522        let mut val = MaybeUninit::<T>::uninit();
523
524        // SAFETY:
525        // - The memory range points to typed memory.
526        // - The validity requirements for write accesses are met because the pointer is converted
527        //   from a mutable pointer where the underlying storage outlives the temporary lifetime
528        //   and no other Rust references to the same storage exist during the lifetime.
529        // - The type, i.e., `T`, is plain-old-data.
530        let mut writer =
531            unsafe { VmWriter::from_kernel_space(val.as_mut_ptr().cast(), size_of::<T>()) };
532        self.read_fallible(&mut writer)
533            .map_err(|(err, copied_len)| {
534                // The `copied_len` is the number of bytes read so far.
535                // So the `cursor` can be moved back to the original position.
536                self.cursor = self.cursor.wrapping_sub(copied_len);
537                err
538            })?;
539        debug_assert!(!writer.has_avail());
540
541        // SAFETY:
542        // - `self.read_fallible` has initialized all the bytes in `val`.
543        // - The type is plain-old-data.
544        let val_inited = unsafe { val.assume_init() };
545        Ok(val_inited)
546    }
547
548    /// Atomically loads a `PodAtomic` value.
549    ///
550    /// Regardless of whether it is successful, the cursor of the reader will not move.
551    ///
552    /// This method only guarantees the atomicity of the specific operation. There are no
553    /// synchronization constraints on other memory accesses. This aligns with the [Relaxed
554    /// ordering](https://en.cppreference.com/w/cpp/atomic/memory_order.html#Relaxed_ordering)
555    /// specified in the C++11 memory model.
556    ///
557    /// This method will fail with errors if
558    ///  1. the remaining space of the reader is less than `size_of::<T>()` bytes, or
559    ///  2. the memory operation fails due to an unresolvable page fault.
560    ///
561    /// # Panics
562    ///
563    /// This method will panic if the memory location is not aligned on an `align_of::<T>()`-byte
564    /// boundary.
565    pub fn atomic_load<T: PodAtomic>(&self) -> Result<T> {
566        if self.remain() < size_of::<T>() {
567            return Err(Error::InvalidArgs);
568        }
569
570        let cursor = self.cursor.cast::<T>();
571        assert!(cursor.is_aligned());
572
573        // SAFETY:
574        // 1. The cursor is either valid for reading or in user space for `size_of::<T>()` bytes.
575        // 2. The cursor is aligned on an `align_of::<T>()`-byte boundary.
576        unsafe { T::atomic_load_fallible(cursor) }
577    }
578}
579
580impl<Fallibility> VmReader<'_, Fallibility> {
581    /// Returns the number of bytes for the remaining data.
582    pub fn remain(&self) -> usize {
583        self.end.addr() - self.cursor.addr()
584    }
585
586    /// Returns the cursor pointer, which refers to the address of the next byte to read.
587    pub fn cursor(&self) -> *const u8 {
588        self.cursor
589    }
590
591    /// Returns if it has remaining data to read.
592    pub fn has_remain(&self) -> bool {
593        self.remain() > 0
594    }
595
596    /// Limits the length of remaining data.
597    ///
598    /// This method ensures the post condition of `self.remain() <= max_remain`.
599    pub fn limit(&mut self, max_remain: usize) -> &mut Self {
600        if max_remain < self.remain() {
601            self.end = self.cursor.wrapping_add(max_remain);
602        }
603
604        self
605    }
606
607    /// Skips the first `nbytes` bytes of data.
608    /// The length of remaining data is decreased accordingly.
609    ///
610    /// # Panics
611    ///
612    /// If `nbytes` is greater than `self.remain()`, then the method panics.
613    pub fn skip(&mut self, nbytes: usize) -> &mut Self {
614        assert!(nbytes <= self.remain());
615        self.cursor = self.cursor.wrapping_add(nbytes);
616
617        self
618    }
619}
620
621impl<'a> From<&'a [u8]> for VmReader<'a, Infallible> {
622    fn from(slice: &'a [u8]) -> Self {
623        // SAFETY:
624        // - The memory range points to typed memory.
625        // - The validity requirements for read accesses are met because the pointer is converted
626        //   from an immutable reference that outlives the lifetime `'a`.
627        // - The type, i.e., the `u8` slice, is plain-old-data.
628        unsafe { Self::from_kernel_space(slice.as_ptr(), slice.len()) }
629    }
630}
631
632/// `VmWriter` is a writer for writing data to a contiguous range of memory.
633///
634/// The memory range write by `VmWriter` can be in either kernel space or user space.
635/// When the operating range is in kernel space, the memory within that range
636/// is guaranteed to be valid, and the corresponding memory writes are infallible.
637/// When the operating range is in user space, it is ensured that the page table of
638/// the process creating the `VmWriter` is active for the duration of `'a`,
639/// and the corresponding memory writes are considered fallible.
640///
641/// When perform writing with a `VmReader`, if one of them represents typed memory,
642/// it can ensure that the writing range in this writer and reading range in the
643/// reader are not overlapped.
644///
645/// NOTE: The overlap mentioned above is at both the virtual address level
646/// and physical address level. There is not guarantee for the operation results
647/// of `VmReader` and `VmWriter` in overlapping untyped addresses, and it is
648/// the user's responsibility to handle this situation.
649pub struct VmWriter<'a, Fallibility = Fallible> {
650    cursor: *mut u8,
651    end: *mut u8,
652    phantom: PhantomData<(&'a mut [u8], Fallibility)>,
653}
654
655impl<'a> VmWriter<'a, Infallible> {
656    /// Constructs a `VmWriter` from a pointer and a length, which represents
657    /// a memory range in kernel space.
658    ///
659    /// # Safety
660    ///
661    /// `ptr` must be [valid] for writes of `len` bytes during the entire lifetime `a`.
662    ///
663    /// [valid]: crate::mm::io#safety
664    pub unsafe fn from_kernel_space(ptr: *mut u8, len: usize) -> Self {
665        // If casting a zero sized slice to a pointer, the pointer may be null
666        // and does not reside in our kernel space range.
667        debug_assert!(len == 0 || KERNEL_BASE_VADDR <= ptr.addr());
668        debug_assert!(len == 0 || ptr.addr().checked_add(len).unwrap() <= KERNEL_END_VADDR);
669
670        Self {
671            cursor: ptr,
672            end: ptr.wrapping_add(len),
673            phantom: PhantomData,
674        }
675    }
676
677    /// Writes all data from the reader until one of the two conditions is met:
678    /// 1. The reader has no remaining data.
679    /// 2. The writer has no available space.
680    ///
681    /// Returns the number of bytes written.
682    pub fn write(&mut self, reader: &mut VmReader<'_, Infallible>) -> usize {
683        reader.read(self)
684    }
685
686    /// Writes a value of `Pod` type.
687    ///
688    /// If the length of the `Pod` type exceeds `self.avail()`,
689    /// this method will return `Err`.
690    pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> {
691        if self.avail() < size_of::<T>() {
692            return Err(Error::InvalidArgs);
693        }
694
695        let cursor = self.cursor.cast::<T>();
696
697        // SAFETY: We have checked that the number of bytes remaining is at least the size of `T`.
698        // All other safety requirements are the same as for `Self::write`.
699        unsafe { core::intrinsics::unaligned_volatile_store(cursor, *new_val) };
700        self.cursor = self.cursor.wrapping_add(size_of::<T>());
701
702        Ok(())
703    }
704
705    /// Writes a value of the `PodOnce` type using one non-tearing memory store.
706    ///
707    /// If the length of the `PodOnce` type exceeds `self.remain()`, this method will return `Err`.
708    ///
709    /// # Panics
710    ///
711    /// This method will panic if the current position of the writer does not meet the alignment
712    /// requirements of type `T`.
713    pub fn write_once<T: PodOnce>(&mut self, new_val: &T) -> Result<()> {
714        if self.avail() < size_of::<T>() {
715            return Err(Error::InvalidArgs);
716        }
717
718        let cursor = self.cursor.cast::<T>();
719        assert!(cursor.is_aligned());
720
721        const { assert!(pod_once_impls::is_non_tearing::<T>()) };
722
723        // SAFETY: We have checked that the number of bytes remaining is at least the size of `T`
724        // and that the cursor is properly aligned with respect to the type `T`. All other safety
725        // requirements are the same as for `Self::write`.
726        unsafe { cursor.write_volatile(*new_val) };
727        self.cursor = self.cursor.wrapping_add(size_of::<T>());
728
729        Ok(())
730    }
731
732    // Currently, there are no volatile atomic operations in `core::intrinsics`. Therefore, we do
733    // not provide an infallible implementation of `VmWriter::atomic_compare_exchange`.
734
735    /// Writes `len` zeros to the target memory.
736    ///
737    /// This method attempts to fill up to `len` bytes with zeros. If the available
738    /// memory from the current cursor position is less than `len`, it will only fill
739    /// the available space.
740    pub fn fill_zeros(&mut self, len: usize) -> usize {
741        let len_to_set = self.avail().min(len);
742        if len_to_set == 0 {
743            return 0;
744        }
745
746        // SAFETY: The destination is a subset of the memory range specified by
747        // the current writer, so it is valid for writing.
748        unsafe { memset::<Infallible>(self.cursor, 0u8, len_to_set) };
749        self.cursor = self.cursor.wrapping_add(len_to_set);
750
751        len_to_set
752    }
753
754    /// Converts to a fallible writer.
755    pub fn to_fallible(self) -> VmWriter<'a, Fallible> {
756        // It is safe to construct a fallible reader since an infallible reader covers the
757        // capabilities of a fallible reader.
758        VmWriter {
759            cursor: self.cursor,
760            end: self.end,
761            phantom: PhantomData,
762        }
763    }
764}
765
766impl VmWriter<'_, Fallible> {
767    /// Constructs a `VmWriter` from a pointer and a length, which represents
768    /// a memory range in user space.
769    ///
770    /// The current context should be consistently associated with valid user space during the
771    /// entire lifetime `'a`. This is for correct semantics and is not a safety requirement.
772    ///
773    /// # Safety
774    ///
775    /// `ptr` must be in user space for `len` bytes.
776    pub unsafe fn from_user_space(ptr: *mut u8, len: usize) -> Self {
777        debug_assert!(super::is_in_user_space(ptr.addr(), len));
778
779        Self {
780            cursor: ptr,
781            end: ptr.wrapping_add(len),
782            phantom: PhantomData,
783        }
784    }
785
786    /// Writes a value of `Pod` type.
787    ///
788    /// If the length of the `Pod` type exceeds `self.avail()`,
789    /// or the value can not be write completely,
790    /// this method will return `Err`.
791    ///
792    /// If the memory write failed, this method will return `Err`
793    /// and the current writer's cursor remains pointing to
794    /// the original starting position.
795    pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> {
796        if self.avail() < size_of::<T>() {
797            return Err(Error::InvalidArgs);
798        }
799
800        let mut reader = VmReader::from(new_val.as_bytes());
801        self.write_fallible(&mut reader)
802            .map_err(|(err, copied_len)| {
803                // The `copied_len` is the number of bytes written so far.
804                // So the `cursor` can be moved back to the original position.
805                self.cursor = self.cursor.wrapping_sub(copied_len);
806                err
807            })?;
808        Ok(())
809    }
810
811    /// Atomically compares and exchanges a `PodAtomic` value.
812    ///
813    /// This method compares `old_val` with the value pointed by `self` and, if they are equal,
814    /// updates it with `new_val`.
815    ///
816    /// The value that was previously in memory will be returned, along with a boolean denoting
817    /// whether the compare-and-exchange succeeds. The caller usually wants to retry if this
818    /// flag is false, passing the most recent value that was returned by this method.
819    ///
820    /// The caller is required to provide a reader which points to the exact same memory location
821    /// to ensure that reading from the memory is allowed.
822    ///
823    /// Regardless of whether it is successful, the cursors of the reader and writer will not move.
824    ///
825    /// This method only guarantees the atomicity of the specific operation. There are no
826    /// synchronization constraints on other memory accesses. This aligns with the [Relaxed
827    /// ordering](https://en.cppreference.com/w/cpp/atomic/memory_order.html#Relaxed_ordering)
828    /// specified in the C++11 memory model.
829    ///
830    /// Since the operation does not involve memory locks, it can't prevent the [ABA
831    /// problem](https://en.wikipedia.org/wiki/ABA_problem).
832    ///
833    /// This method will fail with errors if:
834    ///  1. the remaining space of the reader or the available space of the writer are less than
835    ///     `size_of::<T>()` bytes, or
836    ///  2. the memory operation fails due to an unresolvable page fault.
837    ///
838    /// # Panics
839    ///
840    /// This method will panic if:
841    ///  1. the reader and the writer does not point to the same memory location, or
842    ///  2. the memory location is not aligned on an `align_of::<T>()`-byte boundary.
843    pub fn atomic_compare_exchange<T>(
844        &self,
845        reader: &VmReader,
846        old_val: T,
847        new_val: T,
848    ) -> Result<(T, bool)>
849    where
850        T: PodAtomic + Eq,
851    {
852        if self.avail() < size_of::<T>() || reader.remain() < size_of::<T>() {
853            return Err(Error::InvalidArgs);
854        }
855
856        assert_eq!(self.cursor.cast_const(), reader.cursor);
857
858        let cursor = self.cursor.cast::<T>();
859        assert!(cursor.is_aligned());
860
861        // SAFETY:
862        // 1. The cursor is either valid for reading and writing or in user space for
863        //    `size_of::<T>()` bytes.
864        // 2. The cursor is aligned on an `align_of::<T>()`-byte boundary.
865        let cur_val = unsafe { T::atomic_cmpxchg_fallible(cursor, old_val, new_val)? };
866
867        Ok((cur_val, old_val == cur_val))
868    }
869
870    /// Writes `len` zeros to the target memory.
871    ///
872    /// This method attempts to fill up to `len` bytes with zeros. If the available
873    /// memory from the current cursor position is less than `len`, it will only fill
874    /// the available space.
875    ///
876    /// If the memory write failed due to an unresolvable page fault, this method
877    /// will return `Err` with the length set so far.
878    pub fn fill_zeros(&mut self, len: usize) -> Result<usize, (Error, usize)> {
879        let len_to_set = self.avail().min(len);
880        if len_to_set == 0 {
881            return Ok(0);
882        }
883
884        // SAFETY: The destination is a subset of the memory range specified by
885        // the current writer, so it is either valid for writing or in user space.
886        let set_len = unsafe { memset::<Fallible>(self.cursor, 0u8, len_to_set) };
887        self.cursor = self.cursor.wrapping_add(set_len);
888
889        if set_len < len_to_set {
890            Err((Error::PageFault, set_len))
891        } else {
892            Ok(len_to_set)
893        }
894    }
895}
896
897impl<Fallibility> VmWriter<'_, Fallibility> {
898    /// Returns the number of bytes for the available space.
899    pub fn avail(&self) -> usize {
900        self.end.addr() - self.cursor.addr()
901    }
902
903    /// Returns the cursor pointer, which refers to the address of the next byte to write.
904    pub fn cursor(&self) -> *mut u8 {
905        self.cursor
906    }
907
908    /// Returns if it has available space to write.
909    pub fn has_avail(&self) -> bool {
910        self.avail() > 0
911    }
912
913    /// Limits the length of available space.
914    ///
915    /// This method ensures the post condition of `self.avail() <= max_avail`.
916    pub fn limit(&mut self, max_avail: usize) -> &mut Self {
917        if max_avail < self.avail() {
918            self.end = self.cursor.wrapping_add(max_avail);
919        }
920
921        self
922    }
923
924    /// Skips the first `nbytes` bytes of data.
925    /// The length of available space is decreased accordingly.
926    ///
927    /// # Panics
928    ///
929    /// If `nbytes` is greater than `self.avail()`, then the method panics.
930    pub fn skip(&mut self, nbytes: usize) -> &mut Self {
931        assert!(nbytes <= self.avail());
932        self.cursor = self.cursor.wrapping_add(nbytes);
933
934        self
935    }
936
937    /// Creates a clone of this writer, requiring exclusive access.
938    ///
939    /// This method is analogous to [`Clone::clone`], but takes `&mut self`
940    /// instead of `&self`. The `&mut self` receiver is necessary because
941    /// `VmWriter` cannot safely implement `Clone`:
942    /// the underlying buffer may be a mutable slice,
943    /// and two concurrent writers would violate Rust's aliasing rules.
944    ///
945    /// The returned writer has the same cursor position and limit as `self`.
946    /// Because it borrows `self` mutably,
947    /// the original writer cannot be used until the returned writer is dropped.
948    ///
949    /// Note that writes through the returned writer
950    /// do **not** advance the cursor of the original writer.
951    pub fn clone_exclusive(&mut self) -> VmWriter<'_, Fallibility> {
952        VmWriter {
953            cursor: self.cursor,
954            end: self.end,
955            phantom: PhantomData,
956        }
957    }
958}
959
960impl<'a> From<&'a mut [u8]> for VmWriter<'a, Infallible> {
961    fn from(slice: &'a mut [u8]) -> Self {
962        // SAFETY:
963        // - The memory range points to typed memory.
964        // - The validity requirements for write accesses are met because the pointer is converted
965        //   from a mutable reference that outlives the lifetime `'a`.
966        // - The type, i.e., the `u8` slice, is plain-old-data.
967        unsafe { Self::from_kernel_space(slice.as_mut_ptr(), slice.len()) }
968    }
969}
970
971/// A marker trait for POD types that can be read or written with one instruction.
972///
973/// This trait is mostly a hint, since it's safe and can be implemented for _any_ POD type. If it
974/// is implemented for a type that cannot be read or written with a single instruction, calling
975/// `read_once`/`write_once` will lead to a failed compile-time assertion.
976pub trait PodOnce: Pod {}
977
978#[cfg(any(
979    target_arch = "x86_64",
980    target_arch = "riscv64",
981    target_arch = "loongarch64",
982    target_arch = "aarch64"
983))]
984mod pod_once_impls {
985    use super::PodOnce;
986
987    impl PodOnce for u8 {}
988    impl PodOnce for u16 {}
989    impl PodOnce for u32 {}
990    impl PodOnce for u64 {}
991    impl PodOnce for usize {}
992    impl PodOnce for i8 {}
993    impl PodOnce for i16 {}
994    impl PodOnce for i32 {}
995    impl PodOnce for i64 {}
996    impl PodOnce for isize {}
997
998    /// Checks whether the memory operation created by `ptr::read_volatile` and
999    /// `ptr::write_volatile` doesn't tear.
1000    ///
1001    /// Note that the Rust documentation makes no such guarantee, and even the wording in the LLVM
1002    /// LangRef is ambiguous. But this is unlikely to break in practice because the Linux kernel
1003    /// also uses "volatile" semantics to implement `READ_ONCE`/`WRITE_ONCE`.
1004    pub(super) const fn is_non_tearing<T>() -> bool {
1005        let size = size_of::<T>();
1006
1007        size == 1 || size == 2 || size == 4 || size == 8
1008    }
1009}
1010
1011/// A marker trait for POD types that can be read or written atomically.
1012pub trait PodAtomic: Pod {
1013    /// Atomically loads a value.
1014    /// This function will return errors if encountering an unresolvable page fault.
1015    ///
1016    /// Returns the loaded value.
1017    ///
1018    /// # Safety
1019    ///
1020    /// - `ptr` must either be [valid] for writes of `size_of::<T>()` bytes or be in user
1021    ///   space for `size_of::<T>()` bytes.
1022    /// - `ptr` must be aligned on an `align_of::<T>()`-byte boundary.
1023    ///
1024    /// [valid]: crate::mm::io#safety
1025    #[doc(hidden)]
1026    unsafe fn atomic_load_fallible(ptr: *const Self) -> Result<Self>;
1027
1028    /// Atomically compares and exchanges a value.
1029    /// This function will return errors if encountering an unresolvable page fault.
1030    ///
1031    /// Returns the previous value.
1032    /// `new_val` will be written if and only if the previous value is equal to `old_val`.
1033    ///
1034    /// # Safety
1035    ///
1036    /// - `ptr` must either be [valid] for writes of `size_of::<T>()` bytes or be in user
1037    ///   space for `size_of::<T>()` bytes.
1038    /// - `ptr` must be aligned on an `align_of::<T>()`-byte boundary.
1039    ///
1040    /// [valid]: crate::mm::io#safety
1041    #[doc(hidden)]
1042    unsafe fn atomic_cmpxchg_fallible(ptr: *mut Self, old_val: Self, new_val: Self)
1043    -> Result<Self>;
1044}
1045
1046impl PodAtomic for u32 {
1047    unsafe fn atomic_load_fallible(ptr: *const Self) -> Result<Self> {
1048        // SAFETY: The safety is upheld by the caller.
1049        let result = unsafe { __atomic_load_fallible(ptr) };
1050        if result == !0 {
1051            Err(Error::PageFault)
1052        } else {
1053            Ok(result as Self)
1054        }
1055    }
1056
1057    unsafe fn atomic_cmpxchg_fallible(ptr: *mut Self, old_val: Self, new_val: Self) -> Result<u32> {
1058        // SAFETY: The safety is upheld by the caller.
1059        let result = unsafe { __atomic_cmpxchg_fallible(ptr, old_val, new_val) };
1060        if result == !0 {
1061            Err(Error::PageFault)
1062        } else {
1063            Ok(result as Self)
1064        }
1065    }
1066}