starry_vm/
lib.rs

1//! Virtual memory utilities.
2#![no_std]
3#![feature(maybe_uninit_as_bytes)]
4#![feature(maybe_uninit_slice)]
5#![warn(missing_docs)]
6
7use core::{mem::MaybeUninit, slice};
8
9use axerrno::AxError;
10use extern_trait::extern_trait;
11
12/// Errors that can occur during virtual memory operations.
13#[derive(Debug, PartialEq, Clone, Copy)]
14pub enum VmError {
15    /// The address is invalid, e.g., not aligned to the required boundary,
16    /// out of bounds (including null).
17    BadAddress,
18    /// The operation is not allowed, e.g., trying to write to read-only memory.
19    AccessDenied,
20    /// The C-style string or array is too long.
21    ///
22    /// This error is returned by [`vm_load_until_nul`] when the null terminator
23    /// is not found within a predefined search limit.
24    #[cfg(feature = "alloc")]
25    TooLong,
26}
27
28impl From<VmError> for AxError {
29    fn from(err: VmError) -> Self {
30        match err {
31            VmError::BadAddress | VmError::AccessDenied => AxError::BadAddress,
32            #[cfg(feature = "alloc")]
33            VmError::TooLong => AxError::NameTooLong,
34        }
35    }
36}
37
38/// A result type for virtual memory operations.
39pub type VmResult<T = ()> = Result<T, VmError>;
40
41/// The interface for accessing virtual memory.
42///
43/// # Safety
44///
45/// - Satisfy the restrictions of [`mod@extern_trait`].
46/// - The implementation must ensure that the memory accesses are safe and do
47///   not violate any memory safety rules.
48#[extern_trait(VmImpl)]
49pub unsafe trait VmIo {
50    /// Creates an instance of [`VmIo`].
51    ///
52    /// This is used for implementations which might need to store some state or
53    /// data to perform the operations. Implementators may leave this empty
54    /// if no state is needed.
55    fn new() -> Self;
56
57    /// Reads data from the virtual memory starting at `start` into `buf`.
58    fn read(&mut self, start: usize, buf: &mut [MaybeUninit<u8>]) -> VmResult;
59
60    /// Writes data to the virtual memory starting at `start` from `buf`.
61    fn write(&mut self, start: usize, buf: &[u8]) -> VmResult;
62}
63
64/// Reads a slice from the virtual memory.
65pub fn vm_read_slice<T>(ptr: *const T, buf: &mut [MaybeUninit<T>]) -> VmResult {
66    if !ptr.is_aligned() {
67        return Err(VmError::BadAddress);
68    }
69    VmImpl::new().read(ptr.addr(), buf.as_bytes_mut())
70}
71
72/// Writes data to the virtual memory.
73pub fn vm_write_slice<T>(ptr: *mut T, buf: &[T]) -> VmResult {
74    if !ptr.is_aligned() {
75        return Err(VmError::BadAddress);
76    }
77    // SAFETY: we don't care about validity, since these bytes are only used for
78    // writing to the virtual memory.
79    let bytes = unsafe { slice::from_raw_parts(buf.as_ptr().cast::<u8>(), size_of_val(buf)) };
80    VmImpl::new().write(ptr.addr(), bytes)
81}
82
83mod thin;
84pub use thin::{VmMutPtr, VmPtr};
85
86#[cfg(feature = "alloc")]
87mod alloc;
88#[cfg(feature = "alloc")]
89pub use alloc::{vm_load, vm_load_any, vm_load_until_nul};