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}